aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPeter Meerwald <p.meerwald@bct-electronic.com>2012-03-23 18:02:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-23 19:58:35 -0400
commit75cb2e1d1a53e732ebc81e7c4fa781aa8d7a9619 (patch)
treecd2b0edb7792f8b0bb0adbdc1b121b853f4e5d1d /drivers
parentd06cb46c3e59e4f212bc7b86720a073a1aee1f63 (diff)
drivers/leds: add driver for PCA9633 I2C chip
Driver for the PCA9633 I2C chip supporting four LEDs and 255 brightness levels. [akpm@linux-foundation.org: fix kcalloc() call] [axel.lin@gmail.com: fix kcalloc parameters swapped] Signed-off-by: Peter Meerwald <p.meerwald@bct-electronic.com> Signed-off-by: Axel Lin <axel.lin@gmail.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-pca9633.c195
3 files changed, 204 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 8c7a75d53101..e2ac190df528 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -234,6 +234,14 @@ config LEDS_PCA955X
234 LED driver chips accessed via the I2C bus. Supported 234 LED driver chips accessed via the I2C bus. Supported
235 devices include PCA9550, PCA9551, PCA9552, and PCA9553. 235 devices include PCA9550, PCA9551, PCA9552, and PCA9553.
236 236
237config LEDS_PCA9633
238 tristate "LED support for PCA9633 I2C chip"
239 depends on LEDS_CLASS
240 depends on I2C
241 help
242 This option enables support for LEDs connected to the PCA9633
243 LED driver chip accessed via the I2C bus.
244
237config LEDS_WM831X_STATUS 245config LEDS_WM831X_STATUS
238 tristate "LED support for status LEDs on WM831x PMICs" 246 tristate "LED support for status LEDs on WM831x PMICs"
239 depends on LEDS_CLASS 247 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 6bcf4f695515..fa0f428b32fe 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
30obj-$(CONFIG_LEDS_OT200) += leds-ot200.o 30obj-$(CONFIG_LEDS_OT200) += leds-ot200.o
31obj-$(CONFIG_LEDS_FSG) += leds-fsg.o 31obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
32obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o 32obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
33obj-$(CONFIG_LEDS_PCA9633) += leds-pca9633.o
33obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o 34obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
34obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o 35obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
35obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o 36obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
new file mode 100644
index 000000000000..80cb61adc2d6
--- /dev/null
+++ b/drivers/leds/leds-pca9633.c
@@ -0,0 +1,195 @@
1/*
2 * Copyright 2011 bct electronic GmbH
3 *
4 * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
5 *
6 * Based on leds-pca955x.c
7 *
8 * This file is subject to the terms and conditions of version 2 of
9 * the GNU General Public License. See the file COPYING in the main
10 * directory of this archive for more details.
11 *
12 * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/string.h>
19#include <linux/ctype.h>
20#include <linux/leds.h>
21#include <linux/err.h>
22#include <linux/i2c.h>
23#include <linux/workqueue.h>
24#include <linux/slab.h>
25
26/* LED select registers determine the source that drives LED outputs */
27#define PCA9633_LED_OFF 0x0 /* LED driver off */
28#define PCA9633_LED_ON 0x1 /* LED driver on */
29#define PCA9633_LED_PWM 0x2 /* Controlled through PWM */
30#define PCA9633_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
31
32#define PCA9633_MODE1 0x00
33#define PCA9633_MODE2 0x01
34#define PCA9633_PWM_BASE 0x02
35#define PCA9633_LEDOUT 0x08
36
37static const struct i2c_device_id pca9633_id[] = {
38 { "pca9633", 0 },
39 { }
40};
41MODULE_DEVICE_TABLE(i2c, pca9633_id);
42
43struct pca9633_led {
44 struct i2c_client *client;
45 struct work_struct work;
46 enum led_brightness brightness;
47 struct led_classdev led_cdev;
48 int led_num; /* 0 .. 3 potentially */
49 char name[32];
50};
51
52static void pca9633_led_work(struct work_struct *work)
53{
54 struct pca9633_led *pca9633 = container_of(work,
55 struct pca9633_led, work);
56 u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
57 int shift = 2 * pca9633->led_num;
58 u8 mask = 0x3 << shift;
59
60 switch (pca9633->brightness) {
61 case LED_FULL:
62 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
63 (ledout & ~mask) | (PCA9633_LED_ON << shift));
64 break;
65 case LED_OFF:
66 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
67 ledout & ~mask);
68 break;
69 default:
70 i2c_smbus_write_byte_data(pca9633->client,
71 PCA9633_PWM_BASE + pca9633->led_num,
72 pca9633->brightness);
73 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
74 (ledout & ~mask) | (PCA9633_LED_PWM << shift));
75 break;
76 }
77}
78
79static void pca9633_led_set(struct led_classdev *led_cdev,
80 enum led_brightness value)
81{
82 struct pca9633_led *pca9633;
83
84 pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
85
86 pca9633->brightness = value;
87
88 /*
89 * Must use workqueue for the actual I/O since I2C operations
90 * can sleep.
91 */
92 schedule_work(&pca9633->work);
93}
94
95static int __devinit pca9633_probe(struct i2c_client *client,
96 const struct i2c_device_id *id)
97{
98 struct pca9633_led *pca9633;
99 struct i2c_adapter *adapter;
100 struct led_platform_data *pdata;
101 int i, err;
102
103 adapter = to_i2c_adapter(client->dev.parent);
104 pdata = client->dev.platform_data;
105
106 if (pdata) {
107 if (pdata->num_leds <= 0 || pdata->num_leds > 4) {
108 dev_err(&client->dev, "board info must claim at most 4 LEDs");
109 return -EINVAL;
110 }
111 }
112
113 pca9633 = kcalloc(4, sizeof(*pca9633), GFP_KERNEL);
114 if (!pca9633)
115 return -ENOMEM;
116
117 i2c_set_clientdata(client, pca9633);
118
119 for (i = 0; i < 4; i++) {
120 pca9633[i].client = client;
121 pca9633[i].led_num = i;
122
123 /* Platform data can specify LED names and default triggers */
124 if (pdata && i < pdata->num_leds) {
125 if (pdata->leds[i].name)
126 snprintf(pca9633[i].name,
127 sizeof(pca9633[i].name), "pca9633:%s",
128 pdata->leds[i].name);
129 if (pdata->leds[i].default_trigger)
130 pca9633[i].led_cdev.default_trigger =
131 pdata->leds[i].default_trigger;
132 } else {
133 snprintf(pca9633[i].name, sizeof(pca9633[i].name),
134 "pca9633:%d", i);
135 }
136
137 pca9633[i].led_cdev.name = pca9633[i].name;
138 pca9633[i].led_cdev.brightness_set = pca9633_led_set;
139
140 INIT_WORK(&pca9633[i].work, pca9633_led_work);
141
142 err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
143 if (err < 0)
144 goto exit;
145 }
146
147 /* Disable LED all-call address and set normal mode */
148 i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
149
150 /* Turn off LEDs */
151 i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
152
153 return 0;
154
155exit:
156 while (i--) {
157 led_classdev_unregister(&pca9633[i].led_cdev);
158 cancel_work_sync(&pca9633[i].work);
159 }
160
161 kfree(pca9633);
162
163 return err;
164}
165
166static int __devexit pca9633_remove(struct i2c_client *client)
167{
168 struct pca9633_led *pca9633 = i2c_get_clientdata(client);
169 int i;
170
171 for (i = 0; i < 4; i++) {
172 led_classdev_unregister(&pca9633[i].led_cdev);
173 cancel_work_sync(&pca9633[i].work);
174 }
175
176 kfree(pca9633);
177
178 return 0;
179}
180
181static struct i2c_driver pca9633_driver = {
182 .driver = {
183 .name = "leds-pca9633",
184 .owner = THIS_MODULE,
185 },
186 .probe = pca9633_probe,
187 .remove = __devexit_p(pca9633_remove),
188 .id_table = pca9633_id,
189};
190
191module_i2c_driver(pca9633_driver);
192
193MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
194MODULE_DESCRIPTION("PCA9633 LED driver");
195MODULE_LICENSE("GPL v2");