/* * A simple GPIO VBUS sensing driver for B peripheral only devices * with internal transceivers. It can control a D+ pullup GPIO and * a regulator to limit the current drawn from VBUS. * * Needs to be loaded before the UDC driver that will use it.
*/ struct gpio_vbus_data { struct gpio_desc *vbus_gpiod; struct gpio_desc *pullup_gpiod; struct usb_phy phy; struct device *dev; struct regulator *vbus_draw; int vbus_draw_enabled; unsigned mA; struct delayed_work work; int vbus; int irq;
};
/* * This driver relies on "both edges" triggering. VBUS has 100 msec to * stabilize, so the peripheral controller driver may need to cope with * some bouncing due to current surges (e.g. charging local capacitance) * and contact chatter. * * REVISIT in desperate straits, toggling between rising and falling * edges might be workable.
*/ #define VBUS_IRQ_FLAGS \
(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
/* interface to regulator framework */ staticvoid set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
{ struct regulator *vbus_draw = gpio_vbus->vbus_draw; int enabled; int ret;
if (!vbus_draw) return;
enabled = gpio_vbus->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;
gpio_vbus->vbus_draw_enabled = 1;
}
} else { if (enabled) {
ret = regulator_disable(vbus_draw); if (ret < 0) return;
gpio_vbus->vbus_draw_enabled = 0;
}
}
gpio_vbus->mA = mA;
}
/* Peripheral controllers which manage the pullup themselves won't have * a pullup GPIO configured here. If it's configured here, we'll do * what isp1301_omap::b_peripheral() does and enable the pullup here... * although that may complicate usb_gadget_{,dis}connect() support.
*/
if (vbus) {
status = USB_EVENT_VBUS;
gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL;
gpio_vbus->phy.last_event = status;
usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
/* drawing a "unit load" is *always* OK, except for OTG */
set_vbus_draw(gpio_vbus, 100);
/* optionally enable D+ pullup */ if (gpio_vbus->pullup_gpiod)
gpiod_set_value(gpio_vbus->pullup_gpiod, 1);
/* draw max 0 mA from vbus in suspend mode; or the previously * recorded amount of current if not suspended * * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA * if they're wake-enabled ... we don't handle that yet.
*/ return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
}
/* * The VBUS sensing GPIO should have a pulldown, which will normally be * part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a * value the GPIO detects as active. Some systems will use comparators. * Get the optional D+ or D- pullup GPIO. If the data line pullup is * in use, initialize it to "not pulling up"
*/
gpio_vbus->pullup_gpiod = devm_gpiod_get_optional(dev, "pullup",
GPIOD_OUT_LOW); if (IS_ERR(gpio_vbus->pullup_gpiod)) {
err = PTR_ERR(gpio_vbus->pullup_gpiod);
dev_err(&pdev->dev, "can't request pullup gpio, err: %d\n",
err); return err;
} if (gpio_vbus->pullup_gpiod)
gpiod_set_consumer_name(gpio_vbus->pullup_gpiod, "udc_pullup");
gpio_vbus->vbus_draw = devm_regulator_get(&pdev->dev, "vbus_draw"); if (IS_ERR(gpio_vbus->vbus_draw)) {
dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
PTR_ERR(gpio_vbus->vbus_draw));
gpio_vbus->vbus_draw = NULL;
}
/* only active when a gadget is registered */
err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2); if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err); return err;
}
/* TODO: wakeup could be enabled here with device_init_wakeup(dev, 1) */
/* * NOTE: this driver matches against "gpio-usb-b-connector" for * devices that do NOT support role switch.
*/ staticconststruct of_device_id gpio_vbus_of_match[] = {
{
.compatible = "gpio-usb-b-connector",
},
{},
};
MODULE_DEVICE_TABLE(of, gpio_vbus_of_match);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.