[PATCH v2 1/7] usb: dwc3: keystone: add basic PM support
Felipe Balbi
balbi at ti.com
Thu Dec 12 16:45:55 EST 2013
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 at ti.com>
---
improve error path a little bit.
drivers/usb/dwc3/dwc3-keystone.c | 94 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 1fad161..3b3761c 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,22 @@ 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);
+ goto err_irq;
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "missing irq\n");
@@ -151,8 +161,11 @@ 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);
+ pm_runtime_disable(dev);
+ clk_unprepare(kdwc->clk);
return error;
}
@@ -172,7 +185,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 +199,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
More information about the linux-arm-kernel
mailing list