summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/Kconfig12
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/at91_udc.c1538
-rw-r--r--drivers/usb/gadget/at91_udc.h168
-rw-r--r--drivers/usb/gadget/dfu.c9
-rw-r--r--drivers/usb/gadget/f_acm.c4
-rw-r--r--drivers/usb/gadget/fsl_udc.c45
-rw-r--r--drivers/usb/gadget/serial.c57
-rw-r--r--drivers/usb/gadget/u_serial.c22
-rw-r--r--drivers/usb/host/Kconfig1
-rw-r--r--drivers/usb/otg/twl4030.c6
11 files changed, 1830 insertions, 33 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 472c591c35..797d19fe5f 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -15,6 +15,13 @@ config USB_GADGET_DRIVER_ARC
depends on ARCH_IMX
select USB_GADGET_DUALSPEED
+config USB_GADGET_DRIVER_AT91
+ bool
+ prompt "at91 gadget driver"
+ depends on ARCH_AT91
+ select USB_GADGET_DUALSPEED
+ select POLLER
+
config USB_GADGET_DRIVER_PXA27X
bool
prompt "PXA27x gadget driver"
@@ -23,8 +30,7 @@ config USB_GADGET_DRIVER_PXA27X
select POLLER
endchoice
-choice
- prompt "USB Gadget drivers"
+comment "USB Gadget drivers"
config USB_GADGET_DFU
bool
@@ -35,7 +41,5 @@ config USB_GADGET_SERIAL
depends on EXPERIMENTAL
prompt "Serial Gadget"
-endchoice
-
endif
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e034786dc8..367d7ceaba 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -3,4 +3,5 @@ obj-$(CONFIG_USB_GADGET) += composite.o config.o usbstring.o epautoconf.o
obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o serial.o f_serial.o f_acm.o
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
obj-$(CONFIG_USB_GADGET_DRIVER_ARC) += fsl_udc.o
+obj-$(CONFIG_USB_GADGET_DRIVER_AT91) += at91_udc.o
obj-$(CONFIG_USB_GADGET_DRIVER_PXA27X) += pxa27x_udc.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
new file mode 100644
index 0000000000..bb0d6143f1
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.c
@@ -0,0 +1,1538 @@
+/*
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#undef VERBOSE_DEBUG
+#undef PACKET_TRACE
+
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <clock.h>
+#include <usb/ch9.h>
+#include <usb/gadget.h>
+#include <poller.h>
+
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9261_matrix.h>
+
+#include "at91_udc.h"
+
+
+/*
+ * This controller is simple and PIO-only. It's used in many AT91-series
+ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs suppporting
+ * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the
+ * testing hasn't covered such cases.)
+ *
+ * The pullup is most important (so it's integrated on sam926x parts). It
+ * provides software control over whether the host enumerates the device.
+ *
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power. During USB suspend, the 48 MHz clock is gated off in hardware;
+ * it may also be gated off by software during some Linux sleep states.
+ */
+
+#define DRIVER_VERSION "3 May 2006"
+
+#define driver_name "at91_udc"
+static const char ep0name[] = "ep0";
+
+#define at91_udp_read(udc, reg) \
+ __raw_readl((udc)->udp_baseaddr + (reg))
+#define at91_udp_write(udc, reg, val) \
+ __raw_writel((val), (udc)->udp_baseaddr + (reg))
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+ unsigned stopped = ep->stopped;
+ struct at91_udc *udc = ep->udc;
+
+ list_del_init(&req->queue);
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+ if (status && status != -ESHUTDOWN)
+ VDBG(udc, "%s done %p, status %d\n", ep->ep.name, req, status);
+
+ ep->stopped = 1;
+ req->req.complete(&ep->ep, &req->req);
+ ep->stopped = stopped;
+
+ /* ep0 is always ready; other endpoints need a non-empty queue */
+ if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+ at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define RX_DATA_READY (AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ * - clear SET_FX bits (setting them could change something)
+ * - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ *
+ * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains,
+ * implying a need to wait for one write to complete (test relevant bits)
+ * before starting the next write. This shouldn't be an issue given how
+ * infrequently we write, except maybe for write-then-read idioms.
+ */
+#define SET_FX (AT91_UDP_TXPKTRDY)
+#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \
+ | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+ u32 __iomem *creg = ep->creg;
+ u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+ u32 csr;
+ u8 *buf;
+ unsigned int count, bufferspace, is_done;
+
+ buf = req->req.buf + req->req.actual;
+ bufferspace = req->req.length - req->req.actual;
+
+ /*
+ * there might be nothing to read if ep_queue() calls us,
+ * or if we already emptied both pingpong buffers
+ */
+rescan:
+ csr = __raw_readl(creg);
+ if ((csr & RX_DATA_READY) == 0)
+ return 0;
+
+ count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+ if (count > ep->ep.maxpacket)
+ count = ep->ep.maxpacket;
+ if (count > bufferspace) {
+ DBG(ep->udc, "%s buffer overflow\n", ep->ep.name);
+ req->req.status = -EOVERFLOW;
+ count = bufferspace;
+ }
+ readsb(dreg, buf, count);
+
+ /* release and swap pingpong mem bank */
+ csr |= CLR_FX;
+ if (ep->is_pingpong) {
+ if (ep->fifo_bank == 0) {
+ csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+ ep->fifo_bank = 1;
+ } else {
+ csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+ ep->fifo_bank = 0;
+ }
+ } else
+ csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+ __raw_writel(csr, creg);
+
+ req->req.actual += count;
+ is_done = (count < ep->ep.maxpacket);
+ if (count == bufferspace)
+ is_done = 1;
+
+ PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+ is_done ? " (done)" : "");
+
+ /*
+ * avoid extra trips through IRQ logic for packets already in
+ * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+ */
+ if (is_done)
+ done(ep, req, 0);
+ else if (ep->is_pingpong) {
+ /*
+ * One dummy read to delay the code because of a HW glitch:
+ * CSR returns bad RXCOUNT when read too soon after updating
+ * RX_DATA_BK flags.
+ */
+ csr = __raw_readl(creg);
+
+ bufferspace -= count;
+ buf += count;
+ goto rescan;
+ }
+
+ return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+ u32 __iomem *creg = ep->creg;
+ u32 csr = __raw_readl(creg);
+ u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+ unsigned total, count, is_last;
+ u8 *buf;
+
+ /*
+ * TODO: allow for writing two packets to the fifo ... that'll
+ * reduce the amount of IN-NAKing, but probably won't affect
+ * throughput much. (Unlike preventing OUT-NAKing!)
+ */
+
+ /*
+ * If ep_queue() calls us, the queue is empty and possibly in
+ * odd states like TXCOMP not yet cleared (we do it, saving at
+ * least one IRQ) or the fifo not yet being free. Those aren't
+ * issues normally (IRQ handler fast path).
+ */
+ if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+ if (csr & AT91_UDP_TXCOMP) {
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+ __raw_writel(csr, creg);
+ csr = __raw_readl(creg);
+ }
+ if (csr & AT91_UDP_TXPKTRDY)
+ return 0;
+ }
+
+ buf = req->req.buf + req->req.actual;
+ total = req->req.length - req->req.actual;
+ if (ep->ep.maxpacket < total) {
+ count = ep->ep.maxpacket;
+ is_last = 0;
+ } else {
+ count = total;
+ is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+ }
+
+ /*
+ * Write the packet, maybe it's a ZLP.
+ *
+ * NOTE: incrementing req->actual before we receive the ACK means
+ * gadget driver IN bytecounts can be wrong in fault cases. That's
+ * fixable with PIO drivers like this one (save "count" here, and
+ * do the increment later on TX irq), but not for most DMA hardware.
+ *
+ * So all gadget drivers must accept that potential error. Some
+ * hardware supports precise fifo status reporting, letting them
+ * recover when the actual bytecount matters (e.g. for USB Test
+ * and Measurement Class devices).
+ */
+ writesb(dreg, buf, count);
+ csr &= ~SET_FX;
+ csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+ writel(csr, creg);
+ req->req.actual += count;
+
+ PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+ is_last ? " (done)" : "");
+ if (is_last)
+ done(ep, req, 0);
+ return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+ struct at91_request *req;
+
+ /* terminate any request in the queue */
+ ep->stopped = 1;
+ if (list_empty(&ep->queue))
+ return;
+
+ VDBG(udc, "%s %s\n", __func__, ep->ep.name);
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct at91_request, queue);
+ done(ep, req, status);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+ struct at91_udc *udc = ep->udc;
+ u16 maxpacket;
+ u32 tmp;
+
+ if (!_ep || !ep
+ || !desc || ep->desc
+ || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+ || maxpacket > ep->maxpacket) {
+ DBG(udc, "bad ep or descriptor\n");
+ return -EINVAL;
+ }
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ DBG(udc, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ tmp = usb_endpoint_type(desc);
+ switch (tmp) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ DBG(udc, "only one control endpoint\n");
+ return -EINVAL;
+ case USB_ENDPOINT_XFER_INT:
+ if (maxpacket > 64)
+ goto bogus_max;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ switch (maxpacket) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ goto ok;
+ }
+bogus_max:
+ DBG(udc, "bogus maxpacket %d\n", maxpacket);
+ return -EINVAL;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!ep->is_pingpong) {
+ DBG(udc, "iso requires double buffering\n");
+ return -EINVAL;
+ }
+ break;
+ }
+
+ok:
+
+ /* initialize endpoint to match this descriptor */
+ ep->is_in = usb_endpoint_dir_in(desc);
+ ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+ ep->stopped = 0;
+ if (ep->is_in)
+ tmp |= 0x04;
+ tmp <<= 8;
+ tmp |= AT91_UDP_EPEDS;
+ __raw_writel(tmp, ep->creg);
+
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ /*
+ * reset/init endpoint fifo. NOTE: leaves fifo_bank alone,
+ * since endpoint resets don't reset hw pingpong state.
+ */
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+
+ return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+ struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+ struct at91_udc *udc = ep->udc;
+
+ if (ep == &ep->udc->ep[0])
+ return -EINVAL;
+
+ nuke(ep, -ESHUTDOWN);
+
+ /* restore the endpoint's pristine config */
+ ep->desc = NULL;
+ ep->ep.maxpacket = ep->maxpacket;
+
+ /* reset fifos and endpoint */
+ if (ep->udc->clocked) {
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+ __raw_writel(0, ep->creg);
+ }
+
+ return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *
+at91_ep_alloc_request(struct usb_ep *_ep)
+{
+ struct at91_request *req;
+
+ req = xzalloc(sizeof *req);
+
+ INIT_LIST_HEAD(&req->queue);
+ return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct at91_request *req;
+
+ req = container_of(_req, struct at91_request, req);
+ BUG_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct at91_request *req;
+ struct at91_ep *ep;
+ struct at91_udc *udc;
+ int status;
+
+ req = container_of(_req, struct at91_request, req);
+ ep = container_of(_ep, struct at91_ep, ep);
+
+ if (!_req || !_req->complete
+ || !_req->buf || !list_empty(&req->queue)) {
+ DBG(udc, "invalid request\n");
+ return -EINVAL;
+ }
+
+ if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+ DBG(udc, "invalid ep\n");
+ return -EINVAL;
+ }
+
+ udc = ep->udc;
+
+ if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ DBG(udc, "invalid device\n");
+ return -EINVAL;
+ }
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ /* try to kickstart any empty and idle queue */
+ if (list_empty(&ep->queue) && !ep->stopped) {
+ int is_ep0;
+
+ /*
+ * If this control request has a non-empty DATA stage, this
+ * will start that stage. It works just like a non-control
+ * request (until the status stage starts, maybe early).
+ *
+ * If the data stage is empty, then this starts a successful
+ * IN/STATUS stage. (Unsuccessful ones use set_halt.)
+ */
+ is_ep0 = (ep->ep.name == ep0name);
+ if (is_ep0) {
+ u32 tmp;
+
+ if (!udc->req_pending) {
+ status = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * defer changing CONFG until after the gadget driver
+ * reconfigures the endpoints.
+ */
+ if (udc->wait_for_config_ack) {
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+ tmp ^= AT91_UDP_CONFG;
+ VDBG(udc, "toggle config\n");
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+ }
+ if (req->req.length == 0) {
+ep0_in_status:
+ PACKET("ep0 in/status\n");
+ status = 0;
+ tmp = __raw_readl(ep->creg);
+ tmp &= ~SET_FX;
+ tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+ __raw_writel(tmp, ep->creg);
+ udc->req_pending = 0;
+ goto done;
+ }
+ }
+
+ if (ep->is_in)
+ status = write_fifo(ep, req);
+ else {
+ status = read_fifo(ep, req);
+
+ /* IN/STATUS stage is otherwise triggered by irq */
+ if (status && is_ep0)
+ goto ep0_in_status;
+ }
+ } else
+ status = 0;
+
+ if (req && !status) {
+ list_add_tail (&req->queue, &ep->queue);
+ }
+done:
+ return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct at91_ep *ep;
+ struct at91_request *req;
+
+ ep = container_of(_ep, struct at91_ep, ep);
+ if (!_ep || ep->ep.name == ep0name)
+ return -EINVAL;
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry (req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+ return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+ struct at91_udc *udc = ep->udc;
+ u32 __iomem *creg;
+ u32 csr;
+ int status = 0;
+
+ if (!_ep || ep->is_iso || !ep->udc->clocked)
+ return -EINVAL;
+
+ creg = ep->creg;
+
+ csr = __raw_readl(creg);
+
+ /*
+ * fail with still-busy IN endpoints, ensuring correct sequencing
+ * of data tx then stall. note that the fifo rx bytecount isn't
+ * completely accurate as a tx bytecount.
+ */
+ if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+ status = -EAGAIN;
+ else {
+ csr |= CLR_FX;
+ csr &= ~SET_FX;
+ if (value) {
+ csr |= AT91_UDP_FORCESTALL;
+ VDBG(udc, "halt %s\n", ep->ep.name);
+ } else {
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+ csr &= ~AT91_UDP_FORCESTALL;
+ }
+ __raw_writel(csr, creg);
+ }
+
+ return status;
+}
+
+static const struct usb_ep_ops at91_ep_ops = {
+ .enable = at91_ep_enable,
+ .disable = at91_ep_disable,
+ .alloc_request = at91_ep_alloc_request,
+ .free_request = at91_ep_free_request,
+ .queue = at91_ep_queue,
+ .dequeue = at91_ep_dequeue,
+ .set_halt = at91_ep_set_halt,
+ /* there's only imprecise fifo status reporting */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+ struct at91_udc *udc = to_udc(gadget);
+
+ if (!to_udc(gadget)->clocked)
+ return -EINVAL;
+ return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+ struct at91_udc *udc = to_udc(gadget);
+ u32 glbstate;
+ int status = -EINVAL;
+
+ DBG(udc, "%s\n", __func__ );
+
+ if (!udc->clocked || !udc->suspended)
+ goto done;
+
+ /* NOTE: some "early versions" handle ESR differently ... */
+
+ glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+ if (!(glbstate & AT91_UDP_ESR))
+ goto done;
+ glbstate |= AT91_UDP_ESR;
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
+
+done:
+ return status;
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct at91_ep *ep = &udc->ep[i];
+
+ if (i != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->desc = NULL;
+ ep->stopped = 0;
+ ep->fifo_bank = 0;
+ ep->ep.maxpacket = ep->maxpacket;
+ ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
+ /* initialize one queue per endpoint */
+ INIT_LIST_HEAD(&ep->queue);
+ }
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+ struct usb_gadget_driver *driver = udc->driver;
+ int i;
+
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct at91_ep *ep = &udc->ep[i];
+ ep->stopped = 1;
+ nuke(ep, -ESHUTDOWN);
+ }
+ if (driver) {
+ driver->disconnect(&udc->gadget);
+ }
+
+ udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+ if (udc->clocked)
+ return;
+ udc->clocked = 1;
+ clk_enable(udc->iclk);
+ clk_enable(udc->fclk);
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+ if (!udc->clocked)
+ return;
+ udc->clocked = 0;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ clk_disable(udc->fclk);
+ clk_disable(udc->iclk);
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+ int active = !udc->board.pullup_active_low;
+
+ if (!udc->enabled || !udc->vbus)
+ is_on = 0;
+ DBG(udc, "%sactive\n", is_on ? "" : "in");
+
+ if (is_on) {
+ clk_on(udc);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_TXVC, 0);
+ if (cpu_is_at91rm9200())
+ gpio_set_value(udc->board.pullup_pin, active);
+ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ 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() || cpu_is_at91sam9g10()) {
+ 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_IDR, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ if (cpu_is_at91rm9200())
+ gpio_set_value(udc->board.pullup_pin, !active);
+ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
+ 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() || cpu_is_at91sam9g10()) {
+ u32 usbpucr;
+ usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
+ at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ }
+ clk_off(udc);
+ }
+}
+
+/* vbus is here! turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct at91_udc *udc = to_udc(gadget);
+
+ /* VDBG(udc, "vbus %s\n", is_active ? "on" : "off"); */
+ udc->vbus = (is_active != 0);
+ if (udc->driver)
+ pullup(udc, is_active);
+ else
+ pullup(udc, 0);
+ return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct at91_udc *udc = to_udc(gadget);
+
+ udc->enabled = is_on = !!is_on;
+ pullup(udc, is_on);
+ return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+ struct at91_udc *udc = to_udc(gadget);
+
+ udc->selfpowered = (is_on != 0);
+ return 0;
+}
+
+static const struct usb_gadget_ops at91_udc_ops = {
+ .get_frame = at91_get_frame,
+ .wakeup = at91_wakeup,
+ .set_selfpowered = at91_set_selfpowered,
+ .vbus_session = at91_vbus_session,
+ .pullup = at91_pullup,
+
+ /*
+ * VBUS-powered devices may also also want to support bigger
+ * power budgets after an appropriate SET_CONFIGURATION.
+ */
+ /* .vbus_power = at91_vbus_power, */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+ struct at91_request *req;
+ u32 __iomem *creg = ep->creg;
+ u32 csr = __raw_readl(creg);
+
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next,
+ struct at91_request, queue);
+ else
+ req = NULL;
+
+ if (ep->is_in) {
+ if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+ __raw_writel(csr, creg);
+ }
+ if (req)
+ return write_fifo(ep, req);
+
+ } else {
+ if (csr & AT91_UDP_STALLSENT) {
+ /* STALLSENT bit == ISOERR */
+ if (ep->is_iso && req)
+ req->req.status = -EILSEQ;
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+ __raw_writel(csr, creg);
+ csr = __raw_readl(creg);
+ }
+ if (req && (csr & RX_DATA_READY))
+ return read_fifo(ep, req);
+ }
+ return 0;
+}
+
+union setup {
+ u8 raw[8];
+ struct usb_ctrlrequest r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+ u32 __iomem *creg = ep->creg;
+ u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+ unsigned rxcount, i = 0;
+ u32 tmp;
+ union setup pkt;
+ int status = 0;
+
+ /* read and ack SETUP; hard-fail for bogus packets */
+ rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+ if (likely(rxcount == 8)) {
+ while (rxcount--)
+ pkt.raw[i++] = __raw_readb(dreg);
+ if (pkt.r.bRequestType & USB_DIR_IN) {
+ csr |= AT91_UDP_DIR;
+ ep->is_in = 1;
+ } else {
+ csr &= ~AT91_UDP_DIR;
+ ep->is_in = 0;
+ }
+ } else {
+ /* REVISIT this happens sometimes under load; why?? */
+ ERR(udc, "SETUP len %d, csr %08x\n", rxcount, csr);
+ status = -EINVAL;
+ }
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+ __raw_writel(csr, creg);
+ udc->wait_for_addr_ack = 0;
+ udc->wait_for_config_ack = 0;
+ ep->stopped = 0;
+ if (unlikely(status != 0))
+ goto stall;
+
+#define w_index le16_to_cpu(pkt.r.wIndex)
+#define w_value le16_to_cpu(pkt.r.wValue)
+#define w_length le16_to_cpu(pkt.r.wLength)
+
+ VDBG(udc, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+ pkt.r.bRequestType, pkt.r.bRequest,
+ w_value, w_index, w_length);
+
+ /*
+ * A few standard requests get handled here, ones that touch
+ * hardware ... notably for device and endpoint features.
+ */
+ udc->req_pending = 1;
+ csr = __raw_readl(creg);
+ csr |= CLR_FX;
+ csr &= ~SET_FX;
+ switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+ case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+ | USB_REQ_SET_ADDRESS:
+ __raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+ udc->addr = w_value;
+ udc->wait_for_addr_ack = 1;
+ udc->req_pending = 0;
+ /* FADDR is set later, when we ack host STATUS */
+ return;
+
+ case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+ | USB_REQ_SET_CONFIGURATION:
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+ if (pkt.r.wValue)
+ udc->wait_for_config_ack = (tmp == 0);
+ else
+ udc->wait_for_config_ack = (tmp != 0);
+ if (udc->wait_for_config_ack)
+ VDBG(udc, "wait for config\n");
+ /* CONFG is toggled later, if gadget driver succeeds */
+ break;
+
+ /*
+ * Hosts may set or clear remote wakeup status, and
+ * devices may report they're VBUS powered.
+ */
+ case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+ | USB_REQ_GET_STATUS:
+ tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+ if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+ tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+ PACKET("get device status\n");
+ __raw_writeb(tmp, dreg);
+ __raw_writeb(0, dreg);
+ goto write_in;
+ /* then STATUS starts later, automatically */
+ case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+ | USB_REQ_SET_FEATURE:
+ if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+ goto stall;
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+ tmp |= AT91_UDP_ESR;
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+ goto succeed;
+ case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+ | USB_REQ_CLEAR_FEATURE:
+ if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+ goto stall;
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+ tmp &= ~AT91_UDP_ESR;
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+ goto succeed;
+
+ /*
+ * Interfaces have no feature settings; this is pretty useless.
+ * we won't even insist the interface exists...
+ */
+ case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+ | USB_REQ_GET_STATUS:
+ PACKET("get interface status\n");
+ __raw_writeb(0, dreg);
+ __raw_writeb(0, dreg);
+ goto write_in;
+ /* then STATUS starts later, automatically */
+ case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+ | USB_REQ_SET_FEATURE:
+ case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+ | USB_REQ_CLEAR_FEATURE:
+ goto stall;
+
+ /*
+ * Hosts may clear bulk/intr endpoint halt after the gadget
+ * driver sets it (not widely used); or set it (for testing)
+ */
+ case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+ | USB_REQ_GET_STATUS:
+ tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ ep = &udc->ep[tmp];
+ if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
+ goto stall;
+
+ if (tmp) {
+ if ((w_index & USB_DIR_IN)) {
+ if (!ep->is_in)
+ goto stall;
+ } else if (ep->is_in)
+ goto stall;
+ }
+ PACKET("get %s status\n", ep->ep.name);
+ if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+ tmp = (1 << USB_ENDPOINT_HALT);
+ else
+ tmp = 0;
+ __raw_writeb(tmp, dreg);
+ __raw_writeb(0, dreg);
+ goto write_in;
+ /* then STATUS starts later, automatically */
+ case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+ | USB_REQ_SET_FEATURE:
+ tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ ep = &udc->ep[tmp];
+ if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+ goto stall;
+ if (!ep->desc || ep->is_iso)
+ goto stall;
+ if ((w_index & USB_DIR_IN)) {
+ if (!ep->is_in)
+ goto stall;
+ } else if (ep->is_in)
+ goto stall;
+
+ tmp = __raw_readl(ep->creg);
+ tmp &= ~SET_FX;
+ tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+ __raw_writel(tmp, ep->creg);
+ goto succeed;
+ case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+ | USB_REQ_CLEAR_FEATURE:
+ tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+ ep = &udc->ep[tmp];
+ if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
+ goto stall;
+ if (tmp == 0)
+ goto succeed;
+ if (!ep->desc || ep->is_iso)
+ goto stall;
+ if ((w_index & USB_DIR_IN)) {
+ if (!ep->is_in)
+ goto stall;
+ } else if (ep->is_in)
+ goto stall;
+
+ at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+ at91_udp_write(udc, AT91_UDP_RST_EP, 0);
+ tmp = __raw_readl(ep->creg);
+ tmp |= CLR_FX;
+ tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+ __raw_writel(tmp, ep->creg);
+ if (!list_empty(&ep->queue))
+ handle_ep(ep);
+ goto succeed;
+ }
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+ /* pass request up to the gadget driver */
+ if (udc->driver) {
+ status = udc->driver->setup(&udc->gadget, &pkt.r);
+ }
+ else
+ status = -ENODEV;
+ if (status < 0) {
+stall:
+ VDBG(udc, "req %02x.%02x protocol STALL; stat %d\n",
+ pkt.r.bRequestType, pkt.r.bRequest, status);
+ csr |= AT91_UDP_FORCESTALL;
+ __raw_writel(csr, creg);
+ udc->req_pending = 0;
+ }
+ return;
+
+succeed:
+ /* immediate successful (IN) STATUS after zero length DATA */
+ PACKET("ep0 in/status\n");
+write_in:
+ csr |= AT91_UDP_TXPKTRDY;
+ __raw_writel(csr, creg);
+ udc->req_pending = 0;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+ struct at91_ep *ep0 = &udc->ep[0];
+ u32 __iomem *creg = ep0->creg;
+ u32 csr = __raw_readl(creg);
+ struct at91_request *req;
+
+ if (unlikely(csr & AT91_UDP_STALLSENT)) {
+ nuke(ep0, -EPROTO);
+ udc->req_pending = 0;
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+ __raw_writel(csr, creg);
+ VDBG(udc, "ep0 stalled\n");
+ csr = __raw_readl(creg);
+ }
+ if (csr & AT91_UDP_RXSETUP) {
+ nuke(ep0, 0);
+ udc->req_pending = 0;
+ handle_setup(udc, ep0, csr);
+ return;
+ }
+
+ if (list_empty(&ep0->queue))
+ req = NULL;
+ else
+ req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+ /* host ACKed an IN packet that we sent */
+ if (csr & AT91_UDP_TXCOMP) {
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+ /* write more IN DATA? */
+ if (req && ep0->is_in) {
+ if (handle_ep(ep0))
+ udc->req_pending = 0;
+
+ /*
+ * Ack after:
+ * - last IN DATA packet (including GET_STATUS)
+ * - IN/STATUS for OUT DATA
+ * - IN/STATUS for any zero-length DATA stage
+ * except for the IN DATA case, the host should send
+ * an OUT status later, which we'll ack.
+ */
+ } else {
+ udc->req_pending = 0;
+ __raw_writel(csr, creg);
+
+ /*
+ * SET_ADDRESS takes effect only after the STATUS
+ * (to the original address) gets acked.
+ */
+ if (udc->wait_for_addr_ack) {
+ u32 tmp;
+
+ at91_udp_write(udc, AT91_UDP_FADDR,
+ AT91_UDP_FEN | udc->addr);
+ tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
+ tmp &= ~AT91_UDP_FADDEN;
+ if (udc->addr)
+ tmp |= AT91_UDP_FADDEN;
+ at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
+
+ udc->wait_for_addr_ack = 0;
+ VDBG(udc, "address %d\n", udc->addr);
+ }
+ }
+ }
+
+ /* OUT packet arrived ... */
+ else if (csr & AT91_UDP_RX_DATA_BK0) {
+ csr |= CLR_FX;
+ csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+ /* OUT DATA stage */
+ if (!ep0->is_in) {
+ if (req) {
+ if (handle_ep(ep0)) {
+ /* send IN/STATUS */
+ PACKET("ep0 in/status\n");
+ csr = __raw_readl(creg);
+ csr &= ~SET_FX;
+ csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+ __raw_writel(csr, creg);
+ udc->req_pending = 0;
+ }
+ } else if (udc->req_pending) {
+ /*
+ * AT91 hardware has a hard time with this
+ * "deferred response" mode for control-OUT
+ * transfers. (For control-IN it's fine.)
+ *
+ * The normal solution leaves OUT data in the
+ * fifo until the gadget driver is ready.
+ * We couldn't do that here without disabling
+ * the IRQ that tells about SETUP packets,
+ * e.g. when the host gets impatient...
+ *
+ * Working around it by copying into a buffer
+ * would almost be a non-deferred response,
+ * except that it wouldn't permit reliable
+ * stalling of the request. Instead, demand
+ * that gadget drivers not use this mode.
+ */
+ DBG(udc, "no control-OUT deferred responses!\n");
+ __raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+ udc->req_pending = 0;
+ }
+
+ /* STATUS stage for control-IN; ack. */
+ } else {
+ PACKET("ep0 out/status ACK\n");
+ __raw_writel(csr, creg);
+
+ /* "early" status stage */
+ if (req)
+ done(ep0, req, 0);
+ }
+ }
+}
+
+static void at91_udc_irq (void *_udc)
+{
+ struct at91_udc *udc = _udc;
+ u32 rescans = 5;
+
+ while (rescans--) {
+ u32 status;
+
+ status = at91_udp_read(udc, AT91_UDP_ISR);
+ if (!status)
+ break;
+
+ /* USB reset irq: not maskable */
+ if (status & AT91_UDP_ENDBUSRES) {
+ at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+ /* Atmel code clears this irq twice */
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+ VDBG(udc, "end bus reset\n");
+ udc->addr = 0;
+ stop_activity(udc);
+
+ /* enable ep0 */
+ at91_udp_write(udc, AT91_UDP_CSR(0),
+ AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+ udc->gadget.speed = USB_SPEED_FULL;
+ udc->suspended = 0;
+
+ /*
+ * NOTE: this driver keeps clocks off unless the
+ * USB host is present. That saves power, but for
+ * boards that don't support VBUS detection, both
+ * clocks need to be active most of the time.
+ */
+
+ /* host initiated suspend (3+ms bus idle) */
+ } else if (status & AT91_UDP_RXSUSP) {
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
+ /* VDBG(udc, "bus suspend\n"); */
+ if (udc->suspended)
+ continue;
+ udc->suspended = 1;
+
+ /*
+ * NOTE: when suspending a VBUS-powered device, the
+ * gadget driver should switch into slow clock mode
+ * and then into standby to avoid drawing more than
+ * 500uA power (2500uA for some high-power configs).
+ */
+ if (udc->driver && udc->driver->suspend) {
+ udc->driver->suspend(&udc->gadget);
+ }
+
+ /* host initiated resume */
+ } else if (status & AT91_UDP_RXRSM) {
+ at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+ at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
+ /* VDBG(udc, "bus resume\n"); */
+ if (!udc->suspended)
+ continue;
+ udc->suspended = 0;
+
+ /*
+ * NOTE: for a VBUS-powered device, the gadget driver
+ * would normally want to switch out of slow clock
+ * mode into normal mode.
+ */
+ if (udc->driver && udc->driver->resume) {
+ udc->driver->resume(&udc->gadget);
+ }
+
+ /* endpoint IRQs are cleared by handling them */
+ } else {
+ int i;
+ unsigned mask = 1;
+ struct at91_ep *ep = &udc->ep[1];
+
+ if (status & mask)
+ handle_ep0(udc);
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ mask <<= 1;
+ if (status & mask)
+ handle_ep(ep);
+ ep++;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct at91_udc controller = {
+ .gadget = {
+ .ops = &at91_udc_ops,
+ .ep0 = &controller.ep[0].ep,
+ .name = driver_name,
+ },
+ .ep[0] = {
+ .ep = {
+ .name = ep0name,
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 8,
+ .int_mask = 1 << 0,
+ },
+ .ep[1] = {
+ .ep = {
+ .name = "ep1",
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .is_pingpong = 1,
+ .maxpacket = 64,
+ .int_mask = 1 << 1,
+ },
+ .ep[2] = {
+ .ep = {
+ .name = "ep2",
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .is_pingpong = 1,
+ .maxpacket = 64,
+ .int_mask = 1 << 2,
+ },
+ .ep[3] = {
+ .ep = {
+ /* could actually do bulk too */
+ .name = "ep3-int",
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 8,
+ .int_mask = 1 << 3,
+ },
+ .ep[4] = {
+ .ep = {
+ .name = "ep4",
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .is_pingpong = 1,
+ .maxpacket = 256,
+ .int_mask = 1 << 4,
+ },
+ .ep[5] = {
+ .ep = {
+ .name = "ep5",
+ .ops = &at91_ep_ops,
+ },
+ .udc = &controller,
+ .is_pingpong = 1,
+ .maxpacket = 256,
+ .int_mask = 1 << 5,
+ },
+ /* ep6 and ep7 are also reserved (custom silicon might use them) */
+};
+
+static void at91_udc_irq (void *_udc);
+
+static void at91_update_vbus(struct at91_udc *udc, u32 value)
+{
+ if (value == udc->gpio_vbus_val)
+ return;
+
+ if (value)
+ dev_set_param(udc->dev, "vbus", "1");
+ else
+ dev_set_param(udc->dev, "vbus", "0");
+
+ udc->gpio_vbus_val = value;
+}
+
+int usb_gadget_poll(void)
+{
+ struct at91_udc *udc = &controller;
+ u32 value;
+
+ if (!udc->udp_baseaddr)
+ return 0;
+
+ value = gpio_get_value(udc->board.vbus_pin);
+ value ^= udc->board.vbus_active_low;
+
+ if (!value) {
+ at91_update_vbus(udc, value);
+ return 0;
+ }
+ at91_update_vbus(udc, value);
+
+ value = at91_udp_read(udc, AT91_UDP_ISR) & (~(AT91_UDP_SOFINT));
+ if (value)
+ at91_udc_irq(udc);
+
+ return value;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct at91_udc *udc = &controller;
+ int retval;
+
+ if (!udc->iclk)
+ return -ENODEV;
+
+ if (!driver
+ || driver->speed < USB_SPEED_FULL
+ || !driver->bind
+ || !driver->setup) {
+ DBG(udc, "bad parameter.\n");
+ return -EINVAL;
+ }
+
+ if (udc->driver) {
+ DBG(udc, "UDC already has a gadget driver\n");
+ return -EBUSY;
+ }
+
+ udc->driver = driver;
+ udc->enabled = 1;
+ udc->selfpowered = 1;
+
+ retval = driver->bind(&udc->gadget);
+ if (retval) {
+ DBG(udc, "bind() returned %d\n", retval);
+ udc->driver = NULL;
+ udc->enabled = 0;
+ udc->selfpowered = 0;
+ return retval;
+ }
+
+ pullup(udc, 1);
+
+ DBG(udc, "bound to %s\n", driver->function);
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+ struct at91_udc *udc = &controller;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ udc->enabled = 0;
+ at91_udp_write(udc, AT91_UDP_IDR, ~0);
+ pullup(udc, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->driver = NULL;
+
+ DBG(udc, "unbound from %s\n", driver->function);
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91_udc_poller(struct poller_struct *poller)
+{
+ usb_gadget_poll();
+}
+
+static struct poller_struct poller = {
+ .func = at91_udc_poller
+};
+
+static int __init at91udc_probe(struct device_d *dev)
+{
+ struct at91_udc *udc;
+ int retval;
+
+ if (!dev->platform_data) {
+ /* small (so we copy it) but critical! */
+ DBG(udc, "missing platform_data\n");
+ return -ENODEV;
+ }
+
+ /* init software state */
+ udc = &controller;
+ udc->dev = dev;
+ udc->board = *(struct at91_udc_data *) dev->platform_data;
+ udc->enabled = 0;
+
+ /* rm9200 needs manual D+ pullup; off by default */
+ if (cpu_is_at91rm9200()) {
+ if (udc->board.pullup_pin <= 0) {
+ DBG(udc, "no D+ pullup?\n");
+ retval = -ENODEV;
+ goto fail0;
+ }
+ retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
+ if (retval) {
+ DBG(udc, "D+ pullup is busy\n");
+ goto fail0;
+ }
+ gpio_direction_output(udc->board.pullup_pin,
+ udc->board.pullup_active_low);
+ }
+
+ /* newer chips have more FIFO memory than rm9200 */
+ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
+ udc->ep[0].maxpacket = 64;
+ udc->ep[3].maxpacket = 64;
+ udc->ep[4].maxpacket = 512;
+ udc->ep[5].maxpacket = 512;
+ } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
+ udc->ep[3].maxpacket = 64;
+ } else if (cpu_is_at91sam9263()) {
+ udc->ep[0].maxpacket = 64;
+ udc->ep[3].maxpacket = 64;
+ }
+
+ udc->udp_baseaddr = dev_request_mem_region(dev, 0);
+ if (!udc->udp_baseaddr) {
+ retval = -ENOMEM;
+ goto fail0a;
+ }
+
+ udc_reinit(udc);
+
+ /* get interface and function clocks */
+ udc->iclk = clk_get(dev, "udc_clk");
+ udc->fclk = clk_get(dev, "udpck");
+ if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+ DBG(udc, "clocks missing\n");
+ retval = -ENODEV;
+ /* NOTE: we "know" here that refcounts on these are NOPs */
+ goto fail0a;
+ }
+
+ /* don't do anything until we have both gadget driver and VBUS */
+ 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);
+
+ 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);
+ DBG(udc, "VBUS detection: host:%s \n",
+ udc->vbus ? "present":"absent");
+ } else {
+ DBG(udc, "no VBUS detection, assuming always-on\n");
+ udc->vbus = 1;
+ }
+
+ dev_add_param(dev, "vbus", NULL, NULL, 0);
+ dev_set_param(dev, "vbus", "0");
+
+ poller_register(&poller);
+
+ INFO(udc, "%s version %s\n", driver_name, DRIVER_VERSION);
+ return 0;
+
+fail0a:
+ if (cpu_is_at91rm9200())
+ gpio_free(udc->board.pullup_pin);
+fail0:
+ DBG(udc, "%s probe failed, %d\n", driver_name, retval);
+ return retval;
+}
+
+
+static struct driver_d at91_udc_driver = {
+ .name = driver_name,
+ .probe = at91udc_probe,
+};
+
+static int at91_udc_init(void)
+{
+ register_driver(&at91_udc_driver);
+ return 0;
+}
+device_initcall(at91_udc_init);
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
new file mode 100644
index 0000000000..e592cc54ff
--- /dev/null
+++ b/drivers/usb/gadget/at91_udc.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */
+#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */
+#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */
+#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */
+
+#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */
+#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */
+#define AT91_UDP_CONFG (1 << 1) /* Configured */
+#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */
+#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */
+#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR 0x08 /* Function Address Register */
+#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */
+#define AT91_UDP_FEN (1 << 8) /* Function Enable */
+
+#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */
+#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */
+#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */
+
+#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */
+#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 [AT91RM9200 only] */
+#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */
+#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset 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 */
+
+#define AT91_UDP_CSR(n) (0x30+((n)*4)) /* Endpoint Control/Status Registers 0-7 */
+#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */
+#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */
+#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */
+#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */
+#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */
+#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */
+#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */
+#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */
+#define AT91_UDP_EPTYPE_CTRL (0 << 8)
+#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8)
+#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8)
+#define AT91_UDP_EPTYPE_INT_OUT (3 << 8)
+#define AT91_UDP_EPTYPE_ISO_IN (5 << 8)
+#define AT91_UDP_EPTYPE_BULK_IN (6 << 8)
+#define AT91_UDP_EPTYPE_INT_IN (7 << 8)
+#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */
+#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */
+#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n) (0x50+((n)*4)) /* Endpoint FIFO Data Registers 0-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] */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define NUM_ENDPOINTS 6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define MINIMUS_INTERRUPTUS \
+ (AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct at91_udc *udc;
+ void __iomem *creg;
+
+ unsigned maxpacket:16;
+ u8 int_mask;
+ unsigned is_pingpong:1;
+
+ unsigned stopped:1;
+ unsigned is_in:1;
+ unsigned is_iso:1;
+ unsigned fifo_bank:1;
+
+ const struct usb_endpoint_descriptor
+ *desc;
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+ struct usb_gadget gadget;
+ struct at91_ep ep[NUM_ENDPOINTS];
+ struct usb_gadget_driver *driver;
+ unsigned vbus:1;
+ unsigned enabled:1;
+ unsigned clocked:1;
+ unsigned suspended:1;
+ unsigned req_pending:1;
+ unsigned wait_for_addr_ack:1;
+ unsigned wait_for_config_ack:1;
+ unsigned selfpowered:1;
+ unsigned active_suspend:1;
+ u8 addr;
+ u32 gpio_vbus_val;
+ struct at91_udc_data board;
+ struct clk *iclk, *fclk;
+ struct device_d *dev;
+ void __iomem *udp_baseaddr;
+ int udp_irq;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+ return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef VERBOSE_DEBUG
+# define VDBG DBG
+#else
+# define VDBG(stuff...) do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+# define PACKET VDBG
+#else
+# define PACKET(stuff...) do{}while(0)
+#endif
+
+#define ERR(udc, stuff...) dev_err((udc)->dev, ##stuff)
+#define WARNING(udc, stuff...) dev_warn((udc)->dev, ##stuff)
+#define INFO(udc, stuff...) dev_info((udc)->dev, ##stuff)
+#define DBG(udc, stuff...) dev_dbg((udc)->dev, ##stuff)
+
+#endif
diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c
index 0a0d244106..f26c1e43d0 100644
--- a/drivers/usb/gadget/dfu.c
+++ b/drivers/usb/gadget/dfu.c
@@ -67,6 +67,7 @@ static int dfualt;
static int dfufd = -EINVAL;;
static struct usb_dfu_dev *dfu_devs;
static int dfu_num_alt;
+static int dfudetach;
/* USB DFU functional descriptor */
static struct usb_dfu_func_descriptor usb_dfu_func = {
@@ -204,6 +205,9 @@ static int dfu_status(struct usb_function *f, const struct usb_ctrlrequest *ctrl
dstat->bStatus = dfu->dfu_status;
dstat->bState = dfu->dfu_state;
dstat->iString = 0;
+ dstat->bwPollTimeout[0] = 10;
+ dstat->bwPollTimeout[1] = 0;
+ dstat->bwPollTimeout[2] = 0;
return sizeof(*dstat);
}
@@ -425,6 +429,8 @@ static int dfu_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
* least the Linux USB stack likes to send a number of resets
* in a row :( */
dfu->dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;
+ value = 0;
+ dfudetach = 1;
break;
default:
dfu->dfu_state = DFU_STATE_dfuERROR;
@@ -690,11 +696,12 @@ int usb_dfu_register(struct usb_dfu_pdata *pdata)
while (1) {
usb_gadget_poll();
- if (ctrlc())
+ if (ctrlc() || dfudetach)
goto out;
}
out:
+ dfudetach = 0;
usb_composite_unregister(&dfu_driver);
return 0;
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 43b4992560..218aed219c 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -407,7 +407,7 @@ static void acm_disable(struct usb_function *f)
{
struct f_acm *acm = func_to_acm(f);
- printf("acm ttyGS%d deactivated\n", acm->port_num);
+ VDBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
gserial_disconnect(&acm->port);
usb_ep_disable(acm->notify);
acm->notify->driver_data = NULL;
@@ -473,7 +473,7 @@ static int acm_notify_serial_state(struct f_acm *acm)
int status;
if (acm->notify_req) {
- printf("acm ttyGS%d serial state %04x\n",
+ VDBG(cdev, "acm ttyGS%d serial state %04x\n",
acm->port_num, acm->serial_state);
status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
0, &acm->serial_state, sizeof(acm->serial_state));
diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c
index fbc6e4ecc7..5b64ec2011 100644
--- a/drivers/usb/gadget/fsl_udc.c
+++ b/drivers/usb/gadget/fsl_udc.c
@@ -6,6 +6,7 @@
#include <usb/gadget.h>
#include <usb/fsl_usb2.h>
#include <io.h>
+#include <poller.h>
#include <asm/byteorder.h>
#include <asm/mmu.h>
@@ -233,6 +234,7 @@ struct usb_dr_device {
#define USB_MODE_CTRL_MODE_DEVICE 0x00000002
#define USB_MODE_CTRL_MODE_HOST 0x00000003
#define USB_MODE_CTRL_MODE_RSV 0x00000001
+#define USB_MODE_CTRL_MODE_MASK 0x00000003
#define USB_MODE_SETUP_LOCK_OFF 0x00000008
#define USB_MODE_STREAM_DISABLE 0x00000010
/* Endpoint Flush Register */
@@ -603,7 +605,8 @@ static void nuke(struct fsl_ep *ep, int status)
static int dr_controller_setup(struct fsl_udc *udc)
{
- unsigned int tmp, portctrl;
+ unsigned int tmp, portctrl, ep_num;
+ unsigned int max_no_of_ep;
uint64_t to;
/* Config PHY interface */
@@ -647,6 +650,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
/* Set the controller as device mode */
tmp = readl(&dr_regs->usbmode);
+ tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
tmp |= USB_MODE_CTRL_MODE_DEVICE;
/* Disable Setup Lockout */
tmp |= USB_MODE_SETUP_LOCK_OFF;
@@ -659,6 +663,14 @@ static int dr_controller_setup(struct fsl_udc *udc)
tmp &= USB_EP_LIST_ADDRESS_MASK;
writel(tmp, &dr_regs->endpointlistaddr);
+ max_no_of_ep = (0x0000001F & readl(&dr_regs->dccparams));
+ for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
+ tmp = readl(&dr_regs->endptctrl[ep_num]);
+ tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
+ tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
+ | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
+ writel(tmp, &dr_regs->endptctrl[ep_num]);
+ }
VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
udc->ep_qh, (int)tmp,
readl(&dr_regs->endpointlistaddr));
@@ -725,12 +737,14 @@ static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
if (ep_num)
tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
tmp_epctrl |= EPCTRL_TX_ENABLE;
+ tmp_epctrl &= ~EPCTRL_TX_TYPE;
tmp_epctrl |= ((unsigned int)(ep_type)
<< EPCTRL_TX_EP_TYPE_SHIFT);
} else {
if (ep_num)
tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
tmp_epctrl |= EPCTRL_RX_ENABLE;
+ tmp_epctrl &= ~EPCTRL_RX_TYPE;
tmp_epctrl |= ((unsigned int)(ep_type)
<< EPCTRL_RX_EP_TYPE_SHIFT);
}
@@ -887,7 +901,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
case USB_ENDPOINT_XFER_ISOC:
/* Calculate transactions needed for high bandwidth iso */
mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
+ max = max & 0x7ff; /* bit 0~10 */
/* 3 transactions at most */
if (mult > 3)
goto en_done;
@@ -924,7 +938,6 @@ static int fsl_ep_enable(struct usb_ep *_ep,
(desc->bEndpointAddress & USB_DIR_IN)
? "in" : "out", max);
en_done:
- printf("%s: %d\n", __func__, retval);
return retval;
}
@@ -948,10 +961,13 @@ static int fsl_ep_disable(struct usb_ep *_ep)
/* disable ep on controller */
ep_num = ep_index(ep);
epctrl = readl(&dr_regs->endptctrl[ep_num]);
- if (ep_is_in(ep))
- epctrl &= ~EPCTRL_TX_ENABLE;
- else
- epctrl &= ~EPCTRL_RX_ENABLE;
+ if (ep_is_in(ep)) {
+ epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
+ } else {
+ epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
+ }
writel(epctrl, &dr_regs->endptctrl[ep_num]);
udc = (struct fsl_udc *)ep->udc;
@@ -1921,7 +1937,7 @@ int usb_gadget_poll(void)
/* Disable ISR for OTG host mode */
if (udc->stopped)
- return 0;
+ return -EIO;
irq_src = readl(&dr_regs->usbsts) & readl(&dr_regs->usbintr);
/* Clear notification bits */
@@ -1999,7 +2015,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
/* bind udc driver to gadget driver */
retval = driver->bind(&udc_controller->gadget);
if (retval) {
- VDBG("bind to %s --> %d", driver->driver.name, retval);
+ VDBG("bind to gadget --> %d", retval);
udc_controller->driver = NULL;
goto out;
}
@@ -2231,6 +2247,15 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
return 0;
}
+static void fsl_udc_poller(struct poller_struct *poller)
+{
+ usb_gadget_poll();
+}
+
+static struct poller_struct poller = {
+ .func = fsl_udc_poller
+};
+
static int fsl_udc_probe(struct device_d *dev)
{
int ret, i;
@@ -2293,6 +2318,8 @@ static int fsl_udc_probe(struct device_d *dev)
struct_ep_setup(udc_controller, i * 2 + 1, name, 1);
}
+ poller_register(&poller);
+
return 0;
err_out:
return ret;
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f6a712b1c4..98a501b891 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -4,6 +4,7 @@
#include <usb/ch9.h>
#include <usb/gadget.h>
#include <usb/composite.h>
+#include <usb/usbserial.h>
#include <asm/byteorder.h>
#include "u_serial.h"
@@ -52,7 +53,9 @@ static struct usb_gadget_strings *dev_strings[] = {
};
static int use_acm = 1;
+#ifdef HAVE_OBEX
static int use_obex = 0;
+#endif
static unsigned n_ports = 1;
static int serial_bind_config(struct usb_configuration *c)
@@ -63,8 +66,10 @@ static int serial_bind_config(struct usb_configuration *c)
for (i = 0; i < n_ports && status == 0; i++) {
if (use_acm)
status = acm_bind_config(c, i);
+#ifdef HAVE_OBEX
else if (use_obex)
status = obex_bind_config(c, i);
+#endif
else
status = gser_bind_config(c, i);
}
@@ -100,7 +105,7 @@ static int gs_bind(struct usb_composite_dev *cdev)
int gcnum;
struct usb_gadget *gadget = cdev->gadget;
int status;
-printf("%s\n", __func__);
+
status = gserial_setup(cdev->gadget, n_ports);
if (status < 0)
return status;
@@ -174,24 +179,56 @@ static struct usb_composite_driver gserial_driver = {
.bind = gs_bind,
};
-static int __init gserial_init(void)
+int usb_serial_register(struct usb_serial_pdata *pdata)
{
/* We *could* export two configs; that'd be much cleaner...
* but neither of these product IDs was defined that way.
*/
+
+ /*
+ * PXA CPU suffer a silicon bug which prevents them from being a
+ * compound device, forbiding the ACM configurations.
+ */
+#ifdef CONFIG_ARCH_PXA2XX
+ use_acm = 0;
+#endif
+ switch (pdata->mode) {
+ case 1:
+#ifdef HAVE_OBEX
+ use_obex = 1;
+#endif
+ use_acm = 0;
+ break;
+ case 2:
+#ifdef HAVE_OBEX
+ use_obex = 1;
+#endif
+ use_acm = 0;
+ break;
+ default:
+#ifdef HAVE_OBEX
+ use_obex = 0;
+#endif
+ use_acm = 1;
+ }
+
if (use_acm) {
serial_config_driver.label = "CDC ACM config";
serial_config_driver.bConfigurationValue = 2;
device_desc.bDeviceClass = USB_CLASS_COMM;
device_desc.idProduct =
cpu_to_le16(GS_CDC_PRODUCT_ID);
- } else if (use_obex) {
+ }
+#ifdef HAVE_OBEX
+ else if (use_obex) {
serial_config_driver.label = "CDC OBEX config";
serial_config_driver.bConfigurationValue = 3;
device_desc.bDeviceClass = USB_CLASS_COMM;
device_desc.idProduct =
cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
- } else {
+ }
+#endif
+ else {
serial_config_driver.label = "Generic Serial config";
serial_config_driver.bConfigurationValue = 1;
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
@@ -199,9 +236,17 @@ static int __init gserial_init(void)
cpu_to_le16(GS_PRODUCT_ID);
}
strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
+ if (pdata->idVendor)
+ device_desc.idVendor = pdata->idVendor;
+ if (pdata->idProduct)
+ device_desc.idProduct = pdata->idProduct;
+ strings_dev[STRING_MANUFACTURER_IDX].s = pdata->manufacturer;
+ strings_dev[STRING_PRODUCT_IDX].s = pdata->productname;
return usb_composite_register(&gserial_driver);
}
-late_initcall(gserial_init);
-
+void usb_serial_unregister(void)
+{
+ usb_composite_unregister(&gserial_driver);
+}
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 49aedc23ef..e310c3ae1d 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -20,6 +20,7 @@
#include <common.h>
#include <usb/cdc.h>
#include <kfifo.h>
+#include <clock.h>
#include "u_serial.h"
@@ -107,8 +108,6 @@ static unsigned n_ports;
#define GS_CLOSE_TIMEOUT 15 /* seconds */
-
-
#ifdef VERBOSE_DEBUG
#define pr_vdebug(fmt, arg...) \
pr_debug(fmt, ##arg)
@@ -370,6 +369,7 @@ static void serial_putc(struct console_device *cdev, char c)
struct usb_ep *in;
struct usb_request *req;
int status;
+ uint64_t to;
if (list_empty(pool))
return;
@@ -382,8 +382,12 @@ static void serial_putc(struct console_device *cdev, char c)
*(unsigned char *)req->buf = c;
status = usb_ep_queue(in, req);
- while (status >= 0 && list_empty(pool))
+ to = get_time_ns();
+ while (status >= 0 && list_empty(pool)) {
status = usb_gadget_poll();
+ if (is_timeout(to, 300 * MSECOND))
+ break;
+ }
}
static int serial_tstc(struct console_device *cdev)
@@ -399,11 +403,16 @@ static int serial_getc(struct console_device *cdev)
struct gs_port *port = container_of(cdev,
struct gs_port, cdev);
unsigned char ch;
+ uint64_t to;
if (!port->port_usb)
return -EIO;
- while (kfifo_getc(port->recv_fifo, &ch))
+ to = get_time_ns();
+ while (kfifo_getc(port->recv_fifo, &ch)) {
usb_gadget_poll();
+ if (is_timeout(to, 300 * MSECOND))
+ break;
+ }
return ch;
}
@@ -420,8 +429,6 @@ int gserial_connect(struct gserial *gser, u8 port_num)
int status;
struct console_device *cdev;
- printf("%s %p %d\n", __func__, gser, port_num);
-
/* we "know" gserial_cleanup() hasn't been called */
port = ports[port_num].port;
@@ -451,7 +458,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
port->recv_fifo = kfifo_alloc(1024);
- printf("gserial_connect: start ttyGS%d\n", port->port_num);
+ /*printf("gserial_connect: start ttyGS%d\n", port->port_num);*/
gs_start_io(port);
if (gser->connect)
gser->connect(gser);
@@ -508,7 +515,6 @@ void gserial_disconnect(struct gserial *gser)
struct gs_port *port = gser->ioport;
struct console_device *cdev;
- printf("%s\n", __func__);
if (!port)
return;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 96e09e28a0..439d8ebbb4 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -3,6 +3,7 @@ config USB_EHCI
config USB_EHCI_OMAP
depends on ARCH_OMAP3
+ depends on USB_TWL4030
bool "OMAP EHCI driver"
config USB_OHCI
diff --git a/drivers/usb/otg/twl4030.c b/drivers/usb/otg/twl4030.c
index 40771699ea..123f0a52ac 100644
--- a/drivers/usb/otg/twl4030.c
+++ b/drivers/usb/otg/twl4030.c
@@ -118,10 +118,10 @@ static void twl4030_usb_ldo_init(void)
twl4030_reg_write(twl4030, TWL4030_PM_RECEIVER_VUSB1V8_TYPE, 0x00);
/* disable access to power configuration registers */
- twl4030_reg_write(twl4030, TWL4030_PM_MASTER_PROTECT_KEY, 0x0 );
-
- twl4030_reg_write(twl4030, TWL4030_BASEADD_LED, 0x33); /* FIXME *need to enable LED to get USB power? */
+ twl4030_reg_write(twl4030, TWL4030_PM_MASTER_PROTECT_KEY, 0x0);
+ /* FIXME *need to enable LED to get USB power? */
+ twl4030_reg_write(twl4030, TWL4030_BASEADD_LED, 0x33);
}
static void twl4030_phy_power(void)