static int edp_ctrl_training(struct edp_ctrl *ctrl) { int ret; /* Do link training only when power is on */ if (!ctrl->power_on) return -EINVAL; train_start: ret = edp_do_link_train(ctrl); if (ret == EDP_TRAIN_RECONFIG) { /* Re-configure main link */ edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); msm_edp_phy_ctrl(ctrl->phy, 0); /* Make sure link is fully disabled */ wmb(); usleep_range(500, 1000); msm_edp_phy_ctrl(ctrl->phy, 1); edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); goto train_start; } return ret; }
static void edp_ctrl_on_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, on_work); int ret; mutex_lock(&ctrl->dev_mutex); if (ctrl->power_on) { DBG("already on"); goto unlock_ret; } edp_ctrl_phy_aux_enable(ctrl, 1); edp_ctrl_link_enable(ctrl, 1); edp_ctrl_irq_enable(ctrl, 1); ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link); if (ret) goto fail; ctrl->power_on = true; /* Start link training */ ret = edp_ctrl_training(ctrl); if (ret != EDP_TRAIN_SUCCESS) goto fail; DBG("DONE"); goto unlock_ret; fail: edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); ctrl->power_on = false; unlock_ret: mutex_unlock(&ctrl->dev_mutex); }
static void edp_ctrl_off_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, off_work); int ret; mutex_lock(&ctrl->dev_mutex); if (!ctrl->power_on) { DBG("already off"); goto unlock_ret; } reinit_completion(&ctrl->idle_comp); edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); ret = wait_for_completion_timeout(&ctrl->idle_comp, msecs_to_jiffies(500)); if (ret <= 0) DBG("%s: idle pattern timedout, %d\n", __func__, ret); edp_state_ctrl(ctrl, 0); drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link); edp_ctrl_irq_enable(ctrl, 0); edp_ctrl_link_enable(ctrl, 0); edp_ctrl_phy_aux_enable(ctrl, 0); ctrl->power_on = false; unlock_ret: mutex_unlock(&ctrl->dev_mutex); }