int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl,
			 u8 offset, u8 set_int)
{
	int prior;
	if (offset >= 2)
		return -EFAULT;

	switch (offset) {
	case 0:
		if (set_int & MHL_INT_DCAP_CHG) {
			/* peer dcap has changed */
			mhl_ctrl->devcap_state = 0;
			mhl_msc_read_devcap_all(mhl_ctrl);
		}
		if (set_int & MHL_INT_DSCR_CHG) {
			/* peer's scratchpad reg changed */
			pr_debug("%s: dscr chg\n", __func__);
			mhl_read_scratchpad(mhl_ctrl);
			mhl_ctrl->scrpd_busy = false;
			mhl_notify_event(mhl_ctrl, MHL_TX_EVENT_DSCR_CHG);
		}
		if (set_int & MHL_INT_REQ_WRT) {
			/* SET_INT: REQ_WRT */
			if (mhl_ctrl->scrpd_busy) {
				prior = MSC_NORMAL_SEND;
			} else {
				prior = MSC_PRIORITY_SEND;
				mhl_ctrl->scrpd_busy = true;
			}
			mhl_msc_send_set_int(
				mhl_ctrl,
				MHL_RCHANGE_INT,
				MHL_INT_GRT_WRT,
				prior);
		}
		if (set_int & MHL_INT_GRT_WRT) {
			/* SET_INT: GRT_WRT */
			pr_debug("%s: recvd req to permit/grant write",
				 __func__);
			complete_all(&mhl_ctrl->req_write_done);
			mhl_msc_write_burst(
				mhl_ctrl,
				MHL_SCRATCHPAD_OFFSET,
				mhl_ctrl->scrpd.data,
				mhl_ctrl->scrpd.length);
		}
		break;
	case 1:
		if (set_int & MHL_INT_EDID_CHG) {
			/* peer EDID has changed
			 * toggle HPD to read EDID
			 */
			pr_debug("%s: EDID CHG\n", __func__);
			mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
			msleep(110);
			mhl_drive_hpd(mhl_ctrl, HPD_UP);
		}
	}
	return 0;
}
예제 #2
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 int mhl_request_write_burst(struct mhl_tx_ctrl *mhl_ctrl,
				   u8 start_reg,
				   u8 length, u8 *data)
{
	int i, reg;
	int timeout, retry = 20;

	if (!(mhl_ctrl->devcap[DEVCAP_OFFSET_FEATURE_FLAG] &
	      MHL_FEATURE_SP_SUPPORT)) {
		pr_debug("MHL: SCRATCHPAD_NOT_SUPPORTED\n");
		return -EFAULT;
	}

	/*
	 * scratchpad remains busy as long as a peer's permission or
	 * write bursts are pending; experimentally it was found that
	 * 50ms is optimal
	 */
	while (mhl_ctrl->scrpd_busy && retry--)
		msleep(50);
	if (!retry) {
		pr_debug("MHL: scratchpad_busy\n");
		return -EBUSY;
	}

	for (i = 0, reg = start_reg; (i < length) &&
		     (reg < MHL_SCRATCHPAD_SIZE); i++, reg++)
		mhl_ctrl->scrpd.data[reg] = data[i];
	mhl_ctrl->scrpd.length = length;
	mhl_ctrl->scrpd.offset = start_reg;

	retry = 5;
	do {
		init_completion(&mhl_ctrl->req_write_done);
		mhl_msc_send_set_int(
			mhl_ctrl,
			MHL_RCHANGE_INT,
			MHL_INT_REQ_WRT,
			MSC_PRIORITY_SEND);
		timeout = wait_for_completion_interruptible_timeout(
			&mhl_ctrl->req_write_done,
			msecs_to_jiffies(MHL_BURST_WAIT));
		if (!timeout)
			mhl_ctrl->scrpd_busy = false;
	} while (retry-- && timeout == 0);
	if (!timeout) {
		pr_err("%s: timed out!\n", __func__);
		return -EAGAIN;
	}

	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);
			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;
}
예제 #6
0
static int mhl_msc_recv_set_int(u8 offset, u8 set_int)
{
	if (offset >= 2)
		return -EFAULT;

	switch (offset) {
	case 0:
		/* DCAP_CHG */
		if (set_int & MHL_INT_DCAP_CHG) {
			/* peer dcap has changed */
			if (mhl_msc_read_devcap_all() == -EBUSY) {
				pr_err("READ DEVCAP FAILED to send successfully\n");
				break;
			}
		}
		/* DSCR_CHG */
		if (set_int & MHL_INT_DSCR_CHG)
			;
		/* REQ_WRT */
		if (set_int & MHL_INT_REQ_WRT) {
			/* SET_INT: GRT_WRT */
			mhl_msc_send_set_int(
				MHL_RCHANGE_INT,
				MHL_INT_GRT_WRT);
		}
		/* GRT_WRT */
		if (set_int & MHL_INT_GRT_WRT)
			;
		break;
	case 1:
		/* EDID_CHG */
		if (set_int & MHL_INT_EDID_CHG) {
			/* peer EDID has changed.
			 * toggle HPD to read EDID again
			 * In 8x30 FLUID  HDMI HPD line
			 * is not connected
			 * with MHL 8334 transmitter
			 */
		}
	}
	return 0;
}
예제 #7
0
static void mhl_msm_connection(struct mhl_tx_ctrl *mhl_ctrl)
{
	uint8_t val;
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	pr_debug("%s: cur st [0x%x]\n", __func__,
		mhl_ctrl->cur_state);

	if (mhl_ctrl->cur_state == POWER_STATE_D0_MHL) {
		/* Already in D0 - MHL power state */
		pr_err("%s: cur st not D0\n", __func__);
		return;
	}
	switch_mode(mhl_ctrl, POWER_STATE_D0_MHL, true);

	MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
	MHL_SII_CBUS_WR(0x07, 0xF2);

	/*
	 * Keep the discovery enabled. Need RGND interrupt
	 * Possibly chip disables discovery after MHL_EST??
	 * Need to re-enable here
	 */
	val = MHL_SII_PAGE3_RD(0x10);
	MHL_SII_PAGE3_WR(0x10, val | BIT0);

	/*
	 * indicate DCAP_RDY and DCAP_CHG
	 * to the peer only after
	 * msm conn has been established
	 */
	mhl_msc_send_write_stat(mhl_ctrl,
				MHL_STATUS_REG_CONNECTED_RDY,
				MHL_STATUS_DCAP_RDY);

	mhl_msc_send_set_int(mhl_ctrl,
			     MHL_RCHANGE_INT,
			     MHL_INT_DCAP_CHG,
			     MSC_PRIORITY_SEND);

}
static int mhl_msc_recv_set_int(u8 offset, u8 set_int)
{
	if (offset >= 2)
		return -EFAULT;

	switch (offset) {
	case 0:
		
		if (set_int & MHL_INT_DCAP_CHG) {
			
			if (mhl_msc_read_devcap_all() == -EBUSY) {
				pr_err("READ DEVCAP FAILED to send successfully\n");
				break;
			}
		}
		
		if (set_int & MHL_INT_DSCR_CHG)
			;
		
		if (set_int & MHL_INT_REQ_WRT) {
			
			mhl_msc_send_set_int(
				MHL_RCHANGE_INT,
				MHL_INT_GRT_WRT);
		}
		
		if (set_int & MHL_INT_GRT_WRT)
			;
		break;
	case 1:
		
		if (set_int & MHL_INT_EDID_CHG) {
		}
	}
	return 0;
}