From 5d4c2707cf605fbf205b6d0a3c63d07204295f22 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Tue, 4 Mar 2008 15:48:37 +0100 Subject: [PATCH 1/6] atmel_usba: Kill copy_to_fifo() and copy_from_fifo() These functions do exactly the same as memcpy_toio() and memcpy_fromio() respectively. Signed-off-by: Haavard Skinnemoen Acked-by: David Brownell --- drivers/usb/gadget/atmel_usba_udc.c | 55 +++-------------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index af8b2a3a2d4a..33a797bf413f 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -324,53 +324,6 @@ static int vbus_is_present(struct usba_udc *udc) return 1; } -static void copy_to_fifo(void __iomem *fifo, const void *buf, int len) -{ - unsigned long tmp; - - DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len); - for (; len > 0; len -= 4, buf += 4, fifo += 4) { - tmp = *(unsigned long *)buf; - if (len >= 4) { - DBG(DBG_FIFO, " -> %08lx\n", tmp); - __raw_writel(tmp, fifo); - } else { - do { - DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24); - __raw_writeb(tmp >> 24, fifo); - fifo++; - tmp <<= 8; - } while (--len); - break; - } - } -} - -static void copy_from_fifo(void *buf, void __iomem *fifo, int len) -{ - union { - unsigned long *w; - unsigned char *b; - } p; - unsigned long tmp; - - DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len); - for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) { - if (len >= 4) { - tmp = __raw_readl(fifo); - *p.w = tmp; - DBG(DBG_FIFO, " -> %08lx\n", tmp); - } else { - do { - tmp = __raw_readb(fifo); - *p.b = tmp; - DBG(DBG_FIFO, " -> %02lx\n", tmp); - fifo++, p.b++; - } while (--len); - } - } -} - static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) { unsigned int transaction_len; @@ -387,7 +340,7 @@ static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) ep->ep.name, req, transaction_len, req->last_transaction ? ", done" : ""); - copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len); + memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); req->req.actual += transaction_len; } @@ -476,7 +429,7 @@ static void receive_data(struct usba_ep *ep) bytecount = req->req.length - req->req.actual; } - copy_from_fifo(req->req.buf + req->req.actual, + memcpy_fromio(req->req.buf + req->req.actual, ep->fifo, bytecount); req->req.actual += bytecount; @@ -1231,7 +1184,7 @@ static int do_test_mode(struct usba_udc *udc) } else { usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); usba_writel(udc, TST, USBA_TST_PKT_MODE); - copy_to_fifo(ep->fifo, test_packet_buffer, + memcpy_toio(ep->fifo, test_packet_buffer, sizeof(test_packet_buffer)); usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); dev_info(dev, "Entering Test_Packet mode...\n"); @@ -1536,7 +1489,7 @@ static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) } DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); - copy_from_fifo(crq.data, ep->fifo, sizeof(crq)); + memcpy_fromio(crq.data, ep->fifo, sizeof(crq)); /* Free up one bank in the FIFO so that we can * generate or receive a reply right away. */ From 7a242471af4d15c2637025f0acd352c0a92a4cc4 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Wed, 5 Mar 2008 22:59:15 +0100 Subject: [PATCH 2/6] atmel_usba_udc: Fix endpoint names. The endpoints of the atmel_usba_udc driver do not have directional (in/out) or usage (ctrl/bulk/iso) restrictions, as their names incorrectly implied. Signed-off-by: Stelian Pop Acked-by: David Brownell Signed-off-by: Haavard Skinnemoen --- drivers/usb/gadget/atmel_usba_udc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 33a797bf413f..d5a2c5162915 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -999,13 +999,13 @@ static const struct usb_gadget_ops usba_udc_ops = { } static struct usba_ep usba_ep[] = { - EP("ep0", 0, 64, 1, 0, 0), - EP("ep1in-bulk", 1, 512, 2, 1, 1), - EP("ep2out-bulk", 2, 512, 2, 1, 1), - EP("ep3in-int", 3, 64, 3, 1, 0), - EP("ep4out-int", 4, 64, 3, 1, 0), - EP("ep5in-iso", 5, 1024, 3, 1, 1), - EP("ep6out-iso", 6, 1024, 3, 1, 1), + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1", 1, 512, 2, 1, 1), + EP("ep2", 2, 512, 2, 1, 1), + EP("ep3-int", 3, 64, 3, 1, 0), + EP("ep4-int", 4, 64, 3, 1, 0), + EP("ep5", 5, 1024, 3, 1, 1), + EP("ep6", 6, 1024, 3, 1, 1), }; #undef EP From 8d12c32c19a2719f6a96a23e94d95699c47e55d0 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Wed, 5 Mar 2008 22:20:36 +0100 Subject: [PATCH 3/6] atmel_usba_udc: Kill GPIO_PIN_NONE GPIO_PIN_NONE should no longer be used. Replace it with a simple test against negative values. This is a transitional patch, waiting for gpio_is_valid() to be merged at which point the tests should be revisited. Signed-off-by: Stelian Pop Acked-by: David Brownell Signed-off-by: Haavard Skinnemoen --- drivers/usb/gadget/atmel_usba_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index d5a2c5162915..39d187fb038a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1937,7 +1937,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) goto err_device_add; } - if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) { + if (pdata && pdata->vbus_pin >= 0) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; From 8d855317fcf7fd9bd900d1e5ef1bea1b14bbe6af Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Wed, 5 Mar 2008 00:00:00 +0100 Subject: [PATCH 4/6] atmel_usba_udc: move endpoint declarations into platform data. The atmel_usba_udc driver is being used by several platforms and arches (avr32 and at91 ATM), and each platform may have different endpoint settings. The patch below moves the endpoint declarations into the platform data and make the necessary adjustments for AVR32 (improved by Haavard Skinnemoen ). Signed-off-by: Stelian Pop Acked-by: David Brownell Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/at32ap700x.c | 50 ++++++++++++++++--- drivers/usb/gadget/atmel_usba_udc.c | 71 ++++++++++++++------------- include/asm-avr32/arch-at32ap/board.h | 4 +- include/linux/usb/atmel_usba_udc.h | 22 +++++++++ 4 files changed, 105 insertions(+), 42 deletions(-) create mode 100644 include/linux/usb/atmel_usba_udc.h diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 7678fee9a885..cb47afc9fffc 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1351,9 +1352,39 @@ static struct clk usba0_hclk = { .index = 6, }; +#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ + [idx] = { \ + .name = nam, \ + .index = idx, \ + .fifo_size = maxpkt, \ + .nr_banks = maxbk, \ + .can_dma = dma, \ + .can_isoc = isoc, \ + } + +static struct usba_ep_data at32_usba_ep[] __initdata = { + EP("ep0", 0, 64, 1, 0, 0), + EP("ep1", 1, 512, 2, 1, 1), + EP("ep2", 2, 512, 2, 1, 1), + EP("ep3-int", 3, 64, 3, 1, 0), + EP("ep4-int", 4, 64, 3, 1, 0), + EP("ep5", 5, 1024, 3, 1, 1), + EP("ep6", 6, 1024, 3, 1, 1), +}; + +#undef EP + struct platform_device *__init at32_add_device_usba(unsigned int id, struct usba_platform_data *data) { + /* + * pdata doesn't have room for any endpoints, so we need to + * append room for the ones we need right after it. + */ + struct { + struct usba_platform_data pdata; + struct usba_ep_data ep[7]; + } usba_data; struct platform_device *pdev; if (id != 0) @@ -1367,13 +1398,20 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data) ARRAY_SIZE(usba0_resource))) goto out_free_pdev; - if (data) { - if (platform_device_add_data(pdev, data, sizeof(*data))) - goto out_free_pdev; + if (data) + usba_data.pdata.vbus_pin = data->vbus_pin; + else + usba_data.pdata.vbus_pin = -EINVAL; - if (data->vbus_pin != GPIO_PIN_NONE) - at32_select_gpio(data->vbus_pin, 0); - } + data = &usba_data.pdata; + data->num_ep = ARRAY_SIZE(at32_usba_ep); + memcpy(data->ep, at32_usba_ep, sizeof(at32_usba_ep)); + + if (platform_device_add_data(pdev, data, sizeof(usba_data))) + goto out_free_pdev; + + if (data->vbus_pin >= 0) + at32_select_gpio(data->vbus_pin, 0); usba0_pclk.dev = &pdev->dev; usba0_hclk.dev = &pdev->dev; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 39d187fb038a..71d3c5171f89 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ static struct usba_udc the_udc; +static struct usba_ep *usba_ep; #ifdef CONFIG_USB_GADGET_DEBUG_FS #include @@ -982,33 +984,6 @@ static const struct usb_gadget_ops usba_udc_ops = { .set_selfpowered = usba_udc_set_selfpowered, }; -#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \ -{ \ - .ep = { \ - .ops = &usba_ep_ops, \ - .name = nam, \ - .maxpacket = maxpkt, \ - }, \ - .udc = &the_udc, \ - .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \ - .fifo_size = maxpkt, \ - .nr_banks = maxbk, \ - .index = idx, \ - .can_dma = dma, \ - .can_isoc = isoc, \ -} - -static struct usba_ep usba_ep[] = { - EP("ep0", 0, 64, 1, 0, 0), - EP("ep1", 1, 512, 2, 1, 1), - EP("ep2", 2, 512, 2, 1, 1), - EP("ep3-int", 3, 64, 3, 1, 0), - EP("ep4-int", 4, 64, 3, 1, 0), - EP("ep5", 5, 1024, 3, 1, 1), - EP("ep6", 6, 1024, 3, 1, 1), -}; -#undef EP - static struct usb_endpoint_descriptor usba_ep0_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -1027,7 +1002,6 @@ static void nop_release(struct device *dev) static struct usba_udc the_udc = { .gadget = { .ops = &usba_udc_ops, - .ep0 = &usba_ep[0].ep, .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), .is_dualspeed = 1, .name = "atmel_usba_udc", @@ -1861,7 +1835,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); - if (!regs || !fifo) + if (!regs || !fifo || !pdata) return -ENXIO; irq = platform_get_irq(pdev, 0); @@ -1909,16 +1883,44 @@ static int __init usba_udc_probe(struct platform_device *pdev) usba_writel(udc, CTRL, 0); clk_disable(pclk); + usba_ep = kmalloc(sizeof(struct usba_ep) * pdata->num_ep, + GFP_KERNEL); + if (!usba_ep) + goto err_alloc_ep; + + the_udc.gadget.ep0 = &usba_ep[0].ep; + INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) { + usba_ep[0].ep.ops = &usba_ep_ops; + usba_ep[0].ep.name = pdata->ep[0].name; + usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size; + usba_ep[0].udc = &the_udc; + INIT_LIST_HEAD(&usba_ep[0].queue); + usba_ep[0].fifo_size = pdata->ep[0].fifo_size; + usba_ep[0].nr_banks = pdata->ep[0].nr_banks; + usba_ep[0].index = pdata->ep[0].index; + usba_ep[0].can_dma = pdata->ep[0].can_dma; + usba_ep[0].can_isoc = pdata->ep[0].can_isoc; + + for (i = 1; i < pdata->num_ep; i++) { struct usba_ep *ep = &usba_ep[i]; ep->ep_regs = udc->regs + USBA_EPT_BASE(i); ep->dma_regs = udc->regs + USBA_DMA_BASE(i); ep->fifo = udc->fifo + USBA_FIFO_BASE(i); + ep->ep.ops = &usba_ep_ops; + ep->ep.name = pdata->ep[i].name; + ep->ep.maxpacket = pdata->ep[i].fifo_size; + ep->udc = &the_udc; + INIT_LIST_HEAD(&ep->queue); + ep->fifo_size = pdata->ep[i].fifo_size; + ep->nr_banks = pdata->ep[i].nr_banks; + ep->index = pdata->ep[i].index; + ep->can_dma = pdata->ep[i].can_dma; + ep->can_isoc = pdata->ep[i].can_isoc; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } @@ -1937,7 +1939,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) goto err_device_add; } - if (pdata && pdata->vbus_pin >= 0) { + if (pdata->vbus_pin >= 0) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; @@ -1957,7 +1959,7 @@ static int __init usba_udc_probe(struct platform_device *pdev) } usba_init_debugfs(udc); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + for (i = 1; i < pdata->num_ep; i++) usba_ep_init_debugfs(udc, &usba_ep[i]); return 0; @@ -1965,6 +1967,8 @@ static int __init usba_udc_probe(struct platform_device *pdev) err_device_add: free_irq(irq, udc); err_request_irq: + kfree(usba_ep); +err_alloc_ep: iounmap(udc->fifo); err_map_fifo: iounmap(udc->regs); @@ -1982,10 +1986,11 @@ static int __exit usba_udc_remove(struct platform_device *pdev) { struct usba_udc *udc; int i; + struct usba_platform_data *pdata = pdev->dev.platform_data; udc = platform_get_drvdata(pdev); - for (i = 1; i < ARRAY_SIZE(usba_ep); i++) + for (i = 1; i < pdata->num_ep; i++) usba_ep_cleanup_debugfs(&usba_ep[i]); usba_cleanup_debugfs(udc); diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 7597b0bd2f01..3fea2004f7db 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -38,9 +38,7 @@ struct platform_device * at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, unsigned long fbmem_start, unsigned long fbmem_len); -struct usba_platform_data { - int vbus_pin; -}; +struct usba_platform_data; struct platform_device * at32_add_device_usba(unsigned int id, struct usba_platform_data *data); diff --git a/include/linux/usb/atmel_usba_udc.h b/include/linux/usb/atmel_usba_udc.h new file mode 100644 index 000000000000..6311fa2d9f82 --- /dev/null +++ b/include/linux/usb/atmel_usba_udc.h @@ -0,0 +1,22 @@ +/* + * Platform data definitions for Atmel USBA gadget driver. + */ +#ifndef __LINUX_USB_USBA_H +#define __LINUX_USB_USBA_H + +struct usba_ep_data { + char *name; + int index; + int fifo_size; + int nr_banks; + int can_dma; + int can_isoc; +}; + +struct usba_platform_data { + int vbus_pin; + int num_ep; + struct usba_ep_data ep[0]; +}; + +#endif /* __LINUX_USB_USBA_H */ From 5275653fa12b30cea6e309cc03e518bfd00073a5 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Thu, 3 Apr 2008 14:51:41 +0200 Subject: [PATCH 5/6] atmel_usba_udc: Add missing kfree() in usba_udc_remove() Signed-off-by: Stelian Pop Signed-off-by: Haavard Skinnemoen --- drivers/usb/gadget/atmel_usba_udc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 71d3c5171f89..ddb7301a0138 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1998,6 +1998,7 @@ static int __exit usba_udc_remove(struct platform_device *pdev) gpio_free(udc->vbus_pin); free_irq(udc->irq, udc); + kfree(usba_ep); iounmap(udc->fifo); iounmap(udc->regs); clk_put(udc->hclk); From 16a45bc82e61891daec1ffcd057679bdf962aeb8 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Sat, 5 Apr 2008 22:25:47 +0200 Subject: [PATCH 6/6] 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 Acked-by: Andrew Victor Acked-by: David Brownell Signed-off-by: Haavard Skinnemoen --- drivers/usb/gadget/Kconfig | 4 +-- drivers/usb/gadget/atmel_usba_udc.c | 41 ++++++++++++++++++++++++----- drivers/usb/gadget/atmel_usba_udc.h | 9 +++++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 6f45dd669b33..d681bb27fa58 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -118,10 +118,10 @@ config USB_AMD5536UDC config USB_GADGET_ATMEL_USBA boolean "Atmel USBA" select USB_GADGET_DUALSPEED - depends on AVR32 + depends on AVR32 || ARCH_AT91CAP9 help USBA is the integrated high-speed USB Device controller on - the AT32AP700x processors from Atmel. + the AT32AP700x and AT91CAP9 processors from Atmel. config USB_ATMEL_USBA tristate 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 + +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 @@ static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) 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, diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 08bf6f9aaf7e..f7baea307f0d 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -41,6 +41,15 @@ #define USBA_EN_USBA (1 << 8) #define USBA_DETACH (1 << 9) #define USBA_REMOTE_WAKE_UP (1 << 10) +#define USBA_PULLD_DIS (1 << 11) + +#if defined(CONFIG_AVR32) +#define USBA_ENABLE_MASK USBA_EN_USBA +#define USBA_DISABLE_MASK 0 +#elif defined(CONFIG_ARCH_AT91) +#define USBA_ENABLE_MASK (USBA_EN_USBA | USBA_PULLD_DIS) +#define USBA_DISABLE_MASK USBA_DETACH +#endif /* CONFIG_ARCH_AT91 */ /* Bitfields in FNUM */ #define USBA_MICRO_FRAME_NUM_OFFSET 0