msm_fb: MHL Driver for SI-8334 Transmitter

The device driver for SI8334 Silicon Image's
Mobile High-definition Link (MHL) Transmitter implements
wake-up, discovery and communication with MHL sink.
The MHL-8334 Tx is attached to MSM as an I2C-client.

Change-Id: I845bc1b30dc799183357224a296215ecc1d44893
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
Signed-off-by: Abhishek Kharbanda <akharban@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 9bf80ed..8b5c693 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -256,6 +256,7 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+#if defined(CONFIG_FB_MSM_HDMI_MHL_8334) || defined(CONFIG_FB_MSM_HDMI_MHL_9244)
 static struct gpiomux_setting hdmi_active_3_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -270,6 +271,7 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 #endif
+#endif
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
@@ -690,6 +692,7 @@
 			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
 		},
 	},
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
 		{
 		.gpio = 15,
 		.settings = {
@@ -704,6 +707,23 @@
 			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
 		},
 	},
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+#endif /* CONFIG_FB_MSM_HDMI_MHL */
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6ed174c..c294919 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -110,6 +110,9 @@
 #define KS8851_IRQ_GPIO		90
 #define HAP_SHIFT_LVL_OE_GPIO	47
 
+#define MHL_GPIO_INT            4
+#define MHL_GPIO_RESET          15
+
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 
 struct sx150x_platform_data msm8960_sx150x_data[] = {
@@ -2273,11 +2276,76 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+static void mhl_sii_reset_gpio(int on)
+{
+	gpio_set_value(MHL_GPIO_RESET, on);
+	return;
+}
+
+/*
+ * Request for GPIO allocations
+ * Set appropriate GPIO directions
+ */
+static int mhl_sii_gpio_setup(int on)
+{
+	int ret;
+
+	if (on) {
+		ret = gpio_request(MHL_GPIO_RESET, "W_RST#");
+		if (ret < 0) {
+			pr_err("GPIO RESET request failed: %d\n", ret);
+			return -EBUSY;
+		}
+		ret = gpio_direction_output(MHL_GPIO_RESET, 1);
+		if (ret < 0) {
+			pr_err("SET GPIO RESET direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_request(MHL_GPIO_INT, "W_INT");
+		if (ret < 0) {
+			pr_err("GPIO INT request failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_direction_input(MHL_GPIO_INT);
+		if (ret < 0) {
+			pr_err("SET GPIO INTR direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			gpio_free(MHL_GPIO_INT);
+			return -EBUSY;
+		}
+	} else {
+		gpio_free(MHL_GPIO_RESET);
+		gpio_free(MHL_GPIO_INT);
+	}
+
+	return 0;
+}
+
+static struct msm_mhl_platform_data mhl_platform_data = {
+	.irq = MSM_GPIO_TO_INT(4),
+	.gpio_setup = mhl_sii_gpio_setup,
+	.reset_pin = mhl_sii_reset_gpio,
+};
+#endif
+
 static struct i2c_board_info sii_device_info[] __initdata = {
 	{
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		/*
+		 * keeps SI 8334 as the default
+		 * MHL TX
+		 */
+		I2C_BOARD_INFO("sii8334", 0x39),
+		.platform_data = &mhl_platform_data,
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
 		I2C_BOARD_INFO("Sil-9244", 0x39),
-		.flags = I2C_CLIENT_WAKE,
 		.irq = MSM_GPIO_TO_INT(15),
+#endif /* CONFIG_MSM_HDMI_MHL */
+		.flags = I2C_CLIENT_WAKE,
 	},
 };
 
@@ -2902,7 +2970,7 @@
 		ARRAY_SIZE(mxt_device_info),
 	},
 	{
-		I2C_FFA | I2C_LIQUID,
+		I2C_SURF | I2C_FFA | I2C_LIQUID,
 		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
 		sii_device_info,
 		ARRAY_SIZE(sii_device_info),
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 36cdd86..c46c493 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -475,6 +475,12 @@
 	bool (*check_hdcp_hw_support)(void);
 };
 
+struct msm_mhl_platform_data {
+	int irq;
+	int (*gpio_setup)(int on);
+	void (*reset_pin)(int on);
+};
+
 struct msm_i2c_platform_data {
 	int clk_freq;
 	uint32_t rmutex;
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 578e339..b8d1df8 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -802,9 +802,18 @@
 	  Support for HDMI CEC Feature
 	  Choose to enable CEC
 
-config FB_MSM_HDMI_MHL
+config FB_MSM_HDMI_MHL_9244
 	depends on FB_MSM_HDMI_MSM_PANEL
-	bool 'HDMI to MHL support'
+	bool 'SI_MHL 9244 support'
+	default n
+	---help---
+	  Support the HDMI to MHL conversion.
+	  MHL (Mobile High-Definition Link) technology
+	  uses USB connector to output HDMI content
+
+config FB_MSM_HDMI_MHL_8334
+	depends on FB_MSM_HDMI_MSM_PANEL
+	bool 'SI_MHL 8334 support '
 	default n
 	---help---
 	  Support the HDMI to MHL conversion.
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 5a72ad4..b2ecb08 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -171,6 +171,11 @@
 
 obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o
 
+ccflags-y := -I$(src)/mhl
+obj-$(CONFIG_FB_MSM_HDMI_MHL_8334) += mhl-8334.o
+mhl-8334-objs  += mhl/mhl_8334.o
+mhl-8334-objs  += mhl/mhl_i2c_utils.o
+
 obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
 
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
new file mode 100644
index 0000000..43280a5
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -0,0 +1,849 @@
+/* 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/types.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <mach/msm_hdmi_audio.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "msm_fb.h"
+#include "external_common.h"
+#include "mhl_8334.h"
+#include "mhl_i2c_utils.h"
+
+#define DEBUG
+
+
+static struct i2c_device_id mhl_sii_i2c_id[] = {
+	{ MHL_DRIVER_NAME, 0 },
+	{ }
+};
+
+struct mhl_msm_state_t *mhl_msm_state;
+spinlock_t mhl_state_lock;
+
+static int mhl_i2c_probe(struct i2c_client *client,\
+	const struct i2c_device_id *id);
+static int mhl_i2c_remove(struct i2c_client *client);
+static void force_usb_switch_open(void);
+static void release_usb_switch_open(void);
+static void switch_mode(enum mhl_st_type to_mode);
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
+
+static struct i2c_driver mhl_sii_i2c_driver = {
+	.driver = {
+		.name = MHL_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = mhl_i2c_probe,
+	/*.remove =  __exit_p(mhl_i2c_remove),*/
+	.remove =  mhl_i2c_remove,
+	.id_table = mhl_sii_i2c_id,
+};
+
+bool mhl_is_connected(void)
+{
+	return true;
+}
+
+static void cbus_reset(void)
+{
+	uint8_t i;
+
+	/*
+	 * REG_SRST
+	 */
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, BIT3);
+	msleep(20);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, 0x00);
+	/*
+	 * REG_INTR1 and REG_INTR4
+	 */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6 | BIT5);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0022,
+		BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+	/* REG5 */
+	if (mhl_msm_state->chip_rev_id < 1)
+		mhl_i2c_reg_write(TX_PAGE_3, 0x0024, BIT3 | BIT4);
+	else
+		/*REG5 Mask disabled due to auto FIFO reset ??*/
+		mhl_i2c_reg_write(TX_PAGE_3, 0x0024, 0x00);
+
+	/* Unmask CBUS1 Intrs */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0009,
+		BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+
+	/* Unmask CBUS2 Intrs */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x001F, BIT2 | BIT3);
+
+	for (i = 0; i < 4; i++) {
+		/*
+		 * Enable WRITE_STAT interrupt for writes to
+		 * all 4 MSC Status registers.
+		 */
+		mhl_i2c_reg_write(TX_PAGE_CBUS, (0xE0 + i), 0xFF);
+
+		/*
+		 * Enable SET_INT interrupt for writes to
+		 * all 4 MSC Interrupt registers.
+		 */
+		mhl_i2c_reg_write(TX_PAGE_CBUS, (0xF0 + i), 0xFF);
+	}
+}
+
+static void init_cbus_regs(void)
+{
+	uint8_t		regval;
+
+	/* Increase DDC translation layer timer*/
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0007, 0xF2);
+	/* Drive High Time */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0036, 0x03);
+	/* Use programmed timing */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0039, 0x30);
+	/* CBUS Drive Strength */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0040, 0x03);
+	/*
+	 * Write initial default settings
+	 * to devcap regs: default settings
+	 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_STATE,
+		DEVCAP_VAL_DEV_STATE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_MHL_VERSION,
+		DEVCAP_VAL_MHL_VERSION);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_CAT,
+		DEVCAP_VAL_DEV_CAT);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_H,
+		DEVCAP_VAL_ADOPTER_ID_H);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_L,
+		DEVCAP_VAL_ADOPTER_ID_L);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VID_LINK_MODE,
+		DEVCAP_VAL_VID_LINK_MODE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_AUD_LINK_MODE,
+		DEVCAP_VAL_AUD_LINK_MODE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VIDEO_TYPE,
+		DEVCAP_VAL_VIDEO_TYPE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_LOG_DEV_MAP,
+		DEVCAP_VAL_LOG_DEV_MAP);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_BANDWIDTH,
+		DEVCAP_VAL_BANDWIDTH);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_FEATURE_FLAG,
+		DEVCAP_VAL_FEATURE_FLAG);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_H,
+		DEVCAP_VAL_DEVICE_ID_H);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_L,
+		DEVCAP_VAL_DEVICE_ID_L);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_SCRATCHPAD_SIZE,
+		DEVCAP_VAL_SCRATCHPAD_SIZE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_INT_STAT_SIZE,
+		DEVCAP_VAL_INT_STAT_SIZE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_RESERVED,
+		DEVCAP_VAL_RESERVED);
+
+	/* Make bits 2,3 (initiator timeout) to 1,1
+	 * for register CBUS_LINK_CONTROL_2
+	 * REG_CBUS_LINK_CONTROL_2
+	 */
+	regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0031);
+	regval = (regval | 0x0C);
+	/* REG_CBUS_LINK_CONTROL_2 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0031, regval);
+	 /* REG_MSC_TIMEOUT_LIMIT */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0022, 0x0F);
+	/* REG_CBUS_LINK_CONTROL_1 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0030, 0x01);
+	/* disallow vendor specific commands */
+	mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x002E, BIT4, BIT4);
+}
+
+/*
+ * Configure the initial reg settings
+ */
+static void mhl_init_reg_settings(void)
+{
+
+	/*
+	 * ============================================
+	 * POWER UP
+	 * ============================================
+	 */
+
+	/* Power up 1.2V core */
+	mhl_i2c_reg_write(TX_PAGE_L1, 0x003D, 0x3F);
+	/* Enable Tx PLL Clock */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0011, 0x01);
+	/* Enable Tx Clock Path and Equalizer */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0012, 0x11);
+	/* Tx Source Termination ON */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0x10);
+	/* Enable 1X MHL Clock output */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0035, 0xAC);
+	/* Tx Differential Driver Config */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0031, 0x3C);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0033, 0xD9);
+	/* PLL Bandwidth Control */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0037, 0x02);
+	/*
+	 * ============================================
+	 * Analog PLL Control
+	 * ============================================
+	 */
+	/* Enable Rx PLL clock */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0080, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x00F8, 0x0C);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0085, 0x02);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0000, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0013, 0x60);
+	/* PLL Cal ref sel */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0017, 0x03);
+	/* VCO Cal */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x001A, 0x20);
+	/* Auto EQ */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0022, 0xE0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0023, 0xC0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0024, 0xA0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0025, 0x80);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0026, 0x60);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0027, 0x40);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0028, 0x20);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0029, 0x00);
+	/* Rx PLL Bandwidth 4MHz */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0031, 0x0A);
+	/* Rx PLL Bandwidth value from I2C */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0045, 0x06);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004B, 0x06);
+	/* Manual zone control */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004C, 0xE0);
+	/* PLL Mode value */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004D, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0008, 0x35);
+	/*
+	 * Discovery Control and Status regs
+	 * Setting De-glitch time to 50 ms (default)
+	 * Switch Control Disabled
+	 */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0011, 0xAD);
+	/* 1.8V CBUS VTH */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0014, 0x55);
+	/* RGND and single Discovery attempt */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0015, 0x11);
+	/* Ignore VBUS */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0017, 0x82);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0018, 0x24);
+	/* Pull-up resistance off for IDLE state */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0013, 0x84);
+	/* Enable CBUS Discovery */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0016, 0x20);
+	/* MHL CBUS Discovery - immediate comm.  */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+	/* Do not force HPD to 0 during wake-up from D3 */
+	if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+			       BIT5 | BIT4, BIT4);
+	}
+	/* Enable Auto Soft RESET */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0000, 0x084);
+	/* HDMI Transcode mode enable */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x000D, 0x1C);
+
+	cbus_reset();
+	init_cbus_regs();
+}
+
+static int mhl_chip_init(void)
+{
+	/* Read the chip rev ID */
+	mhl_msm_state->chip_rev_id = mhl_i2c_reg_read(TX_PAGE_L0, 0x04);
+	pr_debug("MHL: chip rev ID read=[%x]\n", mhl_msm_state->chip_rev_id);
+
+	/* Reset the TX chip */
+	mhl_msm_state->mhl_data->reset_pin(0);
+	msleep(20);
+	mhl_msm_state->mhl_data->reset_pin(1);
+	/* MHL spec requires a 100 ms wait here.  */
+	msleep(100);
+
+	mhl_init_reg_settings();
+
+	/*
+	 * Power down the chip to the
+	 * D3 - a low power standby mode
+	 * cable impedance measurement logic is operational
+	 */
+	switch_mode(POWER_STATE_D3);
+	return 0;
+}
+
+/*
+ * I2C probe
+ */
+static int mhl_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int ret;
+	mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data),
+		GFP_KERNEL);
+	if (!(mhl_msm_state->mhl_data)) {
+		ret = -ENOMEM;
+		goto probe_exit;
+	}
+	pr_debug("Inside probe\n");
+	mhl_msm_state->i2c_client = client;
+
+	spin_lock_init(&mhl_state_lock);
+
+	i2c_set_clientdata(client, mhl_msm_state);
+	mhl_msm_state->mhl_data = client->dev.platform_data;
+
+	/* Init GPIO stuff here */
+	ret = mhl_msm_state->mhl_data->gpio_setup(1);
+	if (ret == -1) {
+		pr_err("MHL: mhl_gpio_init has failed\n");
+		ret = -ENODEV;
+		goto probe_exit;
+	}
+	return 0;
+
+probe_exit:
+	if (mhl_msm_state->mhl_data) {
+		/* free the gpios */
+		mhl_msm_state->mhl_data->gpio_setup(0);
+		kfree(mhl_msm_state->mhl_data);
+		mhl_msm_state->mhl_data = NULL;
+	}
+	return ret;
+}
+
+static int mhl_i2c_remove(struct i2c_client *client)
+{
+	pr_debug("inside i2c remove\n");
+	mhl_msm_state->mhl_data->gpio_setup(0);
+	kfree(mhl_msm_state->mhl_data);
+	return 0;
+}
+
+static int __init mhl_msm_init(void)
+{
+	int32_t     ret;
+
+	mhl_msm_state = kzalloc(sizeof(struct mhl_msm_state_t), GFP_KERNEL);
+	if (!mhl_msm_state) {
+		pr_err("mhl_msm_init FAILED: out of memory\n");
+		ret = -ENOMEM;
+		goto init_exit;
+	}
+
+	mhl_msm_state->i2c_client = NULL;
+	ret = i2c_add_driver(&mhl_sii_i2c_driver);
+	if (ret) {
+		pr_err("MHL: I2C driver add failed: %d\n", ret);
+		ret = -ENODEV;
+		goto init_exit;
+	} else {
+		if (mhl_msm_state->i2c_client == NULL) {
+			pr_err("JSR: I2C driver add failed\n");
+			ret = -ENODEV;
+			goto init_exit;
+		}
+		pr_debug("MHL: I2C driver added\n");
+	}
+
+	/* Request IRQ stuff here */
+	pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
+		mhl_msm_state->mhl_data->irq);
+	ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
+				   &mhl_tx_isr,
+				 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				 "mhl_tx_isr", mhl_msm_state);
+	if (ret != 0) {
+		pr_err("request_threaded_irq failed, status: %d\n",
+			ret);
+		ret = -EACCES; /* Error code???? */
+		goto init_exit;
+	}
+
+	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+
+	/* MHL SII 8334 chip specific init */
+	mhl_chip_init();
+	return 0;
+
+init_exit:
+	pr_err("Exiting from the init with err\n");
+	i2c_del_driver(&mhl_sii_i2c_driver);
+	if (!mhl_msm_state) {
+		kfree(mhl_msm_state);
+		mhl_msm_state = NULL;
+	 }
+	 return ret;
+}
+
+static void switch_mode(enum mhl_st_type to_mode)
+{
+	unsigned long flags;
+
+	switch (to_mode) {
+	case POWER_STATE_D0_NO_MHL:
+		break;
+	case POWER_STATE_D0_MHL:
+		mhl_init_reg_settings();
+
+		/* REG_DISC_CTRL1 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1, 0);
+
+		/*
+		 * TPI_DEVICE_POWER_STATE_CTRL_REG
+		 * TX_POWER_STATE_MASK = BIT1 | BIT0
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_TPI, 0x001E, BIT1 | BIT0, 0x00);
+		break;
+	case POWER_STATE_D3:
+		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+			/* Force HPD to 0 when not in MHL mode.  */
+			mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+				BIT5 | BIT4, BIT4);
+
+			/*
+			 * Change TMDS termination to high impedance
+			 * on disconnection.
+			 */
+			mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
+			mhl_i2c_reg_modify(TX_PAGE_L1, 0x003D,
+				BIT1 | BIT0, BIT0);
+			spin_lock_irqsave(&mhl_state_lock, flags);
+			mhl_msm_state->cur_state = POWER_STATE_D3;
+			spin_unlock_irqrestore(&mhl_state_lock, flags);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void mhl_drive_hpd(uint8_t to_state)
+{
+	pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
+	if (to_state == HPD_UP) {
+		/*
+		 * Drive HPD to UP state
+		 *
+		 * The below two reg configs combined
+		 * enable TMDS output.
+		 */
+
+		/* Enable TMDS on TMDS_CCTRL */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4);
+
+		/*
+		 * Set HPD_OUT_OVR_EN = HPD State
+		 * EDID read and Un-force HPD (from low)
+		 * propogate to src let HPD float by clearing
+		 * HPD OUT OVRRD EN
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT4, 0x00);
+	} else {
+		/*
+		 * Drive HPD to DOWN state
+		 * Disable TMDS Output on REG_TMDS_CCTRL
+		 * Enable/Disable TMDS output (MHL TMDS output only)
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
+	}
+	return;
+}
+
+static void mhl_msm_connection(void)
+{
+	uint8_t val;
+	unsigned long flags;
+
+	pr_err("%s: cur state = [0x%x]\n", __func__, mhl_msm_state->cur_state);
+
+	if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+		/* Already in D0 - MHL power state */
+		return;
+	}
+	spin_lock_irqsave(&mhl_state_lock, flags);
+	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+	spin_unlock_irqrestore(&mhl_state_lock, flags);
+
+	mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0x10);
+
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x07, 0xF2);
+
+	/*
+	 * Keep the discovery enabled. Need RGND interrupt
+	 * Possibly chip disables discovery after MHL_EST??
+	 * Need to re-enable here
+	 */
+	val = mhl_i2c_reg_read(TX_PAGE_3, 0x10);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0));
+
+	return;
+}
+
+static void mhl_msm_disconnection(void)
+{
+	uint8_t reg;
+
+	/* Clear interrupts - REG INTR4 */
+	reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
+	/*
+	 * MHL TX CTL1
+	 * Disabling Tx termination
+	 */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0xD0);
+	/*
+	 * MSC REQUESTOR ABORT REASON
+	 * Clear CBUS_HPD status
+	 */
+	mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x000D, BIT6, 0x00);
+	/* Change HPD line to drive it low */
+	mhl_drive_hpd(HPD_DOWN);
+	/* switch power state to D3 */
+	switch_mode(POWER_STATE_D3);
+	return;
+}
+
+/*
+ * If hardware detected a change in impedence and raised an INTR
+ * We check the range of this impedence to infer if the connected
+ * device is MHL or USB and take appropriate actions.
+ */
+static void mhl_msm_read_rgnd_int(void)
+{
+	uint8_t rgnd_imp;
+
+	/*
+	 * DISC STATUS REG 2
+	 * 1:0 RGND
+	 * 00  - open (USB)
+	 * 01  - 2 kOHM (USB)
+	 * 10  - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec
+	 * 11  - short (USB)
+	 */
+	rgnd_imp = mhl_i2c_reg_read(TX_PAGE_3, 0x001C);
+	pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);
+
+
+	if (0x02 == rgnd_imp) {
+		pr_debug("MHL: MHL DEVICE!!!\n");
+		/*
+		 * Handling the MHL event in driver
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
+	} else {
+		pr_debug("MHL: NON-MHL DEVICE!!!\n");
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
+	}
+}
+
+static void force_usb_switch_open(void)
+{
+	/*DISABLE_DISCOVERY*/
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, 0);
+	/* Force USB ID switch to open*/
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, BIT6);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+	/* Force HPD to 0 when not in Mobile HD mode. */
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT5 | BIT4, BIT4);
+}
+
+static void release_usb_switch_open(void)
+{
+	msleep(50);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, 0x00);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, BIT0);
+}
+
+static void int_4_isr(void)
+{
+	uint8_t status;
+
+	/* INTR_STATUS4 */
+	status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+
+	/*
+	 * When I2C is inoperational (D3) and
+	 * a previous interrupt brought us here,
+	 * do nothing.
+	 */
+	pr_debug("MHL: MRR Interrupt status is = %02X\n", (int) status);
+	if (0xFF != status) {
+		if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) {
+			uint8_t tmds_cstat;
+			uint8_t mhl_fifo_status;
+
+			/* TMDS CSTAT */
+			tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040);
+
+			pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat);
+
+			if (tmds_cstat & 0x02) {
+				mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3,
+					0x0023);
+				pr_debug("MHL FIFO status: 0x%02x\n",
+					mhl_fifo_status);
+				if (mhl_fifo_status & 0x0C) {
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0023,
+						0x0C);
+
+					pr_debug("Apply MHL FIFO Reset\n");
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+						0x94);
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+						0x84);
+				}
+			}
+		}
+
+		if (status & BIT1)
+			pr_err("MHL: INT4 BIT1 is set\n");
+
+		/* MHL_EST interrupt */
+		if (status & BIT2) {
+			pr_err("MHL: Calling mhl_msm_connection() from ISR\n");
+			mhl_msm_connection();
+			pr_err("MHL Connect  Drv: INT4 Status = %02X\n",
+				(int) status);
+		} else if (status & BIT3) {
+			pr_err("MHL: uUSB-A type device detected.\n");
+			mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80);
+			switch_mode(POWER_STATE_D3);
+		}
+
+		if (status & BIT5) {
+			mhl_msm_disconnection();
+			pr_err("MHL Disconnect Drv: INT4 Status = %02X\n",
+				(int)status);
+		}
+
+		if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\
+			(status & BIT6)) {
+			/* RGND READY Intr */
+			switch_mode(POWER_STATE_D0_MHL);
+			mhl_msm_read_rgnd_int();
+		}
+
+		/* Can't succeed at these in D3 */
+		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+			/* CBUS Lockout interrupt? */
+			/*
+			 * Hardware detection mechanism figures that
+			 * CBUS line is latched and raises this intr
+			 * where we force usb switch open and release
+			 */
+			if (status & BIT4) {
+				force_usb_switch_open();
+				release_usb_switch_open();
+			}
+		}
+	}
+	pr_debug("MHL END  Drv: INT4 Status = %02X\n", (int) status);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status);
+
+	return;
+}
+
+static void int_5_isr(void)
+{
+	uint8_t intr_5_stat;
+
+	/*
+	 * Clear INT 5 ??
+	 * Probably need to revisit this later
+	 * INTR5 is related to FIFO underflow/overflow reset
+	 * which is handled in 8334 by auto FIFO reset
+	 */
+	intr_5_stat = mhl_i2c_reg_read(TX_PAGE_3, 0x0023);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0023, intr_5_stat);
+}
+
+
+static void int_1_isr(void)
+{
+	/* This ISR mainly handles the HPD status changes */
+	uint8_t intr_1_stat;
+	uint8_t cbus_stat;
+
+	/* INTR STATUS 1 */
+	intr_1_stat = mhl_i2c_reg_read(TX_PAGE_L0, 0x0071);
+
+	if (intr_1_stat) {
+		/* Clear interrupts */
+		mhl_i2c_reg_write(TX_PAGE_L0, 0x0071, intr_1_stat);
+		if (BIT6 & intr_1_stat) {
+			/*
+			 * HPD status change event is pending
+			 * Read CBUS HPD status for this info
+			 */
+
+			/* MSC REQ ABRT REASON */
+			cbus_stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D);
+			if (BIT6 & cbus_stat)
+				mhl_drive_hpd(HPD_UP);
+		}
+	}
+	return;
+}
+
+/*
+ * RCP, RAP messages - mandatory for compliance
+ *
+ */
+static void mhl_cbus_isr(void)
+{
+	uint8_t regval;
+	int req_done = FALSE;
+	uint8_t sub_cmd;
+	uint8_t cmd_data;
+	int msc_msg_recved = FALSE;
+	int rc = -1;
+
+	regval  = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x08);
+	if (regval == 0xff)
+		return;
+
+	/* clear all interrupts that were raised even if we did not process */
+	if (regval)
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval);
+
+	pr_err("%s: CBUS_INT = %02x\n", __func__, regval);
+
+	/* MSC_MSG (RCP/RAP) */
+	if (regval & BIT(3)) {
+		sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18);
+		cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19);
+		msc_msg_recved = TRUE;
+	}
+
+	/* MSC_REQ_DONE */
+	if (regval & BIT(4))
+		req_done = TRUE;
+
+	/* Now look for interrupts on CBUS_MSC_INT2 */
+	regval  = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x1E);
+
+	/* clear all interrupts that were raised */
+	/* even if we did not process */
+	if (regval)
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x1E, regval);
+
+	pr_err("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
+
+	/* received SET_INT */
+	if (regval & BIT(2)) {
+		uint8_t intr;
+		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0);
+		pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
+		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1);
+		pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA2, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA3, 0xFF);
+	}
+
+	/* received WRITE_STAT */
+	if (regval & BIT(3)) {
+		uint8_t stat;
+		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0);
+		pr_err("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
+		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1);
+		pr_err("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
+
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB1, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB2, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB3, 0xFF);
+	}
+
+	/* received MSC_MSG */
+	if (msc_msg_recved) {
+		/*mhl msc recv msc msg*/
+		if (rc)
+			pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
+	}
+
+	return;
+}
+
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id)
+{
+	/*
+	 * Check discovery interrupt
+	 * if not yet connected
+	 */
+	pr_debug("MHL: Current POWER state is [0x%x]\n",
+		mhl_msm_state->cur_state);
+	/*
+	 * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
+	 * interrupts. In D3, we get only RGND
+	 */
+	int_4_isr();
+
+	pr_debug("MHL: Current POWER state is [0x%x]\n",
+		mhl_msm_state->cur_state);
+	if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+		/*
+		 * If int_4_isr() didn't move the tx to D3
+		 * on disconnect, continue to check other
+		 * interrupt sources.
+		 */
+		int_5_isr();
+
+		/*
+		 * Check for any peer messages for DCAP_CHG etc
+		 * Dispatch to have the CBUS module working only
+		 * once connected.
+		 */
+		mhl_cbus_isr();
+		int_1_isr();
+	}
+	return IRQ_HANDLED;
+}
+
+static void __exit mhl_msm_exit(void)
+{
+	pr_warn("MHL: Exiting, Bye\n");
+	/*
+	 * Delete driver if i2c client structure is NULL
+	 */
+	i2c_del_driver(&mhl_sii_i2c_driver);
+	if (!mhl_msm_state) {
+		kfree(mhl_msm_state);
+		mhl_msm_state = NULL;
+	 }
+}
+
+module_init(mhl_msm_init);
+module_exit(mhl_msm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MHL SII 8334 TX driver");
diff --git a/drivers/video/msm/mhl/mhl_8334.h b/drivers/video/msm/mhl/mhl_8334.h
new file mode 100644
index 0000000..c1d9030
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.h
@@ -0,0 +1,74 @@
+/* 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.
+ *
+ */
+
+#ifndef __MHL_MSM_H__
+#define __MHL_MSM_H__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+
+#include "mhl_devcap.h"
+#include "mhl_defs.h"
+
+#define GPIO_MHL_RESET       15
+#define GPIO_MHL_INT         4
+
+#define MHL_DEVICE_NAME "sii8334"
+#define MHL_DRIVER_NAME "sii8334"
+
+#define HPD_UP               1
+#define HPD_DOWN             0
+
+struct mhl_msm_state_t {
+	struct i2c_client *i2c_client;
+	struct i2c_driver *i2c_driver;
+	uint8_t      cur_state;
+	uint8_t chip_rev_id;
+	struct msm_mhl_platform_data *mhl_data;
+};
+
+enum {
+	TX_PAGE_TPI          = 0x00,
+	TX_PAGE_L0           = 0x01,
+	TX_PAGE_L1           = 0x02,
+	TX_PAGE_2            = 0x03,
+	TX_PAGE_3            = 0x04,
+	TX_PAGE_CBUS         = 0x05,
+	TX_PAGE_DDC_EDID     = 0x06,
+	TX_PAGE_DDC_SEGM     = 0x07,
+};
+
+enum mhl_st_type {
+	POWER_STATE_D0_NO_MHL = 0,
+	POWER_STATE_D0_MHL    = 2,
+	POWER_STATE_D3        = 3,
+};
+
+enum {
+	DEV_PAGE_TPI_0      = (0x72),
+	DEV_PAGE_TX_L0_0    = (0x72),
+	DEV_PAGE_TPI_1      = (0x76),
+	DEV_PAGE_TX_L0_1    = (0x76),
+	DEV_PAGE_TX_L1_0    = (0x7A),
+	DEV_PAGE_TX_L1_1    = (0x7E),
+	DEV_PAGE_TX_2_0     = (0x92),
+	DEV_PAGE_TX_2_1     = (0x96),
+	DEV_PAGE_TX_3_0	    = (0x9A),
+	DEV_PAGE_TX_3_1	    = (0x9E),
+	DEV_PAGE_CBUS       = (0xC8),
+	DEV_PAGE_DDC_EDID   = (0xA0),
+	DEV_PAGE_DDC_SEGM   = (0x60),
+};
+
+#endif /* __MHL_MSM_H__ */
diff --git a/drivers/video/msm/mhl/mhl_defs.h b/drivers/video/msm/mhl/mhl_defs.h
new file mode 100644
index 0000000..094874e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_defs.h
@@ -0,0 +1,222 @@
+/* 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.
+ *
+ */
+#ifndef __MHL_SPEC_DEFS_H__
+#define __MHL_SPEC_DEFS_H__
+
+enum DevCapOffset_e {
+	DEVCAP_OFFSET_DEV_STATE         = 0x00,
+	DEVCAP_OFFSET_MHL_VERSION	= 0x01,
+	DEVCAP_OFFSET_DEV_CAT           = 0x02,
+	DEVCAP_OFFSET_ADOPTER_ID_H      = 0x03,
+	DEVCAP_OFFSET_ADOPTER_ID_L      = 0x04,
+	DEVCAP_OFFSET_VID_LINK_MODE     = 0x05,
+	DEVCAP_OFFSET_AUD_LINK_MODE     = 0x06,
+	DEVCAP_OFFSET_VIDEO_TYPE        = 0x07,
+	DEVCAP_OFFSET_LOG_DEV_MAP       = 0x08,
+	DEVCAP_OFFSET_BANDWIDTH         = 0x09,
+	DEVCAP_OFFSET_FEATURE_FLAG      = 0x0A,
+	DEVCAP_OFFSET_DEVICE_ID_H       = 0x0B,
+	DEVCAP_OFFSET_DEVICE_ID_L       = 0x0C,
+	DEVCAP_OFFSET_SCRATCHPAD_SIZE   = 0x0D,
+	DEVCAP_OFFSET_INT_STAT_SIZE     = 0x0E,
+	DEVCAP_OFFSET_RESERVED          = 0x0F,
+	/* this one must be last */
+	DEVCAP_SIZE
+};
+
+#ifndef __MHL_MSM_8334_REGS_H__
+#define __MHL_MSM_8334_REGS_H__
+
+#define BIT0                    0x01
+#define BIT1                    0x02
+#define BIT2                    0x04
+#define BIT3                    0x08
+#define BIT4                    0x10
+#define BIT5                    0x20
+#define BIT6                    0x40
+#define BIT7                    0x80
+
+#define LOW                     0
+#define HIGH                    1
+
+#define MAX_PAGES               8
+#endif
+
+
+/* Version that this chip supports*/
+/* bits 4..7 */
+#define	MHL_VER_MAJOR           (0x01 << 4)
+/* bits 0..3 */
+#define	MHL_VER_MINOR		0x01
+#define MHL_VERSION		(MHL_VER_MAJOR | MHL_VER_MINOR)
+
+/*Device Category*/
+#define	MHL_DEV_CATEGORY_OFFSET		DEVCAP_OFFSET_DEV_CAT
+#define	MHL_DEV_CATEGORY_POW_BIT	(BIT4)
+
+#define	MHL_DEV_CAT_SOURCE		0x02
+
+/*Video Link Mode*/
+#define	MHL_DEV_VID_LINK_SUPPRGB444		0x01
+#define	MHL_DEV_VID_LINK_SUPPYCBCR444		0x02
+#define	MHL_DEV_VID_LINK_SUPPYCBCR422		0x04
+#define	MHL_DEV_VID_LINK_SUPP_PPIXEL		0x08
+#define	MHL_DEV_VID_LINK_SUPP_ISLANDS		0x10
+
+/*Audio Link Mode Support*/
+#define	MHL_DEV_AUD_LINK_2CH				0x01
+#define	MHL_DEV_AUD_LINK_8CH				0x02
+
+
+/*Feature Flag in the devcap*/
+#define	MHL_DEV_FEATURE_FLAG_OFFSET		DEVCAP_OFFSET_FEATURE_FLAG
+/* Dongles have freedom to not support RCP */
+#define	MHL_FEATURE_RCP_SUPPORT				BIT0
+/* Dongles have freedom to not support RAP */
+#define	MHL_FEATURE_RAP_SUPPORT				BIT1
+/* Dongles have freedom to not support SCRATCHPAD */
+#define	MHL_FEATURE_SP_SUPPORT				BIT2
+
+/*Logical Dev Map*/
+#define	MHL_DEV_LD_DISPLAY					(0x01 << 0)
+#define	MHL_DEV_LD_VIDEO					(0x01 << 1)
+#define	MHL_DEV_LD_AUDIO					(0x01 << 2)
+#define	MHL_DEV_LD_MEDIA					(0x01 << 3)
+#define	MHL_DEV_LD_TUNER					(0x01 << 4)
+#define	MHL_DEV_LD_RECORD					(0x01 << 5)
+#define	MHL_DEV_LD_SPEAKER					(0x01 << 6)
+#define	MHL_DEV_LD_GUI						(0x01 << 7)
+
+/*Bandwidth*/
+/* 225 MHz */
+#define	MHL_BANDWIDTH_LIMIT					22
+
+
+#define MHL_STATUS_REG_CONNECTED_RDY        0x30
+#define MHL_STATUS_REG_LINK_MODE            0x31
+
+#define	MHL_STATUS_DCAP_RDY					BIT0
+
+#define MHL_STATUS_CLK_MODE_MASK            0x07
+#define MHL_STATUS_CLK_MODE_PACKED_PIXEL    0x02
+#define MHL_STATUS_CLK_MODE_NORMAL          0x03
+#define MHL_STATUS_PATH_EN_MASK             0x08
+#define MHL_STATUS_PATH_ENABLED             0x08
+#define MHL_STATUS_PATH_DISABLED            0x00
+#define MHL_STATUS_MUTED_MASK               0x10
+
+#define MHL_RCHANGE_INT                     0x20
+#define MHL_DCHANGE_INT                     0x21
+
+#define	MHL_INT_DCAP_CHG					BIT0
+#define MHL_INT_DSCR_CHG                    BIT1
+#define MHL_INT_REQ_WRT                     BIT2
+#define MHL_INT_GRT_WRT                     BIT3
+
+/* On INTR_1 the EDID_CHG is located at BIT 0*/
+#define	MHL_INT_EDID_CHG					BIT1
+
+/* This contains one nibble each - max offset */
+#define		MHL_INT_AND_STATUS_SIZE			0x33
+#define		MHL_SCRATCHPAD_SIZE			16
+/* manually define highest number */
+#define		MHL_MAX_BUFFER_SIZE			MHL_SCRATCHPAD_SIZE
+
+
+
+enum {
+	/* RCP sub-command  */
+	MHL_MSC_MSG_RCP             = 0x10,
+	/* RCP Acknowledge sub-command  */
+	MHL_MSC_MSG_RCPK            = 0x11,
+	/* RCP Error sub-command  */
+	MHL_MSC_MSG_RCPE            = 0x12,
+	/* Mode Change Warning sub-command  */
+	MHL_MSC_MSG_RAP             = 0x20,
+	/* MCW Acknowledge sub-command  */
+	MHL_MSC_MSG_RAPK            = 0x21,
+};
+
+#define	RCPE_NO_ERROR				0x00
+#define	RCPE_INEEFECTIVE_KEY_CODE	0x01
+#define	RCPE_BUSY					0x02
+/* MHL spec related defines*/
+enum {
+	/* Command or Data byte acknowledge */
+	MHL_ACK						= 0x33,
+	/* Command or Data byte not acknowledge */
+	MHL_NACK					= 0x34,
+	/* Transaction abort */
+	MHL_ABORT					= 0x35,
+	/* 0xE0 - Write one status register strip top bit */
+	MHL_WRITE_STAT				= 0x60 | 0x80,
+	/* Write one interrupt register */
+	MHL_SET_INT					= 0x60,
+	/* Read one register */
+	MHL_READ_DEVCAP				= 0x61,
+	/* Read CBUS revision level from follower */
+	MHL_GET_STATE				= 0x62,
+	/* Read vendor ID value from follower. */
+	MHL_GET_VENDOR_ID			= 0x63,
+	/* Set Hot Plug Detect in follower */
+	MHL_SET_HPD					= 0x64,
+	/* Clear Hot Plug Detect in follower */
+	MHL_CLR_HPD					= 0x65,
+	/* Set Capture ID for downstream device. */
+	MHL_SET_CAP_ID				= 0x66,
+	/* Get Capture ID from downstream device. */
+	MHL_GET_CAP_ID				= 0x67,
+	/* VS command to send RCP sub-commands */
+	MHL_MSC_MSG					= 0x68,
+	/* Get Vendor-Specific command error code. */
+	MHL_GET_SC1_ERRORCODE		= 0x69,
+	/* Get DDC channel command error code. */
+	MHL_GET_DDC_ERRORCODE		= 0x6A,
+	/* Get MSC command error code. */
+	MHL_GET_MSC_ERRORCODE		= 0x6B,
+	/* Write 1-16 bytes to responder's scratchpad. */
+	MHL_WRITE_BURST				= 0x6C,
+	/* Get channel 3 command error code. */
+	MHL_GET_SC3_ERRORCODE		= 0x6D,
+};
+
+/* Turn content streaming ON. */
+#define	MHL_RAP_CONTENT_ON		0x10
+/* Turn content streaming OFF. */
+#define	MHL_RAP_CONTENT_OFF		0x11
+
+/*
+ *
+ * MHL Timings applicable to this driver.
+ *
+ */
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_VBUS_CBUS_TO_STABLE	(200)
+/* 20 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_PULSE_WIDTH_1	(20)
+/* 60 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_PULSE_WIDTH_2	(60)
+
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_TO_DISCOVER		(500)
+
+#define T_SRC_VBUS_CBUS_T0_STABLE	(500)
+
+/* Allow RSEN to stay low this much before reacting.*/
+#define	T_SRC_RSEN_DEGLITCH			(100)
+
+/* Wait this much after connection before reacting to RSEN (300-500ms)*/
+/* Per specs between 300 to 500 ms*/
+#define	T_SRC_RXSENSE_CHK			(400)
+
+#endif /* __MHL_SPEC_DEFS_H__ */
diff --git a/drivers/video/msm/mhl/mhl_devcap.h b/drivers/video/msm/mhl/mhl_devcap.h
new file mode 100644
index 0000000..6d01daf
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_devcap.h
@@ -0,0 +1,45 @@
+/* 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.
+ *
+ */
+#ifndef __MHL_DEVCAP_H__
+#define __MHL_DEVCAP_H__
+
+#define SILICON_IMAGE_ADOPTER_ID 322
+#define TRANSCODER_DEVICE_ID 0x8334
+
+#define MHL_DEV_LD_AUDIO (0x01 << 2)
+#define MHL_DEV_LD_VIDEO (0x01 << 1)
+#define MHL_DEV_LD_MEDIA (0x01 << 3)
+#define MHL_DEV_LD_GUI (0x01 << 7)
+#define	MHL_LOGICAL_DEVICE_MAP		(MHL_DEV_LD_AUDIO |\
+	MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
+
+#define DEVCAP_VAL_DEV_STATE       0
+#define DEVCAP_VAL_MHL_VERSION     MHL_VERSION
+#define DEVCAP_VAL_DEV_CAT         (MHL_DEV_CAT_SOURCE |\
+	MHL_DEV_CATEGORY_POW_BIT)
+#define DEVCAP_VAL_ADOPTER_ID_H    (uint8_t)(SILICON_IMAGE_ADOPTER_ID >>   8)
+#define DEVCAP_VAL_ADOPTER_ID_L    (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
+#define DEVCAP_VAL_VID_LINK_MODE   MHL_DEV_VID_LINK_SUPPRGB444
+#define DEVCAP_VAL_AUD_LINK_MODE   MHL_DEV_AUD_LINK_2CH
+#define DEVCAP_VAL_VIDEO_TYPE      0
+#define DEVCAP_VAL_LOG_DEV_MAP     MHL_LOGICAL_DEVICE_MAP
+#define DEVCAP_VAL_BANDWIDTH       0
+#define DEVCAP_VAL_FEATURE_FLAG    (MHL_FEATURE_RCP_SUPPORT |\
+	MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
+#define DEVCAP_VAL_DEVICE_ID_H     (uint8_t)(TRANSCODER_DEVICE_ID >>   8)
+#define DEVCAP_VAL_DEVICE_ID_L     (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF)
+#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
+#define DEVCAP_VAL_INT_STAT_SIZE   MHL_INT_AND_STATUS_SIZE
+#define DEVCAP_VAL_RESERVED        0
+
+#endif /* __MHL_DEVCAP_H__ */
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.c b/drivers/video/msm/mhl/mhl_i2c_utils.c
new file mode 100644
index 0000000..596af2e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.c
@@ -0,0 +1,107 @@
+/* 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/i2c.h>
+
+#include "mhl_i2c_utils.h"
+#include "mhl_8334.h"
+
+#define DEBUG
+
+uint8_t slave_addrs[MAX_PAGES] = {
+	DEV_PAGE_TPI_0    ,
+	DEV_PAGE_TX_L0_0  ,
+	DEV_PAGE_TX_L1_0  ,
+	DEV_PAGE_TX_2_0   ,
+	DEV_PAGE_TX_3_0   ,
+	DEV_PAGE_CBUS     ,
+	DEV_PAGE_DDC_EDID ,
+	DEV_PAGE_DDC_SEGM ,
+};
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset)
+{
+	struct i2c_msg msgs[2];
+	uint8_t buffer = 0;
+	int ret = -1;
+
+	pr_debug("MRR: Reading from slave_addr_index=[%x] and offset=[%x]\n",
+		slave_addr_index, reg_offset);
+	pr_debug("MRR: Addr slave_addr_index=[%x]\n",
+		slave_addrs[slave_addr_index]);
+
+	/* Slave addr */
+	msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+	msgs[1].addr = slave_addrs[slave_addr_index] >> 1;
+
+	/* Write Command */
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+
+	/* Register offset for the next transaction */
+	msgs[0].buf = &reg_offset;
+	msgs[1].buf = &buffer;
+
+	/* Offset is 1 Byte long */
+	msgs[0].len = 1;
+	msgs[1].len = 1;
+
+	ret = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 2);
+	if (ret < 1) {
+		pr_err("I2C READ FAILED=[%d]\n", ret);
+		return -EACCES;
+	}
+	pr_err("Buffer is [%x]\n", buffer);
+	return buffer;
+}
+
+
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t value)
+{
+	return mhl_i2c_reg_write_cmds(slave_addr_index, reg_offset, &value, 1);
+}
+
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t *value, uint16_t count)
+{
+	struct i2c_msg msgs[1];
+	uint8_t data[2];
+	int status = -EACCES;
+
+	msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = data;
+	data[0] = reg_offset;
+	data[1] = *value;
+
+	status = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 1);
+	if (status < 1) {
+		pr_err("I2C WRITE FAILED=[%d]\n", status);
+		return -EACCES;
+	}
+
+	return status;
+}
+
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t mask, uint8_t val)
+{
+	uint8_t temp;
+
+	temp = mhl_i2c_reg_read(slave_addr_index, reg_offset);
+	temp &= (~mask);
+	temp |= (mask & val);
+	mhl_i2c_reg_write(slave_addr_index, reg_offset, temp);
+}
+
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.h b/drivers/video/msm/mhl/mhl_i2c_utils.h
new file mode 100644
index 0000000..76498d4
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.h
@@ -0,0 +1,39 @@
+/* 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.
+ *
+ */
+
+#ifndef __MHL_I2C_UTILS_H__
+#define __MHL_I2C_UTILS_H__
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+#include "mhl_defs.h"
+
+/*
+ * I2C command to the adapter to append
+ * the buffer from next msg to this one.
+ */
+#define I2C_M_APPND_NXT_WR          0x0002
+
+extern uint8_t slave_addrs[MAX_PAGES];
+extern struct mhl_msm_state_t *mhl_msm_state;
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset);
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t value);
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t *value, uint16_t count);
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t mask, uint8_t val);
+
+#endif /* __MHL_I2C_UTILS_H__ */
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index 627f802..a4364ea 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -14,7 +14,7 @@
 #ifndef __MHL_API_H__
 #define __MHL_API_H__
 
-#ifdef CONFIG_FB_MSM_HDMI_MHL
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
 bool mhl_is_connected(void);
 #else
 static bool mhl_is_connected(void)