leds: Teach leds-gpio to handle timer-unsafe GPIOs

Teach the new leds-gpio driver that some GPIOs can't be accessed from
timer callbacks ... which is how all today's standard triggers use them.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Richard Purdie <rpurdie@rpsys.net>

authored by David Brownell and committed by Richard Purdie 00852279 22e03f3b

+26 -1
+26 -1
drivers/leds/leds-gpio.c
··· 13 #include <linux/init.h> 14 #include <linux/platform_device.h> 15 #include <linux/leds.h> 16 #include <asm/gpio.h> 17 18 struct gpio_led_data { 19 struct led_classdev cdev; 20 unsigned gpio; 21 u8 active_low; 22 }; 23 24 25 static void gpio_led_set(struct led_classdev *led_cdev, 26 enum led_brightness value) ··· 49 if (led_dat->active_low) 50 level = !level; 51 52 - gpio_set_value(led_dat->gpio, level); 53 } 54 55 static int __init gpio_led_probe(struct platform_device *pdev) ··· 82 led_dat->cdev.name = cur_led->name; 83 led_dat->cdev.default_trigger = cur_led->default_trigger; 84 led_dat->gpio = cur_led->gpio; 85 led_dat->active_low = cur_led->active_low; 86 led_dat->cdev.brightness_set = gpio_led_set; 87 led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF; ··· 98 gpio_free(led_dat->gpio); 99 goto err; 100 } 101 } 102 103 platform_set_drvdata(pdev, leds_data); ··· 113 gpio_free(leds_data[i].gpio); 114 } 115 } 116 kfree(leds_data); 117 118 return ret;
··· 13 #include <linux/init.h> 14 #include <linux/platform_device.h> 15 #include <linux/leds.h> 16 + #include <linux/workqueue.h> 17 + 18 #include <asm/gpio.h> 19 20 struct gpio_led_data { 21 struct led_classdev cdev; 22 unsigned gpio; 23 + struct work_struct work; 24 + u8 new_level; 25 + u8 can_sleep; 26 u8 active_low; 27 }; 28 29 + static void gpio_led_work(struct work_struct *work) 30 + { 31 + struct gpio_led_data *led_dat = 32 + container_of(work, struct gpio_led_data, work); 33 + 34 + gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); 35 + } 36 37 static void gpio_led_set(struct led_classdev *led_cdev, 38 enum led_brightness value) ··· 37 if (led_dat->active_low) 38 level = !level; 39 40 + /* setting GPIOs with I2C/etc requires a preemptible task context */ 41 + if (led_dat->can_sleep) { 42 + if (preempt_count()) { 43 + led_dat->new_level = level; 44 + schedule_work(&led_dat->work); 45 + } else 46 + gpio_set_value_cansleep(led_dat->gpio, level); 47 + } else 48 + gpio_set_value(led_dat->gpio, level); 49 } 50 51 static int __init gpio_led_probe(struct platform_device *pdev) ··· 62 led_dat->cdev.name = cur_led->name; 63 led_dat->cdev.default_trigger = cur_led->default_trigger; 64 led_dat->gpio = cur_led->gpio; 65 + led_dat->can_sleep = gpio_cansleep(cur_led->gpio); 66 led_dat->active_low = cur_led->active_low; 67 led_dat->cdev.brightness_set = gpio_led_set; 68 led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF; ··· 77 gpio_free(led_dat->gpio); 78 goto err; 79 } 80 + 81 + INIT_WORK(&led_dat->work, gpio_led_work); 82 } 83 84 platform_set_drvdata(pdev, leds_data); ··· 90 gpio_free(leds_data[i].gpio); 91 } 92 } 93 + 94 + flush_scheduled_work(); 95 kfree(leds_data); 96 97 return ret;