Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

leds: leds-ns2: move LED modes mapping outside of the driver

On the board n090401 (Seagate NAS 4-Bay), the LED mode mapping (GPIO
values to LED mode) is different from the one used on other boards
supported by the leds-ns2 driver.

With this patch the hardcoded mapping is removed from leds-ns2. Now,
it must be defined either in the platform data (if an old-fashion board
setup file is used) or in the DT node. In order to allow the later, this
patch also introduces a modes-map property for the leds-ns2 DT binding.

Signed-off-by: Vincent Donnefort <vdonnefort@gmail.com>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>

authored by

Vincent Donnefort and committed by
Jacek Anaszewski
f7fafd08 de88e71a

+85 -48
+9
Documentation/devicetree/bindings/leds/leds-ns2.txt
··· 8 8 Required sub-node properties: 9 9 - cmd-gpio: Command LED GPIO. See OF device-tree GPIO specification. 10 10 - slow-gpio: Slow LED GPIO. See OF device-tree GPIO specification. 11 + - modes-map: A mapping between LED modes (off, on or SATA activity blinking) and 12 + the corresponding cmd-gpio/slow-gpio values. All the GPIO values combinations 13 + should be given in order to avoid having an unknown mode at driver probe time. 11 14 12 15 Optional sub-node properties: 13 16 - label: Name for this LED. If omitted, the label is taken from the node name. 14 17 - linux,default-trigger: Trigger assigned to the LED. 15 18 16 19 Example: 20 + 21 + #include <dt-bindings/leds/leds-ns2.h> 17 22 18 23 ns2-leds { 19 24 compatible = "lacie,ns2-leds"; ··· 27 22 label = "ns2:blue:sata"; 28 23 slow-gpio = <&gpio0 29 0>; 29 24 cmd-gpio = <&gpio0 30 0>; 25 + modes-map = <NS_V2_LED_OFF 0 1 26 + NS_V2_LED_ON 1 0 27 + NS_V2_LED_ON 0 0 28 + NS_V2_LED_SATA 1 1>; 30 29 }; 31 30 };
+54 -48
drivers/leds/leds-ns2.c
··· 33 33 #include <linux/of_gpio.h> 34 34 35 35 /* 36 - * The Network Space v2 dual-GPIO LED is wired to a CPLD and can blink in 37 - * relation with the SATA activity. This capability is exposed through the 38 - * "sata" sysfs attribute. 39 - * 40 - * The following array detail the different LED registers and the combination 41 - * of their possible values: 42 - * 43 - * cmd_led | slow_led | /SATA active | LED state 44 - * | | | 45 - * 1 | 0 | x | off 46 - * - | 1 | x | on 47 - * 0 | 0 | 1 | on 48 - * 0 | 0 | 0 | blink (rate 300ms) 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. 49 40 */ 50 - 51 - enum ns2_led_modes { 52 - NS_V2_LED_OFF, 53 - NS_V2_LED_ON, 54 - NS_V2_LED_SATA, 55 - }; 56 - 57 - struct ns2_led_mode_value { 58 - enum ns2_led_modes mode; 59 - int cmd_level; 60 - int slow_level; 61 - }; 62 - 63 - static struct ns2_led_mode_value ns2_led_modval[] = { 64 - { NS_V2_LED_OFF , 1, 0 }, 65 - { NS_V2_LED_ON , 0, 1 }, 66 - { NS_V2_LED_ON , 1, 1 }, 67 - { NS_V2_LED_SATA, 0, 0 }, 68 - }; 69 41 70 42 struct ns2_led_data { 71 43 struct led_classdev cdev; ··· 45 73 unsigned slow; 46 74 unsigned char sata; /* True when SATA mode active. */ 47 75 rwlock_t rw_lock; /* Lock GPIOs. */ 76 + int num_modes; 77 + struct ns2_led_modval *modval; 48 78 }; 49 79 50 80 static int ns2_led_get_mode(struct ns2_led_data *led_dat, ··· 62 88 cmd_level = gpio_get_value(led_dat->cmd); 63 89 slow_level = gpio_get_value(led_dat->slow); 64 90 65 - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { 66 - if (cmd_level == ns2_led_modval[i].cmd_level && 67 - slow_level == ns2_led_modval[i].slow_level) { 68 - *mode = ns2_led_modval[i].mode; 91 + for (i = 0; i < led_dat->num_modes; i++) { 92 + if (cmd_level == led_dat->modval[i].cmd_level && 93 + slow_level == led_dat->modval[i].slow_level) { 94 + *mode = led_dat->modval[i].mode; 69 95 ret = 0; 70 96 break; 71 97 } ··· 84 110 85 111 write_lock_irqsave(&led_dat->rw_lock, flags); 86 112 87 - for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { 88 - if (mode == ns2_led_modval[i].mode) { 113 + for (i = 0; i < led_dat->num_modes; i++) { 114 + if (mode == led_dat->modval[i].mode) { 89 115 gpio_set_value(led_dat->cmd, 90 - ns2_led_modval[i].cmd_level); 116 + led_dat->modval[i].cmd_level); 91 117 gpio_set_value(led_dat->slow, 92 - ns2_led_modval[i].slow_level); 118 + led_dat->modval[i].slow_level); 93 119 } 94 120 } 95 121 ··· 202 228 led_dat->cdev.groups = ns2_led_groups; 203 229 led_dat->cmd = template->cmd; 204 230 led_dat->slow = template->slow; 231 + led_dat->modval = template->modval; 232 + led_dat->num_modes = template->num_modes; 205 233 206 234 ret = ns2_led_get_mode(led_dat, &mode); 207 235 if (ret < 0) ··· 235 259 { 236 260 struct device_node *np = dev->of_node; 237 261 struct device_node *child; 238 - struct ns2_led *leds; 262 + struct ns2_led *led, *leds; 239 263 int num_leds = 0; 240 - int i = 0; 241 264 242 265 num_leds = of_get_child_count(np); 243 266 if (!num_leds) ··· 247 272 if (!leds) 248 273 return -ENOMEM; 249 274 275 + led = leds; 250 276 for_each_child_of_node(np, child) { 251 277 const char *string; 252 - int ret; 278 + int ret, i, num_modes; 279 + struct ns2_led_modval *modval; 253 280 254 281 ret = of_get_named_gpio(child, "cmd-gpio", 0); 255 282 if (ret < 0) 256 283 return ret; 257 - leds[i].cmd = ret; 284 + led->cmd = ret; 258 285 ret = of_get_named_gpio(child, "slow-gpio", 0); 259 286 if (ret < 0) 260 287 return ret; 261 - leds[i].slow = ret; 288 + led->slow = ret; 262 289 ret = of_property_read_string(child, "label", &string); 263 - leds[i].name = (ret == 0) ? string : child->name; 290 + led->name = (ret == 0) ? string : child->name; 264 291 ret = of_property_read_string(child, "linux,default-trigger", 265 292 &string); 266 293 if (ret == 0) 267 - leds[i].default_trigger = string; 294 + led->default_trigger = string; 268 295 269 - i++; 296 + ret = of_property_count_u32_elems(child, "modes-map"); 297 + if (ret < 0 || ret % 3) { 298 + dev_err(dev, 299 + "Missing or malformed modes-map property\n"); 300 + return -EINVAL; 301 + } 302 + 303 + num_modes = ret / 3; 304 + modval = devm_kzalloc(dev, 305 + num_modes * sizeof(struct ns2_led_modval), 306 + GFP_KERNEL); 307 + if (!modval) 308 + return -ENOMEM; 309 + 310 + for (i = 0; i < num_modes; i++) { 311 + of_property_read_u32_index(child, 312 + "modes-map", 3 * i, 313 + (u32 *) &modval[i].mode); 314 + of_property_read_u32_index(child, 315 + "modes-map", 3 * i + 1, 316 + (u32 *) &modval[i].cmd_level); 317 + of_property_read_u32_index(child, 318 + "modes-map", 3 * i + 2, 319 + (u32 *) &modval[i].slow_level); 320 + } 321 + 322 + led->num_modes = num_modes; 323 + led->modval = modval; 324 + 325 + led++; 270 326 } 271 327 272 328 pdata->leds = leds;
+8
include/dt-bindings/leds/leds-ns2.h
··· 1 + #ifndef _DT_BINDINGS_LEDS_NS2_H 2 + #define _DT_BINDINGS_LEDS_NS2_H 3 + 4 + #define NS_V2_LED_OFF 0 5 + #define NS_V2_LED_ON 1 6 + #define NS_V2_LED_SATA 2 7 + 8 + #endif
+14
include/linux/platform_data/leds-kirkwood-ns2.h
··· 9 9 #ifndef __LEDS_KIRKWOOD_NS2_H 10 10 #define __LEDS_KIRKWOOD_NS2_H 11 11 12 + enum ns2_led_modes { 13 + NS_V2_LED_OFF, 14 + NS_V2_LED_ON, 15 + NS_V2_LED_SATA, 16 + }; 17 + 18 + struct ns2_led_modval { 19 + enum ns2_led_modes mode; 20 + int cmd_level; 21 + int slow_level; 22 + }; 23 + 12 24 struct ns2_led { 13 25 const char *name; 14 26 const char *default_trigger; 15 27 unsigned cmd; 16 28 unsigned slow; 29 + int num_modes; 30 + struct ns2_led_modval *modval; 17 31 }; 18 32 19 33 struct ns2_led_platform_data {