usb: phy: generic: Implement otg->set_vbus
authorSean Anderson <sean.anderson@seco.com>
Tue, 23 Jan 2024 22:51:10 +0000 (17:51 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 28 Jan 2024 01:37:22 +0000 (17:37 -0800)
Some USB controller drivers call otg_set_vbus when entering host or
device mode. Implement this callback so that VBUS can be turned on and
off automatically. This is especially useful when there is no property
for a VBUS supply in the controller's binding.

This results in a change in semantics of the vbus_draw regulator.
Whereas before it represented the VBUS supplied by an A-Device when we
acted as a B-Device, now it represents an internal VBUS source.
Accordingly, we no longer set the current limit or enable/disable the
bus from nop_gpio_vbus_thread. Because this supply was never initialized
before the previous commit, there should be no change in behavior.

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
Link: https://lore.kernel.org/r/20240123225111.1629405-4-sean.anderson@seco.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/phy/phy-generic.c

index 16494030209eae584a517e77dade1a2aacb6d5fa..f7db24b5ed5c0bab85ae31e19e2811a8f9f8960d 100644 (file)
@@ -74,33 +74,26 @@ static void nop_reset(struct usb_phy_generic *nop)
 }
 
 /* interface to regulator framework */
-static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
+static int nop_set_vbus(struct usb_otg *otg, bool enable)
 {
-       struct regulator *vbus_draw = nop->vbus_draw;
-       int enabled;
-       int ret;
+       int ret = 0;
+       struct usb_phy_generic *nop = dev_get_drvdata(otg->usb_phy->dev);
 
-       if (!vbus_draw)
-               return;
+       if (!nop->vbus_draw)
+               return 0;
 
-       enabled = nop->vbus_draw_enabled;
-       if (mA) {
-               regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
-               if (!enabled) {
-                       ret = regulator_enable(vbus_draw);
-                       if (ret < 0)
-                               return;
-                       nop->vbus_draw_enabled = 1;
-               }
-       } else {
-               if (enabled) {
-                       ret = regulator_disable(vbus_draw);
-                       if (ret < 0)
-                               return;
-                       nop->vbus_draw_enabled = 0;
-               }
+       if (enable && !nop->vbus_draw_enabled) {
+               ret = regulator_enable(nop->vbus_draw);
+               if (ret)
+                       nop->vbus_draw_enabled = false;
+               else
+                       nop->vbus_draw_enabled = true;
+
+       } else if (!enable && nop->vbus_draw_enabled) {
+               ret = regulator_disable(nop->vbus_draw);
+               nop->vbus_draw_enabled = false;
        }
-       nop->mA = mA;
+       return ret;
 }
 
 
@@ -120,14 +113,9 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
                otg->state = OTG_STATE_B_PERIPHERAL;
                nop->phy.last_event = status;
 
-               /* drawing a "unit load" is *always* OK, except for OTG */
-               nop_set_vbus_draw(nop, 100);
-
                atomic_notifier_call_chain(&nop->phy.notifier, status,
                                           otg->gadget);
        } else {
-               nop_set_vbus_draw(nop, 0);
-
                status = USB_EVENT_NONE;
                otg->state = OTG_STATE_B_IDLE;
                nop->phy.last_event = status;
@@ -291,6 +279,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
        nop->phy.otg->usb_phy           = &nop->phy;
        nop->phy.otg->set_host          = nop_set_host;
        nop->phy.otg->set_peripheral    = nop_set_peripheral;
+       nop->phy.otg->set_vbus          = nop_set_vbus;
 
        return 0;
 }