msm_fb: display: Add LVDS display driver support for Chimei WXGA

Add LVDS display driver support for Chimei WXGA LVDS display panel

Signed-off-by: Ravishangar Kalyanam <rkalya@codeaurora.org>
Change-Id: If8830295814d0e27f49dfffdeb96db63f73809ba
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 448194a..f261931 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -93,6 +93,10 @@
 	bool
 	default n
 
+config FB_MSM_LVDS
+	bool
+	default n
+
 config FB_MSM_OVERLAY
 	depends on FB_MSM_MDP40 && ANDROID_PMEM
 	bool "MDP4 overlay support"
@@ -247,6 +251,11 @@
 	select FB_MSM_LCDC_PANEL
 	default n
 
+config FB_MSM_LVDS_CHIMEI_WXGA
+	bool
+	select FB_MSM_LVDS
+	default n
+
 config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
 	bool
 	select FB_MSM_MIPI_DSI_TOSHIBA
@@ -389,6 +398,12 @@
 	---help---
 	  Support for LCDC Samsung OLED PT (480x800) panel
 
+config FB_MSM_LVDS_CHIMEI_WXGA_PANEL
+        bool "LVDS Chimei WXGA Panel"
+        select FB_MSM_LVDS_CHIMEI_WXGA
+        ---help---
+          Support for LVDS Chimei WXGA(1366x768) panel
+
 config FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
 	depends on FB_MSM_LCDC_HW
 	bool "MDDI Panel Auto Detect + LCDC Prism WVGA"
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index dc02da4..2d40b15 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -56,6 +56,9 @@
 # LCDC
 obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
 
+# LVDS
+obj-$(CONFIG_FB_MSM_LVDS) += lvds.o
+
 # MDDI
 msm_mddi-objs := mddi.o mddihost.o mddihosti.o
 obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
@@ -143,6 +146,7 @@
 obj-$(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) += lcdc_samsung_oled_pt.o
 obj-$(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) += adv7520.o
 obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
+obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o
 obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o
 
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
new file mode 100644
index 0000000..7ef437c
--- /dev/null
+++ b/drivers/video/msm/lvds.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <mach/clk.h>
+
+#include "msm_fb.h"
+
+static int lvds_probe(struct platform_device *pdev);
+static int lvds_remove(struct platform_device *pdev);
+
+static int lvds_off(struct platform_device *pdev);
+static int lvds_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static struct clk *lvds_clk;
+
+static struct platform_driver lvds_driver = {
+	.probe = lvds_probe,
+	.remove = lvds_remove,
+	.suspend = NULL,
+	.resume = NULL,
+	.shutdown = NULL,
+	.driver = {
+		   .name = "lvds",
+		   },
+};
+
+static struct lcdc_platform_data *lvds_pdata;
+
+static int lvds_off(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	mfd = platform_get_drvdata(pdev);
+	ret = panel_next_off(pdev);
+
+	clk_disable(lvds_clk);
+
+	if (lvds_pdata && lvds_pdata->lcdc_power_save)
+		lvds_pdata->lcdc_power_save(0);
+
+	if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+		ret = lvds_pdata->lcdc_gpio_config(0);
+
+#ifdef CONFIG_MSM_BUS_SCALING
+	mdp_bus_scale_update_request(0);
+#endif
+
+	return ret;
+}
+
+static int lvds_on(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+	unsigned long panel_pixclock_freq = 0;
+	mfd = platform_get_drvdata(pdev);
+
+	if (lvds_pdata && lvds_pdata->lcdc_get_clk)
+		panel_pixclock_freq = lvds_pdata->lcdc_get_clk();
+
+	if (!panel_pixclock_freq)
+		panel_pixclock_freq = mfd->fbi->var.pixclock;
+#ifdef CONFIG_MSM_BUS_SCALING
+	mdp_bus_scale_update_request(2);
+#endif
+	mfd = platform_get_drvdata(pdev);
+
+	mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
+					mfd->fbi->var.pixclock);
+	ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
+	if (ret) {
+		pr_err("%s: Can't set lvds clock to rate %u\n",
+			__func__, mfd->fbi->var.pixclock);
+		goto out;
+	}
+
+	clk_enable(lvds_clk);
+
+	if (lvds_pdata && lvds_pdata->lcdc_power_save)
+		lvds_pdata->lcdc_power_save(1);
+	if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+		ret = lvds_pdata->lcdc_gpio_config(1);
+
+	ret = panel_next_on(pdev);
+
+out:
+	return ret;
+}
+
+static int lvds_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+	struct fb_info *fbi;
+	struct platform_device *mdp_dev = NULL;
+	struct msm_fb_panel_data *pdata = NULL;
+	int rc;
+
+	if (pdev->id == 0) {
+		lvds_pdata = pdev->dev.platform_data;
+		return 0;
+	}
+
+	mfd = platform_get_drvdata(pdev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+		return -ENOMEM;
+
+	mdp_dev = platform_device_alloc("mdp", pdev->id);
+	if (!mdp_dev)
+		return -ENOMEM;
+
+	/*
+	 * link to the latest pdev
+	 */
+	mfd->pdev = mdp_dev;
+	mfd->dest = DISPLAY_LCDC;
+
+	/*
+	 * alloc panel device data
+	 */
+	if (platform_device_add_data
+	    (mdp_dev, pdev->dev.platform_data,
+	     sizeof(struct msm_fb_panel_data))) {
+		pr_err("lvds_probe: platform_device_add_data failed!\n");
+		platform_device_put(mdp_dev);
+		return -ENOMEM;
+	}
+	/*
+	 * data chain
+	 */
+	pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
+	pdata->on = lvds_on;
+	pdata->off = lvds_off;
+	pdata->next = pdev;
+
+	/*
+	 * get/set panel specific fb info
+	 */
+	mfd->panel_info = pdata->panel_info;
+
+	if (mfd->index == 0)
+		mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+	else
+		mfd->fb_imgType = MDP_RGB_565;
+
+	fbi = mfd->fbi;
+	fbi->var.pixclock = clk_round_rate(lvds_clk,
+					mfd->panel_info.clk_rate);
+	fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
+	fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
+	fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
+	fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
+	fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
+	fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
+
+	/*
+	 * set driver data
+	 */
+	platform_set_drvdata(mdp_dev, mfd);
+	/*
+	 * register in mdp driver
+	 */
+	rc = platform_device_add(mdp_dev);
+	if (rc)
+		goto lvds_probe_err;
+
+	pdev_list[pdev_list_cnt++] = pdev;
+
+	return 0;
+
+lvds_probe_err:
+	platform_device_put(mdp_dev);
+	return rc;
+}
+
+static int lvds_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int lvds_register_driver(void)
+{
+	return platform_driver_register(&lvds_driver);
+}
+
+static int __init lvds_driver_init(void)
+{
+	lvds_clk = clk_get(NULL, "lvds_clk");
+	if (IS_ERR(lvds_clk)) {
+		pr_err("Couldnt find lvds_clk\n");
+		return -EINVAL;
+	}
+
+	return lvds_register_driver();
+}
+
+module_init(lvds_driver_init);
diff --git a/drivers/video/msm/lvds_chimei_wxga.c b/drivers/video/msm/lvds_chimei_wxga.c
new file mode 100644
index 0000000..2c6b6d4
--- /dev/null
+++ b/drivers/video/msm/lvds_chimei_wxga.c
@@ -0,0 +1,124 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm_fb.h"
+
+static struct msm_panel_common_pdata *cm_pdata;
+static struct platform_device *cm_fbpdev;
+
+static int lvds_chimei_panel_on(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int lvds_chimei_panel_off(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static void lvds_chimei_set_backlight(struct msm_fb_data_type *mfd)
+{
+}
+
+static int __devinit lvds_chimei_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	if (pdev->id == 0) {
+		cm_pdata = pdev->dev.platform_data;
+		if (cm_pdata == NULL)
+			pr_err("%s: no PWM gpio specified\n", __func__);
+		return 0;
+	}
+
+	cm_fbpdev = msm_fb_add_device(pdev);
+	if (!cm_fbpdev) {
+		dev_err(&pdev->dev, "failed to add msm_fb device\n");
+		rc = -ENODEV;
+		goto probe_exit;
+	}
+
+probe_exit:
+	return rc;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = lvds_chimei_probe,
+	.driver = {
+		.name   = "lvds_chimei_wxga",
+	},
+};
+
+static struct msm_fb_panel_data lvds_chimei_panel_data = {
+	.on = lvds_chimei_panel_on,
+	.off = lvds_chimei_panel_off,
+	.set_backlight = lvds_chimei_set_backlight,
+};
+
+static struct platform_device this_device = {
+	.name   = "lvds_chimei_wxga",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &lvds_chimei_panel_data,
+	}
+};
+
+static int __init lvds_chimei_wxga_init(void)
+{
+	int ret;
+	struct msm_panel_info *pinfo;
+
+	if (msm_fb_detect_client("lvds_chimei_wxga"))
+		return 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret)
+		return ret;
+
+	pinfo = &lvds_chimei_panel_data.panel_info;
+	pinfo->xres = 320;
+	pinfo->yres = 240;
+	MSM_FB_SINGLE_MODE_PANEL(pinfo);
+	pinfo->type = LVDS_PANEL;
+	pinfo->pdest = DISPLAY_1;
+	pinfo->wait_cycle = 0;
+	pinfo->bpp = 24;
+	pinfo->fb_num = 2;
+	pinfo->clk_rate = 75000000;
+	pinfo->bl_max = 15;
+	pinfo->bl_min = 1;
+
+	/*
+	 * this panel is operated by de,
+	 * vsycn and hsync are ignored
+	 */
+	pinfo->lcdc.h_back_porch = 0;
+	pinfo->lcdc.h_front_porch = 194;
+	pinfo->lcdc.h_pulse_width = 40;
+	pinfo->lcdc.v_back_porch = 0;
+	pinfo->lcdc.v_front_porch = 38;
+	pinfo->lcdc.v_pulse_width = 20;
+	pinfo->lcdc.border_clr = 0xffff00;
+	pinfo->lcdc.underflow_clr = 0xff;
+	pinfo->lcdc.hsync_skew = 0;
+	pinfo->lvds.channel_mode = LVDS_SINGLE_CHANNEL_MODE;
+	pinfo->lcdc.xres_pad = 1046;
+	pinfo->lcdc.yres_pad = 528;
+
+	ret = platform_device_register(&this_device);
+	if (ret)
+		platform_driver_unregister(&this_driver);
+
+	return ret;
+}
+
+module_init(lvds_chimei_wxga_init);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index b39e81c..f27bd49 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1562,6 +1562,7 @@
 #endif
 	case HDMI_PANEL:
 	case LCDC_PANEL:
+	case LVDS_PANEL:
 		pdata->on = mdp_lcdc_on;
 		pdata->off = mdp_lcdc_off;
 		mfd->hw_refresh = TRUE;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 88582e4..5f5d632 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -188,9 +188,9 @@
 	dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
 	dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
 	dsi_width = mfd->panel_info.xres +
-		mfd->panel_info.mipi.xres_pad;
+		mfd->panel_info.lcdc.xres_pad;
 	dsi_height = mfd->panel_info.yres +
-		mfd->panel_info.mipi.yres_pad;
+		mfd->panel_info.lcdc.yres_pad;
 	dsi_bpp = mfd->panel_info.bpp;
 
 	hsync_period = hsync_pulse_width + h_back_porch + dsi_width
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 5ad6de3f..ebde23b 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -45,6 +45,73 @@
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
 
+static void lvds_init(struct msm_fb_data_type *mfd)
+{
+	unsigned int lvds_intf, lvds_phy_cfg0;
+
+	if (mfd->panel_info.bpp == 24) {
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2024, 0x1518191a);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc202c, 0x0f16171b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2030, 0x0006070e);
+
+		if (mfd->panel_info.lvds.channel_mode ==
+			LVDS_DUAL_CHANNEL_MODE) {
+			lvds_intf = 0x0001ff80;
+			lvds_phy_cfg0 = BIT(6) | BIT(7);
+			if (mfd->panel_info.lvds.channel_swap)
+				lvds_intf |= BIT(4);
+		} else {
+			lvds_intf = 0x00010f84;
+			lvds_phy_cfg0 = BIT(6);
+		}
+	} else if (mfd->panel_info.bpp == 18) {
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2024, 0x1518191a);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
+
+		if (mfd->panel_info.lvds.channel_mode ==
+			LVDS_DUAL_CHANNEL_MODE) {
+			lvds_intf = 0x00017788;
+			lvds_phy_cfg0 = BIT(6) | BIT(7);
+			if (mfd->panel_info.lvds.channel_swap)
+				lvds_intf |= BIT(4);
+		} else {
+			lvds_intf = 0x0001078c;
+			lvds_phy_cfg0 = BIT(6);
+		}
+	}
+
+	/* MDP_LVDSPHY_CFG0 */
+	MDP_OUTP(MDP_BASE +  0xc3100, lvds_phy_cfg0);
+	/* MDP_LCDC_LVDS_INTF_CTL */
+	MDP_OUTP(MDP_BASE +  0xc2000, lvds_intf);
+	lvds_phy_cfg0 |= BIT(4);
+	/* MDP_LVDSPHY_CFG0, enable serialization */
+	MDP_OUTP(MDP_BASE +  0xc3100, lvds_phy_cfg0);
+}
+
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -165,8 +232,8 @@
 	lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
 	lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
 
-	lcdc_width = var->xres;
-	lcdc_height = var->yres;
+	lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad;
+	lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad;
 	lcdc_bpp = mfd->panel_info.bpp;
 
 	hsync_period =
@@ -237,6 +304,9 @@
 #endif
 	mdp_histogram_ctrl(TRUE);
 
+	if (mfd->panel.type == LVDS_PANEL)
+		lvds_init(mfd);
+
 	ret = panel_next_on(pdev);
 	if (ret == 0) {
 		/* enable LCDC block */
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index aa210f1..f319072 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -196,8 +196,8 @@
 
 	mipi  = &mfd->panel_info.mipi;
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
-		dummy_xres = mfd->panel_info.mipi.xres_pad;
-		dummy_yres = mfd->panel_info.mipi.yres_pad;
+		dummy_xres = mfd->panel_info.lcdc.xres_pad;
+		dummy_yres = mfd->panel_info.lcdc.yres_pad;
 
 		if (mdp_rev >= MDP_REV_41) {
 			MIPI_OUTP(MIPI_DSI_BASE + 0x20,
@@ -539,8 +539,8 @@
 
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
 		!mfd->panel_info.clk_rate) {
-		h_period += mfd->panel_info.mipi.xres_pad;
-		v_period += mfd->panel_info.mipi.yres_pad;
+		h_period += mfd->panel_info.lcdc.xres_pad;
+		v_period += mfd->panel_info.lcdc.yres_pad;
 
 		if (lanes > 0) {
 			mfd->panel_info.clk_rate =
diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
index 2c02490..48bdb1d 100644
--- a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -49,8 +49,8 @@
 	 * include dummy(pad) data of 200 clk in addition to
 	 * width and porch/sync width values
 	 */
-	pinfo.mipi.xres_pad = 200;
-	pinfo.mipi.yres_pad = 0;
+	pinfo.lcdc.xres_pad = 200;
+	pinfo.lcdc.yres_pad = 0;
 
 	pinfo.type = MIPI_VIDEO_PANEL;
 	pinfo.pdest = DISPLAY_1;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 25faf61..bdfadd5 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -270,6 +270,9 @@
 	case HDMI_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
 		break;
+	case LVDS_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
+		break;
 	case DTV_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
 		break;
diff --git a/drivers/video/msm/msm_fb_panel.c b/drivers/video/msm/msm_fb_panel.c
index d8eaea2..8640116 100644
--- a/drivers/video/msm/msm_fb_panel.c
+++ b/drivers/video/msm/msm_fb_panel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -106,6 +106,10 @@
 		snprintf(dev_name, sizeof(dev_name), "lcdc");
 		break;
 
+	case LVDS_PANEL:
+		snprintf(dev_name, sizeof(dev_name), "lvds");
+		break;
+
 	case DTV_PANEL:
 		snprintf(dev_name, sizeof(dev_name), "dtv");
 		break;
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index d66d802..903c865 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
 #define MIPI_VIDEO_PANEL	8	/* MIPI */
 #define MIPI_CMD_PANEL		9	/* MIPI */
 #define WRITEBACK_PANEL		10	/* Wifi display */
+#define LVDS_PANEL		11	/* LVDS */
 
 /* panel class */
 typedef enum {
@@ -77,6 +78,10 @@
 	__u32 border_clr;
 	__u32 underflow_clr;
 	__u32 hsync_skew;
+	/* Pad width */
+	uint32 xres_pad;
+	/* Pad height */
+	uint32 yres_pad;
 };
 
 struct mddi_panel_info {
@@ -127,10 +132,17 @@
 	char no_max_pkt_size;
 	/* Clock required during LP commands */
 	char force_clk_lane_hs;
-	/* Pad width */
-	uint32 xres_pad;
-	/* Pad height */
-	uint32 yres_pad;
+};
+
+enum lvds_mode {
+	LVDS_SINGLE_CHANNEL_MODE,
+	LVDS_DUAL_CHANNEL_MODE,
+};
+
+struct lvds_panel_info {
+	enum lvds_mode channel_mode;
+	/* Channel swap in dual mode */
+	char channel_swap;
 };
 
 struct msm_panel_info {
@@ -156,8 +168,8 @@
 	struct mddi_panel_info mddi;
 	struct lcd_panel_info lcd;
 	struct lcdc_panel_info lcdc;
-
 	struct mipi_panel_info mipi;
+	struct lvds_panel_info lvds;
 };
 
 #define MSM_FB_SINGLE_MODE_PANEL(pinfo)		\