preliminary support for the WRT1900AC (work in progress)
[openwrt/openwrt.git] / target / linux / mvebu / patches-3.14 / 003-add_leds_tlc59116_driver.patch
1 --- a/drivers/leds/Kconfig
2 +++ b/drivers/leds/Kconfig
3 @@ -487,6 +487,15 @@ config LEDS_BLINKM
4 This option enables support for the BlinkM RGB LED connected
5 through I2C. Say Y to enable support for the BlinkM LED.
6
7 +config LEDS_TLC59116
8 + tristate "LED driver for TLC59116F dimmer"
9 + depends on LEDS_CLASS
10 + depends on I2C
11 + help
12 + This option enables support for Texas Instruments TLC59116F
13 + LED controller. It is generally only useful
14 + as a platform driver
15 +
16 comment "LED Triggers"
17 source "drivers/leds/trigger/Kconfig"
18
19 --- a/drivers/leds/Makefile
20 +++ b/drivers/leds/Makefile
21 @@ -54,6 +54,7 @@ obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.
22 obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
23 obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
24 obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
25 +obj-$(CONFIG_LEDS_TLC59116) += leds-tlc59116.o
26
27 # LED SPI Drivers
28 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
29 --- /dev/null
30 +++ b/drivers/leds/leds-tlc59116.c
31 @@ -0,0 +1,498 @@
32 +/*
33 + * Copyright 2014 Belkin Inc.
34 + *
35 + * Author: Belkin Inc.
36 + *
37 + * This file is subject to the terms and conditions of version 2 of
38 + * the GNU General Public License. See the file COPYING in the main
39 + * directory of this archive for more details.
40 + *
41 + * LED driver for various TLC59116 I2C LED drivers
42 + */
43 +
44 +#include <linux/module.h>
45 +#include <linux/delay.h>
46 +#include <linux/string.h>
47 +#include <linux/ctype.h>
48 +#include <linux/leds.h>
49 +#include <linux/err.h>
50 +#include <linux/i2c.h>
51 +#include <linux/workqueue.h>
52 +
53 +/* LED select registers determine the source that drives LED outputs */
54 +#define TLC59116_LED_OFF 0x0 /* Output LOW */
55 +#define TLC59116_LED_ON 0x1 /* Output HI-Z */
56 +#define TLC59116_DIM 0x2 /* Dimming */
57 +#define TLC59116_BLINK 0x3 /* Blinking */
58 +
59 +#define TLC59116_PINS 16
60 +#define TLC59116_REG_MODE1 0x00 /* Mode register 0 */
61 +#define MODE1_RESPON_ADDR_MASK 0xF0
62 +#define MODE1_NORMAL_MODE (0 << 4)
63 +#define MODE1_SPEED_MODE (1 << 4)
64 +
65 +#define TLC59116_REG_MODE2 0x01 /* Mode register 1 */
66 +#define MODE2_DIM (0 << 5)
67 +#define MODE2_BLINK (1 << 5)
68 +#define MODE2_OCH_STOP (0 << 3)
69 +#define MODE2_OCH_ACK (1 << 3)
70 +
71 +#define TLC59116_REG_PWM0 0x02
72 +#define TLC59116_REG_PWM1 0x03
73 +#define TLC59116_REG_PWM2 0x04
74 +#define TLC59116_REG_PWM3 0x05
75 +#define TLC59116_REG_PWM4 0x06
76 +#define TLC59116_REG_PWM5 0x07
77 +#define TLC59116_REG_PWM6 0x08
78 +#define TLC59116_REG_PWM7 0x09
79 +#define TLC59116_REG_PWM8 0x0a
80 +#define TLC59116_REG_PWM9 0x0b
81 +#define TLC59116_REG_PWM10 0x0c
82 +#define TLC59116_REG_PWM11 0x0d
83 +#define TLC59116_REG_PWM12 0x0e
84 +#define TLC59116_REG_PWM13 0x0f
85 +#define TLC59116_REG_PWM14 0x10
86 +#define TLC59116_REG_PWM15 0x01
87 +
88 +#define TLC59116_REG_GRPPWM 0x12
89 +#define TLC59116_REG_GRPFREQ 0x13
90 +
91 +#define TLC59116_PERIOD_MIN 41 /* 41ms */
92 +#define TLC59116_PERIOD_MAX 10730 /* 10.73s */
93 +
94 +#define TLC59116_REG_LEDOUT0 0x14 /* LED [3:0] driver output state registers */
95 +#define TLC59116_REG_LEDOUT1 0x15 /* LED [7:4] driver output state registers */
96 +#define TLC59116_REG_LEDOUT2 0x16 /* LED [11:8] driver output state registers */
97 +#define TLC59116_REG_LEDOUT3 0x17 /* LED [15:12] driver output state registers */
98 +
99 +#define GPIO0_MASK 0x3
100 +
101 +#define DEBUG 0
102 +
103 +#if DEBUG > 1
104 +#define led_dbg(fmt, arg...) printk(KERN_DEBUG "tlc59116:%s " fmt "\n", __func__ , ## arg)
105 +#else
106 +#define led_dbg(fmt, arg...)
107 +#endif
108 +
109 +
110 +#if DEBUG > 0
111 +#define led_info(fmt, arg...) printk("tlc59116:%s " fmt "\n", __func__ , ## arg)
112 +#else
113 +#define led_info(fmt, arg...)
114 +#endif
115 +
116 +enum tlc59116_type {
117 + tlc59116,
118 +};
119 +
120 +struct tlc59116_chipdef {
121 + int bits;
122 + u8 slv_addr; /* 7-bit slave address mask */
123 + int slv_addr_shift; /* Number of bits to ignore */
124 +};
125 +
126 +static struct tlc59116_chipdef tlc59116_chipdefs[] = {
127 + [tlc59116] = {
128 + .bits = 16,
129 + .slv_addr = /* 1100xxx */ 0x68,
130 + .slv_addr_shift = 3,
131 + },
132 +};
133 +
134 +static const struct i2c_device_id tlc59116_id[] = {
135 + { "tlc59116", tlc59116 },
136 + { }
137 +};
138 +MODULE_DEVICE_TABLE(i2c, tlc59116_id);
139 +
140 +struct tlc59116_led {
141 + struct tlc59116_chipdef *chipdef;
142 + struct i2c_client *client;
143 + struct work_struct work;
144 + spinlock_t lock;
145 + enum led_brightness brightness;
146 + struct led_classdev led_cdev;
147 + int led_num; /* 0 .. 8 potentially */
148 + char name[32];
149 +};
150 +
151 +//#define DUMP_REGS
152 +
153 +#ifdef DUMP_REGS
154 +void dump_regs(struct i2c_client *client)
155 +{
156 + int i, j = 0;
157 + u8 data;
158 + printk ("\n-------------------------------------\n");
159 + for (i = 0; i< 0x20; i++)
160 + {
161 + data = i2c_smbus_read_byte_data(client, i);
162 + printk ("[0x%x] = 0x%x ",i, data);
163 + j++;
164 + if (j == 5)
165 + {
166 + printk ("\n");
167 + j = 0;
168 + }
169 + }
170 + printk ("\n");
171 +}
172 +#endif
173 +
174 +static int tlc59116_set_mode(struct i2c_client *client, uint8_t mode)
175 +{
176 + uint8_t val = 0;
177 +
178 + if ((mode != MODE2_DIM) && (mode != MODE2_BLINK))
179 + mode = MODE2_DIM;
180 +
181 + /* Configure MODE1 register */
182 + val &= 0x0;
183 + val &= MODE1_RESPON_ADDR_MASK;
184 + val |= MODE1_NORMAL_MODE;
185 + i2c_smbus_write_byte_data(client, TLC59116_REG_MODE1, val);
186 +
187 + /* Configure MODE2 Reg */
188 + val &= 0x00;
189 + val |= MODE2_OCH_STOP;
190 +
191 + val |= mode;
192 +
193 + i2c_smbus_write_byte_data(client, TLC59116_REG_MODE2, val);
194 + mdelay(100);
195 +
196 + return 0;
197 +}
198 +
199 +static int tlc59116_set_gpio_act(struct i2c_client *client, u8 gpio_no, u8 act_mode)
200 +{
201 + char data, addr = 0, i;
202 +
203 + if ((gpio_no >= 0) && (gpio_no < 4))
204 + addr = TLC59116_REG_LEDOUT0;
205 + else if ((gpio_no >= 4) && (gpio_no < 8))
206 + addr = TLC59116_REG_LEDOUT1;
207 + else if ((gpio_no >= 8) && (gpio_no < 12))
208 + addr = TLC59116_REG_LEDOUT2;
209 + else if ((gpio_no >=12 ) && (gpio_no < 16))
210 + addr = TLC59116_REG_LEDOUT3;
211 +
212 + data = i2c_smbus_read_byte_data(client, addr);
213 +
214 + i = (gpio_no % 4) * 2;
215 +
216 + data &= ~(GPIO0_MASK << i);
217 + act_mode = act_mode << i;
218 + data |= act_mode;
219 +
220 + if(i2c_smbus_write_byte_data(client, addr, data) != 0) {
221 + return -1;
222 + }
223 + return 0;
224 +}
225 +
226 +static int tlc59116_set_gpio(struct i2c_client *client, uint8_t gpio_no, uint8_t val)
227 +{
228 + val &= 0x03;
229 + tlc59116_set_gpio_act(client, gpio_no, val);
230 +#ifdef DUMP_REGS
231 + dump_regs(client);
232 +#endif
233 + return 0;
234 +}
235 +
236 +static int tlc59116_get_gpio(struct i2c_client *client, uint8_t gpio_no)
237 +{
238 + uint8_t val, reg, data;
239 +
240 + led_dbg("gpio = %d\n", gpio_no);
241 + reg = TLC59116_REG_LEDOUT0;
242 +
243 + if ((gpio_no >= 0) && (gpio_no < 4))
244 + reg = TLC59116_REG_LEDOUT0;
245 + else if ((gpio_no >= 4) && (gpio_no < 8)) {
246 + reg = TLC59116_REG_LEDOUT1;
247 + gpio_no = gpio_no - 4;
248 + }
249 + else if ((gpio_no >= 8) && (gpio_no < 12)) {
250 + reg = TLC59116_REG_LEDOUT2;
251 + gpio_no = gpio_no - 8;
252 + }
253 + else if ((gpio_no >=12 ) && (gpio_no < 16)) {
254 + reg = TLC59116_REG_LEDOUT3;
255 + gpio_no = gpio_no - 12;
256 + }
257 +
258 + val = i2c_smbus_read_byte_data(client, reg);
259 +
260 + data = (val >> (gpio_no * 2)) & 0x03;
261 + return data;
262 +}
263 +
264 +/*
265 + * gpio_no [0..7]
266 + * duty_cycle [0..99]%
267 + *
268 + * */
269 +static int tlc59116_individual_brighness_control(struct i2c_client *client, uint8_t gpio_no, uint8_t brightness)
270 +{
271 + uint8_t pwm;
272 +
273 + pwm = gpio_no + TLC59116_REG_PWM0;
274 + i2c_smbus_write_byte_data(client, pwm, brightness);
275 +
276 + return 0;
277 +}
278 +
279 +static void tlc59116_led_work(struct work_struct *work)
280 +{
281 + struct tlc59116_led *tlc59116;
282 +
283 + tlc59116 = container_of(work, struct tlc59116_led, work);
284 +
285 + led_dbg("\nbrighness = %d \n", tlc59116->brightness);
286 + switch (tlc59116->brightness) {
287 + case LED_OFF:
288 + led_info("\nLed off\n");
289 + tlc59116_set_gpio(tlc59116->client, tlc59116->led_num, TLC59116_LED_OFF);
290 + break;
291 +
292 + case LED_FULL:
293 + led_info("\nLed on\n");
294 + tlc59116_set_gpio(tlc59116->client, tlc59116->led_num, TLC59116_LED_ON);
295 + break;
296 + default:
297 + led_info("\nBrightness is %d\n", tlc59116->brightness);
298 + if (TLC59116_BLINK != tlc59116_get_gpio(tlc59116->client, tlc59116->led_num))
299 + tlc59116_set_gpio(tlc59116->client, tlc59116->led_num, TLC59116_DIM);
300 +
301 + tlc59116_individual_brighness_control(tlc59116->client, tlc59116->led_num, tlc59116->brightness);
302 + break;
303 + }
304 +
305 +}
306 +
307 +static void tlc59116_led_set(struct led_classdev *led_cdev, enum led_brightness value)
308 +{
309 + struct tlc59116_led *tlc59116;
310 +
311 + tlc59116 = container_of(led_cdev, struct tlc59116_led, led_cdev);
312 +
313 + spin_lock(&tlc59116->lock);
314 + tlc59116->brightness = value;
315 +
316 + /*
317 + * Must use workqueue for the actual I/O since I2C operations
318 + * can sleep.
319 + */
320 + schedule_work(&tlc59116->work);
321 +
322 + spin_unlock(&tlc59116->lock);
323 +}
324 +
325 +/*
326 + * delay_on, delay_off: units are in ms
327 + *
328 + */
329 +
330 +static int tlc59116_set_blink(struct led_classdev *led_cdev,
331 + unsigned long *delay_on,
332 + unsigned long *delay_off)
333 +{
334 + struct tlc59116_led *tlc59116;
335 + uint16_t period;
336 + uint16_t duty_cycle;
337 + uint8_t gdc;
338 + uint8_t gfrq;
339 +
340 + tlc59116 = container_of(led_cdev, struct tlc59116_led, led_cdev);
341 + led_info ("Blinking: delay_on = %ldms, delay_off = %ldms, brightness = %d\n",
342 + *delay_on, *delay_off, tlc59116->brightness);
343 +
344 + // Hardware blinking only for tricolor leds . The rest will have software blinking
345 + if (tlc59116->led_num > 2)
346 + return 1;
347 +
348 + if ((*delay_on == 0) && (*delay_off ==0)) {
349 + spin_lock(&tlc59116->lock);
350 +
351 + /* MODE2[DMBLNK] = 1 */
352 + tlc59116_set_mode(tlc59116->client, MODE2_BLINK);
353 +
354 + /* Set LDRx = 11 */
355 + tlc59116_set_gpio(tlc59116->client, tlc59116->led_num, TLC59116_BLINK);
356 +
357 + tlc59116_individual_brighness_control(tlc59116->client, tlc59116->led_num, tlc59116->brightness);
358 + spin_unlock(&tlc59116->lock);
359 + return 0;
360 + }
361 +
362 +
363 + if ((*delay_on + *delay_off) > TLC59116_PERIOD_MAX)
364 + {
365 + led_dbg ("Max period is %dms\n", TLC59116_PERIOD_MAX);
366 + return -EINVAL;
367 + }
368 +
369 + if ((*delay_on + *delay_off) < TLC59116_PERIOD_MIN)
370 + {
371 + *delay_on = TLC59116_PERIOD_MIN/2 + 1;
372 + *delay_off = TLC59116_PERIOD_MIN/2 + 1;
373 + }
374 + period = (*delay_on) + (*delay_off);
375 +
376 + duty_cycle = (100 * (*delay_on)) / period;
377 +
378 + spin_lock(&tlc59116->lock);
379 +
380 + /* MODE2[DMBLNK] = 1 */
381 + tlc59116_set_mode(tlc59116->client, MODE2_BLINK);
382 +
383 + /* Set LDRx = 11 */
384 + tlc59116_set_gpio(tlc59116->client, tlc59116->led_num, TLC59116_BLINK);
385 +
386 + tlc59116_individual_brighness_control(tlc59116->client, tlc59116->led_num, tlc59116->brightness);
387 +
388 + gdc = (duty_cycle * 256)/100;
389 + i2c_smbus_write_byte_data(tlc59116->client, TLC59116_REG_GRPPWM, gdc);
390 +
391 + gfrq = (24 * period)/1000 - 1; /* unit is in second (convert from ms to second) */
392 + i2c_smbus_write_byte_data(tlc59116->client, TLC59116_REG_GRPFREQ, gfrq);
393 +
394 +
395 +#ifdef DUMP_REGS
396 + dump_regs(tlc59116->client);
397 +#endif
398 +
399 + spin_unlock(&tlc59116->lock);
400 + return 0;
401 +}
402 +
403 +static int tlc59116_probe(struct i2c_client *client,
404 + const struct i2c_device_id *id)
405 +{
406 + struct tlc59116_led *tlc59116;
407 + struct tlc59116_chipdef *chip;
408 + struct i2c_adapter *adapter;
409 + struct led_platform_data *pdata;
410 + int i, err;
411 +
412 + chip = &tlc59116_chipdefs[id->driver_data];
413 + adapter = to_i2c_adapter(client->dev.parent);
414 + pdata = client->dev.platform_data;
415 +
416 + /* Make sure the slave address / chip type combo given is possible */
417 + if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
418 + chip->slv_addr) {
419 + dev_err(&client->dev, "invalid slave address %02x\n",
420 + client->addr);
421 + return -ENODEV;
422 + }
423 +
424 + printk(KERN_INFO "leds-tlc59116: Using %s %d-bit LED driver at "
425 + "slave address 0x%02x\n",
426 + id->name, chip->bits, client->addr);
427 +
428 + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
429 + return -EIO;
430 +
431 + if (pdata) {
432 + if (pdata->num_leds != chip->bits) {
433 + dev_err(&client->dev, "board info claims %d LEDs"
434 + " on a %d-bit chip\n",
435 + pdata->num_leds, chip->bits);
436 + return -ENODEV;
437 + }
438 + }
439 +
440 + tlc59116 = devm_kzalloc(&client->dev, sizeof(*tlc59116) * chip->bits, GFP_KERNEL);
441 + if (!tlc59116)
442 + return -ENOMEM;
443 +
444 + i2c_set_clientdata(client, tlc59116);
445 +
446 + for (i = 0; i < chip->bits; i++) {
447 + tlc59116[i].chipdef = chip;
448 + tlc59116[i].client = client;
449 + tlc59116[i].led_num = i;
450 +
451 + /* Platform data can specify LED names and default triggers */
452 + if (pdata) {
453 + if (pdata->leds[i].name)
454 + snprintf(tlc59116[i].name,
455 + sizeof(tlc59116[i].name), "tlc59116:%s",
456 + pdata->leds[i].name);
457 + if (pdata->leds[i].default_trigger)
458 + tlc59116[i].led_cdev.default_trigger =
459 + pdata->leds[i].default_trigger;
460 + } else {
461 + snprintf(tlc59116[i].name, sizeof(tlc59116[i].name),
462 + "tlc59116:%d", i);
463 + }
464 +
465 + spin_lock_init(&tlc59116[i].lock);
466 +
467 + tlc59116[i].led_cdev.name = tlc59116[i].name;
468 + tlc59116[i].led_cdev.brightness_set = tlc59116_led_set;
469 + tlc59116[i].led_cdev.blink_set = tlc59116_set_blink;
470 + tlc59116[i].led_cdev.brightness = 0;
471 +
472 + INIT_WORK(&tlc59116[i].work, tlc59116_led_work);
473 +
474 + err = led_classdev_register(&client->dev, &tlc59116[i].led_cdev);
475 + if (err < 0)
476 + goto exit;
477 + }
478 +
479 + tlc59116_set_mode(client, MODE2_DIM);
480 +
481 + /* Turn off LEDs */
482 + for (i = 0; i < chip->bits; i++)
483 + tlc59116_set_gpio(client, i, TLC59116_LED_OFF);
484 +
485 + return 0;
486 +
487 +exit:
488 + while (i--) {
489 + led_classdev_unregister(&tlc59116[i].led_cdev);
490 + cancel_work_sync(&tlc59116[i].work);
491 + }
492 +
493 + devm_kfree(&client->dev, tlc59116);
494 + i2c_set_clientdata(client, NULL);
495 +
496 + return err;
497 +}
498 +
499 +static int tlc59116_remove(struct i2c_client *client)
500 +{
501 + struct tlc59116_led *tlc59116 = i2c_get_clientdata(client);
502 + int i;
503 +
504 + for (i = 0; i < tlc59116->chipdef->bits; i++) {
505 + led_classdev_unregister(&tlc59116[i].led_cdev);
506 + cancel_work_sync(&tlc59116[i].work);
507 + }
508 +
509 + devm_kfree(&client->dev, tlc59116);
510 + i2c_set_clientdata(client, NULL);
511 +
512 + return 0;
513 +}
514 +
515 +static struct i2c_driver tlc59116_driver = {
516 + .driver = {
517 + .name = "leds-tlc59116",
518 + .owner = THIS_MODULE,
519 + },
520 + .probe = tlc59116_probe,
521 + .remove = tlc59116_remove,
522 + .id_table = tlc59116_id,
523 +};
524 +
525 +module_i2c_driver(tlc59116_driver);
526 +
527 +MODULE_AUTHOR("Belkin Inc.");
528 +MODULE_DESCRIPTION("TLC59116 LED driver");
529 +MODULE_LICENSE("GPL v2");