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