static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = container_of(work, struct gpio_vbus_data, work.work); struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev); int gpio, status, vbus; if (!gpio_vbus->phy.otg->gadget) return; vbus = is_vbus_powered(pdata); if ((vbus ^ gpio_vbus->vbus) == 0) return; gpio_vbus->vbus = vbus; /* Peripheral controllers which manage the pullup themselves won't have * gpio_pullup 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. */ gpio = pdata->gpio_pullup; 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_is_valid(gpio)) gpio_set_value(gpio, !pdata->gpio_pullup_inverted); atomic_notifier_call_chain(&gpio_vbus->phy.notifier, status, gpio_vbus->phy.otg->gadget); } else { /* optionally disable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, pdata->gpio_pullup_inverted); set_vbus_draw(gpio_vbus, 0); usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget); status = USB_EVENT_NONE; gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE; gpio_vbus->phy.last_event = status; atomic_notifier_call_chain(&gpio_vbus->phy.notifier, status, gpio_vbus->phy.otg->gadget); } }
/* VBUS change IRQ handler */ static irqreturn_t gpio_vbus_irq(int irq, void *data) { struct platform_device *pdev = data; struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); int gpio, vbus; vbus = gpio_get_value(pdata->gpio_vbus); if (pdata->gpio_vbus_inverted) vbus = !vbus; dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", vbus ? "supplied" : "inactive", gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none"); if (!gpio_vbus->otg.gadget) return IRQ_HANDLED; /* Peripheral controllers which manage the pullup themselves won't have * gpio_pullup 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. */ gpio = pdata->gpio_pullup; if (vbus) { gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL; usb_gadget_vbus_connect(gpio_vbus->otg.gadget); /* drawing a "unit load" is *always* OK, except for OTG */ set_vbus_draw(gpio_vbus, 100); /* optionally enable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, !pdata->gpio_pullup_inverted); } else { /* optionally disable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, pdata->gpio_pullup_inverted); set_vbus_draw(gpio_vbus, 0); usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget); gpio_vbus->otg.state = OTG_STATE_B_IDLE; } return IRQ_HANDLED; }
/* effective for B devices, ignored for A-peripheral */ static int gpio_vbus_set_power(struct otg_transceiver *otg, unsigned mA) { struct gpio_vbus_data *gpio_vbus; gpio_vbus = container_of(otg, struct gpio_vbus_data, otg); if (otg->state == OTG_STATE_B_PERIPHERAL) set_vbus_draw(gpio_vbus, mA); return 0; }
/* effective for B devices, ignored for A-peripheral */ static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA) { struct gpio_vbus_data *gpio_vbus; gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); if (phy->state == OTG_STATE_B_PERIPHERAL) set_vbus_draw(gpio_vbus, mA); return 0; }
static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = container_of(work, struct gpio_vbus_data, work); struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; int gpio; if (!gpio_vbus->otg.gadget) return; /* Peripheral controllers which manage the pullup themselves won't have * gpio_pullup 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. */ gpio = pdata->gpio_pullup; if (is_vbus_powered(pdata)) { gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL; usb_gadget_vbus_connect(gpio_vbus->otg.gadget); /* drawing a "unit load" is *always* OK, except for OTG */ set_vbus_draw(gpio_vbus, 100); /* optionally enable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, !pdata->gpio_pullup_inverted); } else { /* optionally disable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, pdata->gpio_pullup_inverted); set_vbus_draw(gpio_vbus, 0); usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget); gpio_vbus->otg.state = OTG_STATE_B_IDLE; } }
/* bind/unbind the peripheral controller */ static int gpio_vbus_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget) { struct gpio_vbus_data *gpio_vbus; struct gpio_vbus_mach_info *pdata; struct platform_device *pdev; int gpio, irq; gpio_vbus = container_of(otg, struct gpio_vbus_data, otg); pdev = to_platform_device(gpio_vbus->dev); pdata = gpio_vbus->dev->platform_data; irq = gpio_to_irq(pdata->gpio_vbus); gpio = pdata->gpio_pullup; if (!gadget) { dev_dbg(&pdev->dev, "unregistering gadget '%s'\n", otg->gadget->name); /* optionally disable D+ pullup */ if (gpio_is_valid(gpio)) gpio_set_value(gpio, pdata->gpio_pullup_inverted); set_vbus_draw(gpio_vbus, 0); usb_gadget_vbus_disconnect(otg->gadget); otg->state = OTG_STATE_UNDEFINED; otg->gadget = NULL; return 0; } otg->gadget = gadget; dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); /* initialize connection state */ gpio_vbus_irq(irq, pdev); return 0; }