netfilter: remove unnecessary goto statement for error recovery
[cascardo/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         /* Mitsubishi AA084SB01 */
391         {
392                 {
393                         .x_res          = 800,
394                         .y_res          = 600,
395                         .pixel_clock    = 40000,
396
397                         .hsw            = 1,
398                         .hfp            = 254,
399                         .hbp            = 1,
400
401                         .vsw            = 1,
402                         .vfp            = 26,
403                         .vbp            = 1,
404                 },
405                 .config                 = OMAP_DSS_LCD_TFT,
406                 .name                   = "mitsubishi_aa084sb01",
407         },
408         /* EDT ET0500G0DH6 */
409         {
410                 {
411                         .x_res          = 800,
412                         .y_res          = 480,
413                         .pixel_clock    = 33260,
414
415                         .hsw            = 128,
416                         .hfp            = 216,
417                         .hbp            = 40,
418
419                         .vsw            = 2,
420                         .vfp            = 35,
421                         .vbp            = 10,
422                 },
423                 .config                 = OMAP_DSS_LCD_TFT,
424                 .name                   = "edt_et0500g0dh6",
425         },
426
427         /* Prime-View PD050VL1 */
428         {
429                 {
430                         .x_res          = 640,
431                         .y_res          = 480,
432
433                         .pixel_clock    = 25000,
434
435                         .hsw            = 96,
436                         .hfp            = 18,
437                         .hbp            = 46,
438
439                         .vsw            = 2,
440                         .vfp            = 10,
441                         .vbp            = 33,
442                 },
443                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
444                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
445                 .name                   = "primeview_pd050vl1",
446         },
447
448         /* Prime-View PM070WL4 */
449         {
450                 {
451                         .x_res          = 800,
452                         .y_res          = 480,
453
454                         .pixel_clock    = 32000,
455
456                         .hsw            = 128,
457                         .hfp            = 42,
458                         .hbp            = 86,
459
460                         .vsw            = 2,
461                         .vfp            = 10,
462                         .vbp            = 33,
463                 },
464                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
465                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
466                 .name                   = "primeview_pm070wl4",
467         },
468
469         /* Prime-View PD104SLF */
470         {
471                 {
472                         .x_res          = 800,
473                         .y_res          = 600,
474
475                         .pixel_clock    = 40000,
476
477                         .hsw            = 128,
478                         .hfp            = 42,
479                         .hbp            = 86,
480
481                         .vsw            = 4,
482                         .vfp            = 1,
483                         .vbp            = 23,
484                 },
485                 .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
486                                           OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC,
487                 .name                   = "primeview_pd104slf",
488         },
489 };
490
491 struct panel_drv_data {
492
493         struct omap_dss_device *dssdev;
494
495         struct panel_config *panel_config;
496 };
497
498 static inline struct panel_generic_dpi_data
499 *get_panel_data(const struct omap_dss_device *dssdev)
500 {
501         return (struct panel_generic_dpi_data *) dssdev->data;
502 }
503
504 static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
505 {
506         int r;
507         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
508         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
509         struct panel_config *panel_config = drv_data->panel_config;
510
511         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
512                 return 0;
513
514         r = omapdss_dpi_display_enable(dssdev);
515         if (r)
516                 goto err0;
517
518         /* wait couple of vsyncs until enabling the LCD */
519         if (panel_config->power_on_delay)
520                 msleep(panel_config->power_on_delay);
521
522         if (panel_data->platform_enable) {
523                 r = panel_data->platform_enable(dssdev);
524                 if (r)
525                         goto err1;
526         }
527
528         return 0;
529 err1:
530         omapdss_dpi_display_disable(dssdev);
531 err0:
532         return r;
533 }
534
535 static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
536 {
537         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
538         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
539         struct panel_config *panel_config = drv_data->panel_config;
540
541         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
542                 return;
543
544         if (panel_data->platform_disable)
545                 panel_data->platform_disable(dssdev);
546
547         /* wait couple of vsyncs after disabling the LCD */
548         if (panel_config->power_off_delay)
549                 msleep(panel_config->power_off_delay);
550
551         omapdss_dpi_display_disable(dssdev);
552 }
553
554 static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
555 {
556         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
557         struct panel_config *panel_config = NULL;
558         struct panel_drv_data *drv_data = NULL;
559         int i;
560
561         dev_dbg(&dssdev->dev, "probe\n");
562
563         if (!panel_data || !panel_data->name)
564                 return -EINVAL;
565
566         for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
567                 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
568                         panel_config = &generic_dpi_panels[i];
569                         break;
570                 }
571         }
572
573         if (!panel_config)
574                 return -EINVAL;
575
576         dssdev->panel.config = panel_config->config;
577         dssdev->panel.timings = panel_config->timings;
578         dssdev->panel.acb = panel_config->acb;
579         dssdev->panel.acbi = panel_config->acbi;
580
581         drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
582         if (!drv_data)
583                 return -ENOMEM;
584
585         drv_data->dssdev = dssdev;
586         drv_data->panel_config = panel_config;
587
588         dev_set_drvdata(&dssdev->dev, drv_data);
589
590         return 0;
591 }
592
593 static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
594 {
595         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
596
597         dev_dbg(&dssdev->dev, "remove\n");
598
599         kfree(drv_data);
600
601         dev_set_drvdata(&dssdev->dev, NULL);
602 }
603
604 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
605 {
606         int r = 0;
607
608         r = generic_dpi_panel_power_on(dssdev);
609         if (r)
610                 return r;
611
612         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
613
614         return 0;
615 }
616
617 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
618 {
619         generic_dpi_panel_power_off(dssdev);
620
621         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
622 }
623
624 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
625 {
626         generic_dpi_panel_power_off(dssdev);
627
628         dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
629
630         return 0;
631 }
632
633 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
634 {
635         int r = 0;
636
637         r = generic_dpi_panel_power_on(dssdev);
638         if (r)
639                 return r;
640
641         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
642
643         return 0;
644 }
645
646 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
647                 struct omap_video_timings *timings)
648 {
649         dpi_set_timings(dssdev, timings);
650 }
651
652 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
653                 struct omap_video_timings *timings)
654 {
655         return dpi_check_timings(dssdev, timings);
656 }
657
658 static struct omap_dss_driver dpi_driver = {
659         .probe          = generic_dpi_panel_probe,
660         .remove         = __exit_p(generic_dpi_panel_remove),
661
662         .enable         = generic_dpi_panel_enable,
663         .disable        = generic_dpi_panel_disable,
664         .suspend        = generic_dpi_panel_suspend,
665         .resume         = generic_dpi_panel_resume,
666
667         .set_timings    = generic_dpi_panel_set_timings,
668         .check_timings  = generic_dpi_panel_check_timings,
669
670         .driver         = {
671                 .name   = "generic_dpi_panel",
672                 .owner  = THIS_MODULE,
673         },
674 };
675
676 static int __init generic_dpi_panel_drv_init(void)
677 {
678         return omap_dss_register_driver(&dpi_driver);
679 }
680
681 static void __exit generic_dpi_panel_drv_exit(void)
682 {
683         omap_dss_unregister_driver(&dpi_driver);
684 }
685
686 module_init(generic_dpi_panel_drv_init);
687 module_exit(generic_dpi_panel_drv_exit);
688 MODULE_LICENSE("GPL");