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 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 *) 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 200static 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 213static 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 221module_platform_driver(fsg_led_driver); 222 223MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>"); 224MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); 225MODULE_LICENSE("GPL"); 226