By statically hardcoding at compile time the number of supplies
("#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names)"), the
driver assumed that every controller uses supplies and issued a
warning if none were detected via the device tree [1], even though the
vast majority of devices (with 1 exception from Samsung) don't need
nor use them.

So to return to normality and stop warning everyone unconditionally,
detect if there are any supplies and no-op just like the dummy
regulator which got loudly auto-asigned does.

This issue has been previously discussed based on an alternative fix
at [2] a year back but nothing came out of it then.

[1]
dwc2 3f980000.usb: 3f980000.usb supply vusb_d not found, using dummy regulator
dwc2 3f980000.usb: 3f980000.usb supply vusb_a not found, using dummy regulator

[2]
https://www.spinics.net/lists/linux-usb/msg153010.html

Signed-off-by: Ioan-Adrian Ratiu <a...@adirat.com>
---
 drivers/usb/dwc2/core.h     |  5 +++--
 drivers/usb/dwc2/platform.c | 46 +++++++++++++++++++++++++++++++--------------
 2 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index cd77af3b1565..c50b9fc4a162 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -128,7 +128,7 @@ static const char * const dwc2_hsotg_supply_names[] = {
        "vusb_a",               /* analog USB supply, 1.1V */
 };
 
-#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names)
+#define DWC2_MAX_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names)
 
 /*
  * EP0_MPS_LIMIT
@@ -921,7 +921,8 @@ struct dwc2_hsotg {
        struct phy *phy;
        struct usb_phy *uphy;
        struct dwc2_hsotg_plat *plat;
-       struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
+       struct regulator_bulk_data supplies[DWC2_MAX_SUPPLIES];
+       u8 num_supplies;
        u32 phyif;
 
        spinlock_t lock;
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 4703478f702f..3acf658af4e9 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -126,10 +126,12 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg 
*hsotg)
        struct platform_device *pdev = to_platform_device(hsotg->dev);
        int ret;
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
-                                   hsotg->supplies);
-       if (ret)
-               return ret;
+       if (hsotg->num_supplies) {
+               ret = regulator_bulk_enable(hsotg->num_supplies,
+                                           hsotg->supplies);
+               if (ret)
+                       return ret;
+       }
 
        if (hsotg->clk) {
                ret = clk_prepare_enable(hsotg->clk);
@@ -186,8 +188,9 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg 
*hsotg)
        if (hsotg->clk)
                clk_disable_unprepare(hsotg->clk);
 
-       ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
-                                    hsotg->supplies);
+       if (hsotg->num_supplies)
+               ret = regulator_bulk_disable(hsotg->num_supplies,
+                                            hsotg->supplies);
 
        return ret;
 }
@@ -210,6 +213,7 @@ int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
 
 static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 {
+       struct regulator *reg;
        int i, ret;
 
        hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
@@ -290,16 +294,30 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev, "cannot get otg clock\n");
        }
 
-       /* Regulators */
-       for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
-               hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
+       /* Regulators, vast majority of dwc2 devices don't use them at all */
+       for (i = 0; i < DWC2_MAX_SUPPLIES; i++) {
+               reg = regulator_get_optional(hsotg->dev,
+                                            dwc2_hsotg_supply_names[i]);
+
+               /* All or nothing (bulk): regs either are or aren't present */
+               if (IS_ERR(reg)) {
+                       while (--i >= 0) {
+                               regulator_put(hsotg->supplies[i].consumer);
+                               hsotg->supplies[i].consumer = NULL;
+                               hsotg->supplies[i].supply = NULL;
+                               --hsotg->num_supplies;
+                       }
+                       break;
+               }
 
-       ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
-                                     hsotg->supplies);
-       if (ret) {
-               dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
-               return ret;
+               hsotg->supplies[i].consumer = reg;
+               hsotg->supplies[i].supply = dwc2_hsotg_supply_names[i];
+               ++hsotg->num_supplies;
        }
+
+       WARN_ON(hsotg->num_supplies &&
+               hsotg->num_supplies != DWC2_MAX_SUPPLIES);
+
        return 0;
 }
 
-- 
2.16.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to