kernel: add missing MTD_SPLIT_FIT_FW symbol
[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");