drm/nouveau/debugfs: Replace five seq_printf() calls by seq_puts() in nouveau_debugfs...
[linux-2.6-microblaze.git] / drivers / leds / blink / leds-bcm63138.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
4  */
5 #include <linux/delay.h>
6 #include <linux/io.h>
7 #include <linux/leds.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/pinctrl/consumer.h>
11 #include <linux/platform_device.h>
12 #include <linux/spinlock.h>
13
14 #define BCM63138_MAX_LEDS                               32
15 #define BCM63138_MAX_BRIGHTNESS                         9
16
17 #define BCM63138_LED_BITS                               4                               /* how many bits control a single LED */
18 #define BCM63138_LED_MASK                               ((1 << BCM63138_LED_BITS) - 1)  /* 0xf */
19 #define BCM63138_LEDS_PER_REG                           (32 / BCM63138_LED_BITS)        /* 8 */
20
21 #define BCM63138_GLB_CTRL                               0x00
22 #define  BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL         0x00000002
23 #define  BCM63138_GLB_CTRL_SERIAL_LED_EN_POL            0x00000008
24 #define BCM63138_MASK                                   0x04
25 #define BCM63138_HW_LED_EN                              0x08
26 #define BCM63138_SERIAL_LED_SHIFT_SEL                   0x0c
27 #define BCM63138_FLASH_RATE_CTRL1                       0x10
28 #define BCM63138_FLASH_RATE_CTRL2                       0x14
29 #define BCM63138_FLASH_RATE_CTRL3                       0x18
30 #define BCM63138_FLASH_RATE_CTRL4                       0x1c
31 #define BCM63138_BRIGHT_CTRL1                           0x20
32 #define BCM63138_BRIGHT_CTRL2                           0x24
33 #define BCM63138_BRIGHT_CTRL3                           0x28
34 #define BCM63138_BRIGHT_CTRL4                           0x2c
35 #define BCM63138_POWER_LED_CFG                          0x30
36 #define BCM63138_HW_POLARITY                            0xb4
37 #define BCM63138_SW_DATA                                0xb8
38 #define BCM63138_SW_POLARITY                            0xbc
39 #define BCM63138_PARALLEL_LED_POLARITY                  0xc0
40 #define BCM63138_SERIAL_LED_POLARITY                    0xc4
41 #define BCM63138_HW_LED_STATUS                          0xc8
42 #define BCM63138_FLASH_CTRL_STATUS                      0xcc
43 #define BCM63138_FLASH_BRT_CTRL                         0xd0
44 #define BCM63138_FLASH_P_LED_OUT_STATUS                 0xd4
45 #define BCM63138_FLASH_S_LED_OUT_STATUS                 0xd8
46
47 struct bcm63138_leds {
48         struct device *dev;
49         void __iomem *base;
50         spinlock_t lock;
51 };
52
53 struct bcm63138_led {
54         struct bcm63138_leds *leds;
55         struct led_classdev cdev;
56         u32 pin;
57         bool active_low;
58 };
59
60 /*
61  * I/O access
62  */
63
64 static void bcm63138_leds_write(struct bcm63138_leds *leds, unsigned int reg,
65                                 u32 data)
66 {
67         writel(data, leds->base + reg);
68 }
69
70 static unsigned long bcm63138_leds_read(struct bcm63138_leds *leds,
71                                         unsigned int reg)
72 {
73         return readl(leds->base + reg);
74 }
75
76 static void bcm63138_leds_update_bits(struct bcm63138_leds *leds,
77                                       unsigned int reg, u32 mask, u32 val)
78 {
79         WARN_ON(val & ~mask);
80
81         bcm63138_leds_write(leds, reg, (bcm63138_leds_read(leds, reg) & ~mask) | (val & mask));
82 }
83
84 /*
85  * Helpers
86  */
87
88 static void bcm63138_leds_set_flash_rate(struct bcm63138_leds *leds,
89                                          struct bcm63138_led *led,
90                                          u8 value)
91 {
92         int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4;
93         int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS;
94
95         bcm63138_leds_update_bits(leds, BCM63138_FLASH_RATE_CTRL1 + reg_offset,
96                                   BCM63138_LED_MASK << shift, value << shift);
97 }
98
99 static void bcm63138_leds_set_bright(struct bcm63138_leds *leds,
100                                      struct bcm63138_led *led,
101                                      u8 value)
102 {
103         int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4;
104         int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS;
105
106         bcm63138_leds_update_bits(leds, BCM63138_BRIGHT_CTRL1 + reg_offset,
107                                   BCM63138_LED_MASK << shift, value << shift);
108 }
109
110 static void bcm63138_leds_enable_led(struct bcm63138_leds *leds,
111                                      struct bcm63138_led *led,
112                                      enum led_brightness value)
113 {
114         u32 bit = BIT(led->pin);
115
116         bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, value ? bit : 0);
117 }
118
119 /*
120  * API callbacks
121  */
122
123 static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev,
124                                          enum led_brightness value)
125 {
126         struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
127         struct bcm63138_leds *leds = led->leds;
128         unsigned long flags;
129
130         spin_lock_irqsave(&leds->lock, flags);
131
132         bcm63138_leds_enable_led(leds, led, value);
133         if (!value)
134                 bcm63138_leds_set_flash_rate(leds, led, 0);
135         else
136                 bcm63138_leds_set_bright(leds, led, value);
137
138         spin_unlock_irqrestore(&leds->lock, flags);
139 }
140
141 static int bcm63138_leds_blink_set(struct led_classdev *led_cdev,
142                                    unsigned long *delay_on,
143                                    unsigned long *delay_off)
144 {
145         struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
146         struct bcm63138_leds *leds = led->leds;
147         unsigned long flags;
148         u8 value;
149
150         if (!*delay_on && !*delay_off) {
151                 *delay_on = 640;
152                 *delay_off = 640;
153         }
154
155         if (*delay_on != *delay_off) {
156                 dev_dbg(led_cdev->dev, "Blinking at unequal delays is not supported\n");
157                 return -EINVAL;
158         }
159
160         switch (*delay_on) {
161         case 1152 ... 1408: /* 1280 ms ± 10% */
162                 value = 0x7;
163                 break;
164         case 576 ... 704: /* 640 ms ± 10% */
165                 value = 0x6;
166                 break;
167         case 288 ... 352: /* 320 ms ± 10% */
168                 value = 0x5;
169                 break;
170         case 126 ... 154: /* 140 ms ± 10% */
171                 value = 0x4;
172                 break;
173         case 59 ... 72: /* 65 ms ± 10% */
174                 value = 0x3;
175                 break;
176         default:
177                 dev_dbg(led_cdev->dev, "Blinking delay value %lu is unsupported\n",
178                         *delay_on);
179                 return -EINVAL;
180         }
181
182         spin_lock_irqsave(&leds->lock, flags);
183
184         bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS);
185         bcm63138_leds_set_flash_rate(leds, led, value);
186
187         spin_unlock_irqrestore(&leds->lock, flags);
188
189         return 0;
190 }
191
192 /*
193  * LED driver
194  */
195
196 static void bcm63138_leds_create_led(struct bcm63138_leds *leds,
197                                      struct device_node *np)
198 {
199         struct led_init_data init_data = {
200                 .fwnode = of_fwnode_handle(np),
201         };
202         struct device *dev = leds->dev;
203         struct bcm63138_led *led;
204         struct pinctrl *pinctrl;
205         u32 bit;
206         int err;
207
208         led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
209         if (!led) {
210                 dev_err(dev, "Failed to alloc LED\n");
211                 return;
212         }
213
214         led->leds = leds;
215
216         if (of_property_read_u32(np, "reg", &led->pin)) {
217                 dev_err(dev, "Missing \"reg\" property in %pOF\n", np);
218                 goto err_free;
219         }
220
221         if (led->pin >= BCM63138_MAX_LEDS) {
222                 dev_err(dev, "Invalid \"reg\" value %d\n", led->pin);
223                 goto err_free;
224         }
225
226         led->active_low = of_property_read_bool(np, "active-low");
227
228         led->cdev.max_brightness = BCM63138_MAX_BRIGHTNESS;
229         led->cdev.brightness_set = bcm63138_leds_brightness_set;
230         led->cdev.blink_set = bcm63138_leds_blink_set;
231
232         err = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
233         if (err) {
234                 dev_err(dev, "Failed to register LED %pOF: %d\n", np, err);
235                 goto err_free;
236         }
237
238         pinctrl = devm_pinctrl_get_select_default(led->cdev.dev);
239         if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) {
240                 dev_warn(led->cdev.dev, "Failed to select %pOF pinctrl: %ld\n",
241                          np, PTR_ERR(pinctrl));
242         }
243
244         bit = BIT(led->pin);
245         bcm63138_leds_update_bits(leds, BCM63138_PARALLEL_LED_POLARITY, bit,
246                                   led->active_low ? 0 : bit);
247         bcm63138_leds_update_bits(leds, BCM63138_HW_LED_EN, bit, 0);
248         bcm63138_leds_set_flash_rate(leds, led, 0);
249         bcm63138_leds_enable_led(leds, led, led->cdev.brightness);
250
251         return;
252
253 err_free:
254         devm_kfree(dev, led);
255 }
256
257 static int bcm63138_leds_probe(struct platform_device *pdev)
258 {
259         struct device_node *np = dev_of_node(&pdev->dev);
260         struct device *dev = &pdev->dev;
261         struct bcm63138_leds *leds;
262         struct device_node *child;
263
264         leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
265         if (!leds)
266                 return -ENOMEM;
267
268         leds->dev = dev;
269
270         leds->base = devm_platform_ioremap_resource(pdev, 0);
271         if (IS_ERR(leds->base))
272                 return PTR_ERR(leds->base);
273
274         spin_lock_init(&leds->lock);
275
276         bcm63138_leds_write(leds, BCM63138_GLB_CTRL,
277                             BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL |
278                             BCM63138_GLB_CTRL_SERIAL_LED_EN_POL);
279         bcm63138_leds_write(leds, BCM63138_HW_LED_EN, 0);
280         bcm63138_leds_write(leds, BCM63138_SERIAL_LED_POLARITY, 0);
281         bcm63138_leds_write(leds, BCM63138_PARALLEL_LED_POLARITY, 0);
282
283         for_each_available_child_of_node(np, child) {
284                 bcm63138_leds_create_led(leds, child);
285         }
286
287         return 0;
288 }
289
290 static const struct of_device_id bcm63138_leds_of_match_table[] = {
291         { .compatible = "brcm,bcm63138-leds", },
292         { },
293 };
294
295 static struct platform_driver bcm63138_leds_driver = {
296         .probe = bcm63138_leds_probe,
297         .driver = {
298                 .name = "leds-bcm63xxx",
299                 .of_match_table = bcm63138_leds_of_match_table,
300         },
301 };
302
303 module_platform_driver(bcm63138_leds_driver);
304
305 MODULE_AUTHOR("Rafał Miłecki");
306 MODULE_LICENSE("GPL");
307 MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table);