void mhl_screen_notify(struct mhl_tx_ctrl *mhl_ctrl, int screen_mode)
{
	if (!mhl_ctrl) {
		pr_err("%s: invalid input\n", __func__);
		return;
	}

	if (screen_mode) {
		mhl_ctrl->screen_mode = true;
		if (mhl_ctrl->cur_state == POWER_STATE_D0_MHL) {
			if (mhl_ctrl->tmds_ctrl_en) {
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_UP);
			}
			mhl_rap_send_msc_msg(mhl_ctrl, MHL_RAP_CONTENT_ON);
		}
	} else {
		if (!mhl_ctrl->tmds_en_state || !mhl_ctrl->screen_mode) {
			mhl_ctrl->screen_mode = false;
			return;
		}
		if (mhl_ctrl->cur_state == POWER_STATE_D0_MHL) {
			mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
			mhl_rap_send_msc_msg(mhl_ctrl, MHL_RAP_CONTENT_OFF);
		}
		/* NACK any RAP call until chagne to screen on */
		mhl_ctrl->screen_mode = false;
	}
}
static int mhl_rap_action(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
{
	switch (action_code) {
	case MHL_RAP_CONTENT_ON:
		if (!mhl_ctrl->tmds_en_state) {
			/*
			 * not only enabling tmds
			 * send power button press to wake up the device
			 */
			if (!mhl_ctrl->screen_mode)
				mhl_send_power_key_event(mhl_ctrl);

			mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
			mhl_drive_hpd(mhl_ctrl, HPD_UP);
		}
		break;
	case MHL_RAP_CONTENT_OFF:
		if (mhl_ctrl->tmds_en_state && mhl_ctrl->screen_mode) {
			mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
			/* NACK any RAP call until change to screen on */
			mhl_ctrl->screen_mode = false;
			/*
			 * instead of only disabling tmds
			 * send power button press - CONTENT_OFF
			 */
			mhl_send_power_key_event(mhl_ctrl);
		}
		break;
	default:
		break;
	}
	return 0;
}
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
			 struct msc_command_struct *req)
{
	bool dongle_pwr_en = false;

	switch (req->command) {
	case MHL_WRITE_STAT:
		if (req->offset == MHL_STATUS_REG_LINK_MODE) {
			if (req->payload.data[0]
			    & MHL_STATUS_PATH_ENABLED) {
				/* Enable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				if (mhl_ctrl->devcap_state == MHL_DEVCAP_ALL) {
					dongle_pwr_en = mhl_ctrl->devcap[
						   MHL_DEV_CATEGORY_OFFSET] &
						MHL_DEV_CATEGORY_POW_BIT;
					if (dongle_pwr_en)
						mhl_drive_hpd(mhl_ctrl, HPD_UP);
				}
			} else {
				/* Disable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			}
		}
		break;
	case MHL_READ_DEVCAP:
		mhl_update_devcap(mhl_ctrl,
			req->offset, req->retval);
		mhl_ctrl->devcap_state |= BIT(req->offset);
		switch (req->offset) {
		case MHL_DEV_CATEGORY_OFFSET:
			if (req->retval & MHL_DEV_CATEGORY_POW_BIT)
				pr_debug("%s: devcap pow bit set\n",
					 __func__);
			else
				pr_debug("%s: devcap pow bit unset\n",
					 __func__);
			break;
		case DEVCAP_OFFSET_RESERVED:
			mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
			mhl_drive_hpd(mhl_ctrl, HPD_UP);
			break;
		case DEVCAP_OFFSET_MHL_VERSION:
		case DEVCAP_OFFSET_INT_STAT_SIZE:
			if (mhl_qualify_path_enable(mhl_ctrl))
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
			break;
		}
		break;
	case MHL_WRITE_BURST:
		mhl_msc_send_set_int(
			mhl_ctrl,
			MHL_RCHANGE_INT,
			MHL_INT_DSCR_CHG,
			MSC_PRIORITY_SEND);
		break;
	}
	return 0;
}
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
			 struct msc_command_struct *req)
{
	switch (req->command) {
	case MHL_WRITE_STAT:
		if (req->offset == MHL_STATUS_REG_LINK_MODE) {
			if (req->payload.data[0]
			    & MHL_STATUS_PATH_ENABLED) {
				/* Enable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				if (mhl_ctrl->devcap_state == MHL_DEVCAP_ALL) {
					mhl_drive_hpd(mhl_ctrl, HPD_UP);
					mhl_ctrl->tmds_ctrl_en = true;
				}
			} else {
				/* Disable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			}
		}
		break;
	case MHL_READ_DEVCAP:
		mhl_update_devcap(mhl_ctrl,
			req->offset, req->retval);
		mhl_ctrl->devcap_state |= BIT(req->offset);
		switch (req->offset) {
		case MHL_DEV_CATEGORY_OFFSET:
			if (req->retval & MHL_DEV_CATEGORY_POW_BIT)
				pr_debug("%s: devcap pow bit set\n",
					 __func__);
			else
				pr_debug("%s: devcap pow bit unset\n",
					 __func__);
			power_supply_set_present(&mhl_ctrl->mhl_psy,
				!!(req->retval & MHL_DEV_CATEGORY_POW_BIT));
			break;
		case DEVCAP_OFFSET_FEATURE_FLAG:
			mhl_rap_send_msc_msg(mhl_ctrl, MHL_RAP_CONTENT_ON);
			break;
		case DEVCAP_OFFSET_RESERVED:
			if (mhl_qualify_path_enable(mhl_ctrl)) {
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
				mhl_drive_hpd(mhl_ctrl, HPD_UP);
				mhl_ctrl->tmds_ctrl_en = true;
			}
			break;
		}
		break;
	case MHL_WRITE_BURST:
		mhl_msc_send_set_int(
			mhl_ctrl,
			MHL_RCHANGE_INT,
			MHL_INT_DSCR_CHG,
			MSC_PRIORITY_SEND);
		break;
	}
	return 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;
	}
}
int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
			 struct msc_command_struct *req)
{
	switch (req->command) {
	case MHL_WRITE_STAT:
		if (req->offset == MHL_STATUS_REG_LINK_MODE) {
			if (req->payload.data[0]
			    & MHL_STATUS_PATH_ENABLED)
				/* Enable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
			else
				/* Disable TMDS output */
				mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
		}
		break;
	case MHL_READ_DEVCAP:
		mhl_update_devcap(mhl_ctrl,
			req->offset, req->retval);
		mhl_ctrl->devcap_state |= BIT(req->offset);
		switch (req->offset) {
		case MHL_DEV_CATEGORY_OFFSET:
			if (req->retval & MHL_DEV_CATEGORY_POW_BIT)
				pr_debug("%s: devcap pow bit set\n",
					 __func__);
			else
				pr_debug("%s: devcap pow bit unset\n",
					 __func__);
			break;
		case DEVCAP_OFFSET_MHL_VERSION:
		case DEVCAP_OFFSET_INT_STAT_SIZE:
			break;
		}
		break;
	case MHL_WRITE_BURST:
		mhl_msc_send_set_int(
			mhl_ctrl,
			MHL_RCHANGE_INT,
			MHL_INT_DSCR_CHG,
			MSC_PRIORITY_SEND);
		break;
	}
	return 0;
}
static int mhl_rap_action(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
{
	switch (action_code) {
	case MHL_RAP_CONTENT_ON:
		mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
		break;
	case MHL_RAP_CONTENT_OFF:
		/*
		 * instead of only disabling tmds
		 * send power button press - CONTENT_OFF
		 */
		input_report_key(mhl_ctrl->input, KEY_VENDOR, 1);
		input_sync(mhl_ctrl->input);
		input_report_key(mhl_ctrl->input, KEY_VENDOR, 0);
		input_sync(mhl_ctrl->input);
		break;
	default:
		break;
	}
	return 0;
}