1

usb: phy: generic: Implement otg->set_vbus

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>
This commit is contained in:
Sean Anderson 2024-01-23 17:51:10 -05:00 committed by Greg Kroah-Hartman
parent 75fd6485cc
commit 562898808c

View 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;
}