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 32static short __iomem *latch_address; 33static unsigned short latch_value; 34 35 36static 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 48static 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 60static 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 72static 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 84static 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 96static 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 109static 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 115static 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 121static 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 127static 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 133static 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 139static 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 146static 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 203static 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 218static 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 227static int __init fsg_led_init(void) 228{ 229 return platform_driver_register(&fsg_led_driver); 230} 231 232static void __exit fsg_led_exit(void) 233{ 234 platform_driver_unregister(&fsg_led_driver); 235} 236 237 238module_init(fsg_led_init); 239module_exit(fsg_led_exit); 240 241MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>"); 242MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); 243MODULE_LICENSE("GPL"); 244