]> Git Repo - linux.git/blob - drivers/net/dsa/qca/qca8k-leds.c
Linux 6.14-rc3
[linux.git] / drivers / net / dsa / qca / qca8k-leds.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/property.h>
3 #include <linux/regmap.h>
4 #include <net/dsa.h>
5
6 #include "qca8k.h"
7 #include "qca8k_leds.h"
8
9 static u32 qca8k_phy_to_port(int phy)
10 {
11         /* Internal PHY 0 has port at index 1.
12          * Internal PHY 1 has port at index 2.
13          * Internal PHY 2 has port at index 3.
14          * Internal PHY 3 has port at index 4.
15          * Internal PHY 4 has port at index 5.
16          */
17
18         return phy + 1;
19 }
20
21 static int
22 qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
23 {
24         switch (port_num) {
25         case 0:
26                 reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
27                 reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
28                 break;
29         case 1:
30         case 2:
31         case 3:
32                 /* Port 123 are controlled on a different reg */
33                 reg_info->reg = QCA8K_LED_CTRL3_REG;
34                 reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);
35                 break;
36         case 4:
37                 reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
38                 reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
39                 break;
40         default:
41                 return -EINVAL;
42         }
43
44         return 0;
45 }
46
47 static int
48 qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
49 {
50         reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
51
52         /* 6 total control rule:
53          * 3 control rules for phy0-3 that applies to all their leds
54          * 3 control rules for phy4
55          */
56         if (port_num == 4)
57                 reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
58         else
59                 reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
60
61         return 0;
62 }
63
64 static int
65 qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger)
66 {
67         /* Parsing specific to netdev trigger */
68         if (test_bit(TRIGGER_NETDEV_TX, &rules))
69                 *offload_trigger |= QCA8K_LED_TX_BLINK_MASK;
70         if (test_bit(TRIGGER_NETDEV_RX, &rules))
71                 *offload_trigger |= QCA8K_LED_RX_BLINK_MASK;
72         if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
73                 *offload_trigger |= QCA8K_LED_LINK_10M_EN_MASK;
74         if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
75                 *offload_trigger |= QCA8K_LED_LINK_100M_EN_MASK;
76         if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
77                 *offload_trigger |= QCA8K_LED_LINK_1000M_EN_MASK;
78         if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
79                 *offload_trigger |= QCA8K_LED_HALF_DUPLEX_MASK;
80         if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
81                 *offload_trigger |= QCA8K_LED_FULL_DUPLEX_MASK;
82
83         if (rules && !*offload_trigger)
84                 return -EOPNOTSUPP;
85
86         /* Enable some default rule by default to the requested mode:
87          * - Blink at 4Hz by default
88          */
89         *offload_trigger |= QCA8K_LED_BLINK_4HZ;
90
91         return 0;
92 }
93
94 static int
95 qca8k_led_brightness_set(struct qca8k_led *led,
96                          enum led_brightness brightness)
97 {
98         struct qca8k_led_pattern_en reg_info;
99         struct qca8k_priv *priv = led->priv;
100         u32 mask, val;
101
102         qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
103
104         val = QCA8K_LED_ALWAYS_OFF;
105         if (brightness)
106                 val = QCA8K_LED_ALWAYS_ON;
107
108         /* HW regs to control brightness is special and port 1-2-3
109          * are placed in a different reg.
110          *
111          * To control port 0 brightness:
112          * - the 2 bit (15, 14) of:
113          *   - QCA8K_LED_CTRL0_REG for led1
114          *   - QCA8K_LED_CTRL1_REG for led2
115          *   - QCA8K_LED_CTRL2_REG for led3
116          *
117          * To control port 4:
118          * - the 2 bit (31, 30) of:
119          *   - QCA8K_LED_CTRL0_REG for led1
120          *   - QCA8K_LED_CTRL1_REG for led2
121          *   - QCA8K_LED_CTRL2_REG for led3
122          *
123          * To control port 1:
124          *   - the 2 bit at (9, 8) of QCA8K_LED_CTRL3_REG are used for led1
125          *   - the 2 bit at (11, 10) of QCA8K_LED_CTRL3_REG are used for led2
126          *   - the 2 bit at (13, 12) of QCA8K_LED_CTRL3_REG are used for led3
127          *
128          * To control port 2:
129          *   - the 2 bit at (15, 14) of QCA8K_LED_CTRL3_REG are used for led1
130          *   - the 2 bit at (17, 16) of QCA8K_LED_CTRL3_REG are used for led2
131          *   - the 2 bit at (19, 18) of QCA8K_LED_CTRL3_REG are used for led3
132          *
133          * To control port 3:
134          *   - the 2 bit at (21, 20) of QCA8K_LED_CTRL3_REG are used for led1
135          *   - the 2 bit at (23, 22) of QCA8K_LED_CTRL3_REG are used for led2
136          *   - the 2 bit at (25, 24) of QCA8K_LED_CTRL3_REG are used for led3
137          *
138          * To abstract this and have less code, we use the port and led numm
139          * to calculate the shift and the correct reg due to this problem of
140          * not having a 1:1 map of LED with the regs.
141          */
142         if (led->port_num == 0 || led->port_num == 4) {
143                 mask = QCA8K_LED_PATTERN_EN_MASK;
144                 val <<= QCA8K_LED_PATTERN_EN_SHIFT;
145         } else {
146                 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
147         }
148
149         return regmap_update_bits(priv->regmap, reg_info.reg,
150                                   mask << reg_info.shift,
151                                   val << reg_info.shift);
152 }
153
154 static int
155 qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,
156                                    enum led_brightness brightness)
157 {
158         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
159
160         return qca8k_led_brightness_set(led, brightness);
161 }
162
163 static enum led_brightness
164 qca8k_led_brightness_get(struct qca8k_led *led)
165 {
166         struct qca8k_led_pattern_en reg_info;
167         struct qca8k_priv *priv = led->priv;
168         u32 val;
169         int ret;
170
171         qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
172
173         ret = regmap_read(priv->regmap, reg_info.reg, &val);
174         if (ret)
175                 return 0;
176
177         val >>= reg_info.shift;
178
179         if (led->port_num == 0 || led->port_num == 4) {
180                 val &= QCA8K_LED_PATTERN_EN_MASK;
181                 val >>= QCA8K_LED_PATTERN_EN_SHIFT;
182         } else {
183                 val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
184         }
185
186         /* Assume brightness ON only when the LED is set to always ON */
187         return val == QCA8K_LED_ALWAYS_ON;
188 }
189
190 static int
191 qca8k_cled_blink_set(struct led_classdev *ldev,
192                      unsigned long *delay_on,
193                      unsigned long *delay_off)
194 {
195         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
196         u32 mask, val = QCA8K_LED_ALWAYS_BLINK_4HZ;
197         struct qca8k_led_pattern_en reg_info;
198         struct qca8k_priv *priv = led->priv;
199
200         if (*delay_on == 0 && *delay_off == 0) {
201                 *delay_on = 125;
202                 *delay_off = 125;
203         }
204
205         if (*delay_on != 125 || *delay_off != 125) {
206                 /* The hardware only supports blinking at 4Hz. Fall back
207                  * to software implementation in other cases.
208                  */
209                 return -EINVAL;
210         }
211
212         qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
213
214         if (led->port_num == 0 || led->port_num == 4) {
215                 mask = QCA8K_LED_PATTERN_EN_MASK;
216                 val <<= QCA8K_LED_PATTERN_EN_SHIFT;
217         } else {
218                 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
219         }
220
221         regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
222                            val << reg_info.shift);
223
224         return 0;
225 }
226
227 static int
228 qca8k_cled_trigger_offload(struct led_classdev *ldev, bool enable)
229 {
230         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
231
232         struct qca8k_led_pattern_en reg_info;
233         struct qca8k_priv *priv = led->priv;
234         u32 mask, val = QCA8K_LED_ALWAYS_OFF;
235
236         qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
237
238         if (enable)
239                 val = QCA8K_LED_RULE_CONTROLLED;
240
241         if (led->port_num == 0 || led->port_num == 4) {
242                 mask = QCA8K_LED_PATTERN_EN_MASK;
243                 val <<= QCA8K_LED_PATTERN_EN_SHIFT;
244         } else {
245                 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
246         }
247
248         return regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
249                                   val << reg_info.shift);
250 }
251
252 static bool
253 qca8k_cled_hw_control_status(struct led_classdev *ldev)
254 {
255         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
256
257         struct qca8k_led_pattern_en reg_info;
258         struct qca8k_priv *priv = led->priv;
259         u32 val;
260
261         qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
262
263         regmap_read(priv->regmap, reg_info.reg, &val);
264
265         val >>= reg_info.shift;
266
267         if (led->port_num == 0 || led->port_num == 4) {
268                 val &= QCA8K_LED_PATTERN_EN_MASK;
269                 val >>= QCA8K_LED_PATTERN_EN_SHIFT;
270         } else {
271                 val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
272         }
273
274         return val == QCA8K_LED_RULE_CONTROLLED;
275 }
276
277 static int
278 qca8k_cled_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
279 {
280         u32 offload_trigger = 0;
281
282         return qca8k_parse_netdev(rules, &offload_trigger);
283 }
284
285 static int
286 qca8k_cled_hw_control_set(struct led_classdev *ldev, unsigned long rules)
287 {
288         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
289         struct qca8k_led_pattern_en reg_info;
290         struct qca8k_priv *priv = led->priv;
291         u32 offload_trigger = 0;
292         int ret;
293
294         ret = qca8k_parse_netdev(rules, &offload_trigger);
295         if (ret)
296                 return ret;
297
298         ret = qca8k_cled_trigger_offload(ldev, true);
299         if (ret)
300                 return ret;
301
302         qca8k_get_control_led_reg(led->port_num, led->led_num, &reg_info);
303
304         return regmap_update_bits(priv->regmap, reg_info.reg,
305                                   QCA8K_LED_RULE_MASK << reg_info.shift,
306                                   offload_trigger << reg_info.shift);
307 }
308
309 static int
310 qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
311 {
312         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
313         struct qca8k_led_pattern_en reg_info;
314         struct qca8k_priv *priv = led->priv;
315         u32 val;
316         int ret;
317
318         /* With hw control not active return err */
319         if (!qca8k_cled_hw_control_status(ldev))
320                 return -EINVAL;
321
322         qca8k_get_control_led_reg(led->port_num, led->led_num, &reg_info);
323
324         ret = regmap_read(priv->regmap, reg_info.reg, &val);
325         if (ret)
326                 return ret;
327
328         val >>= reg_info.shift;
329         val &= QCA8K_LED_RULE_MASK;
330
331         /* Parsing specific to netdev trigger */
332         if (val & QCA8K_LED_TX_BLINK_MASK)
333                 set_bit(TRIGGER_NETDEV_TX, rules);
334         if (val & QCA8K_LED_RX_BLINK_MASK)
335                 set_bit(TRIGGER_NETDEV_RX, rules);
336         if (val & QCA8K_LED_LINK_10M_EN_MASK)
337                 set_bit(TRIGGER_NETDEV_LINK_10, rules);
338         if (val & QCA8K_LED_LINK_100M_EN_MASK)
339                 set_bit(TRIGGER_NETDEV_LINK_100, rules);
340         if (val & QCA8K_LED_LINK_1000M_EN_MASK)
341                 set_bit(TRIGGER_NETDEV_LINK_1000, rules);
342         if (val & QCA8K_LED_HALF_DUPLEX_MASK)
343                 set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
344         if (val & QCA8K_LED_FULL_DUPLEX_MASK)
345                 set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
346
347         return 0;
348 }
349
350 static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev)
351 {
352         struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
353         struct qca8k_priv *priv = led->priv;
354         struct dsa_port *dp;
355
356         dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num));
357         if (!dp)
358                 return NULL;
359         if (dp->user)
360                 return &dp->user->dev;
361         return NULL;
362 }
363
364 static int
365 qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
366 {
367         struct fwnode_handle *led = NULL, *leds = NULL;
368         struct led_init_data init_data = { };
369         enum led_default_state state;
370         struct qca8k_led *port_led;
371         int led_num, led_index;
372         int ret;
373
374         leds = fwnode_get_named_child_node(port, "leds");
375         if (!leds) {
376                 dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",
377                         port_num);
378                 return 0;
379         }
380
381         fwnode_for_each_child_node(leds, led) {
382                 /* Reg represent the led number of the port.
383                  * Each port can have at most 3 leds attached
384                  * Commonly:
385                  * 1. is gigabit led
386                  * 2. is mbit led
387                  * 3. additional status led
388                  */
389                 if (fwnode_property_read_u32(led, "reg", &led_num))
390                         continue;
391
392                 if (led_num >= QCA8K_LED_PORT_COUNT) {
393                         dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
394                                  led_num, port_num);
395                         continue;
396                 }
397
398                 led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);
399
400                 port_led = &priv->ports_led[led_index];
401                 port_led->port_num = port_num;
402                 port_led->led_num = led_num;
403                 port_led->priv = priv;
404
405                 state = led_init_default_state_get(led);
406                 switch (state) {
407                 case LEDS_DEFSTATE_ON:
408                         port_led->cdev.brightness = 1;
409                         qca8k_led_brightness_set(port_led, 1);
410                         break;
411                 case LEDS_DEFSTATE_KEEP:
412                         port_led->cdev.brightness =
413                                         qca8k_led_brightness_get(port_led);
414                         break;
415                 default:
416                         port_led->cdev.brightness = 0;
417                         qca8k_led_brightness_set(port_led, 0);
418                 }
419
420                 port_led->cdev.max_brightness = 1;
421                 port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
422                 port_led->cdev.blink_set = qca8k_cled_blink_set;
423                 port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
424                 port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
425                 port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
426                 port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;
427                 port_led->cdev.hw_control_trigger = "netdev";
428                 init_data.default_label = ":port";
429                 init_data.fwnode = led;
430                 init_data.devname_mandatory = true;
431                 init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",
432                                                  priv->internal_mdio_bus->id,
433                                                  port_num);
434                 if (!init_data.devicename) {
435                         fwnode_handle_put(led);
436                         fwnode_handle_put(leds);
437                         return -ENOMEM;
438                 }
439
440                 ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);
441                 if (ret)
442                         dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);
443
444                 kfree(init_data.devicename);
445         }
446
447         fwnode_handle_put(leds);
448         return 0;
449 }
450
451 int
452 qca8k_setup_led_ctrl(struct qca8k_priv *priv)
453 {
454         struct fwnode_handle *ports, *port;
455         int port_num;
456         int ret;
457
458         ports = device_get_named_child_node(priv->dev, "ports");
459         if (!ports) {
460                 dev_info(priv->dev, "No ports node specified in device tree!");
461                 return 0;
462         }
463
464         fwnode_for_each_child_node(ports, port) {
465                 if (fwnode_property_read_u32(port, "reg", &port_num))
466                         continue;
467
468                 /* Skip checking for CPU port 0 and CPU port 6 as not supported */
469                 if (port_num == 0 || port_num == 6)
470                         continue;
471
472                 /* Each port can have at most 3 different leds attached.
473                  * Switch port starts from 0 to 6, but port 0 and 6 are CPU
474                  * port. The port index needs to be decreased by one to identify
475                  * the correct port for LED setup.
476                  */
477                 ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));
478                 if (ret) {
479                         fwnode_handle_put(port);
480                         fwnode_handle_put(ports);
481                         return ret;
482                 }
483         }
484
485         fwnode_handle_put(ports);
486         return 0;
487 }
This page took 0.060391 seconds and 4 git commands to generate.