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