Commit | Line | Data |
---|---|---|
3b2e46f8 RW |
1 | /* |
2 | * LED Driver for the Freecom FSG-3 | |
3 | * | |
4 | * Copyright (c) 2008 Rod Whitby <rod@whitby.id.au> | |
5 | * | |
6 | * Author: Rod Whitby <rod@whitby.id.au> | |
7 | * | |
8 | * Based on leds-spitz.c | |
9 | * Copyright 2005-2006 Openedhand Ltd. | |
10 | * Author: Richard Purdie <rpurdie@openedhand.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License version 2 as | |
14 | * published by the Free Software Foundation. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/kernel.h> | |
19 | #include <linux/init.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/leds.h> | |
a09e64fb | 22 | #include <mach/hardware.h> |
3b2e46f8 RW |
23 | #include <asm/io.h> |
24 | ||
25 | static short __iomem *latch_address; | |
26 | static unsigned short latch_value; | |
27 | ||
28 | ||
29 | static void fsg_led_wlan_set(struct led_classdev *led_cdev, | |
30 | enum led_brightness value) | |
31 | { | |
32 | if (value) { | |
33 | latch_value &= ~(1 << FSG_LED_WLAN_BIT); | |
34 | *latch_address = latch_value; | |
35 | } else { | |
36 | latch_value |= (1 << FSG_LED_WLAN_BIT); | |
37 | *latch_address = latch_value; | |
38 | } | |
39 | } | |
40 | ||
41 | static void fsg_led_wan_set(struct led_classdev *led_cdev, | |
42 | enum led_brightness value) | |
43 | { | |
44 | if (value) { | |
45 | latch_value &= ~(1 << FSG_LED_WAN_BIT); | |
46 | *latch_address = latch_value; | |
47 | } else { | |
48 | latch_value |= (1 << FSG_LED_WAN_BIT); | |
49 | *latch_address = latch_value; | |
50 | } | |
51 | } | |
52 | ||
53 | static void fsg_led_sata_set(struct led_classdev *led_cdev, | |
54 | enum led_brightness value) | |
55 | { | |
56 | if (value) { | |
57 | latch_value &= ~(1 << FSG_LED_SATA_BIT); | |
58 | *latch_address = latch_value; | |
59 | } else { | |
60 | latch_value |= (1 << FSG_LED_SATA_BIT); | |
61 | *latch_address = latch_value; | |
62 | } | |
63 | } | |
64 | ||
65 | static void fsg_led_usb_set(struct led_classdev *led_cdev, | |
66 | enum led_brightness value) | |
67 | { | |
68 | if (value) { | |
69 | latch_value &= ~(1 << FSG_LED_USB_BIT); | |
70 | *latch_address = latch_value; | |
71 | } else { | |
72 | latch_value |= (1 << FSG_LED_USB_BIT); | |
73 | *latch_address = latch_value; | |
74 | } | |
75 | } | |
76 | ||
77 | static void fsg_led_sync_set(struct led_classdev *led_cdev, | |
78 | enum led_brightness value) | |
79 | { | |
80 | if (value) { | |
81 | latch_value &= ~(1 << FSG_LED_SYNC_BIT); | |
82 | *latch_address = latch_value; | |
83 | } else { | |
84 | latch_value |= (1 << FSG_LED_SYNC_BIT); | |
85 | *latch_address = latch_value; | |
86 | } | |
87 | } | |
88 | ||
89 | static void fsg_led_ring_set(struct led_classdev *led_cdev, | |
90 | enum led_brightness value) | |
91 | { | |
92 | if (value) { | |
93 | latch_value &= ~(1 << FSG_LED_RING_BIT); | |
94 | *latch_address = latch_value; | |
95 | } else { | |
96 | latch_value |= (1 << FSG_LED_RING_BIT); | |
97 | *latch_address = latch_value; | |
98 | } | |
99 | } | |
100 | ||
101 | ||
102 | ||
103 | static struct led_classdev fsg_wlan_led = { | |
104 | .name = "fsg:blue:wlan", | |
105 | .brightness_set = fsg_led_wlan_set, | |
106 | }; | |
107 | ||
108 | static struct led_classdev fsg_wan_led = { | |
109 | .name = "fsg:blue:wan", | |
110 | .brightness_set = fsg_led_wan_set, | |
111 | }; | |
112 | ||
113 | static struct led_classdev fsg_sata_led = { | |
114 | .name = "fsg:blue:sata", | |
115 | .brightness_set = fsg_led_sata_set, | |
116 | }; | |
117 | ||
118 | static struct led_classdev fsg_usb_led = { | |
119 | .name = "fsg:blue:usb", | |
120 | .brightness_set = fsg_led_usb_set, | |
121 | }; | |
122 | ||
123 | static struct led_classdev fsg_sync_led = { | |
124 | .name = "fsg:blue:sync", | |
125 | .brightness_set = fsg_led_sync_set, | |
126 | }; | |
127 | ||
128 | static struct led_classdev fsg_ring_led = { | |
129 | .name = "fsg:blue:ring", | |
130 | .brightness_set = fsg_led_ring_set, | |
131 | }; | |
132 | ||
133 | ||
134 | ||
135 | #ifdef CONFIG_PM | |
136 | static int fsg_led_suspend(struct platform_device *dev, pm_message_t state) | |
137 | { | |
138 | led_classdev_suspend(&fsg_wlan_led); | |
139 | led_classdev_suspend(&fsg_wan_led); | |
140 | led_classdev_suspend(&fsg_sata_led); | |
141 | led_classdev_suspend(&fsg_usb_led); | |
142 | led_classdev_suspend(&fsg_sync_led); | |
143 | led_classdev_suspend(&fsg_ring_led); | |
144 | return 0; | |
145 | } | |
146 | ||
147 | static int fsg_led_resume(struct platform_device *dev) | |
148 | { | |
149 | led_classdev_resume(&fsg_wlan_led); | |
150 | led_classdev_resume(&fsg_wan_led); | |
151 | led_classdev_resume(&fsg_sata_led); | |
152 | led_classdev_resume(&fsg_usb_led); | |
153 | led_classdev_resume(&fsg_sync_led); | |
154 | led_classdev_resume(&fsg_ring_led); | |
155 | return 0; | |
156 | } | |
157 | #endif | |
158 | ||
159 | ||
160 | static int fsg_led_probe(struct platform_device *pdev) | |
161 | { | |
162 | int ret; | |
163 | ||
164 | ret = led_classdev_register(&pdev->dev, &fsg_wlan_led); | |
165 | if (ret < 0) | |
166 | goto failwlan; | |
167 | ||
168 | ret = led_classdev_register(&pdev->dev, &fsg_wan_led); | |
169 | if (ret < 0) | |
170 | goto failwan; | |
171 | ||
172 | ret = led_classdev_register(&pdev->dev, &fsg_sata_led); | |
173 | if (ret < 0) | |
174 | goto failsata; | |
175 | ||
176 | ret = led_classdev_register(&pdev->dev, &fsg_usb_led); | |
177 | if (ret < 0) | |
178 | goto failusb; | |
179 | ||
180 | ret = led_classdev_register(&pdev->dev, &fsg_sync_led); | |
181 | if (ret < 0) | |
182 | goto failsync; | |
183 | ||
184 | ret = led_classdev_register(&pdev->dev, &fsg_ring_led); | |
185 | if (ret < 0) | |
186 | goto failring; | |
187 | ||
188 | /* Map the LED chip select address space */ | |
189 | latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512); | |
190 | if (!latch_address) { | |
191 | ret = -ENOMEM; | |
192 | goto failremap; | |
193 | } | |
194 | ||
195 | latch_value = 0xffff; | |
196 | *latch_address = latch_value; | |
197 | ||
198 | return ret; | |
199 | ||
200 | failremap: | |
201 | led_classdev_unregister(&fsg_ring_led); | |
202 | failring: | |
203 | led_classdev_unregister(&fsg_sync_led); | |
204 | failsync: | |
205 | led_classdev_unregister(&fsg_usb_led); | |
206 | failusb: | |
207 | led_classdev_unregister(&fsg_sata_led); | |
208 | failsata: | |
209 | led_classdev_unregister(&fsg_wan_led); | |
210 | failwan: | |
211 | led_classdev_unregister(&fsg_wlan_led); | |
212 | failwlan: | |
213 | ||
214 | return ret; | |
215 | } | |
216 | ||
217 | static int fsg_led_remove(struct platform_device *pdev) | |
218 | { | |
219 | iounmap(latch_address); | |
220 | ||
221 | led_classdev_unregister(&fsg_wlan_led); | |
222 | led_classdev_unregister(&fsg_wan_led); | |
223 | led_classdev_unregister(&fsg_sata_led); | |
224 | led_classdev_unregister(&fsg_usb_led); | |
225 | led_classdev_unregister(&fsg_sync_led); | |
226 | led_classdev_unregister(&fsg_ring_led); | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | ||
232 | static struct platform_driver fsg_led_driver = { | |
233 | .probe = fsg_led_probe, | |
234 | .remove = fsg_led_remove, | |
235 | #ifdef CONFIG_PM | |
236 | .suspend = fsg_led_suspend, | |
237 | .resume = fsg_led_resume, | |
238 | #endif | |
239 | .driver = { | |
240 | .name = "fsg-led", | |
241 | }, | |
242 | }; | |
243 | ||
244 | ||
245 | static int __init fsg_led_init(void) | |
246 | { | |
247 | return platform_driver_register(&fsg_led_driver); | |
248 | } | |
249 | ||
250 | static void __exit fsg_led_exit(void) | |
251 | { | |
252 | platform_driver_unregister(&fsg_led_driver); | |
253 | } | |
254 | ||
255 | ||
256 | module_init(fsg_led_init); | |
257 | module_exit(fsg_led_exit); | |
258 | ||
259 | MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>"); | |
260 | MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); | |
261 | MODULE_LICENSE("GPL"); |