1 // SPDX-License-Identifier: GPL-2.0-only
5 #include <linux/delay.h>
7 #include <linux/leds.h>
8 #include <linux/module.h>
10 #include <linux/pinctrl/consumer.h>
11 #include <linux/platform_device.h>
12 #include <linux/spinlock.h>
14 #define BCM63138_MAX_LEDS 32
15 #define BCM63138_MAX_BRIGHTNESS 9
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 */
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
47 struct bcm63138_leds {
54 struct bcm63138_leds *leds;
55 struct led_classdev cdev;
64 static void bcm63138_leds_write(struct bcm63138_leds *leds, unsigned int reg,
67 writel(data, leds->base + reg);
70 static unsigned long bcm63138_leds_read(struct bcm63138_leds *leds,
73 return readl(leds->base + reg);
76 static void bcm63138_leds_update_bits(struct bcm63138_leds *leds,
77 unsigned int reg, u32 mask, u32 val)
81 bcm63138_leds_write(leds, reg, (bcm63138_leds_read(leds, reg) & ~mask) | (val & mask));
88 static void bcm63138_leds_set_flash_rate(struct bcm63138_leds *leds,
89 struct bcm63138_led *led,
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;
95 bcm63138_leds_update_bits(leds, BCM63138_FLASH_RATE_CTRL1 + reg_offset,
96 BCM63138_LED_MASK << shift, value << shift);
99 static void bcm63138_leds_set_bright(struct bcm63138_leds *leds,
100 struct bcm63138_led *led,
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;
106 bcm63138_leds_update_bits(leds, BCM63138_BRIGHT_CTRL1 + reg_offset,
107 BCM63138_LED_MASK << shift, value << shift);
110 static void bcm63138_leds_enable_led(struct bcm63138_leds *leds,
111 struct bcm63138_led *led,
112 enum led_brightness value)
114 u32 bit = BIT(led->pin);
116 bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, value ? bit : 0);
123 static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev,
124 enum led_brightness value)
126 struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
127 struct bcm63138_leds *leds = led->leds;
130 spin_lock_irqsave(&leds->lock, flags);
132 bcm63138_leds_enable_led(leds, led, value);
134 bcm63138_leds_set_flash_rate(leds, led, 0);
136 bcm63138_leds_set_bright(leds, led, value);
138 spin_unlock_irqrestore(&leds->lock, flags);
141 static int bcm63138_leds_blink_set(struct led_classdev *led_cdev,
142 unsigned long *delay_on,
143 unsigned long *delay_off)
145 struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
146 struct bcm63138_leds *leds = led->leds;
150 if (!*delay_on && !*delay_off) {
155 if (*delay_on != *delay_off) {
156 dev_dbg(led_cdev->dev, "Blinking at unequal delays is not supported\n");
161 case 1152 ... 1408: /* 1280 ms ± 10% */
164 case 576 ... 704: /* 640 ms ± 10% */
167 case 288 ... 352: /* 320 ms ± 10% */
170 case 126 ... 154: /* 140 ms ± 10% */
173 case 59 ... 72: /* 65 ms ± 10% */
177 dev_dbg(led_cdev->dev, "Blinking delay value %lu is unsupported\n",
182 spin_lock_irqsave(&leds->lock, flags);
184 bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS);
185 bcm63138_leds_set_flash_rate(leds, led, value);
187 spin_unlock_irqrestore(&leds->lock, flags);
196 static void bcm63138_leds_create_led(struct bcm63138_leds *leds,
197 struct device_node *np)
199 struct led_init_data init_data = {
200 .fwnode = of_fwnode_handle(np),
202 struct device *dev = leds->dev;
203 struct bcm63138_led *led;
204 struct pinctrl *pinctrl;
208 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
210 dev_err(dev, "Failed to alloc LED\n");
216 if (of_property_read_u32(np, "reg", &led->pin)) {
217 dev_err(dev, "Missing \"reg\" property in %pOF\n", np);
221 if (led->pin >= BCM63138_MAX_LEDS) {
222 dev_err(dev, "Invalid \"reg\" value %d\n", led->pin);
226 led->active_low = of_property_read_bool(np, "active-low");
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;
232 err = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
234 dev_err(dev, "Failed to register LED %pOF: %d\n", np, err);
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));
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);
254 devm_kfree(dev, led);
257 static int bcm63138_leds_probe(struct platform_device *pdev)
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;
264 leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
270 leds->base = devm_platform_ioremap_resource(pdev, 0);
271 if (IS_ERR(leds->base))
272 return PTR_ERR(leds->base);
274 spin_lock_init(&leds->lock);
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);
283 for_each_available_child_of_node(np, child) {
284 bcm63138_leds_create_led(leds, child);
290 static const struct of_device_id bcm63138_leds_of_match_table[] = {
291 { .compatible = "brcm,bcm63138-leds", },
295 static struct platform_driver bcm63138_leds_driver = {
296 .probe = bcm63138_leds_probe,
298 .name = "leds-bcm63xxx",
299 .of_match_table = bcm63138_leds_of_match_table,
303 module_platform_driver(bcm63138_leds_driver);
305 MODULE_AUTHOR("Rafał Miłecki");
306 MODULE_LICENSE("GPL");
307 MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table);