[target/xburst] level up target xburst to linux kernel version 3.2.1
[openwrt.git] / target / linux / xburst / patches-3.2 / 0002-Add-jz4740-udc-driver.patch
diff --git a/target/linux/xburst/patches-3.2/0002-Add-jz4740-udc-driver.patch b/target/linux/xburst/patches-3.2/0002-Add-jz4740-udc-driver.patch
new file mode 100644 (file)
index 0000000..f6d0015
--- /dev/null
@@ -0,0 +1,2386 @@
+From 537082e01849ca85227c5b462b8ac9aceb11b77a Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Sat, 24 Apr 2010 12:18:46 +0200
+Subject: [PATCH 02/21] Add jz4740 udc driver
+
+History:
+- driver by Ingenic
+- patch by Lars-Peter Clausen.
+- updated to 3.1 by Maarten ter Huurne
+---
+ drivers/usb/gadget/Kconfig        |    8 +
+ drivers/usb/gadget/Makefile       |    1 +
+ drivers/usb/gadget/gadget_chips.h |    3 +
+ drivers/usb/gadget/jz4740_udc.c   | 2199 +++++++++++++++++++++++++++++++++++++
+ drivers/usb/gadget/jz4740_udc.h   |  101 ++
+ 5 files changed, 2312 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/gadget/jz4740_udc.c
+ create mode 100644 drivers/usb/gadget/jz4740_udc.h
+
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 23a4473..89b7d28 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -178,6 +178,14 @@ config USB_FUSB300
+       help
+          Faraday usb device controller FUSB300 driver
++config USB_JZ4740
++      tristate "JZ4740 UDC"
++      depends on MACH_JZ4740
++      select USB_GADGET_DUALSPEED
++      help
++         Select this to support the Ingenic JZ4740 processor
++         high speed USB device controller.
++
+ config USB_OMAP
+       tristate "OMAP USB Device Controller"
+       depends on ARCH_OMAP
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index b54ac61..2d65f6e 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_USB_PXA_U2O)    += mv_udc.o
+ mv_udc-y                      := mv_udc_core.o
+ obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
+ obj-$(CONFIG_USB_FUSB300)     += fusb300_udc.o
++obj-$(CONFIG_USB_JZ4740)      += jz4740_udc.o
+ #
+ # USB gadget drivers
+diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
+index a8855d0..99f1580 100644
+--- a/drivers/usb/gadget/gadget_chips.h
++++ b/drivers/usb/gadget/gadget_chips.h
+@@ -36,6 +36,7 @@
+ #define gadget_is_fsl_usb2(g)         (!strcmp("fsl-usb2-udc", (g)->name))
+ #define gadget_is_goku(g)             (!strcmp("goku_udc", (g)->name))
+ #define gadget_is_imx(g)              (!strcmp("imx_udc", (g)->name))
++#define gadget_is_jz4740(g)           (!strcmp("ingenic_hsusb", (g)->name))
+ #define gadget_is_langwell(g)         (!strcmp("langwell_udc", (g)->name))
+ #define gadget_is_m66592(g)           (!strcmp("m66592_udc", (g)->name))
+ #define gadget_is_musbhdrc(g)         (!strcmp("musb-hdrc", (g)->name))
+@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+               return 0x31;
+       else if (gadget_is_dwc3(gadget))
+               return 0x32;
++      else if (gadget_is_jz4740(gadget))
++              return 0x33;
+       return -ENOENT;
+ }
+diff --git a/drivers/usb/gadget/jz4740_udc.c b/drivers/usb/gadget/jz4740_udc.c
+new file mode 100644
+index 0000000..8d36434
+--- /dev/null
++++ b/drivers/usb/gadget/jz4740_udc.c
+@@ -0,0 +1,2199 @@
++/*
++ * linux/drivers/usb/gadget/jz4740_udc.c
++ *
++ * Ingenic JZ4740 on-chip high speed USB device controller
++ *
++ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc.
++ * Author: <jlwei@ingenic.cn>
++ *
++ * 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.
++ */
++
++/*
++ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint.
++ *
++ *  - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk.
++ *  - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/proc_fs.h>
++#include <linux/usb.h>
++#include <linux/usb/gadget.h>
++#include <linux/clk.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/mach-jz4740/clock.h>
++
++#include "jz4740_udc.h"
++
++#define JZ_REG_UDC_FADDR      0x00 /* Function Address 8-bit */
++#define JZ_REG_UDC_POWER      0x01 /* Power Management 8-bit */
++#define JZ_REG_UDC_INTRIN     0x02 /* Interrupt IN 16-bit */
++#define JZ_REG_UDC_INTROUT    0x04 /* Interrupt OUT 16-bit */
++#define JZ_REG_UDC_INTRINE    0x06 /* Intr IN enable 16-bit */
++#define JZ_REG_UDC_INTROUTE   0x08 /* Intr OUT enable 16-bit */
++#define JZ_REG_UDC_INTRUSB    0x0a /* Interrupt USB 8-bit */
++#define JZ_REG_UDC_INTRUSBE   0x0b /* Interrupt USB Enable 8-bit */
++#define JZ_REG_UDC_FRAME      0x0c /* Frame number 16-bit */
++#define JZ_REG_UDC_INDEX      0x0e /* Index register 8-bit */
++#define JZ_REG_UDC_TESTMODE   0x0f /* USB test mode 8-bit */
++
++#define JZ_REG_UDC_CSR0               0x12 /* EP0 CSR 8-bit */
++#define JZ_REG_UDC_INMAXP     0x10 /* EP1-2 IN Max Pkt Size 16-bit */
++#define JZ_REG_UDC_INCSR      0x12 /* EP1-2 IN CSR LSB 8/16bit */
++#define JZ_REG_UDC_INCSRH     0x13 /* EP1-2 IN CSR MSB 8-bit */
++
++#define JZ_REG_UDC_OUTMAXP    0x14 /* EP1 OUT Max Pkt Size 16-bit */
++#define JZ_REG_UDC_OUTCSR     0x16 /* EP1 OUT CSR LSB 8/16bit */
++#define JZ_REG_UDC_OUTCSRH    0x17 /* EP1 OUT CSR MSB 8-bit */
++#define JZ_REG_UDC_OUTCOUNT   0x18 /* bytes in EP0/1 OUT FIFO 16-bit */
++
++#define JZ_REG_UDC_EP_FIFO(x) (4 * (x) + 0x20)
++
++#define JZ_REG_UDC_EPINFO     0x78 /* Endpoint information */
++#define JZ_REG_UDC_RAMINFO    0x79 /* RAM information */
++
++#define JZ_REG_UDC_INTR               0x200 /* DMA pending interrupts */
++#define JZ_REG_UDC_CNTL1      0x204 /* DMA channel 1 control */
++#define JZ_REG_UDC_ADDR1      0x208 /* DMA channel 1 AHB memory addr */
++#define JZ_REG_UDC_COUNT1     0x20c /* DMA channel 1 byte count */
++#define JZ_REG_UDC_CNTL2      0x214 /* DMA channel 2 control */
++#define JZ_REG_UDC_ADDR2      0x218 /* DMA channel 2 AHB memory addr */
++#define JZ_REG_UDC_COUNT2     0x21c /* DMA channel 2 byte count */
++
++/* Power register bit masks */
++#define USB_POWER_SUSPENDM    0x01
++#define USB_POWER_RESUME      0x04
++#define USB_POWER_HSMODE      0x10
++#define USB_POWER_HSENAB      0x20
++#define USB_POWER_SOFTCONN    0x40
++
++/* Interrupt register bit masks */
++#define USB_INTR_SUSPEND      0x01
++#define USB_INTR_RESUME               0x02
++#define USB_INTR_RESET                0x04
++
++#define USB_INTR_EP0          0x0001
++#define USB_INTR_INEP1                0x0002
++#define USB_INTR_INEP2                0x0004
++#define USB_INTR_OUTEP1               0x0002
++
++/* CSR0 bit masks */
++#define USB_CSR0_OUTPKTRDY    0x01
++#define USB_CSR0_INPKTRDY     0x02
++#define USB_CSR0_SENTSTALL    0x04
++#define USB_CSR0_DATAEND      0x08
++#define USB_CSR0_SETUPEND     0x10
++#define USB_CSR0_SENDSTALL    0x20
++#define USB_CSR0_SVDOUTPKTRDY 0x40
++#define USB_CSR0_SVDSETUPEND  0x80
++
++/* Endpoint CSR register bits */
++#define USB_INCSRH_AUTOSET    0x80
++#define USB_INCSRH_ISO                0x40
++#define USB_INCSRH_MODE               0x20
++#define USB_INCSRH_DMAREQENAB 0x10
++#define USB_INCSRH_DMAREQMODE 0x04
++#define USB_INCSR_CDT         0x40
++#define USB_INCSR_SENTSTALL   0x20
++#define USB_INCSR_SENDSTALL   0x10
++#define USB_INCSR_FF          0x08
++#define USB_INCSR_UNDERRUN    0x04
++#define USB_INCSR_FFNOTEMPT   0x02
++#define USB_INCSR_INPKTRDY    0x01
++
++#define USB_OUTCSRH_AUTOCLR   0x80
++#define USB_OUTCSRH_ISO               0x40
++#define USB_OUTCSRH_DMAREQENAB        0x20
++#define USB_OUTCSRH_DNYT      0x10
++#define USB_OUTCSRH_DMAREQMODE        0x08
++#define USB_OUTCSR_CDT                0x80
++#define USB_OUTCSR_SENTSTALL  0x40
++#define USB_OUTCSR_SENDSTALL  0x20
++#define USB_OUTCSR_FF         0x10
++#define USB_OUTCSR_DATAERR    0x08
++#define USB_OUTCSR_OVERRUN    0x04
++#define USB_OUTCSR_FFFULL     0x02
++#define USB_OUTCSR_OUTPKTRDY  0x01
++
++/* DMA control bits */
++#define USB_CNTL_ENA          0x01
++#define USB_CNTL_DIR_IN               0x02
++#define USB_CNTL_MODE_1               0x04
++#define USB_CNTL_INTR_EN      0x08
++#define USB_CNTL_EP(n)                ((n) << 4)
++#define USB_CNTL_BURST_0      (0 << 9)
++#define USB_CNTL_BURST_4      (1 << 9)
++#define USB_CNTL_BURST_8      (2 << 9)
++#define USB_CNTL_BURST_16     (3 << 9)
++
++
++#ifndef DEBUG
++# define DEBUG(fmt,args...) do {} while(0)
++#endif
++#ifndef DEBUG_EP0
++# define NO_STATES
++# define DEBUG_EP0(fmt,args...) do {} while(0)
++#endif
++#ifndef DEBUG_SETUP
++# define DEBUG_SETUP(fmt,args...) do {} while(0)
++#endif
++
++static struct jz4740_udc jz4740_udc_controller;
++
++/*
++ * Local declarations.
++ */
++static int jz4740_udc_start(struct usb_gadget_driver *driver,
++              int (*bind)(struct usb_gadget *));
++static int jz4740_udc_stop(struct usb_gadget_driver *driver);
++static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep);
++static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr);
++
++static void done(struct jz4740_ep *ep, struct jz4740_request *req,
++               int status);
++static void pio_irq_enable(struct jz4740_ep *ep);
++static void pio_irq_disable(struct jz4740_ep *ep);
++static void stop_activity(struct jz4740_udc *dev,
++                        struct usb_gadget_driver *driver);
++static void nuke(struct jz4740_ep *ep, int status);
++static void flush(struct jz4740_ep *ep);
++static void udc_set_address(struct jz4740_udc *dev, unsigned char address);
++
++/*-------------------------------------------------------------------------*/
++
++/* inline functions of register read/write/set/clear  */
++
++static inline uint8_t usb_readb(struct jz4740_udc *udc, size_t reg)
++{
++      return readb(udc->base + reg);
++}
++
++static inline uint16_t usb_readw(struct jz4740_udc *udc, size_t reg)
++{
++      return readw(udc->base + reg);
++}
++
++static inline uint32_t usb_readl(struct jz4740_udc *udc, size_t reg)
++{
++      return readl(udc->base + reg);
++}
++
++static inline void usb_writeb(struct jz4740_udc *udc, size_t reg, uint8_t val)
++{
++      writeb(val, udc->base + reg);
++}
++
++static inline void usb_writew(struct jz4740_udc *udc, size_t reg, uint16_t val)
++{
++      writew(val, udc->base + reg);
++}
++
++static inline void usb_writel(struct jz4740_udc *udc, size_t reg, uint32_t val)
++{
++      writel(val, udc->base + reg);
++}
++
++static inline void usb_setb(struct jz4740_udc *udc, size_t reg, uint8_t mask)
++{
++      usb_writeb(udc, reg, usb_readb(udc, reg) | mask);
++}
++
++static inline void usb_setw(struct jz4740_udc *udc, size_t reg, uint16_t mask)
++{
++      usb_writew(udc, reg, usb_readw(udc, reg) | mask);
++}
++
++static inline void usb_clearb(struct jz4740_udc *udc, size_t reg, uint8_t mask)
++{
++      usb_writeb(udc, reg, usb_readb(udc, reg) & ~mask);
++}
++
++static inline void usb_clearw(struct jz4740_udc *udc, size_t reg, uint16_t mask)
++{
++      usb_writew(udc, reg, usb_readw(udc, reg) & ~mask);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static inline void jz_udc_set_index(struct jz4740_udc *udc, uint8_t index)
++{
++      usb_writeb(udc, JZ_REG_UDC_INDEX, index);
++}
++
++static inline void jz_udc_select_ep(struct jz4740_ep *ep)
++{
++      jz_udc_set_index(ep->dev, ep_index(ep));
++}
++
++static inline int write_packet(struct jz4740_ep *ep,
++                                 struct jz4740_request *req, unsigned int count)
++{
++      uint8_t *buf;
++      unsigned int length;
++      void __iomem *fifo = ep->dev->base + ep->fifo;
++
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      buf = req->req.buf + req->req.actual;
++
++      length = req->req.length - req->req.actual;
++      if (length > count)
++              length = count;
++      req->req.actual += length;
++
++      DEBUG("Write %d (count %d), fifo %x\n", length, count, ep->fifo);
++
++      writesl(fifo, buf, length >> 2);
++      writesb(fifo, &buf[length - (length & 3)], length & 3);
++
++      return length;
++}
++
++static int read_packet(struct jz4740_ep *ep,
++                                struct jz4740_request *req, unsigned int count)
++{
++      uint8_t *buf;
++      unsigned int length;
++      void __iomem *fifo = ep->dev->base + ep->fifo;
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      buf = req->req.buf + req->req.actual;
++
++      length = req->req.length - req->req.actual;
++      if (length > count)
++              length = count;
++      req->req.actual += length;
++
++      DEBUG("Read %d, fifo %x\n", length, ep->fifo);
++
++      readsl(fifo, buf, length >> 2);
++      readsb(fifo, &buf[length - (length & 3)], length & 3);
++
++      return length;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ *    udc_disable - disable USB device controller
++ */
++static void udc_disable(struct jz4740_udc *dev)
++{
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      udc_set_address(dev, 0);
++
++      /* Disable interrupts */
++      usb_writew(dev, JZ_REG_UDC_INTRINE, 0);
++      usb_writew(dev, JZ_REG_UDC_INTROUTE, 0);
++      usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0);
++
++      /* Disable DMA */
++      usb_writel(dev, JZ_REG_UDC_CNTL1, 0);
++      usb_writel(dev, JZ_REG_UDC_CNTL2, 0);
++
++      /* Disconnect from usb */
++      usb_clearb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN);
++
++      /* Disable the USB PHY */
++      clk_disable(dev->clk);
++
++      dev->ep0state = WAIT_FOR_SETUP;
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      return;
++}
++
++/*
++ *    udc_reinit - initialize software state
++ */
++static void udc_reinit(struct jz4740_udc *dev)
++{
++      int i;
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      /* device/ep0 records init */
++      INIT_LIST_HEAD(&dev->gadget.ep_list);
++      INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
++      dev->ep0state = WAIT_FOR_SETUP;
++
++      for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
++              struct jz4740_ep *ep = &dev->ep[i];
++
++              if (i != 0)
++                      list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
++
++              INIT_LIST_HEAD(&ep->queue);
++              ep->desc = 0;
++              ep->stopped = 0;
++      }
++}
++
++/* until it's enabled, this UDC should be completely invisible
++ * to any USB host.
++ */
++static void udc_enable(struct jz4740_udc *dev)
++{
++      int i;
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      /* UDC state is incorrect - Added by River */
++      if (dev->state != UDC_STATE_ENABLE) {
++              return;
++      }
++
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* Flush FIFO for each */
++      for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
++              struct jz4740_ep *ep = &dev->ep[i];
++
++              jz_udc_select_ep(ep);
++              flush(ep);
++      }
++
++      /* Set this bit to allow the UDC entering low-power mode when
++       * there are no actions on the USB bus.
++       * UDC still works during this bit was set.
++       */
++      jz4740_clock_udc_enable_auto_suspend();
++
++      /* Enable the USB PHY */
++      clk_enable(dev->clk);
++
++      /* Disable interrupts */
++/*    usb_writew(dev, JZ_REG_UDC_INTRINE, 0);
++      usb_writew(dev, JZ_REG_UDC_INTROUTE, 0);
++      usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0);*/
++
++      /* Enable interrupts */
++      usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_EP0);
++      usb_setb(dev, JZ_REG_UDC_INTRUSBE, USB_INTR_RESET);
++      /* Don't enable rest of the interrupts */
++      /* usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2);
++         usb_setw(dev, JZ_REG_UDC_INTROUTE, USB_INTR_OUTEP1); */
++
++      /* Enable SUSPEND */
++      /* usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SUSPENDM); */
++
++      /* Enable HS Mode */
++      usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_HSENAB);
++
++      /* Let host detect UDC:
++       * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this
++       * transistor on and pull the USBDP pin HIGH.
++       */
++      usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN);
++
++      return;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* keeping it simple:
++ * - one bus driver, initted first;
++ * - one function driver, initted second
++ */
++
++/*
++ * Register entry point for the peripheral controller driver.
++ */
++
++static int jz4740_udc_start(struct usb_gadget_driver *driver,
++              int (*bind)(struct usb_gadget *))
++{
++      struct jz4740_udc *dev = &jz4740_udc_controller;
++      int retval;
++
++      if (!driver || !bind)
++              return -EINVAL;
++
++      if (!dev)
++              return -ENODEV;
++
++      if (dev->driver)
++              return -EBUSY;
++
++      /* hook up the driver */
++      dev->driver = driver;
++      dev->gadget.dev.driver = &driver->driver;
++
++      retval = bind(&dev->gadget);
++      if (retval) {
++              DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name,
++                          driver->driver.name, retval);
++              dev->driver = 0;
++              return retval;
++      }
++
++      /* then enable host detection and ep0; and we're ready
++       * for set_configuration as well as eventual disconnect.
++       */
++      udc_enable(dev);
++
++      DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name,
++            driver->driver.name);
++
++      return 0;
++}
++
++static void stop_activity(struct jz4740_udc *dev,
++                        struct usb_gadget_driver *driver)
++{
++      int i;
++
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      /* don't disconnect drivers more than once */
++      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++              driver = 0;
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* prevent new request submissions, kill any outstanding requests  */
++      for (i = 0; i < UDC_MAX_ENDPOINTS; i++) {
++              struct jz4740_ep *ep = &dev->ep[i];
++
++              ep->stopped = 1;
++
++              jz_udc_select_ep(ep);
++              nuke(ep, -ESHUTDOWN);
++      }
++
++      /* report disconnect; the driver is already quiesced */
++      if (driver) {
++              spin_unlock(&dev->lock);
++              driver->disconnect(&dev->gadget);
++              spin_lock(&dev->lock);
++      }
++
++      /* re-init driver-visible data structures */
++      udc_reinit(dev);
++}
++
++
++/*
++ * Unregister entry point for the peripheral controller driver.
++ */
++static int jz4740_udc_stop(struct usb_gadget_driver *driver)
++{
++      struct jz4740_udc *dev = &jz4740_udc_controller;
++      unsigned long flags;
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      if (!dev)
++              return -ENODEV;
++      if (!driver || driver != dev->driver)
++              return -EINVAL;
++      if (!driver->unbind)
++              return -EBUSY;
++
++      spin_lock_irqsave(&dev->lock, flags);
++      dev->driver = 0;
++      stop_activity(dev, driver);
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      driver->unbind(&dev->gadget);
++
++      udc_disable(dev);
++
++      DEBUG("unregistered driver '%s'\n", driver->driver.name);
++
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/** Write request to FIFO (max write == maxp size)
++ *  Return:  0 = still running, 1 = completed, negative = errno
++ *  NOTE: INDEX register must be set for EP
++ */
++static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req)
++{
++      struct jz4740_udc *dev = ep->dev;
++      uint32_t max, csr;
++
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++      max = le16_to_cpu(ep->desc->wMaxPacketSize);
++
++      csr = usb_readb(dev, ep->csr);
++
++      if (!(csr & USB_INCSR_FFNOTEMPT)) {
++              unsigned count;
++              int is_last, is_short;
++
++              count = write_packet(ep, req, max);
++              usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY);
++
++              /* last packet is usually short (or a zlp) */
++              if (unlikely(count != max))
++                      is_last = is_short = 1;
++              else {
++                      if (likely(req->req.length != req->req.actual)
++                          || req->req.zero)
++                              is_last = 0;
++                      else
++                              is_last = 1;
++                      /* interrupt/iso maxpacket may not fill the fifo */
++                      is_short = unlikely(max < ep_maxpacket(ep));
++              }
++
++              DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__,
++                    ep->ep.name, count,
++                    is_last ? "/L" : "", is_short ? "/S" : "",
++                    req->req.length - req->req.actual, req);
++
++              /* requests complete when all IN data is in the FIFO */
++              if (is_last) {
++                      done(ep, req, 0);
++                      if (list_empty(&ep->queue)) {
++                              pio_irq_disable(ep);
++                      }
++                      return 1;
++              }
++      } else {
++              DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep));
++      }
++
++      return 0;
++}
++
++/** Read to request from FIFO (max read == bytes in fifo)
++ *  Return:  0 = still running, 1 = completed, negative = errno
++ *  NOTE: INDEX register must be set for EP
++ */
++static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req)
++{
++      struct jz4740_udc *dev = ep->dev;
++      uint32_t csr;
++      unsigned count, is_short;
++
++      /* make sure there's a packet in the FIFO. */
++      csr = usb_readb(dev, ep->csr);
++      if (!(csr & USB_OUTCSR_OUTPKTRDY)) {
++              DEBUG("%s: Packet NOT ready!\n", __FUNCTION__);
++              return -EINVAL;
++      }
++
++      /* read all bytes from this packet */
++      count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT);
++
++      is_short = (count < ep->ep.maxpacket);
++
++      count = read_packet(ep, req, count);
++
++      DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n",
++            ep->ep.name, csr, count,
++            is_short ? "/S" : "", req, req->req.actual, req->req.length);
++
++      /* Clear OutPktRdy */
++      usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY);
++
++      /* completion */
++      if (is_short || req->req.actual == req->req.length) {
++              done(ep, req, 0);
++
++              if (list_empty(&ep->queue))
++                      pio_irq_disable(ep);
++              return 1;
++      }
++
++      /* finished that packet.  the next one may be waiting... */
++      return 0;
++}
++
++/*
++ *    done - retire a request; caller blocked irqs
++ *  INDEX register is preserved to keep same
++ */
++static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status)
++{
++      unsigned int stopped = ep->stopped;
++      uint32_t index;
++
++      DEBUG("%s, %p\n", __FUNCTION__, ep);
++      list_del_init(&req->queue);
++
++      if (likely(req->req.status == -EINPROGRESS))
++              req->req.status = status;
++      else
++              status = req->req.status;
++
++      if (status && status != -ESHUTDOWN)
++              DEBUG("complete %s req %p stat %d len %u/%u\n",
++                    ep->ep.name, &req->req, status,
++                    req->req.actual, req->req.length);
++
++      /* don't modify queue heads during completion callback */
++      ep->stopped = 1;
++      /* Read current index (completion may modify it) */
++      index = usb_readb(ep->dev, JZ_REG_UDC_INDEX);
++      spin_unlock_irqrestore(&ep->dev->lock, ep->dev->lock_flags);
++
++      req->req.complete(&ep->ep, &req->req);
++
++      spin_lock_irqsave(&ep->dev->lock, ep->dev->lock_flags);
++      /* Restore index */
++      jz_udc_set_index(ep->dev, index);
++      ep->stopped = stopped;
++}
++
++static inline unsigned int jz4740_udc_ep_irq_enable_reg(struct jz4740_ep *ep)
++{
++      if (ep_is_in(ep))
++              return JZ_REG_UDC_INTRINE;
++      else
++              return JZ_REG_UDC_INTROUTE;
++}
++
++/** Enable EP interrupt */
++static void pio_irq_enable(struct jz4740_ep *ep)
++{
++      DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");
++
++      usb_setw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep)));
++}
++
++/** Disable EP interrupt */
++static void pio_irq_disable(struct jz4740_ep *ep)
++{
++      DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");
++
++      usb_clearw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep)));
++}
++
++/*
++ *    nuke - dequeue ALL requests
++ */
++static void nuke(struct jz4740_ep *ep, int status)
++{
++      struct jz4740_request *req;
++
++      DEBUG("%s, %p\n", __FUNCTION__, ep);
++
++      /* Flush FIFO */
++      flush(ep);
++
++      /* called with irqs blocked */
++      while (!list_empty(&ep->queue)) {
++              req = list_entry(ep->queue.next, struct jz4740_request, queue);
++              done(ep, req, status);
++      }
++
++      /* Disable IRQ if EP is enabled (has descriptor) */
++      if (ep->desc)
++              pio_irq_disable(ep);
++}
++
++/** Flush EP FIFO
++ * NOTE: INDEX register must be set before this call
++ */
++static void flush(struct jz4740_ep *ep)
++{
++      DEBUG("%s: %s\n", __FUNCTION__, ep->ep.name);
++
++      switch (ep->type) {
++      case ep_bulk_in:
++      case ep_interrupt:
++              usb_setb(ep->dev, ep->csr, USB_INCSR_FF);
++              break;
++      case ep_bulk_out:
++              usb_setb(ep->dev, ep->csr, USB_OUTCSR_FF);
++              break;
++      case ep_control:
++              break;
++      }
++}
++
++/**
++ * jz4740_in_epn - handle IN interrupt
++ */
++static void jz4740_in_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr)
++{
++      uint32_t csr;
++      struct jz4740_ep *ep = &dev->ep[ep_idx + 1];
++      struct jz4740_request *req;
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      jz_udc_select_ep(ep);
++
++      csr = usb_readb(dev, ep->csr);
++      DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr);
++
++      if (csr & USB_INCSR_SENTSTALL) {
++              DEBUG("USB_INCSR_SENTSTALL\n");
++              usb_clearb(dev, ep->csr, USB_INCSR_SENTSTALL);
++              return;
++      }
++
++      if (!ep->desc) {
++              DEBUG("%s: NO EP DESC\n", __FUNCTION__);
++              return;
++      }
++
++      if (!list_empty(&ep->queue)) {
++              req = list_first_entry(&ep->queue, struct jz4740_request, queue);
++              write_fifo(ep, req);
++      }
++}
++
++/*
++ * Bulk OUT (recv)
++ */
++static void jz4740_out_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr)
++{
++      struct jz4740_ep *ep = &dev->ep[ep_idx];
++      struct jz4740_request *req;
++
++      DEBUG("%s: %d\n", __FUNCTION__, ep_idx);
++
++      jz_udc_select_ep(ep);
++      if (ep->desc) {
++              uint32_t csr;
++
++              while ((csr = usb_readb(dev, ep->csr)) &
++                     (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) {
++                      DEBUG("%s: %x\n", __FUNCTION__, csr);
++
++                      if (csr & USB_OUTCSR_SENTSTALL) {
++                              DEBUG("%s: stall sent, flush fifo\n",
++                                    __FUNCTION__);
++                              /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */
++                              flush(ep);
++                      } else if (csr & USB_OUTCSR_OUTPKTRDY) {
++                              if (list_empty(&ep->queue))
++                                      req = 0;
++                              else
++                                      req =
++                                              list_entry(ep->queue.next,
++                                                         struct jz4740_request,
++                                                         queue);
++
++                              if (!req) {
++                                      DEBUG("%s: NULL REQ %d\n",
++                                            __FUNCTION__, ep_idx);
++                                      break;
++                              } else {
++                                      read_fifo(ep, req);
++                              }
++                      }
++              }
++      } else {
++              /* Throw packet away.. */
++              DEBUG("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx);
++              flush(ep);
++      }
++}
++
++/** Halt specific EP
++ *  Return 0 if success
++ *  NOTE: Sets INDEX register to EP !
++ */
++static int jz4740_set_halt(struct usb_ep *_ep, int value)
++{
++      struct jz4740_udc *dev;
++      struct jz4740_ep *ep;
++      unsigned long flags;
++
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) {
++              DEBUG("%s, bad ep\n", __FUNCTION__);
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++
++      spin_lock_irqsave(&dev->lock, flags);
++
++      jz_udc_select_ep(ep);
++
++      DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value);
++
++      if (ep_index(ep) == 0) {
++              /* EP0 */
++              usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL);
++      } else if (ep_is_in(ep)) {
++              uint32_t csr = usb_readb(dev, ep->csr);
++              if (value && ((csr & USB_INCSR_FFNOTEMPT)
++                            || !list_empty(&ep->queue))) {
++                      /*
++                       * Attempts to halt IN endpoints will fail (returning -EAGAIN)
++                       * if any transfer requests are still queued, or if the controller
++                       * FIFO still holds bytes that the host hasn\92t collected.
++                       */
++                      spin_unlock_irqrestore(&dev->lock, flags);
++                      DEBUG
++                          ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n",
++                           (csr & USB_INCSR_FFNOTEMPT),
++                           !list_empty(&ep->queue));
++                      return -EAGAIN;
++              }
++              flush(ep);
++              if (value) {
++                      usb_setb(dev, ep->csr, USB_INCSR_SENDSTALL);
++              } else {
++                      usb_clearb(dev, ep->csr, USB_INCSR_SENDSTALL);
++                      usb_setb(dev, ep->csr, USB_INCSR_CDT);
++              }
++      } else {
++
++              flush(ep);
++              if (value) {
++                      usb_setb(dev, ep->csr, USB_OUTCSR_SENDSTALL);
++              } else {
++                      usb_clearb(dev, ep->csr, USB_OUTCSR_SENDSTALL);
++                      usb_setb(dev, ep->csr, USB_OUTCSR_CDT);
++              }
++      }
++
++      ep->stopped = value;
++
++      spin_unlock_irqrestore(&dev->lock, flags);
++
++      DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS");
++
++      return 0;
++}
++
++
++static int jz4740_ep_enable(struct usb_ep *_ep,
++                          const struct usb_endpoint_descriptor *desc)
++{
++      struct jz4740_ep *ep;
++      struct jz4740_udc *dev;
++      unsigned long flags;
++      uint32_t max, csrh = 0;
++
++      DEBUG("%s: trying to enable %s\n", __FUNCTION__, _ep->name);
++
++      if (!_ep || !desc)
++              return -EINVAL;
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (ep->desc || ep->type == ep_control
++          || desc->bDescriptorType != USB_DT_ENDPOINT
++          || ep->bEndpointAddress != desc->bEndpointAddress) {
++              DEBUG("%s, bad ep or descriptor\n", __FUNCTION__);
++              return -EINVAL;
++      }
++
++      /* xfer types must match, except that interrupt ~= bulk */
++      if (ep->bmAttributes != desc->bmAttributes
++          && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
++          && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
++              DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
++              DEBUG("%s, bogus device state\n", __FUNCTION__);
++              return -ESHUTDOWN;
++      }
++
++      max = le16_to_cpu(desc->wMaxPacketSize);
++
++      spin_lock_irqsave(&ep->dev->lock, flags);
++
++      /* Configure the endpoint */
++      jz_udc_select_ep(ep);
++      if (ep_is_in(ep)) {
++              usb_writew(dev, JZ_REG_UDC_INMAXP, max);
++              switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++              case USB_ENDPOINT_XFER_BULK:
++              case USB_ENDPOINT_XFER_INT:
++                      csrh &= ~USB_INCSRH_ISO;
++                      break;
++              case USB_ENDPOINT_XFER_ISOC:
++                      csrh |= USB_INCSRH_ISO;
++                      break;
++              }
++              usb_writeb(dev, JZ_REG_UDC_INCSRH, csrh);
++      }
++      else {
++              usb_writew(dev, JZ_REG_UDC_OUTMAXP, max);
++              switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++              case USB_ENDPOINT_XFER_BULK:
++                       csrh &= ~USB_OUTCSRH_ISO;
++                      break;
++              case USB_ENDPOINT_XFER_INT:
++                      csrh &= ~USB_OUTCSRH_ISO;
++                      csrh |= USB_OUTCSRH_DNYT;
++                      break;
++              case USB_ENDPOINT_XFER_ISOC:
++                      csrh |= USB_OUTCSRH_ISO;
++                      break;
++              }
++              usb_writeb(dev, JZ_REG_UDC_OUTCSRH, csrh);
++      }
++
++
++      ep->stopped = 0;
++      ep->desc = desc;
++      ep->ep.maxpacket = max;
++
++      spin_unlock_irqrestore(&ep->dev->lock, flags);
++
++      /* Reset halt state (does flush) */
++      jz4740_set_halt(_ep, 0);
++
++      DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name);
++
++      return 0;
++}
++
++/** Disable EP
++ *  NOTE: Sets INDEX register
++ */
++static int jz4740_ep_disable(struct usb_ep *_ep)
++{
++      struct jz4740_ep *ep;
++      unsigned long flags;
++
++      DEBUG("%s, %p\n", __FUNCTION__, _ep);
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (!_ep || !ep->desc) {
++              DEBUG("%s, %s not enabled\n", __FUNCTION__,
++                    _ep ? ep->ep.name : NULL);
++              return -EINVAL;
++      }
++
++      spin_lock_irqsave(&ep->dev->lock, flags);
++
++      jz_udc_select_ep(ep);
++
++      /* Nuke all pending requests (does flush) */
++      nuke(ep, -ESHUTDOWN);
++
++      /* Disable ep IRQ */
++      pio_irq_disable(ep);
++
++      ep->desc = 0;
++      ep->stopped = 1;
++
++      spin_unlock_irqrestore(&ep->dev->lock, flags);
++
++      DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name);
++      return 0;
++}
++
++static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
++{
++      struct jz4740_request *req;
++
++      req = kzalloc(sizeof(*req), gfp_flags);
++      if (!req)
++              return NULL;
++
++      INIT_LIST_HEAD(&req->queue);
++
++      return &req->req;
++}
++
++static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req)
++{
++      struct jz4740_request *req;
++
++      req = container_of(_req, struct jz4740_request, req);
++      WARN_ON(!list_empty(&req->queue));
++
++      kfree(req);
++}
++
++/*--------------------------------------------------------------------*/
++
++/** Queue one request
++ *  Kickstart transfer if needed
++ *  NOTE: Sets INDEX register
++ */
++static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req,
++                      gfp_t gfp_flags)
++{
++      struct jz4740_request *req;
++      struct jz4740_ep *ep;
++      struct jz4740_udc *dev;
++
++      DEBUG("%s, %p\n", __FUNCTION__, _ep);
++
++      req = container_of(_req, struct jz4740_request, req);
++      if (unlikely
++          (!_req || !_req->complete || !_req->buf
++           || !list_empty(&req->queue))) {
++              DEBUG("%s, bad params\n", __FUNCTION__);
++              return -EINVAL;
++      }
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) {
++              DEBUG("%s, bad ep\n", __FUNCTION__);
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
++              DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver);
++              return -ESHUTDOWN;
++      }
++
++      DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length,
++            _req->buf);
++
++      spin_lock_irqsave(&dev->lock, dev->lock_flags);
++
++      _req->status = -EINPROGRESS;
++      _req->actual = 0;
++
++      /* kickstart this i/o queue? */
++      DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue),
++            ep->stopped);
++      if (list_empty(&ep->queue) && likely(!ep->stopped)) {
++              uint32_t csr;
++
++              if (unlikely(ep_index(ep) == 0)) {
++                      /* EP0 */
++                      list_add_tail(&req->queue, &ep->queue);
++                      jz4740_ep0_kick(dev, ep);
++                      req = 0;
++              }
++              else if (ep_is_in(ep)) {
++                      /* EP1 & EP2 */
++                      jz_udc_select_ep(ep);
++                      csr = usb_readb(dev, ep->csr);
++                      pio_irq_enable(ep);
++                      if (!(csr & USB_INCSR_FFNOTEMPT)) {
++                              if (write_fifo(ep, req) == 1)
++                                      req = 0;
++                      }
++              } else {
++                      /* EP1 */
++                      jz_udc_select_ep(ep);
++                      csr = usb_readb(dev, ep->csr);
++                      pio_irq_enable(ep);
++                      if (csr & USB_OUTCSR_OUTPKTRDY) {
++                              if (read_fifo(ep, req) == 1)
++                                      req = 0;
++                      }
++              }
++      }
++
++      /* pio or dma irq handler advances the queue. */
++      if (likely(req != 0))
++              list_add_tail(&req->queue, &ep->queue);
++
++      spin_unlock_irqrestore(&dev->lock, dev->lock_flags);
++
++      return 0;
++}
++
++/* dequeue JUST ONE request */
++static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct jz4740_ep *ep;
++      struct jz4740_request *req;
++      unsigned long flags;
++
++      DEBUG("%s, %p\n", __FUNCTION__, _ep);
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (!_ep || ep->type == ep_control)
++              return -EINVAL;
++
++      spin_lock_irqsave(&ep->dev->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->dev->lock, flags);
++              return -EINVAL;
++      }
++      done(ep, req, -ECONNRESET);
++
++      spin_unlock_irqrestore(&ep->dev->lock, flags);
++      return 0;
++}
++
++/** Return bytes in EP FIFO
++ *  NOTE: Sets INDEX register to EP
++ */
++static int jz4740_fifo_status(struct usb_ep *_ep)
++{
++      uint32_t csr;
++      int count = 0;
++      struct jz4740_ep *ep;
++      unsigned long flags;
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (!_ep) {
++              DEBUG("%s, bad ep\n", __FUNCTION__);
++              return -ENODEV;
++      }
++
++      DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep));
++
++      /* LPD can't report unclaimed bytes from IN fifos */
++      if (ep_is_in(ep))
++              return -EOPNOTSUPP;
++
++      spin_lock_irqsave(&ep->dev->lock, flags);
++      jz_udc_select_ep(ep);
++
++      csr = usb_readb(ep->dev, ep->csr);
++      if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN ||
++          csr & 0x1) {
++              count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT);
++      }
++
++      spin_unlock_irqrestore(&ep->dev->lock, flags);
++
++      return count;
++}
++
++/** Flush EP FIFO
++ *  NOTE: Sets INDEX register to EP
++ */
++static void jz4740_fifo_flush(struct usb_ep *_ep)
++{
++      struct jz4740_ep *ep;
++      unsigned long flags;
++
++      DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      ep = container_of(_ep, struct jz4740_ep, ep);
++      if (unlikely(!_ep || (!ep->desc && ep->type == ep_control))) {
++              DEBUG("%s, bad ep\n", __FUNCTION__);
++              return;
++      }
++
++      spin_lock_irqsave(&ep->dev->lock, flags);
++
++      jz_udc_select_ep(ep);
++      flush(ep);
++
++      spin_unlock_irqrestore(&ep->dev->lock, flags);
++}
++
++/****************************************************************/
++/* End Point 0 related functions                                */
++/****************************************************************/
++
++/* return:  0 = still running, 1 = completed, negative = errno */
++static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req)
++{
++      uint32_t max;
++      unsigned count;
++      int is_last;
++
++    DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++      max = ep_maxpacket(ep);
++
++      count = write_packet(ep, req, max);
++
++      /* 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;
++      }
++
++      DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,
++                ep->ep.name, count,
++                is_last ? "/L" : "", req->req.length - req->req.actual, req);
++
++      /* requests complete when all IN data is in the FIFO */
++      if (is_last) {
++              done(ep, req, 0);
++              return 1;
++      }
++
++      return 0;
++}
++
++static inline int jz4740_fifo_read(struct jz4740_ep *ep,
++                                     unsigned char *cp, int max)
++{
++      int bytes;
++      int count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT);
++
++      if (count > max)
++              count = max;
++      bytes = count;
++      while (count--)
++              *cp++ = usb_readb(ep->dev, ep->fifo);
++
++      return bytes;
++}
++
++static inline void jz4740_fifo_write(struct jz4740_ep *ep,
++                                       unsigned char *cp, int count)
++{
++      DEBUG("fifo_write: %d %d\n", ep_index(ep), count);
++      while (count--)
++              usb_writeb(ep->dev, ep->fifo, *cp++);
++}
++
++static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req)
++{
++      struct jz4740_udc *dev = ep->dev;
++      uint32_t csr;
++      uint8_t *buf;
++      unsigned bufferspace, count, is_short;
++
++      DEBUG_EP0("%s\n", __FUNCTION__);
++
++      csr = usb_readb(dev, JZ_REG_UDC_CSR0);
++      if (!(csr & USB_CSR0_OUTPKTRDY))
++              return 0;
++
++      buf = req->req.buf + req->req.actual;
++      prefetchw(buf);
++      bufferspace = req->req.length - req->req.actual;
++
++      /* read all bytes from this packet */
++      if (likely(csr & USB_CSR0_OUTPKTRDY)) {
++              count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT);
++              req->req.actual += min(count, bufferspace);
++      } else                  /* zlp */
++              count = 0;
++
++      is_short = (count < ep->ep.maxpacket);
++      DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n",
++                ep->ep.name, csr, count,
++                is_short ? "/S" : "", req, req->req.actual, req->req.length);
++
++      while (likely(count-- != 0)) {
++              uint8_t byte = (uint8_t)usb_readl(dev, ep->fifo);
++
++              if (unlikely(bufferspace == 0)) {
++                      /* this happens when the driver's buffer
++                       * is smaller than what the host sent.
++                       * discard the extra data.
++                       */
++                      if (req->req.status != -EOVERFLOW)
++                              DEBUG_EP0("%s overflow %d\n", ep->ep.name,
++                                        count);
++                      req->req.status = -EOVERFLOW;
++              } else {
++                      *buf++ = byte;
++                      bufferspace--;
++              }
++      }
++
++      /* completion */
++      if (is_short || req->req.actual == req->req.length) {
++              done(ep, req, 0);
++              return 1;
++      }
++
++      /* finished that packet.  the next one may be waiting... */
++      return 0;
++}
++
++/**
++ * udc_set_address - set the USB address for this device
++ * @address:
++ *
++ * Called from control endpoint function after it decodes a set address setup packet.
++ */
++static void udc_set_address(struct jz4740_udc *dev, unsigned char address)
++{
++      DEBUG_EP0("%s: %d\n", __FUNCTION__, address);
++
++      usb_writeb(dev, JZ_REG_UDC_FADDR, address);
++}
++
++/*
++ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY)
++ *      - if error
++ *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits
++ *      - else
++ *              set USB_CSR0_SVDOUTPKTRDY bit
++                              if last set USB_CSR0_DATAEND bit
++ */
++static void jz4740_ep0_out(struct jz4740_udc *dev, uint32_t csr, int kickstart)
++{
++      struct jz4740_request *req;
++      struct jz4740_ep *ep = &dev->ep[0];
++      int ret;
++
++      DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
++
++      if (list_empty(&ep->queue))
++              req = 0;
++      else
++              req = list_entry(ep->queue.next, struct jz4740_request, queue);
++
++      if (req) {
++              if (req->req.length == 0) {
++                      DEBUG_EP0("ZERO LENGTH OUT!\n");
++                      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
++                      dev->ep0state = WAIT_FOR_SETUP;
++                      return;
++              } else if (kickstart) {
++                      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY));
++                      return;
++              }
++              ret = read_fifo_ep0(ep, req);
++              if (ret) {
++                      /* Done! */
++                      DEBUG_EP0("%s: finished, waiting for status\n",
++                                __FUNCTION__);
++                      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
++                      dev->ep0state = WAIT_FOR_SETUP;
++              } else {
++                      /* Not done yet.. */
++                      DEBUG_EP0("%s: not finished\n", __FUNCTION__);
++                      usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY);
++              }
++      } else {
++              DEBUG_EP0("NO REQ??!\n");
++      }
++}
++
++/*
++ * DATA_STATE_XMIT
++ */
++static int jz4740_ep0_in(struct jz4740_udc *dev, uint32_t csr)
++{
++      struct jz4740_request *req;
++      struct jz4740_ep *ep = &dev->ep[0];
++      int ret, need_zlp = 0;
++
++      DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
++
++      if (list_empty(&ep->queue))
++              req = 0;
++      else
++              req = list_entry(ep->queue.next, struct jz4740_request, queue);
++
++      if (!req) {
++              DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);
++              return 0;
++      }
++
++      if (req->req.length == 0) {
++              usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
++              dev->ep0state = WAIT_FOR_SETUP;
++              return 1;
++      }
++
++      if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) {
++              /* Next write will end with the packet size, */
++              /* so we need zero-length-packet */
++              need_zlp = 1;
++      }
++
++      ret = write_fifo_ep0(ep, req);
++
++      if (ret == 1 && !need_zlp) {
++              /* Last packet */
++              DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__);
++
++              usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
++              dev->ep0state = WAIT_FOR_SETUP;
++      } else {
++              DEBUG_EP0("%s: not finished\n", __FUNCTION__);
++              usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY);
++      }
++
++      if (need_zlp) {
++              DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);
++              usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY);
++              dev->ep0state = DATA_STATE_NEED_ZLP;
++      }
++
++      return 1;
++}
++
++static int jz4740_handle_get_status(struct jz4740_udc *dev,
++                                  struct usb_ctrlrequest *ctrl)
++{
++      struct jz4740_ep *ep0 = &dev->ep[0];
++      struct jz4740_ep *qep;
++      int reqtype = (ctrl->bRequestType & USB_RECIP_MASK);
++      uint16_t val = 0;
++
++    DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++
++      if (reqtype == USB_RECIP_INTERFACE) {
++              /* This is not supported.
++               * And according to the USB spec, this one does nothing..
++               * Just return 0
++               */
++              DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n");
++      } else if (reqtype == USB_RECIP_DEVICE) {
++              DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n");
++              val |= (1 << 0);        /* Self powered */
++              /*val |= (1<<1); *//* Remote wakeup */
++      } else if (reqtype == USB_RECIP_ENDPOINT) {
++              int ep_num = (ctrl->wIndex & ~USB_DIR_IN);
++
++              DEBUG_SETUP
++                      ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n",
++                       ep_num, ctrl->wLength);
++
++              if (ctrl->wLength > 2 || ep_num > 3)
++                      return -EOPNOTSUPP;
++
++              qep = &dev->ep[ep_num];
++              if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0)
++                  && ep_index(qep) != 0) {
++                      return -EOPNOTSUPP;
++              }
++
++              jz_udc_select_ep(qep);
++
++              /* Return status on next IN token */
++              switch (qep->type) {
++              case ep_control:
++                      val =
++                          (usb_readb(dev, qep->csr) & USB_CSR0_SENDSTALL) ==
++                          USB_CSR0_SENDSTALL;
++                      break;
++              case ep_bulk_in:
++              case ep_interrupt:
++                      val =
++                          (usb_readb(dev, qep->csr) & USB_INCSR_SENDSTALL) ==
++                          USB_INCSR_SENDSTALL;
++                      break;
++              case ep_bulk_out:
++                      val =
++                          (usb_readb(dev, qep->csr) & USB_OUTCSR_SENDSTALL) ==
++                          USB_OUTCSR_SENDSTALL;
++                      break;
++              }
++
++              /* Back to EP0 index */
++              jz_udc_set_index(dev, 0);
++
++              DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num,
++                          ctrl->wIndex, val);
++      } else {
++              DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype);
++              return -EOPNOTSUPP;
++      }
++
++      /* Clear "out packet ready" */
++      usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY);
++      /* Put status to FIFO */
++      jz4740_fifo_write(ep0, (uint8_t *)&val, sizeof(val));
++      /* Issue "In packet ready" */
++      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
++
++      return 0;
++}
++
++/*
++ * WAIT_FOR_SETUP (OUTPKTRDY)
++ *      - read data packet from EP0 FIFO
++ *      - decode command
++ *      - if error
++ *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits
++ *      - else
++ *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits
++ */
++static void jz4740_ep0_setup(struct jz4740_udc *dev, uint32_t csr)
++{
++      struct jz4740_ep *ep = &dev->ep[0];
++      struct usb_ctrlrequest ctrl;
++      int i;
++
++      DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);
++
++      /* Nuke all previous transfers */
++      nuke(ep, -EPROTO);
++
++      /* read control req from fifo (8 bytes) */
++      jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8);
++
++      DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n",
++                  ctrl.bRequestType, ctrl.bRequest,
++                  ctrl.wValue, ctrl.wIndex, ctrl.wLength);
++
++      /* Set direction of EP0 */
++      if (likely(ctrl.bRequestType & USB_DIR_IN)) {
++              ep->bEndpointAddress |= USB_DIR_IN;
++      } else {
++              ep->bEndpointAddress &= ~USB_DIR_IN;
++      }
++
++      /* Handle some SETUP packets ourselves */
++      switch (ctrl.bRequest) {
++      case USB_REQ_SET_ADDRESS:
++              if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
++                      break;
++
++              DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue);
++              udc_set_address(dev, ctrl.wValue);
++              usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
++              return;
++
++      case USB_REQ_SET_CONFIGURATION:
++              if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
++                      break;
++
++              DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue);
++/*            usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/
++
++              /* Enable RESUME and SUSPEND interrupts */
++              usb_setb(dev, JZ_REG_UDC_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND));
++              break;
++
++      case USB_REQ_SET_INTERFACE:
++              if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
++                      break;
++
++              DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue);
++/*            usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/
++              break;
++
++      case USB_REQ_GET_STATUS:
++              if (jz4740_handle_get_status(dev, &ctrl) == 0)
++                      return;
++
++      case USB_REQ_CLEAR_FEATURE:
++      case USB_REQ_SET_FEATURE:
++              if (ctrl.bRequestType == USB_RECIP_ENDPOINT) {
++                      struct jz4740_ep *qep;
++                      int ep_num = (ctrl.wIndex & 0x0f);
++
++                      /* Support only HALT feature */
++                      if (ctrl.wValue != 0 || ctrl.wLength != 0
++                          || ep_num > 3 || ep_num < 1)
++                              break;
++
++                      qep = &dev->ep[ep_num];
++                      spin_unlock(&dev->lock);
++                      if (ctrl.bRequest == USB_REQ_SET_FEATURE) {
++                              DEBUG_SETUP("SET_FEATURE (%d)\n",
++                                          ep_num);
++                              jz4740_set_halt(&qep->ep, 1);
++                      } else {
++                              DEBUG_SETUP("CLR_FEATURE (%d)\n",
++                                          ep_num);
++                              jz4740_set_halt(&qep->ep, 0);
++                      }
++                      spin_lock(&dev->lock);
++
++                      jz_udc_set_index(dev, 0);
++
++                      /* Reply with a ZLP on next IN token */
++                      usb_setb(dev, JZ_REG_UDC_CSR0,
++                               (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));
++                      return;
++              }
++              break;
++
++      default:
++              break;
++      }
++
++      /* gadget drivers see class/vendor specific requests,
++       * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},
++       * and more.
++       */
++      if (dev->driver) {
++              /* device-2-host (IN) or no data setup command, process immediately */
++              spin_unlock(&dev->lock);
++
++              i = dev->driver->setup(&dev->gadget, &ctrl);
++              spin_lock(&dev->lock);
++
++              if (unlikely(i < 0)) {
++                      /* setup processing failed, force stall */
++                      DEBUG_SETUP
++                          ("  --> ERROR: gadget setup FAILED (stalling), setup returned %d\n",
++                           i);
++                      jz_udc_set_index(dev, 0);
++                      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL));
++
++                      /* ep->stopped = 1; */
++                      dev->ep0state = WAIT_FOR_SETUP;
++              }
++              else {
++                      DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength);
++/*                    if (!ctrl.wLength) {
++                              usb_setb(JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY);
++                      }*/
++              }
++      }
++}
++
++/*
++ * DATA_STATE_NEED_ZLP
++ */
++static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, uint32_t csr)
++{
++      DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
++
++      usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));
++      dev->ep0state = WAIT_FOR_SETUP;
++}
++
++/*
++ * handle ep0 interrupt
++ */
++static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr)
++{
++      struct jz4740_ep *ep = &dev->ep[0];
++      uint32_t csr;
++
++    DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++      /* Set index 0 */
++      jz_udc_set_index(dev, 0);
++      csr = usb_readb(dev, JZ_REG_UDC_CSR0);
++
++      DEBUG_EP0("%s: csr = %x  state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]);
++
++      /*
++       * if SENT_STALL is set
++       *      - clear the SENT_STALL bit
++       */
++      if (csr & USB_CSR0_SENTSTALL) {
++              DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr);
++              usb_clearb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL);
++              nuke(ep, -ECONNABORTED);
++              dev->ep0state = WAIT_FOR_SETUP;
++              return;
++      }
++
++      /*
++       * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear
++       *      - fill EP0 FIFO
++       *      - if last packet
++       *      -       set IN_PKT_RDY | DATA_END
++       *      - else
++       *              set IN_PKT_RDY
++       */
++      if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) {
++              DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n",
++                        __FUNCTION__);
++
++              switch (dev->ep0state) {
++              case DATA_STATE_XMIT:
++                      DEBUG_EP0("continue with DATA_STATE_XMIT\n");
++                      jz4740_ep0_in(dev, csr);
++                      return;
++              case DATA_STATE_NEED_ZLP:
++                      DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n");
++                      jz4740_ep0_in_zlp(dev, csr);
++                      return;
++              default:
++                      /* Stall? */
++//                    DEBUG_EP0("Odd state!! state = %s\n",
++//                              state_names[dev->ep0state]);
++                      dev->ep0state = WAIT_FOR_SETUP;
++                      /* nuke(ep, 0); */
++                      /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */
++//                    break;
++                      return;
++              }
++      }
++
++      /*
++       * if SETUPEND is set
++       *      - abort the last transfer
++       *      - set SERVICED_SETUP_END_BIT
++       */
++      if (csr & USB_CSR0_SETUPEND) {
++              DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr);
++
++              usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDSETUPEND);
++              nuke(ep, 0);
++              dev->ep0state = WAIT_FOR_SETUP;
++      }
++
++      /*
++       * if USB_CSR0_OUTPKTRDY is set
++       *      - read data packet from EP0 FIFO
++       *      - decode command
++       *      - if error
++       *              set SVDOUTPKTRDY | DATAEND | SENDSTALL bits
++       *      - else
++       *              set SVDOUTPKTRDY | DATAEND bits
++       */
++      if (csr & USB_CSR0_OUTPKTRDY) {
++
++              DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,
++                        csr);
++
++              switch (dev->ep0state) {
++              case WAIT_FOR_SETUP:
++                      DEBUG_EP0("WAIT_FOR_SETUP\n");
++                      jz4740_ep0_setup(dev, csr);
++                      break;
++
++              case DATA_STATE_RECV:
++                      DEBUG_EP0("DATA_STATE_RECV\n");
++                      jz4740_ep0_out(dev, csr, 0);
++                      break;
++
++              default:
++                      /* send stall? */
++                      DEBUG_EP0("strange state!! 2. send stall? state = %d\n",
++                                dev->ep0state);
++                      break;
++              }
++      }
++}
++
++static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep)
++{
++      uint32_t csr;
++
++      jz_udc_set_index(dev, 0);
++
++      DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);
++
++      /* Clear "out packet ready" */
++
++      if (ep_is_in(ep)) {
++              usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY);
++              csr = usb_readb(dev, JZ_REG_UDC_CSR0);
++              dev->ep0state = DATA_STATE_XMIT;
++              jz4740_ep0_in(dev, csr);
++      } else {
++              csr = usb_readb(dev, JZ_REG_UDC_CSR0);
++              dev->ep0state = DATA_STATE_RECV;
++              jz4740_ep0_out(dev, csr, 1);
++      }
++}
++
++/** Handle USB RESET interrupt
++ */
++static void jz4740_reset_irq(struct jz4740_udc *dev)
++{
++      dev->gadget.speed = (usb_readb(dev, JZ_REG_UDC_POWER) & USB_POWER_HSMODE) ?
++              USB_SPEED_HIGH : USB_SPEED_FULL;
++
++      DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, 0,
++                  (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" );
++}
++
++/*
++ *    jz4740 usb device interrupt handler.
++ */
++static irqreturn_t jz4740_udc_irq(int irq, void *devid)
++{
++      struct jz4740_udc *jz4740_udc = devid;
++      uint8_t index;
++
++      uint32_t intr_usb = usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSB) & 0x7; /* mask SOF */
++      uint32_t intr_in  = usb_readw(jz4740_udc, JZ_REG_UDC_INTRIN);
++      uint32_t intr_out = usb_readw(jz4740_udc, JZ_REG_UDC_INTROUT);
++      uint32_t intr_dma = usb_readb(jz4740_udc, JZ_REG_UDC_INTR);
++
++      if (!intr_usb && !intr_in && !intr_out && !intr_dma)
++              return IRQ_HANDLED;
++
++
++      DEBUG("intr_out=%x intr_in=%x intr_usb=%x\n",
++            intr_out, intr_in, intr_usb);
++
++      spin_lock(&jz4740_udc->lock);
++      index = usb_readb(jz4740_udc, JZ_REG_UDC_INDEX);
++
++      /* Check for resume from suspend mode */
++      if ((intr_usb & USB_INTR_RESUME) &&
++          (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_RESUME)) {
++              DEBUG("USB resume\n");
++              jz4740_udc->driver->resume(&jz4740_udc->gadget); /* We have suspend(), so we must have resume() too. */
++      }
++
++      /* Check for system interrupts */
++      if (intr_usb & USB_INTR_RESET) {
++              DEBUG("USB reset\n");
++              jz4740_reset_irq(jz4740_udc);
++      }
++
++      /* Check for endpoint 0 interrupt */
++      if (intr_in & USB_INTR_EP0) {
++              DEBUG("USB_INTR_EP0 (control)\n");
++              jz4740_handle_ep0(jz4740_udc, intr_in);
++      }
++
++      /* Check for Bulk-IN DMA interrupt */
++      if (intr_dma & 0x1) {
++              int ep_num;
++              struct jz4740_ep *ep;
++              ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL1) >> 4) & 0xf;
++              ep = &jz4740_udc->ep[ep_num + 1];
++              jz_udc_select_ep(ep);
++              usb_setb(jz4740_udc, ep->csr, USB_INCSR_INPKTRDY);
++/*            jz4740_in_epn(jz4740_udc, ep_num, intr_in);*/
++      }
++
++      /* Check for Bulk-OUT DMA interrupt */
++      if (intr_dma & 0x2) {
++              int ep_num;
++              ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL2) >> 4) & 0xf;
++              jz4740_out_epn(jz4740_udc, ep_num, intr_out);
++      }
++
++      /* Check for each configured endpoint interrupt */
++      if (intr_in & USB_INTR_INEP1) {
++              DEBUG("USB_INTR_INEP1\n");
++              jz4740_in_epn(jz4740_udc, 1, intr_in);
++      }
++
++      if (intr_in & USB_INTR_INEP2) {
++              DEBUG("USB_INTR_INEP2\n");
++              jz4740_in_epn(jz4740_udc, 2, intr_in);
++      }
++
++      if (intr_out & USB_INTR_OUTEP1) {
++              DEBUG("USB_INTR_OUTEP1\n");
++              jz4740_out_epn(jz4740_udc, 1, intr_out);
++      }
++
++      /* Check for suspend mode */
++      if ((intr_usb & USB_INTR_SUSPEND) &&
++          (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_SUSPEND)) {
++              DEBUG("USB suspend\n");
++              jz4740_udc->driver->suspend(&jz4740_udc->gadget);
++              /* Host unloaded from us, can do something, such as flushing
++               the NAND block cache etc. */
++      }
++
++    jz_udc_set_index(jz4740_udc, index);
++
++      spin_unlock(&jz4740_udc->lock);
++
++      return IRQ_HANDLED;
++}
++
++
++
++/*-------------------------------------------------------------------------*/
++
++
++static inline struct jz4740_udc *gadget_to_udc(struct usb_gadget *gadget)
++{
++      return container_of(gadget, struct jz4740_udc, gadget);
++}
++
++static int jz4740_udc_get_frame(struct usb_gadget *_gadget)
++{
++      DEBUG("%s, %p\n", __FUNCTION__, _gadget);
++      return usb_readw(gadget_to_udc(_gadget), JZ_REG_UDC_FRAME);
++}
++
++static int jz4740_udc_wakeup(struct usb_gadget *_gadget)
++{
++      /* host may not have enabled remote wakeup */
++      /*if ((UDCCS0 & UDCCS0_DRWF) == 0)
++         return -EHOSTUNREACH;
++         udc_set_mask_UDCCR(UDCCR_RSM); */
++      return -ENOTSUPP;
++}
++
++static int jz4740_udc_pullup(struct usb_gadget *_gadget, int on)
++{
++      struct jz4740_udc *udc = gadget_to_udc(_gadget);
++      unsigned long flags;
++
++      local_irq_save(flags);
++
++      if (on) {
++              udc->state = UDC_STATE_ENABLE;
++              udc_enable(udc);
++      } else {
++              udc->state = UDC_STATE_DISABLE;
++              udc_disable(udc);
++      }
++
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++
++static const struct usb_gadget_ops jz4740_udc_ops = {
++      .get_frame = jz4740_udc_get_frame,
++      .wakeup = jz4740_udc_wakeup,
++      .pullup = jz4740_udc_pullup,
++      .start = jz4740_udc_start,
++      .stop = jz4740_udc_stop,
++};
++
++static struct usb_ep_ops jz4740_ep_ops = {
++      .enable         = jz4740_ep_enable,
++      .disable        = jz4740_ep_disable,
++
++      .alloc_request  = jz4740_alloc_request,
++      .free_request   = jz4740_free_request,
++
++      .queue          = jz4740_queue,
++      .dequeue        = jz4740_dequeue,
++
++      .set_halt       = jz4740_set_halt,
++      .fifo_status    = jz4740_fifo_status,
++      .fifo_flush     = jz4740_fifo_flush,
++};
++
++
++/*-------------------------------------------------------------------------*/
++
++static struct jz4740_udc jz4740_udc_controller = {
++      .gadget = {
++              .ops = &jz4740_udc_ops,
++              .ep0 = &jz4740_udc_controller.ep[0].ep,
++              .name = "jz4740-udc",
++              .dev = {
++                      .init_name = "gadget",
++              },
++      },
++
++      /* control endpoint */
++      .ep[0] = {
++              .ep = {
++                      .name = "ep0",
++                      .ops = &jz4740_ep_ops,
++                      .maxpacket = EP0_MAXPACKETSIZE,
++              },
++              .dev = &jz4740_udc_controller,
++
++              .bEndpointAddress = 0,
++              .bmAttributes = 0,
++
++              .type = ep_control,
++              .fifo = JZ_REG_UDC_EP_FIFO(0),
++              .csr = JZ_REG_UDC_CSR0,
++      },
++
++      /* bulk out endpoint */
++      .ep[1] = {
++              .ep = {
++                      .name = "ep1out-bulk",
++                      .ops = &jz4740_ep_ops,
++                      .maxpacket = EPBULK_MAXPACKETSIZE,
++              },
++              .dev = &jz4740_udc_controller,
++
++              .bEndpointAddress = 1,
++              .bmAttributes = USB_ENDPOINT_XFER_BULK,
++
++              .type = ep_bulk_out,
++              .fifo = JZ_REG_UDC_EP_FIFO(1),
++              .csr = JZ_REG_UDC_OUTCSR,
++      },
++
++      /* bulk in endpoint */
++      .ep[2] = {
++              .ep = {
++                      .name = "ep1in-bulk",
++                      .ops = &jz4740_ep_ops,
++                      .maxpacket = EPBULK_MAXPACKETSIZE,
++              },
++              .dev = &jz4740_udc_controller,
++
++              .bEndpointAddress = 1 | USB_DIR_IN,
++              .bmAttributes = USB_ENDPOINT_XFER_BULK,
++
++              .type = ep_bulk_in,
++              .fifo = JZ_REG_UDC_EP_FIFO(1),
++              .csr = JZ_REG_UDC_INCSR,
++      },
++
++      /* interrupt in endpoint */
++      .ep[3] = {
++              .ep = {
++                      .name = "ep2in-int",
++                      .ops = &jz4740_ep_ops,
++                      .maxpacket = EPINTR_MAXPACKETSIZE,
++              },
++              .dev = &jz4740_udc_controller,
++
++              .bEndpointAddress = 2 | USB_DIR_IN,
++              .bmAttributes = USB_ENDPOINT_XFER_INT,
++
++              .type = ep_interrupt,
++              .fifo = JZ_REG_UDC_EP_FIFO(2),
++              .csr = JZ_REG_UDC_INCSR,
++      },
++};
++
++static int __devinit jz4740_udc_probe(struct platform_device *pdev)
++{
++      struct jz4740_udc *jz4740_udc = &jz4740_udc_controller;
++      int ret;
++
++      spin_lock_init(&jz4740_udc->lock);
++
++      jz4740_udc->dev = &pdev->dev;
++      jz4740_udc->gadget.dev.parent = &pdev->dev;
++      jz4740_udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
++
++      ret = device_register(&jz4740_udc->gadget.dev);
++      if (ret)
++              return ret;
++
++      jz4740_udc->clk = clk_get(&pdev->dev, "udc");
++      if (IS_ERR(jz4740_udc->clk)) {
++              ret = PTR_ERR(jz4740_udc->clk);
++              dev_err(&pdev->dev, "Failed to get udc clock: %d\n", ret);
++              goto err_device_unregister;
++      }
++
++      platform_set_drvdata(pdev, jz4740_udc);
++
++      jz4740_udc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      if (!jz4740_udc->mem) {
++              ret = -ENOENT;
++              dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
++              goto err_clk_put;
++      }
++
++      jz4740_udc->mem = request_mem_region(jz4740_udc->mem->start,
++      resource_size(jz4740_udc->mem), pdev->name);
++
++      if (!jz4740_udc->mem) {
++              ret = -EBUSY;
++              dev_err(&pdev->dev, "Failed to request mmio memory region\n");
++              goto err_device_unregister;
++      }
++
++      jz4740_udc->base = ioremap(jz4740_udc->mem->start, resource_size(jz4740_udc->mem));
++
++      if (!jz4740_udc->base) {
++              ret = -EBUSY;
++              dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
++              goto err_release_mem_region;
++      }
++
++      jz4740_udc->irq = platform_get_irq(pdev, 0);
++      ret = request_irq(jz4740_udc->irq, jz4740_udc_irq, 0, pdev->name,
++      jz4740_udc);
++      if (ret) {
++              dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
++              goto err_iounmap;
++      }
++
++      ret = usb_add_gadget_udc(&pdev->dev, &jz4740_udc->gadget);
++      if (ret) {
++              dev_err(&pdev->dev, "Failed to add gadget: %d\n", ret);
++              goto err_free_irq;
++      }
++
++      udc_disable(jz4740_udc);
++      udc_reinit(jz4740_udc);
++
++      return 0;
++
++err_free_irq:
++      free_irq(jz4740_udc->irq, pdev);
++err_iounmap:
++      iounmap(jz4740_udc->base);
++err_release_mem_region:
++      release_mem_region(jz4740_udc->mem->start, resource_size(jz4740_udc->mem));
++err_clk_put:
++      clk_put(jz4740_udc->clk);
++err_device_unregister:
++      device_unregister(&jz4740_udc->gadget.dev);
++      platform_set_drvdata(pdev, NULL);
++
++      return ret;
++}
++
++static int __devexit jz4740_udc_remove(struct platform_device *pdev)
++{
++      struct jz4740_udc *dev = platform_get_drvdata(pdev);
++
++      usb_del_gadget_udc(&dev->gadget);
++      if (dev->driver)
++              return -EBUSY;
++
++      udc_disable(dev);
++
++      free_irq(dev->irq, dev);
++      iounmap(dev->base);
++      release_mem_region(dev->mem->start, resource_size(dev->mem));
++      clk_put(dev->clk);
++
++      platform_set_drvdata(pdev, NULL);
++      device_unregister(&dev->gadget.dev);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++
++static int jz4740_udc_suspend(struct device *dev)
++{
++      struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev);
++
++      if (jz4740_udc->state == UDC_STATE_ENABLE)
++              udc_disable(jz4740_udc);
++
++      return 0;
++}
++
++static int jz4740_udc_resume(struct device *dev)
++{
++      struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev);
++
++      if (jz4740_udc->state == UDC_STATE_ENABLE)
++              udc_enable(jz4740_udc);
++
++      return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(jz4740_udc_pm_ops, jz4740_udc_suspend, jz4740_udc_resume);
++#define JZ4740_UDC_PM_OPS (&jz4740_udc_pm_ops)
++
++#else
++#define JZ4740_UDC_PM_OPS NULL
++#endif
++
++static struct platform_driver udc_driver = {
++      .probe          = jz4740_udc_probe,
++      .remove         = __devexit_p(jz4740_udc_remove),
++      .driver         = {
++              .name   = "jz-udc",
++              .owner  = THIS_MODULE,
++              .pm             = JZ4740_UDC_PM_OPS,
++      },
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int __init udc_init (void)
++{
++      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("JZ4740 USB Device Controller");
++MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/usb/gadget/jz4740_udc.h b/drivers/usb/gadget/jz4740_udc.h
+new file mode 100644
+index 0000000..53fd1da
+--- /dev/null
++++ b/drivers/usb/gadget/jz4740_udc.h
+@@ -0,0 +1,101 @@
++/*
++ * linux/drivers/usb/gadget/jz4740_udc.h
++ *
++ * Ingenic JZ4740 on-chip high speed USB device controller
++ *
++ * Copyright (C) 2006 Ingenic Semiconductor Inc.
++ * Author: <jlwei@ingenic.cn>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef __USB_GADGET_JZ4740_H__
++#define __USB_GADGET_JZ4740_H__
++
++/*-------------------------------------------------------------------------*/
++
++// Max packet size
++#define EP0_MAXPACKETSIZE     64
++#define EPBULK_MAXPACKETSIZE          512
++#define EPINTR_MAXPACKETSIZE          64
++
++#define UDC_MAX_ENDPOINTS       4
++
++/*-------------------------------------------------------------------------*/
++
++enum ep_type {
++      ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt
++};
++
++struct jz4740_ep {
++      struct usb_ep ep;
++      struct jz4740_udc *dev;
++
++      const struct usb_endpoint_descriptor *desc;
++
++      uint8_t stopped;
++      uint8_t bEndpointAddress;
++      uint8_t bmAttributes;
++
++      enum ep_type type;
++      size_t fifo;
++      uint32_t csr;
++
++      uint32_t reg_addr;
++      struct list_head queue;
++};
++
++struct jz4740_request {
++      struct usb_request req;
++      struct list_head queue;
++};
++
++enum ep0state {
++      WAIT_FOR_SETUP,         /* between STATUS ack and SETUP report */
++      DATA_STATE_XMIT,        /* data tx stage */
++      DATA_STATE_NEED_ZLP,    /* data tx zlp stage */
++      WAIT_FOR_OUT_STATUS,    /* status stages */
++      DATA_STATE_RECV,        /* data rx stage */
++};
++
++/* For function binding with UDC Disable - Added by River */
++typedef enum {
++      UDC_STATE_ENABLE = 0,
++      UDC_STATE_DISABLE,
++}udc_state_t;
++
++struct jz4740_udc {
++      struct usb_gadget gadget;
++      struct usb_gadget_driver *driver;
++      struct device *dev;
++      spinlock_t lock;
++      unsigned long lock_flags;
++
++      enum ep0state ep0state;
++      struct jz4740_ep ep[UDC_MAX_ENDPOINTS];
++
++      udc_state_t state;
++
++      struct resource *mem;
++      void __iomem *base;
++      int irq;
++
++      struct clk *clk;
++};
++
++#define ep_maxpacket(EP)      ((EP)->ep.maxpacket)
++
++static inline bool ep_is_in(const struct jz4740_ep *ep)
++{
++      return (ep->bEndpointAddress & USB_DIR_IN) == USB_DIR_IN;
++}
++
++static inline uint8_t ep_index(const struct jz4740_ep *ep)
++{
++      return ep->bEndpointAddress & 0xf;
++}
++
++#endif /* __USB_GADGET_JZ4740_H__ */
+-- 
+1.7.5.4
+
This page took 0.077344 seconds and 4 git commands to generate.