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; }