diff options
Diffstat (limited to 'drivers/video/omap2/displays/panel-generic-dpi.c')
-rw-r--r-- | drivers/video/omap2/displays/panel-generic-dpi.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 4a9b9ff5946..e5691dd55d4 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -33,6 +33,8 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/i2c.h> +#include "../../edid.h" #include <plat/panel-generic-dpi.h> @@ -356,6 +358,100 @@ static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, return dpi_check_timings(dssdev, timings); } +/* i2c / edid support */ + +#define DDC_ADDR 0x50 + +static int do_probe_ddc_edid(struct i2c_adapter *adapter, + unsigned char *buf, int block, int len) +{ + unsigned char start = block * EDID_LENGTH; + int i; + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + } + }; + + /* try at least 3 times, avoid miss for time-out */ + for (i = 0; i < 3; i++) { + if (i2c_transfer(adapter, msgs, 2) == 2) + return 0; + } + + return -1; +} + +static int generic_dpi_panel_get_edid(struct omap_dss_device *dssdev, + u8 *buf, int len) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct i2c_adapter *adapter; + int i; + u8 *edid, *new; + + adapter = i2c_get_adapter(panel_data->i2c_bus_num); + if (!adapter) { + printk(KERN_ERR "Invalid I2C adapter, bus number: %d\n", + panel_data->i2c_bus_num); + return -EINVAL; + } + + if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) + return -EINVAL; + + if (do_probe_ddc_edid(adapter, edid, 0, EDID_LENGTH)) + goto out; + + /* if there are extensions, probe more */ + if (edid[0x7e] != 0) { + new = krealloc(edid, (edid[0x7e] + 1) * EDID_LENGTH, + GFP_KERNEL); + if (!new) + goto out; + edid = new; + + for (i = 1; i <= edid[0x7e]; i++) { + if (do_probe_ddc_edid(adapter, + edid + i * EDID_LENGTH, + i, EDID_LENGTH)) + goto out; + } + } + + if (edid) { + memcpy(buf, edid, len); + kfree(edid); + return 0; + } + +out: + kfree(edid); + return -EINVAL; +} + +static bool generic_dpi_panel_is_detected(struct omap_dss_device *dssdev) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct i2c_adapter *adapter; + unsigned char out; + + adapter = i2c_get_adapter(panel_data->i2c_bus_num); + if (!adapter) { + return omapdss_default_is_detected(dssdev); + } + + return (do_probe_ddc_edid(adapter, &out, 0, 1) == 0); +} + static struct omap_dss_driver dpi_driver = { .probe = generic_dpi_panel_probe, .remove = generic_dpi_panel_remove, @@ -369,6 +465,9 @@ static struct omap_dss_driver dpi_driver = { .get_timings = generic_dpi_panel_get_timings, .check_timings = generic_dpi_panel_check_timings, + .get_edid = generic_dpi_panel_get_edid, + .is_detected = generic_dpi_panel_is_detected, + .driver = { .name = "generic_dpi_panel", .owner = THIS_MODULE, |