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
9static 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
21static int
22qca8k_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
47static int
48qca8k_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
64static int
65qca8k_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
94static int
95qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &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(map: priv->regmap, reg: reg_info.reg,
150 mask: mask << reg_info.shift,
151 val: val << reg_info.shift);
152}
153
154static int
155qca8k_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
163static enum led_brightness
164qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &reg_info);
172
173 ret = regmap_read(map: priv->regmap, reg: reg_info.reg, val: &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
190static int
191qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &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(map: priv->regmap, reg: reg_info.reg, mask: mask << reg_info.shift,
222 val: val << reg_info.shift);
223
224 return 0;
225}
226
227static int
228qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &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(map: priv->regmap, reg: reg_info.reg, mask: mask << reg_info.shift,
249 val: val << reg_info.shift);
250}
251
252static bool
253qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &reg_info);
262
263 regmap_read(map: priv->regmap, reg: reg_info.reg, val: &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
277static int
278qca8k_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: &offload_trigger);
283}
284
285static int
286qca8k_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: &offload_trigger);
295 if (ret)
296 return ret;
297
298 ret = qca8k_cled_trigger_offload(ldev, enable: true);
299 if (ret)
300 return ret;
301
302 qca8k_get_control_led_reg(port_num: led->port_num, led_num: led->led_num, reg_info: &reg_info);
303
304 return regmap_update_bits(map: priv->regmap, reg: reg_info.reg,
305 QCA8K_LED_RULE_MASK << reg_info.shift,
306 val: offload_trigger << reg_info.shift);
307}
308
309static int
310qca8k_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(port_num: led->port_num, led_num: led->led_num, reg_info: &reg_info);
323
324 ret = regmap_read(map: priv->regmap, reg: reg_info.reg, val: &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(nr: TRIGGER_NETDEV_TX, addr: rules);
334 if (val & QCA8K_LED_RX_BLINK_MASK)
335 set_bit(nr: TRIGGER_NETDEV_RX, addr: rules);
336 if (val & QCA8K_LED_LINK_10M_EN_MASK)
337 set_bit(nr: TRIGGER_NETDEV_LINK_10, addr: rules);
338 if (val & QCA8K_LED_LINK_100M_EN_MASK)
339 set_bit(nr: TRIGGER_NETDEV_LINK_100, addr: rules);
340 if (val & QCA8K_LED_LINK_1000M_EN_MASK)
341 set_bit(nr: TRIGGER_NETDEV_LINK_1000, addr: rules);
342 if (val & QCA8K_LED_HALF_DUPLEX_MASK)
343 set_bit(nr: TRIGGER_NETDEV_HALF_DUPLEX, addr: rules);
344 if (val & QCA8K_LED_FULL_DUPLEX_MASK)
345 set_bit(nr: TRIGGER_NETDEV_FULL_DUPLEX, addr: rules);
346
347 return 0;
348}
349
350static 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(ds: priv->ds, p: qca8k_phy_to_port(phy: led->port_num));
357 if (!dp)
358 return NULL;
359 if (dp->user)
360 return &dp->user->dev;
361 return NULL;
362}
363
364static int
365qca8k_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(fwnode: port, childname: "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(fwnode: led, propname: "reg", val: &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(fwnode: led);
406 switch (state) {
407 case LEDS_DEFSTATE_ON:
408 port_led->cdev.brightness = 1;
409 qca8k_led_brightness_set(led: port_led, brightness: 1);
410 break;
411 case LEDS_DEFSTATE_KEEP:
412 port_led->cdev.brightness =
413 qca8k_led_brightness_get(led: port_led);
414 break;
415 default:
416 port_led->cdev.brightness = 0;
417 qca8k_led_brightness_set(led: port_led, brightness: 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, fmt: "%s:0%d",
432 priv->internal_mdio_bus->id,
433 port_num);
434 if (!init_data.devicename)
435 return -ENOMEM;
436
437 ret = devm_led_classdev_register_ext(parent: priv->dev, led_cdev: &port_led->cdev, init_data: &init_data);
438 if (ret)
439 dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);
440
441 kfree(objp: init_data.devicename);
442 }
443
444 return 0;
445}
446
447int
448qca8k_setup_led_ctrl(struct qca8k_priv *priv)
449{
450 struct fwnode_handle *ports, *port;
451 int port_num;
452 int ret;
453
454 ports = device_get_named_child_node(dev: priv->dev, childname: "ports");
455 if (!ports) {
456 dev_info(priv->dev, "No ports node specified in device tree!");
457 return 0;
458 }
459
460 fwnode_for_each_child_node(ports, port) {
461 if (fwnode_property_read_u32(fwnode: port, propname: "reg", val: &port_num))
462 continue;
463
464 /* Skip checking for CPU port 0 and CPU port 6 as not supported */
465 if (port_num == 0 || port_num == 6)
466 continue;
467
468 /* Each port can have at most 3 different leds attached.
469 * Switch port starts from 0 to 6, but port 0 and 6 are CPU
470 * port. The port index needs to be decreased by one to identify
471 * the correct port for LED setup.
472 */
473 ret = qca8k_parse_port_leds(priv, port, port_num: qca8k_port_to_phy(port: port_num));
474 if (ret)
475 return ret;
476 }
477
478 return 0;
479}
480

source code of linux/drivers/net/dsa/qca/qca8k-leds.c