xref: /openbmc/linux/drivers/net/dsa/qca/qca8k-leds.c (revision 2a954832)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/regmap.h>
3 #include <net/dsa.h>
4 
5 #include "qca8k.h"
6 #include "qca8k_leds.h"
7 
8 static int
9 qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)
10 {
11 	switch (port_num) {
12 	case 0:
13 		reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
14 		reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;
15 		break;
16 	case 1:
17 	case 2:
18 	case 3:
19 		/* Port 123 are controlled on a different reg */
20 		reg_info->reg = QCA8K_LED_CTRL3_REG;
21 		reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);
22 		break;
23 	case 4:
24 		reg_info->reg = QCA8K_LED_CTRL_REG(led_num);
25 		reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;
26 		break;
27 	default:
28 		return -EINVAL;
29 	}
30 
31 	return 0;
32 }
33 
34 static int
35 qca8k_led_brightness_set(struct qca8k_led *led,
36 			 enum led_brightness brightness)
37 {
38 	struct qca8k_led_pattern_en reg_info;
39 	struct qca8k_priv *priv = led->priv;
40 	u32 mask, val;
41 
42 	qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
43 
44 	val = QCA8K_LED_ALWAYS_OFF;
45 	if (brightness)
46 		val = QCA8K_LED_ALWAYS_ON;
47 
48 	/* HW regs to control brightness is special and port 1-2-3
49 	 * are placed in a different reg.
50 	 *
51 	 * To control port 0 brightness:
52 	 * - the 2 bit (15, 14) of:
53 	 *   - QCA8K_LED_CTRL0_REG for led1
54 	 *   - QCA8K_LED_CTRL1_REG for led2
55 	 *   - QCA8K_LED_CTRL2_REG for led3
56 	 *
57 	 * To control port 4:
58 	 * - the 2 bit (31, 30) of:
59 	 *   - QCA8K_LED_CTRL0_REG for led1
60 	 *   - QCA8K_LED_CTRL1_REG for led2
61 	 *   - QCA8K_LED_CTRL2_REG for led3
62 	 *
63 	 * To control port 1:
64 	 *   - the 2 bit at (9, 8) of QCA8K_LED_CTRL3_REG are used for led1
65 	 *   - the 2 bit at (11, 10) of QCA8K_LED_CTRL3_REG are used for led2
66 	 *   - the 2 bit at (13, 12) of QCA8K_LED_CTRL3_REG are used for led3
67 	 *
68 	 * To control port 2:
69 	 *   - the 2 bit at (15, 14) of QCA8K_LED_CTRL3_REG are used for led1
70 	 *   - the 2 bit at (17, 16) of QCA8K_LED_CTRL3_REG are used for led2
71 	 *   - the 2 bit at (19, 18) of QCA8K_LED_CTRL3_REG are used for led3
72 	 *
73 	 * To control port 3:
74 	 *   - the 2 bit at (21, 20) of QCA8K_LED_CTRL3_REG are used for led1
75 	 *   - the 2 bit at (23, 22) of QCA8K_LED_CTRL3_REG are used for led2
76 	 *   - the 2 bit at (25, 24) of QCA8K_LED_CTRL3_REG are used for led3
77 	 *
78 	 * To abstract this and have less code, we use the port and led numm
79 	 * to calculate the shift and the correct reg due to this problem of
80 	 * not having a 1:1 map of LED with the regs.
81 	 */
82 	if (led->port_num == 0 || led->port_num == 4) {
83 		mask = QCA8K_LED_PATTERN_EN_MASK;
84 		val <<= QCA8K_LED_PATTERN_EN_SHIFT;
85 	} else {
86 		mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
87 	}
88 
89 	return regmap_update_bits(priv->regmap, reg_info.reg,
90 				  mask << reg_info.shift,
91 				  val << reg_info.shift);
92 }
93 
94 static int
95 qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,
96 				   enum led_brightness brightness)
97 {
98 	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
99 
100 	return qca8k_led_brightness_set(led, brightness);
101 }
102 
103 static enum led_brightness
104 qca8k_led_brightness_get(struct qca8k_led *led)
105 {
106 	struct qca8k_led_pattern_en reg_info;
107 	struct qca8k_priv *priv = led->priv;
108 	u32 val;
109 	int ret;
110 
111 	qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
112 
113 	ret = regmap_read(priv->regmap, reg_info.reg, &val);
114 	if (ret)
115 		return 0;
116 
117 	val >>= reg_info.shift;
118 
119 	if (led->port_num == 0 || led->port_num == 4) {
120 		val &= QCA8K_LED_PATTERN_EN_MASK;
121 		val >>= QCA8K_LED_PATTERN_EN_SHIFT;
122 	} else {
123 		val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;
124 	}
125 
126 	/* Assume brightness ON only when the LED is set to always ON */
127 	return val == QCA8K_LED_ALWAYS_ON;
128 }
129 
130 static int
131 qca8k_cled_blink_set(struct led_classdev *ldev,
132 		     unsigned long *delay_on,
133 		     unsigned long *delay_off)
134 {
135 	struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);
136 	u32 mask, val = QCA8K_LED_ALWAYS_BLINK_4HZ;
137 	struct qca8k_led_pattern_en reg_info;
138 	struct qca8k_priv *priv = led->priv;
139 
140 	if (*delay_on == 0 && *delay_off == 0) {
141 		*delay_on = 125;
142 		*delay_off = 125;
143 	}
144 
145 	if (*delay_on != 125 || *delay_off != 125) {
146 		/* The hardware only supports blinking at 4Hz. Fall back
147 		 * to software implementation in other cases.
148 		 */
149 		return -EINVAL;
150 	}
151 
152 	qca8k_get_enable_led_reg(led->port_num, led->led_num, &reg_info);
153 
154 	if (led->port_num == 0 || led->port_num == 4) {
155 		mask = QCA8K_LED_PATTERN_EN_MASK;
156 		val <<= QCA8K_LED_PATTERN_EN_SHIFT;
157 	} else {
158 		mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;
159 	}
160 
161 	regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,
162 			   val << reg_info.shift);
163 
164 	return 0;
165 }
166 
167 static int
168 qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)
169 {
170 	struct fwnode_handle *led = NULL, *leds = NULL;
171 	struct led_init_data init_data = { };
172 	struct dsa_switch *ds = priv->ds;
173 	enum led_default_state state;
174 	struct qca8k_led *port_led;
175 	int led_num, led_index;
176 	int ret;
177 
178 	leds = fwnode_get_named_child_node(port, "leds");
179 	if (!leds) {
180 		dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",
181 			port_num);
182 		return 0;
183 	}
184 
185 	fwnode_for_each_child_node(leds, led) {
186 		/* Reg represent the led number of the port.
187 		 * Each port can have at most 3 leds attached
188 		 * Commonly:
189 		 * 1. is gigabit led
190 		 * 2. is mbit led
191 		 * 3. additional status led
192 		 */
193 		if (fwnode_property_read_u32(led, "reg", &led_num))
194 			continue;
195 
196 		if (led_num >= QCA8K_LED_PORT_COUNT) {
197 			dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",
198 				 led_num, port_num);
199 			continue;
200 		}
201 
202 		led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);
203 
204 		port_led = &priv->ports_led[led_index];
205 		port_led->port_num = port_num;
206 		port_led->led_num = led_num;
207 		port_led->priv = priv;
208 
209 		state = led_init_default_state_get(led);
210 		switch (state) {
211 		case LEDS_DEFSTATE_ON:
212 			port_led->cdev.brightness = 1;
213 			qca8k_led_brightness_set(port_led, 1);
214 			break;
215 		case LEDS_DEFSTATE_KEEP:
216 			port_led->cdev.brightness =
217 					qca8k_led_brightness_get(port_led);
218 			break;
219 		default:
220 			port_led->cdev.brightness = 0;
221 			qca8k_led_brightness_set(port_led, 0);
222 		}
223 
224 		port_led->cdev.max_brightness = 1;
225 		port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;
226 		port_led->cdev.blink_set = qca8k_cled_blink_set;
227 		init_data.default_label = ":port";
228 		init_data.fwnode = led;
229 		init_data.devname_mandatory = true;
230 		init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->slave_mii_bus->id,
231 						 port_num);
232 		if (!init_data.devicename)
233 			return -ENOMEM;
234 
235 		ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);
236 		if (ret)
237 			dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);
238 
239 		kfree(init_data.devicename);
240 	}
241 
242 	return 0;
243 }
244 
245 int
246 qca8k_setup_led_ctrl(struct qca8k_priv *priv)
247 {
248 	struct fwnode_handle *ports, *port;
249 	int port_num;
250 	int ret;
251 
252 	ports = device_get_named_child_node(priv->dev, "ports");
253 	if (!ports) {
254 		dev_info(priv->dev, "No ports node specified in device tree!");
255 		return 0;
256 	}
257 
258 	fwnode_for_each_child_node(ports, port) {
259 		if (fwnode_property_read_u32(port, "reg", &port_num))
260 			continue;
261 
262 		/* Skip checking for CPU port 0 and CPU port 6 as not supported */
263 		if (port_num == 0 || port_num == 6)
264 			continue;
265 
266 		/* Each port can have at most 3 different leds attached.
267 		 * Switch port starts from 0 to 6, but port 0 and 6 are CPU
268 		 * port. The port index needs to be decreased by one to identify
269 		 * the correct port for LED setup.
270 		 */
271 		ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));
272 		if (ret)
273 			return ret;
274 	}
275 
276 	return 0;
277 }
278