5 * Copyright (c) 2012, Meraki, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/platform_device.h>
18 #include <linux/leds.h>
19 #include <linux/workqueue.h>
20 #include <linux/delay.h>
21 #include <linux/leds-nu801.h>
23 #include <linux/gpio.h>
24 #include <linux/of_gpio.h>
26 #define MAX_NAME_LENGTH 24
29 static const char * const led_nu801_colors
[] = { "blue", "green", "red" };
31 struct led_nu801_led_data
{
32 struct led_classdev cdev
;
33 struct led_nu801_data
*controller
;
34 enum led_brightness level
;
35 char name
[MAX_NAME_LENGTH
];
38 struct led_nu801_data
{
42 struct delayed_work work
;
43 struct led_nu801_led_data
*led_chain
;
45 const char *device_name
;
51 static void led_nu801_work(struct work_struct
*work
)
53 struct led_nu801_data
*controller
=
54 container_of(work
, struct led_nu801_data
, work
.work
);
55 struct led_nu801_led_data
*led
;
60 for (index
= 0; index
< controller
->num_leds
; index
++) {
61 led
= &controller
->led_chain
[index
];
62 brightness
= led
->level
<< 8; /* To do: gamma correction */
63 for (bit
= 0x8000; bit
; bit
= bit
>> 1) {
64 gpio_set_value(controller
->sdi
,
65 (brightness
& bit
) != 0);
66 gpio_set_value(controller
->cki
, 1);
67 if (unlikely(((index
== (controller
->num_leds
- 1)) &&
69 (controller
->lei
< 0)))) {
72 ndelay(controller
->ndelay
);
74 gpio_set_value(controller
->cki
, 0);
75 ndelay(controller
->ndelay
);
78 if (controller
->lei
>= 0) {
79 gpio_set_value(controller
->lei
, 1);
80 ndelay(controller
->ndelay
);
81 gpio_set_value(controller
->lei
, 0);
83 atomic_set(&controller
->pending
, 1);
86 static void led_nu801_set(struct led_classdev
*led_cdev
,
87 enum led_brightness value
)
89 struct led_nu801_led_data
*led_dat
=
90 container_of(led_cdev
, struct led_nu801_led_data
, cdev
);
91 struct led_nu801_data
*controller
= led_dat
->controller
;
93 if (led_dat
->level
!= value
) {
94 led_dat
->level
= value
;
95 if (atomic_dec_and_test(&controller
->pending
))
96 schedule_delayed_work(&led_dat
->controller
->work
,
101 static int __init
led_nu801_create(struct led_nu801_data
*controller
,
102 struct device
*parent
,
104 enum led_brightness brightness
,
105 #ifdef CONFIG_LEDS_TRIGGERS
106 const char *default_trigger
,
110 struct led_nu801_led_data
*led
= &controller
->led_chain
[index
];
113 scnprintf(led
->name
, sizeof(led
->name
), "%s:%s:%s%d",
114 controller
->device_name
, color
, controller
->name
,
115 (controller
->num_leds
- (index
+ 1)) / NUM_COLORS
);
116 led
->cdev
.name
= led
->name
;
117 led
->cdev
.brightness_set
= led_nu801_set
;
118 #ifdef CONFIG_LEDS_TRIGGERS
119 led
->cdev
.default_trigger
= default_trigger
;
121 led
->level
= brightness
;
122 led
->controller
= controller
;
123 ret
= led_classdev_register(parent
, &led
->cdev
);
135 led_nu801_create_chain(const struct led_nu801_template
*template,
136 struct led_nu801_data
*controller
,
137 struct device
*parent
)
142 controller
->cki
= template->cki
;
143 controller
->sdi
= template->sdi
;
144 controller
->lei
= template->lei
;
145 controller
->num_leds
= template->num_leds
* 3;
146 controller
->device_name
= template->device_name
;
147 controller
->name
= template->name
;
148 controller
->ndelay
= template->ndelay
;
149 atomic_set(&controller
->pending
, 1);
151 controller
->led_chain
= kzalloc(sizeof(struct led_nu801_led_data
) *
152 controller
->num_leds
, GFP_KERNEL
);
154 if (!controller
->led_chain
)
157 ret
= gpio_request(controller
->cki
, template->name
);
161 ret
= gpio_request(controller
->sdi
, template->name
);
165 if (controller
->lei
>= 0) {
166 ret
= gpio_request(controller
->lei
, template->name
);
169 ret
= gpio_direction_output(controller
->lei
, 0);
174 ret
= gpio_direction_output(controller
->cki
, 0);
178 ret
= gpio_direction_output(controller
->sdi
, 0);
182 for (index
= 0; index
< controller
->num_leds
; index
++) {
183 ret
= led_nu801_create(controller
, parent
, index
,
184 template->init_brightness
185 [index
% NUM_COLORS
],
186 #ifdef CONFIG_LEDS_TRIGGERS
187 template->default_trigger
,
189 template->led_colors
[index
% NUM_COLORS
] ?
190 template->led_colors
[index
% NUM_COLORS
] :
191 led_nu801_colors
[index
% NUM_COLORS
]);
196 INIT_DELAYED_WORK(&controller
->work
, led_nu801_work
);
197 schedule_delayed_work(&controller
->work
, 0);
202 if (controller
->lei
>= 0)
203 gpio_free(controller
->lei
);
205 gpio_free(controller
->sdi
);
207 gpio_free(controller
->cki
);
209 kfree(controller
->led_chain
);
214 static void led_nu801_delete_chain(struct led_nu801_data
*controller
)
216 struct led_nu801_led_data
*led_chain
;
217 struct led_nu801_led_data
*led
;
221 led_chain
= controller
->led_chain
;
222 controller
->led_chain
= 0;
223 num_leds
= controller
->num_leds
;
224 controller
->num_leds
= 0;
225 cancel_delayed_work_sync(&controller
->work
);
227 for (index
= 0; index
< num_leds
; index
++) {
228 led
= &led_chain
[index
];
229 led_classdev_unregister(&led
->cdev
);
232 gpio_free(controller
->cki
);
233 gpio_free(controller
->sdi
);
234 if (controller
->lei
>= 0)
235 gpio_free(controller
->lei
);
240 static struct led_nu801_data
* __init
241 leds_nu801_create_of(struct platform_device
*pdev
)
243 struct device_node
*np
= pdev
->dev
.of_node
, *child
;
244 struct led_nu801_data
*controllers
;
248 for_each_child_of_node(np
, child
)
253 controllers
= kzalloc(sizeof(struct led_nu801_data
) * count
,
258 for_each_child_of_node(np
, child
) {
260 struct led_nu801_template
template = {};
261 struct device_node
*colors
;
264 template.cki
= of_get_named_gpio_flags(child
, "cki", 0, NULL
);
265 template.sdi
= of_get_named_gpio_flags(child
, "sdi", 0, NULL
);
266 if (of_find_property(child
, "lei", NULL
)) {
267 template.lei
= of_get_named_gpio_flags(child
, "lei",
272 of_property_read_u32(child
, "ndelay", &template.ndelay
);
273 of_property_read_u32(child
, "num_leds", &template.num_leds
);
274 template.name
= of_get_property(child
, "label", NULL
) ? :
276 template.default_trigger
= of_get_property(child
,
277 "default-trigger", NULL
);
280 for_each_child_of_node(child
, colors
) {
281 template.led_colors
[jj
] = of_get_property(colors
,
283 state
= of_get_property(colors
, "state", NULL
);
284 if (!strncmp(state
, "off", 3))
285 template.init_brightness
[jj
] = LED_OFF
;
286 else if (!strncmp(state
, "half", 4))
287 template.init_brightness
[jj
] = LED_HALF
;
288 else if (!strncmp(state
, "full", 4))
289 template.init_brightness
[jj
] = LED_FULL
;
293 ret
= led_nu801_create_chain(&template,
304 for (i
= i
- 1; i
>= 0; i
--)
305 led_nu801_delete_chain(&controllers
[i
]);
310 static int __init
led_nu801_probe(struct platform_device
*pdev
)
312 struct led_nu801_platform_data
*pdata
= pdev
->dev
.platform_data
;
313 struct led_nu801_data
*controllers
;
316 if (!(pdata
&& pdata
->num_controllers
)) {
317 controllers
= leds_nu801_create_of(pdev
);
322 controllers
= kzalloc(sizeof(struct led_nu801_data
) *
323 pdata
->num_controllers
, GFP_KERNEL
);
327 for (i
= 0; i
< pdata
->num_controllers
; i
++) {
328 ret
= led_nu801_create_chain(&pdata
->template[i
],
335 platform_set_drvdata(pdev
, controllers
);
340 for (i
= i
- 1; i
>= 0; i
--)
341 led_nu801_delete_chain(&controllers
[i
]);
348 static int led_nu801_remove(struct platform_device
*pdev
)
351 struct led_nu801_platform_data
*pdata
= pdev
->dev
.platform_data
;
352 struct led_nu801_data
*controllers
;
354 controllers
= platform_get_drvdata(pdev
);
356 for (i
= 0; i
< pdata
->num_controllers
; i
++)
357 led_nu801_delete_chain(&controllers
[i
]);
364 static const struct of_device_id of_numen_leds_match
[] = {
365 { .compatible
= "numen,leds-nu801", },
368 MODULE_DEVICE_TABLE(of
, of_pwm_leds_match
);
370 static struct platform_driver led_nu801_driver
= {
371 .probe
= led_nu801_probe
,
372 .remove
= led_nu801_remove
,
374 .name
= "leds-nu801",
375 .owner
= THIS_MODULE
,
376 .of_match_table
= of_numen_leds_match
,
380 static int __init
led_nu801_init(void)
382 return platform_driver_register(&led_nu801_driver
);
385 static void __exit
led_nu801_exit(void)
387 platform_driver_unregister(&led_nu801_driver
);
390 module_init(led_nu801_init
);
391 module_exit(led_nu801_exit
);
393 MODULE_AUTHOR("Kevin Paul Herbert <kph@meraki.net>");
394 MODULE_DESCRIPTION("NU801 LED driver");
395 MODULE_LICENSE("GPL v2");
396 MODULE_ALIAS("platform:leds-nu801");