diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 7d82d5add7c1..2e37272d990f 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -74,6 +74,7 @@ struct sysc { u32 revision; bool enabled; bool needs_resume; + struct delayed_work idle_work; }; static u32 sysc_read(struct sysc *ddata, int offset) @@ -1028,6 +1029,16 @@ static int sysc_init_match(struct sysc *ddata) return 0; } +static void ti_sysc_idle(struct work_struct *work) +{ + struct sysc *ddata; + + ddata = container_of(work, struct sysc, idle_work.work); + + if (pm_runtime_active(ddata->dev)) + pm_runtime_put_sync(ddata->dev); +} + static int sysc_probe(struct platform_device *pdev) { struct sysc *ddata; @@ -1081,8 +1092,6 @@ static int sysc_probe(struct platform_device *pdev) goto unprepare; } - pm_runtime_use_autosuspend(ddata->dev); - sysc_show_registers(ddata); ddata->dev->type = &sysc_device_type; @@ -1091,13 +1100,19 @@ static int sysc_probe(struct platform_device *pdev) if (error) goto err; - pm_runtime_mark_last_busy(ddata->dev); - pm_runtime_put_autosuspend(ddata->dev); + INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle); + + /* At least earlycon won't survive without deferred idle */ + if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT | + SYSC_QUIRK_NO_RESET_ON_INIT)) { + schedule_delayed_work(&ddata->idle_work, 3000); + } else { + pm_runtime_put(&pdev->dev); + } return 0; err: - pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); unprepare: @@ -1111,6 +1126,8 @@ static int sysc_remove(struct platform_device *pdev) struct sysc *ddata = platform_get_drvdata(pdev); int error; + cancel_delayed_work_sync(&ddata->idle_work); + error = pm_runtime_get_sync(ddata->dev); if (error < 0) { pm_runtime_put_noidle(ddata->dev); @@ -1120,7 +1137,6 @@ static int sysc_remove(struct platform_device *pdev) of_platform_depopulate(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev);