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)
200 {
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;
285 }
287 static int tps611xx_bl_get_brightness(struct backlight_device *bl)
288 {
289 return bl->props.brightness;
290 }
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)
300 {
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;
328 }
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)
344 {
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;
371 }
373 #else
374 static int tps611xx_backlight_parse_dt(struct tps611xx_bl_data *pchip)
375 {
376 return -ENODEV;
377 }
378 #endif
380 static int tps611xx_backlight_probe(struct platform_device *pdev)
381 {
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;
454 }
456 static int tps611xx_backlight_remove(struct platform_device *pdev)
457 {
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;
465 }
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");