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
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>
18 #include <linux/platform_data/leds-kirkwood-netxbig.h>
24 static DEFINE_SPINLOCK(gpio_ext_lock);
26 static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
30 for (pin = 0; pin < gpio_ext->num_addr; pin++)
31 gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
34 static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
38 for (pin = 0; pin < gpio_ext->num_data; pin++)
39 gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1);
42 static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
44 /* Enable select is done on the raising edge. */
45 gpio_set_value(gpio_ext->enable, 0);
46 gpio_set_value(gpio_ext->enable, 1);
49 static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
54 spin_lock_irqsave(&gpio_ext_lock, flags);
55 gpio_ext_set_addr(gpio_ext, addr);
56 gpio_ext_set_data(gpio_ext, value);
57 gpio_ext_enable_select(gpio_ext);
58 spin_unlock_irqrestore(&gpio_ext_lock, flags);
61 static int gpio_ext_init(struct platform_device *pdev,
62 struct netxbig_gpio_ext *gpio_ext)
67 if (unlikely(!gpio_ext))
70 /* Configure address GPIOs. */
71 for (i = 0; i < gpio_ext->num_addr; i++) {
72 err = devm_gpio_request_one(&pdev->dev, gpio_ext->addr[i],
74 "GPIO extension addr");
78 /* Configure data GPIOs. */
79 for (i = 0; i < gpio_ext->num_data; i++) {
80 err = devm_gpio_request_one(&pdev->dev, gpio_ext->data[i],
82 "GPIO extension data");
86 /* Configure "enable select" GPIO. */
87 err = devm_gpio_request_one(&pdev->dev, gpio_ext->enable,
89 "GPIO extension enable");
100 struct netxbig_led_data {
101 struct netxbig_gpio_ext *gpio_ext;
102 struct led_classdev cdev;
106 struct netxbig_led_timer *timer;
108 enum netxbig_led_mode mode;
113 static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
114 unsigned long delay_on,
115 unsigned long delay_off,
116 struct netxbig_led_timer *timer,
121 for (i = 0; i < num_timer; i++) {
122 if (timer[i].delay_on == delay_on &&
123 timer[i].delay_off == delay_off) {
124 *mode = timer[i].mode;
131 static int netxbig_led_blink_set(struct led_classdev *led_cdev,
132 unsigned long *delay_on,
133 unsigned long *delay_off)
135 struct netxbig_led_data *led_dat =
136 container_of(led_cdev, struct netxbig_led_data, cdev);
137 enum netxbig_led_mode mode;
141 /* Look for a LED mode with the requested timer frequency. */
142 ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
143 led_dat->timer, led_dat->num_timer);
147 mode_val = led_dat->mode_val[mode];
148 if (mode_val == NETXBIG_LED_INVALID_MODE)
151 spin_lock_irq(&led_dat->lock);
153 gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
154 led_dat->mode = mode;
156 spin_unlock_irq(&led_dat->lock);
161 static void netxbig_led_set(struct led_classdev *led_cdev,
162 enum led_brightness value)
164 struct netxbig_led_data *led_dat =
165 container_of(led_cdev, struct netxbig_led_data, cdev);
166 enum netxbig_led_mode mode;
168 int set_brightness = 1;
171 spin_lock_irqsave(&led_dat->lock, flags);
173 if (value == LED_OFF) {
174 mode = NETXBIG_LED_OFF;
178 mode = NETXBIG_LED_SATA;
179 else if (led_dat->mode == NETXBIG_LED_OFF)
180 mode = NETXBIG_LED_ON;
181 else /* Keep 'timer' mode. */
182 mode = led_dat->mode;
184 mode_val = led_dat->mode_val[mode];
186 gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
187 led_dat->mode = mode;
189 * Note that the brightness register is shared between all the
190 * SATA LEDs. So, change the brightness setting for a single
191 * SATA LED will affect all the others.
194 gpio_ext_set_value(led_dat->gpio_ext,
195 led_dat->bright_addr, value);
197 spin_unlock_irqrestore(&led_dat->lock, flags);
200 static ssize_t netxbig_led_sata_store(struct device *dev,
201 struct device_attribute *attr,
202 const char *buff, size_t count)
204 struct led_classdev *led_cdev = dev_get_drvdata(dev);
205 struct netxbig_led_data *led_dat =
206 container_of(led_cdev, struct netxbig_led_data, cdev);
207 unsigned long enable;
208 enum netxbig_led_mode mode;
212 ret = kstrtoul(buff, 10, &enable);
218 spin_lock_irq(&led_dat->lock);
220 if (led_dat->sata == enable) {
225 if (led_dat->mode != NETXBIG_LED_ON &&
226 led_dat->mode != NETXBIG_LED_SATA)
227 mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
229 mode = NETXBIG_LED_SATA;
231 mode = NETXBIG_LED_ON;
233 mode_val = led_dat->mode_val[mode];
234 if (mode_val == NETXBIG_LED_INVALID_MODE) {
239 gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
240 led_dat->mode = mode;
241 led_dat->sata = enable;
246 spin_unlock_irq(&led_dat->lock);
251 static ssize_t netxbig_led_sata_show(struct device *dev,
252 struct device_attribute *attr, char *buf)
254 struct led_classdev *led_cdev = dev_get_drvdata(dev);
255 struct netxbig_led_data *led_dat =
256 container_of(led_cdev, struct netxbig_led_data, cdev);
258 return sprintf(buf, "%d\n", led_dat->sata);
261 static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
263 static struct attribute *netxbig_led_attrs[] = {
267 ATTRIBUTE_GROUPS(netxbig_led);
269 static int create_netxbig_led(struct platform_device *pdev,
270 struct netxbig_led_platform_data *pdata,
271 struct netxbig_led_data *led_dat,
272 const struct netxbig_led *template)
274 spin_lock_init(&led_dat->lock);
275 led_dat->gpio_ext = pdata->gpio_ext;
276 led_dat->cdev.name = template->name;
277 led_dat->cdev.default_trigger = template->default_trigger;
278 led_dat->cdev.blink_set = netxbig_led_blink_set;
279 led_dat->cdev.brightness_set = netxbig_led_set;
281 * Because the GPIO extension bus don't allow to read registers
282 * value, there is no way to probe the LED initial state.
283 * So, the initial sysfs LED value for the "brightness" and "sata"
284 * attributes are inconsistent.
286 * Note that the initial LED state can't be reconfigured.
287 * The reason is that the LED behaviour must stay uniform during
288 * the whole boot process (bootloader+linux).
291 led_dat->cdev.brightness = LED_OFF;
292 led_dat->cdev.max_brightness = template->bright_max;
293 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
294 led_dat->mode_addr = template->mode_addr;
295 led_dat->mode_val = template->mode_val;
296 led_dat->bright_addr = template->bright_addr;
297 led_dat->timer = pdata->timer;
298 led_dat->num_timer = pdata->num_timer;
300 * If available, expose the SATA activity blink capability through
301 * a "sata" sysfs attribute.
303 if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
304 led_dat->cdev.groups = netxbig_led_groups;
306 return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
309 #ifdef CONFIG_OF_GPIO
310 static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np,
311 struct netxbig_gpio_ext *gpio_ext)
314 int num_addr, num_data;
318 ret = of_gpio_named_count(np, "addr-gpios");
321 "Failed to count GPIOs in DT property addr-gpios\n");
325 addr = devm_kcalloc(dev, num_addr, sizeof(*addr), GFP_KERNEL);
329 for (i = 0; i < num_addr; i++) {
330 ret = of_get_named_gpio(np, "addr-gpios", i);
335 gpio_ext->addr = addr;
336 gpio_ext->num_addr = num_addr;
338 ret = of_gpio_named_count(np, "data-gpios");
341 "Failed to count GPIOs in DT property data-gpios\n");
345 data = devm_kcalloc(dev, num_data, sizeof(*data), GFP_KERNEL);
349 for (i = 0; i < num_data; i++) {
350 ret = of_get_named_gpio(np, "data-gpios", i);
355 gpio_ext->data = data;
356 gpio_ext->num_data = num_data;
358 ret = of_get_named_gpio(np, "enable-gpio", 0);
361 "Failed to get GPIO from DT property enable-gpio\n");
364 gpio_ext->enable = ret;
369 static int netxbig_leds_get_of_pdata(struct device *dev,
370 struct netxbig_led_platform_data *pdata)
372 struct device_node *np = dev->of_node;
373 struct device_node *gpio_ext_np;
374 struct device_node *child;
375 struct netxbig_gpio_ext *gpio_ext;
376 struct netxbig_led_timer *timers;
377 struct netxbig_led *leds, *led;
384 gpio_ext_np = of_parse_phandle(np, "gpio-ext", 0);
386 dev_err(dev, "Failed to get DT handle gpio-ext\n");
390 gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
393 ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext);
396 of_node_put(gpio_ext_np);
397 pdata->gpio_ext = gpio_ext;
399 /* Timers (optional) */
400 ret = of_property_count_u32_elems(np, "timers");
404 num_timers = ret / 3;
405 timers = devm_kcalloc(dev, num_timers, sizeof(*timers),
409 for (i = 0; i < num_timers; i++) {
412 of_property_read_u32_index(np, "timers", 3 * i,
414 if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
416 of_property_read_u32_index(np, "timers",
418 timers[i].delay_on = tmp;
419 of_property_read_u32_index(np, "timers",
421 timers[i].delay_off = tmp;
423 pdata->timer = timers;
424 pdata->num_timer = num_timers;
428 num_leds = of_get_child_count(np);
430 dev_err(dev, "No LED subnodes found in DT\n");
434 leds = devm_kcalloc(dev, num_leds, sizeof(*leds), GFP_KERNEL);
439 for_each_child_of_node(np, child) {
444 ret = of_property_read_u32(child, "mode-addr",
449 ret = of_property_read_u32(child, "bright-addr",
454 ret = of_property_read_u32(child, "max-brightness",
461 NETXBIG_LED_MODE_NUM, sizeof(*mode_val),
468 for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
469 mode_val[i] = NETXBIG_LED_INVALID_MODE;
471 ret = of_property_count_u32_elems(child, "mode-val");
472 if (ret < 0 || ret % 2) {
477 if (num_modes > NETXBIG_LED_MODE_NUM) {
482 for (i = 0; i < num_modes; i++) {
486 of_property_read_u32_index(child,
487 "mode-val", 2 * i, &mode);
488 of_property_read_u32_index(child,
489 "mode-val", 2 * i + 1, &val);
490 if (mode >= NETXBIG_LED_MODE_NUM) {
494 mode_val[mode] = val;
496 led->mode_val = mode_val;
498 if (!of_property_read_string(child, "label", &string))
501 led->name = child->name;
503 if (!of_property_read_string(child,
504 "linux,default-trigger", &string))
505 led->default_trigger = string;
511 pdata->num_leds = num_leds;
520 static const struct of_device_id of_netxbig_leds_match[] = {
521 { .compatible = "lacie,netxbig-leds", },
524 MODULE_DEVICE_TABLE(of, of_netxbig_leds_match);
527 netxbig_leds_get_of_pdata(struct device *dev,
528 struct netxbig_led_platform_data *pdata)
532 #endif /* CONFIG_OF_GPIO */
534 static int netxbig_led_probe(struct platform_device *pdev)
536 struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
537 struct netxbig_led_data *leds_data;
542 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
545 ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
550 leds_data = devm_kcalloc(&pdev->dev,
551 pdata->num_leds, sizeof(*leds_data),
556 ret = gpio_ext_init(pdev, pdata->gpio_ext);
560 for (i = 0; i < pdata->num_leds; i++) {
561 ret = create_netxbig_led(pdev, pdata,
562 &leds_data[i], &pdata->leds[i]);
570 static struct platform_driver netxbig_led_driver = {
571 .probe = netxbig_led_probe,
573 .name = "leds-netxbig",
574 .of_match_table = of_match_ptr(of_netxbig_leds_match),
578 module_platform_driver(netxbig_led_driver);
581 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
582 MODULE_LICENSE("GPL");
583 MODULE_ALIAS("platform:leds-netxbig");