OMAP: DSS2: Support for UMSH-8173MD TFT panel
[pandora-kernel.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
347 struct panel_drv_data {
348
349         struct omap_dss_device *dssdev;
350
351         struct panel_config *panel_config;
352 };
353
354 static inline struct panel_generic_dpi_data
355 *get_panel_data(const struct omap_dss_device *dssdev)
356 {
357         return (struct panel_generic_dpi_data *) dssdev->data;
358 }
359
360 static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
361 {
362         int r;
363         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
364         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
365         struct panel_config *panel_config = drv_data->panel_config;
366
367         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
368                 return 0;
369
370         r = omapdss_dpi_display_enable(dssdev);
371         if (r)
372                 goto err0;
373
374         /* wait couple of vsyncs until enabling the LCD */
375         if (panel_config->power_on_delay)
376                 msleep(panel_config->power_on_delay);
377
378         if (panel_data->platform_enable) {
379                 r = panel_data->platform_enable(dssdev);
380                 if (r)
381                         goto err1;
382         }
383
384         return 0;
385 err1:
386         omapdss_dpi_display_disable(dssdev);
387 err0:
388         return r;
389 }
390
391 static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
392 {
393         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
394         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
395         struct panel_config *panel_config = drv_data->panel_config;
396
397         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
398                 return;
399
400         if (panel_data->platform_disable)
401                 panel_data->platform_disable(dssdev);
402
403         /* wait couple of vsyncs after disabling the LCD */
404         if (panel_config->power_off_delay)
405                 msleep(panel_config->power_off_delay);
406
407         omapdss_dpi_display_disable(dssdev);
408 }
409
410 static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
411 {
412         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
413         struct panel_config *panel_config = NULL;
414         struct panel_drv_data *drv_data = NULL;
415         int i;
416
417         dev_dbg(&dssdev->dev, "probe\n");
418
419         if (!panel_data || !panel_data->name)
420                 return -EINVAL;
421
422         for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
423                 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
424                         panel_config = &generic_dpi_panels[i];
425                         break;
426                 }
427         }
428
429         if (!panel_config)
430                 return -EINVAL;
431
432         dssdev->panel.config = panel_config->config;
433         dssdev->panel.timings = panel_config->timings;
434         dssdev->panel.acb = panel_config->acb;
435         dssdev->panel.acbi = panel_config->acbi;
436
437         drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
438         if (!drv_data)
439                 return -ENOMEM;
440
441         drv_data->dssdev = dssdev;
442         drv_data->panel_config = panel_config;
443
444         dev_set_drvdata(&dssdev->dev, drv_data);
445
446         return 0;
447 }
448
449 static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
450 {
451         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
452
453         dev_dbg(&dssdev->dev, "remove\n");
454
455         kfree(drv_data);
456
457         dev_set_drvdata(&dssdev->dev, NULL);
458 }
459
460 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
461 {
462         int r = 0;
463
464         r = generic_dpi_panel_power_on(dssdev);
465         if (r)
466                 return r;
467
468         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
469
470         return 0;
471 }
472
473 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
474 {
475         generic_dpi_panel_power_off(dssdev);
476
477         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
478 }
479
480 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
481 {
482         generic_dpi_panel_power_off(dssdev);
483
484         dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
485
486         return 0;
487 }
488
489 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
490 {
491         int r = 0;
492
493         r = generic_dpi_panel_power_on(dssdev);
494         if (r)
495                 return r;
496
497         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
498
499         return 0;
500 }
501
502 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
503                 struct omap_video_timings *timings)
504 {
505         dpi_set_timings(dssdev, timings);
506 }
507
508 static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
509                 struct omap_video_timings *timings)
510 {
511         *timings = dssdev->panel.timings;
512 }
513
514 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
515                 struct omap_video_timings *timings)
516 {
517         return dpi_check_timings(dssdev, timings);
518 }
519
520 static struct omap_dss_driver dpi_driver = {
521         .probe          = generic_dpi_panel_probe,
522         .remove         = __exit_p(generic_dpi_panel_remove),
523
524         .enable         = generic_dpi_panel_enable,
525         .disable        = generic_dpi_panel_disable,
526         .suspend        = generic_dpi_panel_suspend,
527         .resume         = generic_dpi_panel_resume,
528
529         .set_timings    = generic_dpi_panel_set_timings,
530         .get_timings    = generic_dpi_panel_get_timings,
531         .check_timings  = generic_dpi_panel_check_timings,
532
533         .driver         = {
534                 .name   = "generic_dpi_panel",
535                 .owner  = THIS_MODULE,
536         },
537 };
538
539 static int __init generic_dpi_panel_drv_init(void)
540 {
541         return omap_dss_register_driver(&dpi_driver);
542 }
543
544 static void __exit generic_dpi_panel_drv_exit(void)
545 {
546         omap_dss_unregister_driver(&dpi_driver);
547 }
548
549 module_init(generic_dpi_panel_drv_init);
550 module_exit(generic_dpi_panel_drv_exit);
551 MODULE_LICENSE("GPL");