From patchwork Sat Jan 6 18:40:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Angelo Daros de Luca X-Patchwork-Id: 13512783 X-Patchwork-Delegate: kuba@kernel.org Received: from mail-oo1-f52.google.com (mail-oo1-f52.google.com [209.85.161.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 779EEE549 for ; Sat, 6 Jan 2024 18:47:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jPU4P7wi" Received: by mail-oo1-f52.google.com with SMTP id 006d021491bc7-5957ede4deaso457341eaf.1 for ; Sat, 06 Jan 2024 10:47:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1704566832; x=1705171632; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QWlM5w2cwHnwcKJWW5OvVvhaX3WCs6fjM2qtn9E0OVM=; b=jPU4P7wiOBl8ODc/oCB62tnMhOFmBPKAiyqKj891jRlxbtKgEuXlvl+Mrc2avyck/I SoE5BaOFEajIZudS8iepOrHvizRk7LHlI7V1/UUjOvqaPjtPKZrDeHA6LoYMFzfGjSh0 3KX5s+C8yaFJLfIWVX4GR/QSKjnipOvK/IDYFqUQZqvMZZU5XTI+FPV/41f1fy/eu+8L z9eciev/UyFOZFWahuXkSxrmBPSIgZUbQEf9m/jwLvDojXZruyWmYAps94zzyt/Hddk0 6ClYLWtfpkUmhqHkHn9SAUbp+Xyg6E/xT96s/CBqprjUGkYAjUi1a1I48JN2beg+A2lq mkPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704566832; x=1705171632; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QWlM5w2cwHnwcKJWW5OvVvhaX3WCs6fjM2qtn9E0OVM=; b=YPYF9Nb6PTS8zE49Z3JJ7FieqstF9kK+zo/k4tgT2Gyh2yJnbINd1ZN5yUVOGDzmw5 d2cWufMHjvdd7h8Y/FtuHkdAXyBmBI81Mf08Tab2tPFA3pmLkgcvCpwxmR35EszLSqgc 6+F5YkcyVLfvKmZq6+2fwBApJj7TcM8dp+tnCb2YQJiCMegusUmU16a+PzkbD5LgTXyQ gKES0jwXhc1EVOHDQ0Uf6EioRRQQtuW7liH6/DxRe3ByhixMCl8bb51QZml1DOJZ4rOA 93Inh6uEipB2MM8EKQ/hgHSgih50PURAgYezJC2Oy+Rzn18cqtKtVCuXt2LhT7LmtTN2 ZVmQ== X-Gm-Message-State: AOJu0YwndypQlwAgsTBtEc/PnXR4brBvGYRZCMm44AhNPzB2GGTgtdfF Oqt0oq6Wb7vl96ZSK35SD6iT+P62mAA3oA== X-Google-Smtp-Source: AGHT+IFJZidlEAesEfwQjTuSoz/5tz3MAb3tTP8dNdCPfGrEkfLZ9EAzJ1bG3LGpgaG7yENdtxkUKQ== X-Received: by 2002:a05:6358:3107:b0:175:51c1:70d2 with SMTP id c7-20020a056358310700b0017551c170d2mr1627179rwe.28.1704566832382; Sat, 06 Jan 2024 10:47:12 -0800 (PST) Received: from tresc054937.tre-sc.gov.br ([187.94.103.218]) by smtp.gmail.com with ESMTPSA id u23-20020a17090ae01700b0028bdc7e5a15sm3363915pjy.53.2024.01.06.10.47.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 Jan 2024 10:47:11 -0800 (PST) From: Luiz Angelo Daros de Luca To: netdev@vger.kernel.org Cc: linus.walleij@linaro.org, alsi@bang-olufsen.dk, andrew@lunn.ch, f.fainelli@gmail.com, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, arinc.unal@arinc9.com, ansuelsmth@gmail.com, Luiz Angelo Daros de Luca Subject: [RFC net-next 1/2] net: dsa: realtek: keep default LED state in rtl8366rb Date: Sat, 6 Jan 2024 15:40:46 -0300 Message-ID: <20240106184651.3665-2-luizluca@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240106184651.3665-1-luizluca@gmail.com> References: <20240106184651.3665-1-luizluca@gmail.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This switch family supports four LEDs for each of its six ports. Each LED group is composed of one of these four LEDs from all six ports. LED groups can be configured to display hardware information, such as link activity, or manually controlled through a bitmap in registers RTL8366RB_LED_0_1_CTRL_REG and RTL8366RB_LED_2_3_CTRL_REG. After a reset, the default LED group configuration for groups 0 to 3 indicates link activity at 1000M, 100M, and 10M, or RTL8366RB_LED_CTRL_REG as 0x5432. These configurations are commonly used for LED indications. However, the driver was replacing that configuration to use manually controlled LEDs (RTL8366RB_LED_FORCE) without providing a way for the OS to control them. The default configuration is deemed more useful than fixed, uncontrollable turned-on LEDs. The driver was enabling/disabling LEDs during port_enable/disable. However, these events occur when the port is administratively controlled (up or down) and are not related to link presence. Additionally, when a port N was disabled, the driver was turning off all LEDs for group N, not only the corresponding LED for port N in any of those 4 groups. In such cases, if port 0 is WAN and brought down, the LEDs for all ports in LED group 0 would be turned off. As another side effect, the driver was wrongly warning that port 5 didn't have an LED ("no LED for port 5"). Since showing the administrative state of ports is not an orthodox way to use LEDs, it was not worth it to fix it and all this code was dropped. The code to disable LEDs was simplified only changing each LED group to the RTL8366RB_LED_OFF state. Registers RTL8366RB_LED_0_1_CTRL_REG and RTL8366RB_LED_2_3_CTRL_REG are only used when the corresponding LED group is configured with RTL8366RB_LED_FORCE and they don't need to be cleaned. The code still references an LED controlled by RTL8366RB_INTERRUPT_CONTROL_REG, but as of now, no test device has actually used it. Also, some magic numbers were replaced by macros. Signed-off-by: Luiz Angelo Daros de Luca --- drivers/net/dsa/realtek/rtl8366rb.c | 87 +++++++---------------------- 1 file changed, 20 insertions(+), 67 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index e3b6a470ca67..874e04cf2e0d 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -182,7 +182,12 @@ #define RTL8366RB_LED_BLINKRATE_222MS 0x0004 #define RTL8366RB_LED_BLINKRATE_446MS 0x0005 +/* LED trigger event for each group */ #define RTL8366RB_LED_CTRL_REG 0x0431 +#define RTL8366RB_LED_CTRL_OFFSET(led_group) \ + (4 * (led_group)) +#define RTL8366RB_LED_CTRL_MASK(led_group) \ + (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group)) #define RTL8366RB_LED_OFF 0x0 #define RTL8366RB_LED_DUP_COL 0x1 #define RTL8366RB_LED_LINK_ACT 0x2 @@ -199,6 +204,11 @@ #define RTL8366RB_LED_LINK_TX 0xd #define RTL8366RB_LED_MASTER 0xe #define RTL8366RB_LED_FORCE 0xf + +/* The RTL8366RB_LED_X_X registers are used to manually set the LED state only + * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is + * RTL8366RB_LED_FORCE. Otherwise, it is ignored. + */ #define RTL8366RB_LED_0_1_CTRL_REG 0x0432 #define RTL8366RB_LED_1_OFFSET 6 #define RTL8366RB_LED_2_3_CTRL_REG 0x0433 @@ -998,28 +1008,20 @@ static int rtl8366rb_setup(struct dsa_switch *ds) */ if (priv->leds_disabled) { /* Turn everything off */ - regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x0FFF, 0); - regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x0FFF, 0); regmap_update_bits(priv->map, RTL8366RB_INTERRUPT_CONTROL_REG, RTL8366RB_P4_RGMII_LED, 0); - val = RTL8366RB_LED_OFF; - } else { - /* TODO: make this configurable per LED */ - val = RTL8366RB_LED_FORCE; - } - for (i = 0; i < 4; i++) { - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_CTRL_REG, - 0xf << (i * 4), - val << (i * 4)); - if (ret) - return ret; + + for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) { + val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i); + ret = regmap_update_bits(priv->map, + RTL8366RB_LED_CTRL_REG, + RTL8366RB_LED_CTRL_MASK(i), + val); + if (ret) + return ret; + } } ret = rtl8366_reset_vlan(priv); @@ -1166,52 +1168,6 @@ rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, } } -static void rb8366rb_set_port_led(struct realtek_priv *priv, - int port, bool enable) -{ - u16 val = enable ? 0x3f : 0; - int ret; - - if (priv->leds_disabled) - return; - - switch (port) { - case 0: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F, val); - break; - case 1: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_0_1_CTRL_REG, - 0x3F << RTL8366RB_LED_1_OFFSET, - val << RTL8366RB_LED_1_OFFSET); - break; - case 2: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F, val); - break; - case 3: - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_2_3_CTRL_REG, - 0x3F << RTL8366RB_LED_3_OFFSET, - val << RTL8366RB_LED_3_OFFSET); - break; - case 4: - ret = regmap_update_bits(priv->map, - RTL8366RB_INTERRUPT_CONTROL_REG, - RTL8366RB_P4_RGMII_LED, - enable ? RTL8366RB_P4_RGMII_LED : 0); - break; - default: - dev_err(priv->dev, "no LED for port %d\n", port); - return; - } - if (ret) - dev_err(priv->dev, "error updating LED on port %d\n", port); -} - static int rtl8366rb_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) @@ -1225,7 +1181,6 @@ rtl8366rb_port_enable(struct dsa_switch *ds, int port, if (ret) return ret; - rb8366rb_set_port_led(priv, port, true); return 0; } @@ -1240,8 +1195,6 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port) BIT(port)); if (ret) return; - - rb8366rb_set_port_led(priv, port, false); } static int From patchwork Sat Jan 6 18:40:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Angelo Daros de Luca X-Patchwork-Id: 13512784 X-Patchwork-Delegate: kuba@kernel.org Received: from mail-oo1-f50.google.com (mail-oo1-f50.google.com [209.85.161.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E6337F4E7 for ; Sat, 6 Jan 2024 18:47:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="RKr8WoNp" Received: by mail-oo1-f50.google.com with SMTP id 006d021491bc7-59496704246so391159eaf.2 for ; Sat, 06 Jan 2024 10:47:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1704566837; x=1705171637; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QtZrYKB5uzDAMWN0sjnqmn2ZcRKrQ5RAQeRItD+zkhk=; b=RKr8WoNptLxYGyUvzOVqTlfa9qU/S/BQ0F1itvdDqGwks5U/u5jxuh81ImVEr9ot0s nMxa85j7d4l1EVIBAY6utqLpzWiJRh0ATHV9qOK1hzbcDHmDcrpDNDoHRrud/7sMcxrE xd73CR7MK/BsviBm0yMe975uCcah7yQ6nwksPivtIybYQemHlGIGND1M0CBT7pydyz1L XIUt3tjxi2ATUcaqV7GqBceJvwwJQXbg9kN0FX3WlQD4EIgul4rvnpRcjzwWNTau58oi 7ZcYM6kjADh7ZZDu93G+nPRiB9w29HZqRTZzE6Ft4qxwXSITDjXSzkTE3jo3b9iWD5eG Tjpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1704566837; x=1705171637; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QtZrYKB5uzDAMWN0sjnqmn2ZcRKrQ5RAQeRItD+zkhk=; b=dilFvgkLVXBapBQia3MyOQW5i36SHT5VJ8L6c0cfcEl5L+uQiQ3m+cjOhtjeOlJaek 9JASSRaDQceE5N1eMKss7DV0rv+K5Htj8p1np4vDXipt0mXwAtOiVBosdsoSjGwAAksQ +FXhYlxDB40XsJ6N2t13OSjS/zPUde6oACC96jhaUuWLsUbhkwYLIJGROxX2jhPWyMGx 64dt+61cQ6URrB2nwYrvQdZFQXW1r9QJkL1TCtd/Fyobs7ARARKje5IZVGjYL9gVcyGz LdglWxA9XnKpv15Evatylalf/G/P4xKDPYPqwlVmTiC6KUVUMjhsCWbUNK1YZpj3z3yM nyQA== X-Gm-Message-State: AOJu0YzM6cn7wjSzb2VfVovyAoUidZl0DrSq6Vx4iL9areXlo0tEnUDA xnUNJXi+UEFfSJ93Y08sKLlpfPPuR11jQg== X-Google-Smtp-Source: AGHT+IEGyr5r57TtEtaYmwBLAwwY670gRD+NGcukEm9qMOXowGOMVUqa4fcc0uylZvmWZbSJIFp6dg== X-Received: by 2002:a05:6359:1a92:b0:174:b927:5859 with SMTP id rv18-20020a0563591a9200b00174b9275859mr626630rwb.21.1704566836951; Sat, 06 Jan 2024 10:47:16 -0800 (PST) Received: from tresc054937.tre-sc.gov.br ([187.94.103.218]) by smtp.gmail.com with ESMTPSA id u23-20020a17090ae01700b0028bdc7e5a15sm3363915pjy.53.2024.01.06.10.47.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 06 Jan 2024 10:47:16 -0800 (PST) From: Luiz Angelo Daros de Luca To: netdev@vger.kernel.org Cc: linus.walleij@linaro.org, alsi@bang-olufsen.dk, andrew@lunn.ch, f.fainelli@gmail.com, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, arinc.unal@arinc9.com, ansuelsmth@gmail.com, Luiz Angelo Daros de Luca Subject: [RFC net-next 2/2] net: dsa: realtek: add LED drivers for rtl8366rb Date: Sat, 6 Jan 2024 15:40:47 -0300 Message-ID: <20240106184651.3665-3-luizluca@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240106184651.3665-1-luizluca@gmail.com> References: <20240106184651.3665-1-luizluca@gmail.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This commit introduces LED drivers for rtl8366rb, allowing LEDs to be described in the device tree using the same format as qca8k. Each port can configure up to 4 LEDs. If LEDs use the default state "keep", they will keep the default behavior after a reset. Changing the brightness of one LED will cause the entire LED group to switch to manually controlled LEDs. Once in this mode, there is no way to revert to hardware-controlled LEDs (except by resetting the switch). Software triggers function as expected with manually controlled LEDs. Signed-off-by: Luiz Angelo Daros de Luca --- drivers/net/dsa/realtek/rtl8366rb.c | 269 +++++++++++++++++++++++++--- 1 file changed, 245 insertions(+), 24 deletions(-) diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index 874e04cf2e0d..f71cb59b8048 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -188,31 +188,21 @@ (4 * (led_group)) #define RTL8366RB_LED_CTRL_MASK(led_group) \ (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group)) -#define RTL8366RB_LED_OFF 0x0 -#define RTL8366RB_LED_DUP_COL 0x1 -#define RTL8366RB_LED_LINK_ACT 0x2 -#define RTL8366RB_LED_SPD1000 0x3 -#define RTL8366RB_LED_SPD100 0x4 -#define RTL8366RB_LED_SPD10 0x5 -#define RTL8366RB_LED_SPD1000_ACT 0x6 -#define RTL8366RB_LED_SPD100_ACT 0x7 -#define RTL8366RB_LED_SPD10_ACT 0x8 -#define RTL8366RB_LED_SPD100_10_ACT 0x9 -#define RTL8366RB_LED_FIBER 0xa -#define RTL8366RB_LED_AN_FAULT 0xb -#define RTL8366RB_LED_LINK_RX 0xc -#define RTL8366RB_LED_LINK_TX 0xd -#define RTL8366RB_LED_MASTER 0xe -#define RTL8366RB_LED_FORCE 0xf /* The RTL8366RB_LED_X_X registers are used to manually set the LED state only * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is * RTL8366RB_LED_FORCE. Otherwise, it is ignored. */ #define RTL8366RB_LED_0_1_CTRL_REG 0x0432 -#define RTL8366RB_LED_1_OFFSET 6 #define RTL8366RB_LED_2_3_CTRL_REG 0x0433 -#define RTL8366RB_LED_3_OFFSET 6 +#define RTL8366RB_LED_X_X_CTRL_REG(led_group) \ + ((led_group) <= 1 ? \ + RTL8366RB_LED_0_1_CTRL_REG : \ + RTL8366RB_LED_2_3_CTRL_REG) +#define RTL8366RB_LED_0_X_CTRL_MASK GENMASK(5, 0) +#define RTL8366RB_LED_X_1_CTRL_MASK GENMASK(11, 6) +#define RTL8366RB_LED_2_X_CTRL_MASK GENMASK(5, 0) +#define RTL8366RB_LED_X_3_CTRL_MASK GENMASK(11, 6) #define RTL8366RB_MIB_COUNT 33 #define RTL8366RB_GLOBAL_MIB_COUNT 1 @@ -356,14 +346,44 @@ #define RTL8366RB_GREEN_FEATURE_TX BIT(0) #define RTL8366RB_GREEN_FEATURE_RX BIT(2) +enum rtl8366_led_mode { + RTL8366RB_LED_OFF = 0x0, + RTL8366RB_LED_DUP_COL = 0x1, + RTL8366RB_LED_LINK_ACT = 0x2, + RTL8366RB_LED_SPD1000 = 0x3, + RTL8366RB_LED_SPD100 = 0x4, + RTL8366RB_LED_SPD10 = 0x5, + RTL8366RB_LED_SPD1000_ACT = 0x6, + RTL8366RB_LED_SPD100_ACT = 0x7, + RTL8366RB_LED_SPD10_ACT = 0x8, + RTL8366RB_LED_SPD100_10_ACT = 0x9, + RTL8366RB_LED_FIBER = 0xa, + RTL8366RB_LED_AN_FAULT = 0xb, + RTL8366RB_LED_LINK_RX = 0xc, + RTL8366RB_LED_LINK_TX = 0xd, + RTL8366RB_LED_MASTER = 0xe, + RTL8366RB_LED_FORCE = 0xf, + + __RTL8366RB_LED_MAX +}; + +struct rtl8366rb_led { + u8 port_num; + u8 led_group; + struct realtek_priv *priv; + struct led_classdev cdev; +}; + /** * struct rtl8366rb - RTL8366RB-specific data * @max_mtu: per-port max MTU setting * @pvid_enabled: if PVID is set for respective port + * @leds: per-port and per-ledgroup led info */ struct rtl8366rb { unsigned int max_mtu[RTL8366RB_NUM_PORTS]; bool pvid_enabled[RTL8366RB_NUM_PORTS]; + struct rtl8366rb_led leds[RTL8366RB_NUM_PORTS][RTL8366RB_NUM_LEDGROUPS]; }; static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { @@ -806,6 +826,207 @@ static int rtl8366rb_jam_table(const struct rtl8366rb_jam_tbl_entry *jam_table, return 0; } +static int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv, + u8 led_group, + enum rtl8366_led_mode mode) +{ + int ret; + u32 val; + + val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group); + + ret = regmap_update_bits(priv->map, + RTL8366RB_LED_CTRL_REG, + RTL8366RB_LED_CTRL_MASK(led_group), + val); + if (ret) + return ret; + + return 0; +} + +static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port) +{ + switch (led_group) { + case 0: + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); + case 1: + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); + case 2: + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); + case 3: + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port)); + default: + return 0; + } +} + +static int rb8366rb_get_port_led(struct rtl8366rb_led *led, bool enable) +{ + struct realtek_priv *priv = led->priv; + u8 led_group = led->led_group; + u8 port_num = led->port_num; + int ret; + u32 val; + + if (led_group >= RTL8366RB_NUM_LEDGROUPS) { + dev_err(priv->dev, "Invalid LED group %d for port %d", + led_group, port_num); + return -EINVAL; + } + + ret = regmap_read(priv->map, RTL8366RB_LED_X_X_CTRL_REG(led_group), + &val); + if (ret) { + dev_err(priv->dev, "error reading LED on port %d group %d\n", + led_group, port_num); + return ret; + } + + return !!(val & rtl8366rb_led_group_port_mask(led_group, port_num)); +} + +static int rb8366rb_set_port_led(struct rtl8366rb_led *led, bool enable) +{ + struct realtek_priv *priv = led->priv; + u8 led_group = led->led_group; + u8 port_num = led->port_num; + int ret; + + if (led_group >= RTL8366RB_NUM_LEDGROUPS) { + dev_err(priv->dev, "Invalid LED group %d for port %d", + led_group, port_num); + return -EINVAL; + } + + ret = regmap_update_bits(priv->map, + RTL8366RB_LED_X_X_CTRL_REG(led_group), + rtl8366rb_led_group_port_mask(led_group, + port_num), + enable ? 0xffff : 0); + if (ret) { + dev_err(priv->dev, "error updating LED on port %d group %d\n", + led_group, port_num); + return ret; + } + + /* Change the LED group to manual controlled LEDs if required */ + ret = rb8366rb_set_ledgroup_mode(priv, led_group, RTL8366RB_LED_FORCE); + + if (ret) { + dev_err(priv->dev, "error updating LED GROUP group %d\n", + led_group); + return ret; + } + + return 0; +} + +static int +rtl8366rb_cled_brightness_set_blocking(struct led_classdev *ldev, + enum led_brightness brightness) +{ + struct rtl8366rb_led *led = container_of(ldev, struct rtl8366rb_led, + cdev); + + return rb8366rb_set_port_led(led, brightness == LED_ON); +} + +static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, + struct fwnode_handle *led_fwnode) +{ + struct rtl8366rb *rb = priv->chip_data; + struct led_init_data init_data = { }; + struct rtl8366rb_led *led; + enum led_default_state state; + u32 led_group; + int ret; + + ret = fwnode_property_read_u32(led_fwnode, "reg", &led_group); + if (ret) + return ret; + + if (led_group >= RTL8366RB_NUM_LEDGROUPS) { + dev_warn(priv->dev, "Invalid LED reg %d defined for port %d", + led_group, dp->index); + return -EINVAL; + } + + led = &rb->leds[dp->index][led_group]; + led->port_num = dp->index; + led->led_group = led_group; + led->priv = priv; + + state = led_init_default_state_get(led_fwnode); + switch (state) { + case LEDS_DEFSTATE_ON: + led->cdev.brightness = 1; + rb8366rb_set_port_led(led, 1); + break; + case LEDS_DEFSTATE_KEEP: + led->cdev.brightness = + rb8366rb_get_port_led(led, 1); + break; + case LEDS_DEFSTATE_OFF: + default: + led->cdev.brightness = 0; + rb8366rb_set_port_led(led, 0); + } + + led->cdev.max_brightness = 1; + led->cdev.brightness_set_blocking = + rtl8366rb_cled_brightness_set_blocking; + init_data.fwnode = led_fwnode; + init_data.devname_mandatory = true; + + init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d", + dp->ds->index, dp->index, led_group); + if (!init_data.devicename) + return -ENOMEM; + + ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data); + if (ret) { + dev_warn(priv->dev, "Failed to init LED %d for port %d", + led_group, dp->index); + return ret; + } + + return 0; +} + +static int rtl8366rb_setup_leds(struct realtek_priv *priv) +{ + struct device_node *leds_np, *led_np; + struct dsa_port *dp; + int ret; + + dsa_switch_for_each_port(dp, priv->ds) { + if (!dp->dn) + continue; + + leds_np = of_get_child_by_name(dp->dn, "leds"); + if (!leds_np) { + dev_dbg(priv->dev, "No leds defined for port %d", + dp->index); + continue; + } + + for_each_child_of_node(leds_np, led_np) { + ret = rtl8366rb_setup_led(priv, dp, + of_fwnode_handle(led_np)); + if (ret) { + of_node_put(led_np); + break; + } + } + + of_node_put(leds_np); + if (ret) + return ret; + } + return 0; +} + static int rtl8366rb_setup(struct dsa_switch *ds) { struct realtek_priv *priv = ds->priv; @@ -814,7 +1035,6 @@ static int rtl8366rb_setup(struct dsa_switch *ds) u32 chip_ver = 0; u32 chip_id = 0; int jam_size; - u32 val; int ret; int i; @@ -1014,14 +1234,15 @@ static int rtl8366rb_setup(struct dsa_switch *ds) 0); for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) { - val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i); - ret = regmap_update_bits(priv->map, - RTL8366RB_LED_CTRL_REG, - RTL8366RB_LED_CTRL_MASK(i), - val); + ret = rb8366rb_set_ledgroup_mode(priv, i, + RTL8366RB_LED_OFF); if (ret) return ret; } + } else { + ret = rtl8366rb_setup_leds(priv); + if (ret) + return ret; } ret = rtl8366_reset_vlan(priv);