Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / drivers / usb / host / ehci-generic.c
index 1cb92c033870887939ee40915ce8af4562f8847b..304a3437d56cb60dcea097e44f1bafb5d719f184 100644 (file)
@@ -1,17 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2015 Alexey Brodkin <abrodkin@synopsys.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <clk.h>
+#include <log.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
 #include <dm/ofnode.h>
 #include <generic-phy.h>
 #include <reset.h>
 #include <asm/io.h>
 #include <dm.h>
 #include "ehci.h"
+#include <power/regulator.h>
 
 /*
  * Even though here we don't explicitly use "struct ehci_ctrl"
@@ -23,10 +26,56 @@ struct generic_ehci {
        struct clk *clocks;
        struct reset_ctl *resets;
        struct phy phy;
+#ifdef CONFIG_DM_REGULATOR
+       struct udevice *vbus_supply;
+#endif
        int clock_count;
        int reset_count;
 };
 
+#ifdef CONFIG_DM_REGULATOR
+static int ehci_enable_vbus_supply(struct udevice *dev)
+{
+       struct generic_ehci *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = device_get_supply_regulator(dev, "vbus-supply",
+                                         &priv->vbus_supply);
+       if (ret && ret != -ENOENT)
+               return ret;
+
+       if (priv->vbus_supply) {
+               ret = regulator_set_enable(priv->vbus_supply, true);
+               if (ret) {
+                       dev_err(dev, "Error enabling VBUS supply\n");
+                       return ret;
+               }
+       } else {
+               dev_dbg(dev, "No vbus supply\n");
+       }
+
+       return 0;
+}
+
+static int ehci_disable_vbus_supply(struct generic_ehci *priv)
+{
+       if (priv->vbus_supply)
+               return regulator_set_enable(priv->vbus_supply, false);
+       else
+               return 0;
+}
+#else
+static int ehci_enable_vbus_supply(struct udevice *dev)
+{
+       return 0;
+}
+
+static int ehci_disable_vbus_supply(struct generic_ehci *priv)
+{
+       return 0;
+}
+#endif
+
 static int ehci_usb_probe(struct udevice *dev)
 {
        struct generic_ehci *priv = dev_get_priv(dev);
@@ -50,8 +99,8 @@ static int ehci_usb_probe(struct udevice *dev)
                        if (err < 0)
                                break;
                        err = clk_enable(&priv->clocks[i]);
-                       if (err) {
-                               pr_err("failed to enable clock %d\n", i);
+                       if (err && err != -ENOSYS) {
+                               dev_err(dev, "failed to enable clock %d\n", i);
                                clk_free(&priv->clocks[i]);
                                goto clk_err;
                        }
@@ -59,7 +108,8 @@ static int ehci_usb_probe(struct udevice *dev)
                }
        } else {
                if (clock_nb != -ENOENT) {
-                       pr_err("failed to get clock phandle(%d)\n", clock_nb);
+                       dev_err(dev, "failed to get clock phandle(%d)\n",
+                               clock_nb);
                        return clock_nb;
                }
        }
@@ -80,7 +130,8 @@ static int ehci_usb_probe(struct udevice *dev)
                                break;
 
                        if (reset_deassert(&priv->resets[i])) {
-                               pr_err("failed to deassert reset %d\n", i);
+                               dev_err(dev, "failed to deassert reset %d\n",
+                                       i);
                                reset_free(&priv->resets[i]);
                                goto reset_err;
                        }
@@ -88,25 +139,19 @@ static int ehci_usb_probe(struct udevice *dev)
                }
        } else {
                if (reset_nb != -ENOENT) {
-                       pr_err("failed to get reset phandle(%d)\n", reset_nb);
+                       dev_err(dev, "failed to get reset phandle(%d)\n",
+                               reset_nb);
                        goto clk_err;
                }
        }
 
-       err = generic_phy_get_by_index(dev, 0, &priv->phy);
-       if (err) {
-               if (err != -ENOENT) {
-                       pr_err("failed to get usb phy\n");
-                       goto reset_err;
-               }
-       } else {
+       err = ehci_enable_vbus_supply(dev);
+       if (err)
+               goto reset_err;
 
-               err = generic_phy_init(&priv->phy);
-               if (err) {
-                       pr_err("failed to init usb phy\n");
-                       goto reset_err;
-               }
-       }
+       err = ehci_setup_phy(dev, &priv->phy, 0);
+       if (err)
+               goto regulator_err;
 
        hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE);
        hcor = (struct ehci_hcor *)((uintptr_t)hccr +
@@ -119,20 +164,23 @@ static int ehci_usb_probe(struct udevice *dev)
        return 0;
 
 phy_err:
-       if (generic_phy_valid(&priv->phy)) {
-               ret = generic_phy_exit(&priv->phy);
-               if (ret)
-                       pr_err("failed to release phy\n");
-       }
+       ret = ehci_shutdown_phy(dev, &priv->phy);
+       if (ret)
+               dev_err(dev, "failed to shutdown usb phy\n");
+
+regulator_err:
+       ret = ehci_disable_vbus_supply(priv);
+       if (ret)
+               dev_err(dev, "failed to disable VBUS supply\n");
 
 reset_err:
        ret = reset_release_all(priv->resets, priv->reset_count);
        if (ret)
-               pr_err("failed to assert all resets\n");
+               dev_err(dev, "failed to assert all resets\n");
 clk_err:
        ret = clk_release_all(priv->clocks, priv->clock_count);
        if (ret)
-               pr_err("failed to disable all clocks\n");
+               dev_err(dev, "failed to disable all clocks\n");
 
        return err;
 }
@@ -146,11 +194,13 @@ static int ehci_usb_remove(struct udevice *dev)
        if (ret)
                return ret;
 
-       if (generic_phy_valid(&priv->phy)) {
-               ret = generic_phy_exit(&priv->phy);
-               if (ret)
-                       return ret;
-       }
+       ret = ehci_shutdown_phy(dev, &priv->phy);
+       if (ret)
+               return ret;
+
+       ret = ehci_disable_vbus_supply(priv);
+       if (ret)
+               return ret;
 
        ret =  reset_release_all(priv->resets, priv->reset_count);
        if (ret)