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 = ®_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)