blob: c17ba743792a4114e65689d09ca30a5b8142b281 [file] [log] [blame]
Bryan Wua9a62b62010-11-17 13:34:33 +00001/*
2 * Generic DPI Panels support
3 *
4 * Copyright (C) 2010 Canonical Ltd.
5 * Author: Bryan Wu <bryan.wu@canonical.com>
6 *
Bryan Wuac1427e2010-11-18 09:45:59 +08007 * 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 *
Bryan Wua9a62b62010-11-17 13:34:33 +000017 * 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>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030036#include <video/omapdss.h>
Bryan Wua9a62b62010-11-17 13:34:33 +000037
Tomi Valkeinenf8ae2f02011-05-10 19:48:10 +030038#include <video/omap-panel-generic-dpi.h>
Bryan Wua9a62b62010-11-17 13:34:33 +000039
40struct panel_config {
41 struct omap_video_timings timings;
42
43 int acbi; /* ac-bias pin transitions per interrupt */
44 /* Unit: line clocks */
45 int acb; /* ac-bias pin frequency */
46
47 enum omap_panel_config config;
48
49 int power_on_delay;
50 int power_off_delay;
51
52 /*
53 * Used to match device to panel configuration
54 * when use generic panel driver
55 */
56 const char *name;
57};
58
59/* Panel configurations */
60static struct panel_config generic_dpi_panels[] = {
Bryan Wua9a62b62010-11-17 13:34:33 +000061 /* Sharp LQ043T1DG01 */
62 {
63 {
64 .x_res = 480,
65 .y_res = 272,
66
67 .pixel_clock = 9000,
68
69 .hsw = 42,
70 .hfp = 3,
71 .hbp = 2,
72
73 .vsw = 11,
74 .vfp = 3,
75 .vbp = 2,
76 },
77 .acbi = 0x0,
78 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +053079 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
80 OMAP_DSS_LCD_IEO,
Bryan Wua9a62b62010-11-17 13:34:33 +000081 .power_on_delay = 50,
82 .power_off_delay = 100,
83 .name = "sharp_lq",
84 },
85
86 /* Sharp LS037V7DW01 */
87 {
88 {
89 .x_res = 480,
90 .y_res = 640,
91
92 .pixel_clock = 19200,
93
94 .hsw = 2,
95 .hfp = 1,
96 .hbp = 28,
97
98 .vsw = 1,
99 .vfp = 1,
100 .vbp = 1,
101 },
102 .acbi = 0x0,
103 .acb = 0x28,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530104 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Bryan Wua9a62b62010-11-17 13:34:33 +0000105 .power_on_delay = 50,
106 .power_off_delay = 100,
107 .name = "sharp_ls",
108 },
109
110 /* Toppoly TDO35S */
111 {
112 {
113 .x_res = 480,
114 .y_res = 640,
115
116 .pixel_clock = 26000,
117
118 .hfp = 104,
119 .hsw = 8,
120 .hbp = 8,
121
122 .vfp = 4,
123 .vsw = 2,
124 .vbp = 2,
125 },
126 .acbi = 0x0,
127 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530128 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
129 OMAP_DSS_LCD_IPC |
130 OMAP_DSS_LCD_ONOFF,
Bryan Wua9a62b62010-11-17 13:34:33 +0000131 .power_on_delay = 0,
132 .power_off_delay = 0,
133 .name = "toppoly_tdo35s",
134 },
Tomi Valkeinen09dc89c2011-02-22 16:39:47 +0200135
136 /* Samsung LTE430WQ-F0C */
137 {
138 {
139 .x_res = 480,
140 .y_res = 272,
141
142 .pixel_clock = 9200,
143
144 .hfp = 8,
145 .hsw = 41,
146 .hbp = 45 - 41,
147
148 .vfp = 4,
149 .vsw = 10,
150 .vbp = 12 - 10,
151 },
152 .acbi = 0x0,
153 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530154 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Tomi Valkeinen09dc89c2011-02-22 16:39:47 +0200155 .power_on_delay = 0,
156 .power_off_delay = 0,
157 .name = "samsung_lte430wq_f0c",
158 },
Enric Balletbo i Serra50ca19d2011-05-03 09:07:36 +0200159
160 /* Seiko 70WVW1TZ3Z3 */
161 {
162 {
163 .x_res = 800,
164 .y_res = 480,
165
166 .pixel_clock = 33000,
167
168 .hsw = 128,
169 .hfp = 10,
170 .hbp = 10,
171
172 .vsw = 2,
173 .vfp = 4,
174 .vbp = 11,
175 },
176 .acbi = 0x0,
177 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530178 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Enric Balletbo i Serra50ca19d2011-05-03 09:07:36 +0200179 .power_on_delay = 0,
180 .power_off_delay = 0,
181 .name = "seiko_70wvw1tz3",
182 },
Enric Balletbo i Serraa0ce4cc2011-05-03 09:07:37 +0200183
184 /* Powertip PH480272T */
185 {
186 {
187 .x_res = 480,
188 .y_res = 272,
189
190 .pixel_clock = 9000,
191
192 .hsw = 40,
193 .hfp = 2,
194 .hbp = 2,
195
196 .vsw = 10,
197 .vfp = 2,
198 .vbp = 2,
199 },
200 .acbi = 0x0,
201 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530202 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
203 OMAP_DSS_LCD_IEO,
Enric Balletbo i Serraa0ce4cc2011-05-03 09:07:37 +0200204 .power_on_delay = 0,
205 .power_off_delay = 0,
206 .name = "powertip_ph480272t",
207 },
Thomas Weber1e497c42011-09-01 15:05:07 +0200208
209 /* Innolux AT070TN83 */
210 {
211 {
212 .x_res = 800,
213 .y_res = 480,
214
215 .pixel_clock = 40000,
216
217 .hsw = 48,
218 .hfp = 1,
219 .hbp = 1,
220
221 .vsw = 3,
222 .vfp = 12,
223 .vbp = 25,
224 },
225 .acbi = 0x0,
226 .acb = 0x28,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530227 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Thomas Weber1e497c42011-09-01 15:05:07 +0200228 .power_on_delay = 0,
229 .power_off_delay = 0,
230 .name = "innolux_at070tn83",
231 },
Tomi Valkeinen3fddbf52011-04-19 19:23:05 +0300232
233 /* NEC NL2432DR22-11B */
234 {
235 {
236 .x_res = 240,
237 .y_res = 320,
238
239 .pixel_clock = 5400,
240
241 .hsw = 3,
242 .hfp = 3,
243 .hbp = 39,
244
245 .vsw = 1,
246 .vfp = 2,
247 .vbp = 7,
248 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530249 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Tomi Valkeinen3fddbf52011-04-19 19:23:05 +0300250 .name = "nec_nl2432dr22-11b",
251 },
Tomi Valkeinen8a41ba92011-04-19 19:59:58 +0300252
253 /* Unknown panel used in OMAP H4 */
254 {
255 {
256 .x_res = 240,
257 .y_res = 320,
258
259 .pixel_clock = 6250,
260
261 .hsw = 15,
262 .hfp = 15,
263 .hbp = 60,
264
265 .vsw = 1,
266 .vfp = 1,
267 .vbp = 1,
268 },
Tomi Valkeinen8a41ba92011-04-19 19:59:58 +0300269 .name = "h4",
270 },
Tomi Valkeinen8d49fe72011-04-20 10:47:28 +0300271
272 /* Unknown panel used in Samsung OMAP2 Apollon */
273 {
274 {
275 .x_res = 480,
276 .y_res = 272,
277
278 .pixel_clock = 6250,
279
280 .hsw = 41,
281 .hfp = 2,
282 .hbp = 2,
283
284 .vsw = 10,
285 .vfp = 2,
286 .vbp = 2,
287 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530288 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Tomi Valkeinen8d49fe72011-04-20 10:47:28 +0300289
290 .name = "apollon",
291 },
Ilya Yanoka47161a2011-11-20 19:15:39 +0100292 /* FocalTech ETM070003DH6 */
293 {
294 {
295 .x_res = 800,
296 .y_res = 480,
297
298 .pixel_clock = 28000,
299
300 .hsw = 48,
301 .hfp = 40,
302 .hbp = 40,
303
304 .vsw = 3,
305 .vfp = 13,
306 .vbp = 29,
307 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530308 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
Ilya Yanoka47161a2011-11-20 19:15:39 +0100309 .name = "focaltech_etm070003dh6",
310 },
Daniel Mack62941ec2011-12-20 10:54:32 +0100311
312 /* Microtips Technologies - UMSH-8173MD */
313 {
314 {
315 .x_res = 800,
316 .y_res = 480,
317
318 .pixel_clock = 34560,
319
320 .hsw = 13,
321 .hfp = 101,
322 .hbp = 101,
323
324 .vsw = 23,
325 .vfp = 1,
326 .vbp = 1,
327 },
328 .acbi = 0x0,
329 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530330 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
331 OMAP_DSS_LCD_IPC,
Daniel Mack62941ec2011-12-20 10:54:32 +0100332 .power_on_delay = 0,
333 .power_off_delay = 0,
334 .name = "microtips_umsh_8173md",
335 },
Ilya Yanok6acea9c2011-12-26 23:56:41 +0100336
337 /* OrtusTech COM43H4M10XTC */
338 {
339 {
340 .x_res = 480,
341 .y_res = 272,
342
343 .pixel_clock = 8000,
344
345 .hsw = 41,
346 .hfp = 8,
347 .hbp = 4,
348
349 .vsw = 10,
350 .vfp = 4,
351 .vbp = 2,
352 },
Ilya Yanok6acea9c2011-12-26 23:56:41 +0100353 .name = "ortustech_com43h4m10xtc",
354 },
Yegor Yefremov992ee642012-02-08 11:11:08 +0100355
356 /* Innolux AT080TN52 */
357 {
358 {
359 .x_res = 800,
360 .y_res = 600,
361
362 .pixel_clock = 41142,
363
364 .hsw = 20,
365 .hfp = 210,
366 .hbp = 46,
367
368 .vsw = 10,
369 .vfp = 12,
370 .vbp = 23,
371 },
372 .acb = 0x0,
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530373 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
374 OMAP_DSS_LCD_IEO,
Yegor Yefremov992ee642012-02-08 11:11:08 +0100375
376 .name = "innolux_at080tn52",
377 },
Thomas Weber697bacb2012-02-17 13:41:58 +0100378
379 /* Mitsubishi AA084SB01 */
380 {
381 {
382 .x_res = 800,
383 .y_res = 600,
384 .pixel_clock = 40000,
385
386 .hsw = 1,
387 .hfp = 254,
388 .hbp = 1,
389
390 .vsw = 1,
391 .vfp = 26,
392 .vbp = 1,
393 },
Thomas Weber697bacb2012-02-17 13:41:58 +0100394 .name = "mitsubishi_aa084sb01",
395 },
Thomas Webere97374c2012-02-17 13:41:59 +0100396 /* EDT ET0500G0DH6 */
397 {
398 {
399 .x_res = 800,
400 .y_res = 480,
401 .pixel_clock = 33260,
402
403 .hsw = 128,
404 .hfp = 216,
405 .hbp = 40,
406
407 .vsw = 2,
408 .vfp = 35,
409 .vbp = 10,
410 },
Thomas Webere97374c2012-02-17 13:41:59 +0100411 .name = "edt_et0500g0dh6",
412 },
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200413
414 /* Prime-View PD050VL1 */
415 {
416 {
417 .x_res = 640,
418 .y_res = 480,
419
420 .pixel_clock = 25000,
421
422 .hsw = 96,
423 .hfp = 18,
424 .hbp = 46,
425
426 .vsw = 2,
427 .vfp = 10,
428 .vbp = 33,
429 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530430 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
431 OMAP_DSS_LCD_IPC,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200432 .name = "primeview_pd050vl1",
433 },
434
435 /* Prime-View PM070WL4 */
436 {
437 {
438 .x_res = 800,
439 .y_res = 480,
440
441 .pixel_clock = 32000,
442
443 .hsw = 128,
444 .hfp = 42,
445 .hbp = 86,
446
447 .vsw = 2,
448 .vfp = 10,
449 .vbp = 33,
450 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530451 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
452 OMAP_DSS_LCD_IPC,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200453 .name = "primeview_pm070wl4",
454 },
455
456 /* Prime-View PD104SLF */
457 {
458 {
459 .x_res = 800,
460 .y_res = 600,
461
462 .pixel_clock = 40000,
463
464 .hsw = 128,
465 .hfp = 42,
466 .hbp = 86,
467
468 .vsw = 4,
469 .vfp = 1,
470 .vbp = 23,
471 },
Archit Taneja5ae9eaa2012-06-21 09:41:10 +0530472 .config = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
473 OMAP_DSS_LCD_IPC,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200474 .name = "primeview_pd104slf",
475 },
Bryan Wua9a62b62010-11-17 13:34:33 +0000476};
477
478struct panel_drv_data {
479
480 struct omap_dss_device *dssdev;
481
482 struct panel_config *panel_config;
483};
484
485static inline struct panel_generic_dpi_data
486*get_panel_data(const struct omap_dss_device *dssdev)
487{
488 return (struct panel_generic_dpi_data *) dssdev->data;
489}
490
491static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
492{
493 int r;
494 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
495 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
496 struct panel_config *panel_config = drv_data->panel_config;
497
498 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
499 return 0;
500
501 r = omapdss_dpi_display_enable(dssdev);
502 if (r)
503 goto err0;
504
505 /* wait couple of vsyncs until enabling the LCD */
506 if (panel_config->power_on_delay)
507 msleep(panel_config->power_on_delay);
508
509 if (panel_data->platform_enable) {
510 r = panel_data->platform_enable(dssdev);
511 if (r)
512 goto err1;
513 }
514
515 return 0;
516err1:
517 omapdss_dpi_display_disable(dssdev);
518err0:
519 return r;
520}
521
522static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
523{
524 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
525 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
526 struct panel_config *panel_config = drv_data->panel_config;
527
528 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
529 return;
530
531 if (panel_data->platform_disable)
532 panel_data->platform_disable(dssdev);
533
534 /* wait couple of vsyncs after disabling the LCD */
535 if (panel_config->power_off_delay)
536 msleep(panel_config->power_off_delay);
537
538 omapdss_dpi_display_disable(dssdev);
539}
540
541static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
542{
543 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
544 struct panel_config *panel_config = NULL;
545 struct panel_drv_data *drv_data = NULL;
546 int i;
547
548 dev_dbg(&dssdev->dev, "probe\n");
549
550 if (!panel_data || !panel_data->name)
551 return -EINVAL;
552
553 for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
554 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
555 panel_config = &generic_dpi_panels[i];
556 break;
557 }
558 }
559
560 if (!panel_config)
561 return -EINVAL;
562
563 dssdev->panel.config = panel_config->config;
564 dssdev->panel.timings = panel_config->timings;
565 dssdev->panel.acb = panel_config->acb;
566 dssdev->panel.acbi = panel_config->acbi;
567
568 drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
569 if (!drv_data)
570 return -ENOMEM;
571
572 drv_data->dssdev = dssdev;
573 drv_data->panel_config = panel_config;
574
575 dev_set_drvdata(&dssdev->dev, drv_data);
576
577 return 0;
578}
579
Tomi Valkeinen14e4d782011-03-31 12:03:51 +0300580static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
Bryan Wua9a62b62010-11-17 13:34:33 +0000581{
582 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
583
584 dev_dbg(&dssdev->dev, "remove\n");
585
586 kfree(drv_data);
587
588 dev_set_drvdata(&dssdev->dev, NULL);
589}
590
591static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
592{
593 int r = 0;
594
595 r = generic_dpi_panel_power_on(dssdev);
596 if (r)
597 return r;
598
599 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
600
601 return 0;
602}
603
604static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
605{
606 generic_dpi_panel_power_off(dssdev);
607
608 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
609}
610
611static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
612{
613 generic_dpi_panel_power_off(dssdev);
614
615 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
616
617 return 0;
618}
619
620static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
621{
622 int r = 0;
623
624 r = generic_dpi_panel_power_on(dssdev);
625 if (r)
626 return r;
627
628 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
629
630 return 0;
631}
632
633static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
634 struct omap_video_timings *timings)
635{
636 dpi_set_timings(dssdev, timings);
637}
638
Bryan Wua9a62b62010-11-17 13:34:33 +0000639static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
640 struct omap_video_timings *timings)
641{
642 return dpi_check_timings(dssdev, timings);
643}
644
645static struct omap_dss_driver dpi_driver = {
646 .probe = generic_dpi_panel_probe,
Tomi Valkeinen14e4d782011-03-31 12:03:51 +0300647 .remove = __exit_p(generic_dpi_panel_remove),
Bryan Wua9a62b62010-11-17 13:34:33 +0000648
649 .enable = generic_dpi_panel_enable,
650 .disable = generic_dpi_panel_disable,
651 .suspend = generic_dpi_panel_suspend,
652 .resume = generic_dpi_panel_resume,
653
654 .set_timings = generic_dpi_panel_set_timings,
Bryan Wua9a62b62010-11-17 13:34:33 +0000655 .check_timings = generic_dpi_panel_check_timings,
656
657 .driver = {
658 .name = "generic_dpi_panel",
659 .owner = THIS_MODULE,
660 },
661};
662
663static int __init generic_dpi_panel_drv_init(void)
664{
665 return omap_dss_register_driver(&dpi_driver);
666}
667
668static void __exit generic_dpi_panel_drv_exit(void)
669{
670 omap_dss_unregister_driver(&dpi_driver);
671}
672
673module_init(generic_dpi_panel_drv_init);
674module_exit(generic_dpi_panel_drv_exit);
675MODULE_LICENSE("GPL");