aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-28 11:26:12 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-28 11:26:12 -0400
commit7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch)
treee730a4565e0318140d2fbd2f0415d18a339d7336 /drivers/leds
parent41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff)
parent0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff)
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig65
-rw-r--r--drivers/leds/Makefile9
-rw-r--r--drivers/leds/led-class.c16
-rw-r--r--drivers/leds/led-triggers.c3
-rw-r--r--drivers/leds/leds-ams-delta.c22
-rw-r--r--drivers/leds/leds-atmel-pwm.c2
-rw-r--r--drivers/leds/leds-cm-x270.c124
-rw-r--r--drivers/leds/leds-corgi.c125
-rw-r--r--drivers/leds/leds-da903x.c175
-rw-r--r--drivers/leds/leds-fsg.c30
-rw-r--r--drivers/leds/leds-h1940.c15
-rw-r--r--drivers/leds/leds-hp-disk.c156
-rw-r--r--drivers/leds/leds-hp6xx.c2
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/leds/leds-pca9532.c337
-rw-r--r--drivers/leds/leds-pca955x.c390
-rw-r--r--drivers/leds/leds-s3c24xx.c6
-rw-r--r--drivers/leds/leds-spitz.c131
-rw-r--r--drivers/leds/leds-sunfire.c273
-rw-r--r--drivers/leds/leds-wrap.c5
-rw-r--r--drivers/leds/ledtrig-backlight.c110
-rw-r--r--drivers/leds/ledtrig-timer.c8
22 files changed, 1548 insertions, 458 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 86a369bc57d6..e7fb7d2fcbfc 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -24,13 +24,6 @@ config LEDS_ATMEL_PWM
24 This option enables support for LEDs driven using outputs 24 This option enables support for LEDs driven using outputs
25 of the dedicated PWM controller found on newer Atmel SOCs. 25 of the dedicated PWM controller found on newer Atmel SOCs.
26 26
27config LEDS_CORGI
28 tristate "LED Support for the Sharp SL-C7x0 series"
29 depends on LEDS_CLASS && PXA_SHARP_C7xx
30 help
31 This option enables support for the LEDs on Sharp Zaurus
32 SL-C7x0 series (C700, C750, C760, C860).
33
34config LEDS_LOCOMO 27config LEDS_LOCOMO
35 tristate "LED Support for Locomo device" 28 tristate "LED Support for Locomo device"
36 depends on LEDS_CLASS && SHARP_LOCOMO 29 depends on LEDS_CLASS && SHARP_LOCOMO
@@ -38,13 +31,6 @@ config LEDS_LOCOMO
38 This option enables support for the LEDs on Sharp Locomo. 31 This option enables support for the LEDs on Sharp Locomo.
39 Zaurus models SL-5500 and SL-5600. 32 Zaurus models SL-5500 and SL-5600.
40 33
41config LEDS_SPITZ
42 tristate "LED Support for the Sharp SL-Cxx00 series"
43 depends on LEDS_CLASS && PXA_SHARP_Cxx00
44 help
45 This option enables support for the LEDs on Sharp Zaurus
46 SL-Cxx00 series (C1000, C3000, C3100).
47
48config LEDS_S3C24XX 34config LEDS_S3C24XX
49 tristate "LED Support for Samsung S3C24XX GPIO LEDs" 35 tristate "LED Support for Samsung S3C24XX GPIO LEDs"
50 depends on LEDS_CLASS && ARCH_S3C2410 36 depends on LEDS_CLASS && ARCH_S3C2410
@@ -96,6 +82,14 @@ config LEDS_COBALT_RAQ
96 help 82 help
97 This option enables support for the Cobalt Raq series LEDs. 83 This option enables support for the Cobalt Raq series LEDs.
98 84
85config LEDS_SUNFIRE
86 tristate "LED support for SunFire servers."
87 depends on LEDS_CLASS && SPARC64
88 select LEDS_TRIGGERS
89 help
90 This option enables support for the Left, Middle, and Right
91 LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
92
99config LEDS_HP6XX 93config LEDS_HP6XX
100 tristate "LED Support for the HP Jornada 6xx" 94 tristate "LED Support for the HP Jornada 6xx"
101 depends on LEDS_CLASS && SH_HP6XX 95 depends on LEDS_CLASS && SH_HP6XX
@@ -103,6 +97,14 @@ config LEDS_HP6XX
103 This option enables led support for the handheld 97 This option enables led support for the handheld
104 HP Jornada 620/660/680/690. 98 HP Jornada 620/660/680/690.
105 99
100config LEDS_PCA9532
101 tristate "LED driver for PCA9532 dimmer"
102 depends on LEDS_CLASS && I2C && INPUT && EXPERIMENTAL
103 help
104 This option enables support for NXP pca9532
105 led controller. It is generally only usefull
106 as a platform driver
107
106config LEDS_GPIO 108config LEDS_GPIO
107 tristate "LED Support for GPIO connected LEDs" 109 tristate "LED Support for GPIO connected LEDs"
108 depends on LEDS_CLASS && GENERIC_GPIO 110 depends on LEDS_CLASS && GENERIC_GPIO
@@ -111,11 +113,12 @@ config LEDS_GPIO
111 outputs. To be useful the particular board must have LEDs 113 outputs. To be useful the particular board must have LEDs
112 and they must be connected to the GPIO lines. 114 and they must be connected to the GPIO lines.
113 115
114config LEDS_CM_X270 116config LEDS_HP_DISK
115 tristate "LED Support for the CM-X270 LEDs" 117 tristate "LED Support for disk protection LED on HP notebooks"
116 depends on LEDS_CLASS && MACH_ARMCORE 118 depends on LEDS_CLASS && ACPI
117 help 119 help
118 This option enables support for the CM-X270 LEDs. 120 This option enable support for disk protection LED, found on
121 newer HP notebooks.
119 122
120config LEDS_CLEVO_MAIL 123config LEDS_CLEVO_MAIL
121 tristate "Mail LED on Clevo notebook (EXPERIMENTAL)" 124 tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
@@ -147,6 +150,21 @@ config LEDS_CLEVO_MAIL
147 To compile this driver as a module, choose M here: the 150 To compile this driver as a module, choose M here: the
148 module will be called leds-clevo-mail. 151 module will be called leds-clevo-mail.
149 152
153config LEDS_PCA955X
154 tristate "LED Support for PCA955x I2C chips"
155 depends on LEDS_CLASS && I2C
156 help
157 This option enables support for LEDs connected to PCA955x
158 LED driver chips accessed via the I2C bus. Supported
159 devices include PCA9550, PCA9551, PCA9552, and PCA9553.
160
161config LEDS_DA903X
162 tristate "LED Support for DA9030/DA9034 PMIC"
163 depends on LEDS_CLASS && PMIC_DA903X
164 help
165 This option enables support for on-chip LED drivers found
166 on Dialog Semiconductor DA9030/DA9034 PMICs.
167
150comment "LED Triggers" 168comment "LED Triggers"
151 169
152config LEDS_TRIGGERS 170config LEDS_TRIGGERS
@@ -169,7 +187,7 @@ config LEDS_TRIGGER_TIMER
169 187
170config LEDS_TRIGGER_IDE_DISK 188config LEDS_TRIGGER_IDE_DISK
171 bool "LED IDE Disk Trigger" 189 bool "LED IDE Disk Trigger"
172 depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK 190 depends on LEDS_TRIGGERS && IDE_GD_ATA
173 help 191 help
174 This allows LEDs to be controlled by IDE disk activity. 192 This allows LEDs to be controlled by IDE disk activity.
175 If unsure, say Y. 193 If unsure, say Y.
@@ -183,6 +201,15 @@ config LEDS_TRIGGER_HEARTBEAT
183 load average. 201 load average.
184 If unsure, say Y. 202 If unsure, say Y.
185 203
204config LEDS_TRIGGER_BACKLIGHT
205 tristate "LED backlight Trigger"
206 depends on LEDS_TRIGGERS
207 help
208 This allows LEDs to be controlled as a backlight device: they
209 turn off and on when the display is blanked and unblanked.
210
211 If unsure, say N.
212
186config LEDS_TRIGGER_DEFAULT_ON 213config LEDS_TRIGGER_DEFAULT_ON
187 tristate "LED Default ON Trigger" 214 tristate "LED Default ON Trigger"
188 depends on LEDS_TRIGGERS 215 depends on LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 973d626f5f4a..e1967a29850e 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -6,9 +6,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
6 6
7# LED Platform Drivers 7# LED Platform Drivers
8obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o 8obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o
9obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o
10obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o 9obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
11obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
12obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o 10obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
13obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o 11obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
14obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o 12obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
@@ -16,14 +14,19 @@ obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
16obj-$(CONFIG_LEDS_H1940) += leds-h1940.o 14obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
17obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o 15obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
18obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o 16obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
17obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
18obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
19obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o 19obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
20obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
21obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o 20obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
22obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o 21obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
23obj-$(CONFIG_LEDS_FSG) += leds-fsg.o 22obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
23obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
24obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
25obj-$(CONFIG_LEDS_HP_DISK) += leds-hp-disk.o
24 26
25# LED Triggers 27# LED Triggers
26obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o 28obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
27obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o 29obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
28obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o 30obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
31obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
29obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o 32obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 559a40861c39..6c4a326176d7 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -34,14 +34,11 @@ static ssize_t led_brightness_show(struct device *dev,
34 struct device_attribute *attr, char *buf) 34 struct device_attribute *attr, char *buf)
35{ 35{
36 struct led_classdev *led_cdev = dev_get_drvdata(dev); 36 struct led_classdev *led_cdev = dev_get_drvdata(dev);
37 ssize_t ret = 0;
38 37
39 /* no lock needed for this */ 38 /* no lock needed for this */
40 led_update_brightness(led_cdev); 39 led_update_brightness(led_cdev);
41 sprintf(buf, "%u\n", led_cdev->brightness);
42 ret = strlen(buf) + 1;
43 40
44 return ret; 41 return sprintf(buf, "%u\n", led_cdev->brightness);
45} 42}
46 43
47static ssize_t led_brightness_store(struct device *dev, 44static ssize_t led_brightness_store(struct device *dev,
@@ -103,8 +100,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
103{ 100{
104 int rc; 101 int rc;
105 102
106 led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev, 103 led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
107 "%s", led_cdev->name); 104 "%s", led_cdev->name);
108 if (IS_ERR(led_cdev->dev)) 105 if (IS_ERR(led_cdev->dev))
109 return PTR_ERR(led_cdev->dev); 106 return PTR_ERR(led_cdev->dev);
110 107
@@ -113,6 +110,9 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
113 if (rc) 110 if (rc)
114 goto err_out; 111 goto err_out;
115 112
113#ifdef CONFIG_LEDS_TRIGGERS
114 init_rwsem(&led_cdev->trigger_lock);
115#endif
116 /* add to the list of leds */ 116 /* add to the list of leds */
117 down_write(&leds_list_lock); 117 down_write(&leds_list_lock);
118 list_add_tail(&led_cdev->node, &leds_list); 118 list_add_tail(&led_cdev->node, &leds_list);
@@ -121,8 +121,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
121 led_update_brightness(led_cdev); 121 led_update_brightness(led_cdev);
122 122
123#ifdef CONFIG_LEDS_TRIGGERS 123#ifdef CONFIG_LEDS_TRIGGERS
124 init_rwsem(&led_cdev->trigger_lock);
125
126 rc = device_create_file(led_cdev->dev, &dev_attr_trigger); 124 rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
127 if (rc) 125 if (rc)
128 goto err_out_led_list; 126 goto err_out_led_list;
@@ -147,7 +145,7 @@ err_out:
147EXPORT_SYMBOL_GPL(led_classdev_register); 145EXPORT_SYMBOL_GPL(led_classdev_register);
148 146
149/** 147/**
150 * __led_classdev_unregister - unregisters a object of led_properties class. 148 * led_classdev_unregister - unregisters a object of led_properties class.
151 * @led_cdev: the led device to unregister 149 * @led_cdev: the led device to unregister
152 * 150 *
153 * Unregisters a previously registered via led_classdev_register object. 151 * Unregisters a previously registered via led_classdev_register object.
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 0f242b3f09b6..f910eaffe3a6 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -111,16 +111,17 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
111 flags); 111 flags);
112 if (led_cdev->trigger->deactivate) 112 if (led_cdev->trigger->deactivate)
113 led_cdev->trigger->deactivate(led_cdev); 113 led_cdev->trigger->deactivate(led_cdev);
114 led_cdev->trigger = NULL;
114 led_set_brightness(led_cdev, LED_OFF); 115 led_set_brightness(led_cdev, LED_OFF);
115 } 116 }
116 if (trigger) { 117 if (trigger) {
117 write_lock_irqsave(&trigger->leddev_list_lock, flags); 118 write_lock_irqsave(&trigger->leddev_list_lock, flags);
118 list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); 119 list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
119 write_unlock_irqrestore(&trigger->leddev_list_lock, flags); 120 write_unlock_irqrestore(&trigger->leddev_list_lock, flags);
121 led_cdev->trigger = trigger;
120 if (trigger->activate) 122 if (trigger->activate)
121 trigger->activate(led_cdev); 123 trigger->activate(led_cdev);
122 } 124 }
123 led_cdev->trigger = trigger;
124} 125}
125EXPORT_SYMBOL_GPL(led_trigger_set); 126EXPORT_SYMBOL_GPL(led_trigger_set);
126 127
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index c37bb0d5a0c5..1bd590bb3a6e 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -12,7 +12,7 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/platform_device.h> 13#include <linux/platform_device.h>
14#include <linux/leds.h> 14#include <linux/leds.h>
15#include <asm/arch/board-ams-delta.h> 15#include <mach/board-ams-delta.h>
16 16
17/* 17/*
18 * Our context 18 * Our context
@@ -107,27 +107,27 @@ static int ams_delta_led_resume(struct platform_device *dev)
107 107
108static int ams_delta_led_probe(struct platform_device *pdev) 108static int ams_delta_led_probe(struct platform_device *pdev)
109{ 109{
110 int i; 110 int i, ret;
111 int ret;
112 111
113 for (i = ret = 0; ret >= 0 && i < ARRAY_SIZE(ams_delta_leds); i++) { 112 for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) {
114 ret = led_classdev_register(&pdev->dev, 113 ret = led_classdev_register(&pdev->dev,
115 &ams_delta_leds[i].cdev); 114 &ams_delta_leds[i].cdev);
115 if (ret < 0)
116 goto fail;
116 } 117 }
117 118
118 if (ret < 0 && i > 1) { 119 return 0;
119 for (i = i - 2; i >= 0; i--) 120fail:
120 led_classdev_unregister(&ams_delta_leds[i].cdev); 121 while (--i >= 0)
121 } 122 led_classdev_unregister(&ams_delta_leds[i].cdev);
122 123 return ret;
123 return ret;
124} 124}
125 125
126static int ams_delta_led_remove(struct platform_device *pdev) 126static int ams_delta_led_remove(struct platform_device *pdev)
127{ 127{
128 int i; 128 int i;
129 129
130 for (i = ARRAY_SIZE(ams_delta_leds) - 1; i >= 0; i--) 130 for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i--)
131 led_classdev_unregister(&ams_delta_leds[i].cdev); 131 led_classdev_unregister(&ams_delta_leds[i].cdev);
132 132
133 return 0; 133 return 0;
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c
index 28db6c1444ed..52297c3ab246 100644
--- a/drivers/leds/leds-atmel-pwm.c
+++ b/drivers/leds/leds-atmel-pwm.c
@@ -37,7 +37,7 @@ static int __init pwmled_probe(struct platform_device *pdev)
37{ 37{
38 const struct gpio_led_platform_data *pdata; 38 const struct gpio_led_platform_data *pdata;
39 struct pwmled *leds; 39 struct pwmled *leds;
40 unsigned i; 40 int i;
41 int status; 41 int status;
42 42
43 pdata = pdev->dev.platform_data; 43 pdata = pdev->dev.platform_data;
diff --git a/drivers/leds/leds-cm-x270.c b/drivers/leds/leds-cm-x270.c
deleted file mode 100644
index accc7eddb788..000000000000
--- a/drivers/leds/leds-cm-x270.c
+++ /dev/null
@@ -1,124 +0,0 @@
1/*
2 * drivers/leds/leds-cm-x270.c
3 *
4 * Copyright 2007 CompuLab Ltd.
5 * Author: Mike Rapoport <mike@compulab.co.il>
6 *
7 * Based on leds-corgi.c
8 * Author: Richard Purdie <rpurdie@openedhand.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/leds.h>
20
21#include <asm/arch/hardware.h>
22#include <asm/arch/pxa-regs.h>
23
24#define GPIO_RED_LED (93)
25#define GPIO_GREEN_LED (94)
26
27static void cmx270_red_set(struct led_classdev *led_cdev,
28 enum led_brightness value)
29{
30 if (value)
31 GPCR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
32 else
33 GPSR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
34}
35
36static void cmx270_green_set(struct led_classdev *led_cdev,
37 enum led_brightness value)
38{
39 if (value)
40 GPCR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
41 else
42 GPSR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
43}
44
45static struct led_classdev cmx270_red_led = {
46 .name = "cm-x270:red",
47 .default_trigger = "nand-disk",
48 .brightness_set = cmx270_red_set,
49};
50
51static struct led_classdev cmx270_green_led = {
52 .name = "cm-x270:green",
53 .default_trigger = "heartbeat",
54 .brightness_set = cmx270_green_set,
55};
56
57#ifdef CONFIG_PM
58static int cmx270led_suspend(struct platform_device *dev, pm_message_t state)
59{
60 led_classdev_suspend(&cmx270_red_led);
61 led_classdev_suspend(&cmx270_green_led);
62 return 0;
63}
64
65static int cmx270led_resume(struct platform_device *dev)
66{
67 led_classdev_resume(&cmx270_red_led);
68 led_classdev_resume(&cmx270_green_led);
69 return 0;
70}
71#endif
72
73static int cmx270led_probe(struct platform_device *pdev)
74{
75 int ret;
76
77 ret = led_classdev_register(&pdev->dev, &cmx270_red_led);
78 if (ret < 0)
79 return ret;
80
81 ret = led_classdev_register(&pdev->dev, &cmx270_green_led);
82 if (ret < 0)
83 led_classdev_unregister(&cmx270_red_led);
84
85 return ret;
86}
87
88static int cmx270led_remove(struct platform_device *pdev)
89{
90 led_classdev_unregister(&cmx270_red_led);
91 led_classdev_unregister(&cmx270_green_led);
92 return 0;
93}
94
95static struct platform_driver cmx270led_driver = {
96 .probe = cmx270led_probe,
97 .remove = cmx270led_remove,
98#ifdef CONFIG_PM
99 .suspend = cmx270led_suspend,
100 .resume = cmx270led_resume,
101#endif
102 .driver = {
103 .name = "cm-x270-led",
104 .owner = THIS_MODULE,
105 },
106};
107
108static int __init cmx270led_init(void)
109{
110 return platform_driver_register(&cmx270led_driver);
111}
112
113static void __exit cmx270led_exit(void)
114{
115 platform_driver_unregister(&cmx270led_driver);
116}
117
118module_init(cmx270led_init);
119module_exit(cmx270led_exit);
120
121MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
122MODULE_DESCRIPTION("CM-x270 LED driver");
123MODULE_LICENSE("GPL");
124MODULE_ALIAS("platform:cm-x270-led");
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c
deleted file mode 100644
index a709704b9f93..000000000000
--- a/drivers/leds/leds-corgi.c
+++ /dev/null
@@ -1,125 +0,0 @@
1/*
2 * LED Triggers Core
3 *
4 * Copyright 2005-2006 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/platform_device.h>
17#include <linux/leds.h>
18#include <asm/mach-types.h>
19#include <asm/arch/corgi.h>
20#include <asm/arch/hardware.h>
21#include <asm/arch/pxa-regs.h>
22#include <asm/hardware/scoop.h>
23
24static void corgiled_amber_set(struct led_classdev *led_cdev,
25 enum led_brightness value)
26{
27 if (value)
28 GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
29 else
30 GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
31}
32
33static void corgiled_green_set(struct led_classdev *led_cdev,
34 enum led_brightness value)
35{
36 if (value)
37 set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
38 else
39 reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
40}
41
42static struct led_classdev corgi_amber_led = {
43 .name = "corgi:amber:charge",
44 .default_trigger = "sharpsl-charge",
45 .brightness_set = corgiled_amber_set,
46};
47
48static struct led_classdev corgi_green_led = {
49 .name = "corgi:green:mail",
50 .default_trigger = "nand-disk",
51 .brightness_set = corgiled_green_set,
52};
53
54#ifdef CONFIG_PM
55static int corgiled_suspend(struct platform_device *dev, pm_message_t state)
56{
57#ifdef CONFIG_LEDS_TRIGGERS
58 if (corgi_amber_led.trigger &&
59 strcmp(corgi_amber_led.trigger->name, "sharpsl-charge"))
60#endif
61 led_classdev_suspend(&corgi_amber_led);
62 led_classdev_suspend(&corgi_green_led);
63 return 0;
64}
65
66static int corgiled_resume(struct platform_device *dev)
67{
68 led_classdev_resume(&corgi_amber_led);
69 led_classdev_resume(&corgi_green_led);
70 return 0;
71}
72#endif
73
74static int corgiled_probe(struct platform_device *pdev)
75{
76 int ret;
77
78 ret = led_classdev_register(&pdev->dev, &corgi_amber_led);
79 if (ret < 0)
80 return ret;
81
82 ret = led_classdev_register(&pdev->dev, &corgi_green_led);
83 if (ret < 0)
84 led_classdev_unregister(&corgi_amber_led);
85
86 return ret;
87}
88
89static int corgiled_remove(struct platform_device *pdev)
90{
91 led_classdev_unregister(&corgi_amber_led);
92 led_classdev_unregister(&corgi_green_led);
93 return 0;
94}
95
96static struct platform_driver corgiled_driver = {
97 .probe = corgiled_probe,
98 .remove = corgiled_remove,
99#ifdef CONFIG_PM
100 .suspend = corgiled_suspend,
101 .resume = corgiled_resume,
102#endif
103 .driver = {
104 .name = "corgi-led",
105 .owner = THIS_MODULE,
106 },
107};
108
109static int __init corgiled_init(void)
110{
111 return platform_driver_register(&corgiled_driver);
112}
113
114static void __exit corgiled_exit(void)
115{
116 platform_driver_unregister(&corgiled_driver);
117}
118
119module_init(corgiled_init);
120module_exit(corgiled_exit);
121
122MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
123MODULE_DESCRIPTION("Corgi LED driver");
124MODULE_LICENSE("GPL");
125MODULE_ALIAS("platform:corgi-led");
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
new file mode 100644
index 000000000000..f1fddb18d70d
--- /dev/null
+++ b/drivers/leds/leds-da903x.c
@@ -0,0 +1,175 @@
1/*
2 * LEDs driver for Dialog Semiconductor DA9030/DA9034
3 *
4 * Copyright (C) 2008 Compulab, Ltd.
5 * Mike Rapoport <mike@compulab.co.il>
6 *
7 * Copyright (C) 2006-2008 Marvell International Ltd.
8 * Eric Miao <eric.miao@marvell.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/leds.h>
20#include <linux/mfd/da903x.h>
21
22#define DA9030_LED1_CONTROL 0x20
23#define DA9030_LED2_CONTROL 0x21
24#define DA9030_LED3_CONTROL 0x22
25#define DA9030_LED4_CONTROL 0x23
26#define DA9030_LEDPC_CONTROL 0x24
27#define DA9030_MISC_CONTROL_A 0x26 /* Vibrator Control */
28
29#define DA9034_LED1_CONTROL 0x35
30#define DA9034_LED2_CONTROL 0x36
31#define DA9034_VIBRA 0x40
32
33struct da903x_led {
34 struct led_classdev cdev;
35 struct work_struct work;
36 struct device *master;
37 enum led_brightness new_brightness;
38 int id;
39 int flags;
40};
41
42#define DA9030_LED_OFFSET(id) ((id) - DA9030_ID_LED_1)
43#define DA9034_LED_OFFSET(id) ((id) - DA9034_ID_LED_1)
44
45static void da903x_led_work(struct work_struct *work)
46{
47 struct da903x_led *led = container_of(work, struct da903x_led, work);
48 uint8_t val;
49 int offset;
50
51 switch (led->id) {
52 case DA9030_ID_LED_1:
53 case DA9030_ID_LED_2:
54 case DA9030_ID_LED_3:
55 case DA9030_ID_LED_4:
56 case DA9030_ID_LED_PC:
57 offset = DA9030_LED_OFFSET(led->id);
58 val = led->flags & ~0x87;
59 val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
60 val |= (led->new_brightness >> 5) & 0x7; /* PWM<2:0> */
61 da903x_write(led->master, DA9030_LED1_CONTROL + offset, val);
62 break;
63 case DA9030_ID_VIBRA:
64 val = led->flags & ~0x80;
65 val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
66 da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
67 break;
68 case DA9034_ID_LED_1:
69 case DA9034_ID_LED_2:
70 offset = DA9034_LED_OFFSET(led->id);
71 val = (led->new_brightness * 0x5f / LED_FULL) & 0x7f;
72 val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
73 da903x_write(led->master, DA9034_LED1_CONTROL + offset, val);
74 break;
75 case DA9034_ID_VIBRA:
76 val = led->new_brightness & 0xfe;
77 da903x_write(led->master, DA9034_VIBRA, val);
78 break;
79 }
80}
81
82static void da903x_led_set(struct led_classdev *led_cdev,
83 enum led_brightness value)
84{
85 struct da903x_led *led;
86
87 led = container_of(led_cdev, struct da903x_led, cdev);
88 led->new_brightness = value;
89 schedule_work(&led->work);
90}
91
92static int __devinit da903x_led_probe(struct platform_device *pdev)
93{
94 struct led_info *pdata = pdev->dev.platform_data;
95 struct da903x_led *led;
96 int id, ret;
97
98 if (pdata == NULL)
99 return 0;
100
101 id = pdev->id;
102
103 if (!((id >= DA9030_ID_LED_1 && id <= DA9030_ID_VIBRA) ||
104 (id >= DA9034_ID_LED_1 && id <= DA9034_ID_VIBRA))) {
105 dev_err(&pdev->dev, "invalid LED ID (%d) specified\n", id);
106 return -EINVAL;
107 }
108
109 led = kzalloc(sizeof(struct da903x_led), GFP_KERNEL);
110 if (led == NULL) {
111 dev_err(&pdev->dev, "failed to alloc memory for LED%d\n", id);
112 return -ENOMEM;
113 }
114
115 led->cdev.name = pdata->name;
116 led->cdev.default_trigger = pdata->default_trigger;
117 led->cdev.brightness_set = da903x_led_set;
118 led->cdev.brightness = LED_OFF;
119
120 led->id = id;
121 led->flags = pdata->flags;
122 led->master = pdev->dev.parent;
123 led->new_brightness = LED_OFF;
124
125 INIT_WORK(&led->work, da903x_led_work);
126
127 ret = led_classdev_register(led->master, &led->cdev);
128 if (ret) {
129 dev_err(&pdev->dev, "failed to register LED %d\n", id);
130 goto err;
131 }
132
133 platform_set_drvdata(pdev, led);
134 return 0;
135
136err:
137 kfree(led);
138 return ret;
139}
140
141static int __devexit da903x_led_remove(struct platform_device *pdev)
142{
143 struct da903x_led *led = platform_get_drvdata(pdev);
144
145 led_classdev_unregister(&led->cdev);
146 kfree(led);
147 return 0;
148}
149
150static struct platform_driver da903x_led_driver = {
151 .driver = {
152 .name = "da903x-led",
153 .owner = THIS_MODULE,
154 },
155 .probe = da903x_led_probe,
156 .remove = __devexit_p(da903x_led_remove),
157};
158
159static int __init da903x_led_init(void)
160{
161 return platform_driver_register(&da903x_led_driver);
162}
163module_init(da903x_led_init);
164
165static void __exit da903x_led_exit(void)
166{
167 platform_driver_unregister(&da903x_led_driver);
168}
169module_exit(da903x_led_exit);
170
171MODULE_DESCRIPTION("LEDs driver for Dialog Semiconductor DA9030/DA9034");
172MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
173 "Mike Rapoport <mike@compulab.co.il>");
174MODULE_LICENSE("GPL");
175MODULE_ALIAS("platform:da903x-led");
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index a7421b8c47d8..34935155c1c0 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -19,7 +19,7 @@
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/leds.h> 21#include <linux/leds.h>
22#include <asm/arch/hardware.h> 22#include <mach/hardware.h>
23#include <asm/io.h> 23#include <asm/io.h>
24 24
25static short __iomem *latch_address; 25static short __iomem *latch_address;
@@ -161,6 +161,16 @@ static int fsg_led_probe(struct platform_device *pdev)
161{ 161{
162 int ret; 162 int ret;
163 163
164 /* Map the LED chip select address space */
165 latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
166 if (!latch_address) {
167 ret = -ENOMEM;
168 goto failremap;
169 }
170
171 latch_value = 0xffff;
172 *latch_address = latch_value;
173
164 ret = led_classdev_register(&pdev->dev, &fsg_wlan_led); 174 ret = led_classdev_register(&pdev->dev, &fsg_wlan_led);
165 if (ret < 0) 175 if (ret < 0)
166 goto failwlan; 176 goto failwlan;
@@ -185,20 +195,8 @@ static int fsg_led_probe(struct platform_device *pdev)
185 if (ret < 0) 195 if (ret < 0)
186 goto failring; 196 goto failring;
187 197
188 /* Map the LED chip select address space */
189 latch_address = (unsigned short *) ioremap(IXP4XX_EXP_BUS_BASE(2), 512);
190 if (!latch_address) {
191 ret = -ENOMEM;
192 goto failremap;
193 }
194
195 latch_value = 0xffff;
196 *latch_address = latch_value;
197
198 return ret; 198 return ret;
199 199
200 failremap:
201 led_classdev_unregister(&fsg_ring_led);
202 failring: 200 failring:
203 led_classdev_unregister(&fsg_sync_led); 201 led_classdev_unregister(&fsg_sync_led);
204 failsync: 202 failsync:
@@ -210,14 +208,14 @@ static int fsg_led_probe(struct platform_device *pdev)
210 failwan: 208 failwan:
211 led_classdev_unregister(&fsg_wlan_led); 209 led_classdev_unregister(&fsg_wlan_led);
212 failwlan: 210 failwlan:
211 iounmap(latch_address);
212 failremap:
213 213
214 return ret; 214 return ret;
215} 215}
216 216
217static int fsg_led_remove(struct platform_device *pdev) 217static int fsg_led_remove(struct platform_device *pdev)
218{ 218{
219 iounmap(latch_address);
220
221 led_classdev_unregister(&fsg_wlan_led); 219 led_classdev_unregister(&fsg_wlan_led);
222 led_classdev_unregister(&fsg_wan_led); 220 led_classdev_unregister(&fsg_wan_led);
223 led_classdev_unregister(&fsg_sata_led); 221 led_classdev_unregister(&fsg_sata_led);
@@ -225,6 +223,8 @@ static int fsg_led_remove(struct platform_device *pdev)
225 led_classdev_unregister(&fsg_sync_led); 223 led_classdev_unregister(&fsg_sync_led);
226 led_classdev_unregister(&fsg_ring_led); 224 led_classdev_unregister(&fsg_ring_led);
227 225
226 iounmap(latch_address);
227
228 return 0; 228 return 0;
229} 229}
230 230
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index bcec42230389..11b77a70bbcb 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -16,14 +16,15 @@
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/ctype.h> 17#include <linux/ctype.h>
18#include <linux/leds.h> 18#include <linux/leds.h>
19#include <asm/arch/regs-gpio.h> 19#include <mach/regs-gpio.h>
20#include <asm/hardware.h> 20#include <mach/hardware.h>
21#include <asm/arch/h1940-latch.h> 21#include <mach/h1940-latch.h>
22 22
23/* 23/*
24 * Green led. 24 * Green led.
25 */ 25 */
26void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value) 26static void h1940_greenled_set(struct led_classdev *led_dev,
27 enum led_brightness value)
27{ 28{
28 switch (value) { 29 switch (value) {
29 case LED_HALF: 30 case LED_HALF:
@@ -52,7 +53,8 @@ static struct led_classdev h1940_greenled = {
52/* 53/*
53 * Red led. 54 * Red led.
54 */ 55 */
55void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value) 56static void h1940_redled_set(struct led_classdev *led_dev,
57 enum led_brightness value)
56{ 58{
57 switch (value) { 59 switch (value) {
58 case LED_HALF: 60 case LED_HALF:
@@ -82,7 +84,8 @@ static struct led_classdev h1940_redled = {
82 * Blue led. 84 * Blue led.
83 * (it can only be blue flashing led) 85 * (it can only be blue flashing led)
84 */ 86 */
85void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value) 87static void h1940_blueled_set(struct led_classdev *led_dev,
88 enum led_brightness value)
86{ 89{
87 if (value) { 90 if (value) {
88 /* flashing Blue */ 91 /* flashing Blue */
diff --git a/drivers/leds/leds-hp-disk.c b/drivers/leds/leds-hp-disk.c
new file mode 100644
index 000000000000..53a25b1c2dae
--- /dev/null
+++ b/drivers/leds/leds-hp-disk.c
@@ -0,0 +1,156 @@
1/*
2 * leds-hp-disk.c - driver for HP "hard disk protection" LED
3 *
4 * Copyright (C) 2008 Pavel Machek
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/dmi.h>
24#include <linux/module.h>
25#include <linux/types.h>
26#include <linux/platform_device.h>
27#include <linux/interrupt.h>
28#include <linux/input.h>
29#include <linux/kthread.h>
30#include <linux/version.h>
31#include <linux/leds.h>
32#include <acpi/acpi_drivers.h>
33
34#define DRIVER_NAME "leds-hp-disk"
35#define ACPI_MDPS_CLASS "led"
36
37/* For automatic insertion of the module */
38static struct acpi_device_id hpled_device_ids[] = {
39 {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
40 {"", 0},
41};
42MODULE_DEVICE_TABLE(acpi, hpled_device_ids);
43
44struct acpi_hpled {
45 struct acpi_device *device; /* The ACPI device */
46};
47
48static struct acpi_hpled adev;
49
50static acpi_status hpled_acpi_write(acpi_handle handle, int reg)
51{
52 unsigned long ret; /* Not used when writing */
53 union acpi_object in_obj[1];
54 struct acpi_object_list args = { 1, in_obj };
55
56 in_obj[0].type = ACPI_TYPE_INTEGER;
57 in_obj[0].integer.value = reg;
58
59 return acpi_evaluate_integer(handle, "ALED", &args, &ret);
60}
61
62static void hpled_set(struct led_classdev *led_cdev,
63 enum led_brightness value)
64{
65 hpled_acpi_write(adev.device->handle, !!value);
66}
67
68static struct led_classdev hpled_led = {
69 .name = "hp:red:hddprotection",
70 .default_trigger = "heartbeat",
71 .brightness_set = hpled_set,
72};
73
74#ifdef CONFIG_PM
75static int hpled_suspend(struct acpi_device *dev, pm_message_t state)
76{
77 led_classdev_suspend(&hpled_led);
78 return 0;
79}
80
81static int hpled_resume(struct acpi_device *dev)
82{
83 led_classdev_resume(&hpled_led);
84 return 0;
85}
86#else
87#define hpled_suspend NULL
88#define hpled_resume NULL
89#endif
90
91static int hpled_add(struct acpi_device *device)
92{
93 int ret;
94
95 if (!device)
96 return -EINVAL;
97
98 adev.device = device;
99 strcpy(acpi_device_name(device), DRIVER_NAME);
100 strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
101 device->driver_data = &adev;
102
103 ret = led_classdev_register(NULL, &hpled_led);
104 return ret;
105}
106
107static int hpled_remove(struct acpi_device *device, int type)
108{
109 if (!device)
110 return -EINVAL;
111
112 led_classdev_unregister(&hpled_led);
113 return 0;
114}
115
116
117
118static struct acpi_driver leds_hp_driver = {
119 .name = DRIVER_NAME,
120 .class = ACPI_MDPS_CLASS,
121 .ids = hpled_device_ids,
122 .ops = {
123 .add = hpled_add,
124 .remove = hpled_remove,
125 .suspend = hpled_suspend,
126 .resume = hpled_resume,
127 }
128};
129
130static int __init hpled_init_module(void)
131{
132 int ret;
133
134 if (acpi_disabled)
135 return -ENODEV;
136
137 ret = acpi_bus_register_driver(&leds_hp_driver);
138 if (ret < 0)
139 return ret;
140
141 printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
142
143 return 0;
144}
145
146static void __exit hpled_exit_module(void)
147{
148 acpi_bus_unregister_driver(&leds_hp_driver);
149}
150
151MODULE_DESCRIPTION("Driver for HP disk protection LED");
152MODULE_AUTHOR("Pavel Machek <pavel@suse.cz>");
153MODULE_LICENSE("GPL");
154
155module_init(hpled_init_module);
156module_exit(hpled_exit_module);
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index 844d5979c904..e8fb1baf8a50 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -15,7 +15,7 @@
15#include <linux/platform_device.h> 15#include <linux/platform_device.h>
16#include <linux/leds.h> 16#include <linux/leds.h>
17#include <asm/hd64461.h> 17#include <asm/hd64461.h>
18#include <asm/hp6xx.h> 18#include <mach/hp6xx.h>
19 19
20static void hp6xxled_green_set(struct led_classdev *led_cdev, 20static void hp6xxled_green_set(struct led_classdev *led_cdev,
21 enum led_brightness value) 21 enum led_brightness value)
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 7295f7f52185..5d91362e3066 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -13,7 +13,7 @@
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/leds.h> 14#include <linux/leds.h>
15 15
16#include <asm/hardware.h> 16#include <mach/hardware.h>
17#include <asm/hardware/locomo.h> 17#include <asm/hardware/locomo.h>
18 18
19static void locomoled_brightness_set(struct led_classdev *led_cdev, 19static void locomoled_brightness_set(struct led_classdev *led_cdev,
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
new file mode 100644
index 000000000000..4064d4f6b33b
--- /dev/null
+++ b/drivers/leds/leds-pca9532.c
@@ -0,0 +1,337 @@
1/*
2 * pca9532.c - 16-bit Led dimmer
3 *
4 * Copyright (C) 2008 Riku Voipio <riku.voipio@movial.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * Datasheet: http://www.nxp.com/acrobat/datasheets/PCA9532_3.pdf
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/i2c.h>
16#include <linux/leds.h>
17#include <linux/input.h>
18#include <linux/mutex.h>
19#include <linux/leds-pca9532.h>
20
21static const unsigned short normal_i2c[] = { /*0x60,*/ I2C_CLIENT_END};
22I2C_CLIENT_INSMOD_1(pca9532);
23
24#define PCA9532_REG_PSC(i) (0x2+(i)*2)
25#define PCA9532_REG_PWM(i) (0x3+(i)*2)
26#define PCA9532_REG_LS0 0x6
27#define LED_REG(led) ((led>>2)+PCA9532_REG_LS0)
28#define LED_NUM(led) (led & 0x3)
29
30#define ldev_to_led(c) container_of(c, struct pca9532_led, ldev)
31
32struct pca9532_data {
33 struct i2c_client *client;
34 struct pca9532_led leds[16];
35 struct mutex update_lock;
36 struct input_dev *idev;
37 u8 pwm[2];
38 u8 psc[2];
39};
40
41static int pca9532_probe(struct i2c_client *client,
42 const struct i2c_device_id *id);
43static int pca9532_remove(struct i2c_client *client);
44
45static const struct i2c_device_id pca9532_id[] = {
46 { "pca9532", 0 },
47 { }
48};
49
50MODULE_DEVICE_TABLE(i2c, pca9532_id);
51
52static struct i2c_driver pca9532_driver = {
53 .driver = {
54 .name = "pca9532",
55 },
56 .probe = pca9532_probe,
57 .remove = pca9532_remove,
58 .id_table = pca9532_id,
59};
60
61/* We have two pwm/blinkers, but 16 possible leds to drive. Additionaly,
62 * the clever Thecus people are using one pwm to drive the beeper. So,
63 * as a compromise we average one pwm to the values requested by all
64 * leds that are not ON/OFF.
65 * */
66static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink,
67 enum led_brightness value)
68{
69 int a = 0, b = 0, i = 0;
70 struct pca9532_data *data = i2c_get_clientdata(client);
71 for (i = 0; i < 16; i++) {
72 if (data->leds[i].type == PCA9532_TYPE_LED &&
73 data->leds[i].state == PCA9532_PWM0+pwm) {
74 a++;
75 b += data->leds[i].ldev.brightness;
76 }
77 }
78 if (a == 0) {
79 dev_err(&client->dev,
80 "fear of division by zero %d/%d, wanted %d\n",
81 b, a, value);
82 return -EINVAL;
83 }
84 b = b/a;
85 if (b > 0xFF)
86 return -EINVAL;
87 mutex_lock(&data->update_lock);
88 data->pwm[pwm] = b;
89 i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
90 data->pwm[pwm]);
91 data->psc[pwm] = blink;
92 i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
93 data->psc[pwm]);
94 mutex_unlock(&data->update_lock);
95 return 0;
96}
97
98/* Set LED routing */
99static void pca9532_setled(struct pca9532_led *led)
100{
101 struct i2c_client *client = led->client;
102 struct pca9532_data *data = i2c_get_clientdata(client);
103 char reg;
104
105 mutex_lock(&data->update_lock);
106 reg = i2c_smbus_read_byte_data(client, LED_REG(led->id));
107 /* zero led bits */
108 reg = reg & ~(0x3<<LED_NUM(led->id)*2);
109 /* set the new value */
110 reg = reg | (led->state << LED_NUM(led->id)*2);
111 i2c_smbus_write_byte_data(client, LED_REG(led->id), reg);
112 mutex_unlock(&data->update_lock);
113}
114
115static void pca9532_set_brightness(struct led_classdev *led_cdev,
116 enum led_brightness value)
117{
118 int err = 0;
119 struct pca9532_led *led = ldev_to_led(led_cdev);
120
121 if (value == LED_OFF)
122 led->state = PCA9532_OFF;
123 else if (value == LED_FULL)
124 led->state = PCA9532_ON;
125 else {
126 led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
127 err = pca9532_setpwm(led->client, 0, 0, value);
128 if (err)
129 return; /* XXX: led api doesn't allow error code? */
130 }
131 pca9532_setled(led);
132}
133
134static int pca9532_set_blink(struct led_classdev *led_cdev,
135 unsigned long *delay_on, unsigned long *delay_off)
136{
137 struct pca9532_led *led = ldev_to_led(led_cdev);
138 struct i2c_client *client = led->client;
139 int psc;
140
141 if (*delay_on == 0 && *delay_off == 0) {
142 /* led subsystem ask us for a blink rate */
143 *delay_on = 1000;
144 *delay_off = 1000;
145 }
146 if (*delay_on != *delay_off || *delay_on > 1690 || *delay_on < 6)
147 return -EINVAL;
148
149 /* Thecus specific: only use PSC/PWM 0 */
150 psc = (*delay_on * 152-1)/1000;
151 return pca9532_setpwm(client, 0, psc, led_cdev->brightness);
152}
153
154int pca9532_event(struct input_dev *dev, unsigned int type, unsigned int code,
155 int value)
156{
157 struct pca9532_data *data = input_get_drvdata(dev);
158
159 if (type != EV_SND && (code != SND_BELL || code != SND_TONE))
160 return -1;
161
162 /* XXX: allow different kind of beeps with psc/pwm modifications */
163 if (value > 1 && value < 32767)
164 data->pwm[1] = 127;
165 else
166 data->pwm[1] = 0;
167
168 dev_info(&dev->dev, "setting beep to %d \n", data->pwm[1]);
169 mutex_lock(&data->update_lock);
170 i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
171 data->pwm[1]);
172 mutex_unlock(&data->update_lock);
173
174 return 0;
175}
176
177static int pca9532_configure(struct i2c_client *client,
178 struct pca9532_data *data, struct pca9532_platform_data *pdata)
179{
180 int i, err = 0;
181
182 for (i = 0; i < 2; i++) {
183 data->pwm[i] = pdata->pwm[i];
184 data->psc[i] = pdata->psc[i];
185 i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(i),
186 data->pwm[i]);
187 i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(i),
188 data->psc[i]);
189 }
190
191 for (i = 0; i < 16; i++) {
192 struct pca9532_led *led = &data->leds[i];
193 struct pca9532_led *pled = &pdata->leds[i];
194 led->client = client;
195 led->id = i;
196 led->type = pled->type;
197 switch (led->type) {
198 case PCA9532_TYPE_NONE:
199 break;
200 case PCA9532_TYPE_LED:
201 led->state = pled->state;
202 led->name = pled->name;
203 led->ldev.name = led->name;
204 led->ldev.brightness = LED_OFF;
205 led->ldev.brightness_set = pca9532_set_brightness;
206 led->ldev.blink_set = pca9532_set_blink;
207 if (led_classdev_register(&client->dev,
208 &led->ldev) < 0) {
209 dev_err(&client->dev,
210 "couldn't register LED %s\n",
211 led->name);
212 goto exit;
213 }
214 pca9532_setled(led);
215 break;
216 case PCA9532_TYPE_N2100_BEEP:
217 BUG_ON(data->idev);
218 led->state = PCA9532_PWM1;
219 pca9532_setled(led);
220 data->idev = input_allocate_device();
221 if (data->idev == NULL) {
222 err = -ENOMEM;
223 goto exit;
224 }
225 data->idev->name = pled->name;
226 data->idev->phys = "i2c/pca9532";
227 data->idev->id.bustype = BUS_HOST;
228 data->idev->id.vendor = 0x001f;
229 data->idev->id.product = 0x0001;
230 data->idev->id.version = 0x0100;
231 data->idev->evbit[0] = BIT_MASK(EV_SND);
232 data->idev->sndbit[0] = BIT_MASK(SND_BELL) |
233 BIT_MASK(SND_TONE);
234 data->idev->event = pca9532_event;
235 input_set_drvdata(data->idev, data);
236 err = input_register_device(data->idev);
237 if (err) {
238 input_free_device(data->idev);
239 data->idev = NULL;
240 goto exit;
241 }
242 break;
243 }
244 }
245 return 0;
246
247exit:
248 if (i > 0)
249 for (i = i - 1; i >= 0; i--)
250 switch (data->leds[i].type) {
251 case PCA9532_TYPE_NONE:
252 break;
253 case PCA9532_TYPE_LED:
254 led_classdev_unregister(&data->leds[i].ldev);
255 break;
256 case PCA9532_TYPE_N2100_BEEP:
257 if (data->idev != NULL) {
258 input_unregister_device(data->idev);
259 input_free_device(data->idev);
260 data->idev = NULL;
261 }
262 break;
263 }
264
265 return err;
266
267}
268
269static int pca9532_probe(struct i2c_client *client,
270 const struct i2c_device_id *id)
271{
272 struct pca9532_data *data = i2c_get_clientdata(client);
273 struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
274
275 if (!i2c_check_functionality(client->adapter,
276 I2C_FUNC_SMBUS_BYTE_DATA))
277 return -EIO;
278
279 data = kzalloc(sizeof(struct pca9532_data), GFP_KERNEL);
280 if (!data)
281 return -ENOMEM;
282
283 dev_info(&client->dev, "setting platform data\n");
284 i2c_set_clientdata(client, data);
285 data->client = client;
286 mutex_init(&data->update_lock);
287
288 if (pca9532_pdata == NULL)
289 return -EIO;
290
291 pca9532_configure(client, data, pca9532_pdata);
292 return 0;
293
294}
295
296static int pca9532_remove(struct i2c_client *client)
297{
298 struct pca9532_data *data = i2c_get_clientdata(client);
299 int i;
300 for (i = 0; i < 16; i++)
301 switch (data->leds[i].type) {
302 case PCA9532_TYPE_NONE:
303 break;
304 case PCA9532_TYPE_LED:
305 led_classdev_unregister(&data->leds[i].ldev);
306 break;
307 case PCA9532_TYPE_N2100_BEEP:
308 if (data->idev != NULL) {
309 input_unregister_device(data->idev);
310 input_free_device(data->idev);
311 data->idev = NULL;
312 }
313 break;
314 }
315
316 kfree(data);
317 i2c_set_clientdata(client, NULL);
318 return 0;
319}
320
321static int __init pca9532_init(void)
322{
323 return i2c_add_driver(&pca9532_driver);
324}
325
326static void __exit pca9532_exit(void)
327{
328 i2c_del_driver(&pca9532_driver);
329}
330
331MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
332MODULE_LICENSE("GPL");
333MODULE_DESCRIPTION("PCA 9532 LED dimmer");
334
335module_init(pca9532_init);
336module_exit(pca9532_exit);
337
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
new file mode 100644
index 000000000000..4e2d1a42b48f
--- /dev/null
+++ b/drivers/leds/leds-pca955x.c
@@ -0,0 +1,390 @@
1/*
2 * Copyright 2007-2008 Extreme Engineering Solutions, Inc.
3 *
4 * Author: Nate Case <ncase@xes-inc.com>
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * LED driver for various PCA955x I2C LED drivers
11 *
12 * Supported devices:
13 *
14 * Device Description 7-bit slave address
15 * ------ ----------- -------------------
16 * PCA9550 2-bit driver 0x60 .. 0x61
17 * PCA9551 8-bit driver 0x60 .. 0x67
18 * PCA9552 16-bit driver 0x60 .. 0x67
19 * PCA9553/01 4-bit driver 0x62
20 * PCA9553/02 4-bit driver 0x63
21 *
22 * Philips PCA955x LED driver chips follow a register map as shown below:
23 *
24 * Control Register Description
25 * ---------------- -----------
26 * 0x0 Input register 0
27 * ..
28 * NUM_INPUT_REGS - 1 Last Input register X
29 *
30 * NUM_INPUT_REGS Frequency prescaler 0
31 * NUM_INPUT_REGS + 1 PWM register 0
32 * NUM_INPUT_REGS + 2 Frequency prescaler 1
33 * NUM_INPUT_REGS + 3 PWM register 1
34 *
35 * NUM_INPUT_REGS + 4 LED selector 0
36 * NUM_INPUT_REGS + 4
37 * + NUM_LED_REGS - 1 Last LED selector
38 *
39 * where NUM_INPUT_REGS and NUM_LED_REGS vary depending on how many
40 * bits the chip supports.
41 */
42
43#include <linux/module.h>
44#include <linux/delay.h>
45#include <linux/string.h>
46#include <linux/ctype.h>
47#include <linux/leds.h>
48#include <linux/err.h>
49#include <linux/i2c.h>
50#include <linux/workqueue.h>
51
52/* LED select registers determine the source that drives LED outputs */
53#define PCA955X_LS_LED_ON 0x0 /* Output LOW */
54#define PCA955X_LS_LED_OFF 0x1 /* Output HI-Z */
55#define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */
56#define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */
57
58enum pca955x_type {
59 pca9550,
60 pca9551,
61 pca9552,
62 pca9553,
63};
64
65struct pca955x_chipdef {
66 int bits;
67 u8 slv_addr; /* 7-bit slave address mask */
68 int slv_addr_shift; /* Number of bits to ignore */
69};
70
71static struct pca955x_chipdef pca955x_chipdefs[] = {
72 [pca9550] = {
73 .bits = 2,
74 .slv_addr = /* 110000x */ 0x60,
75 .slv_addr_shift = 1,
76 },
77 [pca9551] = {
78 .bits = 8,
79 .slv_addr = /* 1100xxx */ 0x60,
80 .slv_addr_shift = 3,
81 },
82 [pca9552] = {
83 .bits = 16,
84 .slv_addr = /* 1100xxx */ 0x60,
85 .slv_addr_shift = 3,
86 },
87 [pca9553] = {
88 .bits = 4,
89 .slv_addr = /* 110001x */ 0x62,
90 .slv_addr_shift = 1,
91 },
92};
93
94static const struct i2c_device_id pca955x_id[] = {
95 { "pca9550", pca9550 },
96 { "pca9551", pca9551 },
97 { "pca9552", pca9552 },
98 { "pca9553", pca9553 },
99 { }
100};
101MODULE_DEVICE_TABLE(i2c, pca955x_id);
102
103struct pca955x_led {
104 struct pca955x_chipdef *chipdef;
105 struct i2c_client *client;
106 struct work_struct work;
107 spinlock_t lock;
108 enum led_brightness brightness;
109 struct led_classdev led_cdev;
110 int led_num; /* 0 .. 15 potentially */
111 char name[32];
112};
113
114/* 8 bits per input register */
115static inline int pca95xx_num_input_regs(int bits)
116{
117 return (bits + 7) / 8;
118}
119
120/* 4 bits per LED selector register */
121static inline int pca95xx_num_led_regs(int bits)
122{
123 return (bits + 3) / 4;
124}
125
126/*
127 * Return an LED selector register value based on an existing one, with
128 * the appropriate 2-bit state value set for the given LED number (0-3).
129 */
130static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state)
131{
132 return (oldval & (~(0x3 << (led_num << 1)))) |
133 ((state & 0x3) << (led_num << 1));
134}
135
136/*
137 * Write to frequency prescaler register, used to program the
138 * period of the PWM output. period = (PSCx + 1) / 38
139 */
140static void pca955x_write_psc(struct i2c_client *client, int n, u8 val)
141{
142 struct pca955x_led *pca955x = i2c_get_clientdata(client);
143
144 i2c_smbus_write_byte_data(client,
145 pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n,
146 val);
147}
148
149/*
150 * Write to PWM register, which determines the duty cycle of the
151 * output. LED is OFF when the count is less than the value of this
152 * register, and ON when it is greater. If PWMx == 0, LED is always OFF.
153 *
154 * Duty cycle is (256 - PWMx) / 256
155 */
156static void pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
157{
158 struct pca955x_led *pca955x = i2c_get_clientdata(client);
159
160 i2c_smbus_write_byte_data(client,
161 pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n,
162 val);
163}
164
165/*
166 * Write to LED selector register, which determines the source that
167 * drives the LED output.
168 */
169static void pca955x_write_ls(struct i2c_client *client, int n, u8 val)
170{
171 struct pca955x_led *pca955x = i2c_get_clientdata(client);
172
173 i2c_smbus_write_byte_data(client,
174 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n,
175 val);
176}
177
178/*
179 * Read the LED selector register, which determines the source that
180 * drives the LED output.
181 */
182static u8 pca955x_read_ls(struct i2c_client *client, int n)
183{
184 struct pca955x_led *pca955x = i2c_get_clientdata(client);
185
186 return (u8) i2c_smbus_read_byte_data(client,
187 pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
188}
189
190static void pca955x_led_work(struct work_struct *work)
191{
192 struct pca955x_led *pca955x;
193 u8 ls;
194 int chip_ls; /* which LSx to use (0-3 potentially) */
195 int ls_led; /* which set of bits within LSx to use (0-3) */
196
197 pca955x = container_of(work, struct pca955x_led, work);
198 chip_ls = pca955x->led_num / 4;
199 ls_led = pca955x->led_num % 4;
200
201 ls = pca955x_read_ls(pca955x->client, chip_ls);
202
203 switch (pca955x->brightness) {
204 case LED_FULL:
205 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
206 break;
207 case LED_OFF:
208 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF);
209 break;
210 case LED_HALF:
211 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK0);
212 break;
213 default:
214 /*
215 * Use PWM1 for all other values. This has the unwanted
216 * side effect of making all LEDs on the chip share the
217 * same brightness level if set to a value other than
218 * OFF, HALF, or FULL. But, this is probably better than
219 * just turning off for all other values.
220 */
221 pca955x_write_pwm(pca955x->client, 1, 255-pca955x->brightness);
222 ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1);
223 break;
224 }
225
226 pca955x_write_ls(pca955x->client, chip_ls, ls);
227}
228
229static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value)
230{
231 struct pca955x_led *pca955x;
232
233 pca955x = container_of(led_cdev, struct pca955x_led, led_cdev);
234
235 spin_lock(&pca955x->lock);
236 pca955x->brightness = value;
237
238 /*
239 * Must use workqueue for the actual I/O since I2C operations
240 * can sleep.
241 */
242 schedule_work(&pca955x->work);
243
244 spin_unlock(&pca955x->lock);
245}
246
247static int __devinit pca955x_probe(struct i2c_client *client,
248 const struct i2c_device_id *id)
249{
250 struct pca955x_led *pca955x;
251 struct pca955x_chipdef *chip;
252 struct i2c_adapter *adapter;
253 struct led_platform_data *pdata;
254 int i, err;
255
256 chip = &pca955x_chipdefs[id->driver_data];
257 adapter = to_i2c_adapter(client->dev.parent);
258 pdata = client->dev.platform_data;
259
260 /* Make sure the slave address / chip type combo given is possible */
261 if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
262 chip->slv_addr) {
263 dev_err(&client->dev, "invalid slave address %02x\n",
264 client->addr);
265 return -ENODEV;
266 }
267
268 printk(KERN_INFO "leds-pca955x: Using %s %d-bit LED driver at "
269 "slave address 0x%02x\n",
270 id->name, chip->bits, client->addr);
271
272 if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
273 return -EIO;
274
275 if (pdata) {
276 if (pdata->num_leds != chip->bits) {
277 dev_err(&client->dev, "board info claims %d LEDs"
278 " on a %d-bit chip\n",
279 pdata->num_leds, chip->bits);
280 return -ENODEV;
281 }
282 }
283
284 pca955x = kzalloc(sizeof(*pca955x) * chip->bits, GFP_KERNEL);
285 if (!pca955x)
286 return -ENOMEM;
287
288 i2c_set_clientdata(client, pca955x);
289
290 for (i = 0; i < chip->bits; i++) {
291 pca955x[i].chipdef = chip;
292 pca955x[i].client = client;
293 pca955x[i].led_num = i;
294
295 /* Platform data can specify LED names and default triggers */
296 if (pdata) {
297 if (pdata->leds[i].name)
298 snprintf(pca955x[i].name,
299 sizeof(pca955x[i].name), "pca955x:%s",
300 pdata->leds[i].name);
301 if (pdata->leds[i].default_trigger)
302 pca955x[i].led_cdev.default_trigger =
303 pdata->leds[i].default_trigger;
304 } else {
305 snprintf(pca955x[i].name, sizeof(pca955x[i].name),
306 "pca955x:%d", i);
307 }
308
309 spin_lock_init(&pca955x[i].lock);
310
311 pca955x[i].led_cdev.name = pca955x[i].name;
312 pca955x[i].led_cdev.brightness_set = pca955x_led_set;
313
314 INIT_WORK(&pca955x[i].work, pca955x_led_work);
315
316 err = led_classdev_register(&client->dev, &pca955x[i].led_cdev);
317 if (err < 0)
318 goto exit;
319 }
320
321 /* Turn off LEDs */
322 for (i = 0; i < pca95xx_num_led_regs(chip->bits); i++)
323 pca955x_write_ls(client, i, 0x55);
324
325 /* PWM0 is used for half brightness or 50% duty cycle */
326 pca955x_write_pwm(client, 0, 255-LED_HALF);
327
328 /* PWM1 is used for variable brightness, default to OFF */
329 pca955x_write_pwm(client, 1, 0);
330
331 /* Set to fast frequency so we do not see flashing */
332 pca955x_write_psc(client, 0, 0);
333 pca955x_write_psc(client, 1, 0);
334
335 return 0;
336
337exit:
338 while (i--) {
339 led_classdev_unregister(&pca955x[i].led_cdev);
340 cancel_work_sync(&pca955x[i].work);
341 }
342
343 kfree(pca955x);
344 i2c_set_clientdata(client, NULL);
345
346 return err;
347}
348
349static int __devexit pca955x_remove(struct i2c_client *client)
350{
351 struct pca955x_led *pca955x = i2c_get_clientdata(client);
352 int i;
353
354 for (i = 0; i < pca955x->chipdef->bits; i++) {
355 led_classdev_unregister(&pca955x[i].led_cdev);
356 cancel_work_sync(&pca955x[i].work);
357 }
358
359 kfree(pca955x);
360 i2c_set_clientdata(client, NULL);
361
362 return 0;
363}
364
365static struct i2c_driver pca955x_driver = {
366 .driver = {
367 .name = "leds-pca955x",
368 .owner = THIS_MODULE,
369 },
370 .probe = pca955x_probe,
371 .remove = __devexit_p(pca955x_remove),
372 .id_table = pca955x_id,
373};
374
375static int __init pca955x_leds_init(void)
376{
377 return i2c_add_driver(&pca955x_driver);
378}
379
380static void __exit pca955x_leds_exit(void)
381{
382 i2c_del_driver(&pca955x_driver);
383}
384
385module_init(pca955x_leds_init);
386module_exit(pca955x_leds_exit);
387
388MODULE_AUTHOR("Nate Case <ncase@xes-inc.com>");
389MODULE_DESCRIPTION("PCA955x LED driver");
390MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index d4f5021dccbf..25a07f2643ad 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -16,9 +16,9 @@
16#include <linux/platform_device.h> 16#include <linux/platform_device.h>
17#include <linux/leds.h> 17#include <linux/leds.h>
18 18
19#include <asm/hardware.h> 19#include <mach/hardware.h>
20#include <asm/arch/regs-gpio.h> 20#include <mach/regs-gpio.h>
21#include <asm/arch/leds-gpio.h> 21#include <mach/leds-gpio.h>
22 22
23/* our context */ 23/* our context */
24 24
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c
deleted file mode 100644
index e75e8543bc5a..000000000000
--- a/drivers/leds/leds-spitz.c
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * LED Triggers Core
3 *
4 * Copyright 2005-2006 Openedhand Ltd.
5 *
6 * Author: Richard Purdie <rpurdie@openedhand.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/platform_device.h>
17#include <linux/leds.h>
18#include <asm/hardware/scoop.h>
19#include <asm/mach-types.h>
20#include <asm/arch/hardware.h>
21#include <asm/arch/pxa-regs.h>
22#include <asm/arch/spitz.h>
23
24static void spitzled_amber_set(struct led_classdev *led_cdev,
25 enum led_brightness value)
26{
27 if (value)
28 set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
29 else
30 reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
31}
32
33static void spitzled_green_set(struct led_classdev *led_cdev,
34 enum led_brightness value)
35{
36 if (value)
37 set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
38 else
39 reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
40}
41
42static struct led_classdev spitz_amber_led = {
43 .name = "spitz:amber:charge",
44 .default_trigger = "sharpsl-charge",
45 .brightness_set = spitzled_amber_set,
46};
47
48static struct led_classdev spitz_green_led = {
49 .name = "spitz:green:hddactivity",
50 .default_trigger = "ide-disk",
51 .brightness_set = spitzled_green_set,
52};
53
54#ifdef CONFIG_PM
55static int spitzled_suspend(struct platform_device *dev, pm_message_t state)
56{
57#ifdef CONFIG_LEDS_TRIGGERS
58 if (spitz_amber_led.trigger &&
59 strcmp(spitz_amber_led.trigger->name, "sharpsl-charge"))
60#endif
61 led_classdev_suspend(&spitz_amber_led);
62 led_classdev_suspend(&spitz_green_led);
63 return 0;
64}
65
66static int spitzled_resume(struct platform_device *dev)
67{
68 led_classdev_resume(&spitz_amber_led);
69 led_classdev_resume(&spitz_green_led);
70 return 0;
71}
72#endif
73
74static int spitzled_probe(struct platform_device *pdev)
75{
76 int ret;
77
78 if (machine_is_akita()) {
79 spitz_green_led.name = "spitz:green:mail";
80 spitz_green_led.default_trigger = "nand-disk";
81 }
82
83 ret = led_classdev_register(&pdev->dev, &spitz_amber_led);
84 if (ret < 0)
85 return ret;
86
87 ret = led_classdev_register(&pdev->dev, &spitz_green_led);
88 if (ret < 0)
89 led_classdev_unregister(&spitz_amber_led);
90
91 return ret;
92}
93
94static int spitzled_remove(struct platform_device *pdev)
95{
96 led_classdev_unregister(&spitz_amber_led);
97 led_classdev_unregister(&spitz_green_led);
98
99 return 0;
100}
101
102static struct platform_driver spitzled_driver = {
103 .probe = spitzled_probe,
104 .remove = spitzled_remove,
105#ifdef CONFIG_PM
106 .suspend = spitzled_suspend,
107 .resume = spitzled_resume,
108#endif
109 .driver = {
110 .name = "spitz-led",
111 .owner = THIS_MODULE,
112 },
113};
114
115static int __init spitzled_init(void)
116{
117 return platform_driver_register(&spitzled_driver);
118}
119
120static void __exit spitzled_exit(void)
121{
122 platform_driver_unregister(&spitzled_driver);
123}
124
125module_init(spitzled_init);
126module_exit(spitzled_exit);
127
128MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
129MODULE_DESCRIPTION("Spitz LED driver");
130MODULE_LICENSE("GPL");
131MODULE_ALIAS("platform:spitz-led");
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644
index 000000000000..6b008f0c3f62
--- /dev/null
+++ b/drivers/leds/leds-sunfire.c
@@ -0,0 +1,273 @@
1/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
2 *
3 * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/leds.h>
10#include <linux/io.h>
11#include <linux/platform_device.h>
12
13#include <asm/fhc.h>
14#include <asm/upa.h>
15
16#define DRIVER_NAME "leds-sunfire"
17#define PFX DRIVER_NAME ": "
18
19MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
20MODULE_DESCRIPTION("Sun Fire LED driver");
21MODULE_LICENSE("GPL");
22
23struct sunfire_led {
24 struct led_classdev led_cdev;
25 void __iomem *reg;
26};
27#define to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
28
29static void __clockboard_set(struct led_classdev *led_cdev,
30 enum led_brightness led_val, u8 bit)
31{
32 struct sunfire_led *p = to_sunfire_led(led_cdev);
33 u8 reg = upa_readb(p->reg);
34
35 switch (bit) {
36 case CLOCK_CTRL_LLED:
37 if (led_val)
38 reg &= ~bit;
39 else
40 reg |= bit;
41 break;
42
43 default:
44 if (led_val)
45 reg |= bit;
46 else
47 reg &= ~bit;
48 break;
49 }
50 upa_writeb(reg, p->reg);
51}
52
53static void clockboard_left_set(struct led_classdev *led_cdev,
54 enum led_brightness led_val)
55{
56 __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED);
57}
58
59static void clockboard_middle_set(struct led_classdev *led_cdev,
60 enum led_brightness led_val)
61{
62 __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED);
63}
64
65static void clockboard_right_set(struct led_classdev *led_cdev,
66 enum led_brightness led_val)
67{
68 __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED);
69}
70
71static void __fhc_set(struct led_classdev *led_cdev,
72 enum led_brightness led_val, u32 bit)
73{
74 struct sunfire_led *p = to_sunfire_led(led_cdev);
75 u32 reg = upa_readl(p->reg);
76
77 switch (bit) {
78 case FHC_CONTROL_LLED:
79 if (led_val)
80 reg &= ~bit;
81 else
82 reg |= bit;
83 break;
84
85 default:
86 if (led_val)
87 reg |= bit;
88 else
89 reg &= ~bit;
90 break;
91 }
92 upa_writel(reg, p->reg);
93}
94
95static void fhc_left_set(struct led_classdev *led_cdev,
96 enum led_brightness led_val)
97{
98 __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED);
99}
100
101static void fhc_middle_set(struct led_classdev *led_cdev,
102 enum led_brightness led_val)
103{
104 __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED);
105}
106
107static void fhc_right_set(struct led_classdev *led_cdev,
108 enum led_brightness led_val)
109{
110 __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED);
111}
112
113typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
114struct led_type {
115 const char *name;
116 set_handler handler;
117 const char *default_trigger;
118};
119
120#define NUM_LEDS_PER_BOARD 3
121struct sunfire_drvdata {
122 struct sunfire_led leds[NUM_LEDS_PER_BOARD];
123};
124
125static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
126 struct led_type *types)
127{
128 struct sunfire_drvdata *p;
129 int i, err = -EINVAL;
130
131 if (pdev->num_resources != 1) {
132 printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
133 pdev->num_resources);
134 goto out;
135 }
136
137 p = kzalloc(sizeof(*p), GFP_KERNEL);
138 if (!p) {
139 printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
140 goto out;
141 }
142
143 for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
144 struct led_classdev *lp = &p->leds[i].led_cdev;
145
146 p->leds[i].reg = (void __iomem *) pdev->resource[0].start;
147 lp->name = types[i].name;
148 lp->brightness = LED_FULL;
149 lp->brightness_set = types[i].handler;
150 lp->default_trigger = types[i].default_trigger;
151
152 err = led_classdev_register(&pdev->dev, lp);
153 if (err) {
154 printk(KERN_ERR PFX "Could not register %s LED\n",
155 lp->name);
156 goto out_unregister_led_cdevs;
157 }
158 }
159
160 dev_set_drvdata(&pdev->dev, p);
161
162 err = 0;
163out:
164 return err;
165
166out_unregister_led_cdevs:
167 for (i--; i >= 0; i--)
168 led_classdev_unregister(&p->leds[i].led_cdev);
169 goto out;
170}
171
172static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
173{
174 struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
175 int i;
176
177 for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
178 led_classdev_unregister(&p->leds[i].led_cdev);
179
180 kfree(p);
181
182 return 0;
183}
184
185static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
186 {
187 .name = "clockboard-left",
188 .handler = clockboard_left_set,
189 },
190 {
191 .name = "clockboard-middle",
192 .handler = clockboard_middle_set,
193 },
194 {
195 .name = "clockboard-right",
196 .handler = clockboard_right_set,
197 .default_trigger= "heartbeat",
198 },
199};
200
201static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
202{
203 return sunfire_led_generic_probe(pdev, clockboard_led_types);
204}
205
206static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
207 {
208 .name = "fhc-left",
209 .handler = fhc_left_set,
210 },
211 {
212 .name = "fhc-middle",
213 .handler = fhc_middle_set,
214 },
215 {
216 .name = "fhc-right",
217 .handler = fhc_right_set,
218 .default_trigger= "heartbeat",
219 },
220};
221
222static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
223{
224 return sunfire_led_generic_probe(pdev, fhc_led_types);
225}
226
227MODULE_ALIAS("platform:sunfire-clockboard-leds");
228MODULE_ALIAS("platform:sunfire-fhc-leds");
229
230static struct platform_driver sunfire_clockboard_led_driver = {
231 .probe = sunfire_clockboard_led_probe,
232 .remove = __devexit_p(sunfire_led_generic_remove),
233 .driver = {
234 .name = "sunfire-clockboard-leds",
235 .owner = THIS_MODULE,
236 },
237};
238
239static struct platform_driver sunfire_fhc_led_driver = {
240 .probe = sunfire_fhc_led_probe,
241 .remove = __devexit_p(sunfire_led_generic_remove),
242 .driver = {
243 .name = "sunfire-fhc-leds",
244 .owner = THIS_MODULE,
245 },
246};
247
248static int __init sunfire_leds_init(void)
249{
250 int err = platform_driver_register(&sunfire_clockboard_led_driver);
251
252 if (err) {
253 printk(KERN_ERR PFX "Could not register clock board LED driver\n");
254 return err;
255 }
256
257 err = platform_driver_register(&sunfire_fhc_led_driver);
258 if (err) {
259 printk(KERN_ERR PFX "Could not register FHC LED driver\n");
260 platform_driver_unregister(&sunfire_clockboard_led_driver);
261 }
262
263 return err;
264}
265
266static void __exit sunfire_leds_exit(void)
267{
268 platform_driver_unregister(&sunfire_clockboard_led_driver);
269 platform_driver_unregister(&sunfire_fhc_led_driver);
270}
271
272module_init(sunfire_leds_init);
273module_exit(sunfire_leds_exit);
diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c
index 7ac61a7b56ad..2f3aa87f2a1f 100644
--- a/drivers/leds/leds-wrap.c
+++ b/drivers/leds/leds-wrap.c
@@ -53,8 +53,9 @@ static void wrap_extra_led_set(struct led_classdev *led_cdev,
53} 53}
54 54
55static struct led_classdev wrap_power_led = { 55static struct led_classdev wrap_power_led = {
56 .name = "wrap::power", 56 .name = "wrap::power",
57 .brightness_set = wrap_power_led_set, 57 .brightness_set = wrap_power_led_set,
58 .default_trigger = "default-on",
58}; 59};
59 60
60static struct led_classdev wrap_error_led = { 61static struct led_classdev wrap_error_led = {
diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c
new file mode 100644
index 000000000000..d3dfcfb417b8
--- /dev/null
+++ b/drivers/leds/ledtrig-backlight.c
@@ -0,0 +1,110 @@
1/*
2 * Backlight emulation LED trigger
3 *
4 * Copyright 2008 (C) Rodolfo Giometti <giometti@linux.it>
5 * Copyright 2008 (C) Eurotech S.p.A. <info@eurotech.it>
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
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/fb.h>
17#include <linux/leds.h>
18#include "leds.h"
19
20#define BLANK 1
21#define UNBLANK 0
22
23struct bl_trig_notifier {
24 struct led_classdev *led;
25 int brightness;
26 int old_status;
27 struct notifier_block notifier;
28};
29
30static int fb_notifier_callback(struct notifier_block *p,
31 unsigned long event, void *data)
32{
33 struct bl_trig_notifier *n = container_of(p,
34 struct bl_trig_notifier, notifier);
35 struct led_classdev *led = n->led;
36 struct fb_event *fb_event = data;
37 int *blank = fb_event->data;
38
39 switch (event) {
40 case FB_EVENT_BLANK :
41 if (*blank && n->old_status == UNBLANK) {
42 n->brightness = led->brightness;
43 led_set_brightness(led, LED_OFF);
44 n->old_status = BLANK;
45 } else if (!*blank && n->old_status == BLANK) {
46 led_set_brightness(led, n->brightness);
47 n->old_status = UNBLANK;
48 }
49 break;
50 }
51
52 return 0;
53}
54
55static void bl_trig_activate(struct led_classdev *led)
56{
57 int ret;
58
59 struct bl_trig_notifier *n;
60
61 n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
62 led->trigger_data = n;
63 if (!n) {
64 dev_err(led->dev, "unable to allocate backlight trigger\n");
65 return;
66 }
67
68 n->led = led;
69 n->brightness = led->brightness;
70 n->old_status = UNBLANK;
71 n->notifier.notifier_call = fb_notifier_callback;
72
73 ret = fb_register_client(&n->notifier);
74 if (ret)
75 dev_err(led->dev, "unable to register backlight trigger\n");
76}
77
78static void bl_trig_deactivate(struct led_classdev *led)
79{
80 struct bl_trig_notifier *n =
81 (struct bl_trig_notifier *) led->trigger_data;
82
83 if (n) {
84 fb_unregister_client(&n->notifier);
85 kfree(n);
86 }
87}
88
89static struct led_trigger bl_led_trigger = {
90 .name = "backlight",
91 .activate = bl_trig_activate,
92 .deactivate = bl_trig_deactivate
93};
94
95static int __init bl_trig_init(void)
96{
97 return led_trigger_register(&bl_led_trigger);
98}
99
100static void __exit bl_trig_exit(void)
101{
102 led_trigger_unregister(&bl_led_trigger);
103}
104
105module_init(bl_trig_init);
106module_exit(bl_trig_exit);
107
108MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
109MODULE_DESCRIPTION("Backlight emulation LED trigger");
110MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 5c99f4f0c692..db681962d7bb 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -70,9 +70,7 @@ static ssize_t led_delay_on_show(struct device *dev,
70 struct led_classdev *led_cdev = dev_get_drvdata(dev); 70 struct led_classdev *led_cdev = dev_get_drvdata(dev);
71 struct timer_trig_data *timer_data = led_cdev->trigger_data; 71 struct timer_trig_data *timer_data = led_cdev->trigger_data;
72 72
73 sprintf(buf, "%lu\n", timer_data->delay_on); 73 return sprintf(buf, "%lu\n", timer_data->delay_on);
74
75 return strlen(buf) + 1;
76} 74}
77 75
78static ssize_t led_delay_on_store(struct device *dev, 76static ssize_t led_delay_on_store(struct device *dev,
@@ -116,9 +114,7 @@ static ssize_t led_delay_off_show(struct device *dev,
116 struct led_classdev *led_cdev = dev_get_drvdata(dev); 114 struct led_classdev *led_cdev = dev_get_drvdata(dev);
117 struct timer_trig_data *timer_data = led_cdev->trigger_data; 115 struct timer_trig_data *timer_data = led_cdev->trigger_data;
118 116
119 sprintf(buf, "%lu\n", timer_data->delay_off); 117 return sprintf(buf, "%lu\n", timer_data->delay_off);
120
121 return strlen(buf) + 1;
122} 118}
123 119
124static ssize_t led_delay_off_store(struct device *dev, 120static ssize_t led_delay_off_store(struct device *dev,