1 /*
2  * DVI output support
3  *
4  * Copyright (C) 2011 Texas Instruments Inc
5  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <video/omapdss.h>
23 #include <linux/i2c.h>
24 #include <drm/drm_edid.h>
25 
26 #include <video/omap-panel-dvi.h>
27 
28 static const struct omap_video_timings panel_dvi_default_timings = {
29 	.x_res		= 640,
30 	.y_res		= 480,
31 
32 	.pixel_clock	= 23500,
33 
34 	.hfp		= 48,
35 	.hsw		= 32,
36 	.hbp		= 80,
37 
38 	.vfp		= 3,
39 	.vsw		= 4,
40 	.vbp		= 7,
41 };
42 
43 struct panel_drv_data {
44 	struct omap_dss_device *dssdev;
45 
46 	struct mutex lock;
47 };
48 
49 static inline struct panel_dvi_platform_data
get_pdata(const struct omap_dss_device * dssdev)50 *get_pdata(const struct omap_dss_device *dssdev)
51 {
52 	return dssdev->data;
53 }
54 
panel_dvi_power_on(struct omap_dss_device * dssdev)55 static int panel_dvi_power_on(struct omap_dss_device *dssdev)
56 {
57 	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
58 	int r;
59 
60 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
61 		return 0;
62 
63 	r = omapdss_dpi_display_enable(dssdev);
64 	if (r)
65 		goto err0;
66 
67 	if (pdata->platform_enable) {
68 		r = pdata->platform_enable(dssdev);
69 		if (r)
70 			goto err1;
71 	}
72 
73 	return 0;
74 err1:
75 	omapdss_dpi_display_disable(dssdev);
76 err0:
77 	return r;
78 }
79 
panel_dvi_power_off(struct omap_dss_device * dssdev)80 static void panel_dvi_power_off(struct omap_dss_device *dssdev)
81 {
82 	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
83 
84 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
85 		return;
86 
87 	if (pdata->platform_disable)
88 		pdata->platform_disable(dssdev);
89 
90 	omapdss_dpi_display_disable(dssdev);
91 }
92 
panel_dvi_probe(struct omap_dss_device * dssdev)93 static int panel_dvi_probe(struct omap_dss_device *dssdev)
94 {
95 	struct panel_drv_data *ddata;
96 
97 	ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
98 	if (!ddata)
99 		return -ENOMEM;
100 
101 	dssdev->panel.timings = panel_dvi_default_timings;
102 	dssdev->panel.config = OMAP_DSS_LCD_TFT;
103 
104 	ddata->dssdev = dssdev;
105 	mutex_init(&ddata->lock);
106 
107 	dev_set_drvdata(&dssdev->dev, ddata);
108 
109 	return 0;
110 }
111 
panel_dvi_remove(struct omap_dss_device * dssdev)112 static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
113 {
114 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
115 
116 	mutex_lock(&ddata->lock);
117 
118 	dev_set_drvdata(&dssdev->dev, NULL);
119 
120 	mutex_unlock(&ddata->lock);
121 
122 	kfree(ddata);
123 }
124 
panel_dvi_enable(struct omap_dss_device * dssdev)125 static int panel_dvi_enable(struct omap_dss_device *dssdev)
126 {
127 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
128 	int r;
129 
130 	mutex_lock(&ddata->lock);
131 
132 	r = panel_dvi_power_on(dssdev);
133 	if (r == 0)
134 		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
135 
136 	mutex_unlock(&ddata->lock);
137 
138 	return r;
139 }
140 
panel_dvi_disable(struct omap_dss_device * dssdev)141 static void panel_dvi_disable(struct omap_dss_device *dssdev)
142 {
143 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
144 
145 	mutex_lock(&ddata->lock);
146 
147 	panel_dvi_power_off(dssdev);
148 
149 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
150 
151 	mutex_unlock(&ddata->lock);
152 }
153 
panel_dvi_suspend(struct omap_dss_device * dssdev)154 static int panel_dvi_suspend(struct omap_dss_device *dssdev)
155 {
156 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
157 
158 	mutex_lock(&ddata->lock);
159 
160 	panel_dvi_power_off(dssdev);
161 
162 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
163 
164 	mutex_unlock(&ddata->lock);
165 
166 	return 0;
167 }
168 
panel_dvi_resume(struct omap_dss_device * dssdev)169 static int panel_dvi_resume(struct omap_dss_device *dssdev)
170 {
171 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
172 	int r;
173 
174 	mutex_lock(&ddata->lock);
175 
176 	r = panel_dvi_power_on(dssdev);
177 	if (r == 0)
178 		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
179 
180 	mutex_unlock(&ddata->lock);
181 
182 	return r;
183 }
184 
panel_dvi_set_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)185 static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
186 		struct omap_video_timings *timings)
187 {
188 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
189 
190 	mutex_lock(&ddata->lock);
191 	dpi_set_timings(dssdev, timings);
192 	mutex_unlock(&ddata->lock);
193 }
194 
panel_dvi_get_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)195 static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
196 		struct omap_video_timings *timings)
197 {
198 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
199 
200 	mutex_lock(&ddata->lock);
201 	*timings = dssdev->panel.timings;
202 	mutex_unlock(&ddata->lock);
203 }
204 
panel_dvi_check_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)205 static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
206 		struct omap_video_timings *timings)
207 {
208 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
209 	int r;
210 
211 	mutex_lock(&ddata->lock);
212 	r = dpi_check_timings(dssdev, timings);
213 	mutex_unlock(&ddata->lock);
214 
215 	return r;
216 }
217 
218 
panel_dvi_ddc_read(struct i2c_adapter * adapter,unsigned char * buf,u16 count,u8 offset)219 static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
220 		unsigned char *buf, u16 count, u8 offset)
221 {
222 	int r, retries;
223 
224 	for (retries = 3; retries > 0; retries--) {
225 		struct i2c_msg msgs[] = {
226 			{
227 				.addr   = DDC_ADDR,
228 				.flags  = 0,
229 				.len    = 1,
230 				.buf    = &offset,
231 			}, {
232 				.addr   = DDC_ADDR,
233 				.flags  = I2C_M_RD,
234 				.len    = count,
235 				.buf    = buf,
236 			}
237 		};
238 
239 		r = i2c_transfer(adapter, msgs, 2);
240 		if (r == 2)
241 			return 0;
242 
243 		if (r != -EAGAIN)
244 			break;
245 	}
246 
247 	return r < 0 ? r : -EIO;
248 }
249 
panel_dvi_read_edid(struct omap_dss_device * dssdev,u8 * edid,int len)250 static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
251 		u8 *edid, int len)
252 {
253 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
254 	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
255 	struct i2c_adapter *adapter;
256 	int r, l, bytes_read;
257 
258 	mutex_lock(&ddata->lock);
259 
260 	if (pdata->i2c_bus_num == 0) {
261 		r = -ENODEV;
262 		goto err;
263 	}
264 
265 	adapter = i2c_get_adapter(pdata->i2c_bus_num);
266 	if (!adapter) {
267 		dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
268 				pdata->i2c_bus_num);
269 		r = -EINVAL;
270 		goto err;
271 	}
272 
273 	l = min(EDID_LENGTH, len);
274 	r = panel_dvi_ddc_read(adapter, edid, l, 0);
275 	if (r)
276 		goto err;
277 
278 	bytes_read = l;
279 
280 	/* if there are extensions, read second block */
281 	if (len > EDID_LENGTH && edid[0x7e] > 0) {
282 		l = min(EDID_LENGTH, len - EDID_LENGTH);
283 
284 		r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
285 				l, EDID_LENGTH);
286 		if (r)
287 			goto err;
288 
289 		bytes_read += l;
290 	}
291 
292 	mutex_unlock(&ddata->lock);
293 
294 	return bytes_read;
295 
296 err:
297 	mutex_unlock(&ddata->lock);
298 	return r;
299 }
300 
panel_dvi_detect(struct omap_dss_device * dssdev)301 static bool panel_dvi_detect(struct omap_dss_device *dssdev)
302 {
303 	struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
304 	struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
305 	struct i2c_adapter *adapter;
306 	unsigned char out;
307 	int r;
308 
309 	mutex_lock(&ddata->lock);
310 
311 	if (pdata->i2c_bus_num == 0)
312 		goto out;
313 
314 	adapter = i2c_get_adapter(pdata->i2c_bus_num);
315 	if (!adapter)
316 		goto out;
317 
318 	r = panel_dvi_ddc_read(adapter, &out, 1, 0);
319 
320 	mutex_unlock(&ddata->lock);
321 
322 	return r == 0;
323 
324 out:
325 	mutex_unlock(&ddata->lock);
326 	return true;
327 }
328 
329 static struct omap_dss_driver panel_dvi_driver = {
330 	.probe		= panel_dvi_probe,
331 	.remove		= __exit_p(panel_dvi_remove),
332 
333 	.enable		= panel_dvi_enable,
334 	.disable	= panel_dvi_disable,
335 	.suspend	= panel_dvi_suspend,
336 	.resume		= panel_dvi_resume,
337 
338 	.set_timings	= panel_dvi_set_timings,
339 	.get_timings	= panel_dvi_get_timings,
340 	.check_timings	= panel_dvi_check_timings,
341 
342 	.read_edid	= panel_dvi_read_edid,
343 	.detect		= panel_dvi_detect,
344 
345 	.driver         = {
346 		.name   = "dvi",
347 		.owner  = THIS_MODULE,
348 	},
349 };
350 
panel_dvi_init(void)351 static int __init panel_dvi_init(void)
352 {
353 	return omap_dss_register_driver(&panel_dvi_driver);
354 }
355 
panel_dvi_exit(void)356 static void __exit panel_dvi_exit(void)
357 {
358 	omap_dss_unregister_driver(&panel_dvi_driver);
359 }
360 
361 module_init(panel_dvi_init);
362 module_exit(panel_dvi_exit);
363 MODULE_LICENSE("GPL");
364