• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
qca8k_phy_to_port(int phy)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
qca8k_get_enable_led_reg(int port_num,int led_num,struct qca8k_led_pattern_en * reg_info)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
qca8k_get_control_led_reg(int port_num,int led_num,struct qca8k_led_pattern_en * reg_info)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
qca8k_parse_netdev(unsigned long rules,u32 * offload_trigger)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
qca8k_led_brightness_set(struct qca8k_led * led,enum led_brightness brightness)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
qca8k_cled_brightness_set_blocking(struct led_classdev * ldev,enum led_brightness brightness)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
qca8k_led_brightness_get(struct qca8k_led * led)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
qca8k_cled_blink_set(struct led_classdev * ldev,unsigned long * delay_on,unsigned long * delay_off)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
qca8k_cled_trigger_offload(struct led_classdev * ldev,bool enable)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
qca8k_cled_hw_control_status(struct led_classdev * ldev)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
qca8k_cled_hw_control_is_supported(struct led_classdev * ldev,unsigned long rules)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
qca8k_cled_hw_control_set(struct led_classdev * ldev,unsigned long rules)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
qca8k_cled_hw_control_get(struct led_classdev * ldev,unsigned long * rules)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 
qca8k_cled_hw_control_get_device(struct led_classdev * ldev)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->slave)
360 		return &dp->slave->dev;
361 	return NULL;
362 }
363 
364 static int
qca8k_parse_port_leds(struct qca8k_priv * priv,struct fwnode_handle * port,int port_num)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 	struct dsa_switch *ds = priv->ds;
370 	enum led_default_state state;
371 	struct qca8k_led *port_led;
372 	int led_num, led_index;
373 	int ret;
374 
375 	leds = fwnode_get_named_child_node(port, "leds");
376 	if (!leds) {
377 		dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",
378 			port_num);
379 		return 0;
380 	}
381 
382 	fwnode_for_each_child_node(leds, led) {
383 		/* Reg represent the led number of the port.
384 		 * Each port can have at most 3 leds attached
385 		 * Commonly:
386 		 * 1. is gigabit led
387 		 * 2. is mbit led
388 		 * 3. additional status led
389 		 */
390 		if (fwnode_property_read_u32(led, "reg", &led_num))
391 			continue;
392 
393 		if (led_num >= QCA8K_LED_PORT_COUNT) {
394 			dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
395 				 led_num, port_num);
396 			continue;
397 		}
398 
399 		led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);
400 
401 		port_led = &priv->ports_led[led_index];
402 		port_led->port_num = port_num;
403 		port_led->led_num = led_num;
404 		port_led->priv = priv;
405 
406 		state = led_init_default_state_get(led);
407 		switch (state) {
408 		case LEDS_DEFSTATE_ON:
409 			port_led->cdev.brightness = 1;
410 			qca8k_led_brightness_set(port_led, 1);
411 			break;
412 		case LEDS_DEFSTATE_KEEP:
413 			port_led->cdev.brightness =
414 					qca8k_led_brightness_get(port_led);
415 			break;
416 		default:
417 			port_led->cdev.brightness = 0;
418 			qca8k_led_brightness_set(port_led, 0);
419 		}
420 
421 		port_led->cdev.max_brightness = 1;
422 		port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
423 		port_led->cdev.blink_set = qca8k_cled_blink_set;
424 		port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;
425 		port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;
426 		port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;
427 		port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;
428 		port_led->cdev.hw_control_trigger = "netdev";
429 		init_data.default_label = ":port";
430 		init_data.fwnode = led;
431 		init_data.devname_mandatory = true;
432 		init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->slave_mii_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
qca8k_setup_led_ctrl(struct qca8k_priv * priv)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 }
488