Merge "phy: msm: usb: Check VBUS state before accessing registers in suspend"

This commit is contained in:
qctecmdr
2021-09-13 17:07:50 -07:00
committed by Gerrit - the friendly Code Review server

View File

@@ -1420,6 +1420,7 @@ static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data)
static void msm_otg_set_vbus_state(int online); static void msm_otg_set_vbus_state(int online);
static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode); static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode);
static int get_psy_type(struct msm_otg *motg);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int msm_otg_suspend(struct msm_otg *motg) static int msm_otg_suspend(struct msm_otg *motg)
@@ -1458,7 +1459,11 @@ static int msm_otg_suspend(struct msm_otg *motg)
msm_otg_perf_vote_update(motg, false); msm_otg_perf_vote_update(motg, false);
host_pc_charger = (motg->chg_type == USB_SDP_CHARGER) || host_pc_charger = (motg->chg_type == USB_SDP_CHARGER) ||
(motg->chg_type == USB_CDP_CHARGER); (motg->chg_type == USB_CDP_CHARGER) ||
(get_psy_type(motg) == POWER_SUPPLY_TYPE_USB) ||
(get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_CDP);
msm_otg_dbg_log_event(phy, "CHARGER CONNECTED",
host_pc_charger, motg->inputs);
/* !BSV, but its handling is in progress by otg sm_work */ /* !BSV, but its handling is in progress by otg sm_work */
sm_work_busy = !test_bit(B_SESS_VLD, &motg->inputs) && sm_work_busy = !test_bit(B_SESS_VLD, &motg->inputs) &&
@@ -1468,17 +1473,6 @@ static int msm_otg_suspend(struct msm_otg *motg)
if (motg->err_event_seen) if (motg->err_event_seen)
msm_otg_reset(phy); msm_otg_reset(phy);
/* Enable line state difference wakeup fix for only device and host
* bus suspend scenarios. Otherwise PHY can not be suspended when
* a charger that pulls DP/DM high is connected.
*/
config2 = readl_relaxed(USB_GENCONFIG_2);
if (device_bus_suspend)
config2 |= GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
else
config2 &= ~GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
writel_relaxed(config2, USB_GENCONFIG_2);
/* /*
* Abort suspend when, * Abort suspend when,
* 1. host mode activation in progress due to Micro-A cable insertion * 1. host mode activation in progress due to Micro-A cable insertion
@@ -1496,6 +1490,17 @@ static int msm_otg_suspend(struct msm_otg *motg)
return -EBUSY; return -EBUSY;
} }
/* Enable line state difference wakeup fix for only device and host
* bus suspend scenarios. Otherwise PHY can not be suspended when
* a charger that pulls DP/DM high is connected.
*/
config2 = readl_relaxed(USB_GENCONFIG_2);
if (device_bus_suspend)
config2 |= GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
else
config2 &= ~GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
writel_relaxed(config2, USB_GENCONFIG_2);
if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) { if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
/* put the controller in non-driving mode */ /* put the controller in non-driving mode */
func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL); func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
@@ -2862,6 +2867,10 @@ static void check_for_sdp_connection(struct work_struct *w)
msm_otg_set_vbus_state(motg->vbus_state); msm_otg_set_vbus_state(motg->vbus_state);
} }
#define DP_PULSE_WIDTH_MSEC 200
static int
msm_otg_phy_drive_dp_pulse(struct msm_otg *motg, unsigned int pulse_width);
static void msm_otg_sm_work(struct work_struct *w) static void msm_otg_sm_work(struct work_struct *w)
{ {
struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
@@ -2905,6 +2914,9 @@ static void msm_otg_sm_work(struct work_struct *w)
get_pm_runtime_counter(dev), 0); get_pm_runtime_counter(dev), 0);
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
break; break;
} else if (get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_CDP) {
pr_debug("Connected to CDP, pull DP up from sm_work\n");
msm_otg_phy_drive_dp_pulse(motg, DP_PULSE_WIDTH_MSEC);
} }
pm_runtime_put(dev); pm_runtime_put(dev);
/* FALL THROUGH */ /* FALL THROUGH */
@@ -3073,9 +3085,14 @@ msm_otg_phy_drive_dp_pulse(struct msm_otg *motg, unsigned int pulse_width)
{ {
int ret = 0; int ret = 0;
u32 val; u32 val;
bool in_lpm = false;
msm_otg_dbg_log_event(&motg->phy, "DRIVE DP PULSE", msm_otg_dbg_log_event(&motg->phy, "DRIVE DP PULSE",
motg->inputs, 0); motg->inputs, 0);
if (atomic_read(&motg->in_lpm))
in_lpm = true;
if (in_lpm) {
ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON); ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
if (ret) if (ret)
return ret; return ret;
@@ -3086,6 +3103,7 @@ msm_otg_phy_drive_dp_pulse(struct msm_otg *motg, unsigned int pulse_width)
clk_prepare_enable(motg->phy_csr_clk); clk_prepare_enable(motg->phy_csr_clk);
clk_prepare_enable(motg->core_clk); clk_prepare_enable(motg->core_clk);
clk_prepare_enable(motg->pclk); clk_prepare_enable(motg->pclk);
}
msm_otg_exit_phy_retention(motg); msm_otg_exit_phy_retention(motg);
@@ -3131,6 +3149,7 @@ msm_otg_phy_drive_dp_pulse(struct msm_otg *motg, unsigned int pulse_width)
/* Make sure above writes are completed before clks off */ /* Make sure above writes are completed before clks off */
mb(); mb();
if (in_lpm) {
clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->pclk);
clk_disable_unprepare(motg->core_clk); clk_disable_unprepare(motg->core_clk);
clk_disable_unprepare(motg->phy_csr_clk); clk_disable_unprepare(motg->phy_csr_clk);
@@ -3138,17 +3157,19 @@ msm_otg_phy_drive_dp_pulse(struct msm_otg *motg, unsigned int pulse_width)
regulator_disable(hsusb_vdd); regulator_disable(hsusb_vdd);
msm_hsusb_config_vddcx(0); msm_hsusb_config_vddcx(0);
msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF); msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
} else {
msm_otg_reset(&motg->phy);
}
msm_otg_dbg_log_event(&motg->phy, "DP PULSE DRIVEN", msm_otg_dbg_log_event(&motg->phy, "DP PULSE DRIVEN",
motg->inputs, 0); motg->inputs, 0);
return 0; return 0;
} }
#define DP_PULSE_WIDTH_MSEC 200
static void msm_otg_set_vbus_state(int online) static void msm_otg_set_vbus_state(int online)
{ {
struct msm_otg *motg = the_msm_otg; struct msm_otg *motg = the_msm_otg;
struct usb_otg *otg = motg->phy.otg;
motg->vbus_state = online; motg->vbus_state = online;
@@ -3161,7 +3182,12 @@ static void msm_otg_set_vbus_state(int online)
motg->inputs, 0); motg->inputs, 0);
if (test_and_set_bit(B_SESS_VLD, &motg->inputs)) if (test_and_set_bit(B_SESS_VLD, &motg->inputs))
return; return;
if (get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_CDP) { /*
* It might race with block reset happening in sm_work, while
* state machine is in undefined state. Add check to avoid it.
*/
if ((get_psy_type(motg) == POWER_SUPPLY_TYPE_USB_CDP) &&
(otg->state != OTG_STATE_UNDEFINED)) {
pr_debug("Connected to CDP, pull DP up\n"); pr_debug("Connected to CDP, pull DP up\n");
msm_otg_phy_drive_dp_pulse(motg, DP_PULSE_WIDTH_MSEC); msm_otg_phy_drive_dp_pulse(motg, DP_PULSE_WIDTH_MSEC);
} }