Version:  2.0.40 2.2.26 2.4.37 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6

Linux/drivers/leds/leds-netxbig.c

  1 /*
  2  * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
  3  *
  4  * Copyright (C) 2010 LaCie
  5  *
  6  * Author: Simon Guinot <sguinot@lacie.com>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or
 11  * (at your option) any later version.
 12  *
 13  * This program is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16  * GNU General Public License for more details.
 17  *
 18  * You should have received a copy of the GNU General Public License
 19  * along with this program; if not, write to the Free Software
 20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 21  */
 22 
 23 #include <linux/module.h>
 24 #include <linux/irq.h>
 25 #include <linux/slab.h>
 26 #include <linux/spinlock.h>
 27 #include <linux/platform_device.h>
 28 #include <linux/gpio.h>
 29 #include <linux/of_gpio.h>
 30 #include <linux/leds.h>
 31 #include <linux/platform_data/leds-kirkwood-netxbig.h>
 32 
 33 /*
 34  * GPIO extension bus.
 35  */
 36 
 37 static DEFINE_SPINLOCK(gpio_ext_lock);
 38 
 39 static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
 40 {
 41         int pin;
 42 
 43         for (pin = 0; pin < gpio_ext->num_addr; pin++)
 44                 gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
 45 }
 46 
 47 static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
 48 {
 49         int pin;
 50 
 51         for (pin = 0; pin < gpio_ext->num_data; pin++)
 52                 gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1);
 53 }
 54 
 55 static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
 56 {
 57         /* Enable select is done on the raising edge. */
 58         gpio_set_value(gpio_ext->enable, 0);
 59         gpio_set_value(gpio_ext->enable, 1);
 60 }
 61 
 62 static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
 63                                int addr, int value)
 64 {
 65         unsigned long flags;
 66 
 67         spin_lock_irqsave(&gpio_ext_lock, flags);
 68         gpio_ext_set_addr(gpio_ext, addr);
 69         gpio_ext_set_data(gpio_ext, value);
 70         gpio_ext_enable_select(gpio_ext);
 71         spin_unlock_irqrestore(&gpio_ext_lock, flags);
 72 }
 73 
 74 static int gpio_ext_init(struct platform_device *pdev,
 75                          struct netxbig_gpio_ext *gpio_ext)
 76 {
 77         int err;
 78         int i;
 79 
 80         if (unlikely(!gpio_ext))
 81                 return -EINVAL;
 82 
 83         /* Configure address GPIOs. */
 84         for (i = 0; i < gpio_ext->num_addr; i++) {
 85                 err = devm_gpio_request_one(&pdev->dev, gpio_ext->addr[i],
 86                                             GPIOF_OUT_INIT_LOW,
 87                                             "GPIO extension addr");
 88                 if (err)
 89                         return err;
 90         }
 91         /* Configure data GPIOs. */
 92         for (i = 0; i < gpio_ext->num_data; i++) {
 93                 err = devm_gpio_request_one(&pdev->dev, gpio_ext->data[i],
 94                                             GPIOF_OUT_INIT_LOW,
 95                                             "GPIO extension data");
 96                 if (err)
 97                         return err;
 98         }
 99         /* Configure "enable select" GPIO. */
100         err = devm_gpio_request_one(&pdev->dev, gpio_ext->enable,
101                                     GPIOF_OUT_INIT_LOW,
102                                     "GPIO extension enable");
103         if (err)
104                 return err;
105 
106         return 0;
107 }
108 
109 /*
110  * Class LED driver.
111  */
112 
113 struct netxbig_led_data {
114         struct netxbig_gpio_ext *gpio_ext;
115         struct led_classdev     cdev;
116         int                     mode_addr;
117         int                     *mode_val;
118         int                     bright_addr;
119         struct                  netxbig_led_timer *timer;
120         int                     num_timer;
121         enum netxbig_led_mode   mode;
122         int                     sata;
123         spinlock_t              lock;
124 };
125 
126 static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
127                                       unsigned long delay_on,
128                                       unsigned long delay_off,
129                                       struct netxbig_led_timer *timer,
130                                       int num_timer)
131 {
132         int i;
133 
134         for (i = 0; i < num_timer; i++) {
135                 if (timer[i].delay_on == delay_on &&
136                     timer[i].delay_off == delay_off) {
137                         *mode = timer[i].mode;
138                         return 0;
139                 }
140         }
141         return -EINVAL;
142 }
143 
144 static int netxbig_led_blink_set(struct led_classdev *led_cdev,
145                                  unsigned long *delay_on,
146                                  unsigned long *delay_off)
147 {
148         struct netxbig_led_data *led_dat =
149                 container_of(led_cdev, struct netxbig_led_data, cdev);
150         enum netxbig_led_mode mode;
151         int mode_val;
152         int ret;
153 
154         /* Look for a LED mode with the requested timer frequency. */
155         ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
156                                          led_dat->timer, led_dat->num_timer);
157         if (ret < 0)
158                 return ret;
159 
160         mode_val = led_dat->mode_val[mode];
161         if (mode_val == NETXBIG_LED_INVALID_MODE)
162                 return -EINVAL;
163 
164         spin_lock_irq(&led_dat->lock);
165 
166         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
167         led_dat->mode = mode;
168 
169         spin_unlock_irq(&led_dat->lock);
170 
171         return 0;
172 }
173 
174 static void netxbig_led_set(struct led_classdev *led_cdev,
175                             enum led_brightness value)
176 {
177         struct netxbig_led_data *led_dat =
178                 container_of(led_cdev, struct netxbig_led_data, cdev);
179         enum netxbig_led_mode mode;
180         int mode_val;
181         int set_brightness = 1;
182         unsigned long flags;
183 
184         spin_lock_irqsave(&led_dat->lock, flags);
185 
186         if (value == LED_OFF) {
187                 mode = NETXBIG_LED_OFF;
188                 set_brightness = 0;
189         } else {
190                 if (led_dat->sata)
191                         mode = NETXBIG_LED_SATA;
192                 else if (led_dat->mode == NETXBIG_LED_OFF)
193                         mode = NETXBIG_LED_ON;
194                 else /* Keep 'timer' mode. */
195                         mode = led_dat->mode;
196         }
197         mode_val = led_dat->mode_val[mode];
198 
199         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
200         led_dat->mode = mode;
201         /*
202          * Note that the brightness register is shared between all the
203          * SATA LEDs. So, change the brightness setting for a single
204          * SATA LED will affect all the others.
205          */
206         if (set_brightness)
207                 gpio_ext_set_value(led_dat->gpio_ext,
208                                    led_dat->bright_addr, value);
209 
210         spin_unlock_irqrestore(&led_dat->lock, flags);
211 }
212 
213 static ssize_t netxbig_led_sata_store(struct device *dev,
214                                       struct device_attribute *attr,
215                                       const char *buff, size_t count)
216 {
217         struct led_classdev *led_cdev = dev_get_drvdata(dev);
218         struct netxbig_led_data *led_dat =
219                 container_of(led_cdev, struct netxbig_led_data, cdev);
220         unsigned long enable;
221         enum netxbig_led_mode mode;
222         int mode_val;
223         int ret;
224 
225         ret = kstrtoul(buff, 10, &enable);
226         if (ret < 0)
227                 return ret;
228 
229         enable = !!enable;
230 
231         spin_lock_irq(&led_dat->lock);
232 
233         if (led_dat->sata == enable) {
234                 ret = count;
235                 goto exit_unlock;
236         }
237 
238         if (led_dat->mode != NETXBIG_LED_ON &&
239             led_dat->mode != NETXBIG_LED_SATA)
240                 mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
241         else if (enable)
242                 mode = NETXBIG_LED_SATA;
243         else
244                 mode = NETXBIG_LED_ON;
245 
246         mode_val = led_dat->mode_val[mode];
247         if (mode_val == NETXBIG_LED_INVALID_MODE) {
248                 ret = -EINVAL;
249                 goto exit_unlock;
250         }
251 
252         gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
253         led_dat->mode = mode;
254         led_dat->sata = enable;
255 
256         ret = count;
257 
258 exit_unlock:
259         spin_unlock_irq(&led_dat->lock);
260 
261         return ret;
262 }
263 
264 static ssize_t netxbig_led_sata_show(struct device *dev,
265                                      struct device_attribute *attr, char *buf)
266 {
267         struct led_classdev *led_cdev = dev_get_drvdata(dev);
268         struct netxbig_led_data *led_dat =
269                 container_of(led_cdev, struct netxbig_led_data, cdev);
270 
271         return sprintf(buf, "%d\n", led_dat->sata);
272 }
273 
274 static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
275 
276 static struct attribute *netxbig_led_attrs[] = {
277         &dev_attr_sata.attr,
278         NULL
279 };
280 ATTRIBUTE_GROUPS(netxbig_led);
281 
282 static int create_netxbig_led(struct platform_device *pdev,
283                               struct netxbig_led_platform_data *pdata,
284                               struct netxbig_led_data *led_dat,
285                               const struct netxbig_led *template)
286 {
287         spin_lock_init(&led_dat->lock);
288         led_dat->gpio_ext = pdata->gpio_ext;
289         led_dat->cdev.name = template->name;
290         led_dat->cdev.default_trigger = template->default_trigger;
291         led_dat->cdev.blink_set = netxbig_led_blink_set;
292         led_dat->cdev.brightness_set = netxbig_led_set;
293         /*
294          * Because the GPIO extension bus don't allow to read registers
295          * value, there is no way to probe the LED initial state.
296          * So, the initial sysfs LED value for the "brightness" and "sata"
297          * attributes are inconsistent.
298          *
299          * Note that the initial LED state can't be reconfigured.
300          * The reason is that the LED behaviour must stay uniform during
301          * the whole boot process (bootloader+linux).
302          */
303         led_dat->sata = 0;
304         led_dat->cdev.brightness = LED_OFF;
305         led_dat->cdev.max_brightness = template->bright_max;
306         led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
307         led_dat->mode_addr = template->mode_addr;
308         led_dat->mode_val = template->mode_val;
309         led_dat->bright_addr = template->bright_addr;
310         led_dat->timer = pdata->timer;
311         led_dat->num_timer = pdata->num_timer;
312         /*
313          * If available, expose the SATA activity blink capability through
314          * a "sata" sysfs attribute.
315          */
316         if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
317                 led_dat->cdev.groups = netxbig_led_groups;
318 
319         return devm_led_classdev_register(&pdev->dev, &led_dat->cdev);
320 }
321 
322 #ifdef CONFIG_OF_GPIO
323 static int gpio_ext_get_of_pdata(struct device *dev, struct device_node *np,
324                                  struct netxbig_gpio_ext *gpio_ext)
325 {
326         int *addr, *data;
327         int num_addr, num_data;
328         int ret;
329         int i;
330 
331         ret = of_gpio_named_count(np, "addr-gpios");
332         if (ret < 0) {
333                 dev_err(dev,
334                         "Failed to count GPIOs in DT property addr-gpios\n");
335                 return ret;
336         }
337         num_addr = ret;
338         addr = devm_kzalloc(dev, num_addr * sizeof(*addr), GFP_KERNEL);
339         if (!addr)
340                 return -ENOMEM;
341 
342         for (i = 0; i < num_addr; i++) {
343                 ret = of_get_named_gpio(np, "addr-gpios", i);
344                 if (ret < 0)
345                         return ret;
346                 addr[i] = ret;
347         }
348         gpio_ext->addr = addr;
349         gpio_ext->num_addr = num_addr;
350 
351         ret = of_gpio_named_count(np, "data-gpios");
352         if (ret < 0) {
353                 dev_err(dev,
354                         "Failed to count GPIOs in DT property data-gpios\n");
355                 return ret;
356         }
357         num_data = ret;
358         data = devm_kzalloc(dev, num_data * sizeof(*data), GFP_KERNEL);
359         if (!data)
360                 return -ENOMEM;
361 
362         for (i = 0; i < num_data; i++) {
363                 ret = of_get_named_gpio(np, "data-gpios", i);
364                 if (ret < 0)
365                         return ret;
366                 data[i] = ret;
367         }
368         gpio_ext->data = data;
369         gpio_ext->num_data = num_data;
370 
371         ret = of_get_named_gpio(np, "enable-gpio", 0);
372         if (ret < 0) {
373                 dev_err(dev,
374                         "Failed to get GPIO from DT property enable-gpio\n");
375                 return ret;
376         }
377         gpio_ext->enable = ret;
378 
379         return 0;
380 }
381 
382 static int netxbig_leds_get_of_pdata(struct device *dev,
383                                      struct netxbig_led_platform_data *pdata)
384 {
385         struct device_node *np = dev->of_node;
386         struct device_node *gpio_ext_np;
387         struct device_node *child;
388         struct netxbig_gpio_ext *gpio_ext;
389         struct netxbig_led_timer *timers;
390         struct netxbig_led *leds, *led;
391         int num_timers;
392         int num_leds = 0;
393         int ret;
394         int i;
395 
396         /* GPIO extension */
397         gpio_ext_np = of_parse_phandle(np, "gpio-ext", 0);
398         if (!gpio_ext_np) {
399                 dev_err(dev, "Failed to get DT handle gpio-ext\n");
400                 return -EINVAL;
401         }
402 
403         gpio_ext = devm_kzalloc(dev, sizeof(*gpio_ext), GFP_KERNEL);
404         if (!gpio_ext)
405                 return -ENOMEM;
406         ret = gpio_ext_get_of_pdata(dev, gpio_ext_np, gpio_ext);
407         if (ret)
408                 return ret;
409         of_node_put(gpio_ext_np);
410         pdata->gpio_ext = gpio_ext;
411 
412         /* Timers (optional) */
413         ret = of_property_count_u32_elems(np, "timers");
414         if (ret > 0) {
415                 if (ret % 3)
416                         return -EINVAL;
417                 num_timers = ret / 3;
418                 timers = devm_kzalloc(dev, num_timers * sizeof(*timers),
419                                       GFP_KERNEL);
420                 if (!timers)
421                         return -ENOMEM;
422                 for (i = 0; i < num_timers; i++) {
423                         u32 tmp;
424 
425                         of_property_read_u32_index(np, "timers", 3 * i,
426                                                    &timers[i].mode);
427                         if (timers[i].mode >= NETXBIG_LED_MODE_NUM)
428                                 return -EINVAL;
429                         of_property_read_u32_index(np, "timers",
430                                                    3 * i + 1, &tmp);
431                         timers[i].delay_on = tmp;
432                         of_property_read_u32_index(np, "timers",
433                                                    3 * i + 2, &tmp);
434                         timers[i].delay_off = tmp;
435                 }
436                 pdata->timer = timers;
437                 pdata->num_timer = num_timers;
438         }
439 
440         /* LEDs */
441         num_leds = of_get_child_count(np);
442         if (!num_leds) {
443                 dev_err(dev, "No LED subnodes found in DT\n");
444                 return -ENODEV;
445         }
446 
447         leds = devm_kzalloc(dev, num_leds * sizeof(*leds), GFP_KERNEL);
448         if (!leds)
449                 return -ENOMEM;
450 
451         led = leds;
452         for_each_child_of_node(np, child) {
453                 const char *string;
454                 int *mode_val;
455                 int num_modes;
456 
457                 ret = of_property_read_u32(child, "mode-addr",
458                                            &led->mode_addr);
459                 if (ret)
460                         goto err_node_put;
461 
462                 ret = of_property_read_u32(child, "bright-addr",
463                                            &led->bright_addr);
464                 if (ret)
465                         goto err_node_put;
466 
467                 ret = of_property_read_u32(child, "max-brightness",
468                                            &led->bright_max);
469                 if (ret)
470                         goto err_node_put;
471 
472                 mode_val =
473                         devm_kzalloc(dev,
474                                      NETXBIG_LED_MODE_NUM * sizeof(*mode_val),
475                                      GFP_KERNEL);
476                 if (!mode_val) {
477                         ret = -ENOMEM;
478                         goto err_node_put;
479                 }
480 
481                 for (i = 0; i < NETXBIG_LED_MODE_NUM; i++)
482                         mode_val[i] = NETXBIG_LED_INVALID_MODE;
483 
484                 ret = of_property_count_u32_elems(child, "mode-val");
485                 if (ret < 0 || ret % 2) {
486                         ret = -EINVAL;
487                         goto err_node_put;
488                 }
489                 num_modes = ret / 2;
490                 if (num_modes > NETXBIG_LED_MODE_NUM) {
491                         ret = -EINVAL;
492                         goto err_node_put;
493                 }
494 
495                 for (i = 0; i < num_modes; i++) {
496                         int mode;
497                         int val;
498 
499                         of_property_read_u32_index(child,
500                                                    "mode-val", 2 * i, &mode);
501                         of_property_read_u32_index(child,
502                                                    "mode-val", 2 * i + 1, &val);
503                         if (mode >= NETXBIG_LED_MODE_NUM) {
504                                 ret = -EINVAL;
505                                 goto err_node_put;
506                         }
507                         mode_val[mode] = val;
508                 }
509                 led->mode_val = mode_val;
510 
511                 if (!of_property_read_string(child, "label", &string))
512                         led->name = string;
513                 else
514                         led->name = child->name;
515 
516                 if (!of_property_read_string(child,
517                                              "linux,default-trigger", &string))
518                         led->default_trigger = string;
519 
520                 led++;
521         }
522 
523         pdata->leds = leds;
524         pdata->num_leds = num_leds;
525 
526         return 0;
527 
528 err_node_put:
529         of_node_put(child);
530         return ret;
531 }
532 
533 static const struct of_device_id of_netxbig_leds_match[] = {
534         { .compatible = "lacie,netxbig-leds", },
535         {},
536 };
537 #else
538 static inline int
539 netxbig_leds_get_of_pdata(struct device *dev,
540                           struct netxbig_led_platform_data *pdata)
541 {
542         return -ENODEV;
543 }
544 #endif /* CONFIG_OF_GPIO */
545 
546 static int netxbig_led_probe(struct platform_device *pdev)
547 {
548         struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
549         struct netxbig_led_data *leds_data;
550         int i;
551         int ret;
552 
553         if (!pdata) {
554                 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
555                 if (!pdata)
556                         return -ENOMEM;
557                 ret = netxbig_leds_get_of_pdata(&pdev->dev, pdata);
558                 if (ret)
559                         return ret;
560         }
561 
562         leds_data = devm_kzalloc(&pdev->dev,
563                                  pdata->num_leds * sizeof(*leds_data),
564                                  GFP_KERNEL);
565         if (!leds_data)
566                 return -ENOMEM;
567 
568         ret = gpio_ext_init(pdev, pdata->gpio_ext);
569         if (ret < 0)
570                 return ret;
571 
572         for (i = 0; i < pdata->num_leds; i++) {
573                 ret = create_netxbig_led(pdev, pdata,
574                                          &leds_data[i], &pdata->leds[i]);
575                 if (ret < 0)
576                         return ret;
577         }
578 
579         return 0;
580 }
581 
582 static struct platform_driver netxbig_led_driver = {
583         .probe          = netxbig_led_probe,
584         .driver         = {
585                 .name           = "leds-netxbig",
586                 .of_match_table = of_match_ptr(of_netxbig_leds_match),
587         },
588 };
589 
590 module_platform_driver(netxbig_led_driver);
591 
592 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
593 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
594 MODULE_LICENSE("GPL");
595 MODULE_ALIAS("platform:leds-netxbig");
596 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us