LP8758 - consolidated version
[mlp-open-source/kernel.git] / drivers / video / backlight / tps611xx_bl.c
1 /*
2  * Simple driver for Texas Instruments TPS611XX Backlight driver chip
3  *        using EasyScale Interface. It supports TPS61158, TPS61161,
4  *        TPS61163 and TPS61165.
5  *
6  * Copyright (C) 2014 Texas Instruments
7  * Author: Daniel Jeong  <gshark.jeong@gmail.com>
8  *             Ldd Mlp <ldd-mlp@list.ti.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  */
16 #include <linux/backlight.h>
17 #include <linux/delay.h>
18 #include <linux/err.h>
19 #include <linux/fb.h>
20 #include <linux/gpio.h>
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/of_device.h>
26 #include <linux/platform_data/tps611xx_bl.h>
27 #include <linux/platform_device.h>
28 #include <linux/slab.h>
30 #define CMD_FORWARD 0
31 #define CMD_BACKWARD 1
33 enum tps611xx_id {
34         TPS61158_ID = 0,
35         TPS61161_ID,
36         TPS61163_ID,
37         TPS61165_ID,
38 };
40 /*
41  * easyscale time spec
42  * @es_delay : es delay time(ns)
43  * @es_det   : es detection time(ns)
44  * @start    : start time of data stream(ns)
45  * @eos      : end time of data stream(ns)
46  * @reset    : ic shutdown time(ms)
47  * @logic_1_low : low time high bit(ns)
48  * @logic_0_low : low time low bit(ns)
49  * @ackn        : duation of ack condistion(ns)
50  * @ack_poll    : ack polling duration(ns)
51  */
52 struct tps611xx_time {
53         unsigned int es_delay;
54         unsigned int es_det;
55         unsigned int start;
56         unsigned int eos;
57         unsigned int reset;
58         unsigned int logic_1_low;
59         unsigned int logic_0_low;
60         unsigned int ackn;
61         unsigned int ack_poll;
62 };
64 /*
65  * @seq : sequence of data transfer
66  * @size: size of data
67  * @brt_max : max brightness
68  * @brt_bmask : bit mask of dimming bits
69  * @rfa_bmask : bit mask of request of ack
70  */
71 struct tps611xx_command {
72         int seq;
73         int size;
74         int brt_max;
75         int brt_bmask;
76         int rfa_bmask;
77 };
79 /*
80  * @id : product id
81  * @name : product name
82  * @addr : device address
83  * @cmd  : es command info
84  * @time : es time info
85  */
86 struct tps611xx_esdata {
87         enum tps611xx_id id;
88         char *name;
89         int addr;
90         struct tps611xx_command cmd;
91         struct tps611xx_time time;
92 };
94 struct tps611xx_bl_data {
95         struct device *dev;
96         struct backlight_device *bled;
97         struct tps611xx_platform_data *pdata;
99         /*
100          * @rfa_en : acknowlege request enable
101          * @en_gpio: enable pin gpio no.
102          * @esdata : easyscale data
103          */
104         int rfa_en;
105         unsigned int en_gpio;
106         const struct tps611xx_esdata *esdata;
107 };
109 static struct tps611xx_esdata tps611xx_info[] = {
110         [TPS61158_ID] = {
111                          .id = TPS61158_ID,
112                          .name = "tps61158",
113                          .addr = 0x5800,
114                          .cmd = {
115                                  .seq = CMD_FORWARD,
116                                  .size = 16,
117                                  .brt_max = 31,
118                                  .brt_bmask = 0x1f,
119                                  .rfa_bmask = 0x80},
120                          .time = {
121                                   .es_delay = 100000,
122                                   .es_det = 450000,
123                                   .start = 3500,
124                                   .eos = 3500,
125                                   .reset = 4,
126                                   .logic_1_low = 5000,
127                                   .logic_0_low = 15000,
128                                   .ackn = 900000,
129                                   .ack_poll = 2000},
130                          },
132         [TPS61161_ID] = {
133                          .id = TPS61161_ID,
134                          .name = "tps61161",
135                          .addr = 0x7200,
136                          .cmd = {
137                                  .seq = CMD_FORWARD,
138                                  .size = 16,
139                                  .brt_max = 31,
140                                  .brt_bmask = 0x1f,
141                                  .rfa_bmask = 0x80},
142                          .time = {
143                                   .es_delay = 120000,
144                                   .es_det = 280000,
145                                   .start = 2000,
146                                   .eos = 2000,
147                                   .reset = 3,
148                                   .logic_1_low = 3000,
149                                   .logic_0_low = 7000,
150                                   .ackn = 512000,
151                                   .ack_poll = 2000},
152                          },
154         [TPS61163_ID] = {
155                          .id = TPS61163_ID,
156                          .name = "tps61163",
157                          .addr = 0x8F0000,
158                          .cmd = {
159                                  .seq = CMD_BACKWARD,
160                                  .size = 24,
161                                  .brt_max = 511,
162                                  .brt_bmask = 0x1ff,
163                                  .rfa_bmask = 0x400},
164                          .time = {
165                                   .es_delay = 100000,
166                                   .es_det = 260000,
167                                   .start = 2000,
168                                   .eos = 2000,
169                                   .reset = 3,
170                                   .logic_1_low = 3000,
171                                   .logic_0_low = 7000,
172                                   .ackn = 512000,
173                                   .ack_poll = 2000},
174                          },
176         [TPS61165_ID] = {
177                          .id = TPS61165_ID,
178                          .name = "tps61165",
179                          .addr = 0x7200,
180                          .cmd = {
181                                  .seq = CMD_FORWARD,
182                                  .size = 16,
183                                  .brt_max = 31,
184                                  .brt_bmask = 0x1f,
185                                  .rfa_bmask = 0x80},
186                          .time = {
187                                   .es_delay = 120000,
188                                   .es_det = 280000,
189                                   .start = 4000,
190                                   .eos = 4000,
191                                   .reset = 3,
192                                   .logic_1_low = 3000,
193                                   .logic_0_low = 7000,
194                                   .ackn = 512000,
195                                   .ack_poll = 2000},
196                          },
197 };
199 static int tps611xx_bl_update_status(struct backlight_device *bl)
201         struct tps611xx_bl_data *pchip = bl_get_data(bl);
202         const struct tps611xx_esdata *esdata = pchip->esdata;
203         int data_in, t_low, t_logic, max_bmask;
204         unsigned long flags;
206         data_in = esdata->addr | (bl->props.brightness & esdata->cmd.brt_bmask);
207         if (pchip->rfa_en)
208                 data_in |= esdata->cmd.rfa_bmask;
210         max_bmask = 0x1 << esdata->cmd.size;
211         t_logic = esdata->time.logic_1_low + esdata->time.logic_0_low;
213         local_irq_save(flags);
214         /* t_start : 2us high before data byte */
215         gpio_direction_output(pchip->en_gpio, 1);
216         ndelay(esdata->time.start);
218         /* forward command transfer */
219         if (esdata->cmd.seq == CMD_FORWARD) {
220                 int addr_bmask = max_bmask >> 8;
221                 for (max_bmask >>= 1; max_bmask > 0x0; max_bmask >>= 1) {
222                         if (data_in & max_bmask)
223                                 t_low = esdata->time.logic_1_low;
224                         else
225                                 t_low = esdata->time.logic_0_low;
227                         gpio_direction_output(pchip->en_gpio, 0);
228                         ndelay(t_low);
229                         gpio_direction_output(pchip->en_gpio, 1);
230                         ndelay(t_logic - t_low);
232                         if (max_bmask == addr_bmask) {
233                                 gpio_direction_output(pchip->en_gpio, 0);
234                                 /* t_eos : low after address byte */
235                                 ndelay(esdata->time.eos);
236                                 gpio_direction_output(pchip->en_gpio, 1);
237                                 /* t_start : high before data byte */
238                                 ndelay(esdata->time.start);
239                         }
240                 }
241         } else {
242                 /* backward command tansfer */
243                 int bmask;
244                 for (bmask = 0x01; bmask < max_bmask; bmask <<= 1) {
245                         if (data_in & bmask)
246                                 t_low = esdata->time.logic_1_low;
247                         else
248                                 t_low = esdata->time.logic_0_low;
250                         gpio_direction_output(pchip->en_gpio, 0);
251                         ndelay(t_low);
252                         gpio_direction_output(pchip->en_gpio, 1);
253                         ndelay(t_logic - t_low);
254                 }
255         }
257         /*
258          * t_eos : low after address byte
259          * t_ackVal is also t_eos
260          */
261         gpio_direction_output(pchip->en_gpio, 0);
262         ndelay(esdata->time.eos);
264         /* RFA management  */
265         if (pchip->rfa_en) {
266                 int max_ack_time = esdata->time.ackn;
267                 /* set input */
268                 gpio_direction_input(pchip->en_gpio);
269                 /* read acknowledge from chip */
270                 while (max_ack_time > 0) {
271                         if (gpio_get_value(pchip->en_gpio) == 0)
272                                 break;
273                         max_ack_time -= esdata->time.ack_poll;
274                 }
275                 if (max_ack_time <= 0)
276                         dev_err(pchip->dev,
277                                 "easyscale : no ack from %s\n", esdata->name);
278                 else
279                         ndelay(max_ack_time);
280         }
281         gpio_direction_output(pchip->en_gpio, 1);
282         local_irq_restore(flags);
284         return bl->props.brightness;
287 static int tps611xx_bl_get_brightness(struct backlight_device *bl)
289         return bl->props.brightness;
292 static const struct backlight_ops tps611xx_bl_ops = {
293         .update_status = tps611xx_bl_update_status,
294         .get_brightness = tps611xx_bl_get_brightness,
295 };
297 static ssize_t tps611xx_enable_store(struct device *dev,
298                                      struct device_attribute *devAttr,
299                                      const char *buf, size_t size)
301         struct tps611xx_bl_data *pchip = dev_get_drvdata(dev);
302         const struct tps611xx_esdata *esdata = pchip->esdata;
303         unsigned long flags;
304         unsigned int input;
305         int ret;
307         ret = kstrtouint(buf, 10, &input);
308         if (ret)
309                 return -EINVAL;
311         local_irq_save(flags);
312         if (input == 0) {
313                 /* chip disable */
314                 gpio_direction_output(pchip->en_gpio, 0);
315                 /* low more than reset ms to reset */
316                 mdelay(esdata->time.reset);
317         } else {
318                 /* easyscale detection window */
319                 gpio_direction_output(pchip->en_gpio, 1);
320                 ndelay(esdata->time.es_delay);
321                 gpio_direction_output(pchip->en_gpio, 0);
322                 ndelay(esdata->time.es_det);
323                 gpio_direction_output(pchip->en_gpio, 1);
324         }
325         local_irq_restore(flags);
327         return size;
330 static DEVICE_ATTR(enable, S_IWUSR, NULL, tps611xx_enable_store);
332 #ifdef CONFIG_OF
333 static struct of_device_id tps611xx_backlight_of_match[] = {
334         {.compatible = "ti,tps61158_bl",.data = &tps611xx_info[TPS61158_ID]},
335         {.compatible = "ti,tps61161_bl",.data = &tps611xx_info[TPS61161_ID]},
336         {.compatible = "ti,tps61163_bl",.data = &tps611xx_info[TPS61163_ID]},
337         {.compatible = "ti,tps61165_bl",.data = &tps611xx_info[TPS61165_ID]},
338         {}
339 };
341 MODULE_DEVICE_TABLE(of, tps611xx_backlight_of_match);
343 static int tps611xx_backlight_parse_dt(struct tps611xx_bl_data *pchip)
345         struct device *dev = pchip->dev;
346         struct device_node *node = dev->of_node;
347         const struct of_device_id *of_id =
348             of_match_device(tps611xx_backlight_of_match, dev);
349         u32 value;
350         int ret;
352         if (!node)
353                 return -ENODEV;
355         if (!of_id || !of_id->data) {
356                 dev_err(dev, "Failed to find tps611xx chip id\n");
357                 return -EFAULT;
358         }
359         pchip->esdata = of_id->data;
361         ret = of_property_read_u32(node, "en_gpio_num", &value);
362         if (ret < 0)
363                 return ret;
364         pchip->en_gpio = value;
365         ret = of_property_read_u32(node, "rfa_en", &value);
366         if (ret < 0)
367                 return ret;
368         pchip->rfa_en = value;
370         return 0;
373 #else
374 static int tps611xx_backlight_parse_dt(struct tps611xx_bl_data *pchip)
376         return -ENODEV;
378 #endif
380 static int tps611xx_backlight_probe(struct platform_device *pdev)
382         struct tps611xx_bl_data *pchip;
383         struct backlight_properties props;
384         const struct tps611xx_esdata *esdata;
385         struct tps611xx_platform_data *pdata = dev_get_platdata(&pdev->dev);
386         unsigned long flags;
387         int ret;
389         printk(KERN_INFO "\n\n");
390         pchip = devm_kzalloc(&pdev->dev,
391                              sizeof(struct tps611xx_bl_data), GFP_KERNEL);
392         if (pchip == NULL)
393                 return -ENOMEM;
394         pchip->dev = &pdev->dev;
396         if (pdata == NULL) {
397                 ret = tps611xx_backlight_parse_dt(pchip);
398                 if (ret < 0)
399                         return ret;
400         } else {
401                 pchip->rfa_en = pdata->rfa_en;
402                 pchip->en_gpio = pdata->en_gpio_num;
403                 pchip->esdata = (const struct tps611xx_esdata *)
404                     platform_get_device_id(pdev)->driver_data;
405         }
407         esdata = pchip->esdata;
408         memset(&props, 0, sizeof(struct backlight_properties));
409         props.brightness = esdata->cmd.brt_max;
410         props.max_brightness = esdata->cmd.brt_max;
411         props.type = BACKLIGHT_RAW;
412         pchip->bled =
413             devm_backlight_device_register(pchip->dev, TPS611XX_NAME,
414                                            pchip->dev, pchip,
415                                            &tps611xx_bl_ops, &props);
416         if (IS_ERR(pchip->bled))
417                 return PTR_ERR(pchip->bled);
419         /* for enable/disable */
420         ret = device_create_file(&(pchip->bled->dev), &dev_attr_enable);
421         if (ret < 0) {
422                 dev_err(pchip->dev, "failed : add sysfs entries\n");
423                 goto err_out;
424         }
425         platform_set_drvdata(pdev, pchip);
427         /* EasyScale init */
428         ret = gpio_request(pchip->en_gpio, "tps611xx");
429         if (ret) {
430                 device_remove_file(&(pchip->bled->dev), &dev_attr_enable);
431                 dev_err(pchip->dev, "failed : get gpio %d\n", pchip->en_gpio);
432                 goto err_out;
433         }
435         /*
436          * ES Detection Window
437          *   - ES detect delay
438          *   - ES detect time
439          */
440         local_irq_save(flags);
441         gpio_direction_output(pchip->en_gpio, 1);
442         ndelay(esdata->time.es_delay);
443         gpio_direction_output(pchip->en_gpio, 0);
444         ndelay(esdata->time.es_det);
445         gpio_direction_output(pchip->en_gpio, 1);
446         local_irq_restore(flags);
447         dev_info(pchip->dev,
448                  "%s based on EasyScale is initialized\n", pchip->esdata->name);
449         return 0;
451 err_out:
452         backlight_device_unregister(pchip->bled);
453         return ret;
456 static int tps611xx_backlight_remove(struct platform_device *pdev)
458         struct tps611xx_bl_data *pchip = platform_get_drvdata(pdev);
459         const struct tps611xx_esdata *esdata = pchip->esdata;
461         device_remove_file(&(pchip->bled->dev), &dev_attr_enable);
462         gpio_direction_output(pchip->en_gpio, 0);
463         mdelay(esdata->time.reset);
464         return 0;
467 static const struct platform_device_id tps611xx_id_table[] = {
468         {TPS61158_NAME, (unsigned long)&tps611xx_info[TPS61158_ID]},
469         {TPS61161_NAME, (unsigned long)&tps611xx_info[TPS61161_ID]},
470         {TPS61163_NAME, (unsigned long)&tps611xx_info[TPS61163_ID]},
471         {TPS61165_NAME, (unsigned long)&tps611xx_info[TPS61165_ID]},
472         {}
473 };
475 static struct platform_driver tps611xx_backlight_driver = {
476         .driver = {
477                    .name = TPS611XX_NAME,
478                    .owner = THIS_MODULE,
479                    .of_match_table = of_match_ptr(tps611xx_backlight_of_match),
480                    },
481         .probe = tps611xx_backlight_probe,
482         .remove = tps611xx_backlight_remove,
483         .id_table = tps611xx_id_table,
484 };
486 module_platform_driver(tps611xx_backlight_driver);
488 MODULE_DESCRIPTION("EasyScale based tps611xx Backlight Driver");
489 MODULE_LICENSE("GPL");
490 MODULE_ALIAS("platform:tps611xx_bl");