usb: dwc3-msm: Simplify OTG_STATE_UNDEFINED handling
In commit 48924e2fe107 ("dwc3: Reset USB controller/PHY after psy connect indication at bootup") the controller initialization path was removed from dwc3_msm_probe() and is deferred to when actually needed, which is when beginning peripheral or host mode. This was to optimize for the HVDCP charger already-connected case in which case we want to avoid performing controller initialization which can disrupt D+/D- linestate. As part of that change, the OTG_STATE_UNDEFINED state was made to be the entry point for starting controller initialization. However, apart from that, the handling is identical to B_IDLE_STATE, and therefore could be consolidated. And now that charger driver only notifies us when SDP or CDP types, but not when DCP/HVDCP are connected, the code can be simplified by removing the duplicate code between dwc3_initialize() and dwc3_msm_resume(). Change-Id: Ife749c864284864098bcbcbdbda096d05397c60e Signed-off-by: Jack Pham <jackp@codeaurora.org>
This commit is contained in:
parent
40a697724b
commit
b885707413
1 changed files with 41 additions and 116 deletions
|
@ -1717,6 +1717,13 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
|
||||||
clk_disable_unprepare(mdwc->cfg_ahb_clk);
|
clk_disable_unprepare(mdwc->cfg_ahb_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mdwc->init) {
|
||||||
|
dbg_event(0xFF, "dwc3 init",
|
||||||
|
atomic_read(&mdwc->dev->power.usage_count));
|
||||||
|
dwc3_core_pre_init(dwc);
|
||||||
|
mdwc->init = true;
|
||||||
|
}
|
||||||
|
|
||||||
dwc3_core_init(dwc);
|
dwc3_core_init(dwc);
|
||||||
/* Re-configure event buffers */
|
/* Re-configure event buffers */
|
||||||
dwc3_event_buffers_setup(dwc);
|
dwc3_event_buffers_setup(dwc);
|
||||||
|
@ -1985,11 +1992,16 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
|
||||||
|
|
||||||
/* Recover from controller power collapse */
|
/* Recover from controller power collapse */
|
||||||
if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
|
if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__);
|
dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__);
|
||||||
|
|
||||||
dwc3_msm_power_collapse_por(mdwc);
|
dwc3_msm_power_collapse_por(mdwc);
|
||||||
|
|
||||||
/* Re-enable IN_P3 event */
|
/* Get initial P3 status and enable IN_P3 event */
|
||||||
|
tmp = dwc3_msm_read_reg_field(mdwc->base,
|
||||||
|
DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK);
|
||||||
|
atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3);
|
||||||
dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG,
|
dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG,
|
||||||
PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);
|
PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);
|
||||||
|
|
||||||
|
@ -2069,15 +2081,6 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc)
|
||||||
clear_bit(B_SUSPEND, &mdwc->inputs);
|
clear_bit(B_SUSPEND, &mdwc->inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mdwc->init) {
|
|
||||||
mdwc->init = true;
|
|
||||||
pm_runtime_set_autosuspend_delay(mdwc->dev, 1000);
|
|
||||||
pm_runtime_use_autosuspend(mdwc->dev);
|
|
||||||
if (!work_busy(&mdwc->sm_work.work))
|
|
||||||
schedule_delayed_work(&mdwc->sm_work, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
schedule_delayed_work(&mdwc->sm_work, 0);
|
schedule_delayed_work(&mdwc->sm_work, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2497,20 +2500,14 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Some platforms have a special interrupt line for indicating resume
|
|
||||||
* while in low power mode, when clocks are disabled.
|
|
||||||
*/
|
|
||||||
mdwc->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq");
|
mdwc->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq");
|
||||||
if (mdwc->pwr_event_irq < 0) {
|
if (mdwc->pwr_event_irq < 0) {
|
||||||
dev_err(&pdev->dev, "pget_irq for pwr_event_irq failed\n");
|
dev_err(&pdev->dev, "pget_irq for pwr_event_irq failed\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/* will be enabled in dwc3_msm_resume() */
|
||||||
* enable pwr event irq early during PM resume to meet bus
|
irq_set_status_flags(mdwc->pwr_event_irq, IRQ_NOAUTOEN);
|
||||||
* resume timeline from usb device
|
|
||||||
*/
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, mdwc->pwr_event_irq,
|
ret = devm_request_threaded_irq(&pdev->dev, mdwc->pwr_event_irq,
|
||||||
msm_dwc3_pwr_irq,
|
msm_dwc3_pwr_irq,
|
||||||
msm_dwc3_pwr_irq_thread,
|
msm_dwc3_pwr_irq_thread,
|
||||||
|
@ -2701,8 +2698,18 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
||||||
if (cpu_to_affin)
|
if (cpu_to_affin)
|
||||||
register_cpu_notifier(&mdwc->dwc3_cpu_notifier);
|
register_cpu_notifier(&mdwc->dwc3_cpu_notifier);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clocks and regulators will not be turned on until the first time
|
||||||
|
* runtime PM resume is called. This is to allow for booting up with
|
||||||
|
* charger already connected so as not to disturb PHY line states.
|
||||||
|
*/
|
||||||
|
mdwc->lpm_flags = MDWC3_POWER_COLLAPSE | MDWC3_SS_PHY_SUSPEND;
|
||||||
|
atomic_set(&dwc->in_lpm, 1);
|
||||||
|
pm_runtime_set_suspended(mdwc->dev);
|
||||||
|
pm_runtime_set_autosuspend_delay(mdwc->dev, 1000);
|
||||||
|
pm_runtime_use_autosuspend(mdwc->dev);
|
||||||
|
pm_runtime_enable(mdwc->dev);
|
||||||
device_init_wakeup(mdwc->dev, 1);
|
device_init_wakeup(mdwc->dev, 1);
|
||||||
pm_stay_awake(mdwc->dev);
|
|
||||||
|
|
||||||
if (of_property_read_bool(node, "qcom,disable-dev-mode-pm"))
|
if (of_property_read_bool(node, "qcom,disable-dev-mode-pm"))
|
||||||
pm_runtime_get_noresume(mdwc->dev);
|
pm_runtime_get_noresume(mdwc->dev);
|
||||||
|
@ -3053,52 +3060,6 @@ psy_error:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dwc3_initialize(struct dwc3_msm *mdwc)
|
|
||||||
{
|
|
||||||
u32 tmp;
|
|
||||||
int ret;
|
|
||||||
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
|
|
||||||
|
|
||||||
dbg_event(0xFF, "Initialized Start",
|
|
||||||
atomic_read(&mdwc->dev->power.usage_count));
|
|
||||||
|
|
||||||
if (mdwc->bus_perf_client) {
|
|
||||||
mdwc->bus_vote = 1;
|
|
||||||
schedule_work(&mdwc->bus_vote_w);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enable USB GDSC */
|
|
||||||
dwc3_msm_config_gdsc(mdwc, 1);
|
|
||||||
|
|
||||||
/* enable all clocks */
|
|
||||||
ret = clk_prepare_enable(mdwc->xo_clk);
|
|
||||||
clk_prepare_enable(mdwc->iface_clk);
|
|
||||||
clk_prepare_enable(mdwc->core_clk);
|
|
||||||
clk_prepare_enable(mdwc->sleep_clk);
|
|
||||||
clk_prepare_enable(mdwc->utmi_clk);
|
|
||||||
if (mdwc->bus_aggr_clk)
|
|
||||||
clk_prepare_enable(mdwc->bus_aggr_clk);
|
|
||||||
|
|
||||||
/* Perform controller GCC reset */
|
|
||||||
dwc3_msm_link_clk_reset(mdwc, 1);
|
|
||||||
msleep(20);
|
|
||||||
dwc3_msm_link_clk_reset(mdwc, 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get core configuration and initialized
|
|
||||||
* Set Event buffers
|
|
||||||
* Reset both USB PHYs and initialized
|
|
||||||
*/
|
|
||||||
dwc3_core_pre_init(dwc);
|
|
||||||
|
|
||||||
/* Get initial P3 status and enable IN_P3 event */
|
|
||||||
tmp = dwc3_msm_read_reg_field(mdwc->base,
|
|
||||||
DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK);
|
|
||||||
atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3);
|
|
||||||
dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG,
|
|
||||||
PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc3_otg_sm_work - workqueue function.
|
* dwc3_otg_sm_work - workqueue function.
|
||||||
*
|
*
|
||||||
|
@ -3130,57 +3091,21 @@ static void dwc3_otg_sm_work(struct work_struct *w)
|
||||||
/* Check OTG state */
|
/* Check OTG state */
|
||||||
switch (mdwc->otg_state) {
|
switch (mdwc->otg_state) {
|
||||||
case OTG_STATE_UNDEFINED:
|
case OTG_STATE_UNDEFINED:
|
||||||
if (!test_bit(ID, &mdwc->inputs)) {
|
/* Do nothing if no cable connected */
|
||||||
dbg_event(0xFF, "undef_host", 0);
|
if (test_bit(ID, &mdwc->inputs) &&
|
||||||
atomic_set(&dwc->in_lpm, 0);
|
!test_bit(B_SESS_VLD, &mdwc->inputs))
|
||||||
pm_runtime_set_active(mdwc->dev);
|
|
||||||
pm_runtime_enable(mdwc->dev);
|
|
||||||
pm_runtime_get_noresume(mdwc->dev);
|
|
||||||
dwc3_initialize(mdwc);
|
|
||||||
mdwc->otg_state = OTG_STATE_A_HOST;
|
|
||||||
ret = dwc3_otg_start_host(mdwc, 1);
|
|
||||||
pm_runtime_put_noidle(mdwc->dev);
|
|
||||||
if (ret != -EPROBE_DEFER)
|
|
||||||
return;
|
|
||||||
/*
|
|
||||||
* regulator_get for VBUS may fail with -EPROBE_DEFER.
|
|
||||||
* Set the state as A_IDLE which will re-schedule
|
|
||||||
* sm_work after 1sec and call start_host again.
|
|
||||||
*/
|
|
||||||
mdwc->otg_state = OTG_STATE_A_IDLE;
|
|
||||||
work = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (test_bit(B_SESS_VLD, &mdwc->inputs)) {
|
dbg_event(0xFF, "Exit UNDEF", 0);
|
||||||
dev_dbg(mdwc->dev, "b_sess_vld\n");
|
|
||||||
dbg_event(0xFF, "undef_b_sess_vld", 0);
|
|
||||||
atomic_set(&dwc->in_lpm, 0);
|
|
||||||
pm_runtime_set_active(mdwc->dev);
|
|
||||||
pm_runtime_enable(mdwc->dev);
|
|
||||||
pm_runtime_get_noresume(mdwc->dev);
|
|
||||||
dwc3_initialize(mdwc);
|
|
||||||
dwc3_otg_start_peripheral(mdwc, 1);
|
|
||||||
mdwc->otg_state = OTG_STATE_B_PERIPHERAL;
|
|
||||||
dbg_event(0xFF, "Undef SDP",
|
|
||||||
atomic_read(&mdwc->dev->power.usage_count));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!test_bit(B_SESS_VLD, &mdwc->inputs)) {
|
|
||||||
dbg_event(0xFF, "undef_!b_sess_vld", 0);
|
|
||||||
atomic_set(&dwc->in_lpm, 0);
|
|
||||||
pm_runtime_set_active(mdwc->dev);
|
|
||||||
pm_runtime_enable(mdwc->dev);
|
|
||||||
pm_runtime_get_noresume(mdwc->dev);
|
|
||||||
dwc3_initialize(mdwc);
|
|
||||||
pm_runtime_put_sync(mdwc->dev);
|
|
||||||
dbg_event(0xFF, "Undef NoUSB",
|
|
||||||
atomic_read(&mdwc->dev->power.usage_count));
|
|
||||||
mdwc->otg_state = OTG_STATE_B_IDLE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first call to msm_resume will enable this IRQ which
|
||||||
|
* needs to first be disabled else it will be unbalanced.
|
||||||
|
*/
|
||||||
|
if (dwc->irq)
|
||||||
|
disable_irq(dwc->irq);
|
||||||
|
mdwc->otg_state = OTG_STATE_B_IDLE;
|
||||||
|
/* fall-through */
|
||||||
case OTG_STATE_B_IDLE:
|
case OTG_STATE_B_IDLE:
|
||||||
if (!test_bit(ID, &mdwc->inputs)) {
|
if (!test_bit(ID, &mdwc->inputs)) {
|
||||||
dev_dbg(mdwc->dev, "!id\n");
|
dev_dbg(mdwc->dev, "!id\n");
|
||||||
|
@ -3202,7 +3127,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
dwc3_msm_gadget_vbus_draw(mdwc, 0);
|
dwc3_msm_gadget_vbus_draw(mdwc, 0);
|
||||||
dev_dbg(mdwc->dev, "No device, allowing suspend\n");
|
dev_dbg(mdwc->dev, "Cable disconnected\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3218,7 +3143,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
|
||||||
* OTG_STATE_B_IDLE state
|
* OTG_STATE_B_IDLE state
|
||||||
*/
|
*/
|
||||||
pm_runtime_put_sync(mdwc->dev);
|
pm_runtime_put_sync(mdwc->dev);
|
||||||
dbg_event(0xFF, "BPER psync",
|
dbg_event(0xFF, "!BSV psync",
|
||||||
atomic_read(&mdwc->dev->power.usage_count));
|
atomic_read(&mdwc->dev->power.usage_count));
|
||||||
work = 1;
|
work = 1;
|
||||||
} else if (test_bit(B_SUSPEND, &mdwc->inputs) &&
|
} else if (test_bit(B_SUSPEND, &mdwc->inputs) &&
|
||||||
|
@ -3254,7 +3179,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
|
||||||
* OTG_STATE_B_PERIPHERAL state.
|
* OTG_STATE_B_PERIPHERAL state.
|
||||||
*/
|
*/
|
||||||
pm_runtime_get_sync(mdwc->dev);
|
pm_runtime_get_sync(mdwc->dev);
|
||||||
dbg_event(0xFF, "SUSP gsync",
|
dbg_event(0xFF, "!SUSP gsync",
|
||||||
atomic_read(&mdwc->dev->power.usage_count));
|
atomic_read(&mdwc->dev->power.usage_count));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue