aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-22 14:22:01 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-22 14:22:01 -0400
commitd7f5e3df3574c6e38b99f5fe22f15540b2b9811d (patch)
tree75fc060628490d4bc78dd3b92635b8437b6e4290
parent2fe83b3ad12d43799af5f3156886eca443a88bac (diff)
parentf8a7c6fe14f556ca8eeddce258cb21392d0c3a2f (diff)
Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds: leds: Convert from struct class_device to struct device leds: leds-gpio for ngw100 leds: Add warning printks in error paths leds: Fix trigger unregister_simple if register_simple fails leds: Use menuconfig objects II - LED leds: Teach leds-gpio to handle timer-unsafe GPIOs leds: Add generic GPIO LED driver
-rw-r--r--arch/avr32/boards/atngw100/setup.c31
-rw-r--r--arch/avr32/configs/atngw100_defconfig16
-rw-r--r--drivers/leds/Kconfig22
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c49
-rw-r--r--drivers/leds/led-triggers.c27
-rw-r--r--drivers/leds/leds-gpio.c199
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/leds/leds.h8
-rw-r--r--drivers/leds/ledtrig-timer.c49
-rw-r--r--include/linux/leds.h17
11 files changed, 343 insertions, 78 deletions
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 6c4dc0a00e9f..2edcecdea8bd 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -13,6 +13,7 @@
13#include <linux/linkage.h> 13#include <linux/linkage.h>
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/leds.h>
16#include <linux/spi/spi.h> 17#include <linux/spi/spi.h>
17 18
18#include <asm/io.h> 19#include <asm/io.h>
@@ -21,6 +22,7 @@
21#include <asm/arch/at32ap7000.h> 22#include <asm/arch/at32ap7000.h>
22#include <asm/arch/board.h> 23#include <asm/arch/board.h>
23#include <asm/arch/init.h> 24#include <asm/arch/init.h>
25#include <asm/arch/portmux.h>
24 26
25/* Initialized by bootloader-specific startup code. */ 27/* Initialized by bootloader-specific startup code. */
26struct tag *bootloader_tags __initdata; 28struct tag *bootloader_tags __initdata;
@@ -100,8 +102,31 @@ void __init setup_board(void)
100 at32_setup_serial_console(0); 102 at32_setup_serial_console(0);
101} 103}
102 104
105static const struct gpio_led ngw_leds[] = {
106 { .name = "sys", .gpio = GPIO_PIN_PA(16), .active_low = 1,
107 .default_trigger = "heartbeat",
108 },
109 { .name = "a", .gpio = GPIO_PIN_PA(19), .active_low = 1, },
110 { .name = "b", .gpio = GPIO_PIN_PE(19), .active_low = 1, },
111};
112
113static const struct gpio_led_platform_data ngw_led_data = {
114 .num_leds = ARRAY_SIZE(ngw_leds),
115 .leds = (void *) ngw_leds,
116};
117
118static struct platform_device ngw_gpio_leds = {
119 .name = "leds-gpio",
120 .id = -1,
121 .dev = {
122 .platform_data = (void *) &ngw_led_data,
123 }
124};
125
103static int __init atngw100_init(void) 126static int __init atngw100_init(void)
104{ 127{
128 unsigned i;
129
105 /* 130 /*
106 * ATNGW100 uses 16-bit SDRAM interface, so we don't need to 131 * ATNGW100 uses 16-bit SDRAM interface, so we don't need to
107 * reserve any pins for it. 132 * reserve any pins for it.
@@ -116,6 +141,12 @@ static int __init atngw100_init(void)
116 141
117 at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); 142 at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
118 143
144 for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
145 at32_select_gpio(ngw_leds[i].gpio,
146 AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
147 }
148 platform_device_register(&ngw_gpio_leds);
149
119 return 0; 150 return 0;
120} 151}
121postcore_initcall(atngw100_init); 152postcore_initcall(atngw100_init);
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
index 49493ad3b5a9..b799a68ffd97 100644
--- a/arch/avr32/configs/atngw100_defconfig
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -712,7 +712,21 @@ CONFIG_SPI_ATMEL=y
712# 712#
713# LED devices 713# LED devices
714# 714#
715# CONFIG_NEW_LEDS is not set 715CONFIG_NEW_LEDS=y
716CONFIG_LEDS_CLASS=y
717
718#
719# LED drivers
720#
721CONFIG_LEDS_GPIO=y
722
723#
724# LED Triggers
725#
726CONFIG_LEDS_TRIGGERS=y
727CONFIG_LEDS_TRIGGER_TIMER=y
728CONFIG_LEDS_TRIGGER_HEARTBEAT=y
729
716 730
717# 731#
718# LED drivers 732# LED drivers
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 87d2046f866c..4468cb3a8d24 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,9 +1,6 @@
1 1menuconfig NEW_LEDS
2menu "LED devices"
3 depends on HAS_IOMEM
4
5config NEW_LEDS
6 bool "LED Support" 2 bool "LED Support"
3 depends on HAS_IOMEM
7 help 4 help
8 Say Y to enable Linux LED support. This allows control of supported 5 Say Y to enable Linux LED support. This allows control of supported
9 LEDs from both userspace and optionally, by kernel events (triggers). 6 LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@ config NEW_LEDS
11 This is not related to standard keyboard LEDs which are controlled 8 This is not related to standard keyboard LEDs which are controlled
12 via the input system. 9 via the input system.
13 10
11if NEW_LEDS
12
14config LEDS_CLASS 13config LEDS_CLASS
15 tristate "LED Class Support" 14 tristate "LED Class Support"
16 depends on NEW_LEDS
17 help 15 help
18 This option enables the led sysfs class in /sys/class/leds. You'll 16 This option enables the led sysfs class in /sys/class/leds. You'll
19 need this to do anything useful with LEDs. If unsure, say N. 17 need this to do anything useful with LEDs. If unsure, say N.
@@ -95,11 +93,18 @@ config LEDS_COBALT
95 help 93 help
96 This option enables support for the front LED on Cobalt Server 94 This option enables support for the front LED on Cobalt Server
97 95
96config LEDS_GPIO
97 tristate "LED Support for GPIO connected LEDs"
98 depends on LEDS_CLASS && GENERIC_GPIO
99 help
100 This option enables support for the LEDs connected to GPIO
101 outputs. To be useful the particular board must have LEDs
102 and they must be connected to the GPIO lines.
103
98comment "LED Triggers" 104comment "LED Triggers"
99 105
100config LEDS_TRIGGERS 106config LEDS_TRIGGERS
101 bool "LED Trigger support" 107 bool "LED Trigger support"
102 depends on NEW_LEDS
103 help 108 help
104 This option enables trigger support for the leds class. 109 This option enables trigger support for the leds class.
105 These triggers allow kernel events to drive the LEDs and can 110 These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +133,4 @@ config LEDS_TRIGGER_HEARTBEAT
128 load average. 133 load average.
129 If unsure, say Y. 134 If unsure, say Y.
130 135
131endmenu 136endif # NEW_LEDS
132
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa2c18efa5b2..f8995c9bc2ea 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
16obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o 16obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
17obj-$(CONFIG_LEDS_H1940) += leds-h1940.o 17obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
18obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o 18obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
19obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
19 20
20# LED Triggers 21# LED Triggers
21obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 22obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c1711210e38..4211293ce862 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -2,7 +2,7 @@
2 * LED Class Core 2 * LED Class Core
3 * 3 *
4 * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu> 4 * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
5 * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com> 5 * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -24,9 +24,10 @@
24 24
25static struct class *leds_class; 25static struct class *leds_class;
26 26
27static ssize_t led_brightness_show(struct class_device *dev, char *buf) 27static ssize_t led_brightness_show(struct device *dev,
28 struct device_attribute *attr, char *buf)
28{ 29{
29 struct led_classdev *led_cdev = class_get_devdata(dev); 30 struct led_classdev *led_cdev = dev_get_drvdata(dev);
30 ssize_t ret = 0; 31 ssize_t ret = 0;
31 32
32 /* no lock needed for this */ 33 /* no lock needed for this */
@@ -36,10 +37,10 @@ static ssize_t led_brightness_show(struct class_device *dev, char *buf)
36 return ret; 37 return ret;
37} 38}
38 39
39static ssize_t led_brightness_store(struct class_device *dev, 40static ssize_t led_brightness_store(struct device *dev,
40 const char *buf, size_t size) 41 struct device_attribute *attr, const char *buf, size_t size)
41{ 42{
42 struct led_classdev *led_cdev = class_get_devdata(dev); 43 struct led_classdev *led_cdev = dev_get_drvdata(dev);
43 ssize_t ret = -EINVAL; 44 ssize_t ret = -EINVAL;
44 char *after; 45 char *after;
45 unsigned long state = simple_strtoul(buf, &after, 10); 46 unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@ static ssize_t led_brightness_store(struct class_device *dev,
56 return ret; 57 return ret;
57} 58}
58 59
59static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, 60static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
60 led_brightness_store);
61#ifdef CONFIG_LEDS_TRIGGERS 61#ifdef CONFIG_LEDS_TRIGGERS
62static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); 62static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
63#endif 63#endif
64 64
65/** 65/**
@@ -93,16 +93,15 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
93{ 93{
94 int rc; 94 int rc;
95 95
96 led_cdev->class_dev = class_device_create(leds_class, NULL, 0, 96 led_cdev->dev = device_create(leds_class, parent, 0, "%s",
97 parent, "%s", led_cdev->name); 97 led_cdev->name);
98 if (unlikely(IS_ERR(led_cdev->class_dev))) 98 if (unlikely(IS_ERR(led_cdev->dev)))
99 return PTR_ERR(led_cdev->class_dev); 99 return PTR_ERR(led_cdev->dev);
100 100
101 class_set_devdata(led_cdev->class_dev, led_cdev); 101 dev_set_drvdata(led_cdev->dev, led_cdev);
102 102
103 /* register the attributes */ 103 /* register the attributes */
104 rc = class_device_create_file(led_cdev->class_dev, 104 rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
105 &class_device_attr_brightness);
106 if (rc) 105 if (rc)
107 goto err_out; 106 goto err_out;
108 107
@@ -114,8 +113,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
114#ifdef CONFIG_LEDS_TRIGGERS 113#ifdef CONFIG_LEDS_TRIGGERS
115 rwlock_init(&led_cdev->trigger_lock); 114 rwlock_init(&led_cdev->trigger_lock);
116 115
117 rc = class_device_create_file(led_cdev->class_dev, 116 rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
118 &class_device_attr_trigger);
119 if (rc) 117 if (rc)
120 goto err_out_led_list; 118 goto err_out_led_list;
121 119
@@ -123,18 +121,17 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
123#endif 121#endif
124 122
125 printk(KERN_INFO "Registered led device: %s\n", 123 printk(KERN_INFO "Registered led device: %s\n",
126 led_cdev->class_dev->class_id); 124 led_cdev->name);
127 125
128 return 0; 126 return 0;
129 127
130#ifdef CONFIG_LEDS_TRIGGERS 128#ifdef CONFIG_LEDS_TRIGGERS
131err_out_led_list: 129err_out_led_list:
132 class_device_remove_file(led_cdev->class_dev, 130 device_remove_file(led_cdev->dev, &dev_attr_brightness);
133 &class_device_attr_brightness);
134 list_del(&led_cdev->node); 131 list_del(&led_cdev->node);
135#endif 132#endif
136err_out: 133err_out:
137 class_device_unregister(led_cdev->class_dev); 134 device_unregister(led_cdev->dev);
138 return rc; 135 return rc;
139} 136}
140EXPORT_SYMBOL_GPL(led_classdev_register); 137EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
147 */ 144 */
148void led_classdev_unregister(struct led_classdev *led_cdev) 145void led_classdev_unregister(struct led_classdev *led_cdev)
149{ 146{
150 class_device_remove_file(led_cdev->class_dev, 147 device_remove_file(led_cdev->dev, &dev_attr_brightness);
151 &class_device_attr_brightness);
152#ifdef CONFIG_LEDS_TRIGGERS 148#ifdef CONFIG_LEDS_TRIGGERS
153 class_device_remove_file(led_cdev->class_dev, 149 device_remove_file(led_cdev->dev, &dev_attr_trigger);
154 &class_device_attr_trigger);
155 write_lock(&led_cdev->trigger_lock); 150 write_lock(&led_cdev->trigger_lock);
156 if (led_cdev->trigger) 151 if (led_cdev->trigger)
157 led_trigger_set(led_cdev, NULL); 152 led_trigger_set(led_cdev, NULL);
158 write_unlock(&led_cdev->trigger_lock); 153 write_unlock(&led_cdev->trigger_lock);
159#endif 154#endif
160 155
161 class_device_unregister(led_cdev->class_dev); 156 device_unregister(led_cdev->dev);
162 157
163 write_lock(&leds_list_lock); 158 write_lock(&leds_list_lock);
164 list_del(&led_cdev->node); 159 list_del(&led_cdev->node);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 454fb0901f82..575368c2b100 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * LED Triggers Core 2 * LED Triggers Core
3 * 3 *
4 * Copyright 2005-2006 Openedhand Ltd. 4 * Copyright 2005-2007 Openedhand Ltd.
5 * 5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com> 6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 * 7 *
@@ -28,10 +28,10 @@
28static DEFINE_RWLOCK(triggers_list_lock); 28static DEFINE_RWLOCK(triggers_list_lock);
29static LIST_HEAD(trigger_list); 29static LIST_HEAD(trigger_list);
30 30
31ssize_t led_trigger_store(struct class_device *dev, const char *buf, 31ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
32 size_t count) 32 const char *buf, size_t count)
33{ 33{
34 struct led_classdev *led_cdev = class_get_devdata(dev); 34 struct led_classdev *led_cdev = dev_get_drvdata(dev);
35 char trigger_name[TRIG_NAME_MAX]; 35 char trigger_name[TRIG_NAME_MAX];
36 struct led_trigger *trig; 36 struct led_trigger *trig;
37 size_t len; 37 size_t len;
@@ -67,9 +67,10 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf,
67} 67}
68 68
69 69
70ssize_t led_trigger_show(struct class_device *dev, char *buf) 70ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
71 char *buf)
71{ 72{
72 struct led_classdev *led_cdev = class_get_devdata(dev); 73 struct led_classdev *led_cdev = dev_get_drvdata(dev);
73 struct led_trigger *trig; 74 struct led_trigger *trig;
74 int len = 0; 75 int len = 0;
75 76
@@ -183,13 +184,20 @@ int led_trigger_register(struct led_trigger *trigger)
183void led_trigger_register_simple(const char *name, struct led_trigger **tp) 184void led_trigger_register_simple(const char *name, struct led_trigger **tp)
184{ 185{
185 struct led_trigger *trigger; 186 struct led_trigger *trigger;
187 int err;
186 188
187 trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); 189 trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
188 190
189 if (trigger) { 191 if (trigger) {
190 trigger->name = name; 192 trigger->name = name;
191 led_trigger_register(trigger); 193 err = led_trigger_register(trigger);
192 } 194 if (err < 0)
195 printk(KERN_WARNING "LED trigger %s failed to register"
196 " (%d)\n", name, err);
197 } else
198 printk(KERN_WARNING "LED trigger %s failed to register"
199 " (no memory)\n", name);
200
193 *tp = trigger; 201 *tp = trigger;
194} 202}
195 203
@@ -215,7 +223,8 @@ void led_trigger_unregister(struct led_trigger *trigger)
215 223
216void led_trigger_unregister_simple(struct led_trigger *trigger) 224void led_trigger_unregister_simple(struct led_trigger *trigger)
217{ 225{
218 led_trigger_unregister(trigger); 226 if (trigger)
227 led_trigger_unregister(trigger);
219 kfree(trigger); 228 kfree(trigger);
220} 229}
221 230
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 000000000000..47d90db280ce
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,199 @@
1/*
2 * LEDs driver for GPIOs
3 *
4 * Copyright (C) 2007 8D Technologies inc.
5 * Raphael Assenat <raph@8d.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/kernel.h>
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
20struct 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
29static 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
37static void gpio_led_set(struct led_classdev *led_cdev,
38 enum led_brightness value)
39{
40 struct gpio_led_data *led_dat =
41 container_of(led_cdev, struct gpio_led_data, cdev);
42 int level;
43
44 if (value == LED_OFF)
45 level = 0;
46 else
47 level = 1;
48
49 if (led_dat->active_low)
50 level = !level;
51
52 /* setting GPIOs with I2C/etc requires a preemptible task context */
53 if (led_dat->can_sleep) {
54 if (preempt_count()) {
55 led_dat->new_level = level;
56 schedule_work(&led_dat->work);
57 } else
58 gpio_set_value_cansleep(led_dat->gpio, level);
59 } else
60 gpio_set_value(led_dat->gpio, level);
61}
62
63static int __init gpio_led_probe(struct platform_device *pdev)
64{
65 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
66 struct gpio_led *cur_led;
67 struct gpio_led_data *leds_data, *led_dat;
68 int i, ret = 0;
69
70 if (!pdata)
71 return -EBUSY;
72
73 leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
74 GFP_KERNEL);
75 if (!leds_data)
76 return -ENOMEM;
77
78 for (i = 0; i < pdata->num_leds; i++) {
79 cur_led = &pdata->leds[i];
80 led_dat = &leds_data[i];
81
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->can_sleep = gpio_cansleep(cur_led->gpio);
86 led_dat->active_low = cur_led->active_low;
87 led_dat->cdev.brightness_set = gpio_led_set;
88 led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
89
90 ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
91 if (ret < 0)
92 goto err;
93
94 gpio_direction_output(led_dat->gpio, led_dat->active_low);
95
96 ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
97 if (ret < 0) {
98 gpio_free(led_dat->gpio);
99 goto err;
100 }
101
102 INIT_WORK(&led_dat->work, gpio_led_work);
103 }
104
105 platform_set_drvdata(pdev, leds_data);
106
107 return 0;
108
109err:
110 if (i > 0) {
111 for (i = i - 1; i >= 0; i--) {
112 led_classdev_unregister(&leds_data[i].cdev);
113 gpio_free(leds_data[i].gpio);
114 }
115 }
116
117 flush_scheduled_work();
118 kfree(leds_data);
119
120 return ret;
121}
122
123static int __exit gpio_led_remove(struct platform_device *pdev)
124{
125 int i;
126 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
127 struct gpio_led_data *leds_data;
128
129 leds_data = platform_get_drvdata(pdev);
130
131 for (i = 0; i < pdata->num_leds; i++) {
132 led_classdev_unregister(&leds_data[i].cdev);
133 gpio_free(leds_data[i].gpio);
134 }
135
136 kfree(leds_data);
137
138 return 0;
139}
140
141#ifdef CONFIG_PM
142static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
143{
144 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
145 struct gpio_led_data *leds_data;
146 int i;
147
148 leds_data = platform_get_drvdata(pdev);
149
150 for (i = 0; i < pdata->num_leds; i++)
151 led_classdev_suspend(&leds_data[i].cdev);
152
153 return 0;
154}
155
156static int gpio_led_resume(struct platform_device *pdev)
157{
158 struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
159 struct gpio_led_data *leds_data;
160 int i;
161
162 leds_data = platform_get_drvdata(pdev);
163
164 for (i = 0; i < pdata->num_leds; i++)
165 led_classdev_resume(&leds_data[i].cdev);
166
167 return 0;
168}
169#else
170#define gpio_led_suspend NULL
171#define gpio_led_resume NULL
172#endif
173
174static struct platform_driver gpio_led_driver = {
175 .remove = __exit_p(gpio_led_remove),
176 .suspend = gpio_led_suspend,
177 .resume = gpio_led_resume,
178 .driver = {
179 .name = "leds-gpio",
180 .owner = THIS_MODULE,
181 },
182};
183
184static int __init gpio_led_init(void)
185{
186 return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
187}
188
189static void __exit gpio_led_exit(void)
190{
191 platform_driver_unregister(&gpio_led_driver);
192}
193
194module_init(gpio_led_init);
195module_exit(gpio_led_exit);
196
197MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
198MODULE_DESCRIPTION("GPIO LED driver");
199MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 6f2d449ba983..bfac499f3258 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -19,7 +19,7 @@
19static void locomoled_brightness_set(struct led_classdev *led_cdev, 19static void locomoled_brightness_set(struct led_classdev *led_cdev,
20 enum led_brightness value, int offset) 20 enum led_brightness value, int offset)
21{ 21{
22 struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev); 22 struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
23 unsigned long flags; 23 unsigned long flags;
24 24
25 local_irq_save(flags); 25 local_irq_save(flags);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index a715c4ed93ff..f2f3884fe063 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -13,6 +13,7 @@
13#ifndef __LEDS_H_INCLUDED 13#ifndef __LEDS_H_INCLUDED
14#define __LEDS_H_INCLUDED 14#define __LEDS_H_INCLUDED
15 15
16#include <linux/device.h>
16#include <linux/leds.h> 17#include <linux/leds.h>
17 18
18static inline void led_set_brightness(struct led_classdev *led_cdev, 19static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@ void led_trigger_set(struct led_classdev *led_cdev,
37#define led_trigger_set(x, y) do {} while(0) 38#define led_trigger_set(x, y) do {} while(0)
38#endif 39#endif
39 40
40ssize_t led_trigger_store(struct class_device *dev, const char *buf, 41ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
41 size_t count); 42 const char *buf, size_t count);
42ssize_t led_trigger_show(struct class_device *dev, char *buf); 43ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
44 char *buf);
43 45
44#endif /* __LEDS_H_INCLUDED */ 46#endif /* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d756bdb01c59..ed9ff02c77ea 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -52,9 +52,10 @@ static void led_timer_function(unsigned long data)
52 mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); 52 mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
53} 53}
54 54
55static ssize_t led_delay_on_show(struct class_device *dev, char *buf) 55static ssize_t led_delay_on_show(struct device *dev,
56 struct device_attribute *attr, char *buf)
56{ 57{
57 struct led_classdev *led_cdev = class_get_devdata(dev); 58 struct led_classdev *led_cdev = dev_get_drvdata(dev);
58 struct timer_trig_data *timer_data = led_cdev->trigger_data; 59 struct timer_trig_data *timer_data = led_cdev->trigger_data;
59 60
60 sprintf(buf, "%lu\n", timer_data->delay_on); 61 sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@ static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
62 return strlen(buf) + 1; 63 return strlen(buf) + 1;
63} 64}
64 65
65static ssize_t led_delay_on_store(struct class_device *dev, const char *buf, 66static ssize_t led_delay_on_store(struct device *dev,
66 size_t size) 67 struct device_attribute *attr, const char *buf, size_t size)
67{ 68{
68 struct led_classdev *led_cdev = class_get_devdata(dev); 69 struct led_classdev *led_cdev = dev_get_drvdata(dev);
69 struct timer_trig_data *timer_data = led_cdev->trigger_data; 70 struct timer_trig_data *timer_data = led_cdev->trigger_data;
70 int ret = -EINVAL; 71 int ret = -EINVAL;
71 char *after; 72 char *after;
@@ -84,9 +85,10 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
84 return ret; 85 return ret;
85} 86}
86 87
87static ssize_t led_delay_off_show(struct class_device *dev, char *buf) 88static ssize_t led_delay_off_show(struct device *dev,
89 struct device_attribute *attr, char *buf)
88{ 90{
89 struct led_classdev *led_cdev = class_get_devdata(dev); 91 struct led_classdev *led_cdev = dev_get_drvdata(dev);
90 struct timer_trig_data *timer_data = led_cdev->trigger_data; 92 struct timer_trig_data *timer_data = led_cdev->trigger_data;
91 93
92 sprintf(buf, "%lu\n", timer_data->delay_off); 94 sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@ static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
94 return strlen(buf) + 1; 96 return strlen(buf) + 1;
95} 97}
96 98
97static ssize_t led_delay_off_store(struct class_device *dev, const char *buf, 99static ssize_t led_delay_off_store(struct device *dev,
98 size_t size) 100 struct device_attribute *attr, const char *buf, size_t size)
99{ 101{
100 struct led_classdev *led_cdev = class_get_devdata(dev); 102 struct led_classdev *led_cdev = dev_get_drvdata(dev);
101 struct timer_trig_data *timer_data = led_cdev->trigger_data; 103 struct timer_trig_data *timer_data = led_cdev->trigger_data;
102 int ret = -EINVAL; 104 int ret = -EINVAL;
103 char *after; 105 char *after;
@@ -116,10 +118,8 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
116 return ret; 118 return ret;
117} 119}
118 120
119static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show, 121static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
120 led_delay_on_store); 122static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
121static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
122 led_delay_off_store);
123 123
124static void timer_trig_activate(struct led_classdev *led_cdev) 124static void timer_trig_activate(struct led_classdev *led_cdev)
125{ 125{
@@ -136,18 +136,17 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
136 timer_data->timer.function = led_timer_function; 136 timer_data->timer.function = led_timer_function;
137 timer_data->timer.data = (unsigned long) led_cdev; 137 timer_data->timer.data = (unsigned long) led_cdev;
138 138
139 rc = class_device_create_file(led_cdev->class_dev, 139 rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
140 &class_device_attr_delay_on); 140 if (rc)
141 if (rc) goto err_out; 141 goto err_out;
142 rc = class_device_create_file(led_cdev->class_dev, 142 rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
143 &class_device_attr_delay_off); 143 if (rc)
144 if (rc) goto err_out_delayon; 144 goto err_out_delayon;
145 145
146 return; 146 return;
147 147
148err_out_delayon: 148err_out_delayon:
149 class_device_remove_file(led_cdev->class_dev, 149 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
150 &class_device_attr_delay_on);
151err_out: 150err_out:
152 led_cdev->trigger_data = NULL; 151 led_cdev->trigger_data = NULL;
153 kfree(timer_data); 152 kfree(timer_data);
@@ -158,10 +157,8 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
158 struct timer_trig_data *timer_data = led_cdev->trigger_data; 157 struct timer_trig_data *timer_data = led_cdev->trigger_data;
159 158
160 if (timer_data) { 159 if (timer_data) {
161 class_device_remove_file(led_cdev->class_dev, 160 device_remove_file(led_cdev->dev, &dev_attr_delay_on);
162 &class_device_attr_delay_on); 161 device_remove_file(led_cdev->dev, &dev_attr_delay_off);
163 class_device_remove_file(led_cdev->class_dev,
164 &class_device_attr_delay_off);
165 del_timer_sync(&timer_data->timer); 162 del_timer_sync(&timer_data->timer);
166 kfree(timer_data); 163 kfree(timer_data);
167 } 164 }
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 494bed7c2fc1..421175092ee2 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -15,7 +15,6 @@
15#include <linux/list.h> 15#include <linux/list.h>
16 16
17struct device; 17struct device;
18struct class_device;
19/* 18/*
20 * LED Core 19 * LED Core
21 */ 20 */
@@ -37,7 +36,7 @@ struct led_classdev {
37 void (*brightness_set)(struct led_classdev *led_cdev, 36 void (*brightness_set)(struct led_classdev *led_cdev,
38 enum led_brightness brightness); 37 enum led_brightness brightness);
39 38
40 struct class_device *class_dev; 39 struct device *dev;
41 struct list_head node; /* LED Device list */ 40 struct list_head node; /* LED Device list */
42 char *default_trigger; /* Trigger to use */ 41 char *default_trigger; /* Trigger to use */
43 42
@@ -109,4 +108,18 @@ extern void ledtrig_ide_activity(void);
109#define ledtrig_ide_activity() do {} while(0) 108#define ledtrig_ide_activity() do {} while(0)
110#endif 109#endif
111 110
111/* For the leds-gpio driver */
112struct gpio_led {
113 const char *name;
114 char *default_trigger;
115 unsigned gpio;
116 u8 active_low;
117};
118
119struct gpio_led_platform_data {
120 int num_leds;
121 struct gpio_led *leds;
122};
123
124
112#endif /* __LINUX_LEDS_H_INCLUDED */ 125#endif /* __LINUX_LEDS_H_INCLUDED */