aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds
diff options
context:
space:
mode:
authorMaximilian Güntner <maximilian.guentner@gmail.com>2013-10-16 21:09:17 -0400
committerBryan Wu <cooloney@gmail.com>2013-10-22 13:57:35 -0400
commitbb6febdc90efe7f664328075c204eed8e9af7ec9 (patch)
tree51ecf9e4ac1f0a3af243799d3b40078bc1f3eab3 /drivers/leds
parent1e08f72dd248645450b01c86ccc066c0a90767d8 (diff)
leds: Added driver for the NXP PCA9685 I2C chip
The NXP PCA9685 supports 16 channels/leds using a 12-bit PWM (4095 levels of brightness) This driver supports configuration using platform_data. Signed-off-by: Maximilian Güntner <maximilian.guentner@gmail.com> Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-pca9685.c213
3 files changed, 224 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 875bbe4c962e..72156c123033 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -300,6 +300,16 @@ config LEDS_PCA963X
300 LED driver chip accessed via the I2C bus. Supported 300 LED driver chip accessed via the I2C bus. Supported
301 devices include PCA9633 and PCA9634 301 devices include PCA9633 and PCA9634
302 302
303config LEDS_PCA9685
304 tristate "LED support for PCA9685 I2C chip"
305 depends on LEDS_CLASS
306 depends on I2C
307 help
308 This option enables support for LEDs connected to the PCA9685
309 LED driver chip accessed via the I2C bus.
310 The PCA9685 offers 12-bit PWM (4095 levels of brightness) on
311 16 individual channels.
312
303config LEDS_WM831X_STATUS 313config LEDS_WM831X_STATUS
304 tristate "LED support for status LEDs on WM831x PMICs" 314 tristate "LED support for status LEDs on WM831x PMICs"
305 depends on LEDS_CLASS 315 depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 8979b0b2c85e..3cd76dbd9be2 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o
36obj-$(CONFIG_LEDS_FSG) += leds-fsg.o 36obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
37obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o 37obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
38obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o 38obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o
39obj-$(CONFIG_LEDS_PCA9685) += leds-pca9685.o
39obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o 40obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
40obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o 41obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o
41obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o 42obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
diff --git a/drivers/leds/leds-pca9685.c b/drivers/leds/leds-pca9685.c
new file mode 100644
index 000000000000..6e1ef3a9d6ef
--- /dev/null
+++ b/drivers/leds/leds-pca9685.c
@@ -0,0 +1,213 @@
1/*
2 * Copyright 2013 Maximilian Güntner <maximilian.guentner@gmail.com>
3 *
4 * This file is subject to the terms and conditions of version 2 of
5 * the GNU General Public License. See the file COPYING in the main
6 * directory of this archive for more details.
7 *
8 * Based on leds-pca963x.c driver by
9 * Peter Meerwald <p.meerwald@bct-electronic.com>
10 *
11 * Driver for the NXP PCA9685 12-Bit PWM LED driver chip.
12 *
13 */
14
15#include <linux/ctype.h>
16#include <linux/delay.h>
17#include <linux/err.h>
18#include <linux/i2c.h>
19#include <linux/leds.h>
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <linux/workqueue.h>
24
25#include <linux/platform_data/leds-pca9685.h>
26
27/* Register Addresses */
28#define PCA9685_MODE1 0x00
29#define PCA9685_MODE2 0x01
30#define PCA9685_LED0_ON_L 0x06
31#define PCA9685_ALL_LED_ON_L 0xFA
32
33/* MODE1 Register */
34#define PCA9685_ALLCALL 0x00
35#define PCA9685_SLEEP 0x04
36#define PCA9685_AI 0x05
37
38/* MODE2 Register */
39#define PCA9685_INVRT 0x04
40#define PCA9685_OUTDRV 0x02
41
42static const struct i2c_device_id pca9685_id[] = {
43 { "pca9685", 0 },
44 { }
45};
46MODULE_DEVICE_TABLE(i2c, pca9685_id);
47
48struct pca9685_led {
49 struct i2c_client *client;
50 struct work_struct work;
51 u16 brightness;
52 struct led_classdev led_cdev;
53 int led_num; /* 0-15 */
54 char name[32];
55};
56
57static void pca9685_write_msg(struct i2c_client *client, u8 *buf, u8 len)
58{
59 struct i2c_msg msg = {
60 .addr = client->addr,
61 .flags = 0x00,
62 .len = len,
63 .buf = buf
64 };
65 i2c_transfer(client->adapter, &msg, 1);
66}
67
68static void pca9685_all_off(struct i2c_client *client)
69{
70 u8 i2c_buffer[5] = {PCA9685_ALL_LED_ON_L, 0x00, 0x00, 0x00, 0x10};
71 pca9685_write_msg(client, i2c_buffer, 5);
72}
73
74static void pca9685_led_work(struct work_struct *work)
75{
76 struct pca9685_led *pca9685;
77 u8 i2c_buffer[5];
78
79 pca9685 = container_of(work, struct pca9685_led, work);
80 i2c_buffer[0] = PCA9685_LED0_ON_L + 4 * pca9685->led_num;
81 /*
82 * 4095 is the maximum brightness, so we set the ON time to 0x1000
83 * which disables the PWM generator for that LED
84 */
85 if (pca9685->brightness == 4095)
86 *((__le16 *)(i2c_buffer+1)) = cpu_to_le16(0x1000);
87 else
88 *((__le16 *)(i2c_buffer+1)) = 0x0000;
89
90 if (pca9685->brightness == 0)
91 *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(0x1000);
92 else if (pca9685->brightness == 4095)
93 *((__le16 *)(i2c_buffer+3)) = 0x0000;
94 else
95 *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(pca9685->brightness);
96
97 pca9685_write_msg(pca9685->client, i2c_buffer, 5);
98}
99
100static void pca9685_led_set(struct led_classdev *led_cdev,
101 enum led_brightness value)
102{
103 struct pca9685_led *pca9685;
104 pca9685 = container_of(led_cdev, struct pca9685_led, led_cdev);
105 pca9685->brightness = value;
106
107 schedule_work(&pca9685->work);
108}
109
110static int pca9685_probe(struct i2c_client *client,
111 const struct i2c_device_id *id)
112{
113 struct pca9685_led *pca9685;
114 struct pca9685_platform_data *pdata;
115 int err;
116 u8 i;
117
118 pdata = dev_get_platdata(&client->dev);
119 if (pdata) {
120 if (pdata->leds.num_leds < 1 || pdata->leds.num_leds > 15) {
121 dev_err(&client->dev, "board info must claim 1-16 LEDs");
122 return -EINVAL;
123 }
124 }
125
126 pca9685 = devm_kzalloc(&client->dev, 16 * sizeof(*pca9685), GFP_KERNEL);
127 if (!pca9685)
128 return -ENOMEM;
129
130 i2c_set_clientdata(client, pca9685);
131 pca9685_all_off(client);
132
133 for (i = 0; i < 16; i++) {
134 pca9685[i].client = client;
135 pca9685[i].led_num = i;
136 pca9685[i].name[0] = '\0';
137 if (pdata && i < pdata->leds.num_leds) {
138 if (pdata->leds.leds[i].name)
139 strncpy(pca9685[i].name,
140 pdata->leds.leds[i].name,
141 sizeof(pca9685[i].name)-1);
142 if (pdata->leds.leds[i].default_trigger)
143 pca9685[i].led_cdev.default_trigger =
144 pdata->leds.leds[i].default_trigger;
145 }
146 if (strlen(pca9685[i].name) == 0) {
147 /*
148 * Write adapter and address to the name as well.
149 * Otherwise multiple chips attached to one host would
150 * not work.
151 */
152 snprintf(pca9685[i].name, sizeof(pca9685[i].name),
153 "pca9685:%d:x%.2x:%d",
154 client->adapter->nr, client->addr, i);
155 }
156 pca9685[i].led_cdev.name = pca9685[i].name;
157 pca9685[i].led_cdev.max_brightness = 0xfff;
158 pca9685[i].led_cdev.brightness_set = pca9685_led_set;
159
160 INIT_WORK(&pca9685[i].work, pca9685_led_work);
161 err = led_classdev_register(&client->dev, &pca9685[i].led_cdev);
162 if (err < 0)
163 goto exit;
164 }
165
166 if (pdata)
167 i2c_smbus_write_byte_data(client, PCA9685_MODE2,
168 pdata->outdrv << PCA9685_OUTDRV |
169 pdata->inverted << PCA9685_INVRT);
170 else
171 i2c_smbus_write_byte_data(client, PCA9685_MODE2,
172 PCA9685_TOTEM_POLE << PCA9685_OUTDRV);
173 /* Enable Auto-Increment, enable oscillator, ALLCALL/SUBADDR disabled */
174 i2c_smbus_write_byte_data(client, PCA9685_MODE1, BIT(PCA9685_AI));
175
176 return 0;
177
178exit:
179 while (i--) {
180 led_classdev_unregister(&pca9685[i].led_cdev);
181 cancel_work_sync(&pca9685[i].work);
182 }
183 return err;
184}
185
186static int pca9685_remove(struct i2c_client *client)
187{
188 struct pca9685_led *pca9685 = i2c_get_clientdata(client);
189 u8 i;
190
191 for (i = 0; i < 16; i++) {
192 led_classdev_unregister(&pca9685[i].led_cdev);
193 cancel_work_sync(&pca9685[i].work);
194 }
195 pca9685_all_off(client);
196 return 0;
197}
198
199static struct i2c_driver pca9685_driver = {
200 .driver = {
201 .name = "leds-pca9685",
202 .owner = THIS_MODULE,
203 },
204 .probe = pca9685_probe,
205 .remove = pca9685_remove,
206 .id_table = pca9685_id,
207};
208
209module_i2c_driver(pca9685_driver);
210
211MODULE_AUTHOR("Maximilian Güntner <maximilian.guentner@gmail.com>");
212MODULE_DESCRIPTION("PCA9685 LED Driver");
213MODULE_LICENSE("GPL v2");