1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
5 * Copyright (C) 2010 LaCie
7 * Author: Simon Guinot <sguinot@lacie.com>
10 #include <linux/module.h>
11 #include <linux/irq.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/platform_device.h>
15 #include <linux/gpio.h>
16 #include <linux/of_gpio.h>
17 #include <linux/leds.h>
19 struct netxbig_gpio_ext
{
27 enum netxbig_led_mode
{
36 #define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
38 struct netxbig_led_timer
{
39 unsigned long delay_on
;
40 unsigned long delay_off
;
41 enum netxbig_led_mode mode
;
46 const char *default_trigger
;
53 struct netxbig_led_platform_data
{
54 struct netxbig_gpio_ext
*gpio_ext
;
55 struct netxbig_led_timer
*timer
;
57 struct netxbig_led
*leds
;
65 static DEFINE_SPINLOCK(gpio_ext_lock
);
67 static void gpio_ext_set_addr(struct netxbig_gpio_ext
*gpio_ext
, int addr
)
71 for (pin
= 0; pin
< gpio_ext
->num_addr
; pin
++)
72 gpio_set_value(gpio_ext
->addr
[pin
], (addr
>> pin
) & 1);
75 static void gpio_ext_set_data(struct netxbig_gpio_ext
*gpio_ext
, int data
)
79 for (pin
= 0; pin
< gpio_ext
->num_data
; pin
++)
80 gpio_set_value(gpio_ext
->data
[pin
], (data
>> pin
) & 1);
83 static void gpio_ext_enable_select(struct netxbig_gpio_ext
*gpio_ext
)
85 /* Enable select is done on the raising edge. */
86 gpio_set_value(gpio_ext
->enable
, 0);
87 gpio_set_value(gpio_ext
->enable
, 1);
90 static void gpio_ext_set_value(struct netxbig_gpio_ext
*gpio_ext
,
95 spin_lock_irqsave(&gpio_ext_lock
, flags
);
96 gpio_ext_set_addr(gpio_ext
, addr
);
97 gpio_ext_set_data(gpio_ext
, value
);
98 gpio_ext_enable_select(gpio_ext
);
99 spin_unlock_irqrestore(&gpio_ext_lock
, flags
);
102 static int gpio_ext_init(struct platform_device
*pdev
,
103 struct netxbig_gpio_ext
*gpio_ext
)
108 if (unlikely(!gpio_ext
))
111 /* Configure address GPIOs. */
112 for (i
= 0; i
< gpio_ext
->num_addr
; i
++) {
113 err
= devm_gpio_request_one(&pdev
->dev
, gpio_ext
->addr
[i
],
115 "GPIO extension addr");
119 /* Configure data GPIOs. */
120 for (i
= 0; i
< gpio_ext
->num_data
; i
++) {
121 err
= devm_gpio_request_one(&pdev
->dev
, gpio_ext
->data
[i
],
123 "GPIO extension data");
127 /* Configure "enable select" GPIO. */
128 err
= devm_gpio_request_one(&pdev
->dev
, gpio_ext
->enable
,
130 "GPIO extension enable");
141 struct netxbig_led_data
{
142 struct netxbig_gpio_ext
*gpio_ext
;
143 struct led_classdev cdev
;
147 struct netxbig_led_timer
*timer
;
149 enum netxbig_led_mode mode
;
154 static int netxbig_led_get_timer_mode(enum netxbig_led_mode
*mode
,
155 unsigned long delay_on
,
156 unsigned long delay_off
,
157 struct netxbig_led_timer
*timer
,
162 for (i
= 0; i
< num_timer
; i
++) {
163 if (timer
[i
].delay_on
== delay_on
&&
164 timer
[i
].delay_off
== delay_off
) {
165 *mode
= timer
[i
].mode
;
172 static int netxbig_led_blink_set(struct led_classdev
*led_cdev
,
173 unsigned long *delay_on
,
174 unsigned long *delay_off
)
176 struct netxbig_led_data
*led_dat
=
177 container_of(led_cdev
, struct netxbig_led_data
, cdev
);
178 enum netxbig_led_mode mode
;
182 /* Look for a LED mode with the requested timer frequency. */
183 ret
= netxbig_led_get_timer_mode(&mode
, *delay_on
, *delay_off
,
184 led_dat
->timer
, led_dat
->num_timer
);
188 mode_val
= led_dat
->mode_val
[mode
];
189 if (mode_val
== NETXBIG_LED_INVALID_MODE
)
192 spin_lock_irq(&led_dat
->lock
);
194 gpio_ext_set_value(led_dat
->gpio_ext
, led_dat
->mode_addr
, mode_val
);
195 led_dat
->mode
= mode
;
197 spin_unlock_irq(&led_dat
->lock
);
202 static void netxbig_led_set(struct led_classdev
*led_cdev
,
203 enum led_brightness value
)
205 struct netxbig_led_data
*led_dat
=
206 container_of(led_cdev
, struct netxbig_led_data
, cdev
);
207 enum netxbig_led_mode mode
;
209 int set_brightness
= 1;
212 spin_lock_irqsave(&led_dat
->lock
, flags
);
214 if (value
== LED_OFF
) {
215 mode
= NETXBIG_LED_OFF
;
219 mode
= NETXBIG_LED_SATA
;
220 else if (led_dat
->mode
== NETXBIG_LED_OFF
)
221 mode
= NETXBIG_LED_ON
;
222 else /* Keep 'timer' mode. */
223 mode
= led_dat
->mode
;
225 mode_val
= led_dat
->mode_val
[mode
];
227 gpio_ext_set_value(led_dat
->gpio_ext
, led_dat
->mode_addr
, mode_val
);
228 led_dat
->mode
= mode
;
230 * Note that the brightness register is shared between all the
231 * SATA LEDs. So, change the brightness setting for a single
232 * SATA LED will affect all the others.
235 gpio_ext_set_value(led_dat
->gpio_ext
,
236 led_dat
->bright_addr
, value
);
238 spin_unlock_irqrestore(&led_dat
->lock
, flags
);
241 static ssize_t
netxbig_led_sata_store(struct device
*dev
,
242 struct device_attribute
*attr
,
243 const char *buff
, size_t count
)
245 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
246 struct netxbig_led_data
*led_dat
=
247 container_of(led_cdev
, struct netxbig_led_data
, cdev
);
248 unsigned long enable
;
249 enum netxbig_led_mode mode
;
253 ret
= kstrtoul(buff
, 10, &enable
);
259 spin_lock_irq(&led_dat
->lock
);
261 if (led_dat
->sata
== enable
) {
266 if (led_dat
->mode
!= NETXBIG_LED_ON
&&
267 led_dat
->mode
!= NETXBIG_LED_SATA
)
268 mode
= led_dat
->mode
; /* Keep modes 'off' and 'timer'. */
270 mode
= NETXBIG_LED_SATA
;
272 mode
= NETXBIG_LED_ON
;
274 mode_val
= led_dat
->mode_val
[mode
];
275 if (mode_val
== NETXBIG_LED_INVALID_MODE
) {
280 gpio_ext_set_value(led_dat
->gpio_ext
, led_dat
->mode_addr
, mode_val
);
281 led_dat
->mode
= mode
;
282 led_dat
->sata
= enable
;
287 spin_unlock_irq(&led_dat
->lock
);
292 static ssize_t
netxbig_led_sata_show(struct device
*dev
,
293 struct device_attribute
*attr
, char *buf
)
295 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
296 struct netxbig_led_data
*led_dat
=
297 container_of(led_cdev
, struct netxbig_led_data
, cdev
);
299 return sprintf(buf
, "%d\n", led_dat
->sata
);
302 static DEVICE_ATTR(sata
, 0644, netxbig_led_sata_show
, netxbig_led_sata_store
);
304 static struct attribute
*netxbig_led_attrs
[] = {
308 ATTRIBUTE_GROUPS(netxbig_led
);
310 static int create_netxbig_led(struct platform_device
*pdev
,
311 struct netxbig_led_platform_data
*pdata
,
312 struct netxbig_led_data
*led_dat
,
313 const struct netxbig_led
*template)
315 spin_lock_init(&led_dat
->lock
);
316 led_dat
->gpio_ext
= pdata
->gpio_ext
;
317 led_dat
->cdev
.name
= template->name
;
318 led_dat
->cdev
.default_trigger
= template->default_trigger
;
319 led_dat
->cdev
.blink_set
= netxbig_led_blink_set
;
320 led_dat
->cdev
.brightness_set
= netxbig_led_set
;
322 * Because the GPIO extension bus don't allow to read registers
323 * value, there is no way to probe the LED initial state.
324 * So, the initial sysfs LED value for the "brightness" and "sata"
325 * attributes are inconsistent.
327 * Note that the initial LED state can't be reconfigured.
328 * The reason is that the LED behaviour must stay uniform during
329 * the whole boot process (bootloader+linux).
332 led_dat
->cdev
.brightness
= LED_OFF
;
333 led_dat
->cdev
.max_brightness
= template->bright_max
;
334 led_dat
->cdev
.flags
|= LED_CORE_SUSPENDRESUME
;
335 led_dat
->mode_addr
= template->mode_addr
;
336 led_dat
->mode_val
= template->mode_val
;
337 led_dat
->bright_addr
= template->bright_addr
;
338 led_dat
->timer
= pdata
->timer
;
339 led_dat
->num_timer
= pdata
->num_timer
;
341 * If available, expose the SATA activity blink capability through
342 * a "sata" sysfs attribute.
344 if (led_dat
->mode_val
[NETXBIG_LED_SATA
] != NETXBIG_LED_INVALID_MODE
)
345 led_dat
->cdev
.groups
= netxbig_led_groups
;
347 return devm_led_classdev_register(&pdev
->dev
, &led_dat
->cdev
);
350 static int gpio_ext_get_of_pdata(struct device
*dev
, struct device_node
*np
,
351 struct netxbig_gpio_ext
*gpio_ext
)
354 int num_addr
, num_data
;
358 ret
= of_gpio_named_count(np
, "addr-gpios");
361 "Failed to count GPIOs in DT property addr-gpios\n");
365 addr
= devm_kcalloc(dev
, num_addr
, sizeof(*addr
), GFP_KERNEL
);
369 for (i
= 0; i
< num_addr
; i
++) {
370 ret
= of_get_named_gpio(np
, "addr-gpios", i
);
375 gpio_ext
->addr
= addr
;
376 gpio_ext
->num_addr
= num_addr
;
378 ret
= of_gpio_named_count(np
, "data-gpios");
381 "Failed to count GPIOs in DT property data-gpios\n");
385 data
= devm_kcalloc(dev
, num_data
, sizeof(*data
), GFP_KERNEL
);
389 for (i
= 0; i
< num_data
; i
++) {
390 ret
= of_get_named_gpio(np
, "data-gpios", i
);
395 gpio_ext
->data
= data
;
396 gpio_ext
->num_data
= num_data
;
398 ret
= of_get_named_gpio(np
, "enable-gpio", 0);
401 "Failed to get GPIO from DT property enable-gpio\n");
404 gpio_ext
->enable
= ret
;
409 static int netxbig_leds_get_of_pdata(struct device
*dev
,
410 struct netxbig_led_platform_data
*pdata
)
412 struct device_node
*np
= dev
->of_node
;
413 struct device_node
*gpio_ext_np
;
414 struct device_node
*child
;
415 struct netxbig_gpio_ext
*gpio_ext
;
416 struct netxbig_led_timer
*timers
;
417 struct netxbig_led
*leds
, *led
;
424 gpio_ext_np
= of_parse_phandle(np
, "gpio-ext", 0);
426 dev_err(dev
, "Failed to get DT handle gpio-ext\n");
430 gpio_ext
= devm_kzalloc(dev
, sizeof(*gpio_ext
), GFP_KERNEL
);
432 of_node_put(gpio_ext_np
);
435 ret
= gpio_ext_get_of_pdata(dev
, gpio_ext_np
, gpio_ext
);
436 of_node_put(gpio_ext_np
);
439 pdata
->gpio_ext
= gpio_ext
;
441 /* Timers (optional) */
442 ret
= of_property_count_u32_elems(np
, "timers");
446 num_timers
= ret
/ 3;
447 timers
= devm_kcalloc(dev
, num_timers
, sizeof(*timers
),
451 for (i
= 0; i
< num_timers
; i
++) {
454 of_property_read_u32_index(np
, "timers", 3 * i
,
456 if (timers
[i
].mode
>= NETXBIG_LED_MODE_NUM
)
458 of_property_read_u32_index(np
, "timers",
460 timers
[i
].delay_on
= tmp
;
461 of_property_read_u32_index(np
, "timers",
463 timers
[i
].delay_off
= tmp
;
465 pdata
->timer
= timers
;
466 pdata
->num_timer
= num_timers
;
470 num_leds
= of_get_child_count(np
);
472 dev_err(dev
, "No LED subnodes found in DT\n");
476 leds
= devm_kcalloc(dev
, num_leds
, sizeof(*leds
), GFP_KERNEL
);
481 for_each_child_of_node(np
, child
) {
486 ret
= of_property_read_u32(child
, "mode-addr",
491 ret
= of_property_read_u32(child
, "bright-addr",
496 ret
= of_property_read_u32(child
, "max-brightness",
503 NETXBIG_LED_MODE_NUM
, sizeof(*mode_val
),
510 for (i
= 0; i
< NETXBIG_LED_MODE_NUM
; i
++)
511 mode_val
[i
] = NETXBIG_LED_INVALID_MODE
;
513 ret
= of_property_count_u32_elems(child
, "mode-val");
514 if (ret
< 0 || ret
% 2) {
519 if (num_modes
> NETXBIG_LED_MODE_NUM
) {
524 for (i
= 0; i
< num_modes
; i
++) {
528 of_property_read_u32_index(child
,
529 "mode-val", 2 * i
, &mode
);
530 of_property_read_u32_index(child
,
531 "mode-val", 2 * i
+ 1, &val
);
532 if (mode
>= NETXBIG_LED_MODE_NUM
) {
536 mode_val
[mode
] = val
;
538 led
->mode_val
= mode_val
;
540 if (!of_property_read_string(child
, "label", &string
))
543 led
->name
= child
->name
;
545 if (!of_property_read_string(child
,
546 "linux,default-trigger", &string
))
547 led
->default_trigger
= string
;
553 pdata
->num_leds
= num_leds
;
562 static const struct of_device_id of_netxbig_leds_match
[] = {
563 { .compatible
= "lacie,netxbig-leds", },
566 MODULE_DEVICE_TABLE(of
, of_netxbig_leds_match
);
568 static int netxbig_led_probe(struct platform_device
*pdev
)
570 struct netxbig_led_platform_data
*pdata
;
571 struct netxbig_led_data
*leds_data
;
575 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
578 ret
= netxbig_leds_get_of_pdata(&pdev
->dev
, pdata
);
582 leds_data
= devm_kcalloc(&pdev
->dev
,
583 pdata
->num_leds
, sizeof(*leds_data
),
588 ret
= gpio_ext_init(pdev
, pdata
->gpio_ext
);
592 for (i
= 0; i
< pdata
->num_leds
; i
++) {
593 ret
= create_netxbig_led(pdev
, pdata
,
594 &leds_data
[i
], &pdata
->leds
[i
]);
602 static struct platform_driver netxbig_led_driver
= {
603 .probe
= netxbig_led_probe
,
605 .name
= "leds-netxbig",
606 .of_match_table
= of_netxbig_leds_match
,
610 module_platform_driver(netxbig_led_driver
);
612 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
613 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
614 MODULE_LICENSE("GPL");
615 MODULE_ALIAS("platform:leds-netxbig");