| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 22 | #include <mach/hardware.h> | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 102 | static struct led_classdev fsg_wlan_led = { | 
|  | 103 | .name			= "fsg:blue:wlan", | 
|  | 104 | .brightness_set		= fsg_led_wlan_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 105 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 106 | }; | 
|  | 107 |  | 
|  | 108 | static struct led_classdev fsg_wan_led = { | 
|  | 109 | .name			= "fsg:blue:wan", | 
|  | 110 | .brightness_set		= fsg_led_wan_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 111 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 112 | }; | 
|  | 113 |  | 
|  | 114 | static struct led_classdev fsg_sata_led = { | 
|  | 115 | .name			= "fsg:blue:sata", | 
|  | 116 | .brightness_set		= fsg_led_sata_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 117 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 118 | }; | 
|  | 119 |  | 
|  | 120 | static struct led_classdev fsg_usb_led = { | 
|  | 121 | .name			= "fsg:blue:usb", | 
|  | 122 | .brightness_set		= fsg_led_usb_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 123 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 124 | }; | 
|  | 125 |  | 
|  | 126 | static struct led_classdev fsg_sync_led = { | 
|  | 127 | .name			= "fsg:blue:sync", | 
|  | 128 | .brightness_set		= fsg_led_sync_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 129 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 130 | }; | 
|  | 131 |  | 
|  | 132 | static struct led_classdev fsg_ring_led = { | 
|  | 133 | .name			= "fsg:blue:ring", | 
|  | 134 | .brightness_set		= fsg_led_ring_set, | 
| Richard Purdie | 859cb7f | 2009-01-08 17:55:03 +0000 | [diff] [blame] | 135 | .flags			= LED_CORE_SUSPENDRESUME, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 136 | }; | 
|  | 137 |  | 
|  | 138 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 139 | static int fsg_led_probe(struct platform_device *pdev) | 
|  | 140 | { | 
|  | 141 | int ret; | 
|  | 142 |  | 
| Sven Wegener | 07f696c | 2008-10-03 15:23:47 -0700 | [diff] [blame] | 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 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 177 | return ret; | 
|  | 178 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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: | 
| Sven Wegener | 07f696c | 2008-10-03 15:23:47 -0700 | [diff] [blame] | 190 | iounmap(latch_address); | 
|  | 191 | failremap: | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 192 |  | 
|  | 193 | return ret; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | static int fsg_led_remove(struct platform_device *pdev) | 
|  | 197 | { | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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 |  | 
| Sven Wegener | 07f696c | 2008-10-03 15:23:47 -0700 | [diff] [blame] | 205 | iounmap(latch_address); | 
|  | 206 |  | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 207 | return 0; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 |  | 
|  | 211 | static struct platform_driver fsg_led_driver = { | 
|  | 212 | .probe		= fsg_led_probe, | 
|  | 213 | .remove		= fsg_led_remove, | 
| Rod Whitby | 3b2e46f | 2008-04-24 23:43:09 +0100 | [diff] [blame] | 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"); |