blob: 5c75e4de073cab826f0b8e3244c16e9df3c7f488 [file] [log] [blame]
Bryan Wua9a62b62010-11-17 13:34:33 +00001/*
2 * Generic DPI Panels support
3 *
4 * Copyright (C) 2010 Canonical Ltd.
5 * Author: Bryan Wu <bryan.wu@canonical.com>
6 *
Bryan Wuac1427e2010-11-18 09:45:59 +08007 * 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 *
Bryan Wua9a62b62010-11-17 13:34:33 +000017 * 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>
Tomi Valkeinen08017112013-02-12 14:59:17 +053036#include <linux/gpio.h>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030037#include <video/omapdss.h>
Bryan Wua9a62b62010-11-17 13:34:33 +000038
Archit Tanejaa0d8dde2013-02-12 16:46:46 +053039#include <video/omap-panel-data.h>
Bryan Wua9a62b62010-11-17 13:34:33 +000040
41struct panel_config {
42 struct omap_video_timings timings;
43
Bryan Wua9a62b62010-11-17 13:34:33 +000044 int power_on_delay;
45 int power_off_delay;
46
47 /*
48 * Used to match device to panel configuration
49 * when use generic panel driver
50 */
51 const char *name;
52};
53
54/* Panel configurations */
55static struct panel_config generic_dpi_panels[] = {
Bryan Wua9a62b62010-11-17 13:34:33 +000056 /* Sharp LQ043T1DG01 */
57 {
58 {
59 .x_res = 480,
60 .y_res = 272,
61
62 .pixel_clock = 9000,
63
64 .hsw = 42,
65 .hfp = 3,
66 .hbp = 2,
67
68 .vsw = 11,
69 .vfp = 3,
70 .vbp = 2,
Archit Tanejaa8d5e412012-06-25 12:26:38 +053071
72 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
73 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
74 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
75 .de_level = OMAPDSS_SIG_ACTIVE_LOW,
76 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Bryan Wua9a62b62010-11-17 13:34:33 +000077 },
Bryan Wua9a62b62010-11-17 13:34:33 +000078 .power_on_delay = 50,
79 .power_off_delay = 100,
80 .name = "sharp_lq",
81 },
82
83 /* Sharp LS037V7DW01 */
84 {
85 {
86 .x_res = 480,
87 .y_res = 640,
88
89 .pixel_clock = 19200,
90
91 .hsw = 2,
92 .hfp = 1,
93 .hbp = 28,
94
95 .vsw = 1,
96 .vfp = 1,
97 .vbp = 1,
Archit Tanejaa8d5e412012-06-25 12:26:38 +053098
99 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
100 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
101 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
102 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
103 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Bryan Wua9a62b62010-11-17 13:34:33 +0000104 },
Bryan Wua9a62b62010-11-17 13:34:33 +0000105 .power_on_delay = 50,
106 .power_off_delay = 100,
107 .name = "sharp_ls",
108 },
109
110 /* Toppoly TDO35S */
111 {
112 {
113 .x_res = 480,
114 .y_res = 640,
115
116 .pixel_clock = 26000,
117
118 .hfp = 104,
119 .hsw = 8,
120 .hbp = 8,
121
122 .vfp = 4,
123 .vsw = 2,
124 .vbp = 2,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530125
126 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
127 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
128 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
129 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
130 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
Bryan Wua9a62b62010-11-17 13:34:33 +0000131 },
Bryan Wua9a62b62010-11-17 13:34:33 +0000132 .power_on_delay = 0,
133 .power_off_delay = 0,
134 .name = "toppoly_tdo35s",
135 },
Tomi Valkeinen09dc89c2011-02-22 16:39:47 +0200136
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,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530152
153 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
154 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
155 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
156 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
157 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Tomi Valkeinen09dc89c2011-02-22 16:39:47 +0200158 },
Tomi Valkeinen09dc89c2011-02-22 16:39:47 +0200159 .power_on_delay = 0,
160 .power_off_delay = 0,
161 .name = "samsung_lte430wq_f0c",
162 },
Enric Balletbo i Serra50ca19d2011-05-03 09:07:36 +0200163
164 /* Seiko 70WVW1TZ3Z3 */
165 {
166 {
167 .x_res = 800,
168 .y_res = 480,
169
170 .pixel_clock = 33000,
171
172 .hsw = 128,
173 .hfp = 10,
174 .hbp = 10,
175
176 .vsw = 2,
177 .vfp = 4,
178 .vbp = 11,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530179
180 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
181 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
182 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
183 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
184 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Enric Balletbo i Serra50ca19d2011-05-03 09:07:36 +0200185 },
Enric Balletbo i Serra50ca19d2011-05-03 09:07:36 +0200186 .power_on_delay = 0,
187 .power_off_delay = 0,
188 .name = "seiko_70wvw1tz3",
189 },
Enric Balletbo i Serraa0ce4cc2011-05-03 09:07:37 +0200190
191 /* Powertip PH480272T */
192 {
193 {
194 .x_res = 480,
195 .y_res = 272,
196
197 .pixel_clock = 9000,
198
199 .hsw = 40,
200 .hfp = 2,
201 .hbp = 2,
202
203 .vsw = 10,
204 .vfp = 2,
205 .vbp = 2,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530206
207 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
208 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
209 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
210 .de_level = OMAPDSS_SIG_ACTIVE_LOW,
211 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Enric Balletbo i Serraa0ce4cc2011-05-03 09:07:37 +0200212 },
Enric Balletbo i Serraa0ce4cc2011-05-03 09:07:37 +0200213 .power_on_delay = 0,
214 .power_off_delay = 0,
215 .name = "powertip_ph480272t",
216 },
Thomas Weber1e497c42011-09-01 15:05:07 +0200217
218 /* Innolux AT070TN83 */
219 {
220 {
221 .x_res = 800,
222 .y_res = 480,
223
224 .pixel_clock = 40000,
225
226 .hsw = 48,
227 .hfp = 1,
228 .hbp = 1,
229
230 .vsw = 3,
231 .vfp = 12,
232 .vbp = 25,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530233
234 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
235 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
236 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
237 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
238 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Thomas Weber1e497c42011-09-01 15:05:07 +0200239 },
Thomas Weber1e497c42011-09-01 15:05:07 +0200240 .power_on_delay = 0,
241 .power_off_delay = 0,
242 .name = "innolux_at070tn83",
243 },
Tomi Valkeinen3fddbf52011-04-19 19:23:05 +0300244
245 /* NEC NL2432DR22-11B */
246 {
247 {
248 .x_res = 240,
249 .y_res = 320,
250
251 .pixel_clock = 5400,
252
253 .hsw = 3,
254 .hfp = 3,
255 .hbp = 39,
256
257 .vsw = 1,
258 .vfp = 2,
259 .vbp = 7,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530260
261 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
262 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
263 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
264 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
265 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Tomi Valkeinen3fddbf52011-04-19 19:23:05 +0300266 },
Tomi Valkeinen3fddbf52011-04-19 19:23:05 +0300267 .name = "nec_nl2432dr22-11b",
268 },
Tomi Valkeinen8a41ba92011-04-19 19:59:58 +0300269
270 /* Unknown panel used in OMAP H4 */
271 {
272 {
273 .x_res = 240,
274 .y_res = 320,
275
276 .pixel_clock = 6250,
277
278 .hsw = 15,
279 .hfp = 15,
280 .hbp = 60,
281
282 .vsw = 1,
283 .vfp = 1,
284 .vbp = 1,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530285
286 .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
287 .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
288 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
289 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
290 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Tomi Valkeinen8a41ba92011-04-19 19:59:58 +0300291 },
Tomi Valkeinen8a41ba92011-04-19 19:59:58 +0300292 .name = "h4",
293 },
Tomi Valkeinen8d49fe72011-04-20 10:47:28 +0300294
Ilya Yanoka47161a2011-11-20 19:15:39 +0100295 /* FocalTech ETM070003DH6 */
296 {
297 {
298 .x_res = 800,
299 .y_res = 480,
300
301 .pixel_clock = 28000,
302
303 .hsw = 48,
304 .hfp = 40,
305 .hbp = 40,
306
307 .vsw = 3,
308 .vfp = 13,
309 .vbp = 29,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530310
311 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
312 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
313 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
314 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
315 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Ilya Yanoka47161a2011-11-20 19:15:39 +0100316 },
Ilya Yanoka47161a2011-11-20 19:15:39 +0100317 .name = "focaltech_etm070003dh6",
318 },
Daniel Mack62941ec2011-12-20 10:54:32 +0100319
320 /* Microtips Technologies - UMSH-8173MD */
321 {
322 {
323 .x_res = 800,
324 .y_res = 480,
325
326 .pixel_clock = 34560,
327
328 .hsw = 13,
329 .hfp = 101,
330 .hbp = 101,
331
332 .vsw = 23,
333 .vfp = 1,
334 .vbp = 1,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530335
336 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
337 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
338 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
339 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
340 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Daniel Mack62941ec2011-12-20 10:54:32 +0100341 },
Daniel Mack62941ec2011-12-20 10:54:32 +0100342 .power_on_delay = 0,
343 .power_off_delay = 0,
344 .name = "microtips_umsh_8173md",
345 },
Ilya Yanok6acea9c2011-12-26 23:56:41 +0100346
347 /* OrtusTech COM43H4M10XTC */
348 {
349 {
350 .x_res = 480,
351 .y_res = 272,
352
353 .pixel_clock = 8000,
354
355 .hsw = 41,
356 .hfp = 8,
357 .hbp = 4,
358
359 .vsw = 10,
360 .vfp = 4,
361 .vbp = 2,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530362
363 .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
364 .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
365 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
366 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
367 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Ilya Yanok6acea9c2011-12-26 23:56:41 +0100368 },
Ilya Yanok6acea9c2011-12-26 23:56:41 +0100369 .name = "ortustech_com43h4m10xtc",
370 },
Yegor Yefremov992ee642012-02-08 11:11:08 +0100371
372 /* Innolux AT080TN52 */
373 {
374 {
375 .x_res = 800,
376 .y_res = 600,
377
378 .pixel_clock = 41142,
379
380 .hsw = 20,
381 .hfp = 210,
382 .hbp = 46,
383
384 .vsw = 10,
385 .vfp = 12,
386 .vbp = 23,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530387
388 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
389 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
390 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
391 .de_level = OMAPDSS_SIG_ACTIVE_LOW,
392 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Yegor Yefremov992ee642012-02-08 11:11:08 +0100393 },
Yegor Yefremov992ee642012-02-08 11:11:08 +0100394 .name = "innolux_at080tn52",
395 },
Thomas Weber697bacb2012-02-17 13:41:58 +0100396
397 /* Mitsubishi AA084SB01 */
398 {
399 {
400 .x_res = 800,
401 .y_res = 600,
402 .pixel_clock = 40000,
403
404 .hsw = 1,
405 .hfp = 254,
406 .hbp = 1,
407
408 .vsw = 1,
409 .vfp = 26,
410 .vbp = 1,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530411
412 .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
413 .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
414 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
415 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
416 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Thomas Weber697bacb2012-02-17 13:41:58 +0100417 },
Thomas Weber697bacb2012-02-17 13:41:58 +0100418 .name = "mitsubishi_aa084sb01",
419 },
Thomas Webere97374c2012-02-17 13:41:59 +0100420 /* EDT ET0500G0DH6 */
421 {
422 {
423 .x_res = 800,
424 .y_res = 480,
425 .pixel_clock = 33260,
426
427 .hsw = 128,
428 .hfp = 216,
429 .hbp = 40,
430
431 .vsw = 2,
432 .vfp = 35,
433 .vbp = 10,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530434
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,
Thomas Webere97374c2012-02-17 13:41:59 +0100440 },
Thomas Webere97374c2012-02-17 13:41:59 +0100441 .name = "edt_et0500g0dh6",
442 },
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200443
444 /* Prime-View PD050VL1 */
445 {
446 {
447 .x_res = 640,
448 .y_res = 480,
449
450 .pixel_clock = 25000,
451
452 .hsw = 96,
453 .hfp = 18,
454 .hbp = 46,
455
456 .vsw = 2,
457 .vfp = 10,
458 .vbp = 33,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530459
460 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
461 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
462 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
463 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
464 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200465 },
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200466 .name = "primeview_pd050vl1",
467 },
468
469 /* Prime-View PM070WL4 */
470 {
471 {
472 .x_res = 800,
473 .y_res = 480,
474
475 .pixel_clock = 32000,
476
477 .hsw = 128,
478 .hfp = 42,
479 .hbp = 86,
480
481 .vsw = 2,
482 .vfp = 10,
483 .vbp = 33,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530484
485 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
486 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
487 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
488 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
489 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200490 },
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200491 .name = "primeview_pm070wl4",
492 },
493
494 /* Prime-View PD104SLF */
495 {
496 {
497 .x_res = 800,
498 .y_res = 600,
499
500 .pixel_clock = 40000,
501
502 .hsw = 128,
503 .hfp = 42,
504 .hbp = 86,
505
506 .vsw = 4,
507 .vfp = 1,
508 .vbp = 23,
Archit Tanejaa8d5e412012-06-25 12:26:38 +0530509
510 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
511 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
512 .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
513 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
514 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200515 },
Jan Weitzel3dd606e2012-04-20 11:41:22 +0200516 .name = "primeview_pd104slf",
517 },
Bryan Wua9a62b62010-11-17 13:34:33 +0000518};
519
520struct panel_drv_data {
521
522 struct omap_dss_device *dssdev;
523
524 struct panel_config *panel_config;
Archit Tanejae19d6592012-08-08 14:20:30 +0530525
526 struct mutex lock;
Bryan Wua9a62b62010-11-17 13:34:33 +0000527};
528
529static inline struct panel_generic_dpi_data
530*get_panel_data(const struct omap_dss_device *dssdev)
531{
532 return (struct panel_generic_dpi_data *) dssdev->data;
533}
534
535static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
536{
Tomi Valkeinen08017112013-02-12 14:59:17 +0530537 int r, i;
Bryan Wua9a62b62010-11-17 13:34:33 +0000538 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
539 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
540 struct panel_config *panel_config = drv_data->panel_config;
541
542 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
543 return 0;
544
Archit Tanejac4991442012-08-08 14:28:54 +0530545 omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
Archit Tanejac6b393d2012-07-06 15:30:52 +0530546 omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
Archit Tanejac4991442012-08-08 14:28:54 +0530547
Bryan Wua9a62b62010-11-17 13:34:33 +0000548 r = omapdss_dpi_display_enable(dssdev);
549 if (r)
550 goto err0;
551
552 /* wait couple of vsyncs until enabling the LCD */
553 if (panel_config->power_on_delay)
554 msleep(panel_config->power_on_delay);
555
556 if (panel_data->platform_enable) {
557 r = panel_data->platform_enable(dssdev);
558 if (r)
559 goto err1;
560 }
561
Tomi Valkeinen08017112013-02-12 14:59:17 +0530562 for (i = 0; i < panel_data->num_gpios; ++i) {
563 gpio_set_value_cansleep(panel_data->gpios[i],
564 panel_data->gpio_invert[i] ? 0 : 1);
565 }
566
Bryan Wua9a62b62010-11-17 13:34:33 +0000567 return 0;
568err1:
569 omapdss_dpi_display_disable(dssdev);
570err0:
571 return r;
572}
573
574static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
575{
576 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
577 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
578 struct panel_config *panel_config = drv_data->panel_config;
Tomi Valkeinen08017112013-02-12 14:59:17 +0530579 int i;
Bryan Wua9a62b62010-11-17 13:34:33 +0000580
581 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
582 return;
583
Tomi Valkeinen08017112013-02-12 14:59:17 +0530584 for (i = panel_data->num_gpios - 1; i >= 0; --i) {
585 gpio_set_value_cansleep(panel_data->gpios[i],
586 panel_data->gpio_invert[i] ? 1 : 0);
587 }
588
Bryan Wua9a62b62010-11-17 13:34:33 +0000589 if (panel_data->platform_disable)
590 panel_data->platform_disable(dssdev);
591
592 /* wait couple of vsyncs after disabling the LCD */
593 if (panel_config->power_off_delay)
594 msleep(panel_config->power_off_delay);
595
596 omapdss_dpi_display_disable(dssdev);
597}
598
599static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
600{
601 struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
602 struct panel_config *panel_config = NULL;
603 struct panel_drv_data *drv_data = NULL;
Tomi Valkeinen08017112013-02-12 14:59:17 +0530604 int i, r;
Bryan Wua9a62b62010-11-17 13:34:33 +0000605
606 dev_dbg(&dssdev->dev, "probe\n");
607
608 if (!panel_data || !panel_data->name)
609 return -EINVAL;
610
611 for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
612 if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
613 panel_config = &generic_dpi_panels[i];
614 break;
615 }
616 }
617
618 if (!panel_config)
619 return -EINVAL;
620
Tomi Valkeinen08017112013-02-12 14:59:17 +0530621 for (i = 0; i < panel_data->num_gpios; ++i) {
622 r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
623 panel_data->gpio_invert[i] ?
624 GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
625 "panel gpio");
626 if (r)
627 return r;
628 }
629
Bryan Wua9a62b62010-11-17 13:34:33 +0000630 dssdev->panel.timings = panel_config->timings;
Bryan Wua9a62b62010-11-17 13:34:33 +0000631
Archit Tanejaf5e484d2012-09-14 15:17:01 +0300632 drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL);
Bryan Wua9a62b62010-11-17 13:34:33 +0000633 if (!drv_data)
634 return -ENOMEM;
635
636 drv_data->dssdev = dssdev;
637 drv_data->panel_config = panel_config;
638
Archit Tanejae19d6592012-08-08 14:20:30 +0530639 mutex_init(&drv_data->lock);
640
Bryan Wua9a62b62010-11-17 13:34:33 +0000641 dev_set_drvdata(&dssdev->dev, drv_data);
642
643 return 0;
644}
645
Tomi Valkeinen14e4d782011-03-31 12:03:51 +0300646static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
Bryan Wua9a62b62010-11-17 13:34:33 +0000647{
Bryan Wua9a62b62010-11-17 13:34:33 +0000648 dev_dbg(&dssdev->dev, "remove\n");
649
Bryan Wua9a62b62010-11-17 13:34:33 +0000650 dev_set_drvdata(&dssdev->dev, NULL);
651}
652
653static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
654{
Archit Tanejae19d6592012-08-08 14:20:30 +0530655 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
656 int r;
657
658 mutex_lock(&drv_data->lock);
Bryan Wua9a62b62010-11-17 13:34:33 +0000659
660 r = generic_dpi_panel_power_on(dssdev);
661 if (r)
Archit Tanejae19d6592012-08-08 14:20:30 +0530662 goto err;
Bryan Wua9a62b62010-11-17 13:34:33 +0000663
664 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
Archit Tanejae19d6592012-08-08 14:20:30 +0530665err:
666 mutex_unlock(&drv_data->lock);
Bryan Wua9a62b62010-11-17 13:34:33 +0000667
Archit Tanejae19d6592012-08-08 14:20:30 +0530668 return r;
Bryan Wua9a62b62010-11-17 13:34:33 +0000669}
670
671static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
672{
Archit Tanejae19d6592012-08-08 14:20:30 +0530673 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
674
675 mutex_lock(&drv_data->lock);
676
Bryan Wua9a62b62010-11-17 13:34:33 +0000677 generic_dpi_panel_power_off(dssdev);
678
679 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
Archit Tanejae19d6592012-08-08 14:20:30 +0530680
681 mutex_unlock(&drv_data->lock);
Bryan Wua9a62b62010-11-17 13:34:33 +0000682}
683
Bryan Wua9a62b62010-11-17 13:34:33 +0000684static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
685 struct omap_video_timings *timings)
686{
Archit Tanejae19d6592012-08-08 14:20:30 +0530687 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
688
689 mutex_lock(&drv_data->lock);
690
Archit Tanejac4991442012-08-08 14:28:54 +0530691 omapdss_dpi_set_timings(dssdev, timings);
Archit Tanejae19d6592012-08-08 14:20:30 +0530692
Archit Tanejabdcae3c2012-08-08 14:29:48 +0530693 dssdev->panel.timings = *timings;
694
Archit Tanejae19d6592012-08-08 14:20:30 +0530695 mutex_unlock(&drv_data->lock);
696}
697
698static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
699 struct omap_video_timings *timings)
700{
701 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
702
703 mutex_lock(&drv_data->lock);
704
705 *timings = dssdev->panel.timings;
706
707 mutex_unlock(&drv_data->lock);
Bryan Wua9a62b62010-11-17 13:34:33 +0000708}
709
Bryan Wua9a62b62010-11-17 13:34:33 +0000710static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
711 struct omap_video_timings *timings)
712{
Archit Tanejae19d6592012-08-08 14:20:30 +0530713 struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
714 int r;
715
716 mutex_lock(&drv_data->lock);
717
718 r = dpi_check_timings(dssdev, timings);
719
720 mutex_unlock(&drv_data->lock);
721
722 return r;
Bryan Wua9a62b62010-11-17 13:34:33 +0000723}
724
725static struct omap_dss_driver dpi_driver = {
726 .probe = generic_dpi_panel_probe,
Tomi Valkeinen14e4d782011-03-31 12:03:51 +0300727 .remove = __exit_p(generic_dpi_panel_remove),
Bryan Wua9a62b62010-11-17 13:34:33 +0000728
729 .enable = generic_dpi_panel_enable,
730 .disable = generic_dpi_panel_disable,
Bryan Wua9a62b62010-11-17 13:34:33 +0000731
732 .set_timings = generic_dpi_panel_set_timings,
Archit Tanejae19d6592012-08-08 14:20:30 +0530733 .get_timings = generic_dpi_panel_get_timings,
Bryan Wua9a62b62010-11-17 13:34:33 +0000734 .check_timings = generic_dpi_panel_check_timings,
735
736 .driver = {
737 .name = "generic_dpi_panel",
738 .owner = THIS_MODULE,
739 },
740};
741
742static int __init generic_dpi_panel_drv_init(void)
743{
744 return omap_dss_register_driver(&dpi_driver);
745}
746
747static void __exit generic_dpi_panel_drv_exit(void)
748{
749 omap_dss_unregister_driver(&dpi_driver);
750}
751
752module_init(generic_dpi_panel_drv_init);
753module_exit(generic_dpi_panel_drv_exit);
754MODULE_LICENSE("GPL");