Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / drivers / leds / leds-fsg.c
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>
22 #include <mach/hardware.h>
23 #include <asm/io.h>
24
25 #define FSG_LED_WLAN_BIT        0
26 #define FSG_LED_WAN_BIT         1
27 #define FSG_LED_SATA_BIT        2
28 #define FSG_LED_USB_BIT         4
29 #define FSG_LED_RING_BIT        5
30 #define FSG_LED_SYNC_BIT        7
31
32 static short __iomem *latch_address;
33 static unsigned short latch_value;
34
35
36 static void fsg_led_wlan_set(struct led_classdev *led_cdev,
37                              enum led_brightness value)
38 {
39         if (value) {
40                 latch_value &= ~(1 << FSG_LED_WLAN_BIT);
41                 *latch_address = latch_value;
42         } else {
43                 latch_value |=  (1 << FSG_LED_WLAN_BIT);
44                 *latch_address = latch_value;
45         }
46 }
47
48 static void fsg_led_wan_set(struct led_classdev *led_cdev,
49                             enum led_brightness value)
50 {
51         if (value) {
52                 latch_value &= ~(1 << FSG_LED_WAN_BIT);
53                 *latch_address = latch_value;
54         } else {
55                 latch_value |=  (1 << FSG_LED_WAN_BIT);
56                 *latch_address = latch_value;
57         }
58 }
59
60 static void fsg_led_sata_set(struct led_classdev *led_cdev,
61                              enum led_brightness value)
62 {
63         if (value) {
64                 latch_value &= ~(1 << FSG_LED_SATA_BIT);
65                 *latch_address = latch_value;
66         } else {
67                 latch_value |=  (1 << FSG_LED_SATA_BIT);
68                 *latch_address = latch_value;
69         }
70 }
71
72 static void fsg_led_usb_set(struct led_classdev *led_cdev,
73                             enum led_brightness value)
74 {
75         if (value) {
76                 latch_value &= ~(1 << FSG_LED_USB_BIT);
77                 *latch_address = latch_value;
78         } else {
79                 latch_value |=  (1 << FSG_LED_USB_BIT);
80                 *latch_address = latch_value;
81         }
82 }
83
84 static void fsg_led_sync_set(struct led_classdev *led_cdev,
85                              enum led_brightness value)
86 {
87         if (value) {
88                 latch_value &= ~(1 << FSG_LED_SYNC_BIT);
89                 *latch_address = latch_value;
90         } else {
91                 latch_value |=  (1 << FSG_LED_SYNC_BIT);
92                 *latch_address = latch_value;
93         }
94 }
95
96 static void fsg_led_ring_set(struct led_classdev *led_cdev,
97                              enum led_brightness value)
98 {
99         if (value) {
100                 latch_value &= ~(1 << FSG_LED_RING_BIT);
101                 *latch_address = latch_value;
102         } else {
103                 latch_value |=  (1 << FSG_LED_RING_BIT);
104                 *latch_address = latch_value;
105         }
106 }
107
108
109 static struct led_classdev fsg_wlan_led = {
110         .name                   = "fsg:blue:wlan",
111         .brightness_set         = fsg_led_wlan_set,
112         .flags                  = LED_CORE_SUSPENDRESUME,
113 };
114
115 static struct led_classdev fsg_wan_led = {
116         .name                   = "fsg:blue:wan",
117         .brightness_set         = fsg_led_wan_set,
118         .flags                  = LED_CORE_SUSPENDRESUME,
119 };
120
121 static struct led_classdev fsg_sata_led = {
122         .name                   = "fsg:blue:sata",
123         .brightness_set         = fsg_led_sata_set,
124         .flags                  = LED_CORE_SUSPENDRESUME,
125 };
126
127 static struct led_classdev fsg_usb_led = {
128         .name                   = "fsg:blue:usb",
129         .brightness_set         = fsg_led_usb_set,
130         .flags                  = LED_CORE_SUSPENDRESUME,
131 };
132
133 static struct led_classdev fsg_sync_led = {
134         .name                   = "fsg:blue:sync",
135         .brightness_set         = fsg_led_sync_set,
136         .flags                  = LED_CORE_SUSPENDRESUME,
137 };
138
139 static struct led_classdev fsg_ring_led = {
140         .name                   = "fsg:blue:ring",
141         .brightness_set         = fsg_led_ring_set,
142         .flags                  = LED_CORE_SUSPENDRESUME,
143 };
144
145
146 static int fsg_led_probe(struct platform_device *pdev)
147 {
148         int ret;
149
150         /* Map the LED chip select address space */
151         latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
152         if (!latch_address) {
153                 ret = -ENOMEM;
154                 goto failremap;
155         }
156
157         latch_value = 0xffff;
158         *latch_address = latch_value;
159
160         ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
161         if (ret < 0)
162                 goto failwlan;
163
164         ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
165         if (ret < 0)
166                 goto failwan;
167
168         ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
169         if (ret < 0)
170                 goto failsata;
171
172         ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
173         if (ret < 0)
174                 goto failusb;
175
176         ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
177         if (ret < 0)
178                 goto failsync;
179
180         ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
181         if (ret < 0)
182                 goto failring;
183
184         return ret;
185
186  failring:
187         led_classdev_unregister(&fsg_sync_led);
188  failsync:
189         led_classdev_unregister(&fsg_usb_led);
190  failusb:
191         led_classdev_unregister(&fsg_sata_led);
192  failsata:
193         led_classdev_unregister(&fsg_wan_led);
194  failwan:
195         led_classdev_unregister(&fsg_wlan_led);
196  failwlan:
197         iounmap(latch_address);
198  failremap:
199
200         return ret;
201 }
202
203 static int fsg_led_remove(struct platform_device *pdev)
204 {
205         led_classdev_unregister(&fsg_wlan_led);
206         led_classdev_unregister(&fsg_wan_led);
207         led_classdev_unregister(&fsg_sata_led);
208         led_classdev_unregister(&fsg_usb_led);
209         led_classdev_unregister(&fsg_sync_led);
210         led_classdev_unregister(&fsg_ring_led);
211
212         iounmap(latch_address);
213
214         return 0;
215 }
216
217
218 static struct platform_driver fsg_led_driver = {
219         .probe          = fsg_led_probe,
220         .remove         = fsg_led_remove,
221         .driver         = {
222                 .name           = "fsg-led",
223         },
224 };
225
226
227 static int __init fsg_led_init(void)
228 {
229         return platform_driver_register(&fsg_led_driver);
230 }
231
232 static void __exit fsg_led_exit(void)
233 {
234         platform_driver_unregister(&fsg_led_driver);
235 }
236
237
238 module_init(fsg_led_init);
239 module_exit(fsg_led_exit);
240
241 MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
242 MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
243 MODULE_LICENSE("GPL");