4830b198051f610fafaf2b4f5a453807a1ab7b58
[openwrt/svn-archive/archive.git] / target / linux / ixp4xx / patches-2.6.25 / 031-ixp4xx_fsg_led_driver.patch
1 From a66e34fefb3f8142d7f16808563eb610225f6e77 Mon Sep 17 00:00:00 2001
2 From: Rod Whitby <rod@whitby.id.au>
3 Date: Tue, 29 Jan 2008 23:17:42 +1030
4 Subject: [PATCH] leds: Add new driver for the LEDs on the Freecom FSG-3
5
6 The LEDs on the Freecom FSG-3 are connected to an external
7 memory-mapped latch on the ixp4xx expansion bus, and therefore cannot
8 be supported by any of the existing LEDs drivers.
9
10 Signed-off-by: Rod Whitby <rod@whitby.id.au>
11 --
12 PATCH FOLLOWS
13 KernelVersion: v2.6.25-rc6-117-g457fb60
14 ---
15 drivers/leds/Kconfig | 6 +
16 drivers/leds/Makefile | 1 +
17 drivers/leds/leds-fsg.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++
18 3 files changed, 268 insertions(+), 0 deletions(-)
19 create mode 100644 drivers/leds/leds-fsg.c
20
21 Index: linux-2.6.25.1/drivers/leds/Kconfig
22 ===================================================================
23 --- linux-2.6.25.1.orig/drivers/leds/Kconfig
24 +++ linux-2.6.25.1/drivers/leds/Kconfig
25 @@ -46,6 +46,12 @@ config LEDS_SPITZ
26 This option enables support for the LEDs on Sharp Zaurus
27 SL-Cxx00 series (C1000, C3000, C3100).
28
29 +config LEDS_FSG
30 + tristate "LED Support for the Freecom FSG-3"
31 + depends on LEDS_CLASS && MACH_FSG
32 + help
33 + This option enables support for the LEDs on the Freecom FSG-3.
34 +
35 config LEDS_TOSA
36 tristate "LED Support for the Sharp SL-6000 series"
37 depends on LEDS_CLASS && PXA_SHARPSL
38 Index: linux-2.6.25.1/drivers/leds/Makefile
39 ===================================================================
40 --- linux-2.6.25.1.orig/drivers/leds/Makefile
41 +++ linux-2.6.25.1/drivers/leds/Makefile
42 @@ -22,6 +22,7 @@ obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
43 obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
44 obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
45 obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
46 +obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
47
48 # LED Triggers
49 obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
50 Index: linux-2.6.25.1/drivers/leds/leds-fsg.c
51 ===================================================================
52 --- /dev/null
53 +++ linux-2.6.25.1/drivers/leds/leds-fsg.c
54 @@ -0,0 +1,261 @@
55 +/*
56 + * LED Driver for the Freecom FSG-3
57 + *
58 + * Copyright (c) 2008 Rod Whitby <rod@whitby.id.au>
59 + *
60 + * Author: Rod Whitby <rod@whitby.id.au>
61 + *
62 + * Based on leds-spitz.c
63 + * Copyright 2005-2006 Openedhand Ltd.
64 + * Author: Richard Purdie <rpurdie@openedhand.com>
65 + *
66 + * This program is free software; you can redistribute it and/or modify
67 + * it under the terms of the GNU General Public License version 2 as
68 + * published by the Free Software Foundation.
69 + *
70 + */
71 +
72 +#include <linux/kernel.h>
73 +#include <linux/init.h>
74 +#include <linux/platform_device.h>
75 +#include <linux/leds.h>
76 +#include <asm/arch/hardware.h>
77 +#include <asm/io.h>
78 +
79 +static short __iomem *latch_address;
80 +static unsigned short latch_value;
81 +
82 +
83 +static void fsg_led_wlan_set(struct led_classdev *led_cdev,
84 + enum led_brightness value)
85 +{
86 + if (value) {
87 + latch_value &= ~(1 << FSG_LED_WLAN_BIT);
88 + *latch_address = latch_value;
89 + } else {
90 + latch_value |= (1 << FSG_LED_WLAN_BIT);
91 + *latch_address = latch_value;
92 + }
93 +}
94 +
95 +static void fsg_led_wan_set(struct led_classdev *led_cdev,
96 + enum led_brightness value)
97 +{
98 + if (value) {
99 + latch_value &= ~(1 << FSG_LED_WAN_BIT);
100 + *latch_address = latch_value;
101 + } else {
102 + latch_value |= (1 << FSG_LED_WAN_BIT);
103 + *latch_address = latch_value;
104 + }
105 +}
106 +
107 +static void fsg_led_sata_set(struct led_classdev *led_cdev,
108 + enum led_brightness value)
109 +{
110 + if (value) {
111 + latch_value &= ~(1 << FSG_LED_SATA_BIT);
112 + *latch_address = latch_value;
113 + } else {
114 + latch_value |= (1 << FSG_LED_SATA_BIT);
115 + *latch_address = latch_value;
116 + }
117 +}
118 +
119 +static void fsg_led_usb_set(struct led_classdev *led_cdev,
120 + enum led_brightness value)
121 +{
122 + if (value) {
123 + latch_value &= ~(1 << FSG_LED_USB_BIT);
124 + *latch_address = latch_value;
125 + } else {
126 + latch_value |= (1 << FSG_LED_USB_BIT);
127 + *latch_address = latch_value;
128 + }
129 +}
130 +
131 +static void fsg_led_sync_set(struct led_classdev *led_cdev,
132 + enum led_brightness value)
133 +{
134 + if (value) {
135 + latch_value &= ~(1 << FSG_LED_SYNC_BIT);
136 + *latch_address = latch_value;
137 + } else {
138 + latch_value |= (1 << FSG_LED_SYNC_BIT);
139 + *latch_address = latch_value;
140 + }
141 +}
142 +
143 +static void fsg_led_ring_set(struct led_classdev *led_cdev,
144 + enum led_brightness value)
145 +{
146 + if (value) {
147 + latch_value &= ~(1 << FSG_LED_RING_BIT);
148 + *latch_address = latch_value;
149 + } else {
150 + latch_value |= (1 << FSG_LED_RING_BIT);
151 + *latch_address = latch_value;
152 + }
153 +}
154 +
155 +
156 +
157 +static struct led_classdev fsg_wlan_led = {
158 + .name = "fsg:blue:wlan",
159 + .brightness_set = fsg_led_wlan_set,
160 +};
161 +
162 +static struct led_classdev fsg_wan_led = {
163 + .name = "fsg:blue:wan",
164 + .brightness_set = fsg_led_wan_set,
165 +};
166 +
167 +static struct led_classdev fsg_sata_led = {
168 + .name = "fsg:blue:sata",
169 + .brightness_set = fsg_led_sata_set,
170 +};
171 +
172 +static struct led_classdev fsg_usb_led = {
173 + .name = "fsg:blue:usb",
174 + .brightness_set = fsg_led_usb_set,
175 +};
176 +
177 +static struct led_classdev fsg_sync_led = {
178 + .name = "fsg:blue:sync",
179 + .brightness_set = fsg_led_sync_set,
180 +};
181 +
182 +static struct led_classdev fsg_ring_led = {
183 + .name = "fsg:blue:ring",
184 + .brightness_set = fsg_led_ring_set,
185 +};
186 +
187 +
188 +
189 +#ifdef CONFIG_PM
190 +static int fsg_led_suspend(struct platform_device *dev, pm_message_t state)
191 +{
192 + led_classdev_suspend(&fsg_wlan_led);
193 + led_classdev_suspend(&fsg_wan_led);
194 + led_classdev_suspend(&fsg_sata_led);
195 + led_classdev_suspend(&fsg_usb_led);
196 + led_classdev_suspend(&fsg_sync_led);
197 + led_classdev_suspend(&fsg_ring_led);
198 + return 0;
199 +}
200 +
201 +static int fsg_led_resume(struct platform_device *dev)
202 +{
203 + led_classdev_resume(&fsg_wlan_led);
204 + led_classdev_resume(&fsg_wan_led);
205 + led_classdev_resume(&fsg_sata_led);
206 + led_classdev_resume(&fsg_usb_led);
207 + led_classdev_resume(&fsg_sync_led);
208 + led_classdev_resume(&fsg_ring_led);
209 + return 0;
210 +}
211 +#endif
212 +
213 +
214 +static int fsg_led_probe(struct platform_device *pdev)
215 +{
216 + int ret;
217 +
218 + ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
219 + if (ret < 0)
220 + goto failwlan;
221 +
222 + ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
223 + if (ret < 0)
224 + goto failwan;
225 +
226 + ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
227 + if (ret < 0)
228 + goto failsata;
229 +
230 + ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
231 + if (ret < 0)
232 + goto failusb;
233 +
234 + ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
235 + if (ret < 0)
236 + goto failsync;
237 +
238 + ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
239 + if (ret < 0)
240 + goto failring;
241 +
242 + /* Map the LED chip select address space */
243 + latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
244 + if (!latch_address) {
245 + ret = -ENOMEM;
246 + goto failremap;
247 + }
248 +
249 + latch_value = 0xffff;
250 + *latch_address = latch_value;
251 +
252 + return ret;
253 +
254 + failremap:
255 + led_classdev_unregister(&fsg_ring_led);
256 + failring:
257 + led_classdev_unregister(&fsg_sync_led);
258 + failsync:
259 + led_classdev_unregister(&fsg_usb_led);
260 + failusb:
261 + led_classdev_unregister(&fsg_sata_led);
262 + failsata:
263 + led_classdev_unregister(&fsg_wan_led);
264 + failwan:
265 + led_classdev_unregister(&fsg_wlan_led);
266 + failwlan:
267 +
268 + return ret;
269 +}
270 +
271 +static int fsg_led_remove(struct platform_device *pdev)
272 +{
273 + iounmap(latch_address);
274 +
275 + led_classdev_unregister(&fsg_wlan_led);
276 + led_classdev_unregister(&fsg_wan_led);
277 + led_classdev_unregister(&fsg_sata_led);
278 + led_classdev_unregister(&fsg_usb_led);
279 + led_classdev_unregister(&fsg_sync_led);
280 + led_classdev_unregister(&fsg_ring_led);
281 +
282 + return 0;
283 +}
284 +
285 +
286 +static struct platform_driver fsg_led_driver = {
287 + .probe = fsg_led_probe,
288 + .remove = fsg_led_remove,
289 +#ifdef CONFIG_PM
290 + .suspend = fsg_led_suspend,
291 + .resume = fsg_led_resume,
292 +#endif
293 + .driver = {
294 + .name = "fsg-led",
295 + },
296 +};
297 +
298 +
299 +static int __init fsg_led_init(void)
300 +{
301 + return platform_driver_register(&fsg_led_driver);
302 +}
303 +
304 +static void __exit fsg_led_exit(void)
305 +{
306 + platform_driver_unregister(&fsg_led_driver);
307 +}
308 +
309 +
310 +module_init(fsg_led_init);
311 +module_exit(fsg_led_exit);
312 +
313 +MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
314 +MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
315 +MODULE_LICENSE("GPL");