Root/target/linux/ixp4xx/patches-3.3/295-latch_led_driver.patch

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

Archive Download this file



interactive