1 From 32d617005475a71ebcc4ec8b2791e8d1481e9a10 Mon Sep 17 00:00:00 2001
2 From: Luiz Angelo Daros de Luca <luizluca@gmail.com>
3 Date: Sat, 27 Apr 2024 02:11:30 -0300
4 Subject: [PATCH 3/3] net: dsa: realtek: add LED drivers for rtl8366rb
6 This commit introduces LED drivers for rtl8366rb, enabling LEDs to be
7 described in the device tree using the same format as qca8k. Each port
8 can configure up to 4 LEDs.
10 If all LEDs in a group use the default state "keep", they will use the
11 default behavior after a reset. Changing the brightness of one LED,
12 either manually or by a trigger, will disable the default hardware
13 trigger and switch the entire LED group to manually controlled LEDs.
14 Once in this mode, there is no way to revert to hardware-controlled LEDs
15 (except by resetting the switch).
17 Software triggers function as expected with manually controlled LEDs.
19 Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
20 Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
21 Signed-off-by: David S. Miller <davem@davemloft.net>
23 drivers/net/dsa/realtek/rtl8366rb.c | 304 ++++++++++++++++++++++++----
24 1 file changed, 265 insertions(+), 39 deletions(-)
26 --- a/drivers/net/dsa/realtek/rtl8366rb.c
27 +++ b/drivers/net/dsa/realtek/rtl8366rb.c
29 #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f
31 /* LED control registers */
32 +/* The LED blink rate is global; it is used by all triggers in all groups. */
33 #define RTL8366RB_LED_BLINKRATE_REG 0x0430
34 #define RTL8366RB_LED_BLINKRATE_MASK 0x0007
35 #define RTL8366RB_LED_BLINKRATE_28MS 0x0000
38 #define RTL8366RB_LED_CTRL_MASK(led_group) \
39 (0xf << RTL8366RB_LED_CTRL_OFFSET(led_group))
40 -#define RTL8366RB_LED_OFF 0x0
41 -#define RTL8366RB_LED_DUP_COL 0x1
42 -#define RTL8366RB_LED_LINK_ACT 0x2
43 -#define RTL8366RB_LED_SPD1000 0x3
44 -#define RTL8366RB_LED_SPD100 0x4
45 -#define RTL8366RB_LED_SPD10 0x5
46 -#define RTL8366RB_LED_SPD1000_ACT 0x6
47 -#define RTL8366RB_LED_SPD100_ACT 0x7
48 -#define RTL8366RB_LED_SPD10_ACT 0x8
49 -#define RTL8366RB_LED_SPD100_10_ACT 0x9
50 -#define RTL8366RB_LED_FIBER 0xa
51 -#define RTL8366RB_LED_AN_FAULT 0xb
52 -#define RTL8366RB_LED_LINK_RX 0xc
53 -#define RTL8366RB_LED_LINK_TX 0xd
54 -#define RTL8366RB_LED_MASTER 0xe
55 -#define RTL8366RB_LED_FORCE 0xf
57 /* The RTL8366RB_LED_X_X registers are used to manually set the LED state only
58 * when the corresponding LED group in RTL8366RB_LED_CTRL_REG is
59 - * RTL8366RB_LED_FORCE. Otherwise, it is ignored.
60 + * RTL8366RB_LEDGROUP_FORCE. Otherwise, it is ignored.
62 #define RTL8366RB_LED_0_1_CTRL_REG 0x0432
63 -#define RTL8366RB_LED_1_OFFSET 6
64 #define RTL8366RB_LED_2_3_CTRL_REG 0x0433
65 -#define RTL8366RB_LED_3_OFFSET 6
66 +#define RTL8366RB_LED_X_X_CTRL_REG(led_group) \
67 + ((led_group) <= 1 ? \
68 + RTL8366RB_LED_0_1_CTRL_REG : \
69 + RTL8366RB_LED_2_3_CTRL_REG)
70 +#define RTL8366RB_LED_0_X_CTRL_MASK GENMASK(5, 0)
71 +#define RTL8366RB_LED_X_1_CTRL_MASK GENMASK(11, 6)
72 +#define RTL8366RB_LED_2_X_CTRL_MASK GENMASK(5, 0)
73 +#define RTL8366RB_LED_X_3_CTRL_MASK GENMASK(11, 6)
75 #define RTL8366RB_MIB_COUNT 33
76 #define RTL8366RB_GLOBAL_MIB_COUNT 1
78 #define RTL8366RB_GREEN_FEATURE_TX BIT(0)
79 #define RTL8366RB_GREEN_FEATURE_RX BIT(2)
81 +enum rtl8366_ledgroup_mode {
82 + RTL8366RB_LEDGROUP_OFF = 0x0,
83 + RTL8366RB_LEDGROUP_DUP_COL = 0x1,
84 + RTL8366RB_LEDGROUP_LINK_ACT = 0x2,
85 + RTL8366RB_LEDGROUP_SPD1000 = 0x3,
86 + RTL8366RB_LEDGROUP_SPD100 = 0x4,
87 + RTL8366RB_LEDGROUP_SPD10 = 0x5,
88 + RTL8366RB_LEDGROUP_SPD1000_ACT = 0x6,
89 + RTL8366RB_LEDGROUP_SPD100_ACT = 0x7,
90 + RTL8366RB_LEDGROUP_SPD10_ACT = 0x8,
91 + RTL8366RB_LEDGROUP_SPD100_10_ACT = 0x9,
92 + RTL8366RB_LEDGROUP_FIBER = 0xa,
93 + RTL8366RB_LEDGROUP_AN_FAULT = 0xb,
94 + RTL8366RB_LEDGROUP_LINK_RX = 0xc,
95 + RTL8366RB_LEDGROUP_LINK_TX = 0xd,
96 + RTL8366RB_LEDGROUP_MASTER = 0xe,
97 + RTL8366RB_LEDGROUP_FORCE = 0xf,
99 + __RTL8366RB_LEDGROUP_MODE_MAX
102 +struct rtl8366rb_led {
105 + struct realtek_priv *priv;
106 + struct led_classdev cdev;
110 * struct rtl8366rb - RTL8366RB-specific data
111 * @max_mtu: per-port max MTU setting
112 * @pvid_enabled: if PVID is set for respective port
113 + * @leds: per-port and per-ledgroup led info
116 unsigned int max_mtu[RTL8366RB_NUM_PORTS];
117 bool pvid_enabled[RTL8366RB_NUM_PORTS];
118 + struct rtl8366rb_led leds[RTL8366RB_NUM_PORTS][RTL8366RB_NUM_LEDGROUPS];
121 static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
122 @@ -813,6 +834,217 @@ static int rtl8366rb_jam_table(const str
126 +static int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv,
128 + enum rtl8366_ledgroup_mode mode)
133 + val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group);
135 + ret = regmap_update_bits(priv->map,
136 + RTL8366RB_LED_CTRL_REG,
137 + RTL8366RB_LED_CTRL_MASK(led_group),
145 +static inline u32 rtl8366rb_led_group_port_mask(u8 led_group, u8 port)
147 + switch (led_group) {
149 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
151 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
153 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
155 + return FIELD_PREP(RTL8366RB_LED_0_X_CTRL_MASK, BIT(port));
161 +static int rb8366rb_get_port_led(struct rtl8366rb_led *led)
163 + struct realtek_priv *priv = led->priv;
164 + u8 led_group = led->led_group;
165 + u8 port_num = led->port_num;
169 + ret = regmap_read(priv->map, RTL8366RB_LED_X_X_CTRL_REG(led_group),
172 + dev_err(priv->dev, "error reading LED on port %d group %d\n",
173 + led_group, port_num);
177 + return !!(val & rtl8366rb_led_group_port_mask(led_group, port_num));
180 +static int rb8366rb_set_port_led(struct rtl8366rb_led *led, bool enable)
182 + struct realtek_priv *priv = led->priv;
183 + u8 led_group = led->led_group;
184 + u8 port_num = led->port_num;
187 + ret = regmap_update_bits(priv->map,
188 + RTL8366RB_LED_X_X_CTRL_REG(led_group),
189 + rtl8366rb_led_group_port_mask(led_group,
191 + enable ? 0xffff : 0);
193 + dev_err(priv->dev, "error updating LED on port %d group %d\n",
194 + led_group, port_num);
198 + /* Change the LED group to manual controlled LEDs if required */
199 + ret = rb8366rb_set_ledgroup_mode(priv, led_group,
200 + RTL8366RB_LEDGROUP_FORCE);
203 + dev_err(priv->dev, "error updating LED GROUP group %d\n",
212 +rtl8366rb_cled_brightness_set_blocking(struct led_classdev *ldev,
213 + enum led_brightness brightness)
215 + struct rtl8366rb_led *led = container_of(ldev, struct rtl8366rb_led,
218 + return rb8366rb_set_port_led(led, brightness == LED_ON);
221 +static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp,
222 + struct fwnode_handle *led_fwnode)
224 + struct rtl8366rb *rb = priv->chip_data;
225 + struct led_init_data init_data = { };
226 + enum led_default_state state;
227 + struct rtl8366rb_led *led;
231 + ret = fwnode_property_read_u32(led_fwnode, "reg", &led_group);
235 + if (led_group >= RTL8366RB_NUM_LEDGROUPS) {
236 + dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
237 + led_group, dp->index);
241 + led = &rb->leds[dp->index][led_group];
242 + led->port_num = dp->index;
243 + led->led_group = led_group;
246 + state = led_init_default_state_get(led_fwnode);
248 + case LEDS_DEFSTATE_ON:
249 + led->cdev.brightness = 1;
250 + rb8366rb_set_port_led(led, 1);
252 + case LEDS_DEFSTATE_KEEP:
253 + led->cdev.brightness =
254 + rb8366rb_get_port_led(led);
256 + case LEDS_DEFSTATE_OFF:
258 + led->cdev.brightness = 0;
259 + rb8366rb_set_port_led(led, 0);
262 + led->cdev.max_brightness = 1;
263 + led->cdev.brightness_set_blocking =
264 + rtl8366rb_cled_brightness_set_blocking;
265 + init_data.fwnode = led_fwnode;
266 + init_data.devname_mandatory = true;
268 + init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d",
269 + dp->ds->index, dp->index, led_group);
270 + if (!init_data.devicename)
273 + ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);
275 + dev_warn(priv->dev, "Failed to init LED %d for port %d",
276 + led_group, dp->index);
283 +static int rtl8366rb_setup_all_leds_off(struct realtek_priv *priv)
288 + regmap_update_bits(priv->map,
289 + RTL8366RB_INTERRUPT_CONTROL_REG,
290 + RTL8366RB_P4_RGMII_LED,
293 + for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
294 + ret = rb8366rb_set_ledgroup_mode(priv, i,
295 + RTL8366RB_LEDGROUP_OFF);
303 +static int rtl8366rb_setup_leds(struct realtek_priv *priv)
305 + struct device_node *leds_np, *led_np;
306 + struct dsa_switch *ds = &priv->ds;
307 + struct dsa_port *dp;
310 + dsa_switch_for_each_port(dp, ds) {
314 + leds_np = of_get_child_by_name(dp->dn, "leds");
316 + dev_dbg(priv->dev, "No leds defined for port %d",
321 + for_each_child_of_node(leds_np, led_np) {
322 + ret = rtl8366rb_setup_led(priv, dp,
323 + of_fwnode_handle(led_np));
325 + of_node_put(led_np);
330 + of_node_put(leds_np);
337 static int rtl8366rb_setup(struct dsa_switch *ds)
339 struct realtek_priv *priv = ds->priv;
340 @@ -821,7 +1053,6 @@ static int rtl8366rb_setup(struct dsa_sw
348 @@ -997,7 +1228,9 @@ static int rtl8366rb_setup(struct dsa_sw
352 - /* Set blinking, TODO: make this configurable */
353 + /* Set blinking, used by all LED groups using HW triggers.
354 + * TODO: make this configurable
356 ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG,
357 RTL8366RB_LED_BLINKRATE_MASK,
358 RTL8366RB_LED_BLINKRATE_56MS);
359 @@ -1005,26 +1238,19 @@ static int rtl8366rb_setup(struct dsa_sw
362 /* Set up LED activity:
363 - * Each port has 4 LEDs, we configure all ports to the same
364 - * behaviour (no individual config) but we can set up each
366 + * Each port has 4 LEDs on fixed groups. Each group shares the same
367 + * hardware trigger across all ports. LEDs can only be indiviually
368 + * controlled setting the LED group to fixed mode and using the driver
369 + * to toggle them LEDs on/off.
371 if (priv->leds_disabled) {
372 - /* Turn everything off */
373 - regmap_update_bits(priv->map,
374 - RTL8366RB_INTERRUPT_CONTROL_REG,
375 - RTL8366RB_P4_RGMII_LED,
378 - for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
379 - val = RTL8366RB_LED_OFF << RTL8366RB_LED_CTRL_OFFSET(i);
380 - ret = regmap_update_bits(priv->map,
381 - RTL8366RB_LED_CTRL_REG,
382 - RTL8366RB_LED_CTRL_MASK(i),
387 + ret = rtl8366rb_setup_all_leds_off(priv);
391 + ret = rtl8366rb_setup_leds(priv);
396 ret = rtl8366_reset_vlan(priv);