leds-gpio.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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 __init 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. ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
  81. if (ret < 0) {
  82. gpio_free(led_dat->gpio);
  83. goto err;
  84. }
  85. INIT_WORK(&led_dat->work, gpio_led_work);
  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. gpio_free(leds_data[i].gpio);
  94. }
  95. }
  96. flush_scheduled_work();
  97. kfree(leds_data);
  98. return ret;
  99. }
  100. static int __exit 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. gpio_free(leds_data[i].gpio);
  109. }
  110. kfree(leds_data);
  111. return 0;
  112. }
  113. #ifdef CONFIG_PM
  114. static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
  115. {
  116. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  117. struct gpio_led_data *leds_data;
  118. int i;
  119. leds_data = platform_get_drvdata(pdev);
  120. for (i = 0; i < pdata->num_leds; i++)
  121. led_classdev_suspend(&leds_data[i].cdev);
  122. return 0;
  123. }
  124. static int gpio_led_resume(struct platform_device *pdev)
  125. {
  126. struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
  127. struct gpio_led_data *leds_data;
  128. int i;
  129. leds_data = platform_get_drvdata(pdev);
  130. for (i = 0; i < pdata->num_leds; i++)
  131. led_classdev_resume(&leds_data[i].cdev);
  132. return 0;
  133. }
  134. #else
  135. #define gpio_led_suspend NULL
  136. #define gpio_led_resume NULL
  137. #endif
  138. static struct platform_driver gpio_led_driver = {
  139. .remove = __exit_p(gpio_led_remove),
  140. .suspend = gpio_led_suspend,
  141. .resume = gpio_led_resume,
  142. .driver = {
  143. .name = "leds-gpio",
  144. .owner = THIS_MODULE,
  145. },
  146. };
  147. static int __init gpio_led_init(void)
  148. {
  149. return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
  150. }
  151. static void __exit gpio_led_exit(void)
  152. {
  153. platform_driver_unregister(&gpio_led_driver);
  154. }
  155. module_init(gpio_led_init);
  156. module_exit(gpio_led_exit);
  157. MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
  158. MODULE_DESCRIPTION("GPIO LED driver");
  159. MODULE_LICENSE("GPL");