A bare-minimum PM implementation which will server as building block for more complex PM implementation in the future. At the least will not leave clocks on unnecessarily when e.g. a user write mem to /sys/power/state. Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/dwc3/dwc3-keystone.c | 97 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 1fad161..361437f 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/pm_runtime.h> #include <linux/io.h> #include <linux/of_platform.h> @@ -118,13 +119,23 @@ static int kdwc3_probe(struct platform_device *pdev) kdwc->clk = devm_clk_get(kdwc->dev, "usb"); - error = clk_prepare_enable(kdwc->clk); + error = clk_prepare(kdwc->clk); if (error < 0) { dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n", error); return error; } + pm_runtime_enable(dev); + + error = pm_runtime_get_sync(dev); + if (error < 0) { + dev_dbg(dev, "unable to pm_runtime_get_sync(), err %d\n", + error); + pm_runtime_put_sync(dev); + goto err_runtime_get; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "missing irq\n"); @@ -151,8 +162,13 @@ static int kdwc3_probe(struct platform_device *pdev) err_core: kdwc3_disable_irqs(kdwc); + err_irq: - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(dev); + +err_runtime_get: + pm_runtime_disable(dev); + clk_unprepare(kdwc->clk); return error; } @@ -172,7 +188,9 @@ static int kdwc3_remove(struct platform_device *pdev) kdwc3_disable_irqs(kdwc); device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); - clk_disable_unprepare(kdwc->clk); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + clk_unprepare(kdwc->clk); platform_set_drvdata(pdev, NULL); return 0; @@ -184,6 +202,79 @@ static const struct of_device_id kdwc3_of_match[] = { }; MODULE_DEVICE_TABLE(of, kdwc3_of_match); +static int __kdwc3_suspend(struct dwc3_keystone *kdwc) +{ + clk_disable(kdwc->clk); + + return 0; +} + +static int __kdwc3_resume(struct dwc3_keystone *kdwc) +{ + return clk_enable(kdwc->clk); +} + +static int kdwc3_prepare(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + + kdwc3_disable_irqs(kdwc); + + return 0; +} + +static void kdwc3_complete(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + + kdwc3_enable_irqs(kdwc); +} + +static int kdwc3_suspend(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + + return __kdwc3_suspend(kdwc); +} + +static int kdwc3_resume(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + int ret; + + ret = __kdwc3_resume(kdwc); + if (ret) + return ret; + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static int kdwc3_runtime_suspend(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + + return __kdwc3_suspend(kdwc); +} + +static int kdwc3_runtime_resume(struct device *dev) +{ + struct dwc3_keystone *kdwc = dev_get_drvdata(dev); + + return __kdwc3_resume(kdwc); +} + +static const struct dev_pm_ops kdwc3_dev_pm_ops = { + .prepare = kdwc3_prepare, + .complete = kdwc3_complete, + + SET_SYSTEM_SLEEP_PM_OPS(kdwc3_suspend, kdwc3_resume) + SET_RUNTIME_PM_OPS(kdwc3_runtime_suspend, kdwc3_runtime_resume, NULL) +}; + static struct platform_driver kdwc3_driver = { .probe = kdwc3_probe, .remove = kdwc3_remove, -- 1.8.4.GIT -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html