summaryrefslogtreecommitdiff
path: root/drivers/usb/phy/phy-generic.c
diff options
context:
space:
mode:
authorOleksandr Suvorov <oleksandr.suvorov@toradex.com>2019-11-11 14:47:08 +0100
committerPhilippe Schenker <philippe.schenker@toradex.com>2020-08-13 16:04:48 +0200
commit0d2c39207e403a8ce9141f2abd70bb432810d02d (patch)
tree59f9e79cf846d51f426a9c38cf3c099c9b484526 /drivers/usb/phy/phy-generic.c
parent149b42a99f4f79f10c8930da4d9d1f71a86e395f (diff)
usb: phy: phy-generic: add an ability to reset on resume
Regular USB device gets power down in system suspend. New hardware designs require to include USB devices as part of main scheme. If this case the power could be provide to a device unmanagable. The best option to reset this kind of devices is to reset it on USB physical interface level. Add this ability. Using "reset-on-resume" DT-option for usb-generic driver enables reset nested device on resume event by gpio interface. Signed-off-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com> (cherry picked from commit 4c74d1a7b1e1ece7f6b7a4dfe5da9170a6dd9644) Conflicts: drivers/usb/phy/phy-generic.c Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>
Diffstat (limited to 'drivers/usb/phy/phy-generic.c')
-rw-r--r--drivers/usb/phy/phy-generic.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index a53b89be5324..5c39a2644b5c 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -44,30 +44,37 @@ void usb_phy_generic_unregister(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(usb_phy_generic_unregister);
-static int nop_set_suspend(struct usb_phy *x, int suspend)
-{
- struct usb_phy_generic *nop = dev_get_drvdata(x->dev);
-
- if (!IS_ERR(nop->clk)) {
- if (suspend)
- clk_disable_unprepare(nop->clk);
- else
- clk_prepare_enable(nop->clk);
- }
-
- return 0;
-}
-
static void nop_reset(struct usb_phy_generic *nop)
{
if (!nop->gpiod_reset)
return;
+ dev_dbg(nop->dev, "reset\n");
+
gpiod_set_value_cansleep(nop->gpiod_reset, 1);
usleep_range(10000, 20000);
gpiod_set_value_cansleep(nop->gpiod_reset, 0);
}
+static int nop_set_suspend(struct usb_phy *x, int suspend)
+{
+ struct usb_phy_generic *nop = dev_get_drvdata(x->dev);
+
+ dev_dbg(x->dev, "%s\n", suspend ? "suspend" : "resume");
+
+ if (suspend) {
+ if (!IS_ERR(nop->clk))
+ clk_disable_unprepare(nop->clk);
+ } else {
+ if (!IS_ERR(nop->clk))
+ clk_prepare_enable(nop->clk);
+
+ if (nop->reset_on_resume)
+ nop_reset(nop);
+ }
+ return 0;
+}
+
/* interface to regulator framework */
static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
{
@@ -219,6 +226,9 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
+ nop->reset_on_resume =
+ of_property_read_bool(node, "reset-on-resume");
+
needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_clk = of_property_read_bool(node, "clocks");
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
@@ -229,6 +239,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
"vbus-detect",
GPIOD_ASIS);
err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
+ } else {
+ nop->gpiod_reset = NULL;
}
} else if (pdata) {
type = pdata->type;