2 * LCD panel driver for Sharp LS037V7DW01
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
12 #include <linux/delay.h>
13 #include <linux/gpio.h>
14 #include <linux/module.h>
16 #include <linux/of_gpio.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19 #include <linux/regulator/consumer.h>
20 #include <video/omapdss.h>
21 #include <video/omap-panel-data.h>
23 struct panel_drv_data
{
24 struct omap_dss_device dssdev
;
25 struct omap_dss_device
*in
;
26 struct regulator
*vcc
;
30 struct omap_video_timings videomode
;
32 struct gpio_desc
*resb_gpio
; /* low = reset active min 20 us */
33 struct gpio_desc
*ini_gpio
; /* high = power on */
34 struct gpio_desc
*mo_gpio
; /* low = 480x640, high = 240x320 */
35 struct gpio_desc
*lr_gpio
; /* high = conventional horizontal scanning */
36 struct gpio_desc
*ud_gpio
; /* high = conventional vertical scanning */
39 static const struct omap_video_timings sharp_ls_timings
= {
43 .pixelclock
= 19200000,
53 .vsync_level
= OMAPDSS_SIG_ACTIVE_LOW
,
54 .hsync_level
= OMAPDSS_SIG_ACTIVE_LOW
,
55 .data_pclk_edge
= OMAPDSS_DRIVE_SIG_RISING_EDGE
,
56 .de_level
= OMAPDSS_SIG_ACTIVE_HIGH
,
57 .sync_pclk_edge
= OMAPDSS_DRIVE_SIG_FALLING_EDGE
,
60 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
62 static int sharp_ls_connect(struct omap_dss_device
*dssdev
)
64 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
65 struct omap_dss_device
*in
= ddata
->in
;
68 if (omapdss_device_is_connected(dssdev
))
71 r
= in
->ops
.dpi
->connect(in
, dssdev
);
78 static void sharp_ls_disconnect(struct omap_dss_device
*dssdev
)
80 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
81 struct omap_dss_device
*in
= ddata
->in
;
83 if (!omapdss_device_is_connected(dssdev
))
86 in
->ops
.dpi
->disconnect(in
, dssdev
);
89 static int sharp_ls_enable(struct omap_dss_device
*dssdev
)
91 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
92 struct omap_dss_device
*in
= ddata
->in
;
95 if (!omapdss_device_is_connected(dssdev
))
98 if (omapdss_device_is_enabled(dssdev
))
101 if (ddata
->data_lines
)
102 in
->ops
.dpi
->set_data_lines(in
, ddata
->data_lines
);
103 in
->ops
.dpi
->set_timings(in
, &ddata
->videomode
);
106 r
= regulator_enable(ddata
->vcc
);
111 r
= in
->ops
.dpi
->enable(in
);
113 regulator_disable(ddata
->vcc
);
117 /* wait couple of vsyncs until enabling the LCD */
120 if (ddata
->resb_gpio
)
121 gpiod_set_value_cansleep(ddata
->resb_gpio
, 1);
124 gpiod_set_value_cansleep(ddata
->ini_gpio
, 1);
126 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
131 static void sharp_ls_disable(struct omap_dss_device
*dssdev
)
133 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
134 struct omap_dss_device
*in
= ddata
->in
;
136 if (!omapdss_device_is_enabled(dssdev
))
140 gpiod_set_value_cansleep(ddata
->ini_gpio
, 0);
142 if (ddata
->resb_gpio
)
143 gpiod_set_value_cansleep(ddata
->resb_gpio
, 0);
145 /* wait at least 5 vsyncs after disabling the LCD */
149 in
->ops
.dpi
->disable(in
);
152 regulator_disable(ddata
->vcc
);
154 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
157 static void sharp_ls_set_timings(struct omap_dss_device
*dssdev
,
158 struct omap_video_timings
*timings
)
160 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
161 struct omap_dss_device
*in
= ddata
->in
;
163 ddata
->videomode
= *timings
;
164 dssdev
->panel
.timings
= *timings
;
166 in
->ops
.dpi
->set_timings(in
, timings
);
169 static void sharp_ls_get_timings(struct omap_dss_device
*dssdev
,
170 struct omap_video_timings
*timings
)
172 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
174 *timings
= ddata
->videomode
;
177 static int sharp_ls_check_timings(struct omap_dss_device
*dssdev
,
178 struct omap_video_timings
*timings
)
180 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
181 struct omap_dss_device
*in
= ddata
->in
;
183 return in
->ops
.dpi
->check_timings(in
, timings
);
186 static struct omap_dss_driver sharp_ls_ops
= {
187 .connect
= sharp_ls_connect
,
188 .disconnect
= sharp_ls_disconnect
,
190 .enable
= sharp_ls_enable
,
191 .disable
= sharp_ls_disable
,
193 .set_timings
= sharp_ls_set_timings
,
194 .get_timings
= sharp_ls_get_timings
,
195 .check_timings
= sharp_ls_check_timings
,
197 .get_resolution
= omapdss_default_get_resolution
,
200 static int sharp_ls_get_gpio(struct device
*dev
, int gpio
, unsigned long flags
,
201 char *desc
, struct gpio_desc
**gpiod
)
203 struct gpio_desc
*gd
;
208 r
= devm_gpio_request_one(dev
, gpio
, flags
, desc
);
210 return r
== -ENOENT
? 0 : r
;
212 gd
= gpio_to_desc(gpio
);
214 return PTR_ERR(gd
) == -ENOENT
? 0 : PTR_ERR(gd
);
220 static int sharp_ls_probe_pdata(struct platform_device
*pdev
)
222 const struct panel_sharp_ls037v7dw01_platform_data
*pdata
;
223 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
224 struct omap_dss_device
*dssdev
, *in
;
227 pdata
= dev_get_platdata(&pdev
->dev
);
229 in
= omap_dss_find_output(pdata
->source
);
231 dev_err(&pdev
->dev
, "failed to find video source '%s'\n",
233 return -EPROBE_DEFER
;
238 ddata
->data_lines
= pdata
->data_lines
;
240 dssdev
= &ddata
->dssdev
;
241 dssdev
->name
= pdata
->name
;
243 r
= sharp_ls_get_gpio(&pdev
->dev
, pdata
->mo_gpio
, GPIOF_OUT_INIT_LOW
,
244 "lcd MO", &ddata
->mo_gpio
);
247 r
= sharp_ls_get_gpio(&pdev
->dev
, pdata
->lr_gpio
, GPIOF_OUT_INIT_HIGH
,
248 "lcd LR", &ddata
->lr_gpio
);
251 r
= sharp_ls_get_gpio(&pdev
->dev
, pdata
->ud_gpio
, GPIOF_OUT_INIT_HIGH
,
252 "lcd UD", &ddata
->ud_gpio
);
255 r
= sharp_ls_get_gpio(&pdev
->dev
, pdata
->resb_gpio
, GPIOF_OUT_INIT_LOW
,
256 "lcd RESB", &ddata
->resb_gpio
);
259 r
= sharp_ls_get_gpio(&pdev
->dev
, pdata
->ini_gpio
, GPIOF_OUT_INIT_LOW
,
260 "lcd INI", &ddata
->ini_gpio
);
267 static int sharp_ls_get_gpio_of(struct device
*dev
, int index
, int val
,
268 const char *desc
, struct gpio_desc
**gpiod
)
270 struct gpio_desc
*gd
;
274 gd
= devm_gpiod_get_index(dev
, desc
, index
, GPIOD_OUT_LOW
);
282 static int sharp_ls_probe_of(struct platform_device
*pdev
)
284 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
285 struct device_node
*node
= pdev
->dev
.of_node
;
286 struct omap_dss_device
*in
;
289 ddata
->vcc
= devm_regulator_get(&pdev
->dev
, "envdd");
290 if (IS_ERR(ddata
->vcc
)) {
291 dev_err(&pdev
->dev
, "failed to get regulator\n");
292 return PTR_ERR(ddata
->vcc
);
296 r
= sharp_ls_get_gpio_of(&pdev
->dev
, 0, 0, "enable", &ddata
->ini_gpio
);
301 r
= sharp_ls_get_gpio_of(&pdev
->dev
, 0, 0, "reset", &ddata
->resb_gpio
);
306 r
= sharp_ls_get_gpio_of(&pdev
->dev
, 0, 0, "mode", &ddata
->mo_gpio
);
311 r
= sharp_ls_get_gpio_of(&pdev
->dev
, 1, 1, "mode", &ddata
->lr_gpio
);
316 r
= sharp_ls_get_gpio_of(&pdev
->dev
, 2, 1, "mode", &ddata
->ud_gpio
);
320 in
= omapdss_of_find_source_for_first_ep(node
);
322 dev_err(&pdev
->dev
, "failed to find video source\n");
331 static int sharp_ls_probe(struct platform_device
*pdev
)
333 struct panel_drv_data
*ddata
;
334 struct omap_dss_device
*dssdev
;
337 ddata
= devm_kzalloc(&pdev
->dev
, sizeof(*ddata
), GFP_KERNEL
);
341 platform_set_drvdata(pdev
, ddata
);
343 if (dev_get_platdata(&pdev
->dev
)) {
344 r
= sharp_ls_probe_pdata(pdev
);
347 } else if (pdev
->dev
.of_node
) {
348 r
= sharp_ls_probe_of(pdev
);
355 ddata
->videomode
= sharp_ls_timings
;
357 dssdev
= &ddata
->dssdev
;
358 dssdev
->dev
= &pdev
->dev
;
359 dssdev
->driver
= &sharp_ls_ops
;
360 dssdev
->type
= OMAP_DISPLAY_TYPE_DPI
;
361 dssdev
->owner
= THIS_MODULE
;
362 dssdev
->panel
.timings
= ddata
->videomode
;
363 dssdev
->phy
.dpi
.data_lines
= ddata
->data_lines
;
365 r
= omapdss_register_display(dssdev
);
367 dev_err(&pdev
->dev
, "Failed to register panel\n");
374 omap_dss_put_device(ddata
->in
);
378 static int __exit
sharp_ls_remove(struct platform_device
*pdev
)
380 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
381 struct omap_dss_device
*dssdev
= &ddata
->dssdev
;
382 struct omap_dss_device
*in
= ddata
->in
;
384 omapdss_unregister_display(dssdev
);
386 sharp_ls_disable(dssdev
);
387 sharp_ls_disconnect(dssdev
);
389 omap_dss_put_device(in
);
394 static const struct of_device_id sharp_ls_of_match
[] = {
395 { .compatible
= "omapdss,sharp,ls037v7dw01", },
399 MODULE_DEVICE_TABLE(of
, sharp_ls_of_match
);
401 static struct platform_driver sharp_ls_driver
= {
402 .probe
= sharp_ls_probe
,
403 .remove
= __exit_p(sharp_ls_remove
),
405 .name
= "panel-sharp-ls037v7dw01",
406 .of_match_table
= sharp_ls_of_match
,
407 .suppress_bind_attrs
= true,
411 module_platform_driver(sharp_ls_driver
);
413 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
414 MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
415 MODULE_LICENSE("GPL");