ARM: debug: qcom: add UART addresses to Kconfig help for APQ8084
[pandora-kernel.git] / drivers / video / fbdev / omap2 / displays-new / 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.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17
18 #include <video/omapdss.h>
19 #include <video/omap-panel-data.h>
20
21 struct panel_drv_data {
22         struct omap_dss_device dssdev;
23         struct omap_dss_device *in;
24
25         int data_lines;
26
27         struct omap_video_timings videomode;
28
29         int resb_gpio;
30         int ini_gpio;
31         int mo_gpio;
32         int lr_gpio;
33         int ud_gpio;
34 };
35
36 static const struct omap_video_timings sharp_ls_timings = {
37         .x_res = 480,
38         .y_res = 640,
39
40         .pixelclock     = 19200000,
41
42         .hsw            = 2,
43         .hfp            = 1,
44         .hbp            = 28,
45
46         .vsw            = 1,
47         .vfp            = 1,
48         .vbp            = 1,
49
50         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
51         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
52         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
53         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
54         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
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         in->ops.dpi->set_data_lines(in, ddata->data_lines);
99         in->ops.dpi->set_timings(in, &ddata->videomode);
100
101         r = in->ops.dpi->enable(in);
102         if (r)
103                 return r;
104
105         /* wait couple of vsyncs until enabling the LCD */
106         msleep(50);
107
108         if (gpio_is_valid(ddata->resb_gpio))
109                 gpio_set_value_cansleep(ddata->resb_gpio, 1);
110
111         if (gpio_is_valid(ddata->ini_gpio))
112                 gpio_set_value_cansleep(ddata->ini_gpio, 1);
113
114         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
115
116         return 0;
117 }
118
119 static void sharp_ls_disable(struct omap_dss_device *dssdev)
120 {
121         struct panel_drv_data *ddata = to_panel_data(dssdev);
122         struct omap_dss_device *in = ddata->in;
123
124         if (!omapdss_device_is_enabled(dssdev))
125                 return;
126
127         if (gpio_is_valid(ddata->ini_gpio))
128                 gpio_set_value_cansleep(ddata->ini_gpio, 0);
129
130         if (gpio_is_valid(ddata->resb_gpio))
131                 gpio_set_value_cansleep(ddata->resb_gpio, 0);
132
133         /* wait at least 5 vsyncs after disabling the LCD */
134
135         msleep(100);
136
137         in->ops.dpi->disable(in);
138
139         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
140 }
141
142 static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
143                 struct omap_video_timings *timings)
144 {
145         struct panel_drv_data *ddata = to_panel_data(dssdev);
146         struct omap_dss_device *in = ddata->in;
147
148         ddata->videomode = *timings;
149         dssdev->panel.timings = *timings;
150
151         in->ops.dpi->set_timings(in, timings);
152 }
153
154 static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
155                 struct omap_video_timings *timings)
156 {
157         struct panel_drv_data *ddata = to_panel_data(dssdev);
158
159         *timings = ddata->videomode;
160 }
161
162 static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
163                 struct omap_video_timings *timings)
164 {
165         struct panel_drv_data *ddata = to_panel_data(dssdev);
166         struct omap_dss_device *in = ddata->in;
167
168         return in->ops.dpi->check_timings(in, timings);
169 }
170
171 static struct omap_dss_driver sharp_ls_ops = {
172         .connect        = sharp_ls_connect,
173         .disconnect     = sharp_ls_disconnect,
174
175         .enable         = sharp_ls_enable,
176         .disable        = sharp_ls_disable,
177
178         .set_timings    = sharp_ls_set_timings,
179         .get_timings    = sharp_ls_get_timings,
180         .check_timings  = sharp_ls_check_timings,
181
182         .get_resolution = omapdss_default_get_resolution,
183 };
184
185 static int sharp_ls_probe_pdata(struct platform_device *pdev)
186 {
187         const struct panel_sharp_ls037v7dw01_platform_data *pdata;
188         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
189         struct omap_dss_device *dssdev, *in;
190
191         pdata = dev_get_platdata(&pdev->dev);
192
193         in = omap_dss_find_output(pdata->source);
194         if (in == NULL) {
195                 dev_err(&pdev->dev, "failed to find video source '%s'\n",
196                                 pdata->source);
197                 return -EPROBE_DEFER;
198         }
199
200         ddata->in = in;
201
202         ddata->data_lines = pdata->data_lines;
203
204         dssdev = &ddata->dssdev;
205         dssdev->name = pdata->name;
206
207         ddata->resb_gpio = pdata->resb_gpio;
208         ddata->ini_gpio = pdata->ini_gpio;
209         ddata->mo_gpio = pdata->mo_gpio;
210         ddata->lr_gpio = pdata->lr_gpio;
211         ddata->ud_gpio = pdata->ud_gpio;
212
213         return 0;
214 }
215
216 static int sharp_ls_probe(struct platform_device *pdev)
217 {
218         struct panel_drv_data *ddata;
219         struct omap_dss_device *dssdev;
220         int r;
221
222         ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
223         if (ddata == NULL)
224                 return -ENOMEM;
225
226         platform_set_drvdata(pdev, ddata);
227
228         if (dev_get_platdata(&pdev->dev)) {
229                 r = sharp_ls_probe_pdata(pdev);
230                 if (r)
231                         return r;
232         } else {
233                 return -ENODEV;
234         }
235
236         if (gpio_is_valid(ddata->mo_gpio)) {
237                 r = devm_gpio_request_one(&pdev->dev, ddata->mo_gpio,
238                                 GPIOF_OUT_INIT_LOW, "lcd MO");
239                 if (r)
240                         goto err_gpio;
241         }
242
243         if (gpio_is_valid(ddata->lr_gpio)) {
244                 r = devm_gpio_request_one(&pdev->dev, ddata->lr_gpio,
245                                 GPIOF_OUT_INIT_HIGH, "lcd LR");
246                 if (r)
247                         goto err_gpio;
248         }
249
250         if (gpio_is_valid(ddata->ud_gpio)) {
251                 r = devm_gpio_request_one(&pdev->dev, ddata->ud_gpio,
252                                 GPIOF_OUT_INIT_HIGH, "lcd UD");
253                 if (r)
254                         goto err_gpio;
255         }
256
257         if (gpio_is_valid(ddata->resb_gpio)) {
258                 r = devm_gpio_request_one(&pdev->dev, ddata->resb_gpio,
259                                 GPIOF_OUT_INIT_LOW, "lcd RESB");
260                 if (r)
261                         goto err_gpio;
262         }
263
264         if (gpio_is_valid(ddata->ini_gpio)) {
265                 r = devm_gpio_request_one(&pdev->dev, ddata->ini_gpio,
266                                 GPIOF_OUT_INIT_LOW, "lcd INI");
267                 if (r)
268                         goto err_gpio;
269         }
270
271         ddata->videomode = sharp_ls_timings;
272
273         dssdev = &ddata->dssdev;
274         dssdev->dev = &pdev->dev;
275         dssdev->driver = &sharp_ls_ops;
276         dssdev->type = OMAP_DISPLAY_TYPE_DPI;
277         dssdev->owner = THIS_MODULE;
278         dssdev->panel.timings = ddata->videomode;
279         dssdev->phy.dpi.data_lines = ddata->data_lines;
280
281         r = omapdss_register_display(dssdev);
282         if (r) {
283                 dev_err(&pdev->dev, "Failed to register panel\n");
284                 goto err_reg;
285         }
286
287         return 0;
288
289 err_reg:
290 err_gpio:
291         omap_dss_put_device(ddata->in);
292         return r;
293 }
294
295 static int __exit sharp_ls_remove(struct platform_device *pdev)
296 {
297         struct panel_drv_data *ddata = platform_get_drvdata(pdev);
298         struct omap_dss_device *dssdev = &ddata->dssdev;
299         struct omap_dss_device *in = ddata->in;
300
301         omapdss_unregister_display(dssdev);
302
303         sharp_ls_disable(dssdev);
304         sharp_ls_disconnect(dssdev);
305
306         omap_dss_put_device(in);
307
308         return 0;
309 }
310
311 static struct platform_driver sharp_ls_driver = {
312         .probe = sharp_ls_probe,
313         .remove = __exit_p(sharp_ls_remove),
314         .driver = {
315                 .name = "panel-sharp-ls037v7dw01",
316                 .owner = THIS_MODULE,
317         },
318 };
319
320 module_platform_driver(sharp_ls_driver);
321
322 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
323 MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver");
324 MODULE_LICENSE("GPL");