295-latch_led_driver.patch 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. --- a/drivers/leds/Kconfig
  2. +++ b/drivers/leds/Kconfig
  3. @@ -296,6 +296,12 @@ config LEDS_LP8860
  4. on the LP8860 4 channel LED driver using the I2C communication
  5. bus.
  6. +config LEDS_LATCH
  7. + tristate "LED Support for Memory Latched LEDs"
  8. + depends on LEDS_CLASS
  9. + help
  10. + -- To Do --
  11. +
  12. config LEDS_CLEVO_MAIL
  13. tristate "Mail LED on Clevo notebook"
  14. depends on LEDS_CLASS
  15. --- a/drivers/leds/Makefile
  16. +++ b/drivers/leds/Makefile
  17. @@ -25,6 +25,7 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunf
  18. obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
  19. obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
  20. obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
  21. +obj-$(CONFIG_LEDS_LATCH) += leds-latch.o
  22. obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
  23. obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
  24. obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
  25. --- /dev/null
  26. +++ b/drivers/leds/leds-latch.c
  27. @@ -0,0 +1,152 @@
  28. +/*
  29. + * LEDs driver for Memory Latched Devices
  30. + *
  31. + * Copyright (C) 2008 Gateworks Corp.
  32. + * Chris Lang <clang@gateworks.com>
  33. + *
  34. + * This program is free software; you can redistribute it and/or modify
  35. + * it under the terms of the GNU General Public License version 2 as
  36. + * published by the Free Software Foundation.
  37. + *
  38. + */
  39. +#include <linux/kernel.h>
  40. +#include <linux/slab.h>
  41. +#include <linux/init.h>
  42. +#include <linux/platform_device.h>
  43. +#include <linux/leds.h>
  44. +#include <linux/workqueue.h>
  45. +#include <asm/io.h>
  46. +#include <linux/spinlock.h>
  47. +#include <linux/slab.h>
  48. +#include <linux/module.h>
  49. +#include <linux/export.h>
  50. +
  51. +static unsigned int mem_keep = 0xFF;
  52. +static spinlock_t mem_lock;
  53. +static unsigned char *iobase;
  54. +
  55. +struct latch_led_data {
  56. + struct led_classdev cdev;
  57. + struct work_struct work;
  58. + u8 new_level;
  59. + u8 bit;
  60. + void (*set_led)(u8 bit, enum led_brightness value);
  61. +};
  62. +
  63. +static void latch_set_led(u8 bit, enum led_brightness value)
  64. +{
  65. + if (value == LED_OFF)
  66. + mem_keep |= (0x1 << bit);
  67. + else
  68. + mem_keep &= ~(0x1 << bit);
  69. +
  70. + writeb(mem_keep, iobase);
  71. +}
  72. +
  73. +static void latch_led_set(struct led_classdev *led_cdev,
  74. + enum led_brightness value)
  75. +{
  76. + struct latch_led_data *led_dat =
  77. + container_of(led_cdev, struct latch_led_data, cdev);
  78. +
  79. + raw_spin_lock(mem_lock);
  80. +
  81. + led_dat->set_led(led_dat->bit, value);
  82. +
  83. + raw_spin_unlock(mem_lock);
  84. +}
  85. +
  86. +static int latch_led_probe(struct platform_device *pdev)
  87. +{
  88. + struct latch_led_platform_data *pdata = pdev->dev.platform_data;
  89. + struct latch_led *cur_led;
  90. + struct latch_led_data *leds_data, *led_dat;
  91. + int i, ret = 0;
  92. +
  93. + if (!pdata)
  94. + return -EBUSY;
  95. +
  96. + leds_data = kzalloc(sizeof(struct latch_led_data) * pdata->num_leds,
  97. + GFP_KERNEL);
  98. + if (!leds_data)
  99. + return -ENOMEM;
  100. +
  101. + for (i = 0; i < pdata->num_leds; i++) {
  102. + cur_led = &pdata->leds[i];
  103. + led_dat = &leds_data[i];
  104. +
  105. + led_dat->cdev.name = cur_led->name;
  106. + led_dat->cdev.default_trigger = cur_led->default_trigger;
  107. + led_dat->cdev.brightness_set = latch_led_set;
  108. + led_dat->cdev.brightness = LED_OFF;
  109. + led_dat->bit = cur_led->bit;
  110. + led_dat->set_led = pdata->set_led ? pdata->set_led : latch_set_led;
  111. +
  112. + ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
  113. + if (ret < 0) {
  114. + goto err;
  115. + }
  116. + }
  117. +
  118. + if (!pdata->set_led) {
  119. + iobase = ioremap_nocache(pdata->mem, 0x1000);
  120. + writeb(0xFF, iobase);
  121. + }
  122. + platform_set_drvdata(pdev, leds_data);
  123. +
  124. + return 0;
  125. +
  126. +err:
  127. + if (i > 0) {
  128. + for (i = i - 1; i >= 0; i--) {
  129. + led_classdev_unregister(&leds_data[i].cdev);
  130. + }
  131. + }
  132. +
  133. + kfree(leds_data);
  134. +
  135. + return ret;
  136. +}
  137. +
  138. +static int latch_led_remove(struct platform_device *pdev)
  139. +{
  140. + int i;
  141. + struct latch_led_platform_data *pdata = pdev->dev.platform_data;
  142. + struct latch_led_data *leds_data;
  143. +
  144. + leds_data = platform_get_drvdata(pdev);
  145. +
  146. + for (i = 0; i < pdata->num_leds; i++) {
  147. + led_classdev_unregister(&leds_data[i].cdev);
  148. + cancel_work_sync(&leds_data[i].work);
  149. + }
  150. +
  151. + kfree(leds_data);
  152. +
  153. + return 0;
  154. +}
  155. +
  156. +static struct platform_driver latch_led_driver = {
  157. + .probe = latch_led_probe,
  158. + .remove = latch_led_remove,
  159. + .driver = {
  160. + .name = "leds-latch",
  161. + .owner = THIS_MODULE,
  162. + },
  163. +};
  164. +
  165. +static int __init latch_led_init(void)
  166. +{
  167. + return platform_driver_register(&latch_led_driver);
  168. +}
  169. +
  170. +static void __exit latch_led_exit(void)
  171. +{
  172. + platform_driver_unregister(&latch_led_driver);
  173. +}
  174. +
  175. +module_init(latch_led_init);
  176. +module_exit(latch_led_exit);
  177. +
  178. +MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
  179. +MODULE_DESCRIPTION("Latch LED driver");
  180. --- a/include/linux/leds.h
  181. +++ b/include/linux/leds.h
  182. @@ -385,4 +385,18 @@ static inline void ledtrig_cpu(enum cpu_
  183. }
  184. #endif
  185. +/* For the leds-latch driver */
  186. +struct latch_led {
  187. + const char *name;
  188. + char *default_trigger;
  189. + unsigned bit;
  190. +};
  191. +
  192. +struct latch_led_platform_data {
  193. + int num_leds;
  194. + u32 mem;
  195. + struct latch_led *leds;
  196. + void (*set_led)(u8 bit, enum led_brightness value);
  197. +};
  198. +
  199. #endif /* __LINUX_LEDS_H_INCLUDED */