]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/video/omap2/displays/panel-generic-dpi.c
floppy: Run floppy initialization asynchronous
[karo-tx-linux.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_TFT | OMAP_DSS_LCD_IVS |
80                                         OMAP_DSS_LCD_IHS | 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_TFT | OMAP_DSS_LCD_IVS |
105                                                 OMAP_DSS_LCD_IHS,
106                 .power_on_delay         = 50,
107                 .power_off_delay        = 100,
108                 .name                   = "sharp_ls",
109         },
110
111         /* Toppoly TDO35S */
112         {
113                 {
114                         .x_res          = 480,
115                         .y_res          = 640,
116
117                         .pixel_clock    = 26000,
118
119                         .hfp            = 104,
120                         .hsw            = 8,
121                         .hbp            = 8,
122
123                         .vfp            = 4,
124                         .vsw            = 2,
125                         .vbp            = 2,
126                 },
127                 .acbi                   = 0x0,
128                 .acb                    = 0x0,
129                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
130                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
131                                         OMAP_DSS_LCD_ONOFF,
132                 .power_on_delay         = 0,
133                 .power_off_delay        = 0,
134                 .name                   = "toppoly_tdo35s",
135         },
136
137         /* Samsung LTE430WQ-F0C */
138         {
139                 {
140                         .x_res          = 480,
141                         .y_res          = 272,
142
143                         .pixel_clock    = 9200,
144
145                         .hfp            = 8,
146                         .hsw            = 41,
147                         .hbp            = 45 - 41,
148
149                         .vfp            = 4,
150                         .vsw            = 10,
151                         .vbp            = 12 - 10,
152                 },
153                 .acbi                   = 0x0,
154                 .acb                    = 0x0,
155                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
156                                                 OMAP_DSS_LCD_IHS,
157                 .power_on_delay         = 0,
158                 .power_off_delay        = 0,
159                 .name                   = "samsung_lte430wq_f0c",
160         },
161
162         /* Seiko 70WVW1TZ3Z3 */
163         {
164                 {
165                         .x_res          = 800,
166                         .y_res          = 480,
167
168                         .pixel_clock    = 33000,
169
170                         .hsw            = 128,
171                         .hfp            = 10,
172                         .hbp            = 10,
173
174                         .vsw            = 2,
175                         .vfp            = 4,
176                         .vbp            = 11,
177                 },
178                 .acbi                   = 0x0,
179                 .acb                    = 0x0,
180                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
181                                                 OMAP_DSS_LCD_IHS,
182                 .power_on_delay         = 0,
183                 .power_off_delay        = 0,
184                 .name                   = "seiko_70wvw1tz3",
185         },
186
187         /* Powertip PH480272T */
188         {
189                 {
190                         .x_res          = 480,
191                         .y_res          = 272,
192
193                         .pixel_clock    = 9000,
194
195                         .hsw            = 40,
196                         .hfp            = 2,
197                         .hbp            = 2,
198
199                         .vsw            = 10,
200                         .vfp            = 2,
201                         .vbp            = 2,
202                 },
203                 .acbi                   = 0x0,
204                 .acb                    = 0x0,
205                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
206                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
207                 .power_on_delay         = 0,
208                 .power_off_delay        = 0,
209                 .name                   = "powertip_ph480272t",
210         },
211
212         /* Innolux AT070TN83 */
213         {
214                 {
215                         .x_res          = 800,
216                         .y_res          = 480,
217
218                         .pixel_clock    = 40000,
219
220                         .hsw            = 48,
221                         .hfp            = 1,
222                         .hbp            = 1,
223
224                         .vsw            = 3,
225                         .vfp            = 12,
226                         .vbp            = 25,
227                 },
228                 .acbi                   = 0x0,
229                 .acb                    = 0x28,
230                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
231                                           OMAP_DSS_LCD_IHS,
232                 .power_on_delay         = 0,
233                 .power_off_delay        = 0,
234                 .name                   = "innolux_at070tn83",
235         },
236
237         /* NEC NL2432DR22-11B */
238         {
239                 {
240                         .x_res          = 240,
241                         .y_res          = 320,
242
243                         .pixel_clock    = 5400,
244
245                         .hsw            = 3,
246                         .hfp            = 3,
247                         .hbp            = 39,
248
249                         .vsw            = 1,
250                         .vfp            = 2,
251                         .vbp            = 7,
252                 },
253                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
254                                                 OMAP_DSS_LCD_IHS,
255                 .name                   = "nec_nl2432dr22-11b",
256         },
257
258         /* Unknown panel used in OMAP H4 */
259         {
260                 {
261                         .x_res          = 240,
262                         .y_res          = 320,
263
264                         .pixel_clock    = 6250,
265
266                         .hsw            = 15,
267                         .hfp            = 15,
268                         .hbp            = 60,
269
270                         .vsw            = 1,
271                         .vfp            = 1,
272                         .vbp            = 1,
273                 },
274                 .config                 = OMAP_DSS_LCD_TFT,
275
276                 .name                   = "h4",
277         },
278
279         /* Unknown panel used in Samsung OMAP2 Apollon */
280         {
281                 {
282                         .x_res          = 480,
283                         .y_res          = 272,
284
285                         .pixel_clock    = 6250,
286
287                         .hsw            = 41,
288                         .hfp            = 2,
289                         .hbp            = 2,
290
291                         .vsw            = 10,
292                         .vfp            = 2,
293                         .vbp            = 2,
294                 },
295                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
296                                                 OMAP_DSS_LCD_IHS,
297
298                 .name                   = "apollon",
299         },
300         /* FocalTech ETM070003DH6 */
301         {
302                 {
303                         .x_res          = 800,
304                         .y_res          = 480,
305
306                         .pixel_clock    = 28000,
307
308                         .hsw            = 48,
309                         .hfp            = 40,
310                         .hbp            = 40,
311
312                         .vsw            = 3,
313                         .vfp            = 13,
314                         .vbp            = 29,
315                 },
316                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
317                                           OMAP_DSS_LCD_IHS,
318                 .name                   = "focaltech_etm070003dh6",
319         },
320
321         /* Microtips Technologies - UMSH-8173MD */
322         {
323                 {
324                         .x_res          = 800,
325                         .y_res          = 480,
326
327                         .pixel_clock    = 34560,
328
329                         .hsw            = 13,
330                         .hfp            = 101,
331                         .hbp            = 101,
332
333                         .vsw            = 23,
334                         .vfp            = 1,
335                         .vbp            = 1,
336                 },
337                 .acbi                   = 0x0,
338                 .acb                    = 0x0,
339                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
340                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
341                 .power_on_delay         = 0,
342                 .power_off_delay        = 0,
343                 .name                   = "microtips_umsh_8173md",
344         },
345
346         /* OrtusTech COM43H4M10XTC */
347         {
348                 {
349                         .x_res          = 480,
350                         .y_res          = 272,
351
352                         .pixel_clock    = 8000,
353
354                         .hsw            = 41,
355                         .hfp            = 8,
356                         .hbp            = 4,
357
358                         .vsw            = 10,
359                         .vfp            = 4,
360                         .vbp            = 2,
361                 },
362                 .config                 = OMAP_DSS_LCD_TFT,
363
364                 .name                   = "ortustech_com43h4m10xtc",
365         },
366
367         /* Innolux AT080TN52 */
368         {
369                 {
370                         .x_res = 800,
371                         .y_res = 600,
372
373                         .pixel_clock    = 41142,
374
375                         .hsw            = 20,
376                         .hfp            = 210,
377                         .hbp            = 46,
378
379                         .vsw            = 10,
380                         .vfp            = 12,
381                         .vbp            = 23,
382                 },
383                 .acb                    = 0x0,
384                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
385                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
386
387                 .name                   = "innolux_at080tn52",
388         },
389 };
390
391 struct panel_drv_data {
392
393         struct omap_dss_device *dssdev;
394
395         struct panel_config *panel_config;
396 };
397
398 static inline struct panel_generic_dpi_data
399 *get_panel_data(const struct omap_dss_device *dssdev)
400 {
401         return (struct panel_generic_dpi_data *) dssdev->data;
402 }
403
404 static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
405 {
406         int r;
407         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
408         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
409         struct panel_config *panel_config = drv_data->panel_config;
410
411         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
412                 return 0;
413
414         r = omapdss_dpi_display_enable(dssdev);
415         if (r)
416                 goto err0;
417
418         /* wait couple of vsyncs until enabling the LCD */
419         if (panel_config->power_on_delay)
420                 msleep(panel_config->power_on_delay);
421
422         if (panel_data->platform_enable) {
423                 r = panel_data->platform_enable(dssdev);
424                 if (r)
425                         goto err1;
426         }
427
428         return 0;
429 err1:
430         omapdss_dpi_display_disable(dssdev);
431 err0:
432         return r;
433 }
434
435 static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
436 {
437         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
438         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
439         struct panel_config *panel_config = drv_data->panel_config;
440
441         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
442                 return;
443
444         if (panel_data->platform_disable)
445                 panel_data->platform_disable(dssdev);
446
447         /* wait couple of vsyncs after disabling the LCD */
448         if (panel_config->power_off_delay)
449                 msleep(panel_config->power_off_delay);
450
451         omapdss_dpi_display_disable(dssdev);
452 }
453
454 static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
455 {
456         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
457         struct panel_config *panel_config = NULL;
458         struct panel_drv_data *drv_data = NULL;
459         int i;
460
461         dev_dbg(&dssdev->dev, "probe\n");
462
463         if (!panel_data || !panel_data->name)
464                 return -EINVAL;
465
466         for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
467                 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
468                         panel_config = &generic_dpi_panels[i];
469                         break;
470                 }
471         }
472
473         if (!panel_config)
474                 return -EINVAL;
475
476         dssdev->panel.config = panel_config->config;
477         dssdev->panel.timings = panel_config->timings;
478         dssdev->panel.acb = panel_config->acb;
479         dssdev->panel.acbi = panel_config->acbi;
480
481         drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
482         if (!drv_data)
483                 return -ENOMEM;
484
485         drv_data->dssdev = dssdev;
486         drv_data->panel_config = panel_config;
487
488         dev_set_drvdata(&dssdev->dev, drv_data);
489
490         return 0;
491 }
492
493 static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
494 {
495         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
496
497         dev_dbg(&dssdev->dev, "remove\n");
498
499         kfree(drv_data);
500
501         dev_set_drvdata(&dssdev->dev, NULL);
502 }
503
504 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
505 {
506         int r = 0;
507
508         r = generic_dpi_panel_power_on(dssdev);
509         if (r)
510                 return r;
511
512         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
513
514         return 0;
515 }
516
517 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
518 {
519         generic_dpi_panel_power_off(dssdev);
520
521         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
522 }
523
524 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
525 {
526         generic_dpi_panel_power_off(dssdev);
527
528         dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
529
530         return 0;
531 }
532
533 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
534 {
535         int r = 0;
536
537         r = generic_dpi_panel_power_on(dssdev);
538         if (r)
539                 return r;
540
541         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
542
543         return 0;
544 }
545
546 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
547                 struct omap_video_timings *timings)
548 {
549         dpi_set_timings(dssdev, timings);
550 }
551
552 static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
553                 struct omap_video_timings *timings)
554 {
555         *timings = dssdev->panel.timings;
556 }
557
558 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
559                 struct omap_video_timings *timings)
560 {
561         return dpi_check_timings(dssdev, timings);
562 }
563
564 static struct omap_dss_driver dpi_driver = {
565         .probe          = generic_dpi_panel_probe,
566         .remove         = __exit_p(generic_dpi_panel_remove),
567
568         .enable         = generic_dpi_panel_enable,
569         .disable        = generic_dpi_panel_disable,
570         .suspend        = generic_dpi_panel_suspend,
571         .resume         = generic_dpi_panel_resume,
572
573         .set_timings    = generic_dpi_panel_set_timings,
574         .get_timings    = generic_dpi_panel_get_timings,
575         .check_timings  = generic_dpi_panel_check_timings,
576
577         .driver         = {
578                 .name   = "generic_dpi_panel",
579                 .owner  = THIS_MODULE,
580         },
581 };
582
583 static int __init generic_dpi_panel_drv_init(void)
584 {
585         return omap_dss_register_driver(&dpi_driver);
586 }
587
588 static void __exit generic_dpi_panel_drv_exit(void)
589 {
590         omap_dss_unregister_driver(&dpi_driver);
591 }
592
593 module_init(generic_dpi_panel_drv_init);
594 module_exit(generic_dpi_panel_drv_exit);
595 MODULE_LICENSE("GPL");