[PATCH] Add Freescale high-speed USB DR module device driver
Li Yang
leoli at freescale.com
Fri Jul 14 20:58:04 EST 2006
Freescale high-speed USB SOC can be found on MPC834x and probably more in the future. Its DR(dual-role) module can work as a USB device. This patch adds its support for Linux USB Gadget.
Signed-off-by: Li Yang <leoli at freescale.com>
Signed-off-by: Jiang Bo <Tanya.jiang at freescale.com>
---
This is a resubmission. The first version of the driver is posted on the lists in Aug, 2005. This version adds OTG support (needs separated OTG patch), works with latest gadget drivers and powerpc arch, and some minor fixes.
drivers/usb/gadget/Kconfig | 21
drivers/usb/gadget/Makefile | 1
drivers/usb/gadget/fsl_usb2_udc.c | 2529 +++++++++++++++++++++++++++++++++++++
drivers/usb/gadget/fsl_usb2_udc.h | 608 +++++++++
drivers/usb/gadget/gadget_chips.h | 8
5 files changed, 3167 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 363b2ad..598c200 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -68,6 +68,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_FSL_USB2
+ boolean "Freescale MPC834x DR"
+ depends on MPC834x
+ select USB_GADGET_DUALSPEED
+ help
+ Some of Freescale PowerPC processors have a High Speed
+ Dual-Role(DR) USB controller, which support device mode
+ with 5 programmable endpoints. This driver supports the
+ controller in the MPC834x, and should work with DR module
+ in other Freescale processors too, given minor tweaks.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "fsl_usb2_udc" and force
+ all gadget drivers to also be dynamically linked.
+
+config USB_FSL_USB2
+ tristate
+ depends on USB_GADGET_FSL_USB2
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_NET2280
boolean "NetChip 228x"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5a28e61..c283e5e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
+obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
new file mode 100644
index 0000000..3bea88f
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -0,0 +1,2529 @@
+/*
+ * Copyright (C) 2004-2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli at freescale.com>
+ * Jiang Bo <tanya.jiang at freescale.com>
+ *
+ * Description:
+ * Freescale high-speed USB SOC DR module device controller driver.
+ * This SOC can be found on MPC8349E cpu. The driver is previously named
+ * as mpc_udc.c. Based on bare board code from Dave Liu and Shlomi Gridish.
+ *
+ * Note: The driver will not work with old gadget drivers, as the API
+ * parameter endian has changed.
+ *
+ * Changelog:
+ * Aug 1, 2005
+ * - Initial Version
+ * Jul 13, 2006 Li Yang <LeoLi at freescale.com>
+ * - adopted to powerpc arch and gadget drivers in latest kernel
+ * - add otg support, and minor style fixes
+ *
+ * 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 DEBUG
+#undef VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb_otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+#include "fsl_usb2_udc.h"
+
+#undef USB_TRACE
+
+#define DRIVER_DESC "Freescale PowerPC USB2 DR Device Controller driver"
+#define DRIVER_AUTHOR "Li Yang/Jiang Bo"
+#define DRIVER_VERSION "Jul 13, 2006"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+static const char driver_name[] = "fsl-usb2-dr-udc";
+#else
+static const char driver_name[] = "fsl-usb2-dr";
+#endif
+static const char driver_desc[] = DRIVER_DESC;
+
+volatile static struct usb_dr_device *usb_slave_regs = NULL;
+volatile static struct usb_sys_interface *usb_sys_regs = NULL;
+
+/* it is initialized in probe() */
+static struct mpc_udc *udc_controller = NULL;
+
+/* ep_qh_base store the base address before 2K align */
+static struct ep_queue_head *ep_qh_base = NULL;
+
+/*ep name is important in gadget, it should obey the convention of ep_match()*/
+static const char *const ep_name[] = {
+ "ep0-control", NULL, /* everyone has ep0 */
+ /* 5 configurable endpoints */
+ "ep1out",
+ "ep1in",
+ "ep2out",
+ "ep2in",
+ "ep3out",
+ "ep3in",
+ "ep4out",
+ "ep4in",
+ "ep5out",
+ "ep5in"
+};
+static struct usb_endpoint_descriptor
+mpc_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+};
+
+static int mpc_udc_suspend(struct platform_device *pdev, pm_message_t state);
+static int mpc_udc_resume(struct platform_device *pdev);
+
+/********************************************************************
+ * Internal Used Function
+********************************************************************/
+/*-----------------------------------------------------------------
+ * done() - retire a request; caller blocked irqs
+ * @status : when req->req.status is -EINPROGRESSS, it is input para
+ * else it will be a output parameter
+ * req->req.status : in ep_queue() it will be set as -EINPROGRESS
+ *--------------------------------------------------------------*/
+static void done(struct mpc_ep *ep, struct mpc_req *req, int status)
+{
+ struct mpc_udc *udc = NULL;
+ unsigned char stopped = ep->stopped;
+
+ udc = (struct mpc_udc *) ep->udc;
+ /* the req->queue pointer is used by ep_queue() func, in which
+ * the request will be added into a udc_ep->queue 'd tail
+ * so here the req will be dropped from the ep->queue
+ */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ if (status && (status != -ESHUTDOWN))
+ VDBG("complete %s req %p stat %d len %u/%u",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+
+ spin_unlock(&ep->udc->lock);
+ /* this complete() should a func implemented by gadget layer,
+ * eg fsg->bulk_in_complete() */
+ if (req->req.complete)
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock(&ep->udc->lock);
+ ep->stopped = stopped;
+}
+
+/*-----------------------------------------------------------------
+ * nuke(): delete all requests related to this ep
+ * called by ep_disable() within spinlock held
+ * add status paramter?
+ *--------------------------------------------------------------*/
+static void nuke(struct mpc_ep *ep, int status)
+{
+ ep->stopped = 1;
+
+ /* Whether this eq has request linked */
+ while (!list_empty(&ep->queue)) {
+ struct mpc_req *req = NULL;
+
+ req = list_entry(ep->queue.next, struct mpc_req, queue);
+ done(ep, req, status);
+ }
+}
+
+/*------------------------------------------------------------------
+ Internal Hardware related function
+ ------------------------------------------------------------------*/
+
+/* @qh_addr is the aligned virt addr of ep QH addr
+ * it is used to set endpointlistaddr Reg */
+static int dr_controller_setup(void *qh_addr)
+{
+ unsigned int tmp = 0, portctrl = 0, ctrl = 0;
+
+ /* before here, make sure usb_slave_regs has been initialized */
+ if (!qh_addr)
+ return -EINVAL;
+
+ /* Stop and reset the usb controller */
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = cpu_to_le32(tmp);
+
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp |= USB_CMD_CTRL_RESET;
+ usb_slave_regs->usbcmd = cpu_to_le32(tmp);
+ /* Wait reset completed */
+ while (le32_to_cpu(usb_slave_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+ }
+
+ /* Set the controller as device mode */
+ tmp = le32_to_cpu(usb_slave_regs->usbmode);
+ tmp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ tmp |= USB_MODE_SETUP_LOCK_OFF;
+ usb_slave_regs->usbmode = cpu_to_le32(tmp);
+
+ /* Clear the setup status */
+ usb_slave_regs->usbsts = 0;
+
+ tmp = virt_to_phys(qh_addr);
+ tmp &= USB_EP_LIST_ADDRESS_MASK;
+ usb_slave_regs->endpointlistaddr = cpu_to_le32(tmp);
+
+ VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+ qh_addr, (int)tmp, le32_to_cpu(usb_slave_regs->
+ endpointlistaddr));
+
+ /* Config PHY interface as ULPI for DR */
+ portctrl = le32_to_cpu(usb_slave_regs->portsc1);
+
+ portctrl &= ~PORTSCX_PHY_TYPE_SEL;
+ portctrl |= PORTSCX_PTS_ULPI;
+ usb_slave_regs->portsc1 = cpu_to_le32(portctrl);
+
+ /* Config control enable i/o output, big endian register */
+ ctrl = usb_sys_regs->control;
+ ctrl |= USB_CTRL_IOENB;
+ usb_sys_regs->control = ctrl;
+
+ /* Config snooping, keep the cache consistent
+ * Snoop between 0x0 and 1GB */
+ tmp = 0;
+ tmp &= SNOOP_ADDRESS_MASK;
+ usb_sys_regs->snoop1 = tmp | SNOOP_SIZE_1GB;
+
+ return 0;
+}
+
+/* just Enable DR irq reg and Set Dr controller Run */
+static void dr_controller_run(struct mpc_udc *udc)
+{
+ u32 temp;
+
+ /*Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN |
+ USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN |
+ USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ usb_slave_regs->usbintr = le32_to_cpu(temp);
+
+ /* Clear stopped bit */
+ udc->stopped = 0;
+
+ /* Set the controller as device mode */
+ temp = le32_to_cpu(usb_slave_regs->usbmode);
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ usb_slave_regs->usbmode = cpu_to_le32(temp);
+
+
+ /* Set controller to Run */
+ temp = le32_to_cpu(usb_slave_regs->usbcmd);
+ temp |= USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = le32_to_cpu(temp);
+
+ return;
+}
+
+static void dr_controller_stop(struct mpc_udc *udc)
+{
+ unsigned int tmp;
+
+ /* disable all INTR */
+ usb_slave_regs->usbintr = 0;
+
+ /* Set stopped bit for isr */
+ udc->stopped = 1;
+
+ /* disable IO output */
+/* usb_sys_regs->control = 0; */
+
+ /* set controller to Stop */
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = le32_to_cpu(tmp);
+
+ return;
+}
+
+void dr_ep_setup(unsigned char ep_num, unsigned char dir,
+ unsigned char ep_type)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = le32_to_cpu(usb_slave_regs->endptctrl[ep_num]);
+ if (dir) {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_TX_ENABLE;
+ 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 |=
+ ((unsigned int) (ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+
+ usb_slave_regs->endptctrl[ep_num] = cpu_to_le32(tmp_epctrl);
+
+ /* wait the write reg finished */
+ while (!(le32_to_cpu(usb_slave_regs->endptctrl[ep_num]) &
+ (tmp_epctrl & (EPCTRL_TX_ENABLE | EPCTRL_RX_ENABLE))));
+}
+
+static void dr_ep_change_stall(unsigned char ep_num, unsigned char dir,
+ int value)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = le32_to_cpu(usb_slave_regs->endptctrl[ep_num]);
+
+ if (value) {
+ /* set the stall bit */
+ if (dir)
+ tmp_epctrl |= EPCTRL_TX_EP_STALL;
+ else
+ tmp_epctrl |= EPCTRL_RX_EP_STALL;
+ } else {
+ /* clear the stall bit and reset data toggle */
+ if (dir) {
+ tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ }
+ else {
+ tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ }
+ }
+ usb_slave_regs->endptctrl[ep_num] = cpu_to_le32(tmp_epctrl);
+}
+
+/********************************************************************
+ Internal Structure Build up functions
+********************************************************************/
+
+/*------------------------------------------------------------------
+* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select
+ * @mult: Mult field
+ ------------------------------------------------------------------*/
+static void struct_ep_qh_setup(void *handle, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type,
+ unsigned int max_pkt_len,
+ unsigned int zlt, unsigned char mult)
+{
+ struct mpc_udc *udc = NULL;
+ struct ep_queue_head *p_QH = NULL;
+ unsigned int tmp = 0;
+
+ udc = (struct mpc_udc *) handle;
+
+ p_QH = &udc->ep_qh[2 * ep_num + dir];
+
+ /* set the Endpoint Capabilites Reg of QH */
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* Interrupt On Setup (IOS). for control ep */
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) |
+ EP_QUEUE_HEAD_IOS;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) |
+ (mult << EP_QUEUE_HEAD_MULT_POS);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+ if (zlt)
+ tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+ break;
+ default:
+ VDBG("error ep type is %d",ep_type);
+ return;
+ }
+ p_QH->max_pkt_length = le32_to_cpu(tmp);
+ flush_dcache_range((unsigned long)p_QH, (unsigned long)p_QH +
+ sizeof(struct ep_queue_head));
+
+ return;
+}
+
+/* This function only to make code looks good
+ * it is a collection of struct_ep_qh_setup and dr_ep_setup for ep0
+ * ep0 should set OK before the bind() of gadget layer
+ */
+static void ep0_dr_and_qh_setup(struct mpc_udc *udc)
+{
+ /* the intialization of an ep includes: fields in QH, Regs,
+ * mpc_ep struct */
+ struct_ep_qh_setup(udc, 0, USB_RECV,
+ USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD,
+ 0, 0);
+ struct_ep_qh_setup(udc, 0, USB_SEND,
+ USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD,
+ 0, 0);
+ dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+ return;
+
+}
+
+/***********************************************************************
+ Endpoint Management Functions
+***********************************************************************/
+
+/*-------------------------------------------------------------------------
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 will not use this func it is enable in probe()
+-------------------------------------------------------------------------*/
+static int mpc_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct mpc_udc *udc = NULL;
+ struct mpc_ep *ep = NULL;
+ unsigned short max = 0;
+ unsigned char mult = 0, zlt = 0;
+ int retval = 0;
+ unsigned long flags = 0;
+ char *val = NULL; /* for debug */
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+
+ /* catch various bogus parameters */
+ if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT))
+ /* FIXME: add judge for ep->bEndpointAddress */
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+ retval = -EINVAL;
+
+ /* check the max package size validate for this endpoint */
+ /* Refer to USB2.0 spec table 9-13,
+ */
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if ((max == 128) || (max == 256) || (max == 512))
+ break;
+ default:
+ switch (max) {
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ case USB_SPEED_LOW:
+ goto en_done;
+ }
+ }
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 64)
+ break;
+ default:
+ if (max <= 8)
+ break;
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (strstr(ep->ep.name, "-bulk") || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = (unsigned char) (1 +((le16_to_cpu(desc->wMaxPacketSize)
+ >> 11) & 0x03));
+ zlt = 0;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 1023)
+ break;
+ default:
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ goto en_done;
+ }
+ case USB_SPEED_LOW:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ goto en_done;
+ }
+ default:
+ goto en_done;
+ }
+ break;
+
+ default:
+ goto en_done;
+ }
+
+ /* here initialize variable of ep */
+ spin_lock_irqsave(&udc->lock, flags);
+ ep->ep.maxpacket = max;
+ ep->desc = desc;
+ ep->stopped = 0;
+
+ /* hardware special operation */
+
+ /* Init EPx Queue Head (Ep Capabilites field in QH
+ * according to max, zlt, mult) */
+ struct_ep_qh_setup((void *) udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->
+ bEndpointAddress & USB_DIR_IN) ?
+ USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK),
+ max, zlt, mult);
+
+ /* Init endpoint x at here */
+ /* 83xx RM chapter 16.3.2.24, here init the endpoint ctrl reg */
+ dr_ep_setup((unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK));
+
+ /* Now HW will be NAKing transfers to that EP,
+ * until a buffer is queued to it. */
+
+ /* should have stop the lock */
+ spin_unlock_irqrestore(&udc->lock, flags);
+ retval = 0;
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ val = "bulk";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ val = "iso";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ val = "intr";
+ break;
+ default:
+ val = "ctrl";
+ break;
+ }
+
+ VDBG("enabled %s (ep%d%s-%s) maxpacket %d",ep->ep.name,
+ ep->desc->bEndpointAddress & 0x0f,
+ (desc->bEndpointAddress & USB_DIR_IN) ?
+ "in" : "out", val, max);
+en_done:
+ return retval;
+}
+
+/*---------------------------------------------------------------------
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+*---------------------------------------------------------------------*/
+static int mpc_ep_disable(struct usb_ep *_ep)
+{
+ struct mpc_udc *udc = NULL;
+ struct mpc_ep *ep = NULL;
+ unsigned long flags = 0;
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+ if (!_ep || !ep->desc) {
+ VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ udc = (struct mpc_udc *) ep->udc;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ VDBG("disabled %s OK", _ep->name);
+ return 0;
+}
+
+/*---------------------------------------------------------------------
+ * allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static struct usb_request *mpc_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct mpc_req *req = NULL;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void mpc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mpc_req *req = NULL;
+
+ req = container_of(_req, struct mpc_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+/*------------------------------------------------------------------
+ * Allocate an I/O buffer for the ep->req->buf
+ * @len: length of the desired buffer
+ * @dma: pointer to the buffer's DMA address; must be valid
+ * when gadget layer calls this function, ma is &req->dma
+ * @gfp_flags : GFP_* flags to use
+ * Returns a new buffer, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static void *mpc_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+ dma_addr_t * dma, gfp_t gfp_flags)
+{
+ void *retval = NULL;
+
+ if (!bytes)
+ return 0;
+
+ retval = kmalloc(bytes, gfp_flags);
+ if (retval)
+ *dma = virt_to_phys(retval);
+ return retval;
+}
+
+/*------------------------------------------------------------------
+ * Free an I/O buffer for the ep->req->buf
+ * @dma:for 834x, we will not touch dma field
+*---------------------------------------------------------------------*/
+static void mpc_free_buffer(struct usb_ep *_ep, void *buf,
+ dma_addr_t dma, unsigned bytes)
+{
+ if (buf)
+ kfree(buf);
+}
+
+/*-------------------------------------------------------------------------*/
+static int mpc_queue_td(struct mpc_ep *ep, struct mpc_req *req)
+{
+ int i = ep_index(ep) * 2 + ep_is_in(ep);
+ u32 temp, bitmask, tmp_stat;
+ struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+
+ //VDBG("QH addr Register 0x%8x", usb_slave_regs->endpointlistaddr);
+ //VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i]));
+
+ bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ /* check if the pipe is empty */
+ if (!(list_empty(&ep->queue))) {
+ /* Add td to the end */
+ struct mpc_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct mpc_req, queue);
+ lastreq->tail->next_td_ptr =
+ cpu_to_le32(virt_to_phys(req->head) & DTD_ADDR_MASK);
+
+ /* Read prime bit, if 1 goto done */
+ if (usb_slave_regs->endpointprime & cpu_to_le32(bitmask))
+ goto out;
+
+ do {
+ /* Set ATDTW bit in USBCMD */
+ usb_slave_regs->usbcmd |=
+ cpu_to_le32(USB_CMD_ATDTW);
+
+ /* Read correct status bit */
+ tmp_stat = le32_to_cpu(usb_slave_regs->
+ endptstatus) & bitmask;
+
+ } while (!(usb_slave_regs->
+ usbcmd & cpu_to_le32(USB_CMD_ATDTW)));
+
+ /* Write ATDTW bit to 0 */
+ usb_slave_regs->usbcmd &= cpu_to_le32(~USB_CMD_ATDTW);
+
+ if (tmp_stat)
+ goto out;
+ }
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ temp = virt_to_phys((void *)req->head) &
+ EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ dQH->next_dtd_ptr = cpu_to_le32(temp);
+
+ /* Clear active and halt bit */
+ temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE |
+ EP_QUEUE_HEAD_STATUS_HALT));
+ dQH->size_ioc_int_sts &= temp;
+ flush_dcache_range((unsigned long)dQH,(unsigned long)dQH +
+ sizeof(struct ep_queue_head));
+
+ /* Prime endpoint by writing 1 to ENDPTPRIME */
+ temp = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ usb_slave_regs->endpointprime = cpu_to_le32(temp);
+out:
+ return 0;
+}
+
+static int
+mpc_build_dtd (struct mpc_req *req, unsigned max, struct ep_td_struct **address)
+{
+ unsigned length;
+ u32 swap_temp;
+ struct ep_td_struct *dtd;
+
+ /* how big will this packet be? */
+ length = min(req->req.length - req->req.actual, max);
+
+ /* Assume CACHELINE alignment garantees 32-byte alignment */
+ dtd = kzalloc(sizeof(struct ep_td_struct), GFP_KERNEL);
+ /* check alignment */
+ if ((u32) dtd & ~DTD_ADDR_MASK)
+ panic("Can not allocate aligned memory for dtd");
+
+ /* Fill in the transfer size; set interrupt on every dtd;
+ set active bit */
+ swap_temp = ((length << DTD_LENGTH_BIT_POS) | DTD_IOC
+ | DTD_STATUS_ACTIVE);
+
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Clear reserved field */
+ swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Init all of buffer page pointers */
+ swap_temp = (u32) (req->req.dma + req->req.actual);
+ dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+ dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+ req->req.actual += length;
+ *address = dtd;
+ VDBG("length = %d address= 0x%x", length, (int) dtd);
+
+ return length;
+}
+
+static int
+mpc_req_to_dtd (struct mpc_req *req)
+{
+ unsigned max;
+ unsigned count;
+ int is_last;
+ int is_first =1;
+ struct ep_td_struct *last_addr = NULL, *addr;
+
+ max = EP_MAX_LENGTH_TRANSFER;
+ do {
+ count = mpc_build_dtd(req, max, &addr);
+
+ if (is_first) {
+ is_first = 0;
+ req->head = addr;
+ }
+ else {
+ last_addr->next_td_ptr
+ = cpu_to_le32(virt_to_phys(addr));
+ flush_dcache_range((unsigned long)last_addr,
+ (unsigned long)last_addr +
+ sizeof(struct ep_td_struct));
+ last_addr = addr;
+ }
+ /* last packet is usually short (or a zlp) */
+ if (unlikely (count != max))
+ is_last = 1;
+ else if (likely(req->req.length != req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+
+ req->dtd_count ++;
+ }while(!is_last);
+
+ addr->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+ flush_dcache_range((unsigned long)addr, (unsigned long)addr +
+ sizeof(struct ep_td_struct));
+
+ req->tail = addr;
+
+ return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+mpc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct mpc_ep *ep = container_of(_ep, struct mpc_ep, ep);
+ struct mpc_req *req = container_of(_req, struct mpc_req, req);
+ struct mpc_udc *udc;
+ unsigned long flags;
+ int is_iso = 0;
+
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue) ) {
+ VDBG("%s, bad params\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (!_ep || (!ep->desc && ep_index(ep))) {
+ VDBG("%s, bad ep\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (req->req.length > ep->ep.maxpacket)
+ return -EMSGSIZE;
+ is_iso = 1;
+ }
+
+ udc = ep->udc;
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->dtd_count = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* push the dtds to device queue */
+ if (!mpc_req_to_dtd(req))
+ mpc_queue_td(ep, req);
+
+ /* EP0 */
+ if ((ep_index(ep) == 0))
+ udc->ep0_state = DATA_STATE_XMIT;
+
+ /* irq handler advances the queue */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int mpc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mpc_ep *ep = container_of(_ep, struct mpc_ep, ep);
+ struct mpc_req *req;
+ unsigned long flags;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ /* 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) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return 0;
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt 0--clear halt
+ * Returns zero, or a negative error code.
+*----------------------------------------------------------------*/
+static int _mpc_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct mpc_ep *ep = NULL;
+ unsigned long flags = 0;
+ int status = -EOPNOTSUPP; /* operation not supported */
+ unsigned char ep_dir = 0, ep_num = 0;
+ struct mpc_udc *udc = NULL;
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+ udc = ep->udc;
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ status = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Attemp to halt IN ep will fail if any transfer requests
+ are still queue */
+ if ( value && ep_is_in(ep) && !list_empty(&ep->queue) ) {
+
+ status = -EAGAIN;
+ goto out;
+ }
+
+ status = 0;
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ ep_num = (unsigned char) (ep_index(ep));
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ dr_ep_change_stall(ep_num, ep_dir, value);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if ( ep_index(ep) == 0 )
+ {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+out:
+ VDBG(" %s %s halt stat %d", ep->ep.name, value ?
+ "set" : "clear", status);
+
+ return status;
+}
+
+static int mpc_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ return (_mpc_ep_set_halt(_ep, value));
+}
+
+static struct usb_ep_ops mpc_ep_ops = {
+ .enable = mpc_ep_enable,
+ .disable = mpc_ep_disable,
+
+ .alloc_request = mpc_alloc_request,
+ .free_request = mpc_free_request,
+
+ .alloc_buffer = mpc_alloc_buffer,
+ .free_buffer = mpc_free_buffer,
+
+ .queue = mpc_ep_queue,
+ .dequeue = mpc_ep_dequeue,
+
+ .set_halt = mpc_ep_set_halt,
+// .fifo_status = mpc_ep_fifo_status, /* report bytes in fifo */
+// .fifo_flush = mpc_ep_fifo_flush, /* flush fifo */
+};
+
+/*-------------------------------------------------------------------------
+ Gadget Driver Layer Operations
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+ * Get the current frame number (from DR frame_index Reg )
+ *----------------------------------------------------------------------*/
+static int mpc_get_frame(struct usb_gadget *gadget)
+{
+ return (int) (le32_to_cpu(usb_slave_regs->frindex) &
+ USB_FRINDEX_MASKS);
+}
+
+/*-----------------------------------------------------------------------
+ * Tries to wake up the host connected to this gadget
+ *
+ * Return : 0-success
+ * Negative-this feature not enabled by host or not supported by device hw
+ * FIXME: RM 16.6.2.2.1 DR support this wake-up feature?
+ -----------------------------------------------------------------------*/
+static int mpc_wakeup(struct usb_gadget *gadget)
+{
+ return -ENOTSUPP;
+}
+
+/* sets the device selfpowered feature
+ * this affects the device status reported by the hw driver
+ * to reflect that it now has a local power supply
+ * usually device hw has register for this feature
+ */
+static int
+mpc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ return -ENOTSUPP;
+}
+
+static int can_pullup(struct mpc_udc *udc)
+{
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+/* Notify controller that VBUS is powered, Called by whatever
+ detects VBUS sessions */
+static int mpc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct mpc_udc *udc;
+ unsigned long flags;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+ VDBG("VBUS %s\n", is_active ? "on" : "off");
+ udc->vbus_active = (is_active != 0);
+ if (can_pullup(udc))
+ usb_slave_regs->usbcmd |= USB_CMD_RUN_STOP;
+ else
+ usb_slave_regs->usbcmd &= ~USB_CMD_RUN_STOP;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return 0;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume. For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int mpc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct mpc_udc *udc;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+
+ if (udc->transceiver)
+ return otg_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnet
+ */
+static int mpc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct mpc_udc *udc;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+ udc->softconnect = (is_on != 0);
+ if (can_pullup(udc))
+ usb_slave_regs->usbcmd |= USB_CMD_RUN_STOP;
+ else
+ usb_slave_regs->usbcmd &= ~USB_CMD_RUN_STOP;
+
+ return 0;
+}
+
+/* defined in usb_gadget.h */
+static struct usb_gadget_ops mpc_gadget_ops = {
+ .get_frame = mpc_get_frame,
+ .wakeup = mpc_wakeup,
+ .set_selfpowered = mpc_set_selfpowered,
+ .vbus_session = mpc_vbus_session,
+ .vbus_draw = mpc_vbus_draw,
+ .pullup = mpc_pullup,
+};
+
+static void Ep0Stall(struct mpc_udc *udc)
+{
+ u32 tmp;
+
+ /* a protocol stall */
+ tmp = le32_to_cpu(usb_slave_regs->endptctrl[0]);
+ tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ usb_slave_regs->endptctrl[0] = cpu_to_le32(tmp);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+}
+
+/* if direction is EP_IN, the status is Device->Host
+ * if direction is EP_OUT, the status transaction is Device<-Host
+ */
+static int ep0_prime_status(struct mpc_udc *udc, int direction)
+{
+ struct mpc_req *req = udc->status_req;
+ struct mpc_ep *ep;
+ int status = 0;
+
+ if (direction == EP_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ ep = &udc->eps[0];
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+
+ req->ep = ep;
+ req->req.length = 0;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ if ((mpc_req_to_dtd(req) == 0))
+ status = mpc_queue_td(ep, req);
+ if (status)
+ printk("Can't get control status request \n");
+ list_add_tail(&req->queue, &ep->queue);
+
+ return status;
+}
+
+static int udc_reset_ep_queue(struct mpc_udc *udc, u8 pipe)
+{
+ struct mpc_ep *ep = get_ep_by_pipe(udc, pipe);
+
+ /* FIXME: collect completed requests? */
+ if (!ep->name)
+ return 0;
+
+ nuke(ep, -ECONNRESET);
+
+ return 0;
+}
+
+/*
+ * ch9 Set address
+ */
+static void ch9SetAddress(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ /* Save the new address to device struct */
+ udc->device_address = (u8) value;
+ /* Update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+ /* Status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+}
+
+/*
+ * ch9 Get status
+ */
+static void ch9GetStatus(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ u16 usb_status = 0; /* fix me to give correct status */
+
+ struct mpc_req *req;
+ struct mpc_ep *ep;
+ int status = 0;
+
+ ep = &udc->eps[0];
+
+ req = container_of(mpc_alloc_request(&ep->ep, GFP_KERNEL),
+ struct mpc_req, req);
+ req->req.length = 2;
+ req->req.buf = &usb_status;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+
+ /* data phase */
+ if ((mpc_req_to_dtd(req) == 0))
+ status = mpc_queue_td(ep, req);
+ if (status) {
+ printk("Can't respond to getstatus request \n");
+ Ep0Stall(udc);
+ } else
+ udc->ep0_state = DATA_STATE_XMIT;
+}
+
+/*
+ * ch9 Set config
+ */
+static void ch9SetConfig(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) >= 0)
+ {
+ /* gadget layer deal with the status phase */
+ udc->usb_state = USB_STATE_CONFIGURED;
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+}
+
+static void setup_received_irq(struct mpc_udc *udc,
+ struct usb_ctrlrequest *setup)
+{
+ u16 wValue = le16_to_cpu(setup->wValue);
+ u16 wIndex = le16_to_cpu(setup->wIndex);
+ u16 wLength = le16_to_cpu(setup->wLength);
+
+ udc_reset_ep_queue(udc, 0);
+
+ /* We asume setup only occurs on EP0 */
+ if (setup->bRequestType & USB_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ switch (setup->bRequest) {
+ case USB_BULK_RESET_REQUEST:
+ if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
+ break;
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) >= 0)
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case USB_REQ_GET_STATUS:
+ if ((setup-> bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9GetStatus(udc, wValue, wIndex, wLength);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ ch9SetAddress(udc, wValue, wIndex, wLength);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ /* gadget layer take over the status phase */
+ ch9SetConfig(udc, wValue, wIndex, wLength);
+ break;
+ case USB_REQ_SET_INTERFACE:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_INTERFACE))
+ break;
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) >= 0)
+ /* gadget layer take over the status phase */
+ break;
+ /* Requests with no data phase */
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ { /* status transaction */
+ int rc = -EOPNOTSUPP;
+
+ if (setup->bRequestType == USB_RECIP_ENDPOINT) {
+ int dir = (wIndex & 0x0080) ?
+ EP_DIR_IN: EP_DIR_OUT;
+ int num = (wIndex & 0x000f);
+ struct mpc_ep *ep;
+
+ if (wValue != 0 || wLength != 0
+ || (num *2 + dir) > USB_MAX_PIPES)
+ break;
+ ep = &udc->eps[num*2+dir];
+
+ if (setup->bRequest == USB_REQ_SET_FEATURE) {
+ rc = _mpc_ep_set_halt(&ep->ep, 1);
+ }
+ else {
+ rc = _mpc_ep_set_halt(&ep->ep, 0);
+ }
+
+ } else if (setup->bRequestType == USB_RECIP_DEVICE) {
+ if (!udc->gadget.is_otg)
+ break;
+ else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+ udc->gadget.b_hnp_enable = 1;
+ else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+ udc->gadget.a_hnp_support = 1;
+ else if (setup->bRequest ==
+ USB_DEVICE_A_ALT_HNP_SUPPORT)
+ udc->gadget.a_alt_hnp_support = 1;
+ rc = 0;
+ }
+ if (rc == 0) {
+ /* send status only if _mpc_ep_set_halt success */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+ }
+ break;
+ }
+ default:
+ if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff)
+ != 0) {
+ Ep0Stall(udc);
+ }
+ else if (setup->bRequestType & USB_DIR_IN)
+ udc->ep0_state = DATA_STATE_XMIT;
+ else
+ udc->ep0_state = DATA_STATE_RECV;
+ break;
+ }
+}
+
+static void ep0_req_complete(struct mpc_udc *udc, struct mpc_ep *ep0,
+ struct mpc_req *req)
+{
+ if (udc->usb_state == USB_STATE_ADDRESS) {
+ /* Set the new address */
+ u32 new_address = (u32) udc->device_address;
+ usb_slave_regs->deviceaddr = cpu_to_le32(new_address <<
+ USB_DEVICE_ADDRESS_BIT_POS);
+ }
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+
+ done(ep0, req, 0);
+ /* receive status phase */
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ Ep0Stall(udc);
+ break;
+
+ case DATA_STATE_RECV:
+
+ done(ep0, req, 0);
+ /* send status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+ break;
+
+ case WAIT_FOR_OUT_STATUS:
+ done(ep0, req, 0);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case WAIT_FOR_SETUP:
+ VDBG("Unexpected interrupt");
+ break;
+
+ default:
+ Ep0Stall(udc);
+ break;
+ }
+}
+
+static void tripwire_handler(struct mpc_udc *udc, u8 ep_num,
+ u8 * buffer_ptr)
+{
+ u32 temp;
+ struct ep_queue_head *qh;
+
+ qh = &udc->ep_qh[ep_num*2 + EP_DIR_OUT];
+
+ /* Clear bit in ENDPTSETUPSTAT */
+ temp = cpu_to_le32(1 << ep_num);
+ usb_slave_regs->endptsetupstat |= temp;
+
+ /* while a hazard exists when setup package arrives */
+ do {
+ /* Set Setup Tripwire */
+ temp = cpu_to_le32(USB_CMD_SUTW);
+ usb_slave_regs->usbcmd |= temp;
+
+ /* Copy the setup packet to local buffer */
+ memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+ } while (!(le32_to_cpu(usb_slave_regs->usbcmd) & USB_CMD_SUTW));
+
+ /* Clear Setup Tripwire */
+ temp = le32_to_cpu(usb_slave_regs->usbcmd);
+ temp &= ~USB_CMD_SUTW;
+ usb_slave_regs->usbcmd = le32_to_cpu(temp);
+}
+
+/*process-ep_req(): free the completed Tds for this req */
+/* FIXME: ERROR handling for multi-dtd requests */
+static int process_ep_req(struct mpc_udc *udc, int pipe,
+ struct mpc_req* curr_req)
+{
+ struct ep_td_struct *curr_td, *tmp_td;
+ int td_complete, actual, remaining_length, j, tmp;
+ int status = 0;
+ int errors = 0;
+ struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+ int direction = pipe % 2;
+
+ curr_td = curr_req->head;
+ td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ remaining_length = ((le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS);
+ actual -= remaining_length;
+
+ if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
+ DTD_ERROR_MASK)) {
+ if (errors & DTD_STATUS_HALTED) {
+ printk("dTD error %08x \n", errors);
+ /* Clear the errors and Halt condition */
+ tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
+ tmp &= ~errors;
+ curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
+ status = -EPIPE;
+ /*FIXME clearing active bit, update
+ * nextTD pointer re-prime ep */
+
+ break;
+ }
+ if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+ VDBG( "Transfer overflow");
+ status = -EPROTO;
+ break;
+ }
+ else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+ VDBG("ISO error");
+ status = -EILSEQ;
+ break;
+ }
+ else
+ printk("Unknown error has occured (0x%x)!\r\n",
+ errors);
+
+ } else if (le32_to_cpu(curr_td->size_ioc_sts) &
+ DTD_STATUS_ACTIVE) {
+ VDBG("Request not wholly complete");
+ status = REQ_UNCOMPLETE;
+ return status;
+ } else if (remaining_length)
+ if (direction) {
+ VDBG("Transmit dTD remaining length not zero");
+ status = -EPROTO;
+ break;
+ } else {
+ td_complete +=1;
+ break;
+ }
+ else {
+ td_complete += 1;
+ VDBG("dTD transmitted successful ");
+ }
+
+ if (j != curr_req->dtd_count - 1)
+ curr_td = (struct ep_td_struct*) phys_to_virt(
+ le32_to_cpu(curr_td->next_td_ptr)
+ & DTD_ADDR_MASK);
+ }
+
+ if (status)
+ return status;
+
+ curr_req->req.actual = actual;
+
+ /* Free dtd for completed/error request */
+ curr_td = curr_req->head;
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ tmp_td = curr_td;
+ if (j != curr_req->dtd_count - 1 )
+ curr_td = (struct ep_td_struct*) phys_to_virt(
+ le32_to_cpu(curr_td->next_td_ptr)
+ & DTD_ADDR_MASK);
+ kfree(tmp_td);
+ }
+ return status;
+}
+
+static void dtd_complete_irq(struct mpc_udc *udc)
+{
+ u32 bit_pos;
+ int i, ep_num, direction, bit_mask, status;
+ struct mpc_ep *curr_ep;
+ struct mpc_req *curr_req, *temp_req;
+
+ /* Clear the bits in the register */
+ bit_pos = usb_slave_regs->endptcomplete;
+ usb_slave_regs->endptcomplete = bit_pos;
+ bit_pos = le32_to_cpu(bit_pos);
+
+ if (!bit_pos)
+ return;
+
+ for (i = 0; i < USB_MAX_ENDPOINTS * 2; i++) {
+ ep_num = i >> 1;
+ direction = i % 2;
+
+ bit_mask = 1 << (ep_num + 16 * direction);
+
+ if (!(bit_pos & bit_mask))
+ continue;
+
+ curr_ep = get_ep_by_pipe(udc, i);
+
+ /* If the ep is configured */
+ if (curr_ep->name == NULL) {
+ WARN("Invalid EP?");
+ continue;
+ }
+
+ /* search all mpc_reqs of ep */
+ list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+ queue) {
+ status = process_ep_req(udc, i, curr_req);
+ if (status == REQ_UNCOMPLETE) {
+ VDBG("Not all tds are completed in the req");
+ break;
+ }
+
+ if (ep_num == 0) {
+ ep0_req_complete(udc, curr_ep, curr_req);
+ break;
+ } else
+ done(curr_ep, curr_req, status);
+ }
+ }
+}
+
+static void port_change_irq(struct mpc_udc *udc)
+{
+ u32 speed;
+
+ if (udc->bus_reset)
+ udc->bus_reset = 0;
+
+ /* Bus resetting is finished */
+ if (!(le32_to_cpu(usb_slave_regs->portsc1) & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ speed = (le32_to_cpu(usb_slave_regs->portsc1) &
+ PORTSCX_PORT_SPEED_MASK);
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ udc->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ udc->gadget.speed = USB_SPEED_FULL;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ udc->gadget.speed = USB_SPEED_LOW;
+ break;
+ default:
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ /* Update USB state */
+ if (!udc->resume_state)
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+static void suspend_irq(struct mpc_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ /* report suspend to the driver ,serial.c not support this*/
+ if (udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void resume_irq(struct mpc_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver , serial.c not support this*/
+ if (udc->driver->resume)
+ udc->driver->resume (&udc->gadget);
+}
+
+static int reset_queues(struct mpc_udc *udc)
+{
+ u8 pipe;
+
+ for (pipe = 0; pipe < udc->max_pipes; pipe++)
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+ udc->driver->disconnect(&udc->gadget);
+
+ return 0;
+}
+
+/*
+ * Interrupt handler for USB reset received
+ */
+
+static void reset_irq(struct mpc_udc *udc)
+{
+ u32 temp;
+
+ /* Clear the device address */
+ temp = le32_to_cpu(usb_slave_regs->deviceaddr);
+ temp &= ~USB_DEVICE_ADDRESS_MASK;
+ usb_slave_regs->deviceaddr = cpu_to_le32(temp);
+ udc->device_address = 0;
+
+ /* Clear usb state */
+ udc->usb_state = USB_STATE_DEFAULT;
+
+ /* Clear all the setup token semaphores */
+ temp = le32_to_cpu(usb_slave_regs->endptsetupstat);
+ usb_slave_regs->endptsetupstat = cpu_to_le32(temp);
+
+ /* Clear all the endpoint complete status bits */
+ temp = le32_to_cpu(usb_slave_regs->endptcomplete);
+ usb_slave_regs->endptcomplete = cpu_to_le32(temp);
+
+ while (usb_slave_regs->endpointprime) {
+ /* Wait until all endptprime bits cleared */
+ }
+
+ /* Write 1s to the Flush register */
+ usb_slave_regs->endptflush = 0xFFFFFFFF;
+
+ if (le32_to_cpu(usb_slave_regs->portsc1) & PORTSCX_PORT_RESET) {
+ VDBG("Bus RESET");
+ /* Bus is reseting */
+ udc->bus_reset = 1;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ /* Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ VDBG("RESET queue");
+ reset_queues(udc);
+ VDBG("RESET queue done");
+ } else {
+ VDBG("Controller reset");
+ /* initialize usb hw reg except for regs for EP, not
+ * touch usbintr reg */
+ dr_controller_setup(udc->ep_qh);
+
+ /* FIXME: Reset all internal used Queues */
+ reset_queues(udc);
+
+ ep0_dr_and_qh_setup(udc);
+
+ /* Enable DR IRQ reg, Set Run bit, change udc state */
+ dr_controller_run(udc);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state =WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+}
+
+/*
+ * USB device controller interrupt handler
+ */
+static irqreturn_t mpc_udc_irq(int irq, void *_udc, struct pt_regs *r)
+{
+ struct mpc_udc *udc = _udc;
+ u32 irq_src;
+ irqreturn_t status = IRQ_NONE;
+ unsigned long flags;
+
+ /* Disable ISR for OTG host mode */
+ if (udc->stopped)
+ return IRQ_NONE;
+ spin_lock_irqsave(&udc->lock, flags);
+ irq_src = usb_slave_regs->usbsts & usb_slave_regs->usbintr;
+ /* Clear notification bits */
+ usb_slave_regs->usbsts &= irq_src;
+
+ irq_src = le32_to_cpu(irq_src);
+ /* VDBG("irq_src [0x%8x]", irq_src); */
+
+ /* USB Interrupt */
+ if (irq_src & USB_STS_INT) {
+ VDBG("Packet int");
+ /* Setup package, we only support ep0 as control ep */
+ if (usb_slave_regs->endptsetupstat & cpu_to_le32(
+ EP_SETUP_STATUS_EP0)) {
+ tripwire_handler(udc, 0,
+ (u8 *) (&udc->local_setup_buff));
+ setup_received_irq(udc, &udc->local_setup_buff);
+ status = IRQ_HANDLED;
+ }
+
+ /* completion of dtd */
+ if (usb_slave_regs->endptcomplete) {
+ dtd_complete_irq(udc);
+ status = IRQ_HANDLED;
+ }
+ }
+
+ /* SOF (for ISO transfer) */
+ if (irq_src & USB_STS_SOF) {
+ status = IRQ_HANDLED;
+ }
+
+ /* Port Change */
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ port_change_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Reset Received */
+ if (irq_src & USB_STS_RESET) {
+ reset_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Sleep Enable (Suspend) */
+ if (irq_src & USB_STS_SUSPEND) {
+ suspend_irq(udc);
+ status = IRQ_HANDLED;
+ } else if (udc->resume_state) {
+ resume_irq(udc);
+ }
+
+ if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
+ VDBG("Error IRQ %x ", irq_src);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+}
+
+
+/*----------------------------------------------------------------*
+ * tell the controller driver about gadget layer driver
+ * The driver's bind function will be called to bind it to a gadget.
+ * @driver: for example fsg_driver from file_storage.c
+*----------------------------------------------------------------*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ int retval = -ENODEV;
+ unsigned long flags = 0;
+
+ /* standard operations */
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || (driver->speed != USB_SPEED_FULL
+ && driver->speed != USB_SPEED_HIGH)
+ || !driver->bind || !driver->unbind ||
+ !driver->disconnect || !driver->setup)
+ return -EINVAL;
+
+ if (udc_controller->driver)
+ return -EBUSY;
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+
+ driver->driver.bus = 0;
+ /* hook up the driver */
+ udc_controller->driver = driver;
+ udc_controller->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ retval = driver->bind(&udc_controller->gadget);
+ if (retval) {
+ VDBG("bind to %s --> %d", driver->driver.name,
+ retval);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+ goto out;
+ }
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ /* Suspend the controller until OTG enable it */
+ mpc_udc_suspend(&udc_controller->gadget.dev, 0);
+ printk("Suspend udc for OTG auto detect \n");
+
+ /* export udc suspend/resume call to OTG */
+ udc_controller->gadget.dev.driver->suspend = mpc_udc_suspend;
+ udc_controller->gadget.dev.driver->resume = mpc_udc_resume;
+
+ /* connect to bus through transceiver */
+ if (udc_controller->transceiver) {
+ retval = otg_set_peripheral(udc_controller->transceiver,
+ &udc_controller->gadget);
+ if (retval < 0) {
+ ERR("can't bind to transceiver\n");
+ driver->unbind (&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+ return retval;
+ }
+ }
+
+#else
+ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+ dr_controller_run(udc_controller);
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+#endif
+ printk("mpc_udc: %s bind to driver %s \n", udc_controller->gadget.name,
+ driver->driver.name);
+
+out:
+ if (retval)
+ printk("retval %d \n", retval);
+ return retval;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct mpc_ep *loop_ep;
+ unsigned long flags;
+
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || driver != udc_controller->driver)
+ return -EINVAL;
+
+ if (udc_controller->transceiver)
+ (void) otg_set_peripheral(udc_controller->transceiver, 0);
+
+ /* stop DR, disable intr */
+ dr_controller_stop(udc_controller);
+
+ /* in fact, no needed */
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state =WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+
+ /* stand operation */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc_controller->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+ ep.ep_list)
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+
+ printk("unregistered gadget driver '%s'\r\n", driver->driver.name);
+ return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------
+ PROC File System Support
+-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char proc_filename[] = "driver/fsl_usb2_udc";
+
+static int mpc_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *_dev)
+{
+ char *buf = page;
+ char *next = buf;
+ unsigned size = count;
+ unsigned long flags;
+ int t, i;
+ u32 tmp_reg;
+ struct mpc_ep *ep = NULL;
+ struct mpc_req *req;
+
+ struct mpc_udc *udc = udc_controller;
+ if (off != 0)
+ return 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* ------basic driver infomation ---- */
+ t = scnprintf(next, size,
+ DRIVER_DESC "\n" "%s version: %s\n"
+ "Gadget driver: %s\n\n", driver_name, DRIVER_VERSION,
+ udc->driver ? udc->driver->
+ driver.name : "(none)");
+ size -= t;
+ next += t;
+
+ /* ------ DR Registers ----- */
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbcmd);
+ t = scnprintf(next, size,
+ "USBCMD reg:\n" "SetupTW: %d\n" "Run/Stop: %s\n\n",
+ (tmp_reg & USB_CMD_SUTW) ? 1 : 0,
+ (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbsts);
+ t = scnprintf(next, size,
+ "USB Status Reg:\n" "Dr Suspend: %d"
+ "Reset Received: %d" "System Error: %s"
+ "USB Error Interrupt: %s\n\n",
+ (tmp_reg & USB_STS_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_STS_RESET) ? 1 : 0,
+ (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal",
+ (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbintr);
+ t = scnprintf(next, size,
+ "USB Intrrupt Enable Reg:\n"
+ "Sleep Enable: %d" "SOF Received Enable: %d"
+ "Reset Enable: %d\n" "System Error Enable: %d"
+ "Port Change Dectected Enable: %d\n"
+ "USB Error Intr Enable: %d"
+ "USB Intr Enable: %d\n\n",
+ (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_INT_EN) ? 1 : 0);
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->frindex);
+ t = scnprintf(next, size,
+ "USB Frame Index Reg:" "Frame Number is 0x%x\n\n",
+ (tmp_reg & USB_FRINDEX_MASKS));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->deviceaddr);
+ t = scnprintf(next, size,
+ "USB Device Address Reg:" "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_DEVICE_ADDRESS_MASK));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->endpointlistaddr);
+ t = scnprintf(next, size,
+ "USB Endpoint List Address Reg:"
+ "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_EP_LIST_ADDRESS_MASK));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->portsc1);
+ t = scnprintf(next, size,
+ "USB Port Status&Control Reg:\n"
+ "Port Transceiver Type : %s" "Port Speed: %s \n"
+ "PHY Low Power Suspend: %s" "Port Reset: %s"
+ "Port Suspend Mode: %s \n" "Over-current Change: %s"
+ "Port Enable/Disable Change: %s\n"
+ "Port Enabled/Disabled: %s"
+ "Current Connect Status: %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & PORTSCX_PTS_FSLS) {
+ case PORTSCX_PTS_UTMI:
+ s = "UTMI"; break;
+ case PORTSCX_PTS_ULPI:
+ s = "ULPI "; break;
+ case PORTSCX_PTS_FSLS:
+ s = "FS/LS Serial"; break;
+ default:
+ s = "None"; break;
+ }
+ s;} ), ( {
+ char *s;
+ switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
+ case PORTSCX_PORT_SPEED_FULL:
+ s = "Full Speed"; break;
+ case PORTSCX_PORT_SPEED_LOW:
+ s = "Low Speed"; break;
+ case PORTSCX_PORT_SPEED_HIGH:
+ s = "High Speed"; break;
+ default:
+ s = "Undefined"; break;
+ }
+ s;
+ } ),
+ (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ?
+ "Normal PHY mode" : "Low power mode",
+ (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" :
+ "Not in Reset",
+ (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in",
+ (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" :
+ "No",
+ (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" :
+ "Not change",
+ (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" :
+ "Not correct",
+ (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ?
+ "Attached" : "Not-Att");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbmode);
+ t = scnprintf(next, size,
+ "USB Mode Reg:" "Controller Mode is : %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) {
+ case USB_MODE_CTRL_MODE_IDLE:
+ s = "Idle"; break;
+ case USB_MODE_CTRL_MODE_DEVICE:
+ s = "Device Controller"; break;
+ case USB_MODE_CTRL_MODE_HOST:
+ s = "Host Controller"; break;
+ default:
+ s = "None"; break;
+ }
+ s;
+ } ));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->endptsetupstat);
+ t = scnprintf(next, size,
+ "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n",
+ (tmp_reg & EP_SETUP_STATUS_MASK));
+ size -= t;
+ next += t;
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ tmp_reg = le32_to_cpu(usb_slave_regs->endptctrl[i]);
+ t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n",
+ i, tmp_reg);
+ size -= t;
+ next += t;
+ }
+ tmp_reg = le32_to_cpu(usb_slave_regs->endpointprime);
+ t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg);
+ size -= t;
+ next += t;
+
+ tmp_reg = usb_sys_regs->snoop1;
+ t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg);
+ size -= t;
+ next += t;
+
+ tmp_reg = usb_sys_regs->control;
+ t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
+ tmp_reg);
+ size -= t;
+ next += t;
+
+ /* ------mpc_udc, mpc_ep, mpc_request structure information ----- */
+ ep = &udc->eps[0];
+ t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n",
+ ep->ep.name, ep_maxpacket(ep), ep_index(ep));
+ size -= t;
+ next += t;
+
+ if (list_empty(&ep->queue)) {
+ t = scnprintf(next, size, "its req queue is empty\n\n");
+ size -= t;
+ next += t;
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+ "req %p actual 0x%x length 0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+ next += t;
+ }
+ }
+ /* other gadget->eplist ep */
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc) {
+ t = scnprintf(next, size,
+ "\nFor %s Maxpkt is 0x%x index is 0x%x\n",
+ ep->ep.name,
+ ep_maxpacket(ep),
+ ep_index(ep));
+ size -= t;
+ next += t;
+
+ if (list_empty(&ep->queue)) {
+ t = scnprintf(next, size,
+ "its req queue is empty\n\n");
+ size -= t;
+ next += t;
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+ "req %p actual 0x%x length"
+ "0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+ next += t;
+ } // end for each_entry of ep req
+ } //end for else
+ } //end for if(ep->queue)
+ } // end (ep->desc)
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ *eof = 1;
+ return count - size;
+}
+
+#define create_proc_file() create_proc_read_entry(proc_filename, \
+ 0, NULL, mpc_proc_read, NULL)
+
+#define remove_proc_file() remove_proc_entry(proc_filename, NULL)
+
+#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+
+#define create_proc_file() do {} while (0)
+#define remove_proc_file() do {} while (0)
+
+#endif /*CONFIG_USB_GADGET_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ * Release the mpc specific udc structure
+ * it is not stand gadget function
+ * it is called when the last reference to the device is removed;
+ * it is called from the embedded kobject's release method.
+ * All device structures registered with the core must have a
+ * release method, or the kernel prints out scary complaints
+ *-------------------------------------------------------------------------*/
+static void mpc_udc_release(struct device *dev)
+{
+ complete(udc_controller->done);
+ kfree(ep_qh_base);
+ ep_qh_base = NULL;
+ kfree(udc_controller);
+ udc_controller = NULL;
+}
+
+/******************************************************************
+ Internal structure setup functions
+*******************************************************************/
+/*------------------------------------------------------------------
+ * this func will init resource for globle controller
+ * Return the udc handle on success or Null on failing
+ ------------------------------------------------------------------*/
+static void *struct_udc_setup(struct platform_device *pdev)
+{
+ struct mpc_udc *udc = NULL;
+ unsigned int tmp_sz = 0;
+
+ udc = (struct mpc_udc *)kzalloc(sizeof(struct mpc_udc), GFP_KERNEL);
+ if (udc == NULL) {
+ printk("malloc udc failed\n");
+ goto cleanup;
+ }
+
+ /* initialized QHs, take care the 2K align */
+ tmp_sz = USB_MAX_PIPES * sizeof(struct ep_queue_head);
+ udc->ep_qh = (struct ep_queue_head *)KMALLOC_ALIGN(tmp_sz, GFP_KERNEL,
+ 2 * 1024,
+ (void **)&ep_qh_base);
+ if (!udc->ep_qh) {
+ printk("malloc QHs for udc failed\n");
+ goto cleanup;
+ }
+ /* Initialize ep0 status request structure */
+ /* FIXME: mpc_alloc_request() ignores ep argument */
+ udc->status_req = container_of(mpc_alloc_request(NULL, GFP_KERNEL),
+ struct mpc_req, req);
+ /* allocate a small amount of memory to get valid address */
+ udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+ udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+ spin_lock_init(&udc->lock);
+
+ return udc;
+
+cleanup:
+ kfree(udc);
+ return NULL;
+}
+
+/*----------------------------------------------------------------
+ * set up the mpc_ep struct for eps
+ * ep0out isnot used so do nothing here
+ * ep0in should be taken care
+ * It also link this mpc_ep->ep to gadget->ep_list
+ *--------------------------------------------------------------*/
+static int struct_ep_setup(void *handle, unsigned char pipe_num)
+{
+ struct mpc_udc *udc = (struct mpc_udc *)handle;
+ struct mpc_ep *ep = get_ep_by_pipe(udc, pipe_num);
+
+ ep->udc = udc;
+ strcpy(ep->name, ep_name[pipe_num]);
+ ep->ep.name = ep_name[pipe_num];
+ ep->ep.ops = &mpc_ep_ops;
+ ep->stopped = 0;
+
+ /* for ep0: the desc defined here;
+ * for other eps, gadget layer called ep_enable with defined desc
+ */
+ /* for ep0: maxP defined in desc
+ * for other eps, maxP is set by epautoconfig() called by gadget layer
+ */
+ if (pipe_num == 0)
+ {
+ ep->desc = &mpc_ep0_desc;
+ ep->ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+ }
+ else
+ {
+ ep->ep.maxpacket = (unsigned short) ~0;
+ ep->desc = NULL;
+ }
+
+ /* the queue lists any req for this ep */
+ INIT_LIST_HEAD(&ep->queue);
+
+ /* gagdet.ep_list used for ep_autoconfig so no ep0*/
+ if (pipe_num != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->gadget = &udc->gadget;
+
+ return 0;
+}
+
+/* Driver probe function
+ * all intialize operations implemented here except enabling usb_intr reg
+ */
+static int __init mpc_udc_probe(struct platform_device *pdev)
+{
+ struct resource *dr_resources;
+ int dr_num_resources;
+
+ int tmp_status = -ENODEV;
+ unsigned int i;
+
+ if (strcmp(pdev->name, driver_name)) {
+ VDBG("Wrong device\n");
+ return -ENODEV;
+ }
+
+ /* board env setting should be OK before here
+ * including:
+ * Set up I2C if using USB port of PMC board
+ * Set SCCR for usb clock
+ * Set SICR for io pin according to 83xx RM table 16-1
+ * Set up PCA9555 according PHY interface type if using usb port of PMC
+ */
+
+ /* Initialize the udc structure including QH member and other member */
+ udc_controller = (struct mpc_udc *)struct_udc_setup(pdev);
+ if (!udc_controller)
+ {
+ VDBG("udc_controller is NULL \n");
+ return -ENOMEM;
+ }
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ /* Memory and interrupt resources will be passed from OTG */
+ udc_controller->transceiver = otg_get_transceiver();
+ if (!udc_controller->transceiver) {
+ printk("Can't find OTG driver!\n");
+ return -ENODEV;
+ }
+
+ dr_resources = otg_get_resources(&dr_num_resources);
+ if (!dr_resources) {
+ DBG("resource not registered!\n");
+ return -ENODEV;
+ }
+#else
+ dr_resources = pdev->resource;
+ dr_num_resources = pdev->num_resources;
+
+ if (!request_mem_region(dr_resources[0].start,
+ dr_resources[0].end -
+ dr_resources[0].start + 1,
+ driver_name)) {
+ printk("request mem region for %s failed \n", pdev->name);
+ return -EBUSY;
+ }
+#endif
+ /* Initialize the dr register map addr */
+ if (dr_resources[0].flags != IORESOURCE_MEM
+ || dr_resources[1].flags != IORESOURCE_IRQ) {
+ return -ENODEV;
+ }
+
+ usb_slave_regs = ioremap(dr_resources[0].start,
+ sizeof(struct usb_dr_device));
+ usb_sys_regs = (struct usb_sys_interface *)((int)usb_slave_regs +
+ USB_DR_SYS_OFFSET);
+
+ tmp_status = request_irq(dr_resources[1].start, mpc_udc_irq, SA_SHIRQ,
+ driver_name,udc_controller);
+ if (tmp_status != 0) {
+ printk("cannot request irq %d err %d \n",
+ (int)dr_resources[1].start, tmp_status);
+ return tmp_status;
+ }
+
+
+ /* initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched */
+ dr_controller_setup(udc_controller->ep_qh);
+ /* standard operations for probe */
+ udc_controller->gadget.ops = &mpc_gadget_ops;
+ udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+
+ INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* name: Identifies the controller hardware type. */
+ udc_controller->gadget.name = driver_name;
+
+ device_initialize(&udc_controller->gadget.dev);
+
+ strcpy(udc_controller->gadget.dev.bus_id, "gadget");
+
+ udc_controller->gadget.dev.release = mpc_udc_release;
+ udc_controller->gadget.dev.parent = &pdev->dev;
+
+#if (defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)) && \
+ (defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE))
+ udc_controller->gadget.is_otg = 1;
+#endif
+
+ /* for an EP, the intialization includes: fields in QH, Regs,
+ * mpc_ep struct */
+ ep0_dr_and_qh_setup(udc_controller);
+ for (i = 0; i < USB_MAX_PIPES ; i++) {
+ /* because the ep type isnot decide here so
+ * struct_ep_qh_setup() and dr_ep_setup()
+ * should be called in ep_enable()
+ */
+ if ( ep_name[i] != NULL )
+ /* setup the mpc_ep struct and link ep.ep.list
+ * into gadget.ep_list */
+ struct_ep_setup(udc_controller, i);
+ }
+
+ create_proc_file();
+ device_add(&udc_controller->gadget.dev);
+ return 0;
+}
+
+/* Driver removal functions
+ * Free resources
+ * Finish pending transaction
+ */
+static int __exit mpc_udc_remove(struct platform_device *pdev)
+{
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ int dr_num_resources;
+ struct resource *dr_resources = otg_get_resources(&dr_num_resources);
+#endif
+
+ DECLARE_COMPLETION(done);
+
+ if (!udc_controller)
+ return -ENODEV;
+ udc_controller->done = &done;
+
+ /* DR has been stopped in usb_gadget_unregister_driver() */
+
+ remove_proc_file();
+
+ /* Free allocated memory */
+ kfree(udc_controller->status_req->req.buf);
+ kfree(udc_controller->status_req);
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ free_irq(dr_resources[1].start, udc_controller);
+ /* The OTG driver is responsible to free resources */
+#else
+ free_irq(pdev->resource[1].start, udc_controller);
+
+ release_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
+#endif
+
+ device_unregister(&udc_controller->gadget.dev);
+ /* free udc --wait for the release() finished */
+ wait_for_completion(&done);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Modify Power management attributes
+ * Here we stop the DR controller and disable the irq
+ -----------------------------------------------------------------*/
+static int mpc_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dr_controller_stop(udc_controller);
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Invoked on USB resume. May be called in_interrupt.
+ * Here we start the DR controller and enable the irq
+ *-----------------------------------------------------------------*/
+static int mpc_udc_resume(struct platform_device *pdev)
+{
+ /*Enable DR irq reg and set controller Run */
+ if (udc_controller->stopped) {
+ dr_controller_setup(udc_controller->ep_qh);
+ dr_controller_run(udc_controller);
+ }
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ Register entry point for the peripheral controller driver
+--------------------------------------------------------------------------*/
+
+static struct platform_driver udc_driver = {
+ .probe = mpc_udc_probe,
+ .remove = __exit_p(mpc_udc_remove),
+ /* these suspend and resume are not usb suspend and resume */
+ .suspend = mpc_udc_suspend,
+ .resume = mpc_udc_resume,
+ .driver = {
+ .name = (char *)driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static int __init udc_init(void)
+{
+ printk("%s version %s init \n", driver_desc, DRIVER_VERSION);
+ return platform_driver_register(&udc_driver);
+}
+
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
new file mode 100644
index 0000000..bee746c
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -0,0 +1,608 @@
+/*
+ * Freescale USB device/endpoint management registers
+ * some defines from shlomi
+ */
+#ifndef __MPC_UDC_H
+#define __MPC_UDC_H
+
+/* ### define USB registers here
+ */
+#define USB_MAX_ENDPOINTS 6
+#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
+#define USB_MAX_CTRL_PAYLOAD 64
+#define USB_DR_SYS_OFFSET 0x400
+
+ /* USB DR device mode registers (Little Endian) */
+struct usb_dr_device {
+ /* Capability register */
+ u8 res1[256];
+ u16 caplength; /* Capability Register Length */
+ u16 hciversion; /* Host Controller Interface Version */
+ u32 hcsparams; /* Host Controller Structual Parameters */
+ u32 hccparams; /* Host Controller Capability Parameters */
+ u8 res2[20];
+ u32 dciversion; /* Device Controller Interface Version */
+ u32 dccparams; /* Device Controller Capability Parameters */
+ u8 res3[24];
+ /* Operation register */
+ u32 usbcmd; /* USB Command Register */
+ u32 usbsts; /* USB Status Register */
+ u32 usbintr; /* USB Interrupt Enable Register */
+ u32 frindex; /* Frame Index Register */
+ u8 res4[4];
+ u32 deviceaddr; /* Device Address */
+ u32 endpointlistaddr; /* Endpoint List Address Register */
+ u8 res5[4];
+ u32 burstsize; /* Master Interface Data Burst Size Register */
+ u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
+ u8 res6[24];
+ u32 configflag; /* Configure Flag Register */
+ u32 portsc1; /* Port 1 Status and Control Register */
+ u8 res7[28];
+ u32 otgsc; /* On-The-Go Status and Control */
+ u32 usbmode; /* USB Mode Register */
+ u32 endptsetupstat; /* Endpoint Setup Status Register */
+ u32 endpointprime; /* Endpoint Initialization Register */
+ u32 endptflush; /* Endpoint Flush Register */
+ u32 endptstatus; /* Endpoint Status Register */
+ u32 endptcomplete; /* Endpoint Complete Register */
+ u32 endptctrl[6]; /* Endpoint Control Registers */
+};
+
+ /* USB DR host mode registers (Little Endian) */
+struct usb_dr_host {
+ /* Capability register */
+ u8 res1[256];
+ u16 caplength; /* Capability Register Length */
+ u16 hciversion; /* Host Controller Interface Version */
+ u32 hcsparams; /* Host Controller Structual Parameters */
+ u32 hccparams; /* Host Controller Capability Parameters */
+ u8 res2[20];
+ u32 dciversion; /* Device Controller Interface Version */
+ u32 dccparams; /* Device Controller Capability Parameters */
+ u8 res3[24];
+ /* Operation register */
+ u32 usbcmd; /* USB Command Register */
+ u32 usbsts; /* USB Status Register */
+ u32 usbintr; /* USB Interrupt Enable Register */
+ u32 frindex; /* Frame Index Register */
+ u8 res4[4];
+ u32 periodiclistbase; /* Periodic Frame List Base Address Register */
+ u32 asynclistaddr; /* Current Asynchronous List Address Register */
+ u8 res5[4];
+ u32 burstsize; /* Master Interface Data Burst Size Register */
+ u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
+ u8 res6[24];
+ u32 configflag; /* Configure Flag Register */
+ u32 portsc1; /* Port 1 Status and Control Register */
+ u8 res7[28];
+ u32 otgsc; /* On-The-Go Status and Control */
+ u32 usbmode; /* USB Mode Register */
+ u32 endptsetupstat; /* Endpoint Setup Status Register */
+ u32 endpointprime; /* Endpoint Initialization Register */
+ u32 endptflush; /* Endpoint Flush Register */
+ u32 endptstatus; /* Endpoint Status Register */
+ u32 endptcomplete; /* Endpoint Complete Register */
+ u32 endptctrl[6]; /* Endpoint Control Registers */
+};
+
+
+ /* non-EHCI USB system interface registers (Big Endian) */
+struct usb_sys_interface {
+ u32 snoop1;
+ u32 snoop2;
+ u32 age_cnt_thresh; /* Age Count Threshold Register */
+ u32 pri_ctrl; /* Priority Control Register */
+ u32 si_ctrl; /* System Interface Control Register */
+ u8 res[236];
+ u32 control; /* General Purpose Control Register */
+};
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_MASKS (0x3fff)
+/* USB CMD Register Bit Masks */
+#define USB_CMD_RUN_STOP (0x00000001)
+#define USB_CMD_CTRL_RESET (0x00000002)
+#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
+#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
+#define USB_CMD_INT_AA_DOORBELL (0x00000040)
+#define USB_CMD_ASP (0x00000300)
+#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800)
+#define USB_CMD_SUTW (0x00002000)
+#define USB_CMD_ATDTW (0x00004000)
+#define USB_CMD_ITC (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 (0x00000000)
+#define USB_CMD_FRAME_SIZE_512 (0x00000004)
+#define USB_CMD_FRAME_SIZE_256 (0x00000008)
+#define USB_CMD_FRAME_SIZE_128 (0x0000000C)
+#define USB_CMD_FRAME_SIZE_64 (0x00008000)
+#define USB_CMD_FRAME_SIZE_32 (0x00008004)
+#define USB_CMD_FRAME_SIZE_16 (0x00008008)
+#define USB_CMD_FRAME_SIZE_8 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 (0x00000000)
+#define USB_CMD_ASP_01 (0x00000100)
+#define USB_CMD_ASP_10 (0x00000200)
+#define USB_CMD_ASP_11 (0x00000300)
+#define USB_CMD_ASP_BIT_POS (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD (0x00000000)
+#define USB_CMD_ITC_1_MICRO_FRM (0x00010000)
+#define USB_CMD_ITC_2_MICRO_FRM (0x00020000)
+#define USB_CMD_ITC_4_MICRO_FRM (0x00040000)
+#define USB_CMD_ITC_8_MICRO_FRM (0x00080000)
+#define USB_CMD_ITC_16_MICRO_FRM (0x00100000)
+#define USB_CMD_ITC_32_MICRO_FRM (0x00200000)
+#define USB_CMD_ITC_64_MICRO_FRM (0x00400000)
+#define USB_CMD_ITC_BIT_POS (16)
+
+/* USB STS Register Bit Masks */
+#define USB_STS_INT (0x00000001)
+#define USB_STS_ERR (0x00000002)
+#define USB_STS_PORT_CHANGE (0x00000004)
+#define USB_STS_FRM_LST_ROLL (0x00000008)
+#define USB_STS_SYS_ERR (0x00000010)
+#define USB_STS_IAA (0x00000020)
+#define USB_STS_RESET (0x00000040)
+#define USB_STS_SOF (0x00000080)
+#define USB_STS_SUSPEND (0x00000100)
+#define USB_STS_HC_HALTED (0x00001000)
+#define USB_STS_RCL (0x00002000)
+#define USB_STS_PERIODIC_SCHEDULE (0x00004000)
+#define USB_STS_ASYNC_SCHEDULE (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_INT_EN (0x00000001)
+#define USB_INTR_ERR_INT_EN (0x00000002)
+#define USB_INTR_PTC_DETECT_EN (0x00000004)
+#define USB_INTR_FRM_LST_ROLL_EN (0x00000008)
+#define USB_INTR_SYS_ERR_EN (0x00000010)
+#define USB_INTR_ASYN_ADV_EN (0x00000020)
+#define USB_INTR_RESET_EN (0x00000040)
+#define USB_INTR_SOF_EN (0x00000080)
+#define USB_INTR_DEVICE_SUSPEND (0x00000100)
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDRESS_MASK (0xFE000000)
+#define USB_DEVICE_ADDRESS_BIT_POS (25)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
+#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
+#define PORTSCX_PORT_ENABLE (0x00000004)
+#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
+#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
+#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
+#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
+#define PORTSCX_PORT_SUSPEND (0x00000080)
+#define PORTSCX_PORT_RESET (0x00000100)
+#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
+#define PORTSCX_PORT_POWER (0x00001000)
+#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
+#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
+#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
+#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
+#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
+#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
+#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
+#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
+#define PORTSCX_PORT_WIDTH (0x10000000)
+#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
+#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
+#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
+#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
+#define PORTSCX_LINE_STATUS_BIT_POS (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF (0x00000000)
+#define PORTSCX_PIC_AMBER (0x00004000)
+#define PORTSCX_PIC_GREEN (0x00008000)
+#define PORTSCX_PIC_UNDEF (0x0000C000)
+#define PORTSCX_PIC_BIT_POS (14)
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE (0x00000000)
+#define PORTSCX_PTC_JSTATE (0x00010000)
+#define PORTSCX_PTC_KSTATE (0x00020000)
+#define PORTSCX_PTC_SEQNAK (0x00030000)
+#define PORTSCX_PTC_PACKET (0x00040000)
+#define PORTSCX_PTC_FORCE_EN (0x00050000)
+#define PORTSCX_PTC_BIT_POS (16)
+
+/* bit 27-26 are port speed */
+#define PORTSCX_PORT_SPEED_FULL (0x00000000)
+#define PORTSCX_PORT_SPEED_LOW (0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
+#define PORTSCX_SPEED_BIT_POS (26)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW (0x10000000)
+#define PORTSCX_PTW_8BIT (0x00000000)
+#define PORTSCX_PTW_16BIT (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSCX_PTS_UTMI (0x00000000)
+#define PORTSCX_PTS_ULPI (0x80000000)
+#define PORTSCX_PTS_FSLS (0xC0000000)
+#define PORTSCX_PTS_BIT_POS (30)
+
+/* otgsc Register Bit Masks */
+#define OTGSC_CTRL_VUSB_DISCHARGE (0x00000001)
+#define OTGSC_CTRL_VUSB_CHARGE (0x00000002)
+#define OTGSC_CTRL_OTG_TERM (0x00000008)
+#define OTGSC_CTRL_DATA_PULSING (0x00000010)
+#define OTGSC_STS_USB_ID (0x00000100)
+#define OTGSC_STS_A_VBUS_VALID (0x00000200)
+#define OTGSC_STS_A_SESSION_VALID (0x00000400)
+#define OTGSC_STS_B_SESSION_VALID (0x00000800)
+#define OTGSC_STS_B_SESSION_END (0x00001000)
+#define OTGSC_STS_1MS_TOGGLE (0x00002000)
+#define OTGSC_STS_DATA_PULSING (0x00004000)
+#define OTGSC_INTSTS_USB_ID (0x00010000)
+#define OTGSC_INTSTS_A_VBUS_VALID (0x00020000)
+#define OTGSC_INTSTS_A_SESSION_VALID (0x00040000)
+#define OTGSC_INTSTS_B_SESSION_VALID (0x00080000)
+#define OTGSC_INTSTS_B_SESSION_END (0x00100000)
+#define OTGSC_INTSTS_1MS (0x00200000)
+#define OTGSC_INTSTS_DATA_PULSING (0x00400000)
+#define OTGSC_INTR_USB_ID (0x01000000)
+#define OTGSC_INTR_A_VBUS_VALID (0x02000000)
+#define OTGSC_INTR_A_SESSION_VALID (0x04000000)
+#define OTGSC_INTR_B_SESSION_VALID (0x08000000)
+#define OTGSC_INTR_B_SESSION_END (0x10000000)
+#define OTGSC_INTR_1MS_TIMER (0x20000000)
+#define OTGSC_INTR_DATA_PULSING (0x40000000)
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_CTRL_MODE_IDLE (0x00000000)
+#define USB_MODE_CTRL_MODE_DEVICE (0x00000002)
+#define USB_MODE_CTRL_MODE_HOST (0x00000003)
+#define USB_MODE_CTRL_MODE_RSV (0x00000001)
+#define USB_MODE_SETUP_LOCK_OFF (0x00000008)
+#define USB_MODE_STREAM_DISABLE (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET (0x00010000)
+#define EPFLUSH_RX_OFFSET (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_MASK (0x0000003F)
+#define EP_SETUP_STATUS_EP0 (0x00000001)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
+#define EPCTRL_RX_EP_STALL (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL (0)
+#define EPCTRL_EP_TYPE_ISO (1)
+#define EPCTRL_EP_TYPE_BULK (2)
+#define EPCTRL_EP_TYPE_INTERRUPT (3)
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+
+/* SNOOPn Register Bit Masks */
+#define SNOOP_ADDRESS_MASK (0xFFFFF000)
+#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */
+#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */
+#define SNOOP_SIZE_8KB (0x0C)
+#define SNOOP_SIZE_16KB (0x0D)
+#define SNOOP_SIZE_32KB (0x0E)
+#define SNOOP_SIZE_64KB (0x0F)
+#define SNOOP_SIZE_128KB (0x10)
+#define SNOOP_SIZE_256KB (0x11)
+#define SNOOP_SIZE_512KB (0x12)
+#define SNOOP_SIZE_1MB (0x13)
+#define SNOOP_SIZE_2MB (0x14)
+#define SNOOP_SIZE_4MB (0x15)
+#define SNOOP_SIZE_8MB (0x16)
+#define SNOOP_SIZE_16MB (0x17)
+#define SNOOP_SIZE_32MB (0x18)
+#define SNOOP_SIZE_64MB (0x19)
+#define SNOOP_SIZE_128MB (0x1A)
+#define SNOOP_SIZE_256MB (0x1B)
+#define SNOOP_SIZE_512MB (0x1C)
+#define SNOOP_SIZE_1GB (0x1D)
+#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */
+
+
+/* pri_ctrl Register Bit Masks */
+#define PRI_CTRL_PRI_LVL1 (0x0000000C)
+#define PRI_CTRL_PRI_LVL0 (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define SI_CTRL_ERR_DISABLE (0x00000010)
+#define SI_CTRL_IDRC_DISABLE (0x00000008)
+#define SI_CTRL_RD_SAFE_EN (0x00000004)
+#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
+#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
+
+/* control Register Bit Masks */
+#define USB_CTRL_IOENB (0x00000004)
+#define USB_CTRL_ULPI_INT0EN (0x00000001)
+
+/* Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+ u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
+ and IOS(15) */
+ u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
+ u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
+ u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
+ u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
+ u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
+ u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
+ u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
+ u32 res1;
+ u8 setup_buffer[8]; /* Setup data 8 bytes */
+ u32 res2[4];
+};
+
+/* Endpoint Queue Head Bit Masks */
+#define EP_QUEUE_HEAD_MULT_POS (30)
+#define EP_QUEUE_HEAD_ZLT_SEL (0x20000000)
+#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS (16)
+#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
+#define EP_QUEUE_HEAD_IOS (0x00008000)
+#define EP_QUEUE_HEAD_NEXT_TERMINATE (0x00000001)
+#define EP_QUEUE_HEAD_IOC (0x00008000)
+#define EP_QUEUE_HEAD_MULTO (0x00000C00)
+#define EP_QUEUE_HEAD_STATUS_HALT (0x00000040)
+#define EP_QUEUE_HEAD_STATUS_ACTIVE (0x00000080)
+#define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF)
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0)
+#define EP_QUEUE_FRINDEX_MASK (0x000007FF)
+#define EP_MAX_LENGTH_TRANSFER (0x4000)
+
+/* Endpoint Transfer Descriptor data struct */
+/* Rem: all the variables of td are LittleEndian Mode */
+struct ep_td_struct {
+ u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
+ indicate invalid */
+ u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 */
+ u32 buff_ptr1; /* Buffer pointer Page 1 */
+ u32 buff_ptr2; /* Buffer pointer Page 2 */
+ u32 buff_ptr3; /* Buffer pointer Page 3 */
+ u32 buff_ptr4; /* Buffer pointer Page 4 */
+};
+
+/* Endpoint Transfer Descriptor bit Masks */
+#define DTD_NEXT_TERMINATE (0x00000001)
+#define DTD_IOC (0x00008000)
+#define DTD_STATUS_ACTIVE (0x00000080)
+#define DTD_STATUS_HALTED (0x00000040)
+#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
+#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
+#define DTD_RESERVED_FIELDS (0x80007300)
+#define DTD_ADDR_MASK (0xFFFFFFE0)
+#define DTD_PACKET_SIZE (0x7FFF0000)
+#define DTD_LENGTH_BIT_POS (16)
+#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
+ DTD_STATUS_DATA_BUFF_ERR | \
+ DTD_STATUS_TRANSACTION_ERR)
+
+/* -----------------------------------------------------------------------*/
+/* ##### enum data
+*/
+typedef enum {
+ e_ULPI,
+ e_UTMI_8BIT,
+ e_UTMI_16BIT,
+ e_SERIAL
+} e_PhyInterface;
+
+/*-------------------------------------------------------------------------*/
+
+/* ### driver private data, Need rework
+ */
+struct mpc_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* ep_queue() func will add
+ a request->queue into a udc_ep->queue 'd tail */
+ struct mpc_ep *ep;
+ unsigned mapped:1;
+
+ struct ep_td_struct *head, *tail; /* For dTD List
+ this is a BigEndian Virtual addr */
+ unsigned int dtd_count;
+};
+
+
+#define REQ_UNCOMPLETE (1)
+
+struct mpc_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct mpc_udc *udc;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_gadget *gadget;
+
+ u8 already_seen;
+ u8 setup_stage;
+ u32 last_io; /* timestamp */
+
+ char name[14];
+#if 0
+ u16 maxpacket;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+#endif
+ unsigned double_buf:1;
+ unsigned stopped:1;
+ unsigned fnf:1;
+ unsigned has_dma:1;
+ u8 ackwait;
+ u8 dma_channel;
+ u16 dma_counter;
+ int lch;
+
+ struct timer_list timer;
+
+};
+
+#define EP_DIR_IN 1
+#define EP_DIR_OUT 0
+
+struct mpc_udc {
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct mpc_ep eps[USB_MAX_ENDPOINTS * 2];
+ struct usb_ctrlrequest local_setup_buff;
+ spinlock_t lock;
+ struct otg_transceiver *transceiver;
+ unsigned softconnect:1;
+ unsigned vbus_active:1;
+ unsigned stopped:1;
+
+ struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
+ struct mpc_req *status_req; /* ep0 status request */
+
+ u32 max_pipes; /* Device max pipes */
+ u32 max_use_endpts; /* Max endpointes to be used */
+ u32 bus_reset; /* Device is bus reseting */
+ u32 resume_state; /* USB state to resume*/
+ u32 usb_state; /* USB current state */
+ u32 usb_next_state; /* USB next state */
+ u32 ep0_state; /* Enpoint zero state */
+ u32 ep0_dir; /* Enpoint zero direction: can be
+ USB_DIR_IN or USB_DIR_OUT*/
+ u32 usb_sof_count; /* SOF count */
+ u32 errors; /* USB ERRORs count */
+ u8 device_address; /* Device USB address */
+
+ struct completion *done; /* to make sure release() is done */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
+ __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...) do{}while(0)
+#endif
+
+#if 0
+static void dump_msg(const char *label,
+ const u8 *buf, unsigned int length)
+{
+ unsigned int start, num, i;
+ char line[52], *p;
+
+
+ if (length >= 512)
+ return;
+ DBG("%s, length %u:\n", label, length);
+ start = 0;
+ while (length > 0) {
+ num = min(length, 16u);
+ p = line;
+ for (i = 0; i < num; ++i) {
+ if (i == 8)
+ *p++ = ' ';
+ sprintf(p, " %02x", buf[i]);
+ p += 3;
+ }
+ *p = 0;
+ printk(KERN_DEBUG "%6x: %s\n", start, line);
+ buf += num;
+ start += num;
+ length -= num;
+ }
+}
+#endif
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(stuff...) do{}while(0)
+#endif
+
+#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+
+/*-------------------------------------------------------------------------*/
+
+
+/* ### Add board specific defines here
+ */
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV (0) /* OUT EP */
+#define USB_SEND (1) /* IN EP */
+
+/*
+ * ### internal used help routines.
+ */
+#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+ USB_DIR_IN ):((EP)->desc->bEndpointAddress \
+ & USB_DIR_IN)==USB_DIR_IN)
+#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \
+ &udc->eps[pipe])
+/*
+ * memory kmalloc with alignning size and zero the content
+ * @base :output parameter. It store the base address before align.
+ * Return value it the address after align
+ *
+ */
+static inline void *KMALLOC_ALIGN(size_t size, int flags, unsigned int align,
+ void **base)
+{
+ *base = kzalloc(size + align, flags);
+ if (*base == NULL)
+ return NULL;
+ return (void *) ALIGN((unsigned int) (*base), align);
+}
+
+/* Bulk only class request */
+#define USB_BULK_RESET_REQUEST 0xff
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+/* Get platform resource from OTG driver */
+extern struct resource *otg_get_resources(int* num);
+#endif
+
+#endif
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f09..d76f06c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -93,6 +93,12 @@ #else
#define gadget_is_imx(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define gadget_is_fsl_usb2(g) !strncmp("fsl-usb2-dr-udc", (g)->name, 11)
+#else
+#define gadget_is_fsl_usb2(g) 0
+#endif
+
/* Mentor high speed function controller */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
+ else if (gadget_is_fsl_usb2(gadget))
+ return 0x18;
return -ENOENT;
}
More information about the Linuxppc-dev
mailing list