Commit | Line | Data |
---|---|---|
a9a62b6a BW |
1 | /* |
2 | * Generic DPI Panels support | |
3 | * | |
4 | * Copyright (C) 2010 Canonical Ltd. | |
5 | * Author: Bryan Wu <bryan.wu@canonical.com> | |
6 | * | |
ac1427e1 BW |
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 | * | |
a9a62b6a BW |
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> | |
a0b38cc4 | 36 | #include <video/omapdss.h> |
a9a62b6a | 37 | |
f8ae2f08 | 38 | #include <video/omap-panel-generic-dpi.h> |
a9a62b6a BW |
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 | /* Generic Panel */ | |
62 | { | |
63 | { | |
64 | .x_res = 640, | |
65 | .y_res = 480, | |
66 | ||
67 | .pixel_clock = 23500, | |
68 | ||
69 | .hfp = 48, | |
70 | .hsw = 32, | |
71 | .hbp = 80, | |
72 | ||
73 | .vfp = 3, | |
74 | .vsw = 4, | |
75 | .vbp = 7, | |
76 | }, | |
77 | .acbi = 0x0, | |
78 | .acb = 0x0, | |
79 | .config = OMAP_DSS_LCD_TFT, | |
80 | .power_on_delay = 0, | |
81 | .power_off_delay = 0, | |
82 | .name = "generic", | |
83 | }, | |
84 | ||
85 | /* Sharp LQ043T1DG01 */ | |
86 | { | |
87 | { | |
88 | .x_res = 480, | |
89 | .y_res = 272, | |
90 | ||
91 | .pixel_clock = 9000, | |
92 | ||
93 | .hsw = 42, | |
94 | .hfp = 3, | |
95 | .hbp = 2, | |
96 | ||
97 | .vsw = 11, | |
98 | .vfp = 3, | |
99 | .vbp = 2, | |
100 | }, | |
101 | .acbi = 0x0, | |
102 | .acb = 0x0, | |
103 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | |
104 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, | |
105 | .power_on_delay = 50, | |
106 | .power_off_delay = 100, | |
107 | .name = "sharp_lq", | |
108 | }, | |
109 | ||
110 | /* Sharp LS037V7DW01 */ | |
111 | { | |
112 | { | |
113 | .x_res = 480, | |
114 | .y_res = 640, | |
115 | ||
116 | .pixel_clock = 19200, | |
117 | ||
118 | .hsw = 2, | |
119 | .hfp = 1, | |
120 | .hbp = 28, | |
121 | ||
122 | .vsw = 1, | |
123 | .vfp = 1, | |
124 | .vbp = 1, | |
125 | }, | |
126 | .acbi = 0x0, | |
127 | .acb = 0x28, | |
128 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | |
129 | OMAP_DSS_LCD_IHS, | |
130 | .power_on_delay = 50, | |
131 | .power_off_delay = 100, | |
132 | .name = "sharp_ls", | |
133 | }, | |
134 | ||
135 | /* Toppoly TDO35S */ | |
136 | { | |
137 | { | |
138 | .x_res = 480, | |
139 | .y_res = 640, | |
140 | ||
141 | .pixel_clock = 26000, | |
142 | ||
143 | .hfp = 104, | |
144 | .hsw = 8, | |
145 | .hbp = 8, | |
146 | ||
147 | .vfp = 4, | |
148 | .vsw = 2, | |
149 | .vbp = 2, | |
150 | }, | |
151 | .acbi = 0x0, | |
152 | .acb = 0x0, | |
153 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | |
154 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC | | |
155 | OMAP_DSS_LCD_ONOFF, | |
156 | .power_on_delay = 0, | |
157 | .power_off_delay = 0, | |
158 | .name = "toppoly_tdo35s", | |
159 | }, | |
09dc89cb TV |
160 | |
161 | /* Samsung LTE430WQ-F0C */ | |
162 | { | |
163 | { | |
164 | .x_res = 480, | |
165 | .y_res = 272, | |
166 | ||
167 | .pixel_clock = 9200, | |
168 | ||
169 | .hfp = 8, | |
170 | .hsw = 41, | |
171 | .hbp = 45 - 41, | |
172 | ||
173 | .vfp = 4, | |
174 | .vsw = 10, | |
175 | .vbp = 12 - 10, | |
176 | }, | |
177 | .acbi = 0x0, | |
178 | .acb = 0x0, | |
179 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | |
180 | OMAP_DSS_LCD_IHS, | |
181 | .power_on_delay = 0, | |
182 | .power_off_delay = 0, | |
183 | .name = "samsung_lte430wq_f0c", | |
184 | }, | |
a9a62b6a BW |
185 | }; |
186 | ||
187 | struct panel_drv_data { | |
188 | ||
189 | struct omap_dss_device *dssdev; | |
190 | ||
191 | struct panel_config *panel_config; | |
192 | }; | |
193 | ||
194 | static inline struct panel_generic_dpi_data | |
195 | *get_panel_data(const struct omap_dss_device *dssdev) | |
196 | { | |
197 | return (struct panel_generic_dpi_data *) dssdev->data; | |
198 | } | |
199 | ||
200 | static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | |
201 | { | |
202 | int r; | |
203 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | |
204 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | |
205 | struct panel_config *panel_config = drv_data->panel_config; | |
206 | ||
207 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | |
208 | return 0; | |
209 | ||
210 | r = omapdss_dpi_display_enable(dssdev); | |
211 | if (r) | |
212 | goto err0; | |
213 | ||
214 | /* wait couple of vsyncs until enabling the LCD */ | |
215 | if (panel_config->power_on_delay) | |
216 | msleep(panel_config->power_on_delay); | |
217 | ||
218 | if (panel_data->platform_enable) { | |
219 | r = panel_data->platform_enable(dssdev); | |
220 | if (r) | |
221 | goto err1; | |
222 | } | |
223 | ||
224 | return 0; | |
225 | err1: | |
226 | omapdss_dpi_display_disable(dssdev); | |
227 | err0: | |
228 | return r; | |
229 | } | |
230 | ||
231 | static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) | |
232 | { | |
233 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | |
234 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | |
235 | struct panel_config *panel_config = drv_data->panel_config; | |
236 | ||
237 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | |
238 | return; | |
239 | ||
240 | if (panel_data->platform_disable) | |
241 | panel_data->platform_disable(dssdev); | |
242 | ||
243 | /* wait couple of vsyncs after disabling the LCD */ | |
244 | if (panel_config->power_off_delay) | |
245 | msleep(panel_config->power_off_delay); | |
246 | ||
247 | omapdss_dpi_display_disable(dssdev); | |
248 | } | |
249 | ||
250 | static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |
251 | { | |
252 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | |
253 | struct panel_config *panel_config = NULL; | |
254 | struct panel_drv_data *drv_data = NULL; | |
255 | int i; | |
256 | ||
257 | dev_dbg(&dssdev->dev, "probe\n"); | |
258 | ||
259 | if (!panel_data || !panel_data->name) | |
260 | return -EINVAL; | |
261 | ||
262 | for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) { | |
263 | if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) { | |
264 | panel_config = &generic_dpi_panels[i]; | |
265 | break; | |
266 | } | |
267 | } | |
268 | ||
269 | if (!panel_config) | |
270 | return -EINVAL; | |
271 | ||
272 | dssdev->panel.config = panel_config->config; | |
273 | dssdev->panel.timings = panel_config->timings; | |
274 | dssdev->panel.acb = panel_config->acb; | |
275 | dssdev->panel.acbi = panel_config->acbi; | |
276 | ||
277 | drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); | |
278 | if (!drv_data) | |
279 | return -ENOMEM; | |
280 | ||
281 | drv_data->dssdev = dssdev; | |
282 | drv_data->panel_config = panel_config; | |
283 | ||
284 | dev_set_drvdata(&dssdev->dev, drv_data); | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
289 | static void generic_dpi_panel_remove(struct omap_dss_device *dssdev) | |
290 | { | |
291 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | |
292 | ||
293 | dev_dbg(&dssdev->dev, "remove\n"); | |
294 | ||
295 | kfree(drv_data); | |
296 | ||
297 | dev_set_drvdata(&dssdev->dev, NULL); | |
298 | } | |
299 | ||
300 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) | |
301 | { | |
302 | int r = 0; | |
303 | ||
304 | r = generic_dpi_panel_power_on(dssdev); | |
305 | if (r) | |
306 | return r; | |
307 | ||
308 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | |
309 | ||
310 | return 0; | |
311 | } | |
312 | ||
313 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | |
314 | { | |
315 | generic_dpi_panel_power_off(dssdev); | |
316 | ||
317 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | |
318 | } | |
319 | ||
320 | static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) | |
321 | { | |
322 | generic_dpi_panel_power_off(dssdev); | |
323 | ||
324 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) | |
330 | { | |
331 | int r = 0; | |
332 | ||
333 | r = generic_dpi_panel_power_on(dssdev); | |
334 | if (r) | |
335 | return r; | |
336 | ||
337 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | |
338 | ||
339 | return 0; | |
340 | } | |
341 | ||
342 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | |
343 | struct omap_video_timings *timings) | |
344 | { | |
345 | dpi_set_timings(dssdev, timings); | |
346 | } | |
347 | ||
348 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | |
349 | struct omap_video_timings *timings) | |
350 | { | |
351 | *timings = dssdev->panel.timings; | |
352 | } | |
353 | ||
354 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, | |
355 | struct omap_video_timings *timings) | |
356 | { | |
357 | return dpi_check_timings(dssdev, timings); | |
358 | } | |
359 | ||
360 | static struct omap_dss_driver dpi_driver = { | |
361 | .probe = generic_dpi_panel_probe, | |
362 | .remove = generic_dpi_panel_remove, | |
363 | ||
364 | .enable = generic_dpi_panel_enable, | |
365 | .disable = generic_dpi_panel_disable, | |
366 | .suspend = generic_dpi_panel_suspend, | |
367 | .resume = generic_dpi_panel_resume, | |
368 | ||
369 | .set_timings = generic_dpi_panel_set_timings, | |
370 | .get_timings = generic_dpi_panel_get_timings, | |
371 | .check_timings = generic_dpi_panel_check_timings, | |
372 | ||
373 | .driver = { | |
374 | .name = "generic_dpi_panel", | |
375 | .owner = THIS_MODULE, | |
376 | }, | |
377 | }; | |
378 | ||
379 | static int __init generic_dpi_panel_drv_init(void) | |
380 | { | |
381 | return omap_dss_register_driver(&dpi_driver); | |
382 | } | |
383 | ||
384 | static void __exit generic_dpi_panel_drv_exit(void) | |
385 | { | |
386 | omap_dss_unregister_driver(&dpi_driver); | |
387 | } | |
388 | ||
389 | module_init(generic_dpi_panel_drv_init); | |
390 | module_exit(generic_dpi_panel_drv_exit); | |
391 | MODULE_LICENSE("GPL"); |