]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
drm/omap: omap_display_timings: Use display_flags for sync edge
[karo-tx-linux.git] / drivers / gpu / drm / omapdrm / displays / panel-sharp-ls037v7dw01.c
1 /*
2  * LCD panel driver for Sharp LS037V7DW01
3  *
4  * Copyright (C) 2013 Texas Instruments
5  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6  *
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.
10  */
11
12 #include <linux/delay.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/regulator/consumer.h>
19
20 #include "../dss/omapdss.h"
21
22 struct panel_drv_data {
23         struct omap_dss_device dssdev;
24         struct omap_dss_device *in;
25         struct regulator *vcc;
26
27         int data_lines;
28
29         struct omap_video_timings videomode;
30
31         struct gpio_desc *resb_gpio;    /* low = reset active min 20 us */
32         struct gpio_desc *ini_gpio;     /* high = power on */
33         struct gpio_desc *mo_gpio;      /* low = 480x640, high = 240x320 */
34         struct gpio_desc *lr_gpio;      /* high = conventional horizontal scanning */
35         struct gpio_desc *ud_gpio;      /* high = conventional vertical scanning */
36 };
37
38 static const struct omap_video_timings sharp_ls_timings = {
39         .hactive = 480,
40         .vactive = 640,
41
42         .pixelclock     = 19200000,
43
44         .hsync_len      = 2,
45         .hfront_porch   = 1,
46         .hback_porch    = 28,
47
48         .vsync_len      = 1,
49         .vfront_porch   = 1,
50         .vback_porch    = 1,
51
52         .flags          = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
53                           DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
54                           DISPLAY_FLAGS_PIXDATA_POSEDGE,
55 };
56
57 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
58
59 static int sharp_ls_connect(struct omap_dss_device *dssdev)
60 {
61         struct panel_drv_data *ddata = to_panel_data(dssdev);
62         struct omap_dss_device *in = ddata->in;
63         int r;
64
65         if (omapdss_device_is_connected(dssdev))
66                 return 0;
67
68         r = in->ops.dpi->connect(in, dssdev);
69         if (r)
70                 return r;
71
72         return 0;
73 }
74
75 static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
76 {
77         struct panel_drv_data *ddata = to_panel_data(dssdev);
78         struct omap_dss_device *in = ddata->in;
79
80         if (!omapdss_device_is_connected(dssdev))
81                 return;
82
83         in->ops.dpi->disconnect(in, dssdev);
84 }
85
86 static int sharp_ls_enable(struct omap_dss_device *dssdev)
87 {
88         struct panel_drv_data *ddata = to_panel_data(dssdev);
89         struct omap_dss_device *in = ddata->in;
90         int r;
91
92         if (!omapdss_device_is_connected(dssdev))
93                 return -ENODEV;
94
95         if (omapdss_device_is_enabled(dssdev))
96                 return 0;
97
98         if (ddata->data_lines)
99                 in->ops.dpi->set_data_lines(in, ddata->data_lines);
100         in->ops.dpi->set_timings(in, &ddata->videomode);
101
102         if (ddata->vcc) {
103                 r = regulator_enable(ddata->vcc);
104                 if (r != 0)
105                         return r;
106         }
107
108         r = in->ops.dpi->enable(in);
109         if (r) {
110                 regulator_disable(ddata->vcc);
111                 return r;
112         }
113
114         /* wait couple of vsyncs until enabling the LCD */
115         msleep(50);
116
117         if (ddata->resb_gpio)
118                 gpiod_set_value_cansleep(ddata->resb_gpio, 1);
119
120         if (ddata->ini_gpio)
121                 gpiod_set_value_cansleep(ddata->ini_gpio, 1);
122
123         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
124
125         return 0;
126 }
127
128 static void sharp_ls_disable(struct omap_dss_device *dssdev)
129 {
130         struct panel_drv_data *ddata = to_panel_data(dssdev);
131         struct omap_dss_device *in = ddata->in;
132
133         if (!omapdss_device_is_enabled(dssdev))
134                 return;
135
136         if (ddata->ini_gpio)
137                 gpiod_set_value_cansleep(ddata->ini_gpio, 0);
138
139         if (ddata->resb_gpio)
140                 gpiod_set_value_cansleep(ddata->resb_gpio, 0);
141
142         /* wait at least 5 vsyncs after disabling the LCD */
143
144         msleep(100);
145
146         in->ops.dpi->disable(in);
147
148         if (ddata->vcc)
149                 regulator_disable(ddata->vcc);
150
151         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
152 }
153
154 static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
155                 struct omap_video_timings *timings)
156 {
157         struct panel_drv_data *ddata = to_panel_data(dssdev);
158         struct omap_dss_device *in = ddata->in;
159
160         ddata->videomode = *timings;
161         dssdev->panel.timings = *timings;
162
163         in->ops.dpi->set_timings(in, timings);
164 }
165
166 static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
167                 struct omap_video_timings *timings)
168 {
169         struct panel_drv_data *ddata = to_panel_data(dssdev);
170
171         *timings = ddata->videomode;
172 }
173
174 static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
175                 struct omap_video_timings *timings)
176 {
177         struct panel_drv_data *ddata = to_panel_data(dssdev);
178         struct omap_dss_device *in = ddata->in;
179
180         return in->ops.dpi->check_timings(in, timings);
181 }
182
183 static struct omap_dss_driver sharp_ls_ops = {
184         .connect        = sharp_ls_connect,
185         .disconnect     = sharp_ls_disconnect,
186
187         .enable         = sharp_ls_enable,
188         .disable        = sharp_ls_disable,
189
190         .set_timings    = sharp_ls_set_timings,
191         .get_timings    = sharp_ls_get_timings,
192         .check_timings  = sharp_ls_check_timings,
193
194         .get_resolution = omapdss_default_get_resolution,
195 };
196
197 static  int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
198         const char *desc, struct gpio_desc **gpiod)
199 {
200         struct gpio_desc *gd;
201
202         *gpiod = NULL;
203
204         gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW);
205         if (IS_ERR(gd))
206                 return PTR_ERR(gd);
207
208         *gpiod = gd;
209         return 0;
210 }
211
212 static int sharp_ls_probe_of(struct platform_device *pdev)
213 {
214         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
215         struct device_node *node = pdev->dev.of_node;
216         struct omap_dss_device *in;
217         int r;
218
219         ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");
220         if (IS_ERR(ddata->vcc)) {
221                 dev_err(&pdev->dev, "failed to get regulator\n");
222                 return PTR_ERR(ddata->vcc);
223         }
224
225         /* lcd INI */
226         r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio);
227         if (r)
228                 return r;
229
230         /* lcd RESB */
231         r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio);
232         if (r)
233                 return r;
234
235         /* lcd MO */
236         r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio);
237         if (r)
238                 return r;
239
240         /* lcd LR */
241         r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio);
242         if (r)
243                 return r;
244
245         /* lcd UD */
246         r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio);
247         if (r)
248                 return r;
249
250         in = omapdss_of_find_source_for_first_ep(node);
251         if (IS_ERR(in)) {
252                 dev_err(&pdev->dev, "failed to find video source\n");
253                 return PTR_ERR(in);
254         }
255
256         ddata->in = in;
257
258         return 0;
259 }
260
261 static int sharp_ls_probe(struct platform_device *pdev)
262 {
263         struct panel_drv_data *ddata;
264         struct omap_dss_device *dssdev;
265         int r;
266
267         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
268         if (ddata == NULL)
269                 return -ENOMEM;
270
271         platform_set_drvdata(pdev, ddata);
272
273         if (!pdev->dev.of_node)
274                 return -ENODEV;
275
276         r = sharp_ls_probe_of(pdev);
277         if (r)
278                 return r;
279
280         ddata->videomode = sharp_ls_timings;
281
282         dssdev = &ddata->dssdev;
283         dssdev->dev = &pdev->dev;
284         dssdev->driver = &sharp_ls_ops;
285         dssdev->type = OMAP_DISPLAY_TYPE_DPI;
286         dssdev->owner = THIS_MODULE;
287         dssdev->panel.timings = ddata->videomode;
288         dssdev->phy.dpi.data_lines = ddata->data_lines;
289
290         r = omapdss_register_display(dssdev);
291         if (r) {
292                 dev_err(&pdev->dev, "Failed to register panel\n");
293                 goto err_reg;
294         }
295
296         return 0;
297
298 err_reg:
299         omap_dss_put_device(ddata->in);
300         return r;
301 }
302
303 static int __exit sharp_ls_remove(struct platform_device *pdev)
304 {
305         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
306         struct omap_dss_device *dssdev = &ddata->dssdev;
307         struct omap_dss_device *in = ddata->in;
308
309         omapdss_unregister_display(dssdev);
310
311         sharp_ls_disable(dssdev);
312         sharp_ls_disconnect(dssdev);
313
314         omap_dss_put_device(in);
315
316         return 0;
317 }
318
319 static const struct of_device_id sharp_ls_of_match[] = {
320         { .compatible = "omapdss,sharp,ls037v7dw01", },
321         {},
322 };
323
324 MODULE_DEVICE_TABLE(of, sharp_ls_of_match);
325
326 static struct platform_driver sharp_ls_driver = {
327         .probe = sharp_ls_probe,
328         .remove = __exit_p(sharp_ls_remove),
329         .driver = {
330                 .name = "panel-sharp-ls037v7dw01",
331                 .of_match_table = sharp_ls_of_match,
332                 .suppress_bind_attrs = true,
333         },
334 };
335
336 module_platform_driver(sharp_ls_driver);
337
338 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
339 MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
340 MODULE_LICENSE("GPL");