1 /*
2 * Simple driver for Texas Instruments TPS61163A Backlight driver chip
3 * using EasyScale Interface
4 *
5 * Copyright (C) 2014 Texas Instruments
6 * Author: Daniel Jeong <gshark.jeong@gmail.com>
7 * Ldd Mlp <ldd-mlp@list.ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
15 #include <linux/backlight.h>
16 #include <linux/delay.h>
17 #include <linux/err.h>
18 #include <linux/fb.h>
19 #include <linux/gpio.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/platform_data/tps61163a_bl.h>
24 #include <linux/platform_device.h>
25 #include <linux/slab.h>
27 #define ADDRESS_TPS61163A 0x8F0000
28 #define T_ES_DELAY_NS 100000
29 #define T_ES_DETECTION_NS 260000
30 #define T_START_NS 2000
31 #define T_EOS_NS 2000
32 #define T_RESET_MS 3
33 #define T_LOW_LOGIC_1_NS 3000
34 #define T_LOW_LOGIC_0_NS 7000
35 #define T_LOGIC_NS T_LOW_LOGIC_1_NS + T_LOW_LOGIC_0_NS
37 #define BRIGHTNESS_MAX 0x1ff
38 #define BRIGHTNESS_BMASK 0x1ff
40 struct tps61163a_bl_data {
41 struct device *dev;
42 struct backlight_device *bled;
43 struct tps61163a_platform_data *pdata;
45 unsigned int en_gpio;
46 };
48 static int tps61163a_backlight_update_status(struct backlight_device *bl)
49 {
50 struct tps61163a_bl_data *pchip = bl_get_data(bl);
51 unsigned int es_data, bmask;
53 es_data = ADDRESS_TPS61163A | (bl->props.brightness & BRIGHTNESS_BMASK);
55 /* t_start : 2us high before data byte */
56 gpio_direction_output(pchip->en_gpio,1);
57 ndelay(T_START_NS);
59 for(bmask = 0x01; bmask < 0x1000000 ; bmask <<= 1){
60 int t_low;
61 if(es_data & bmask)
62 t_low = T_LOW_LOGIC_1_NS;
63 else
64 t_low = T_LOW_LOGIC_0_NS;
66 gpio_direction_output(pchip->en_gpio,0);
67 ndelay(t_low);
68 gpio_direction_output(pchip->en_gpio,1);
69 ndelay(T_LOGIC_NS - t_low);
70 }
71 gpio_direction_output(pchip->en_gpio,0);
72 /* t_eos : 2us low after address byte */
73 ndelay(T_EOS_NS);
74 gpio_direction_output(pchip->en_gpio,1);
77 return bl->props.brightness;
78 }
80 static int tps61163a_backlight_get_brightness(struct backlight_device *bl)
81 {
82 return bl->props.brightness;
83 }
85 static const struct backlight_ops tps61163a_bl_ops = {
86 .update_status = tps61163a_backlight_update_status,
87 .get_brightness = tps61163a_backlight_get_brightness,
88 };
90 static ssize_t tps61163a_enable_store(struct device *dev,
91 struct device_attribute *devAttr,
92 const char *buf, size_t size)
93 {
94 struct tps61163a_bl_data *pchip = dev_get_drvdata(dev);
95 unsigned int input;
96 int ret;
98 ret = kstrtouint(buf, 10, &input);
99 if (ret)
100 return -EINVAL;
102 if(input == 0){
103 gpio_direction_output(pchip->en_gpio,0);
104 /* low more than 2.5 ms to reset */
105 mdelay(T_RESET_MS);
106 } else {
107 gpio_direction_output(pchip->en_gpio,1);
108 ndelay(T_ES_DELAY_NS);
109 gpio_direction_output(pchip->en_gpio,0);
110 ndelay(T_ES_DETECTION_NS);
111 gpio_direction_output(pchip->en_gpio,1);
112 }
114 return size;
115 }
116 static DEVICE_ATTR(enable, S_IWUSR, NULL, tps61163a_enable_store);
118 #ifdef CONFIG_OF
119 static int tps61163a_backlight_parse_dt(struct device *dev)
120 {
121 struct device_node *node = dev->of_node;
122 u32 value;
123 int ret;
125 if (!node)
126 return -ENODEV;
128 ret = of_property_read_u32(node, "en_gpio_num",&value);
129 if (ret < 0)
130 return ret;
132 return value;
133 }
135 static struct of_device_id tps61163a_backlight_of_match[] = {
136 { .compatible = TPS61163A_NAME },
137 { }
138 };
140 MODULE_DEVICE_TABLE(of, tps61163a_backlight_of_match);
141 #else
142 static int tps61163a_backlight_parse_dt(struct device *dev,
143 struct platform_tps61163a_backlight_data *data)
144 {
145 return -ENODEV;
146 }
147 #endif
149 static int tps61163a_backlight_probe(struct platform_device *pdev)
150 {
151 struct tps61163a_bl_data *pchip;
152 struct backlight_properties props;
153 struct tps61163a_platform_data *pdata = dev_get_platdata(&pdev->dev);
154 int ret;
156 pchip = devm_kzalloc(&pdev->dev,
157 sizeof(struct tps61163a_bl_data), GFP_KERNEL);
158 if (pchip == NULL)
159 return -ENOMEM;
160 pchip->dev = &pdev->dev;
162 if(pdata == NULL){
163 pdata = devm_kzalloc(&pdev->dev,
164 sizeof(struct tps61163a_platform_data), GFP_KERNEL);
165 if (pdata == NULL)
166 return -ENOMEM;
167 pdata->en_gpio_num = tps61163a_backlight_parse_dt(&pdev->dev);
168 if(pdata->en_gpio_num < 0)
169 return -EINVAL;
170 }
172 pchip->en_gpio = pdata->en_gpio_num;
173 pchip->pdata = pdata;
175 memset(&props, 0, sizeof(struct backlight_properties));
176 props.brightness = BRIGHTNESS_MAX;
177 props.max_brightness = BRIGHTNESS_MAX;
178 props.type = BACKLIGHT_RAW;
179 pchip->bled =
180 backlight_device_register(TPS61163A_NAME, pchip->dev, pchip,
181 &tps61163a_bl_ops, &props);
182 if (IS_ERR(pchip->bled))
183 return PTR_ERR(pchip->bled);
185 /* for enable/disable */
186 ret = device_create_file(&(pchip->bled->dev),
187 &dev_attr_enable);
188 if (ret < 0) {
189 dev_err(pchip->dev, "failed : add sysfs entries\n");
190 goto err_out;
191 }
192 platform_set_drvdata(pdev, pchip);
194 /* EasyScale init */
195 ret = gpio_request( pchip->en_gpio,"tps61163a");
196 if(ret ){
197 dev_err(pchip->dev, "failed : get gpio %d\n",pchip->en_gpio);
198 goto err_out;
199 }
200 /*
201 * ES Detection Window
202 * - ES detect delay : 100us
203 * - ES detect time : 260us
204 * it should be finished in 1ms
205 */
206 gpio_direction_output(pchip->en_gpio,1);
207 ndelay(T_ES_DELAY_NS);
208 gpio_direction_output(pchip->en_gpio,0);
209 ndelay(T_ES_DETECTION_NS);
210 gpio_direction_output(pchip->en_gpio,1);
212 dev_info(pchip->dev,"tps61163a based on EasyScale is initialized\n");
213 return 0;
215 err_out:
217 backlight_device_unregister(pchip->bled);
218 return ret;
219 }
221 static int tps61163a_backlight_remove(struct platform_device *pdev)
222 {
223 struct tps61163a_bl_data *pchip = platform_get_drvdata(pdev);
225 backlight_device_unregister(pchip->bled);
226 gpio_direction_output(pchip->en_gpio,0);
227 mdelay(T_RESET_MS);
228 return 0;
229 }
231 static struct platform_driver tps61163a_backlight_driver = {
232 .driver = {
233 .name = TPS61163A_NAME,
234 .owner = THIS_MODULE,
235 .of_match_table = of_match_ptr(tps61163a_backlight_of_match),
236 },
237 .probe = tps61163a_backlight_probe,
238 .remove = tps61163a_backlight_remove,
239 };
241 module_platform_driver(tps61163a_backlight_driver);
243 MODULE_DESCRIPTION("EasyScale based tps61163a Backlight Driver");
244 MODULE_LICENSE("GPL");
245 MODULE_ALIAS("platform:tps61163a_bl");