4 * Copyright (C) 2011 Texas Instruments Inc
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.
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
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/>.
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>
26 #include <video/omap-panel-dvi.h>
28 static const struct omap_video_timings panel_dvi_default_timings
= {
43 struct panel_drv_data
{
44 struct omap_dss_device
*dssdev
;
49 static inline struct panel_dvi_platform_data
50 *get_pdata(const struct omap_dss_device
*dssdev
)
55 static int panel_dvi_power_on(struct omap_dss_device
*dssdev
)
57 struct panel_dvi_platform_data
*pdata
= get_pdata(dssdev
);
60 if (dssdev
->state
== OMAP_DSS_DISPLAY_ACTIVE
)
63 r
= omapdss_dpi_display_enable(dssdev
);
67 if (pdata
->platform_enable
) {
68 r
= pdata
->platform_enable(dssdev
);
75 omapdss_dpi_display_disable(dssdev
);
80 static void panel_dvi_power_off(struct omap_dss_device
*dssdev
)
82 struct panel_dvi_platform_data
*pdata
= get_pdata(dssdev
);
84 if (dssdev
->state
!= OMAP_DSS_DISPLAY_ACTIVE
)
87 if (pdata
->platform_disable
)
88 pdata
->platform_disable(dssdev
);
90 omapdss_dpi_display_disable(dssdev
);
93 static int panel_dvi_probe(struct omap_dss_device
*dssdev
)
95 struct panel_drv_data
*ddata
;
97 ddata
= kzalloc(sizeof(*ddata
), GFP_KERNEL
);
101 dssdev
->panel
.timings
= panel_dvi_default_timings
;
102 dssdev
->panel
.config
= OMAP_DSS_LCD_TFT
;
104 ddata
->dssdev
= dssdev
;
105 mutex_init(&ddata
->lock
);
107 dev_set_drvdata(&dssdev
->dev
, ddata
);
112 static void __exit
panel_dvi_remove(struct omap_dss_device
*dssdev
)
114 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
116 mutex_lock(&ddata
->lock
);
118 dev_set_drvdata(&dssdev
->dev
, NULL
);
120 mutex_unlock(&ddata
->lock
);
125 static int panel_dvi_enable(struct omap_dss_device
*dssdev
)
127 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
130 mutex_lock(&ddata
->lock
);
132 r
= panel_dvi_power_on(dssdev
);
134 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
136 mutex_unlock(&ddata
->lock
);
141 static void panel_dvi_disable(struct omap_dss_device
*dssdev
)
143 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
145 mutex_lock(&ddata
->lock
);
147 panel_dvi_power_off(dssdev
);
149 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
151 mutex_unlock(&ddata
->lock
);
154 static int panel_dvi_suspend(struct omap_dss_device
*dssdev
)
156 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
158 mutex_lock(&ddata
->lock
);
160 panel_dvi_power_off(dssdev
);
162 dssdev
->state
= OMAP_DSS_DISPLAY_SUSPENDED
;
164 mutex_unlock(&ddata
->lock
);
169 static int panel_dvi_resume(struct omap_dss_device
*dssdev
)
171 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
174 mutex_lock(&ddata
->lock
);
176 r
= panel_dvi_power_on(dssdev
);
178 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
180 mutex_unlock(&ddata
->lock
);
185 static void panel_dvi_set_timings(struct omap_dss_device
*dssdev
,
186 struct omap_video_timings
*timings
)
188 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
190 mutex_lock(&ddata
->lock
);
191 dpi_set_timings(dssdev
, timings
);
192 mutex_unlock(&ddata
->lock
);
195 static void panel_dvi_get_timings(struct omap_dss_device
*dssdev
,
196 struct omap_video_timings
*timings
)
198 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
200 mutex_lock(&ddata
->lock
);
201 *timings
= dssdev
->panel
.timings
;
202 mutex_unlock(&ddata
->lock
);
205 static int panel_dvi_check_timings(struct omap_dss_device
*dssdev
,
206 struct omap_video_timings
*timings
)
208 struct panel_drv_data
*ddata
= dev_get_drvdata(&dssdev
->dev
);
211 mutex_lock(&ddata
->lock
);
212 r
= dpi_check_timings(dssdev
, timings
);
213 mutex_unlock(&ddata
->lock
);
219 static int panel_dvi_ddc_read(struct i2c_adapter
*adapter
,
220 unsigned char *buf
, u16 count
, u8 offset
)
224 for (retries
= 3; retries
> 0; retries
--) {
225 struct i2c_msg msgs
[] = {
239 r
= i2c_transfer(adapter
, msgs
, 2);
247 return r
< 0 ? r
: -EIO
;
250 static int panel_dvi_read_edid(struct omap_dss_device
*dssdev
,
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
;
258 mutex_lock(&ddata
->lock
);
260 if (pdata
->i2c_bus_num
== 0) {
265 adapter
= i2c_get_adapter(pdata
->i2c_bus_num
);
267 dev_err(&dssdev
->dev
, "Failed to get I2C adapter, bus %d\n",
273 l
= min(EDID_LENGTH
, len
);
274 r
= panel_dvi_ddc_read(adapter
, edid
, l
, 0);
280 /* if there are extensions, read second block */
281 if (len
> EDID_LENGTH
&& edid
[0x7e] > 0) {
282 l
= min(EDID_LENGTH
, len
- EDID_LENGTH
);
284 r
= panel_dvi_ddc_read(adapter
, edid
+ EDID_LENGTH
,
292 mutex_unlock(&ddata
->lock
);
297 mutex_unlock(&ddata
->lock
);
301 static bool panel_dvi_detect(struct omap_dss_device
*dssdev
)
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
;
309 mutex_lock(&ddata
->lock
);
311 if (pdata
->i2c_bus_num
== 0)
314 adapter
= i2c_get_adapter(pdata
->i2c_bus_num
);
318 r
= panel_dvi_ddc_read(adapter
, &out
, 1, 0);
320 mutex_unlock(&ddata
->lock
);
325 mutex_unlock(&ddata
->lock
);
329 static struct omap_dss_driver panel_dvi_driver
= {
330 .probe
= panel_dvi_probe
,
331 .remove
= __exit_p(panel_dvi_remove
),
333 .enable
= panel_dvi_enable
,
334 .disable
= panel_dvi_disable
,
335 .suspend
= panel_dvi_suspend
,
336 .resume
= panel_dvi_resume
,
338 .set_timings
= panel_dvi_set_timings
,
339 .get_timings
= panel_dvi_get_timings
,
340 .check_timings
= panel_dvi_check_timings
,
342 .read_edid
= panel_dvi_read_edid
,
343 .detect
= panel_dvi_detect
,
347 .owner
= THIS_MODULE
,
351 static int __init
panel_dvi_init(void)
353 return omap_dss_register_driver(&panel_dvi_driver
);
356 static void __exit
panel_dvi_exit(void)
358 omap_dss_unregister_driver(&panel_dvi_driver
);
361 module_init(panel_dvi_init
);
362 module_exit(panel_dvi_exit
);
363 MODULE_LICENSE("GPL");