leds-gpio.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * LEDs driver for GPIOs
  3. *
  4. * Copyright (C) 2007 8D Technologies inc.
  5. * Raphael Assenat <raph@8d.com>
  6. *
  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.
  10. *
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/init.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/leds.h>
  16. #include <linux/workqueue.h>
  17. #include <asm/gpio.h>
  18. struct gpio_led_data {
  19. struct led_classdev cdev;
  20. unsigned gpio;
  21. struct work_struct work;
  22. u8 new_level;
  23. u8 can_sleep;
  24. u8 active_low;
  25. };
  26. static void gpio_led_work(struct work_struct *work)
  27. {
  28. struct gpio_led_data *led_dat =
  29. container_of(work, struct gpio_led_data, work);
  30. gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
  31. }
  32. static void gpio_led_set(struct led_classdev *led_cdev,
  33. enum led_brightness value)
  34. {
  35. struct gpio_led_data *led_dat =
  36. container_of(led_cdev, struct gpio_led_data, cdev);
  37. int level;
  38. if (value == LED_OFF)
  39. level = 0;
  40. else
  41. level = 1;
  42. if (led_dat->active_low)
  43. level = !level;
  44. /* setting GPIOs with I2C/etc requires a preemptible task context */
  45. if (led_dat->can_sleep) {
  46. if (preempt_count()) {
  47. led_dat->new_level = level;
  48. schedule_work(&led_dat->work);
  49. } else
  50. gpio_set_value_cansleep(led_dat->gpio, level);
  51. } else
  52. gpio_set_value(led_dat->gpio, level);
  53. }
  54. static int gpio_led_probe(struct platform_device *pdev)
  55. {
  56. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  57. struct gpio_led *cur_led;
  58. struct gpio_led_data *leds_data, *led_dat;
  59. int i, ret = 0;
  60. if (!pdata)
  61. return -EBUSY;
  62. leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
  63. GFP_KERNEL);
  64. if (!leds_data)
  65. return -ENOMEM;
  66. for (i = 0; i < pdata->num_leds; i++) {
  67. cur_led = &pdata->leds[i];
  68. led_dat = &leds_data[i];
  69. led_dat->cdev.name = cur_led->name;
  70. led_dat->cdev.default_trigger = cur_led->default_trigger;
  71. led_dat->gpio = cur_led->gpio;
  72. led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
  73. led_dat->active_low = cur_led->active_low;
  74. led_dat->cdev.brightness_set = gpio_led_set;
  75. led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
  76. ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
  77. if (ret < 0)
  78. goto err;
  79. gpio_direction_output(led_dat->gpio, led_dat->active_low);
  80. INIT_WORK(&led_dat->work, gpio_led_work);
  81. ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
  82. if (ret < 0) {
  83. gpio_free(led_dat->gpio);
  84. goto err;
  85. }
  86. }
  87. platform_set_drvdata(pdev, leds_data);
  88. return 0;
  89. err:
  90. if (i > 0) {
  91. for (i = i - 1; i >= 0; i--) {
  92. led_classdev_unregister(&leds_data[i].cdev);
  93. cancel_work_sync(&leds_data[i].work);
  94. gpio_free(leds_data[i].gpio);
  95. }
  96. }
  97. kfree(leds_data);
  98. return ret;
  99. }
  100. static int __devexit gpio_led_remove(struct platform_device *pdev)
  101. {
  102. int i;
  103. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  104. struct gpio_led_data *leds_data;
  105. leds_data = platform_get_drvdata(pdev);
  106. for (i = 0; i < pdata->num_leds; i++) {
  107. led_classdev_unregister(&leds_data[i].cdev);
  108. cancel_work_sync(&leds_data[i].work);
  109. gpio_free(leds_data[i].gpio);
  110. }
  111. kfree(leds_data);
  112. return 0;
  113. }
  114. #ifdef CONFIG_PM
  115. static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
  116. {
  117. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  118. struct gpio_led_data *leds_data;
  119. int i;
  120. leds_data = platform_get_drvdata(pdev);
  121. for (i = 0; i < pdata->num_leds; i++)
  122. led_classdev_suspend(&leds_data[i].cdev);
  123. return 0;
  124. }
  125. static int gpio_led_resume(struct platform_device *pdev)
  126. {
  127. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  128. struct gpio_led_data *leds_data;
  129. int i;
  130. leds_data = platform_get_drvdata(pdev);
  131. for (i = 0; i < pdata->num_leds; i++)
  132. led_classdev_resume(&leds_data[i].cdev);
  133. return 0;
  134. }
  135. #else
  136. #define gpio_led_suspend NULL
  137. #define gpio_led_resume NULL
  138. #endif
  139. static struct platform_driver gpio_led_driver = {
  140. .probe = gpio_led_probe,
  141. .remove = __devexit_p(gpio_led_remove),
  142. .suspend = gpio_led_suspend,
  143. .resume = gpio_led_resume,
  144. .driver = {
  145. .name = "leds-gpio",
  146. .owner = THIS_MODULE,
  147. },
  148. };
  149. static int __init gpio_led_init(void)
  150. {
  151. return platform_driver_register(&gpio_led_driver);
  152. }
  153. static void __exit gpio_led_exit(void)
  154. {
  155. platform_driver_unregister(&gpio_led_driver);
  156. }
  157. module_init(gpio_led_init);
  158. module_exit(gpio_led_exit);
  159. MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
  160. MODULE_DESCRIPTION("GPIO LED driver");
  161. MODULE_LICENSE("GPL");