summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ohci-platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-platform.c')
-rw-r--r--drivers/usb/host/ohci-platform.c78
1 files changed, 57 insertions, 21 deletions
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 65a1c3fdc88c..2e4bb5cc2165 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -28,11 +28,12 @@
#include <linux/usb/ohci_pdriver.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/of.h>
#include "ohci.h"
#define DRIVER_DESC "OHCI generic platform driver"
-#define OHCI_MAX_CLKS 3
+#define OHCI_MAX_CLKS 4
#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
struct ohci_platform_priv {
@@ -40,8 +41,6 @@ struct ohci_platform_priv {
struct reset_control *resets;
};
-static const char hcd_name[] = "ohci-platform";
-
static int ohci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
@@ -70,8 +69,7 @@ static void ohci_platform_power_off(struct platform_device *dev)
int clk;
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
- if (priv->clks[clk])
- clk_disable_unprepare(priv->clks[clk]);
+ clk_disable_unprepare(priv->clks[clk]);
}
static struct hc_driver __read_mostly ohci_platform_hc_driver;
@@ -111,10 +109,8 @@ static int ohci_platform_probe(struct platform_device *dev)
return err;
irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "no irq provided");
+ if (irq < 0)
return irq;
- }
hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
dev_name(&dev->dev));
@@ -203,8 +199,7 @@ static int ohci_platform_probe(struct platform_device *dev)
goto err_reset;
}
- res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
- hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
+ hcd->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto err_power;
@@ -212,6 +207,8 @@ static int ohci_platform_probe(struct platform_device *dev)
hcd->rsrc_start = res_mem->start;
hcd->rsrc_len = resource_size(res_mem);
+ hcd->tpl_support = of_usb_host_tpl_support(dev->dev.of_node);
+
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
goto err_power;
@@ -240,7 +237,7 @@ err_put_clks:
return err;
}
-static int ohci_platform_remove(struct platform_device *dev)
+static void ohci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
@@ -265,8 +262,6 @@ static int ohci_platform_remove(struct platform_device *dev)
if (pdata == &ohci_platform_defaults)
dev->dev.platform_data = NULL;
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -275,6 +270,7 @@ static int ohci_platform_suspend(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev->platform_data;
struct platform_device *pdev = to_platform_device(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
bool do_wakeup = device_may_wakeup(dev);
int ret;
@@ -285,24 +281,55 @@ static int ohci_platform_suspend(struct device *dev)
if (pdata->power_suspend)
pdata->power_suspend(pdev);
+ ret = reset_control_assert(priv->resets);
+ if (ret) {
+ if (pdata->power_on)
+ pdata->power_on(pdev);
+
+ ohci_resume(hcd, false);
+ }
+
return ret;
}
-static int ohci_platform_resume(struct device *dev)
+static int ohci_platform_resume_common(struct device *dev, bool hibernated)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
+ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
+ int err;
+
+ err = reset_control_deassert(priv->resets);
+ if (err)
+ return err;
if (pdata->power_on) {
- int err = pdata->power_on(pdev);
- if (err < 0)
+ err = pdata->power_on(pdev);
+ if (err < 0) {
+ reset_control_assert(priv->resets);
return err;
+ }
}
- ohci_resume(hcd, false);
+ ohci_resume(hcd, hibernated);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
return 0;
}
+
+static int ohci_platform_resume(struct device *dev)
+{
+ return ohci_platform_resume_common(dev, false);
+}
+
+static int ohci_platform_restore(struct device *dev)
+{
+ return ohci_platform_resume_common(dev, true);
+}
#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id ohci_platform_ids[] = {
@@ -319,8 +346,16 @@ static const struct platform_device_id ohci_platform_table[] = {
};
MODULE_DEVICE_TABLE(platform, ohci_platform_table);
-static SIMPLE_DEV_PM_OPS(ohci_platform_pm_ops, ohci_platform_suspend,
- ohci_platform_resume);
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops ohci_platform_pm_ops = {
+ .suspend = ohci_platform_suspend,
+ .resume = ohci_platform_resume,
+ .freeze = ohci_platform_suspend,
+ .thaw = ohci_platform_resume,
+ .poweroff = ohci_platform_suspend,
+ .restore = ohci_platform_restore,
+};
+#endif
static struct platform_driver ohci_platform_driver = {
.id_table = ohci_platform_table,
@@ -329,8 +364,11 @@ static struct platform_driver ohci_platform_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ohci-platform",
+#ifdef CONFIG_PM_SLEEP
.pm = &ohci_platform_pm_ops,
+#endif
.of_match_table = ohci_platform_ids,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
}
};
@@ -339,8 +377,6 @@ static int __init ohci_platform_init(void)
if (usb_disabled())
return -ENODEV;
- pr_info("%s: " DRIVER_DESC "\n", hcd_name);
-
ohci_init_driver(&ohci_platform_hc_driver, &platform_overrides);
return platform_driver_register(&ohci_platform_driver);
}