Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac802...
[firefly-linux-kernel-4.4.55.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/platform_device.h>
20 #include <linux/leds.h>
21 #include <linux/module.h>
22 #include <linux/io.h>
23 #include <mach/hardware.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 *) devm_ioremap(&pdev->dev,
152                                                 IXP4XX_EXP_BUS_BASE(2), 512);
153         if (!latch_address)
154                 return -ENOMEM;
155
156         latch_value = 0xffff;
157         *latch_address = latch_value;
158
159         ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
160         if (ret < 0)
161                 goto failwlan;
162
163         ret = led_classdev_register(&pdev->dev, &fsg_wan_led);
164         if (ret < 0)
165                 goto failwan;
166
167         ret = led_classdev_register(&pdev->dev, &fsg_sata_led);
168         if (ret < 0)
169                 goto failsata;
170
171         ret = led_classdev_register(&pdev->dev, &fsg_usb_led);
172         if (ret < 0)
173                 goto failusb;
174
175         ret = led_classdev_register(&pdev->dev, &fsg_sync_led);
176         if (ret < 0)
177                 goto failsync;
178
179         ret = led_classdev_register(&pdev->dev, &fsg_ring_led);
180         if (ret < 0)
181                 goto failring;
182
183         return ret;
184
185  failring:
186         led_classdev_unregister(&fsg_sync_led);
187  failsync:
188         led_classdev_unregister(&fsg_usb_led);
189  failusb:
190         led_classdev_unregister(&fsg_sata_led);
191  failsata:
192         led_classdev_unregister(&fsg_wan_led);
193  failwan:
194         led_classdev_unregister(&fsg_wlan_led);
195  failwlan:
196
197         return ret;
198 }
199
200 static int fsg_led_remove(struct platform_device *pdev)
201 {
202         led_classdev_unregister(&fsg_wlan_led);
203         led_classdev_unregister(&fsg_wan_led);
204         led_classdev_unregister(&fsg_sata_led);
205         led_classdev_unregister(&fsg_usb_led);
206         led_classdev_unregister(&fsg_sync_led);
207         led_classdev_unregister(&fsg_ring_led);
208
209         return 0;
210 }
211
212
213 static struct platform_driver fsg_led_driver = {
214         .probe          = fsg_led_probe,
215         .remove         = fsg_led_remove,
216         .driver         = {
217                 .name           = "fsg-led",
218         },
219 };
220
221 module_platform_driver(fsg_led_driver);
222
223 MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
224 MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
225 MODULE_LICENSE("GPL");