Merge tag 'for-5.9-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[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 bcm6328_led *led;
332         const char *state;
333         int rc;
334
335         led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
336         if (!led)
337                 return -ENOMEM;
338
339         led->pin = reg;
340         led->mem = mem;
341         led->lock = lock;
342         led->blink_leds = blink_leds;
343         led->blink_delay = blink_delay;
344
345         if (of_property_read_bool(nc, "active-low"))
346                 led->active_low = true;
347
348         led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
349         led->cdev.default_trigger = of_get_property(nc,
350                                                     "linux,default-trigger",
351                                                     NULL);
352
353         if (!of_property_read_string(nc, "default-state", &state)) {
354                 if (!strcmp(state, "on")) {
355                         led->cdev.brightness = LED_FULL;
356                 } else if (!strcmp(state, "keep")) {
357                         void __iomem *mode;
358                         unsigned long val, shift;
359
360                         shift = bcm6328_pin2shift(led->pin);
361                         if (shift / 16)
362                                 mode = mem + BCM6328_REG_MODE_HI;
363                         else
364                                 mode = mem + BCM6328_REG_MODE_LO;
365
366                         val = bcm6328_led_read(mode) >>
367                               BCM6328_LED_SHIFT(shift % 16);
368                         val &= BCM6328_LED_MODE_MASK;
369                         if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
370                             (!led->active_low && val == BCM6328_LED_MODE_ON))
371                                 led->cdev.brightness = LED_FULL;
372                         else
373                                 led->cdev.brightness = LED_OFF;
374                 } else {
375                         led->cdev.brightness = LED_OFF;
376                 }
377         } else {
378                 led->cdev.brightness = LED_OFF;
379         }
380
381         bcm6328_led_set(&led->cdev, led->cdev.brightness);
382
383         led->cdev.brightness_set = bcm6328_led_set;
384         led->cdev.blink_set = bcm6328_blink_set;
385
386         rc = led_classdev_register(dev, &led->cdev);
387         if (rc < 0)
388                 return rc;
389
390         dev_dbg(dev, "registered LED %s\n", led->cdev.name);
391
392         return 0;
393 }
394
395 static int bcm6328_leds_probe(struct platform_device *pdev)
396 {
397         struct device *dev = &pdev->dev;
398         struct device_node *np = pdev->dev.of_node;
399         struct device_node *child;
400         void __iomem *mem;
401         spinlock_t *lock; /* memory lock */
402         unsigned long val, *blink_leds, *blink_delay;
403
404         mem = devm_platform_ioremap_resource(pdev, 0);
405         if (IS_ERR(mem))
406                 return PTR_ERR(mem);
407
408         lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
409         if (!lock)
410                 return -ENOMEM;
411
412         blink_leds = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
413                                   sizeof(*blink_leds), GFP_KERNEL);
414         if (!blink_leds)
415                 return -ENOMEM;
416
417         blink_delay = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS,
418                                    sizeof(*blink_delay), GFP_KERNEL);
419         if (!blink_delay)
420                 return -ENOMEM;
421
422         spin_lock_init(lock);
423
424         bcm6328_led_write(mem + BCM6328_REG_HWDIS, ~0);
425         bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_HI, 0);
426         bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
427
428         val = bcm6328_led_read(mem + BCM6328_REG_INIT);
429         val &= ~(BCM6328_INIT_MASK);
430         if (of_property_read_bool(np, "brcm,serial-leds"))
431                 val |= BCM6328_SERIAL_LED_EN;
432         if (of_property_read_bool(np, "brcm,serial-mux"))
433                 val |= BCM6328_SERIAL_LED_MUX;
434         if (of_property_read_bool(np, "brcm,serial-clk-low"))
435                 val |= BCM6328_SERIAL_LED_CLK_NPOL;
436         if (!of_property_read_bool(np, "brcm,serial-dat-low"))
437                 val |= BCM6328_SERIAL_LED_DATA_PPOL;
438         if (!of_property_read_bool(np, "brcm,serial-shift-inv"))
439                 val |= BCM6328_SERIAL_LED_SHIFT_DIR;
440         bcm6328_led_write(mem + BCM6328_REG_INIT, val);
441
442         for_each_available_child_of_node(np, child) {
443                 int rc;
444                 u32 reg;
445
446                 if (of_property_read_u32(child, "reg", &reg))
447                         continue;
448
449                 if (reg >= BCM6328_LED_MAX_COUNT) {
450                         dev_err(dev, "invalid LED (%u >= %d)\n", reg,
451                                 BCM6328_LED_MAX_COUNT);
452                         continue;
453                 }
454
455                 if (of_property_read_bool(child, "brcm,hardware-controlled"))
456                         rc = bcm6328_hwled(dev, child, reg, mem, lock);
457                 else
458                         rc = bcm6328_led(dev, child, reg, mem, lock,
459                                          blink_leds, blink_delay);
460
461                 if (rc < 0) {
462                         of_node_put(child);
463                         return rc;
464                 }
465         }
466
467         return 0;
468 }
469
470 static const struct of_device_id bcm6328_leds_of_match[] = {
471         { .compatible = "brcm,bcm6328-leds", },
472         { },
473 };
474 MODULE_DEVICE_TABLE(of, bcm6328_leds_of_match);
475
476 static struct platform_driver bcm6328_leds_driver = {
477         .probe = bcm6328_leds_probe,
478         .driver = {
479                 .name = "leds-bcm6328",
480                 .of_match_table = bcm6328_leds_of_match,
481         },
482 };
483
484 module_platform_driver(bcm6328_leds_driver);
485
486 MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
487 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
488 MODULE_DESCRIPTION("LED driver for BCM6328 controllers");
489 MODULE_LICENSE("GPL v2");
490 MODULE_ALIAS("platform:leds-bcm6328");