1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * LED Driver for the Freecom FSG-3 4 * 5 * Copyright (c) 2008 Rod Whitby <rod@whitby.id.au> 6 * 7 * Author: Rod Whitby <rod@whitby.id.au> 8 * 9 * Based on leds-spitz.c 10 * Copyright 2005-2006 Openedhand Ltd. 11 * Author: Richard Purdie <rpurdie@openedhand.com> 12 */ 13 14#include <linux/kernel.h> 15#include <linux/platform_device.h> 16#include <linux/leds.h> 17#include <linux/module.h> 18#include <linux/io.h> 19#include <mach/hardware.h> 20 21#define FSG_LED_WLAN_BIT 0 22#define FSG_LED_WAN_BIT 1 23#define FSG_LED_SATA_BIT 2 24#define FSG_LED_USB_BIT 4 25#define FSG_LED_RING_BIT 5 26#define FSG_LED_SYNC_BIT 7 27 28static short __iomem *latch_address; 29static unsigned short latch_value; 30 31 32static void fsg_led_wlan_set(struct led_classdev *led_cdev, 33 enum led_brightness value) 34{ 35 if (value) { 36 latch_value &= ~(1 << FSG_LED_WLAN_BIT); 37 *latch_address = latch_value; 38 } else { 39 latch_value |= (1 << FSG_LED_WLAN_BIT); 40 *latch_address = latch_value; 41 } 42} 43 44static void fsg_led_wan_set(struct led_classdev *led_cdev, 45 enum led_brightness value) 46{ 47 if (value) { 48 latch_value &= ~(1 << FSG_LED_WAN_BIT); 49 *latch_address = latch_value; 50 } else { 51 latch_value |= (1 << FSG_LED_WAN_BIT); 52 *latch_address = latch_value; 53 } 54} 55 56static void fsg_led_sata_set(struct led_classdev *led_cdev, 57 enum led_brightness value) 58{ 59 if (value) { 60 latch_value &= ~(1 << FSG_LED_SATA_BIT); 61 *latch_address = latch_value; 62 } else { 63 latch_value |= (1 << FSG_LED_SATA_BIT); 64 *latch_address = latch_value; 65 } 66} 67 68static void fsg_led_usb_set(struct led_classdev *led_cdev, 69 enum led_brightness value) 70{ 71 if (value) { 72 latch_value &= ~(1 << FSG_LED_USB_BIT); 73 *latch_address = latch_value; 74 } else { 75 latch_value |= (1 << FSG_LED_USB_BIT); 76 *latch_address = latch_value; 77 } 78} 79 80static void fsg_led_sync_set(struct led_classdev *led_cdev, 81 enum led_brightness value) 82{ 83 if (value) { 84 latch_value &= ~(1 << FSG_LED_SYNC_BIT); 85 *latch_address = latch_value; 86 } else { 87 latch_value |= (1 << FSG_LED_SYNC_BIT); 88 *latch_address = latch_value; 89 } 90} 91 92static void fsg_led_ring_set(struct led_classdev *led_cdev, 93 enum led_brightness value) 94{ 95 if (value) { 96 latch_value &= ~(1 << FSG_LED_RING_BIT); 97 *latch_address = latch_value; 98 } else { 99 latch_value |= (1 << FSG_LED_RING_BIT); 100 *latch_address = latch_value; 101 } 102} 103 104 105static struct led_classdev fsg_wlan_led = { 106 .name = "fsg:blue:wlan", 107 .brightness_set = fsg_led_wlan_set, 108 .flags = LED_CORE_SUSPENDRESUME, 109}; 110 111static struct led_classdev fsg_wan_led = { 112 .name = "fsg:blue:wan", 113 .brightness_set = fsg_led_wan_set, 114 .flags = LED_CORE_SUSPENDRESUME, 115}; 116 117static struct led_classdev fsg_sata_led = { 118 .name = "fsg:blue:sata", 119 .brightness_set = fsg_led_sata_set, 120 .flags = LED_CORE_SUSPENDRESUME, 121}; 122 123static struct led_classdev fsg_usb_led = { 124 .name = "fsg:blue:usb", 125 .brightness_set = fsg_led_usb_set, 126 .flags = LED_CORE_SUSPENDRESUME, 127}; 128 129static struct led_classdev fsg_sync_led = { 130 .name = "fsg:blue:sync", 131 .brightness_set = fsg_led_sync_set, 132 .flags = LED_CORE_SUSPENDRESUME, 133}; 134 135static struct led_classdev fsg_ring_led = { 136 .name = "fsg:blue:ring", 137 .brightness_set = fsg_led_ring_set, 138 .flags = LED_CORE_SUSPENDRESUME, 139}; 140 141 142static int fsg_led_probe(struct platform_device *pdev) 143{ 144 int ret; 145 146 /* Map the LED chip select address space */ 147 latch_address = (unsigned short *) devm_ioremap(&pdev->dev, 148 IXP4XX_EXP_BUS_BASE(2), 512); 149 if (!latch_address) 150 return -ENOMEM; 151 152 latch_value = 0xffff; 153 *latch_address = latch_value; 154 155 ret = devm_led_classdev_register(&pdev->dev, &fsg_wlan_led); 156 if (ret < 0) 157 return ret; 158 159 ret = devm_led_classdev_register(&pdev->dev, &fsg_wan_led); 160 if (ret < 0) 161 return ret; 162 163 ret = devm_led_classdev_register(&pdev->dev, &fsg_sata_led); 164 if (ret < 0) 165 return ret; 166 167 ret = devm_led_classdev_register(&pdev->dev, &fsg_usb_led); 168 if (ret < 0) 169 return ret; 170 171 ret = devm_led_classdev_register(&pdev->dev, &fsg_sync_led); 172 if (ret < 0) 173 return ret; 174 175 ret = devm_led_classdev_register(&pdev->dev, &fsg_ring_led); 176 if (ret < 0) 177 return ret; 178 179 return ret; 180} 181 182static struct platform_driver fsg_led_driver = { 183 .probe = fsg_led_probe, 184 .driver = { 185 .name = "fsg-led", 186 }, 187}; 188 189module_platform_driver(fsg_led_driver); 190 191MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>"); 192MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); 193MODULE_LICENSE("GPL"); 194