hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/leds/leds-bcm6328.c
....@@ -1,13 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Driver for BCM6328 memory-mapped LEDs, based on leds-syscon.c
34 *
45 * Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com>
56 * Copyright 2015 Jonas Gorski <jogo@openwrt.org>
6
- *
7
- * This program is free software; you can redistribute it and/or modify it
8
- * under the terms of the GNU General Public License as published by the
9
- * Free Software Foundation; either version 2 of the License, or (at your
10
- * option) any later version.
117 */
128 #include <linux/io.h>
139 #include <linux/leds.h>
....@@ -28,12 +24,17 @@
2824
2925 #define BCM6328_LED_MAX_COUNT 24
3026 #define BCM6328_LED_DEF_DELAY 500
31
-#define BCM6328_LED_INTERVAL_MS 20
3227
33
-#define BCM6328_LED_INTV_MASK 0x3f
34
-#define BCM6328_LED_FAST_INTV_SHIFT 6
35
-#define BCM6328_LED_FAST_INTV_MASK (BCM6328_LED_INTV_MASK << \
36
- BCM6328_LED_FAST_INTV_SHIFT)
28
+#define BCM6328_LED_BLINK_DELAYS 2
29
+#define BCM6328_LED_BLINK_MS 20
30
+
31
+#define BCM6328_LED_BLINK_MASK 0x3f
32
+#define BCM6328_LED_BLINK1_SHIFT 0
33
+#define BCM6328_LED_BLINK1_MASK (BCM6328_LED_BLINK_MASK << \
34
+ BCM6328_LED_BLINK1_SHIFT)
35
+#define BCM6328_LED_BLINK2_SHIFT 6
36
+#define BCM6328_LED_BLINK2_MASK (BCM6328_LED_BLINK_MASK << \
37
+ BCM6328_LED_BLINK2_SHIFT)
3738 #define BCM6328_SERIAL_LED_EN BIT(12)
3839 #define BCM6328_SERIAL_LED_MUX BIT(13)
3940 #define BCM6328_SERIAL_LED_CLK_NPOL BIT(14)
....@@ -49,8 +50,8 @@
4950
5051 #define BCM6328_LED_MODE_MASK 3
5152 #define BCM6328_LED_MODE_ON 0
52
-#define BCM6328_LED_MODE_FAST 1
53
-#define BCM6328_LED_MODE_BLINK 2
53
+#define BCM6328_LED_MODE_BLINK1 1
54
+#define BCM6328_LED_MODE_BLINK2 2
5455 #define BCM6328_LED_MODE_OFF 3
5556 #define BCM6328_LED_SHIFT(X) ((X) << 1)
5657
....@@ -131,12 +132,18 @@
131132 unsigned long flags;
132133
133134 spin_lock_irqsave(led->lock, flags);
134
- *(led->blink_leds) &= ~BIT(led->pin);
135
+
136
+ /* Remove LED from cached HW blinking intervals */
137
+ led->blink_leds[0] &= ~BIT(led->pin);
138
+ led->blink_leds[1] &= ~BIT(led->pin);
139
+
140
+ /* Set LED on/off */
135141 if ((led->active_low && value == LED_OFF) ||
136142 (!led->active_low && value != LED_OFF))
137143 bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
138144 else
139145 bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
146
+
140147 spin_unlock_irqrestore(led->lock, flags);
141148 }
142149
....@@ -144,8 +151,8 @@
144151 {
145152 unsigned long bcm6328_delay;
146153
147
- bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2;
148
- bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS;
154
+ bcm6328_delay = delay + BCM6328_LED_BLINK_MS / 2;
155
+ bcm6328_delay = bcm6328_delay / BCM6328_LED_BLINK_MS;
149156 if (bcm6328_delay == 0)
150157 bcm6328_delay = 1;
151158
....@@ -172,28 +179,68 @@
172179 return -EINVAL;
173180 }
174181
175
- if (delay > BCM6328_LED_INTV_MASK) {
182
+ if (delay > BCM6328_LED_BLINK_MASK) {
176183 dev_dbg(led_cdev->dev,
177184 "fallback to soft blinking (delay > %ums)\n",
178
- BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
185
+ BCM6328_LED_BLINK_MASK * BCM6328_LED_BLINK_MS);
179186 return -EINVAL;
180187 }
181188
182189 spin_lock_irqsave(led->lock, flags);
183
- if (*(led->blink_leds) == 0 ||
184
- *(led->blink_leds) == BIT(led->pin) ||
185
- *(led->blink_delay) == delay) {
190
+ /*
191
+ * Check if any of the two configurable HW blinking intervals is
192
+ * available:
193
+ * 1. No LEDs assigned to the HW blinking interval.
194
+ * 2. Only this LED is assigned to the HW blinking interval.
195
+ * 3. LEDs with the same delay assigned.
196
+ */
197
+ if (led->blink_leds[0] == 0 ||
198
+ led->blink_leds[0] == BIT(led->pin) ||
199
+ led->blink_delay[0] == delay) {
186200 unsigned long val;
187201
188
- *(led->blink_leds) |= BIT(led->pin);
189
- *(led->blink_delay) = delay;
202
+ /* Add LED to the first HW blinking interval cache */
203
+ led->blink_leds[0] |= BIT(led->pin);
190204
205
+ /* Remove LED from the second HW blinking interval cache */
206
+ led->blink_leds[1] &= ~BIT(led->pin);
207
+
208
+ /* Cache first HW blinking interval delay */
209
+ led->blink_delay[0] = delay;
210
+
211
+ /* Update the delay for the first HW blinking interval */
191212 val = bcm6328_led_read(led->mem + BCM6328_REG_INIT);
192
- val &= ~BCM6328_LED_FAST_INTV_MASK;
193
- val |= (delay << BCM6328_LED_FAST_INTV_SHIFT);
213
+ val &= ~BCM6328_LED_BLINK1_MASK;
214
+ val |= (delay << BCM6328_LED_BLINK1_SHIFT);
194215 bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
195216
196
- bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
217
+ /* Set the LED to first HW blinking interval */
218
+ bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK1);
219
+
220
+ rc = 0;
221
+ } else if (led->blink_leds[1] == 0 ||
222
+ led->blink_leds[1] == BIT(led->pin) ||
223
+ led->blink_delay[1] == delay) {
224
+ unsigned long val;
225
+
226
+ /* Remove LED from the first HW blinking interval */
227
+ led->blink_leds[0] &= ~BIT(led->pin);
228
+
229
+ /* Add LED to the second HW blinking interval */
230
+ led->blink_leds[1] |= BIT(led->pin);
231
+
232
+ /* Cache second HW blinking interval delay */
233
+ led->blink_delay[1] = delay;
234
+
235
+ /* Update the delay for the second HW blinking interval */
236
+ val = bcm6328_led_read(led->mem + BCM6328_REG_INIT);
237
+ val &= ~BCM6328_LED_BLINK2_MASK;
238
+ val |= (delay << BCM6328_LED_BLINK2_SHIFT);
239
+ bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
240
+
241
+ /* Set the LED to second HW blinking interval */
242
+ bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK2);
243
+
197244 rc = 0;
198245 } else {
199246 dev_dbg(led_cdev->dev,
....@@ -281,6 +328,7 @@
281328 void __iomem *mem, spinlock_t *lock,
282329 unsigned long *blink_leds, unsigned long *blink_delay)
283330 {
331
+ struct led_init_data init_data = {};
284332 struct bcm6328_led *led;
285333 const char *state;
286334 int rc;
....@@ -297,11 +345,6 @@
297345
298346 if (of_property_read_bool(nc, "active-low"))
299347 led->active_low = true;
300
-
301
- led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
302
- led->cdev.default_trigger = of_get_property(nc,
303
- "linux,default-trigger",
304
- NULL);
305348
306349 if (!of_property_read_string(nc, "default-state", &state)) {
307350 if (!strcmp(state, "on")) {
....@@ -335,8 +378,9 @@
335378
336379 led->cdev.brightness_set = bcm6328_led_set;
337380 led->cdev.blink_set = bcm6328_blink_set;
381
+ init_data.fwnode = of_fwnode_handle(nc);
338382
339
- rc = devm_led_classdev_register(dev, &led->cdev);
383
+ rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
340384 if (rc < 0)
341385 return rc;
342386
....@@ -348,18 +392,13 @@
348392 static int bcm6328_leds_probe(struct platform_device *pdev)
349393 {
350394 struct device *dev = &pdev->dev;
351
- struct device_node *np = pdev->dev.of_node;
395
+ struct device_node *np = dev_of_node(&pdev->dev);
352396 struct device_node *child;
353
- struct resource *mem_r;
354397 void __iomem *mem;
355398 spinlock_t *lock; /* memory lock */
356399 unsigned long val, *blink_leds, *blink_delay;
357400
358
- mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
359
- if (!mem_r)
360
- return -EINVAL;
361
-
362
- mem = devm_ioremap_resource(dev, mem_r);
401
+ mem = devm_platform_ioremap_resource(pdev, 0);
363402 if (IS_ERR(mem))
364403 return PTR_ERR(mem);
365404
....@@ -367,11 +406,13 @@
367406 if (!lock)
368407 return -ENOMEM;
369408
370
- blink_leds = devm_kzalloc(dev, sizeof(*blink_leds), GFP_KERNEL);
409
+ blink_leds = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
410
+ sizeof(*blink_leds), GFP_KERNEL);
371411 if (!blink_leds)
372412 return -ENOMEM;
373413
374
- blink_delay = devm_kzalloc(dev, sizeof(*blink_delay), GFP_KERNEL);
414
+ blink_delay = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
415
+ sizeof(*blink_delay), GFP_KERNEL);
375416 if (!blink_delay)
376417 return -ENOMEM;
377418