From 42d5b0d1ef1f15622316f59146a3054939493503 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 10 May 2007 10:51:41 +0100 Subject: [PATCH] --- yaml --- r: 62617 b: refs/heads/master c: 00852279af5ad26956bc7f4d0e86fdb40192e542 h: refs/heads/master i: 62615: b483db0df4c25d42a10270fa3727b8648726fa77 v: v3 --- [refs] | 2 +- trunk/drivers/leds/leds-gpio.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 435f309bba7b..e9fb13b73d26 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 22e03f3b58dfcca30f0c8de185022132459638d1 +refs/heads/master: 00852279af5ad26956bc7f4d0e86fdb40192e542 diff --git a/trunk/drivers/leds/leds-gpio.c b/trunk/drivers/leds/leds-gpio.c index 431dcb61902c..47d90db280ce 100644 --- a/trunk/drivers/leds/leds-gpio.c +++ b/trunk/drivers/leds/leds-gpio.c @@ -13,14 +13,26 @@ #include #include #include +#include + #include struct gpio_led_data { struct led_classdev cdev; unsigned gpio; + struct work_struct work; + u8 new_level; + u8 can_sleep; u8 active_low; }; +static void gpio_led_work(struct work_struct *work) +{ + struct gpio_led_data *led_dat = + container_of(work, struct gpio_led_data, work); + + gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); +} static void gpio_led_set(struct led_classdev *led_cdev, enum led_brightness value) @@ -37,7 +49,15 @@ static void gpio_led_set(struct led_classdev *led_cdev, if (led_dat->active_low) level = !level; - gpio_set_value(led_dat->gpio, level); + /* setting GPIOs with I2C/etc requires a preemptible task context */ + if (led_dat->can_sleep) { + if (preempt_count()) { + led_dat->new_level = level; + schedule_work(&led_dat->work); + } else + gpio_set_value_cansleep(led_dat->gpio, level); + } else + gpio_set_value(led_dat->gpio, level); } static int __init gpio_led_probe(struct platform_device *pdev) @@ -62,6 +82,7 @@ static int __init gpio_led_probe(struct platform_device *pdev) led_dat->cdev.name = cur_led->name; led_dat->cdev.default_trigger = cur_led->default_trigger; led_dat->gpio = cur_led->gpio; + led_dat->can_sleep = gpio_cansleep(cur_led->gpio); led_dat->active_low = cur_led->active_low; led_dat->cdev.brightness_set = gpio_led_set; led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF; @@ -77,6 +98,8 @@ static int __init gpio_led_probe(struct platform_device *pdev) gpio_free(led_dat->gpio); goto err; } + + INIT_WORK(&led_dat->work, gpio_led_work); } platform_set_drvdata(pdev, leds_data); @@ -90,6 +113,8 @@ static int __init gpio_led_probe(struct platform_device *pdev) gpio_free(leds_data[i].gpio); } } + + flush_scheduled_work(); kfree(leds_data); return ret;