diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index b53b93700ca874268f8b5c3311f0efbe4ade7cef..c8954a6ddf8c45a47979703a14c219c1034a679f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -51,6 +51,8 @@ #include #include +#include +#include #include "at91_udc.h" @@ -909,11 +911,37 @@ static void pullup(struct at91_udc *udc, int is_on) if (is_on) { clk_on(udc); at91_udp_write(udc, AT91_UDP_TXVC, 0); - at91_set_gpio_value(udc->board.pullup_pin, 1); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 1); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc |= AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr |= AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } } else { stop_activity(udc); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_set_gpio_value(udc->board.pullup_pin, 0); + if (cpu_is_at91rm9200()) + at91_set_gpio_value(udc->board.pullup_pin, 0); + else if (cpu_is_at91sam9260()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc &= ~AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261()) { + u32 usbpucr; + + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } clk_off(udc); } } @@ -1668,7 +1696,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) udc->fclk = clk_get(dev, "udpck"); if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG("clocks missing\n"); - return -ENODEV; + retval = -ENODEV; + goto fail0; } retval = device_register(&udc->gadget.dev); @@ -1679,6 +1708,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) clk_enable(udc->iclk); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); + /* Clear all pending interrupts - UDP may be used by bootloader. */ + at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); clk_disable(udc->iclk); /* request UDC and maybe VBUS irqs */ @@ -1690,6 +1721,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev) goto fail1; } if (udc->board.vbus_pin > 0) { + /* + * Get the initial state of VBUS - we cannot expect + * a pending interrupt. + */ + udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); if (request_irq(udc->board.vbus_pin, at91_vbus_irq, IRQF_DISABLED, driver_name, udc)) { DBG("request vbus irq %d failed\n", diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index a35f3b627d3c0efb221bc2f6f17bcb02f1a6bf1a..677089baa59dd8bcacfc71fa801a18e91e42fda1 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -51,10 +51,10 @@ #define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ #define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ #define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ -#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ #define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ -#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ #define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ #define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ @@ -84,7 +84,7 @@ #define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ #define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ - +#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */ /*-------------------------------------------------------------------------*/