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.c172
1 files changed, 77 insertions, 95 deletions
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 61fe2b985070..2e4bb5cc2165 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Generic platform ohci driver
*
@@ -11,8 +12,6 @@
* Copyright 2000-2002 David Brownell
* Copyright 1999 Linus Torvalds
* Copyright 1999 Gregory P. Smith
- *
- * Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/clk.h>
@@ -22,35 +21,31 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
-#include <linux/phy/phy.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#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_RESETS 2
+#define OHCI_MAX_CLKS 4
#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
struct ohci_platform_priv {
struct clk *clks[OHCI_MAX_CLKS];
- struct reset_control *resets[OHCI_MAX_RESETS];
- struct phy **phys;
- int num_phys;
+ 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);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, ret, phy_num;
+ int clk, ret;
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
@@ -58,24 +53,8 @@ static int ohci_platform_power_on(struct platform_device *dev)
goto err_disable_clks;
}
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- ret = phy_init(priv->phys[phy_num]);
- if (ret)
- goto err_exit_phy;
- ret = phy_power_on(priv->phys[phy_num]);
- if (ret) {
- phy_exit(priv->phys[phy_num]);
- goto err_exit_phy;
- }
- }
-
return 0;
-err_exit_phy:
- while (--phy_num >= 0) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
@@ -87,16 +66,10 @@ static void ohci_platform_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, phy_num;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- phy_power_off(priv->phys[phy_num]);
- phy_exit(priv->phys[phy_num]);
- }
+ 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;
@@ -119,7 +92,7 @@ static int ohci_platform_probe(struct platform_device *dev)
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv;
struct ohci_hcd *ohci;
- int err, irq, phy_num, clk = 0, rst = 0;
+ int err, irq, clk = 0;
if (usb_disabled())
return -ENODEV;
@@ -136,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));
@@ -171,29 +142,6 @@ static int ohci_platform_probe(struct platform_device *dev)
of_property_read_u32(dev->dev.of_node, "num-ports",
&ohci->num_ports);
- priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
- "phys", "#phy-cells");
-
- if (priv->num_phys > 0) {
- priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
- sizeof(struct phy *), GFP_KERNEL);
- if (!priv->phys)
- return -ENOMEM;
- } else
- priv->num_phys = 0;
-
- for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
- priv->phys[phy_num] = devm_of_phy_get_by_index(
- &dev->dev, dev->dev.of_node, phy_num);
- if (IS_ERR(priv->phys[phy_num])) {
- err = PTR_ERR(priv->phys[phy_num]);
- goto err_put_hcd;
- } else if (!hcd->phy) {
- /* Avoiding phy_get() in usb_add_hcd() */
- hcd->phy = priv->phys[phy_num];
- }
- }
-
for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
if (IS_ERR(priv->clks[clk])) {
@@ -204,21 +152,17 @@ static int ohci_platform_probe(struct platform_device *dev)
break;
}
}
- for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
- priv->resets[rst] =
- devm_reset_control_get_shared_by_index(
- &dev->dev, rst);
- if (IS_ERR(priv->resets[rst])) {
- err = PTR_ERR(priv->resets[rst]);
- if (err == -EPROBE_DEFER)
- goto err_reset;
- priv->resets[rst] = NULL;
- break;
- }
- err = reset_control_deassert(priv->resets[rst]);
- if (err)
- goto err_reset;
+
+ priv->resets = devm_reset_control_array_get_optional_shared(
+ &dev->dev);
+ if (IS_ERR(priv->resets)) {
+ err = PTR_ERR(priv->resets);
+ goto err_put_clks;
}
+
+ err = reset_control_deassert(priv->resets);
+ if (err)
+ goto err_put_clks;
}
if (pdata->big_endian_desc)
@@ -255,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;
@@ -264,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;
@@ -279,12 +224,11 @@ err_power:
pdata->power_off(dev);
err_reset:
pm_runtime_disable(&dev->dev);
- while (--rst >= 0)
- reset_control_assert(priv->resets[rst]);
+ reset_control_assert(priv->resets);
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
-err_put_hcd:
+
if (pdata == &ohci_platform_defaults)
dev->dev.platform_data = NULL;
@@ -293,12 +237,12 @@ err_put_hcd:
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);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, rst;
+ int clk;
pm_runtime_get_sync(&dev->dev);
usb_remove_hcd(hcd);
@@ -306,8 +250,7 @@ static int ohci_platform_remove(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
- for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++)
- reset_control_assert(priv->resets[rst]);
+ reset_control_assert(priv->resets);
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
clk_put(priv->clks[clk]);
@@ -319,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
@@ -329,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;
@@ -339,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[] = {
@@ -373,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,
@@ -383,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,
}
};
@@ -393,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);
}