diff options
author | Andrew Victor <andrew@sanpeople.com> | 2006-12-08 01:44:38 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-20 13:14:27 -0500 |
commit | 29ba4b533b677f3cd7f2fc901d51054555a8f243 (patch) | |
tree | 159f814dcf4b500cd0dca369bd39af9cfdcec266 /drivers/usb/gadget/at91_udc.c | |
parent | ffd3326bf6282b9f606e92ae57e8f47f2e10e6b5 (diff) |
USB: at91_udc, misc fixes
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>
Diffstat (limited to 'drivers/usb/gadget/at91_udc.c')
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index b53b93700ca8..c8954a6ddf8c 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c | |||
@@ -51,6 +51,8 @@ | |||
51 | 51 | ||
52 | #include <asm/arch/gpio.h> | 52 | #include <asm/arch/gpio.h> |
53 | #include <asm/arch/board.h> | 53 | #include <asm/arch/board.h> |
54 | #include <asm/arch/cpu.h> | ||
55 | #include <asm/arch/at91sam9261_matrix.h> | ||
54 | 56 | ||
55 | #include "at91_udc.h" | 57 | #include "at91_udc.h" |
56 | 58 | ||
@@ -909,11 +911,37 @@ static void pullup(struct at91_udc *udc, int is_on) | |||
909 | if (is_on) { | 911 | if (is_on) { |
910 | clk_on(udc); | 912 | clk_on(udc); |
911 | at91_udp_write(udc, AT91_UDP_TXVC, 0); | 913 | at91_udp_write(udc, AT91_UDP_TXVC, 0); |
912 | at91_set_gpio_value(udc->board.pullup_pin, 1); | 914 | if (cpu_is_at91rm9200()) |
915 | at91_set_gpio_value(udc->board.pullup_pin, 1); | ||
916 | else if (cpu_is_at91sam9260()) { | ||
917 | u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); | ||
918 | |||
919 | txvc |= AT91_UDP_TXVC_PUON; | ||
920 | at91_udp_write(udc, AT91_UDP_TXVC, txvc); | ||
921 | } else if (cpu_is_at91sam9261()) { | ||
922 | u32 usbpucr; | ||
923 | |||
924 | usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); | ||
925 | usbpucr |= AT91_MATRIX_USBPUCR_PUON; | ||
926 | at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); | ||
927 | } | ||
913 | } else { | 928 | } else { |
914 | stop_activity(udc); | 929 | stop_activity(udc); |
915 | at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); | 930 | at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); |
916 | at91_set_gpio_value(udc->board.pullup_pin, 0); | 931 | if (cpu_is_at91rm9200()) |
932 | at91_set_gpio_value(udc->board.pullup_pin, 0); | ||
933 | else if (cpu_is_at91sam9260()) { | ||
934 | u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); | ||
935 | |||
936 | txvc &= ~AT91_UDP_TXVC_PUON; | ||
937 | at91_udp_write(udc, AT91_UDP_TXVC, txvc); | ||
938 | } else if (cpu_is_at91sam9261()) { | ||
939 | u32 usbpucr; | ||
940 | |||
941 | usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); | ||
942 | usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; | ||
943 | at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); | ||
944 | } | ||
917 | clk_off(udc); | 945 | clk_off(udc); |
918 | } | 946 | } |
919 | } | 947 | } |
@@ -1668,7 +1696,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) | |||
1668 | udc->fclk = clk_get(dev, "udpck"); | 1696 | udc->fclk = clk_get(dev, "udpck"); |
1669 | if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { | 1697 | if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { |
1670 | DBG("clocks missing\n"); | 1698 | DBG("clocks missing\n"); |
1671 | return -ENODEV; | 1699 | retval = -ENODEV; |
1700 | goto fail0; | ||
1672 | } | 1701 | } |
1673 | 1702 | ||
1674 | retval = device_register(&udc->gadget.dev); | 1703 | retval = device_register(&udc->gadget.dev); |
@@ -1679,6 +1708,8 @@ static int __devinit at91udc_probe(struct platform_device *pdev) | |||
1679 | clk_enable(udc->iclk); | 1708 | clk_enable(udc->iclk); |
1680 | at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); | 1709 | at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); |
1681 | at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); | 1710 | at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); |
1711 | /* Clear all pending interrupts - UDP may be used by bootloader. */ | ||
1712 | at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); | ||
1682 | clk_disable(udc->iclk); | 1713 | clk_disable(udc->iclk); |
1683 | 1714 | ||
1684 | /* request UDC and maybe VBUS irqs */ | 1715 | /* request UDC and maybe VBUS irqs */ |
@@ -1690,6 +1721,11 @@ static int __devinit at91udc_probe(struct platform_device *pdev) | |||
1690 | goto fail1; | 1721 | goto fail1; |
1691 | } | 1722 | } |
1692 | if (udc->board.vbus_pin > 0) { | 1723 | if (udc->board.vbus_pin > 0) { |
1724 | /* | ||
1725 | * Get the initial state of VBUS - we cannot expect | ||
1726 | * a pending interrupt. | ||
1727 | */ | ||
1728 | udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); | ||
1693 | if (request_irq(udc->board.vbus_pin, at91_vbus_irq, | 1729 | if (request_irq(udc->board.vbus_pin, at91_vbus_irq, |
1694 | IRQF_DISABLED, driver_name, udc)) { | 1730 | IRQF_DISABLED, driver_name, udc)) { |
1695 | DBG("request vbus irq %d failed\n", | 1731 | DBG("request vbus irq %d failed\n", |