OMAPDSS: remove omap_dss_device's suspend/resume
[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 power_on_delay;
44         int power_off_delay;
45
46         /*
47          * Used to match device to panel configuration
48          * when use generic panel driver
49          */
50         const char *name;
51 };
52
53 /* Panel configurations */
54 static struct panel_config generic_dpi_panels[] = {
55         /* Sharp LQ043T1DG01 */
56         {
57                 {
58                         .x_res          = 480,
59                         .y_res          = 272,
60
61                         .pixel_clock    = 9000,
62
63                         .hsw            = 42,
64                         .hfp            = 3,
65                         .hbp            = 2,
66
67                         .vsw            = 11,
68                         .vfp            = 3,
69                         .vbp            = 2,
70
71                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
72                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
73                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
74                         .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
75                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
76                 },
77                 .power_on_delay         = 50,
78                 .power_off_delay        = 100,
79                 .name                   = "sharp_lq",
80         },
81
82         /* Sharp LS037V7DW01 */
83         {
84                 {
85                         .x_res          = 480,
86                         .y_res          = 640,
87
88                         .pixel_clock    = 19200,
89
90                         .hsw            = 2,
91                         .hfp            = 1,
92                         .hbp            = 28,
93
94                         .vsw            = 1,
95                         .vfp            = 1,
96                         .vbp            = 1,
97
98                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
99                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
100                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
101                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
102                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
103                 },
104                 .power_on_delay         = 50,
105                 .power_off_delay        = 100,
106                 .name                   = "sharp_ls",
107         },
108
109         /* Toppoly TDO35S */
110         {
111                 {
112                         .x_res          = 480,
113                         .y_res          = 640,
114
115                         .pixel_clock    = 26000,
116
117                         .hfp            = 104,
118                         .hsw            = 8,
119                         .hbp            = 8,
120
121                         .vfp            = 4,
122                         .vsw            = 2,
123                         .vbp            = 2,
124
125                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
126                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
127                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
128                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
129                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
130                 },
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                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
153                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
154                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
155                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
156                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
157                 },
158                 .power_on_delay         = 0,
159                 .power_off_delay        = 0,
160                 .name                   = "samsung_lte430wq_f0c",
161         },
162
163         /* Seiko 70WVW1TZ3Z3 */
164         {
165                 {
166                         .x_res          = 800,
167                         .y_res          = 480,
168
169                         .pixel_clock    = 33000,
170
171                         .hsw            = 128,
172                         .hfp            = 10,
173                         .hbp            = 10,
174
175                         .vsw            = 2,
176                         .vfp            = 4,
177                         .vbp            = 11,
178
179                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
180                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
181                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
182                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
183                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
184                 },
185                 .power_on_delay         = 0,
186                 .power_off_delay        = 0,
187                 .name                   = "seiko_70wvw1tz3",
188         },
189
190         /* Powertip PH480272T */
191         {
192                 {
193                         .x_res          = 480,
194                         .y_res          = 272,
195
196                         .pixel_clock    = 9000,
197
198                         .hsw            = 40,
199                         .hfp            = 2,
200                         .hbp            = 2,
201
202                         .vsw            = 10,
203                         .vfp            = 2,
204                         .vbp            = 2,
205
206                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
207                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
208                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
209                         .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
210                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
211                 },
212                 .power_on_delay         = 0,
213                 .power_off_delay        = 0,
214                 .name                   = "powertip_ph480272t",
215         },
216
217         /* Innolux AT070TN83 */
218         {
219                 {
220                         .x_res          = 800,
221                         .y_res          = 480,
222
223                         .pixel_clock    = 40000,
224
225                         .hsw            = 48,
226                         .hfp            = 1,
227                         .hbp            = 1,
228
229                         .vsw            = 3,
230                         .vfp            = 12,
231                         .vbp            = 25,
232
233                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
234                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
235                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
236                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
237                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
238                 },
239                 .power_on_delay         = 0,
240                 .power_off_delay        = 0,
241                 .name                   = "innolux_at070tn83",
242         },
243
244         /* NEC NL2432DR22-11B */
245         {
246                 {
247                         .x_res          = 240,
248                         .y_res          = 320,
249
250                         .pixel_clock    = 5400,
251
252                         .hsw            = 3,
253                         .hfp            = 3,
254                         .hbp            = 39,
255
256                         .vsw            = 1,
257                         .vfp            = 2,
258                         .vbp            = 7,
259
260                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
261                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
262                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
263                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
264                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
265                 },
266                 .name                   = "nec_nl2432dr22-11b",
267         },
268
269         /* Unknown panel used in OMAP H4 */
270         {
271                 {
272                         .x_res          = 240,
273                         .y_res          = 320,
274
275                         .pixel_clock    = 6250,
276
277                         .hsw            = 15,
278                         .hfp            = 15,
279                         .hbp            = 60,
280
281                         .vsw            = 1,
282                         .vfp            = 1,
283                         .vbp            = 1,
284
285                         .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
286                         .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
287                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
288                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
289                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
290                 },
291                 .name                   = "h4",
292         },
293
294         /* Unknown panel used in Samsung OMAP2 Apollon */
295         {
296                 {
297                         .x_res          = 480,
298                         .y_res          = 272,
299
300                         .pixel_clock    = 6250,
301
302                         .hsw            = 41,
303                         .hfp            = 2,
304                         .hbp            = 2,
305
306                         .vsw            = 10,
307                         .vfp            = 2,
308                         .vbp            = 2,
309
310                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
311                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
312                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
313                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
314                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
315                 },
316                 .name                   = "apollon",
317         },
318         /* FocalTech ETM070003DH6 */
319         {
320                 {
321                         .x_res          = 800,
322                         .y_res          = 480,
323
324                         .pixel_clock    = 28000,
325
326                         .hsw            = 48,
327                         .hfp            = 40,
328                         .hbp            = 40,
329
330                         .vsw            = 3,
331                         .vfp            = 13,
332                         .vbp            = 29,
333
334                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
335                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
336                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
337                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
338                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
339                 },
340                 .name                   = "focaltech_etm070003dh6",
341         },
342
343         /* Microtips Technologies - UMSH-8173MD */
344         {
345                 {
346                         .x_res          = 800,
347                         .y_res          = 480,
348
349                         .pixel_clock    = 34560,
350
351                         .hsw            = 13,
352                         .hfp            = 101,
353                         .hbp            = 101,
354
355                         .vsw            = 23,
356                         .vfp            = 1,
357                         .vbp            = 1,
358
359                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
360                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
361                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
362                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
363                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
364                 },
365                 .power_on_delay         = 0,
366                 .power_off_delay        = 0,
367                 .name                   = "microtips_umsh_8173md",
368         },
369
370         /* OrtusTech COM43H4M10XTC */
371         {
372                 {
373                         .x_res          = 480,
374                         .y_res          = 272,
375
376                         .pixel_clock    = 8000,
377
378                         .hsw            = 41,
379                         .hfp            = 8,
380                         .hbp            = 4,
381
382                         .vsw            = 10,
383                         .vfp            = 4,
384                         .vbp            = 2,
385
386                         .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
387                         .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
388                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
389                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
390                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
391                 },
392                 .name                   = "ortustech_com43h4m10xtc",
393         },
394
395         /* Innolux AT080TN52 */
396         {
397                 {
398                         .x_res = 800,
399                         .y_res = 600,
400
401                         .pixel_clock    = 41142,
402
403                         .hsw            = 20,
404                         .hfp            = 210,
405                         .hbp            = 46,
406
407                         .vsw            = 10,
408                         .vfp            = 12,
409                         .vbp            = 23,
410
411                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
412                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
413                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
414                         .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
415                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
416                 },
417                 .name                   = "innolux_at080tn52",
418         },
419
420         /* Mitsubishi AA084SB01 */
421         {
422                 {
423                         .x_res          = 800,
424                         .y_res          = 600,
425                         .pixel_clock    = 40000,
426
427                         .hsw            = 1,
428                         .hfp            = 254,
429                         .hbp            = 1,
430
431                         .vsw            = 1,
432                         .vfp            = 26,
433                         .vbp            = 1,
434
435                         .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
436                         .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
437                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
438                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
439                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
440                 },
441                 .name                   = "mitsubishi_aa084sb01",
442         },
443         /* EDT ET0500G0DH6 */
444         {
445                 {
446                         .x_res          = 800,
447                         .y_res          = 480,
448                         .pixel_clock    = 33260,
449
450                         .hsw            = 128,
451                         .hfp            = 216,
452                         .hbp            = 40,
453
454                         .vsw            = 2,
455                         .vfp            = 35,
456                         .vbp            = 10,
457
458                         .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
459                         .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
460                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
461                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
462                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
463                 },
464                 .name                   = "edt_et0500g0dh6",
465         },
466
467         /* Prime-View PD050VL1 */
468         {
469                 {
470                         .x_res          = 640,
471                         .y_res          = 480,
472
473                         .pixel_clock    = 25000,
474
475                         .hsw            = 96,
476                         .hfp            = 18,
477                         .hbp            = 46,
478
479                         .vsw            = 2,
480                         .vfp            = 10,
481                         .vbp            = 33,
482
483                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
484                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
485                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
486                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
487                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
488                 },
489                 .name                   = "primeview_pd050vl1",
490         },
491
492         /* Prime-View PM070WL4 */
493         {
494                 {
495                         .x_res          = 800,
496                         .y_res          = 480,
497
498                         .pixel_clock    = 32000,
499
500                         .hsw            = 128,
501                         .hfp            = 42,
502                         .hbp            = 86,
503
504                         .vsw            = 2,
505                         .vfp            = 10,
506                         .vbp            = 33,
507
508                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
509                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
510                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
511                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
512                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
513                 },
514                 .name                   = "primeview_pm070wl4",
515         },
516
517         /* Prime-View PD104SLF */
518         {
519                 {
520                         .x_res          = 800,
521                         .y_res          = 600,
522
523                         .pixel_clock    = 40000,
524
525                         .hsw            = 128,
526                         .hfp            = 42,
527                         .hbp            = 86,
528
529                         .vsw            = 4,
530                         .vfp            = 1,
531                         .vbp            = 23,
532
533                         .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
534                         .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
535                         .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
536                         .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
537                         .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
538                 },
539                 .name                   = "primeview_pd104slf",
540         },
541 };
542
543 struct panel_drv_data {
544
545         struct omap_dss_device *dssdev;
546
547         struct panel_config *panel_config;
548
549         struct mutex lock;
550 };
551
552 static inline struct panel_generic_dpi_data
553 *get_panel_data(const struct omap_dss_device *dssdev)
554 {
555         return (struct panel_generic_dpi_data *) dssdev->data;
556 }
557
558 static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
559 {
560         int r;
561         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
562         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
563         struct panel_config *panel_config = drv_data->panel_config;
564
565         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
566                 return 0;
567
568         omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
569         omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
570
571         r = omapdss_dpi_display_enable(dssdev);
572         if (r)
573                 goto err0;
574
575         /* wait couple of vsyncs until enabling the LCD */
576         if (panel_config->power_on_delay)
577                 msleep(panel_config->power_on_delay);
578
579         if (panel_data->platform_enable) {
580                 r = panel_data->platform_enable(dssdev);
581                 if (r)
582                         goto err1;
583         }
584
585         return 0;
586 err1:
587         omapdss_dpi_display_disable(dssdev);
588 err0:
589         return r;
590 }
591
592 static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
593 {
594         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
595         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
596         struct panel_config *panel_config = drv_data->panel_config;
597
598         if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
599                 return;
600
601         if (panel_data->platform_disable)
602                 panel_data->platform_disable(dssdev);
603
604         /* wait couple of vsyncs after disabling the LCD */
605         if (panel_config->power_off_delay)
606                 msleep(panel_config->power_off_delay);
607
608         omapdss_dpi_display_disable(dssdev);
609 }
610
611 static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
612 {
613         struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
614         struct panel_config *panel_config = NULL;
615         struct panel_drv_data *drv_data = NULL;
616         int i;
617
618         dev_dbg(&dssdev->dev, "probe\n");
619
620         if (!panel_data || !panel_data->name)
621                 return -EINVAL;
622
623         for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
624                 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
625                         panel_config = &generic_dpi_panels[i];
626                         break;
627                 }
628         }
629
630         if (!panel_config)
631                 return -EINVAL;
632
633         dssdev->panel.timings = panel_config->timings;
634
635         drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
636         if (!drv_data)
637                 return -ENOMEM;
638
639         drv_data->dssdev = dssdev;
640         drv_data->panel_config = panel_config;
641
642         mutex_init(&drv_data->lock);
643
644         dev_set_drvdata(&dssdev->dev, drv_data);
645
646         return 0;
647 }
648
649 static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
650 {
651         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
652
653         dev_dbg(&dssdev->dev, "remove\n");
654
655         kfree(drv_data);
656
657         dev_set_drvdata(&dssdev->dev, NULL);
658 }
659
660 static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
661 {
662         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
663         int r;
664
665         mutex_lock(&drv_data->lock);
666
667         r = generic_dpi_panel_power_on(dssdev);
668         if (r)
669                 goto err;
670
671         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
672 err:
673         mutex_unlock(&drv_data->lock);
674
675         return r;
676 }
677
678 static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
679 {
680         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
681
682         mutex_lock(&drv_data->lock);
683
684         generic_dpi_panel_power_off(dssdev);
685
686         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
687
688         mutex_unlock(&drv_data->lock);
689 }
690
691 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
692                 struct omap_video_timings *timings)
693 {
694         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
695
696         mutex_lock(&drv_data->lock);
697
698         omapdss_dpi_set_timings(dssdev, timings);
699
700         dssdev->panel.timings = *timings;
701
702         mutex_unlock(&drv_data->lock);
703 }
704
705 static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
706                 struct omap_video_timings *timings)
707 {
708         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
709
710         mutex_lock(&drv_data->lock);
711
712         *timings = dssdev->panel.timings;
713
714         mutex_unlock(&drv_data->lock);
715 }
716
717 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
718                 struct omap_video_timings *timings)
719 {
720         struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
721         int r;
722
723         mutex_lock(&drv_data->lock);
724
725         r = dpi_check_timings(dssdev, timings);
726
727         mutex_unlock(&drv_data->lock);
728
729         return r;
730 }
731
732 static struct omap_dss_driver dpi_driver = {
733         .probe          = generic_dpi_panel_probe,
734         .remove         = __exit_p(generic_dpi_panel_remove),
735
736         .enable         = generic_dpi_panel_enable,
737         .disable        = generic_dpi_panel_disable,
738
739         .set_timings    = generic_dpi_panel_set_timings,
740         .get_timings    = generic_dpi_panel_get_timings,
741         .check_timings  = generic_dpi_panel_check_timings,
742
743         .driver         = {
744                 .name   = "generic_dpi_panel",
745                 .owner  = THIS_MODULE,
746         },
747 };
748
749 static int __init generic_dpi_panel_drv_init(void)
750 {
751         return omap_dss_register_driver(&dpi_driver);
752 }
753
754 static void __exit generic_dpi_panel_drv_exit(void)
755 {
756         omap_dss_unregister_driver(&dpi_driver);
757 }
758
759 module_init(generic_dpi_panel_drv_init);
760 module_exit(generic_dpi_panel_drv_exit);
761 MODULE_LICENSE("GPL");