leds-ns2.c (f7fafd083ccc340502448903aaddc76f10785c8c) | leds-ns2.c (4b90432dc1edca6cfc0bb338794beed46af3a472) |
---|---|
1/* 2 * leds-ns2.c - Driver for the Network Space v2 (and parents) dual-GPIO LED 3 * 4 * Copyright (C) 2010 LaCie 5 * 6 * Author: Simon Guinot <sguinot@lacie.com> 7 * 8 * Based on leds-gpio.c by Raphael Assenat <raph@8d.com> --- 17 unchanged lines hidden (view full) --- 26#include <linux/platform_device.h> 27#include <linux/slab.h> 28#include <linux/gpio.h> 29#include <linux/leds.h> 30#include <linux/module.h> 31#include <linux/platform_data/leds-kirkwood-ns2.h> 32#include <linux/of.h> 33#include <linux/of_gpio.h> | 1/* 2 * leds-ns2.c - Driver for the Network Space v2 (and parents) dual-GPIO LED 3 * 4 * Copyright (C) 2010 LaCie 5 * 6 * Author: Simon Guinot <sguinot@lacie.com> 7 * 8 * Based on leds-gpio.c by Raphael Assenat <raph@8d.com> --- 17 unchanged lines hidden (view full) --- 26#include <linux/platform_device.h> 27#include <linux/slab.h> 28#include <linux/gpio.h> 29#include <linux/leds.h> 30#include <linux/module.h> 31#include <linux/platform_data/leds-kirkwood-ns2.h> 32#include <linux/of.h> 33#include <linux/of_gpio.h> |
34#include "leds.h" |
|
34 35/* 36 * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED 37 * modes are available: off, on and SATA activity blinking. The LED modes are 38 * controlled through two GPIOs (command and slow): each combination of values 39 * for the command/slow GPIOs corresponds to a LED mode. 40 */ 41 42struct ns2_led_data { 43 struct led_classdev cdev; 44 unsigned cmd; 45 unsigned slow; | 35 36/* 37 * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED 38 * modes are available: off, on and SATA activity blinking. The LED modes are 39 * controlled through two GPIOs (command and slow): each combination of values 40 * for the command/slow GPIOs corresponds to a LED mode. 41 */ 42 43struct ns2_led_data { 44 struct led_classdev cdev; 45 unsigned cmd; 46 unsigned slow; |
47 bool can_sleep; 48 int mode_index; |
|
46 unsigned char sata; /* True when SATA mode active. */ 47 rwlock_t rw_lock; /* Lock GPIOs. */ | 49 unsigned char sata; /* True when SATA mode active. */ 50 rwlock_t rw_lock; /* Lock GPIOs. */ |
51 struct work_struct work; |
|
48 int num_modes; 49 struct ns2_led_modval *modval; 50}; 51 | 52 int num_modes; 53 struct ns2_led_modval *modval; 54}; 55 |
56static void ns2_led_work(struct work_struct *work) 57{ 58 struct ns2_led_data *led_dat = 59 container_of(work, struct ns2_led_data, work); 60 int i = led_dat->mode_index; 61 62 gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level); 63 gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level); 64} 65 |
|
52static int ns2_led_get_mode(struct ns2_led_data *led_dat, 53 enum ns2_led_modes *mode) 54{ 55 int i; 56 int ret = -EINVAL; 57 int cmd_level; 58 int slow_level; 59 | 66static int ns2_led_get_mode(struct ns2_led_data *led_dat, 67 enum ns2_led_modes *mode) 68{ 69 int i; 70 int ret = -EINVAL; 71 int cmd_level; 72 int slow_level; 73 |
60 read_lock_irq(&led_dat->rw_lock); | 74 cmd_level = gpio_get_value_cansleep(led_dat->cmd); 75 slow_level = gpio_get_value_cansleep(led_dat->slow); |
61 | 76 |
62 cmd_level = gpio_get_value(led_dat->cmd); 63 slow_level = gpio_get_value(led_dat->slow); 64 | |
65 for (i = 0; i < led_dat->num_modes; i++) { 66 if (cmd_level == led_dat->modval[i].cmd_level && 67 slow_level == led_dat->modval[i].slow_level) { 68 *mode = led_dat->modval[i].mode; 69 ret = 0; 70 break; 71 } 72 } 73 | 77 for (i = 0; i < led_dat->num_modes; i++) { 78 if (cmd_level == led_dat->modval[i].cmd_level && 79 slow_level == led_dat->modval[i].slow_level) { 80 *mode = led_dat->modval[i].mode; 81 ret = 0; 82 break; 83 } 84 } 85 |
74 read_unlock_irq(&led_dat->rw_lock); 75 | |
76 return ret; 77} 78 79static void ns2_led_set_mode(struct ns2_led_data *led_dat, 80 enum ns2_led_modes mode) 81{ 82 int i; | 86 return ret; 87} 88 89static void ns2_led_set_mode(struct ns2_led_data *led_dat, 90 enum ns2_led_modes mode) 91{ 92 int i; |
93 bool found = false; |
|
83 unsigned long flags; 84 | 94 unsigned long flags; 95 |
85 write_lock_irqsave(&led_dat->rw_lock, flags); 86 87 for (i = 0; i < led_dat->num_modes; i++) { | 96 for (i = 0; i < led_dat->num_modes; i++) |
88 if (mode == led_dat->modval[i].mode) { | 97 if (mode == led_dat->modval[i].mode) { |
89 gpio_set_value(led_dat->cmd, 90 led_dat->modval[i].cmd_level); 91 gpio_set_value(led_dat->slow, 92 led_dat->modval[i].slow_level); | 98 found = true; 99 break; |
93 } | 100 } |
101 102 if (!found) 103 return; 104 105 write_lock_irqsave(&led_dat->rw_lock, flags); 106 107 if (!led_dat->can_sleep) { 108 gpio_set_value(led_dat->cmd, 109 led_dat->modval[i].cmd_level); 110 gpio_set_value(led_dat->slow, 111 led_dat->modval[i].slow_level); 112 goto exit_unlock; |
|
94 } 95 | 113 } 114 |
115 led_dat->mode_index = i; 116 schedule_work(&led_dat->work); 117 118exit_unlock: |
|
96 write_unlock_irqrestore(&led_dat->rw_lock, flags); 97} 98 99static void ns2_led_set(struct led_classdev *led_cdev, 100 enum led_brightness value) 101{ 102 struct ns2_led_data *led_dat = 103 container_of(led_cdev, struct ns2_led_data, cdev); --- 13 unchanged lines hidden (view full) --- 117 struct device_attribute *attr, 118 const char *buff, size_t count) 119{ 120 struct led_classdev *led_cdev = dev_get_drvdata(dev); 121 struct ns2_led_data *led_dat = 122 container_of(led_cdev, struct ns2_led_data, cdev); 123 int ret; 124 unsigned long enable; | 119 write_unlock_irqrestore(&led_dat->rw_lock, flags); 120} 121 122static void ns2_led_set(struct led_classdev *led_cdev, 123 enum led_brightness value) 124{ 125 struct ns2_led_data *led_dat = 126 container_of(led_cdev, struct ns2_led_data, cdev); --- 13 unchanged lines hidden (view full) --- 140 struct device_attribute *attr, 141 const char *buff, size_t count) 142{ 143 struct led_classdev *led_cdev = dev_get_drvdata(dev); 144 struct ns2_led_data *led_dat = 145 container_of(led_cdev, struct ns2_led_data, cdev); 146 int ret; 147 unsigned long enable; |
125 enum ns2_led_modes mode; | |
126 127 ret = kstrtoul(buff, 10, &enable); 128 if (ret < 0) 129 return ret; 130 131 enable = !!enable; 132 133 if (led_dat->sata == enable) | 148 149 ret = kstrtoul(buff, 10, &enable); 150 if (ret < 0) 151 return ret; 152 153 enable = !!enable; 154 155 if (led_dat->sata == enable) |
134 return count; | 156 goto exit; |
135 | 157 |
136 ret = ns2_led_get_mode(led_dat, &mode); 137 if (ret < 0) 138 return ret; | 158 led_dat->sata = enable; |
139 | 159 |
140 if (enable && mode == NS_V2_LED_ON) | 160 if (!led_get_brightness(led_cdev)) 161 goto exit; 162 163 if (enable) |
141 ns2_led_set_mode(led_dat, NS_V2_LED_SATA); | 164 ns2_led_set_mode(led_dat, NS_V2_LED_SATA); |
142 if (!enable && mode == NS_V2_LED_SATA) | 165 else |
143 ns2_led_set_mode(led_dat, NS_V2_LED_ON); 144 | 166 ns2_led_set_mode(led_dat, NS_V2_LED_ON); 167 |
145 led_dat->sata = enable; 146 | 168exit: |
147 return count; 148} 149 150static ssize_t ns2_led_sata_show(struct device *dev, 151 struct device_attribute *attr, char *buf) 152{ 153 struct led_classdev *led_cdev = dev_get_drvdata(dev); 154 struct ns2_led_data *led_dat = --- 13 unchanged lines hidden (view full) --- 168static int 169create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, 170 const struct ns2_led *template) 171{ 172 int ret; 173 enum ns2_led_modes mode; 174 175 ret = devm_gpio_request_one(&pdev->dev, template->cmd, | 169 return count; 170} 171 172static ssize_t ns2_led_sata_show(struct device *dev, 173 struct device_attribute *attr, char *buf) 174{ 175 struct led_classdev *led_cdev = dev_get_drvdata(dev); 176 struct ns2_led_data *led_dat = --- 13 unchanged lines hidden (view full) --- 190static int 191create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, 192 const struct ns2_led *template) 193{ 194 int ret; 195 enum ns2_led_modes mode; 196 197 ret = devm_gpio_request_one(&pdev->dev, template->cmd, |
176 gpio_get_value(template->cmd) ? | 198 gpio_get_value_cansleep(template->cmd) ? |
177 GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, 178 template->name); 179 if (ret) { 180 dev_err(&pdev->dev, "%s: failed to setup command GPIO\n", 181 template->name); 182 return ret; 183 } 184 185 ret = devm_gpio_request_one(&pdev->dev, template->slow, | 199 GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, 200 template->name); 201 if (ret) { 202 dev_err(&pdev->dev, "%s: failed to setup command GPIO\n", 203 template->name); 204 return ret; 205 } 206 207 ret = devm_gpio_request_one(&pdev->dev, template->slow, |
186 gpio_get_value(template->slow) ? | 208 gpio_get_value_cansleep(template->slow) ? |
187 GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, 188 template->name); 189 if (ret) { 190 dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n", 191 template->name); 192 return ret; 193 } 194 195 rwlock_init(&led_dat->rw_lock); 196 197 led_dat->cdev.name = template->name; 198 led_dat->cdev.default_trigger = template->default_trigger; 199 led_dat->cdev.blink_set = NULL; 200 led_dat->cdev.brightness_set = ns2_led_set; 201 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; 202 led_dat->cdev.groups = ns2_led_groups; 203 led_dat->cmd = template->cmd; 204 led_dat->slow = template->slow; | 209 GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, 210 template->name); 211 if (ret) { 212 dev_err(&pdev->dev, "%s: failed to setup slow GPIO\n", 213 template->name); 214 return ret; 215 } 216 217 rwlock_init(&led_dat->rw_lock); 218 219 led_dat->cdev.name = template->name; 220 led_dat->cdev.default_trigger = template->default_trigger; 221 led_dat->cdev.blink_set = NULL; 222 led_dat->cdev.brightness_set = ns2_led_set; 223 led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; 224 led_dat->cdev.groups = ns2_led_groups; 225 led_dat->cmd = template->cmd; 226 led_dat->slow = template->slow; |
227 led_dat->can_sleep = gpio_cansleep(led_dat->cmd) | 228 gpio_cansleep(led_dat->slow); |
|
205 led_dat->modval = template->modval; 206 led_dat->num_modes = template->num_modes; 207 208 ret = ns2_led_get_mode(led_dat, &mode); 209 if (ret < 0) 210 return ret; 211 212 /* Set LED initial state. */ 213 led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; 214 led_dat->cdev.brightness = 215 (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; 216 | 229 led_dat->modval = template->modval; 230 led_dat->num_modes = template->num_modes; 231 232 ret = ns2_led_get_mode(led_dat, &mode); 233 if (ret < 0) 234 return ret; 235 236 /* Set LED initial state. */ 237 led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; 238 led_dat->cdev.brightness = 239 (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; 240 |
241 INIT_WORK(&led_dat->work, ns2_led_work); 242 |
|
217 ret = led_classdev_register(&pdev->dev, &led_dat->cdev); 218 if (ret < 0) 219 return ret; 220 221 return 0; 222} 223 224static void delete_ns2_led(struct ns2_led_data *led_dat) 225{ 226 led_classdev_unregister(&led_dat->cdev); | 243 ret = led_classdev_register(&pdev->dev, &led_dat->cdev); 244 if (ret < 0) 245 return ret; 246 247 return 0; 248} 249 250static void delete_ns2_led(struct ns2_led_data *led_dat) 251{ 252 led_classdev_unregister(&led_dat->cdev); |
253 cancel_work_sync(&led_dat->work); |
|
227} 228 229#ifdef CONFIG_OF_GPIO 230/* 231 * Translate OpenFirmware node properties into platform_data. 232 */ 233static int 234ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) --- 164 unchanged lines hidden --- | 254} 255 256#ifdef CONFIG_OF_GPIO 257/* 258 * Translate OpenFirmware node properties into platform_data. 259 */ 260static int 261ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) --- 164 unchanged lines hidden --- |