1 /*
2 * Generic DPI Panels support
3 *
4 * Copyright (C) 2010 Canonical Ltd.
5 * Author: Bryan Wu <bryan.wu@canonical.com>
6 *
7 * LCD panel driver for Sharp LQ043T1DG01
8 *
9 * Copyright (C) 2009 Texas Instruments Inc
10 * Author: Vaibhav Hiremath <hvaibhav@ti.com>
11 *
12 * LCD panel driver for Toppoly TDO35S
13 *
14 * Copyright (C) 2009 CompuLab, Ltd.
15 * Author: Mike Rapoport <mike@compulab.co.il>
16 *
17 * Copyright (C) 2008 Nokia Corporation
18 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
19 *
20 * This program is free software; you can redistribute it and/or modify it
21 * under the terms of the GNU General Public License version 2 as published by
22 * the Free Software Foundation.
23 *
24 * This program is distributed in the hope that it will be useful, but WITHOUT
25 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
27 * more details.
28 *
29 * You should have received a copy of the GNU General Public License along with
30 * this program. If not, see <http://www.gnu.org/licenses/>.
31 */
32
33 #include <linux/module.h>
34 #include <linux/delay.h>
35 #include <linux/slab.h>
36
37 #include <plat/panel-generic-dpi.h>
38
39 struct panel_config {
40 struct omap_video_timings timings;
41
42 int acbi; /* ac-bias pin transitions per interrupt */
43 /* Unit: line clocks */
44 int acb; /* ac-bias pin frequency */
45
46 enum omap_panel_config config;
47
48 int power_on_delay;
49 int power_off_delay;
50
51 /*
52 * Used to match device to panel configuration
53 * when use generic panel driver
54 */
55 const char *name;
56 };
57
58 /* Panel configurations */
59 static struct panel_config generic_dpi_panels[] = {
60 /* Generic Panel */
61 {
62 {
63 .x_res = 640,
64 .y_res = 480,
65
66 .pixel_clock = 23500,
67
68 .hfp = 48,
69 .hsw = 32,
70 .hbp = 80,
71
72 .vfp = 3,
73 .vsw = 4,
74 .vbp = 7,
75 },
76 .acbi = 0x0,
77 .acb = 0x0,
78 .config = OMAP_DSS_LCD_TFT,
79 .power_on_delay = 0,
80 .power_off_delay = 0,
81 .name = "generic",
82 },
83
84 /* Sharp LQ043T1DG01 */
85 {
86 {
87 .x_res = 480,
88 .y_res = 272,
89
90 .pixel_clock = 9000,
91
92 .hsw = 42,
93 .hfp = 3,
94 .hbp = 2,
95
96 .vsw = 11,
97 .vfp = 3,
98 .vbp = 2,
99 },
100 .acbi = 0x0,
101 .acb = 0x0,
102 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
103 OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
104 .power_on_delay = 50,
105 .power_off_delay = 100,
106 .name = "sharp_lq",
107 },
108
109 /* Sharp LS037V7DW01 */
110 {
111 {
112 .x_res = 480,
113 .y_res = 640,
114
115 .pixel_clock = 19200,
116
117 .hsw = 2,
118 .hfp = 1,
119 .hbp = 28,
120
121 .vsw = 1,
122 .vfp = 1,
123 .vbp = 1,
124 },
125 .acbi = 0x0,
126 .acb = 0x28,
127 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
128 OMAP_DSS_LCD_IHS,
129 .power_on_delay = 50,
130 .power_off_delay = 100,
131 .name = "sharp_ls",
132 },
133
134 /* Toppoly TDO35S */
135 {
136 {
137 .x_res = 480,
138 .y_res = 640,
139
140 .pixel_clock = 26000,
141
142 .hfp = 104,
143 .hsw = 8,
144 .hbp = 8,
145
146 .vfp = 4,
147 .vsw = 2,
148 .vbp = 2,
149 },
150 .acbi = 0x0,
151 .acb = 0x0,
152 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
153 OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
154 OMAP_DSS_LCD_ONOFF,
155 .power_on_delay = 0,
156 .power_off_delay = 0,
157 .name = "toppoly_tdo35s",
158 },
159
160 /* Samsung LTE430WQ-F0C */
161 {
162 {
163 .x_res = 480,
164 .y_res = 272,
165
166 .pixel_clock = 9200,
167
168 .hfp = 8,
169 .hsw = 41,
170 .hbp = 45 - 41,
171
172 .vfp = 4,
173 .vsw = 10,
174 .vbp = 12 - 10,
175 },
176 .acbi = 0x0,
177 .acb = 0x0,
178 .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
179 OMAP_DSS_LCD_IHS,
180 .power_on_delay = 0,
181 .power_off_delay = 0,
182 .name = "samsung_lte430wq_f0c",
183 },
184 };
185
186 struct panel_drv_data {
187
188 struct omap_dss_device *dssdev;
189
190 struct panel_config *panel_config;
191 };
192
193 static inline struct panel_generic_dpi_data
get_panel_data(const struct omap_dss_device * dssdev)194 *get_panel_data(const struct omap_dss_device *dssdev)
195 {
196 return (struct panel_generic_dpi_data *) dssdev->data;
197 }
198
generic_dpi_panel_power_on(struct omap_dss_device * dssdev)199 static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
200 {
201 int r;
202 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
203 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
204 struct panel_config *panel_config = drv_data->panel_config;
205
206 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
207 return 0;
208
209 r = omapdss_dpi_display_enable(dssdev);
210 if (r)
211 goto err0;
212
213 /* wait couple of vsyncs until enabling the LCD */
214 if (panel_config->power_on_delay)
215 msleep(panel_config->power_on_delay);
216
217 if (panel_data->platform_enable) {
218 r = panel_data->platform_enable(dssdev);
219 if (r)
220 goto err1;
221 }
222
223 return 0;
224 err1:
225 omapdss_dpi_display_disable(dssdev);
226 err0:
227 return r;
228 }
229
generic_dpi_panel_power_off(struct omap_dss_device * dssdev)230 static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
231 {
232 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
233 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
234 struct panel_config *panel_config = drv_data->panel_config;
235
236 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
237 return;
238
239 if (panel_data->platform_disable)
240 panel_data->platform_disable(dssdev);
241
242 /* wait couple of vsyncs after disabling the LCD */
243 if (panel_config->power_off_delay)
244 msleep(panel_config->power_off_delay);
245
246 omapdss_dpi_display_disable(dssdev);
247 }
248
generic_dpi_panel_probe(struct omap_dss_device * dssdev)249 static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
250 {
251 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
252 struct panel_config *panel_config = NULL;
253 struct panel_drv_data *drv_data = NULL;
254 int i;
255
256 dev_dbg(&dssdev->dev, "probe\n");
257
258 if (!panel_data || !panel_data->name)
259 return -EINVAL;
260
261 for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
262 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
263 panel_config = &generic_dpi_panels[i];
264 break;
265 }
266 }
267
268 if (!panel_config)
269 return -EINVAL;
270
271 dssdev->panel.config = panel_config->config;
272 dssdev->panel.timings = panel_config->timings;
273 dssdev->panel.acb = panel_config->acb;
274 dssdev->panel.acbi = panel_config->acbi;
275
276 drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
277 if (!drv_data)
278 return -ENOMEM;
279
280 drv_data->dssdev = dssdev;
281 drv_data->panel_config = panel_config;
282
283 dev_set_drvdata(&dssdev->dev, drv_data);
284
285 return 0;
286 }
287
generic_dpi_panel_remove(struct omap_dss_device * dssdev)288 static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
289 {
290 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
291
292 dev_dbg(&dssdev->dev, "remove\n");
293
294 kfree(drv_data);
295
296 dev_set_drvdata(&dssdev->dev, NULL);
297 }
298
generic_dpi_panel_enable(struct omap_dss_device * dssdev)299 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
300 {
301 int r = 0;
302
303 r = generic_dpi_panel_power_on(dssdev);
304 if (r)
305 return r;
306
307 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
308
309 return 0;
310 }
311
generic_dpi_panel_disable(struct omap_dss_device * dssdev)312 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
313 {
314 generic_dpi_panel_power_off(dssdev);
315
316 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
317 }
318
generic_dpi_panel_suspend(struct omap_dss_device * dssdev)319 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
320 {
321 generic_dpi_panel_power_off(dssdev);
322
323 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
324
325 return 0;
326 }
327
generic_dpi_panel_resume(struct omap_dss_device * dssdev)328 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
329 {
330 int r = 0;
331
332 r = generic_dpi_panel_power_on(dssdev);
333 if (r)
334 return r;
335
336 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
337
338 return 0;
339 }
340
generic_dpi_panel_set_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)341 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
342 struct omap_video_timings *timings)
343 {
344 dpi_set_timings(dssdev, timings);
345 }
346
generic_dpi_panel_get_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)347 static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
348 struct omap_video_timings *timings)
349 {
350 *timings = dssdev->panel.timings;
351 }
352
generic_dpi_panel_check_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)353 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
354 struct omap_video_timings *timings)
355 {
356 return dpi_check_timings(dssdev, timings);
357 }
358
359 static struct omap_dss_driver dpi_driver = {
360 .probe = generic_dpi_panel_probe,
361 .remove = generic_dpi_panel_remove,
362
363 .enable = generic_dpi_panel_enable,
364 .disable = generic_dpi_panel_disable,
365 .suspend = generic_dpi_panel_suspend,
366 .resume = generic_dpi_panel_resume,
367
368 .set_timings = generic_dpi_panel_set_timings,
369 .get_timings = generic_dpi_panel_get_timings,
370 .check_timings = generic_dpi_panel_check_timings,
371
372 .driver = {
373 .name = "generic_dpi_panel",
374 .owner = THIS_MODULE,
375 },
376 };
377
generic_dpi_panel_drv_init(void)378 static int __init generic_dpi_panel_drv_init(void)
379 {
380 return omap_dss_register_driver(&dpi_driver);
381 }
382
generic_dpi_panel_drv_exit(void)383 static void __exit generic_dpi_panel_drv_exit(void)
384 {
385 omap_dss_unregister_driver(&dpi_driver);
386 }
387
388 module_init(generic_dpi_panel_drv_init);
389 module_exit(generic_dpi_panel_drv_exit);
390 MODULE_LICENSE("GPL");
391