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 | ||
3b2e46f8 RW |
102 | static struct led_classdev fsg_wlan_led = { |
103 | .name = "fsg:blue:wlan", | |
104 | .brightness_set = fsg_led_wlan_set, | |
859cb7f2 | 105 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
106 | }; |
107 | ||
108 | static struct led_classdev fsg_wan_led = { | |
109 | .name = "fsg:blue:wan", | |
110 | .brightness_set = fsg_led_wan_set, | |
859cb7f2 | 111 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
112 | }; |
113 | ||
114 | static struct led_classdev fsg_sata_led = { | |
115 | .name = "fsg:blue:sata", | |
116 | .brightness_set = fsg_led_sata_set, | |
859cb7f2 | 117 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
118 | }; |
119 | ||
120 | static struct led_classdev fsg_usb_led = { | |
121 | .name = "fsg:blue:usb", | |
122 | .brightness_set = fsg_led_usb_set, | |
859cb7f2 | 123 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
124 | }; |
125 | ||
126 | static struct led_classdev fsg_sync_led = { | |
127 | .name = "fsg:blue:sync", | |
128 | .brightness_set = fsg_led_sync_set, | |
859cb7f2 | 129 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
130 | }; |
131 | ||
132 | static struct led_classdev fsg_ring_led = { | |
133 | .name = "fsg:blue:ring", | |
134 | .brightness_set = fsg_led_ring_set, | |
859cb7f2 | 135 | .flags = LED_CORE_SUSPENDRESUME, |
3b2e46f8 RW |
136 | }; |
137 | ||
138 | ||
3b2e46f8 RW |
139 | static int fsg_led_probe(struct platform_device *pdev) |
140 | { | |
141 | int ret; | |
142 | ||
07f696c7 SW |
143 | /* Map the LED chip select address space */ |
144 | latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512); | |
145 | if (!latch_address) { | |
146 | ret = -ENOMEM; | |
147 | goto failremap; | |
148 | } | |
149 | ||
150 | latch_value = 0xffff; | |
151 | *latch_address = latch_value; | |
152 | ||
3b2e46f8 RW |
153 | ret = led_classdev_register(&pdev->dev, &fsg_wlan_led); |
154 | if (ret < 0) | |
155 | goto failwlan; | |
156 | ||
157 | ret = led_classdev_register(&pdev->dev, &fsg_wan_led); | |
158 | if (ret < 0) | |
159 | goto failwan; | |
160 | ||
161 | ret = led_classdev_register(&pdev->dev, &fsg_sata_led); | |
162 | if (ret < 0) | |
163 | goto failsata; | |
164 | ||
165 | ret = led_classdev_register(&pdev->dev, &fsg_usb_led); | |
166 | if (ret < 0) | |
167 | goto failusb; | |
168 | ||
169 | ret = led_classdev_register(&pdev->dev, &fsg_sync_led); | |
170 | if (ret < 0) | |
171 | goto failsync; | |
172 | ||
173 | ret = led_classdev_register(&pdev->dev, &fsg_ring_led); | |
174 | if (ret < 0) | |
175 | goto failring; | |
176 | ||
3b2e46f8 RW |
177 | return ret; |
178 | ||
3b2e46f8 RW |
179 | failring: |
180 | led_classdev_unregister(&fsg_sync_led); | |
181 | failsync: | |
182 | led_classdev_unregister(&fsg_usb_led); | |
183 | failusb: | |
184 | led_classdev_unregister(&fsg_sata_led); | |
185 | failsata: | |
186 | led_classdev_unregister(&fsg_wan_led); | |
187 | failwan: | |
188 | led_classdev_unregister(&fsg_wlan_led); | |
189 | failwlan: | |
07f696c7 SW |
190 | iounmap(latch_address); |
191 | failremap: | |
3b2e46f8 RW |
192 | |
193 | return ret; | |
194 | } | |
195 | ||
196 | static int fsg_led_remove(struct platform_device *pdev) | |
197 | { | |
3b2e46f8 RW |
198 | led_classdev_unregister(&fsg_wlan_led); |
199 | led_classdev_unregister(&fsg_wan_led); | |
200 | led_classdev_unregister(&fsg_sata_led); | |
201 | led_classdev_unregister(&fsg_usb_led); | |
202 | led_classdev_unregister(&fsg_sync_led); | |
203 | led_classdev_unregister(&fsg_ring_led); | |
204 | ||
07f696c7 SW |
205 | iounmap(latch_address); |
206 | ||
3b2e46f8 RW |
207 | return 0; |
208 | } | |
209 | ||
210 | ||
211 | static struct platform_driver fsg_led_driver = { | |
212 | .probe = fsg_led_probe, | |
213 | .remove = fsg_led_remove, | |
3b2e46f8 RW |
214 | .driver = { |
215 | .name = "fsg-led", | |
216 | }, | |
217 | }; | |
218 | ||
219 | ||
220 | static int __init fsg_led_init(void) | |
221 | { | |
222 | return platform_driver_register(&fsg_led_driver); | |
223 | } | |
224 | ||
225 | static void __exit fsg_led_exit(void) | |
226 | { | |
227 | platform_driver_unregister(&fsg_led_driver); | |
228 | } | |
229 | ||
230 | ||
231 | module_init(fsg_led_init); | |
232 | module_exit(fsg_led_exit); | |
233 | ||
234 | MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>"); | |
235 | MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); | |
236 | MODULE_LICENSE("GPL"); |