Add TPS61163A driver using EasyScale Interface - V0 based on LK3.8
[mlp-open-source/kernel.git] / drivers / video / backlight / tps61163a_bl.c
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;
52         
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);
76         
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;
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)
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;
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)
145         return -ENODEV;
147 #endif
149 static int tps61163a_backlight_probe(struct platform_device *pdev)
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;
155         
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;
221 static int tps61163a_backlight_remove(struct platform_device *pdev)
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;
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");