Exemplo n.º 1
0
static void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	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_SII_REG_NAME_MOD(REG_TMDS_CCTRL, 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_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
	} else {
		/*
		 * Drive HPD to DOWN state
		 * Disable TMDS Output on REG_TMDS_CCTRL
		 * Enable/Disable TMDS output (MHL TMDS output only)
		 */
		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
		MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
	}
	return;
}
Exemplo n.º 2
0
static void release_usb_switch_open(struct mhl_tx_ctrl *mhl_ctrl)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	msleep(50);
	MHL_SII_REG_NAME_MOD(REG_DISC_CTRL6, BIT6, 0x00);
	MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT0, BIT0);
}
Exemplo n.º 3
0
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode,
			bool hpd_off)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;
	unsigned long flags;
	int rc;
	struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;

	pr_debug("%s: tx pwr on\n", __func__);
	spin_lock_irqsave(&mhl_ctrl->lock, flags);
	mhl_ctrl->tx_powered_off = false;
	spin_unlock_irqrestore(&mhl_ctrl->lock, flags);

	switch (to_mode) {
	case POWER_STATE_D0_NO_MHL:
		mhl_ctrl->cur_state = to_mode;
		mhl_init_reg_settings(mhl_ctrl, true);
		/* REG_DISC_CTRL1 */
		MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, BIT0);

		/* TPI_DEVICE_POWER_STATE_CTRL_REG */
		mhl_i2c_reg_modify(client, TX_PAGE_TPI, 0x001E, BIT1 | BIT0,
			0x00);
		break;
	case POWER_STATE_D0_MHL:
		mhl_ctrl->cur_state = to_mode;
		break;
	case POWER_STATE_D3:
		if (mhl_ctrl->cur_state == POWER_STATE_D3) {
			pr_debug("%s: mhl tx already in low power mode\n",
				__func__);
			break;
		}

		/* Force HPD to 0 when not in MHL mode.  */
		mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
		mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
		/*
		 * Change TMDS termination to high impedance
		 * on disconnection.
		 */
		MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
		msleep(50);
		if (!mhl_ctrl->disc_enabled)
			MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
		if (hdmi_mhl_ops && hpd_off) {
			rc = hdmi_mhl_ops->set_upstream_hpd(
				mhl_ctrl->pdata->hdmi_pdev, 0);
			pr_debug("%s: hdmi unset hpd %s\n", __func__,
				 rc ? "failed" : "passed");
		}
		mhl_ctrl->cur_state = POWER_STATE_D3;
		break;
	default:
		break;
	}
}
Exemplo n.º 4
0
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;
	if (on) {
		MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
		mhl_drive_hpd(mhl_ctrl, HPD_UP);
	} else {
		MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
	}
}
Exemplo n.º 5
0
static void force_usb_switch_open(struct mhl_tx_ctrl *mhl_ctrl)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	/*disable discovery*/
	MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT0, 0);
	/* force USB ID switch to open*/
	MHL_SII_REG_NAME_MOD(REG_DISC_CTRL6, BIT6, BIT6);
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL3, 0x86);
	/* force HPD to 0 when not in mhl mode. */
	MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT5 | BIT4, BIT4);
}
Exemplo n.º 6
0
static void cbus_reset(struct mhl_tx_ctrl *mhl_ctrl)
{
	uint8_t i;
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	/*
	 * REG_SRST
	 */
	MHL_SII_REG_NAME_MOD(REG_SRST, BIT3, BIT3);
	msleep(20);
	MHL_SII_REG_NAME_MOD(REG_SRST, BIT3, 0x00);
	/*
	 * REG_INTR1 and REG_INTR4
	 */
	MHL_SII_REG_NAME_WR(REG_INTR1_MASK, BIT6);
	MHL_SII_REG_NAME_WR(REG_INTR4_MASK,
		BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);

	if (mhl_ctrl->chip_rev_id < 1)
		MHL_SII_REG_NAME_WR(REG_INTR5_MASK, BIT3 | BIT4);
	else
		MHL_SII_REG_NAME_WR(REG_INTR5_MASK, 0x00);

	/* Unmask CBUS1 Intrs */
	MHL_SII_REG_NAME_WR(REG_CBUS_INTR_ENABLE,
		BIT2 | BIT3 | BIT4 | BIT5 | BIT6);

	/* Unmask CBUS2 Intrs */
	MHL_SII_REG_NAME_WR(REG_CBUS_MSC_INT2_ENABLE, BIT2 | BIT3);

	for (i = 0; i < 4; i++) {
		/*
		 * Enable WRITE_STAT interrupt for writes to
		 * all 4 MSC Status registers.
		 */
		MHL_SII_CBUS_WR((0xE0 + i), 0xFF);

		/*
		 * Enable SET_INT interrupt for writes to
		 * all 4 MSC Interrupt registers.
		 */
		MHL_SII_CBUS_WR((0xF0 + i), 0xFF);
	}
}
Exemplo n.º 7
0
static void cbus_reset(struct i2c_client *client)
{
	uint8_t i;

	/*
	 * REG_SRST
	 */
	MHL_SII_REG_NAME_MOD(REG_SRST, BIT3, BIT3);
	msleep(20);
	MHL_SII_REG_NAME_MOD(REG_SRST, BIT3, 0x00);
	/*
	 * REG_INTR1 and REG_INTR4
	 */
	MHL_SII_REG_NAME_WR(REG_INTR1_MASK, BIT6);
	MHL_SII_REG_NAME_WR(REG_INTR4_MASK,
		BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);

	MHL_SII_REG_NAME_WR(REG_INTR5_MASK, 0x00);

	/* Unmask CBUS1 Intrs */
	MHL_SII_CBUS_WR(0x0009,
		BIT2 | BIT3 | BIT4 | BIT5 | BIT6);

	/* Unmask CBUS2 Intrs */
	MHL_SII_CBUS_WR(0x001F, BIT2 | BIT3);

	for (i = 0; i < 4; i++) {
		/*
		 * Enable WRITE_STAT interrupt for writes to
		 * all 4 MSC Status registers.
		 */
		MHL_SII_CBUS_WR((0xE0 + i), 0xFF);

		/*
		 * Enable SET_INT interrupt for writes to
		 * all 4 MSC Interrupt registers.
		 */
		MHL_SII_CBUS_WR((0xF0 + i), 0xFF);
	}
	return;
}
Exemplo n.º 8
0
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	switch (to_mode) {
	case POWER_STATE_D0_NO_MHL:
		mhl_ctrl->cur_state = to_mode;
		mhl_init_reg_settings(mhl_ctrl, true);
		/* REG_DISC_CTRL1 */
		MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, BIT0);

		/* TPI_DEVICE_POWER_STATE_CTRL_REG */
		mhl_i2c_reg_modify(client, TX_PAGE_TPI, 0x001E, BIT1 | BIT0,
			0x00);
		break;
	case POWER_STATE_D0_MHL:
		mhl_ctrl->cur_state = to_mode;
		break;
	case POWER_STATE_D3:
		if (mhl_ctrl->cur_state == POWER_STATE_D3)
			break;

		/* Force HPD to 0 when not in MHL mode.  */
		mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
		/*
		 * Change TMDS termination to high impedance
		 * on disconnection.
		 */
		MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
		msleep(50);
		if (!mhl_ctrl->disc_enabled)
			MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
		MHL_SII_PAGE3_MOD(0x003D, BIT0, 0x00);
		mhl_ctrl->cur_state = POWER_STATE_D3;
		break;
	default:
		break;
	}
}
Exemplo n.º 9
0
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
	struct i2c_client *client = mhl_ctrl->i2c_handle;
	unsigned long flags;

	pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
	if (to_state == HPD_UP) {
		/*
		 * Drive HPD to UP state
		 * 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
		 */
		spin_lock_irqsave(&mhl_ctrl->lock, flags);
		mhl_ctrl->tx_powered_off = false;
		spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0);
	} else {
		/* Drive HPD to DOWN state */
		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, (BIT4 | BIT5), BIT4);
	}
}
Exemplo n.º 10
0
static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
	uint8_t status, reg;
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	/* INTR_STATUS4 */
	status = MHL_SII_REG_NAME_RD(REG_INTR4);
	pr_debug("%s: reg int4 st=%02X\n", __func__, status);

	if ((0x00 == status) &&\
	    (mhl_ctrl->cur_state == POWER_STATE_D3)) {
		pr_err("%s: invalid intr\n", __func__);
		return 0;
	}

	if (0xFF == status) {
		pr_debug("%s: invalid intr 0xff\n", __func__);
		MHL_SII_REG_NAME_WR(REG_INTR4, status);
		return 0;
	}

	if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
		pr_debug("%s: scdt intr\n", __func__);
		scdt_st_chg(client);
	}

	if (status & BIT1)
		pr_debug("mhl: int4 bit1 set\n");

	/* mhl_est interrupt */
	if (status & BIT2) {
		pr_debug("%s: mhl_est st=%02X\n", __func__,
			 (int) status);
		mhl_msm_connection(mhl_ctrl);
	} else if (status & BIT3) {
		pr_debug("%s: uUSB-a type dev detct\n", __func__);

		/* Short RGND */
		MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
		mhl_msm_disconnection(mhl_ctrl);
		power_supply_changed(&mhl_ctrl->mhl_psy);
		if (mhl_ctrl->notify_usb_online)
			mhl_ctrl->notify_usb_online(0);
		return -EACCES;
	}

	if (status & BIT5) {
		/* clr intr - reg int4 */
		pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
			 (int)status);

		reg = MHL_SII_REG_NAME_RD(REG_INTR4);
		MHL_SII_REG_NAME_WR(REG_INTR4, reg);
		mhl_msm_disconnection(mhl_ctrl);
		power_supply_changed(&mhl_ctrl->mhl_psy);
		if (mhl_ctrl->notify_usb_online)
			mhl_ctrl->notify_usb_online(0);
		return -EACCES;
	}

	if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
	    (status & BIT6)) {
		/* rgnd rdy Intr */
		pr_debug("%s: rgnd ready intr\n", __func__);
		switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, true);
		mhl_msm_read_rgnd_int(mhl_ctrl);
	}

	/* Can't succeed at these in D3 */
	if ((mhl_ctrl->cur_state != POWER_STATE_D3) &&\
	     (status & BIT4)) {
		/* cbus lockout interrupt?
		 * Hardware detection mechanism figures that
		 * CBUS line is latched and raises this intr
		 * where we force usb switch open and release
		 */
		pr_warn("%s: cbus locked out!\n", __func__);
		force_usb_switch_open(mhl_ctrl);
		release_usb_switch_open(mhl_ctrl);
	}
	MHL_SII_REG_NAME_WR(REG_INTR4, status);
	return 0;
}
Exemplo n.º 11
0
/*
 * Configure the initial reg settings
 */
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
	bool mhl_disc_en)
{
	uint8_t regval;

	/*
	 * ============================================
	 * POWER UP
	 * ============================================
	 */
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	/* Power up 1.2V core */
	MHL_SII_PAGE1_WR(0x003D, 0x3F);
	/* Enable Tx PLL Clock */
	MHL_SII_PAGE2_WR(0x0011, 0x01);
	/* Enable Tx Clock Path and Equalizer */
	MHL_SII_PAGE2_WR(0x0012, 0x11);
	/* Tx Source Termination ON */
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
	/* Enable 1X MHL Clock output */
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL6, 0xBC);
	/* Tx Differential Driver Config */
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL2, 0x3C);
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL4, 0xC8);
	/* PLL Bandwidth Control */
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL7, 0x03);
	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL8, 0x0A);
	/*
	 * ============================================
	 * Analog PLL Control
	 * ============================================
	 */
	/* Enable Rx PLL clock */
	MHL_SII_REG_NAME_WR(REG_TMDS_CCTRL,  0x08);
	MHL_SII_PAGE0_WR(0x00F8, 0x8C);
	MHL_SII_PAGE0_WR(0x0085, 0x02);
	MHL_SII_PAGE2_WR(0x0000, 0x00);
	regval = MHL_SII_PAGE2_RD(0x0005);
	regval &= ~BIT5;
	MHL_SII_PAGE2_WR(0x0005, regval);
	MHL_SII_PAGE2_WR(0x0013, 0x60);
	/* PLL Cal ref sel */
	MHL_SII_PAGE2_WR(0x0017, 0x03);
	/* VCO Cal */
	MHL_SII_PAGE2_WR(0x001A, 0x20);
	/* Auto EQ */
	MHL_SII_PAGE2_WR(0x0022, 0xE0);
	MHL_SII_PAGE2_WR(0x0023, 0xC0);
	MHL_SII_PAGE2_WR(0x0024, 0xA0);
	MHL_SII_PAGE2_WR(0x0025, 0x80);
	MHL_SII_PAGE2_WR(0x0026, 0x60);
	MHL_SII_PAGE2_WR(0x0027, 0x40);
	MHL_SII_PAGE2_WR(0x0028, 0x20);
	MHL_SII_PAGE2_WR(0x0029, 0x00);
	/* Rx PLL Bandwidth 4MHz */
	MHL_SII_PAGE2_WR(0x0031, 0x0A);
	/* Rx PLL Bandwidth value from I2C */
	MHL_SII_PAGE2_WR(0x0045, 0x06);
	MHL_SII_PAGE2_WR(0x004B, 0x06);
	MHL_SII_PAGE2_WR(0x004C, 0x60);
	/* Manual zone control */
	MHL_SII_PAGE2_WR(0x004C, 0xE0);
	/* PLL Mode value */
	MHL_SII_PAGE2_WR(0x004D, 0x00);
	MHL_SII_PAGE0_WR(0x0008, 0x35);
	/*
	 * Discovery Control and Status regs
	 * Setting De-glitch time to 50 ms (default)
	 * Switch Control Disabled
	 */
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL2, 0xAD);
	/* 1.8V CBUS VTH */
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL5, 0x57);
	/* RGND and single Discovery attempt */
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL6, 0x11);
	/* Ignore VBUS */
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL8, 0x82);

	/* Enable CBUS Discovery */
	if (mhl_disc_en) {
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL9, 0x24);
		/* Enable MHL Discovery */
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL1, 0x27);
		/* Pull-up resistance off for IDLE state */
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL4, 0x8C);
	} else {
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL9, 0x26);
		/* Disable MHL Discovery */
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL1, 0x26);
		MHL_SII_REG_NAME_WR(REG_DISC_CTRL4, 0x8C);
	}

	MHL_SII_REG_NAME_WR(REG_DISC_CTRL7, 0x20);
	/* MHL CBUS Discovery - immediate comm.  */
	MHL_SII_REG_NAME_WR(REG_DISC_CTRL3, 0x86);

	MHL_SII_PAGE3_WR(0x3C, 0x80);

	if (mhl_ctrl->cur_state != POWER_STATE_D3)
		MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT6 | BIT5 | BIT4, BIT4);

	/* Enable Auto Soft RESET */
	MHL_SII_REG_NAME_WR(REG_SRST, 0x084);
	/* HDMI Transcode mode enable */
	MHL_SII_PAGE0_WR(0x000D, 0x1C);

	cbus_reset(mhl_ctrl);
	init_cbus_regs(client);
}