Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: pxa2xx_udc understands GPIO based VBUS sensing

This updates the PXA 25x UDC board-independent infrastructure for VBUS sensing
and the D+ pullup. The original code evolved from rather bizarre support on
Intel's "Lubbock" reference hardware, so that on more sensible hardware it
doesn't work as well as it could/should.

The change is just to teach the UDC driver how to use built-in PXA GPIO pins
directly. This reduces the amount of board-specfic object code needed, and
enables the use of a VBUS sensing IRQ on boards (like Gumstix) that have one.
With VBUS sensing, the UDC is unclocked until a host is actually connected.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

David Brownell and committed by
Greg Kroah-Hartman
b2bbb20b 3a16f7b4

+85 -32
+1 -14
arch/arm/mach-pxa/corgi.c
··· 284 284 /* 285 285 * USB Device Controller 286 286 */ 287 - static void corgi_udc_command(int cmd) 288 - { 289 - switch(cmd) { 290 - case PXA2XX_UDC_CMD_CONNECT: 291 - GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP); 292 - break; 293 - case PXA2XX_UDC_CMD_DISCONNECT: 294 - GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP); 295 - break; 296 - } 297 - } 298 - 299 287 static struct pxa2xx_udc_mach_info udc_info __initdata = { 300 288 /* no connect GPIO; corgi can't tell connection status */ 301 - .udc_command = corgi_udc_command, 289 + .gpio_pullup = CORGI_GPIO_USB_PULLUP, 302 290 }; 303 291 304 292 ··· 338 350 corgi_ssp_set_machinfo(&corgi_ssp_machinfo); 339 351 340 352 pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT); 341 - pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT); 342 353 pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN); 343 354 344 355 pxa_set_udc_info(&udc_info);
+68 -2
drivers/usb/gadget/pxa2xx_udc.c
··· 150 150 static void pxa2xx_ep_fifo_flush (struct usb_ep *ep); 151 151 static void nuke (struct pxa2xx_ep *, int status); 152 152 153 + /* one GPIO should be used to detect VBUS from the host */ 154 + static int is_vbus_present(void) 155 + { 156 + struct pxa2xx_udc_mach_info *mach = the_controller->mach; 157 + 158 + if (mach->gpio_vbus) 159 + return pxa_gpio_get(mach->gpio_vbus); 160 + if (mach->udc_is_connected) 161 + return mach->udc_is_connected(); 162 + return 1; 163 + } 164 + 165 + /* one GPIO should control a D+ pullup, so host sees this device (or not) */ 166 + static void pullup_off(void) 167 + { 168 + struct pxa2xx_udc_mach_info *mach = the_controller->mach; 169 + 170 + if (mach->gpio_pullup) 171 + pxa_gpio_set(mach->gpio_pullup, 0); 172 + else if (mach->udc_command) 173 + mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); 174 + } 175 + 176 + static void pullup_on(void) 177 + { 178 + struct pxa2xx_udc_mach_info *mach = the_controller->mach; 179 + 180 + if (mach->gpio_pullup) 181 + pxa_gpio_set(mach->gpio_pullup, 1); 182 + else if (mach->udc_command) 183 + mach->udc_command(PXA2XX_UDC_CMD_CONNECT); 184 + } 185 + 153 186 static void pio_irq_enable(int bEndpointAddress) 154 187 { 155 188 bEndpointAddress &= 0xf; ··· 1754 1721 1755 1722 #endif 1756 1723 1724 + static irqreturn_t 1725 + udc_vbus_irq(int irq, void *_dev, struct pt_regs *r) 1726 + { 1727 + struct pxa2xx_udc *dev = _dev; 1728 + int vbus = pxa_gpio_get(dev->mach->gpio_vbus); 1729 + 1730 + pxa2xx_udc_vbus_session(&dev->gadget, vbus); 1731 + return IRQ_HANDLED; 1732 + } 1733 + 1757 1734 1758 1735 /*-------------------------------------------------------------------------*/ 1759 1736 ··· 2481 2438 static int __init pxa2xx_udc_probe(struct platform_device *pdev) 2482 2439 { 2483 2440 struct pxa2xx_udc *dev = &memory; 2484 - int retval, out_dma = 1; 2441 + int retval, out_dma = 1, vbus_irq; 2485 2442 u32 chiprev; 2486 2443 2487 2444 /* insist on Intel/ARM/XScale */ ··· 2545 2502 /* other non-static parts of init */ 2546 2503 dev->dev = &pdev->dev; 2547 2504 dev->mach = pdev->dev.platform_data; 2505 + if (dev->mach->gpio_vbus) { 2506 + vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR); 2507 + pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR) 2508 + | GPIO_IN); 2509 + set_irq_type(vbus_irq, IRQT_BOTHEDGE); 2510 + } else 2511 + vbus_irq = 0; 2512 + if (dev->mach->gpio_pullup) 2513 + pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR) 2514 + | GPIO_OUT | GPIO_DFLT_LOW); 2548 2515 2549 2516 init_timer(&dev->timer); 2550 2517 dev->timer.function = udc_watchdog; ··· 2610 2557 HEX_DISPLAY(dev->stats.irqs); 2611 2558 LUB_DISC_BLNK_LED &= 0xff; 2612 2559 #endif 2613 - } 2560 + } else 2614 2561 #endif 2562 + if (vbus_irq) { 2563 + retval = request_irq(vbus_irq, udc_vbus_irq, 2564 + SA_INTERRUPT | SA_SAMPLE_RANDOM, 2565 + driver_name, dev); 2566 + if (retval != 0) { 2567 + printk(KERN_ERR "%s: can't get irq %i, err %d\n", 2568 + driver_name, vbus_irq, retval); 2569 + free_irq(IRQ_USB, dev); 2570 + return -EBUSY; 2571 + } 2572 + } 2615 2573 create_proc_files(); 2616 2574 2617 2575 return 0; ··· 2651 2587 free_irq(LUBBOCK_USB_IRQ, dev); 2652 2588 } 2653 2589 #endif 2590 + if (dev->mach->gpio_vbus) 2591 + free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev); 2654 2592 platform_set_drvdata(pdev, NULL); 2655 2593 the_controller = NULL; 2656 2594 return 0;
+8 -16
drivers/usb/gadget/pxa2xx_udc.h
··· 177 177 178 178 static struct pxa2xx_udc *the_controller; 179 179 180 - /* one GPIO should be used to detect VBUS from the host */ 181 - static inline int is_vbus_present(void) 180 + static inline int pxa_gpio_get(unsigned gpio) 182 181 { 183 - if (!the_controller->mach->udc_is_connected) 184 - return 1; 185 - return the_controller->mach->udc_is_connected(); 182 + return (GPLR(gpio) & GPIO_bit(gpio)) != 0; 186 183 } 187 184 188 - /* one GPIO should control a D+ pullup, so host sees this device (or not) */ 189 - static inline void pullup_off(void) 185 + static inline void pxa_gpio_set(unsigned gpio, int is_on) 190 186 { 191 - if (!the_controller->mach->udc_command) 192 - return; 193 - the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); 194 - } 187 + int mask = GPIO_bit(gpio); 195 188 196 - static inline void pullup_on(void) 197 - { 198 - if (!the_controller->mach->udc_command) 199 - return; 200 - the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); 189 + if (is_on) 190 + GPSR(gpio) = mask; 191 + else 192 + GPCR(gpio) = mask; 201 193 } 202 194 203 195 /*-------------------------------------------------------------------------*/
+8
include/asm-arm/arch-pxa/udc.h
··· 12 12 void (*udc_command)(int cmd); 13 13 #define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */ 14 14 #define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */ 15 + 16 + /* Boards following the design guidelines in the developer's manual, 17 + * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane 18 + * VBUS IRQ and omit the methods above. Store the GPIO number 19 + * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits. 20 + */ 21 + u16 gpio_vbus; /* high == vbus present */ 22 + u16 gpio_pullup; /* high == pullup activated */ 15 23 }; 16 24 17 25 extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);