aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-05-22 06:54:55 -0400
committerRichard Purdie <rpurdie@linux.intel.com>2010-05-26 08:07:55 -0400
commit2146325df2c2640059a9e064890c30c6e259b458 (patch)
tree022468b1246d7d795ee351b80404efd4b25b5610
parent14e40f644b020d473415342461b7c62e3bb5e312 (diff)
leds: leds-gpio: Change blink_set callback to be able to turn off blinking
The leds-gpio blink_set() callback follows the same prototype as the main leds subsystem blink_set() one. The problem is that to stop blink, normally, a leds driver does it in the brightness_set() callback when asked to set a new fixed value. However, with leds-gpio, the platform has no hook to do so, as this later callback results in a standard GPIO manipulation. This changes the leds-gpio specific callback to take a new argument that indicates whether the LED should be blinking or not and in what state it should be set if not. We also update the dns323 platform which seems to be the only user of this so far. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c22
-rw-r--r--drivers/leds/leds-gpio.c31
-rw-r--r--include/linux/leds.h12
3 files changed, 44 insertions, 21 deletions
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 685f34a9634b..fe0de1698edc 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -240,22 +240,23 @@ error_fail:
240 240
241#define ORION_BLINK_HALF_PERIOD 100 /* ms */ 241#define ORION_BLINK_HALF_PERIOD 100 /* ms */
242 242
243static int dns323_gpio_blink_set(unsigned gpio, 243static int dns323_gpio_blink_set(unsigned gpio, int state,
244 unsigned long *delay_on, unsigned long *delay_off) 244 unsigned long *delay_on, unsigned long *delay_off)
245{ 245{
246 static int value = 0;
247 246
248 if (!*delay_on && !*delay_off) 247 if (delay_on && delay_off && !*delay_on && !*delay_off)
249 *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD; 248 *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
250 249
251 if (ORION_BLINK_HALF_PERIOD == *delay_on 250 switch(state) {
252 && ORION_BLINK_HALF_PERIOD == *delay_off) { 251 case GPIO_LED_NO_BLINK_LOW:
253 value = !value; 252 case GPIO_LED_NO_BLINK_HIGH:
254 orion_gpio_set_blink(gpio, value); 253 orion_gpio_set_blink(gpio, 0);
255 return 0; 254 gpio_set_value(gpio, state);
255 break;
256 case GPIO_LED_BLINK:
257 orion_gpio_set_blink(gpio, 1);
256 } 258 }
257 259 return 0;
258 return -EINVAL;
259} 260}
260 261
261static struct gpio_led dns323_leds[] = { 262static struct gpio_led dns323_leds[] = {
@@ -263,6 +264,7 @@ static struct gpio_led dns323_leds[] = {
263 .name = "power:blue", 264 .name = "power:blue",
264 .gpio = DNS323_GPIO_LED_POWER2, 265 .gpio = DNS323_GPIO_LED_POWER2,
265 .default_trigger = "timer", 266 .default_trigger = "timer",
267 .active_low = 1,
266 }, { 268 }, {
267 .name = "right:amber", 269 .name = "right:amber",
268 .gpio = DNS323_GPIO_LED_RIGHT_AMBER, 270 .gpio = DNS323_GPIO_LED_RIGHT_AMBER,
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 6d94b0b9979c..26843dd6b859 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -26,7 +26,8 @@ struct gpio_led_data {
26 u8 new_level; 26 u8 new_level;
27 u8 can_sleep; 27 u8 can_sleep;
28 u8 active_low; 28 u8 active_low;
29 int (*platform_gpio_blink_set)(unsigned gpio, 29 u8 blinking;
30 int (*platform_gpio_blink_set)(unsigned gpio, int state,
30 unsigned long *delay_on, unsigned long *delay_off); 31 unsigned long *delay_on, unsigned long *delay_off);
31}; 32};
32 33
@@ -35,7 +36,13 @@ static void gpio_led_work(struct work_struct *work)
35 struct gpio_led_data *led_dat = 36 struct gpio_led_data *led_dat =
36 container_of(work, struct gpio_led_data, work); 37 container_of(work, struct gpio_led_data, work);
37 38
38 gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level); 39 if (led_dat->blinking) {
40 led_dat->platform_gpio_blink_set(led_dat->gpio,
41 led_dat->new_level,
42 NULL, NULL);
43 led_dat->blinking = 0;
44 } else
45 gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
39} 46}
40 47
41static void gpio_led_set(struct led_classdev *led_cdev, 48static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,8 +67,14 @@ static void gpio_led_set(struct led_classdev *led_cdev,
60 if (led_dat->can_sleep) { 67 if (led_dat->can_sleep) {
61 led_dat->new_level = level; 68 led_dat->new_level = level;
62 schedule_work(&led_dat->work); 69 schedule_work(&led_dat->work);
63 } else 70 } else {
64 gpio_set_value(led_dat->gpio, level); 71 if (led_dat->blinking) {
72 led_dat->platform_gpio_blink_set(led_dat->gpio, level,
73 NULL, NULL);
74 led_dat->blinking = 0;
75 } else
76 gpio_set_value(led_dat->gpio, level);
77 }
65} 78}
66 79
67static int gpio_blink_set(struct led_classdev *led_cdev, 80static int gpio_blink_set(struct led_classdev *led_cdev,
@@ -70,12 +83,14 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
70 struct gpio_led_data *led_dat = 83 struct gpio_led_data *led_dat =
71 container_of(led_cdev, struct gpio_led_data, cdev); 84 container_of(led_cdev, struct gpio_led_data, cdev);
72 85
73 return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off); 86 led_dat->blinking = 1;
87 return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
88 delay_on, delay_off);
74} 89}
75 90
76static int __devinit create_gpio_led(const struct gpio_led *template, 91static int __devinit create_gpio_led(const struct gpio_led *template,
77 struct gpio_led_data *led_dat, struct device *parent, 92 struct gpio_led_data *led_dat, struct device *parent,
78 int (*blink_set)(unsigned, unsigned long *, unsigned long *)) 93 int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
79{ 94{
80 int ret, state; 95 int ret, state;
81 96
@@ -97,6 +112,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
97 led_dat->gpio = template->gpio; 112 led_dat->gpio = template->gpio;
98 led_dat->can_sleep = gpio_cansleep(template->gpio); 113 led_dat->can_sleep = gpio_cansleep(template->gpio);
99 led_dat->active_low = template->active_low; 114 led_dat->active_low = template->active_low;
115 led_dat->blinking = 0;
100 if (blink_set) { 116 if (blink_set) {
101 led_dat->platform_gpio_blink_set = blink_set; 117 led_dat->platform_gpio_blink_set = blink_set;
102 led_dat->cdev.blink_set = gpio_blink_set; 118 led_dat->cdev.blink_set = gpio_blink_set;
@@ -113,7 +129,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
113 ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); 129 ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
114 if (ret < 0) 130 if (ret < 0)
115 goto err; 131 goto err;
116 132
117 INIT_WORK(&led_dat->work, gpio_led_work); 133 INIT_WORK(&led_dat->work, gpio_led_work);
118 134
119 ret = led_classdev_register(parent, &led_dat->cdev); 135 ret = led_classdev_register(parent, &led_dat->cdev);
@@ -234,6 +250,7 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
234 led.gpio = of_get_gpio_flags(child, 0, &flags); 250 led.gpio = of_get_gpio_flags(child, 0, &flags);
235 led.active_low = flags & OF_GPIO_ACTIVE_LOW; 251 led.active_low = flags & OF_GPIO_ACTIVE_LOW;
236 led.name = of_get_property(child, "label", NULL) ? : child->name; 252 led.name = of_get_property(child, "label", NULL) ? : child->name;
253 led.blinking = 0;
237 led.default_trigger = 254 led.default_trigger =
238 of_get_property(child, "linux,default-trigger", NULL); 255 of_get_property(child, "linux,default-trigger", NULL);
239 state = of_get_property(child, "default-state", NULL); 256 state = of_get_property(child, "default-state", NULL);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index d8bf9665e70c..ba6986a11663 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -149,14 +149,18 @@ struct gpio_led {
149 unsigned default_state : 2; 149 unsigned default_state : 2;
150 /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ 150 /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
151}; 151};
152#define LEDS_GPIO_DEFSTATE_OFF 0 152#define LEDS_GPIO_DEFSTATE_OFF 0
153#define LEDS_GPIO_DEFSTATE_ON 1 153#define LEDS_GPIO_DEFSTATE_ON 1
154#define LEDS_GPIO_DEFSTATE_KEEP 2 154#define LEDS_GPIO_DEFSTATE_KEEP 2
155 155
156struct gpio_led_platform_data { 156struct gpio_led_platform_data {
157 int num_leds; 157 int num_leds;
158 struct gpio_led *leds; 158 struct gpio_led *leds;
159 int (*gpio_blink_set)(unsigned gpio, 159
160#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
161#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
162#define GPIO_LED_BLINK 2 /* Plase, blink */
163 int (*gpio_blink_set)(unsigned gpio, int state,
160 unsigned long *delay_on, 164 unsigned long *delay_on,
161 unsigned long *delay_off); 165 unsigned long *delay_off);
162}; 166};