diff options
author | Stelian Pop <stelian@popies.net> | 2008-04-05 22:25:47 +0200 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-04-06 17:25:06 -0400 |
commit | 16a45bc82e61891daec1ffcd057679bdf962aeb8 (patch) | |
tree | 9b7527cbe92525a56361ad64be1c2d960b2d6021 /drivers/usb/gadget/atmel_usba_udc.c | |
parent | 5275653fa12b30cea6e309cc03e518bfd00073a5 (diff) |
atmel_usba_udc: Add support for AT91CAP9 UDPHS
This patch is part of the series adding support for the USB High
Speed Device Port on the AT91CAP9 system on chip. The AT91CAP9
uses the same UDPHS IP as the AVR32 and the AT91SAM9RL.
The only differences between the AVR32 and the AT91 version of the
device are in the enable/disable and suspend/wakeup sequences: the
AT91 version needs to toggle the USB bias and pulldown explicitly.
Signed-off-by: Stelian Pop <stelian@popies.net>
Acked-by: Andrew Victor <linux@maxim.org.za>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Diffstat (limited to 'drivers/usb/gadget/atmel_usba_udc.c')
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index ddb7301a0138..c9a3c2a462c4 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,6 +326,28 @@ static int vbus_is_present(struct usba_udc *udc) return 1; } +#if defined(CONFIG_AVR32) + +static void toggle_bias(int is_on) +{ +} + +#elif defined(CONFIG_ARCH_AT91) + +#include <asm/arch/at91_pmc.h> + +static void toggle_bias(int is_on) +{ + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (is_on) + at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); + else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); +} + +#endif /* CONFIG_ARCH_AT91 */ + static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) { unsigned int transaction_len; @@ -1457,7 +1479,7 @@ restart: DBG(DBG_HW, "Packet length: %u\n", pkt_len); if (pkt_len != sizeof(crq)) { pr_warning("udc: Invalid packet length %u " - "(expected %lu)\n", pkt_len, sizeof(crq)); + "(expected %zu)\n", pkt_len, sizeof(crq)); set_protocol_stall(udc, ep); return; } @@ -1615,6 +1637,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) DBG(DBG_INT, "irq, status=%#08x\n", status); if (status & USBA_DET_SUSPEND) { + toggle_bias(0); usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); DBG(DBG_BUS, "Suspend detected\n"); if (udc->gadget.speed != USB_SPEED_UNKNOWN @@ -1626,6 +1649,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) } if (status & USBA_WAKE_UP) { + toggle_bias(1); usba_writel(udc, INT_CLR, USBA_WAKE_UP); DBG(DBG_BUS, "Wake Up CPU detected\n"); } @@ -1719,12 +1743,14 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid) vbus = gpio_get_value(udc->vbus_pin); if (vbus != udc->vbus_prev) { if (vbus) { - usba_writel(udc, CTRL, USBA_EN_USBA); + toggle_bias(1); + usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } else { udc->gadget.speed = USB_SPEED_UNKNOWN; reset_all_endpoints(udc); - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); spin_lock(&udc->lock); @@ -1777,7 +1803,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) /* If Vbus is present, enable the controller and wait for reset */ spin_lock_irqsave(&udc->lock, flags); if (vbus_is_present(udc) && udc->vbus_prev == 0) { - usba_writel(udc, CTRL, USBA_EN_USBA); + toggle_bias(1); + usba_writel(udc, CTRL, USBA_ENABLE_MASK); usba_writel(udc, INT_ENB, USBA_END_OF_RESET); } spin_unlock_irqrestore(&udc->lock, flags); @@ -1810,7 +1837,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&udc->lock, flags); /* This will also disable the DP pullup */ - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; @@ -1880,7 +1908,8 @@ static int __init usba_udc_probe(struct platform_device *pdev) /* Make sure we start from a clean slate */ clk_enable(pclk); - usba_writel(udc, CTRL, 0); + toggle_bias(0); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); clk_disable(pclk); usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep, |