]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blob - drivers/video/omap2/displays/panel-tfcs9700.c
omapdss: displays: Add tfcs9700 DPI panel driver
[android-sdk/kernel-video.git] / drivers / video / omap2 / displays / panel-tfcs9700.c
1 /*
2  * Copyright (C) 2013 Texas Instruments Inc
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
17 #include <linux/module.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
20 #include <linux/err.h>
21 #include <linux/i2c.h>
22 #include <linux/gpio.h>
23 #include <linux/of_gpio.h>
24 #include <linux/of_i2c.h>
25 #include <linux/of.h>
26 #include <linux/regmap.h>
28 #include <video/omapdss.h>
29 #include <video/omap-panel-tfcs9700.h>
31 #define TLC_NAME                "tlc59108"
32 #define TLC_I2C_ADDR            0x40
34 #define TLC59108_MODE1          0x00
35 #define TLC59108_PWM2           0x04
36 #define TLC59108_LEDOUT0        0x0c
37 #define TLC59108_LEDOUT1        0x0d
39 struct tlc_data {
40         struct  device *dev;
41         struct  regmap *regmap;
42         int p_gpio;
43 };
45 static const struct omap_video_timings tfc_s9700_default_timings = {
46         .x_res          = 800,
47         .y_res          = 480,
49         .pixel_clock    = 29232,
51         .hfp            = 41,
52         .hsw            = 49,
53         .hbp            = 41,
55         .vfp            = 13,
56         .vsw            = 4,
57         .vbp            = 29,
59         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
60         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
61         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
62         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
63         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
64 };
66 struct panel_drv_data {
67         struct omap_dss_device *dssdev;
69         struct i2c_client *tlc_client;
70         struct mutex lock;
72         int dith;
73 };
75 static int tlc_init(struct i2c_client *client)
76 {
77         struct tlc_data *data = dev_get_drvdata(&client->dev);
78         struct regmap *map = data->regmap;
80         /* init the TLC chip */
81         regmap_write(map, TLC59108_MODE1, 0x01);
83         /*
84          * set LED1(AVDD) to ON state(default), enable LED2 in PWM mode, enable
85          * LED0 to OFF state
86          */
87         regmap_write(map, TLC59108_LEDOUT0, 0x21);
89         /* set LED2 PWM to full freq */
90         regmap_write(map, TLC59108_PWM2, 0xff);
92         /* set LED4(UPDN) and LED6(MODE3) to OFF state */
93         regmap_write(map, TLC59108_LEDOUT1, 0x11);
95         return 0;
96 }
98 static int tlc_uninit(struct i2c_client *client)
99 {
100         struct tlc_data *data = dev_get_drvdata(&client->dev);
101         struct regmap *map = data->regmap;
103         /* clear TLC chip regs */
104         regmap_write(map, TLC59108_PWM2, 0x0);
105         regmap_write(map, TLC59108_LEDOUT0, 0x0);
106         regmap_write(map, TLC59108_LEDOUT1, 0x0);
108         regmap_write(map, TLC59108_MODE1, 0x0);
110         return 0;
113 static int tfc_s9700_power_on(struct omap_dss_device *dssdev)
115         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
116         int r;
118         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
119                 return 0;
121         omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
122         omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
124         r = omapdss_dpi_display_enable(dssdev);
125         if (r)
126                 goto err0;
128         tlc_init(ddata->tlc_client);
130         return 0;
131 err0:
132         return r;
135 static void tfc_s9700_power_off(struct omap_dss_device *dssdev)
137         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
139         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
140                 return;
142         tlc_uninit(ddata->tlc_client);
144         omapdss_dpi_display_disable(dssdev);
147 static int tfc_s9700_probe_of(struct omap_dss_device *dssdev,
148                 struct panel_drv_data *ddata)
150         struct device_node *node = dssdev->dev.of_node;
151         struct device_node *tlc;
152         struct i2c_client *client;
153         int r, datalines;
155         r = of_property_read_u32(node, "data-lines", &datalines);
156         if (r) {
157                 dev_err(&dssdev->dev, "failed to parse datalines");
158                 return r;
159         }
161         tlc = of_parse_phandle(node, "tlc", 0);
162         if (!tlc) {
163                 dev_err(&dssdev->dev, "could not find tlc device\n");
164                 return -EINVAL;
165         }
167         client = of_find_i2c_device_by_node(tlc);
168         if (!client) {
169                 dev_err(&dssdev->dev, "failed to find tlc i2c client device\n");
170                 return -EINVAL;
171         }
173         ddata->tlc_client = client;
175         dssdev->phy.dpi.data_lines = datalines;
177         return 0;
180 static struct i2c_board_info tlc_i2c_board_info = {
181         I2C_BOARD_INFO(TLC_NAME, TLC_I2C_ADDR),
182 };
184 static int tfc_s9700_probe(struct omap_dss_device *dssdev)
186         struct panel_drv_data *ddata;
187         int r;
189         ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL);
190         if (!ddata)
191                 return -ENOMEM;
193         dssdev->panel.timings = tfc_s9700_default_timings;
195         ddata->dssdev = dssdev;
196         mutex_init(&ddata->lock);
198         if (dssdev->dev.of_node) {
199                 r = tfc_s9700_probe_of(dssdev, ddata);
200                 if (r)
201                         return r;
202         } else if (dssdev->data) {
203                 struct tfc_s9700_platform_data *pdata = dssdev->data;
204                 struct i2c_client *client;
205                 struct i2c_adapter *adapter;
206                 int tlc_adapter_id;
208                 dssdev->phy.dpi.data_lines = pdata->datalines;
210                 tlc_adapter_id = pdata->tlc_adapter_id;
212                 adapter = i2c_get_adapter(tlc_adapter_id);
213                 if (!adapter) {
214                         dev_err(&dssdev->dev, "can't get i2c adapter\n");
215                         return -ENODEV;
216                 }
218                 client = i2c_new_device(adapter, &tlc_i2c_board_info);
219                 if (!client) {
220                         dev_err(&dssdev->dev, "can't add i2c device\n");
221                         return -ENODEV;
222                 }
224                 ddata->tlc_client = client;
225         } else {
226                 return -EINVAL;
227         }
230         if (dssdev->phy.dpi.data_lines == 24)
231                 ddata->dith = 0;
232         else if (dssdev->phy.dpi.data_lines == 18)
233                 ddata->dith = 1;
234         else
235                 return -EINVAL;
237         dev_set_drvdata(&dssdev->dev, ddata);
239         return 0;
242 static void __exit tfc_s9700_remove(struct omap_dss_device *dssdev)
244         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
246         mutex_lock(&ddata->lock);
248         dev_set_drvdata(&dssdev->dev, NULL);
250         mutex_unlock(&ddata->lock);
253 static int tfc_s9700_enable(struct omap_dss_device *dssdev)
255         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
256         int r;
258         mutex_lock(&ddata->lock);
260         r = tfc_s9700_power_on(dssdev);
261         if (r == 0)
262                 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
264         mutex_unlock(&ddata->lock);
266         return r;
269 static void tfc_s9700_disable(struct omap_dss_device *dssdev)
271         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
273         mutex_lock(&ddata->lock);
275         tfc_s9700_power_off(dssdev);
277         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
279         mutex_unlock(&ddata->lock);
282 static void tfc_s9700_set_timings(struct omap_dss_device *dssdev,
283                 struct omap_video_timings *timings)
285         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
287         mutex_lock(&ddata->lock);
288         omapdss_dpi_set_timings(dssdev, timings);
289         dssdev->panel.timings = *timings;
290         mutex_unlock(&ddata->lock);
293 static void tfc_s9700_get_timings(struct omap_dss_device *dssdev,
294                 struct omap_video_timings *timings)
296         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
298         mutex_lock(&ddata->lock);
299         *timings = dssdev->panel.timings;
300         mutex_unlock(&ddata->lock);
303 static int tfc_s9700_check_timings(struct omap_dss_device *dssdev,
304                 struct omap_video_timings *timings)
306         struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
307         int r;
309         mutex_lock(&ddata->lock);
310         r = dpi_check_timings(dssdev, timings);
311         mutex_unlock(&ddata->lock);
313         return r;
316 #if defined(CONFIG_OF)
317 static const struct of_device_id tfc_s9700_of_match[] = {
318         {
319                 .compatible = "ti,tfc_s9700",
320         },
321         {},
322 };
324 MODULE_DEVICE_TABLE(of, tfc_s9700_of_match);
325 #else
326 #define dss_of_match NULL
327 #endif
329 static struct omap_dss_driver tfc_s9700_driver = {
330         .probe          = tfc_s9700_probe,
331         .remove         = __exit_p(tfc_s9700_remove),
333         .enable         = tfc_s9700_enable,
334         .disable        = tfc_s9700_disable,
336         .set_timings    = tfc_s9700_set_timings,
337         .get_timings    = tfc_s9700_get_timings,
338         .check_timings  = tfc_s9700_check_timings,
340         .driver         = {
341                 .name   = "tfc_s9700",
342                 .owner  = THIS_MODULE,
343                 .of_match_table = tfc_s9700_of_match,
344         },
345 };
347 struct regmap_config tlc59108_regmap_config = {
348         .reg_bits = 8,
349         .val_bits = 8,
350 };
352 static int tlc59108_i2c_probe(struct i2c_client *client,
353                         const struct i2c_device_id *id)
355         int r;
356         struct regmap *regmap;
357         struct tlc_data *data;
358         struct device *dev = &client->dev;
359         struct device_node *node = dev->of_node;
360         unsigned int val;
361         int gpio;
363         regmap = devm_regmap_init_i2c(client, &tlc59108_regmap_config);
364         if (IS_ERR(regmap)) {
365                 r = PTR_ERR(regmap);
366                 dev_err(&client->dev, "Failed to init regmap: %d\n", r);
367                 return r;
368         }
370         data = devm_kzalloc(dev, sizeof(struct tlc_data), GFP_KERNEL);
371         if (!data)
372                 return -ENOMEM;
374         gpio = of_get_gpio(node, 0);
376         if (gpio_is_valid(gpio)) {
377                 data->p_gpio = gpio;
378         } else if (gpio == -ENOENT) {
379                 data->p_gpio = -1;
380         } else {
381                 dev_err(dev, "failed to parse Power gpio\n");
382                 return gpio;
383         }
385         if (gpio_is_valid(data->p_gpio)) {
386                 r = devm_gpio_request_one(dev, data->p_gpio, GPIOF_OUT_INIT_LOW,
387                                 "tfc_s9700 p_gpio");
388                 if (r) {
389                         dev_err(dev, "Failed to request Power GPIO %d\n",
390                                 data->p_gpio);
391                         return r;
392                 }
393         }
395         dev_set_drvdata(dev, data);
396         data->dev = dev;
397         data->regmap = regmap;
399         msleep(10);
401         /* Try to read a TLC register to verify if i2c works */
402         r = regmap_read(data->regmap, TLC59108_MODE1, &val);
403         if (r < 0) {
404                 dev_err(dev, "Failed to set MODE1: %d\n", r);
405                 return r;
406         }
408         dev_info(dev, "Successfully initialized %s\n", TLC_NAME);
410         return 0;
413 static int tlc59108_i2c_remove(struct i2c_client *client)
415         struct tlc_data *data = dev_get_drvdata(&client->dev);
417         if (gpio_is_valid(data->p_gpio))
418                 gpio_set_value_cansleep(data->p_gpio, 1);
420         return 0;
423 static const struct i2c_device_id tlc59108_id[] = {
424         { TLC_NAME, 0 },
425         { }
426 };
427 MODULE_DEVICE_TABLE(i2c, tlc59108_id);
429 static const struct of_device_id tlc59108_of_match[] = {
430         { .compatible = "ti,tlc59108", },
431         { },
432 };
433 MODULE_DEVICE_TABLE(of, tlc59108_of_match);
435 static struct i2c_driver tlc59108_i2c_driver = {
436         .driver = {
437                 .owner  = THIS_MODULE,
438                 .name   = TLC_NAME,
439                 .of_match_table = tlc59108_of_match,
440         },
441         .id_table       = tlc59108_id,
442         .probe          = tlc59108_i2c_probe,
443         .remove         = tlc59108_i2c_remove,
444 };
446 static int __init tfc_s9700_init(void)
448         int r;
450         r = i2c_add_driver(&tlc59108_i2c_driver);
451         if (r) {
452                 printk(KERN_WARNING "tlc59108 driver" \
453                         " registration failed\n");
454                 return r;
455         }
457         r = omap_dss_register_driver(&tfc_s9700_driver);
458         if (r)
459                 i2c_del_driver(&tlc59108_i2c_driver);
461         return r;
464 static void __exit tfc_s9700_exit(void)
466         omap_dss_unregister_driver(&tfc_s9700_driver);
469 module_init(tfc_s9700_init);
470 module_exit(tfc_s9700_exit);
471 MODULE_LICENSE("GPL");