summaryrefslogtreecommitdiff
path: root/drivers/video/mxc/ldb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/mxc/ldb.c')
-rw-r--r--drivers/video/mxc/ldb.c137
1 files changed, 135 insertions, 2 deletions
diff --git a/drivers/video/mxc/ldb.c b/drivers/video/mxc/ldb.c
index 19de5c541fdd..278475c088f1 100644
--- a/drivers/video/mxc/ldb.c
+++ b/drivers/video/mxc/ldb.c
@@ -102,6 +102,8 @@ struct ldb_data {
};
static int g_ldb_mode;
+static struct i2c_client *ldb_i2c_client[2];
+static u8 g_edid[2][512];
static struct fb_videomode ldb_modedb[] = {
{
@@ -131,6 +133,8 @@ static struct fb_videomode ldb_modedb[] = {
};
static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);
+static int mxc_ldb_edidread(struct i2c_client *client);
+
static int bits_per_pixel(int pixel_fmt)
{
switch (pixel_fmt) {
@@ -412,10 +416,12 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
int ret = 0, i;
struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;
+ struct i2c_client *i2c_dev;
struct resource *res;
uint32_t base_addr;
uint32_t reg, setting_idx;
uint32_t ch_mask = 0, ch_val = 0;
+ int lvds_channel = 0;
uint32_t ipu_id, disp_id;
/* if input format not valid, make RGB666 as default*/
@@ -428,7 +434,6 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
if (!ldb->inited) {
char di_clk[] = "ipu1_di0_clk";
char ldb_clk[] = "ldb_di0_clk";
- int lvds_channel = 0;
setting_idx = 0;
res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);
@@ -619,10 +624,12 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
}
ldb->inited = true;
+
+ i2c_dev = ldb_i2c_client[lvds_channel];
+
} else { /* second time for separate mode */
char di_clk[] = "ipu1_di0_clk";
char ldb_clk[] = "ldb_di0_clk";
- int lvds_channel;
if ((ldb->mode == LDB_SPL_DI0) ||
(ldb->mode == LDB_SPL_DI1) ||
@@ -701,9 +708,16 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
return PTR_ERR(ldb->setting[setting_idx].di_clk);
}
+ i2c_dev = ldb_i2c_client[lvds_channel];
+
dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk);
}
+ if (i2c_dev)
+ mxc_dispdrv_setdev(ldb->disp_ldb, &i2c_dev->dev);
+ else
+ mxc_dispdrv_setdev(ldb->disp_ldb, NULL);
+
ldb->setting[setting_idx].ch_mask = ch_mask;
ldb->setting[setting_idx].ch_val = ch_val;
@@ -734,6 +748,23 @@ static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
}
}
+ /* get screen size in edid */
+ if (i2c_dev) {
+ ret = mxc_ldb_edidread(i2c_dev);
+ if (ret > 0) {
+ fb_edid_to_monspecs(&g_edid[lvds_channel][0],
+ &setting->fbi->monspecs);
+ /* centimeter to millimeter */
+ setting->fbi->var.width =
+ setting->fbi->monspecs.max_x * 10;
+ setting->fbi->var.height =
+ setting->fbi->monspecs.max_y * 10;
+ } else {
+ /* ignore i2c access failure */
+ ret = 0;
+ }
+ }
+
/* save current ldb setting for fb notifier */
ldb->setting[setting_idx].active = true;
ldb->setting[setting_idx].ipu = setting->dev_id;
@@ -791,6 +822,108 @@ static int ldb_resume(struct platform_device *pdev)
return 0;
}
+
+static int mxc_ldb_edidread(struct i2c_client *client)
+{
+ int ret = 0;
+ unsigned char regaddr = 0;
+ struct i2c_adapter *adp = client->adapter;
+ int ldb_id = (int)client->dev.platform_data;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .len = 1,
+ .buf = &regaddr,
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .len = 512,
+ .buf = &g_edid[ldb_id][0],
+ },
+ };
+
+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static ssize_t mxc_ldb_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ret = mxc_ldb_edidread(client);
+ if (ret < 0)
+ strcpy(buf, "plugout\n");
+ else
+ strcpy(buf, "plugin\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(cable_state, S_IRUGO, mxc_ldb_show_state, NULL);
+
+static int __devinit mxc_ldb_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ int ldb_id = (int)client->dev.platform_data;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+
+ ldb_i2c_client[ldb_id] = client;
+
+ ret = device_create_file(&client->dev, &dev_attr_cable_state);
+ if (ret < 0)
+ dev_warn(&client->dev,
+ "cound not create sys node for cable state\n");
+
+
+ return 0;
+}
+
+static int __devexit mxc_ldb_i2c_remove(struct i2c_client *client)
+{
+ int ldb_id = (int)client->dev.platform_data;
+ ldb_i2c_client[ldb_id] = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id mxc_ldb_i2c_id[] = {
+ { "mxc_ldb_i2c", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mxc_ldb_i2c_id);
+
+static struct i2c_driver mxc_ldb_i2c_driver = {
+ .driver = {
+ .name = "mxc_ldb_i2c",
+ },
+ .probe = mxc_ldb_i2c_probe,
+ .remove = mxc_ldb_i2c_remove,
+ .id_table = mxc_ldb_i2c_id,
+};
+
+static int __init mxc_ldb_i2c_init(void)
+{
+ return i2c_add_driver(&mxc_ldb_i2c_driver);
+}
+
+static void __exit mxc_ldb_i2c_exit(void)
+{
+ i2c_del_driver(&mxc_ldb_i2c_driver);
+}
+
+module_init(mxc_ldb_i2c_init);
+module_exit(mxc_ldb_i2c_exit);
+
/*!
* This function is called by the driver framework to initialize the LDB
* device.