Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
panel-generic-dpi.c
Go to the documentation of this file.
1 /*
2  * Generic DPI Panels support
3  *
4  * Copyright (C) 2010 Canonical Ltd.
5  * Author: Bryan Wu <[email protected]>
6  *
7  * LCD panel driver for Sharp LQ043T1DG01
8  *
9  * Copyright (C) 2009 Texas Instruments Inc
10  * Author: Vaibhav Hiremath <[email protected]>
11  *
12  * LCD panel driver for Toppoly TDO35S
13  *
14  * Copyright (C) 2009 CompuLab, Ltd.
15  * Author: Mike Rapoport <[email protected]>
16  *
17  * Copyright (C) 2008 Nokia Corporation
18  * Author: Tomi Valkeinen <[email protected]>
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 
39 
40 struct panel_config {
42 
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 
544 
546 
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:
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 
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 
687 
688  mutex_unlock(&drv_data->lock);
689 }
690 
691 static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
692 {
693  struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
694 
695  mutex_lock(&drv_data->lock);
696 
697  generic_dpi_panel_power_off(dssdev);
698 
700 
701  mutex_unlock(&drv_data->lock);
702 
703  return 0;
704 }
705 
706 static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
707 {
708  struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
709  int r;
710 
711  mutex_lock(&drv_data->lock);
712 
713  r = generic_dpi_panel_power_on(dssdev);
714  if (r)
715  goto err;
716 
717  dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
718 
719 err:
720  mutex_unlock(&drv_data->lock);
721 
722  return r;
723 }
724 
725 static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
726  struct omap_video_timings *timings)
727 {
728  struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
729 
730  mutex_lock(&drv_data->lock);
731 
732  omapdss_dpi_set_timings(dssdev, timings);
733 
734  dssdev->panel.timings = *timings;
735 
736  mutex_unlock(&drv_data->lock);
737 }
738 
739 static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
740  struct omap_video_timings *timings)
741 {
742  struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
743 
744  mutex_lock(&drv_data->lock);
745 
746  *timings = dssdev->panel.timings;
747 
748  mutex_unlock(&drv_data->lock);
749 }
750 
751 static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
752  struct omap_video_timings *timings)
753 {
754  struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
755  int r;
756 
757  mutex_lock(&drv_data->lock);
758 
759  r = dpi_check_timings(dssdev, timings);
760 
761  mutex_unlock(&drv_data->lock);
762 
763  return r;
764 }
765 
766 static struct omap_dss_driver dpi_driver = {
767  .probe = generic_dpi_panel_probe,
768  .remove = __exit_p(generic_dpi_panel_remove),
769 
770  .enable = generic_dpi_panel_enable,
771  .disable = generic_dpi_panel_disable,
772  .suspend = generic_dpi_panel_suspend,
773  .resume = generic_dpi_panel_resume,
774 
775  .set_timings = generic_dpi_panel_set_timings,
776  .get_timings = generic_dpi_panel_get_timings,
777  .check_timings = generic_dpi_panel_check_timings,
778 
779  .driver = {
780  .name = "generic_dpi_panel",
781  .owner = THIS_MODULE,
782  },
783 };
784 
785 static int __init generic_dpi_panel_drv_init(void)
786 {
787  return omap_dss_register_driver(&dpi_driver);
788 }
789 
790 static void __exit generic_dpi_panel_drv_exit(void)
791 {
792  omap_dss_unregister_driver(&dpi_driver);
793 }
794 
795 module_init(generic_dpi_panel_drv_init);
796 module_exit(generic_dpi_panel_drv_exit);
797 MODULE_LICENSE("GPL");