c17ba743792a4114e65689d09ca30a5b8142b281
[linux-3.10.git] / drivers / video / omap2 / displays / panel-generic-dpi.c
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 #include <video/omapdss.h>
37
38 #include <video/omap-panel-generic-dpi.h>
39
40 struct 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 */
60 static struct panel_config generic_dpi_panels[] = {
61         /* 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,
79                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
80                                                 OMAP_DSS_LCD_IEO,
81                 .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,
104                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
105                 .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,
128                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
129                                                 OMAP_DSS_LCD_IPC |
130                                                 OMAP_DSS_LCD_ONOFF,
131                 .power_on_delay         = 0,
132                 .power_off_delay        = 0,
133                 .name                   = "toppoly_tdo35s",
134         },
135
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,
154                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
155                 .power_on_delay         = 0,
156                 .power_off_delay        = 0,
157                 .name                   = "samsung_lte430wq_f0c",
158         },
159
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,
178                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
179                 .power_on_delay         = 0,
180                 .power_off_delay        = 0,
181                 .name                   = "seiko_70wvw1tz3",
182         },
183
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,
202                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
203                                                 OMAP_DSS_LCD_IEO,
204                 .power_on_delay         = 0,
205                 .power_off_delay        = 0,
206                 .name                   = "powertip_ph480272t",
207         },
208
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,
227                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
228                 .power_on_delay         = 0,
229                 .power_off_delay        = 0,
230                 .name                   = "innolux_at070tn83",
231         },
232
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                 },
249                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
250                 .name                   = "nec_nl2432dr22-11b",
251         },
252
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                 },
269                 .name                   = "h4",
270         },
271
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                 },
288                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
289
290                 .name                   = "apollon",
291         },
292         /* 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                 },
308                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS,
309                 .name                   = "focaltech_etm070003dh6",
310         },
311
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,
330                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
331                                                 OMAP_DSS_LCD_IPC,
332                 .power_on_delay         = 0,
333                 .power_off_delay        = 0,
334                 .name                   = "microtips_umsh_8173md",
335         },
336
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                 },
353                 .name                   = "ortustech_com43h4m10xtc",
354         },
355
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,
373                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
374                                                 OMAP_DSS_LCD_IEO,
375
376                 .name                   = "innolux_at080tn52",
377         },
378
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                 },
394                 .name                   = "mitsubishi_aa084sb01",
395         },
396         /* 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                 },
411                 .name                   = "edt_et0500g0dh6",
412         },
413
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                 },
430                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
431                                                 OMAP_DSS_LCD_IPC,
432                 .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                 },
451                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
452                                                 OMAP_DSS_LCD_IPC,
453                 .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                 },
472                 .config                 = OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS |
473                                                 OMAP_DSS_LCD_IPC,
474                 .name                   = "primeview_pd104slf",
475         },
476 };
477
478 struct panel_drv_data {
479
480         struct omap_dss_device *dssdev;
481
482         struct panel_config *panel_config;
483 };
484
485 static 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
491 static 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;
516 err1:
517         omapdss_dpi_display_disable(dssdev);
518 err0:
519         return r;
520 }
521
522 static 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
541 static 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
580 static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
581 {
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
591 static 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
604 static 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
611 static 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
620 static 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
633 static 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
639 static 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
645 static struct omap_dss_driver dpi_driver = {
646         .probe          = generic_dpi_panel_probe,
647         .remove         = __exit_p(generic_dpi_panel_remove),
648
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,
655         .check_timings  = generic_dpi_panel_check_timings,
656
657         .driver         = {
658                 .name   = "generic_dpi_panel",
659                 .owner  = THIS_MODULE,
660         },
661 };
662
663 static int __init generic_dpi_panel_drv_init(void)
664 {
665         return omap_dss_register_driver(&dpi_driver);
666 }
667
668 static void __exit generic_dpi_panel_drv_exit(void)
669 {
670         omap_dss_unregister_driver(&dpi_driver);
671 }
672
673 module_init(generic_dpi_panel_drv_init);
674 module_exit(generic_dpi_panel_drv_exit);
675 MODULE_LICENSE("GPL");