2 * Generic DVI Connector driver
4 * Copyright (C) 2013 Texas Instruments
5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
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.
12 #include <linux/i2c.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
17 #include <drm/drm_edid.h>
19 #include <video/omapdss.h>
20 #include <video/omap-panel-data.h>
22 static const struct omap_video_timings dvic_default_timings
= {
26 .pixelclock
= 23500000,
36 .vsync_level
= OMAPDSS_SIG_ACTIVE_HIGH
,
37 .hsync_level
= OMAPDSS_SIG_ACTIVE_HIGH
,
38 .data_pclk_edge
= OMAPDSS_DRIVE_SIG_RISING_EDGE
,
39 .de_level
= OMAPDSS_SIG_ACTIVE_HIGH
,
40 .sync_pclk_edge
= OMAPDSS_DRIVE_SIG_FALLING_EDGE
,
43 struct panel_drv_data
{
44 struct omap_dss_device dssdev
;
45 struct omap_dss_device
*in
;
47 struct omap_video_timings timings
;
49 struct i2c_adapter
*i2c_adapter
;
52 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
54 static int dvic_connect(struct omap_dss_device
*dssdev
)
56 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
57 struct omap_dss_device
*in
= ddata
->in
;
60 if (omapdss_device_is_connected(dssdev
))
63 r
= in
->ops
.dvi
->connect(in
, dssdev
);
70 static void dvic_disconnect(struct omap_dss_device
*dssdev
)
72 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
73 struct omap_dss_device
*in
= ddata
->in
;
75 if (!omapdss_device_is_connected(dssdev
))
78 in
->ops
.dvi
->disconnect(in
, dssdev
);
81 static int dvic_enable(struct omap_dss_device
*dssdev
)
83 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
84 struct omap_dss_device
*in
= ddata
->in
;
87 if (!omapdss_device_is_connected(dssdev
))
90 if (omapdss_device_is_enabled(dssdev
))
93 in
->ops
.dvi
->set_timings(in
, &ddata
->timings
);
95 r
= in
->ops
.dvi
->enable(in
);
99 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
104 static void dvic_disable(struct omap_dss_device
*dssdev
)
106 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
107 struct omap_dss_device
*in
= ddata
->in
;
109 if (!omapdss_device_is_enabled(dssdev
))
112 in
->ops
.dvi
->disable(in
);
114 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
117 static void dvic_set_timings(struct omap_dss_device
*dssdev
,
118 struct omap_video_timings
*timings
)
120 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
121 struct omap_dss_device
*in
= ddata
->in
;
123 ddata
->timings
= *timings
;
124 dssdev
->panel
.timings
= *timings
;
126 in
->ops
.dvi
->set_timings(in
, timings
);
129 static void dvic_get_timings(struct omap_dss_device
*dssdev
,
130 struct omap_video_timings
*timings
)
132 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
134 *timings
= ddata
->timings
;
137 static int dvic_check_timings(struct omap_dss_device
*dssdev
,
138 struct omap_video_timings
*timings
)
140 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
141 struct omap_dss_device
*in
= ddata
->in
;
143 return in
->ops
.dvi
->check_timings(in
, timings
);
146 static int dvic_ddc_read(struct i2c_adapter
*adapter
,
147 unsigned char *buf
, u16 count
, u8 offset
)
151 for (retries
= 3; retries
> 0; retries
--) {
152 struct i2c_msg msgs
[] = {
166 r
= i2c_transfer(adapter
, msgs
, 2);
174 return r
< 0 ? r
: -EIO
;
177 static int dvic_read_edid(struct omap_dss_device
*dssdev
,
180 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
181 int r
, l
, bytes_read
;
183 if (!ddata
->i2c_adapter
)
186 l
= min(EDID_LENGTH
, len
);
187 r
= dvic_ddc_read(ddata
->i2c_adapter
, edid
, l
, 0);
193 /* if there are extensions, read second block */
194 if (len
> EDID_LENGTH
&& edid
[0x7e] > 0) {
195 l
= min(EDID_LENGTH
, len
- EDID_LENGTH
);
197 r
= dvic_ddc_read(ddata
->i2c_adapter
, edid
+ EDID_LENGTH
,
208 static bool dvic_detect(struct omap_dss_device
*dssdev
)
210 struct panel_drv_data
*ddata
= to_panel_data(dssdev
);
214 if (!ddata
->i2c_adapter
)
217 r
= dvic_ddc_read(ddata
->i2c_adapter
, &out
, 1, 0);
222 static struct omap_dss_driver dvic_driver
= {
223 .connect
= dvic_connect
,
224 .disconnect
= dvic_disconnect
,
226 .enable
= dvic_enable
,
227 .disable
= dvic_disable
,
229 .set_timings
= dvic_set_timings
,
230 .get_timings
= dvic_get_timings
,
231 .check_timings
= dvic_check_timings
,
233 .get_resolution
= omapdss_default_get_resolution
,
235 .read_edid
= dvic_read_edid
,
236 .detect
= dvic_detect
,
239 static int dvic_probe_pdata(struct platform_device
*pdev
)
241 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
242 struct connector_dvi_platform_data
*pdata
;
243 struct omap_dss_device
*in
, *dssdev
;
246 pdata
= dev_get_platdata(&pdev
->dev
);
247 i2c_bus_num
= pdata
->i2c_bus_num
;
249 if (i2c_bus_num
!= -1) {
250 struct i2c_adapter
*adapter
;
252 adapter
= i2c_get_adapter(i2c_bus_num
);
255 "Failed to get I2C adapter, bus %d\n",
257 return -EPROBE_DEFER
;
260 ddata
->i2c_adapter
= adapter
;
263 in
= omap_dss_find_output(pdata
->source
);
265 i2c_put_adapter(ddata
->i2c_adapter
);
267 dev_err(&pdev
->dev
, "Failed to find video source\n");
268 return -EPROBE_DEFER
;
273 dssdev
= &ddata
->dssdev
;
274 dssdev
->name
= pdata
->name
;
279 static int dvic_probe_of(struct platform_device
*pdev
)
281 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
282 struct device_node
*node
= pdev
->dev
.of_node
;
283 struct omap_dss_device
*in
;
284 struct device_node
*adapter_node
;
285 struct i2c_adapter
*adapter
;
287 in
= omapdss_of_find_source_for_first_ep(node
);
289 dev_err(&pdev
->dev
, "failed to find video source\n");
295 adapter_node
= of_parse_phandle(node
, "ddc-i2c-bus", 0);
297 adapter
= of_get_i2c_adapter_by_node(adapter_node
);
298 if (adapter
== NULL
) {
299 dev_err(&pdev
->dev
, "failed to parse ddc-i2c-bus\n");
300 omap_dss_put_device(ddata
->in
);
301 return -EPROBE_DEFER
;
304 ddata
->i2c_adapter
= adapter
;
310 static int dvic_probe(struct platform_device
*pdev
)
312 struct panel_drv_data
*ddata
;
313 struct omap_dss_device
*dssdev
;
316 ddata
= devm_kzalloc(&pdev
->dev
, sizeof(*ddata
), GFP_KERNEL
);
320 platform_set_drvdata(pdev
, ddata
);
322 if (dev_get_platdata(&pdev
->dev
)) {
323 r
= dvic_probe_pdata(pdev
);
326 } else if (pdev
->dev
.of_node
) {
327 r
= dvic_probe_of(pdev
);
334 ddata
->timings
= dvic_default_timings
;
336 dssdev
= &ddata
->dssdev
;
337 dssdev
->driver
= &dvic_driver
;
338 dssdev
->dev
= &pdev
->dev
;
339 dssdev
->type
= OMAP_DISPLAY_TYPE_DVI
;
340 dssdev
->owner
= THIS_MODULE
;
341 dssdev
->panel
.timings
= dvic_default_timings
;
343 r
= omapdss_register_display(dssdev
);
345 dev_err(&pdev
->dev
, "Failed to register panel\n");
352 omap_dss_put_device(ddata
->in
);
354 i2c_put_adapter(ddata
->i2c_adapter
);
359 static int __exit
dvic_remove(struct platform_device
*pdev
)
361 struct panel_drv_data
*ddata
= platform_get_drvdata(pdev
);
362 struct omap_dss_device
*dssdev
= &ddata
->dssdev
;
363 struct omap_dss_device
*in
= ddata
->in
;
365 omapdss_unregister_display(&ddata
->dssdev
);
367 dvic_disable(dssdev
);
368 dvic_disconnect(dssdev
);
370 omap_dss_put_device(in
);
372 i2c_put_adapter(ddata
->i2c_adapter
);
377 static const struct of_device_id dvic_of_match
[] = {
378 { .compatible
= "omapdss,dvi-connector", },
382 MODULE_DEVICE_TABLE(of
, dvic_of_match
);
384 static struct platform_driver dvi_connector_driver
= {
386 .remove
= __exit_p(dvic_remove
),
388 .name
= "connector-dvi",
389 .of_match_table
= dvic_of_match
,
390 .suppress_bind_attrs
= true,
394 module_platform_driver(dvi_connector_driver
);
396 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
397 MODULE_DESCRIPTION("Generic DVI Connector driver");
398 MODULE_LICENSE("GPL");