Merge tag 'for-linus-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw...
[linux-2.6-microblaze.git] / drivers / leds / leds-bcm6328.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Driver for BCM6328 memory-mapped LEDs, based on leds-syscon.c
4  *
5  * Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com>
6  * Copyright 2015 Jonas Gorski <jogo@openwrt.org>
7  */
8 #include <linux/io.h>
9 #include <linux/leds.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/spinlock.h>
14
15 #define BCM6328_REG_INIT                0x00
16 #define BCM6328_REG_MODE_HI             0x04
17 #define BCM6328_REG_MODE_LO             0x08
18 #define BCM6328_REG_HWDIS               0x0c
19 #define BCM6328_REG_STROBE              0x10
20 #define BCM6328_REG_LNKACTSEL_HI        0x14
21 #define BCM6328_REG_LNKACTSEL_LO        0x18
22 #define BCM6328_REG_RBACK               0x1c
23 #define BCM6328_REG_SERMUX              0x20
24
25 #define BCM6328_LED_MAX_COUNT           24
26 #define BCM6328_LED_DEF_DELAY           500
27
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)
38 #define BCM6328_SERIAL_LED_EN           BIT(12)
39 #define BCM6328_SERIAL_LED_MUX          BIT(13)
40 #define BCM6328_SERIAL_LED_CLK_NPOL     BIT(14)
41 #define BCM6328_SERIAL_LED_DATA_PPOL    BIT(15)
42 #define BCM6328_SERIAL_LED_SHIFT_DIR    BIT(16)
43 #define BCM6328_LED_SHIFT_TEST          BIT(30)
44 #define BCM6328_LED_TEST                BIT(31)
45 #define BCM6328_INIT_MASK               (BCM6328_SERIAL_LED_EN | \
46                                          BCM6328_SERIAL_LED_MUX | \
47                                          BCM6328_SERIAL_LED_CLK_NPOL | \
48                                          BCM6328_SERIAL_LED_DATA_PPOL | \
49                                          BCM6328_SERIAL_LED_SHIFT_DIR)
50
51 #define BCM6328_LED_MODE_MASK           3
52 #define BCM6328_LED_MODE_ON             0
53 #define BCM6328_LED_MODE_BLINK1         1
54 #define BCM6328_LED_MODE_BLINK2         2
55 #define BCM6328_LED_MODE_OFF            3
56 #define BCM6328_LED_SHIFT(X)            ((X) << 1)
57
58 /**
59  * struct bcm6328_led - state container for bcm6328 based LEDs
60  * @cdev: LED class device for this LED
61  * @mem: memory resource
62  * @lock: memory lock
63  * @pin: LED pin number
64  * @blink_leds: blinking LEDs
65  * @blink_delay: blinking delay
66  * @active_low: LED is active low
67  */
68 struct bcm6328_led {
69         struct led_classdev cdev;
70         void __iomem *mem;
71         spinlock_t *lock;
72         unsigned long pin;
73         unsigned long *blink_leds;
74         unsigned long *blink_delay;
75         bool active_low;
76 };
77
78 static void bcm6328_led_write(void __iomem *reg, unsigned long data)
79 {
80 #ifdef CONFIG_CPU_BIG_ENDIAN
81         iowrite32be(data, reg);
82 #else
83         writel(data, reg);
84 #endif
85 }
86
87 static unsigned long bcm6328_led_read(void __iomem *reg)
88 {
89 #ifdef CONFIG_CPU_BIG_ENDIAN
90         return ioread32be(reg);
91 #else
92         return readl(reg);
93 #endif
94 }
95
96 /**
97  * LEDMode 64 bits / 24 LEDs
98  * bits [31:0] -> LEDs 8-23
99  * bits [47:32] -> LEDs 0-7
100  * bits [63:48] -> unused
101  */
102 static unsigned long bcm6328_pin2shift(unsigned long pin)
103 {
104         if (pin < 8)
105                 return pin + 16; /* LEDs 0-7 (bits 47:32) */
106         else
107                 return pin - 8; /* LEDs 8-23 (bits 31:0) */
108 }
109
110 static void bcm6328_led_mode(struct bcm6328_led *led, unsigned long value)
111 {
112         void __iomem *mode;
113         unsigned long val, shift;
114
115         shift = bcm6328_pin2shift(led->pin);
116         if (shift / 16)
117                 mode = led->mem + BCM6328_REG_MODE_HI;
118         else
119                 mode = led->mem + BCM6328_REG_MODE_LO;
120
121         val = bcm6328_led_read(mode);
122         val &= ~(BCM6328_LED_MODE_MASK << BCM6328_LED_SHIFT(shift % 16));
123         val |= (value << BCM6328_LED_SHIFT(shift % 16));
124         bcm6328_led_write(mode, val);
125 }
126
127 static void bcm6328_led_set(struct led_classdev *led_cdev,
128                             enum led_brightness value)
129 {
130         struct bcm6328_led *led =
131                 container_of(led_cdev, struct bcm6328_led, cdev);
132         unsigned long flags;
133
134         spin_lock_irqsave(led->lock, flags);
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 */
141         if ((led->active_low && value == LED_OFF) ||
142             (!led->active_low && value != LED_OFF))
143                 bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
144         else
145                 bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
146
147         spin_unlock_irqrestore(led->lock, flags);
148 }
149
150 static unsigned long bcm6328_blink_delay(unsigned long delay)
151 {
152         unsigned long bcm6328_delay;
153
154         bcm6328_delay = delay + BCM6328_LED_BLINK_MS / 2;
155         bcm6328_delay = bcm6328_delay / BCM6328_LED_BLINK_MS;
156         if (bcm6328_delay == 0)
157                 bcm6328_delay = 1;
158
159         return bcm6328_delay;
160 }
161
162 static int bcm6328_blink_set(struct led_classdev *led_cdev,
163                              unsigned long *delay_on, unsigned long *delay_off)
164 {
165         struct bcm6328_led *led =
166                 container_of(led_cdev, struct bcm6328_led, cdev);
167         unsigned long delay, flags;
168         int rc;
169
170         if (!*delay_on)
171                 *delay_on = BCM6328_LED_DEF_DELAY;
172         if (!*delay_off)
173                 *delay_off = BCM6328_LED_DEF_DELAY;
174
175         delay = bcm6328_blink_delay(*delay_on);
176         if (delay != bcm6328_blink_delay(*delay_off)) {
177                 dev_dbg(led_cdev->dev,
178                         "fallback to soft blinking (delay_on != delay_off)\n");
179                 return -EINVAL;
180         }
181
182         if (delay > BCM6328_LED_BLINK_MASK) {
183                 dev_dbg(led_cdev->dev,
184                         "fallback to soft blinking (delay > %ums)\n",
185                         BCM6328_LED_BLINK_MASK * BCM6328_LED_BLINK_MS);
186                 return -EINVAL;
187         }
188
189         spin_lock_irqsave(led->lock, flags);
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) {
200                 unsigned long val;
201
202                 /* Add LED to the first HW blinking interval cache */
203                 led->blink_leds[0] |= BIT(led->pin);
204
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 */
212                 val = bcm6328_led_read(led->mem + BCM6328_REG_INIT);
213                 val &= ~BCM6328_LED_BLINK1_MASK;
214                 val |= (delay << BCM6328_LED_BLINK1_SHIFT);
215                 bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
216
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
244                 rc = 0;
245         } else {
246                 dev_dbg(led_cdev->dev,
247                         "fallback to soft blinking (delay already set)\n");
248                 rc = -EINVAL;
249         }
250         spin_unlock_irqrestore(led->lock, flags);
251
252         return rc;
253 }
254
255 static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
256                          void __iomem *mem, spinlock_t *lock)
257 {
258         int i, cnt;
259         unsigned long flags, val;
260
261         spin_lock_irqsave(lock, flags);
262         val = bcm6328_led_read(mem + BCM6328_REG_HWDIS);
263         val &= ~BIT(reg);
264         bcm6328_led_write(mem + BCM6328_REG_HWDIS, val);
265         spin_unlock_irqrestore(lock, flags);
266
267         /* Only LEDs 0-7 can be activity/link controlled */
268         if (reg >= 8)
269                 return 0;
270
271         cnt = of_property_count_elems_of_size(nc, "brcm,link-signal-sources",
272                                               sizeof(u32));
273         for (i = 0; i < cnt; i++) {
274                 u32 sel;
275                 void __iomem *addr;
276
277                 if (reg < 4)
278                         addr = mem + BCM6328_REG_LNKACTSEL_LO;
279                 else
280                         addr = mem + BCM6328_REG_LNKACTSEL_HI;
281
282                 of_property_read_u32_index(nc, "brcm,link-signal-sources", i,
283                                            &sel);
284
285                 if (reg / 4 != sel / 4) {
286                         dev_warn(dev, "invalid link signal source\n");
287                         continue;
288                 }
289
290                 spin_lock_irqsave(lock, flags);
291                 val = bcm6328_led_read(addr);
292                 val |= (BIT(reg % 4) << (((sel % 4) * 4) + 16));
293                 bcm6328_led_write(addr, val);
294                 spin_unlock_irqrestore(lock, flags);
295         }
296
297         cnt = of_property_count_elems_of_size(nc,
298                                               "brcm,activity-signal-sources",
299                                               sizeof(u32));
300         for (i = 0; i < cnt; i++) {
301                 u32 sel;
302                 void __iomem *addr;
303
304                 if (reg < 4)
305                         addr = mem + BCM6328_REG_LNKACTSEL_LO;
306                 else
307                         addr = mem + BCM6328_REG_LNKACTSEL_HI;
308
309                 of_property_read_u32_index(nc, "brcm,activity-signal-sources",
310                                            i, &sel);
311
312                 if (reg / 4 != sel / 4) {
313                         dev_warn(dev, "invalid activity signal source\n");
314                         continue;
315                 }
316
317                 spin_lock_irqsave(lock, flags);
318                 val = bcm6328_led_read(addr);
319                 val |= (BIT(reg % 4) << ((sel % 4) * 4));
320                 bcm6328_led_write(addr, val);
321                 spin_unlock_irqrestore(lock, flags);
322         }
323
324         return 0;
325 }
326
327 static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
328                        void __iomem *mem, spinlock_t *lock,
329                        unsigned long *blink_leds, unsigned long *blink_delay)
330 {
331         struct led_init_data init_data = {};
332         struct bcm6328_led *led;
333         const char *state;
334         int rc;
335
336         led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
337         if (!led)
338                 return -ENOMEM;
339
340         led->pin = reg;
341         led->mem = mem;
342         led->lock = lock;
343         led->blink_leds = blink_leds;
344         led->blink_delay = blink_delay;
345
346         if (of_property_read_bool(nc, "active-low"))
347                 led->active_low = true;
348
349         if (!of_property_read_string(nc, "default-state", &state)) {
350                 if (!strcmp(state, "on")) {
351                         led->cdev.brightness = LED_FULL;
352                 } else if (!strcmp(state, "keep")) {
353                         void __iomem *mode;
354                         unsigned long val, shift;
355
356                         shift = bcm6328_pin2shift(led->pin);
357                         if (shift / 16)
358                                 mode = mem + BCM6328_REG_MODE_HI;
359                         else
360                                 mode = mem + BCM6328_REG_MODE_LO;
361
362                         val = bcm6328_led_read(mode) >>
363                               BCM6328_LED_SHIFT(shift % 16);
364                         val &= BCM6328_LED_MODE_MASK;
365                         if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
366                             (!led->active_low && val == BCM6328_LED_MODE_ON))
367                                 led->cdev.brightness = LED_FULL;
368                         else
369                                 led->cdev.brightness = LED_OFF;
370                 } else {
371                         led->cdev.brightness = LED_OFF;
372                 }
373         } else {
374                 led->cdev.brightness = LED_OFF;
375         }
376
377         bcm6328_led_set(&led->cdev, led->cdev.brightness);
378
379         led->cdev.brightness_set = bcm6328_led_set;
380         led->cdev.blink_set = bcm6328_blink_set;
381         init_data.fwnode = of_fwnode_handle(nc);
382
383         rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
384         if (rc < 0)
385                 return rc;
386
387         dev_dbg(dev, "registered LED %s\n", led->cdev.name);
388
389         return 0;
390 }
391
392 static int bcm6328_leds_probe(struct platform_device *pdev)
393 {
394         struct device *dev = &pdev->dev;
395         struct device_node *np = dev_of_node(&pdev->dev);
396         struct device_node *child;
397         void __iomem *mem;
398         spinlock_t *lock; /* memory lock */
399         unsigned long val, *blink_leds, *blink_delay;
400
401         mem = devm_platform_ioremap_resource(pdev, 0);
402         if (IS_ERR(mem))
403                 return PTR_ERR(mem);
404
405         lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
406         if (!lock)
407                 return -ENOMEM;
408
409         blink_leds = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
410                                   sizeof(*blink_leds), GFP_KERNEL);
411         if (!blink_leds)
412                 return -ENOMEM;
413
414         blink_delay = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
415                                    sizeof(*blink_delay), GFP_KERNEL);
416         if (!blink_delay)
417                 return -ENOMEM;
418
419         spin_lock_init(lock);
420
421         bcm6328_led_write(mem + BCM6328_REG_HWDIS, ~0);
422         bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_HI, 0);
423         bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
424
425         val = bcm6328_led_read(mem + BCM6328_REG_INIT);
426         val &= ~(BCM6328_INIT_MASK);
427         if (of_property_read_bool(np, "brcm,serial-leds"))
428                 val |= BCM6328_SERIAL_LED_EN;
429         if (of_property_read_bool(np, "brcm,serial-mux"))
430                 val |= BCM6328_SERIAL_LED_MUX;
431         if (of_property_read_bool(np, "brcm,serial-clk-low"))
432                 val |= BCM6328_SERIAL_LED_CLK_NPOL;
433         if (!of_property_read_bool(np, "brcm,serial-dat-low"))
434                 val |= BCM6328_SERIAL_LED_DATA_PPOL;
435         if (!of_property_read_bool(np, "brcm,serial-shift-inv"))
436                 val |= BCM6328_SERIAL_LED_SHIFT_DIR;
437         bcm6328_led_write(mem + BCM6328_REG_INIT, val);
438
439         for_each_available_child_of_node(np, child) {
440                 int rc;
441                 u32 reg;
442
443                 if (of_property_read_u32(child, "reg", &reg))
444                         continue;
445
446                 if (reg >= BCM6328_LED_MAX_COUNT) {
447                         dev_err(dev, "invalid LED (%u >= %d)\n", reg,
448                                 BCM6328_LED_MAX_COUNT);
449                         continue;
450                 }
451
452                 if (of_property_read_bool(child, "brcm,hardware-controlled"))
453                         rc = bcm6328_hwled(dev, child, reg, mem, lock);
454                 else
455                         rc = bcm6328_led(dev, child, reg, mem, lock,
456                                          blink_leds, blink_delay);
457
458                 if (rc < 0) {
459                         of_node_put(child);
460                         return rc;
461                 }
462         }
463
464         return 0;
465 }
466
467 static const struct of_device_id bcm6328_leds_of_match[] = {
468         { .compatible = "brcm,bcm6328-leds", },
469         { },
470 };
471 MODULE_DEVICE_TABLE(of, bcm6328_leds_of_match);
472
473 static struct platform_driver bcm6328_leds_driver = {
474         .probe = bcm6328_leds_probe,
475         .driver = {
476                 .name = "leds-bcm6328",
477                 .of_match_table = bcm6328_leds_of_match,
478         },
479 };
480
481 module_platform_driver(bcm6328_leds_driver);
482
483 MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
484 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
485 MODULE_DESCRIPTION("LED driver for BCM6328 controllers");
486 MODULE_LICENSE("GPL v2");
487 MODULE_ALIAS("platform:leds-bcm6328");