This is an update to the AT91 USB Device (Gadget) driver.

Adds support for the Atmel AT91SAM9260 and AT91SAM9261 processors.  The
only difference is how they handle the pullup pin.
[Patch from Patrice Vilchez]

Need to clear any pending USB Device interrupts before registering the
interrupt handler.  The bootloader might have been using the USB Device
port.   [Patch from Peer Georgi]

VBUS detection is handled by a GPIO interrupt which only triggers on a
change. Is is therefore necessary to read the current VBUS state
explicitly at startup.  [Patch from Peer Georgi]


Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Andrew Victor 2006-12-07 22:44:38 -08:00 коммит произвёл Greg Kroah-Hartman
Родитель ffd3326bf6
Коммит 29ba4b533b
2 изменённых файлов: 42 добавлений и 6 удалений

Просмотреть файл

@ -51,6 +51,8 @@
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/cpu.h>
#include <asm/arch/at91sam9261_matrix.h>
#include "at91_udc.h" #include "at91_udc.h"
@ -909,11 +911,37 @@ static void pullup(struct at91_udc *udc, int is_on)
if (is_on) { if (is_on) {
clk_on(udc); clk_on(udc);
at91_udp_write(udc, AT91_UDP_TXVC, 0); 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 { } else {
stop_activity(udc); stop_activity(udc);
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); 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); clk_off(udc);
} }
} }
@ -1668,7 +1696,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
udc->fclk = clk_get(dev, "udpck"); udc->fclk = clk_get(dev, "udpck");
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
DBG("clocks missing\n"); DBG("clocks missing\n");
return -ENODEV; retval = -ENODEV;
goto fail0;
} }
retval = device_register(&udc->gadget.dev); retval = device_register(&udc->gadget.dev);
@ -1679,6 +1708,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
clk_enable(udc->iclk); clk_enable(udc->iclk);
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); 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); clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */ /* request UDC and maybe VBUS irqs */
@ -1690,6 +1721,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
goto fail1; goto fail1;
} }
if (udc->board.vbus_pin > 0) { 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, if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
IRQF_DISABLED, driver_name, udc)) { IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed\n", DBG("request vbus irq %d failed\n",

Просмотреть файл

@ -51,10 +51,10 @@
#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ #define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */
#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend 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_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_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt 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_ICR 0x20 /* Interrupt Clear Register */
#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint 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 0x74 /* Transceiver Control Register */
#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ #define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */
#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/