fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / usb / gadget / omap_udc.c
index 98cbcbc..cdcfd42 100644 (file)
@@ -22,7 +22,6 @@
 #undef DEBUG
 #undef VERBOSE
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/usb_ch9.h>
 #include <linux/usb_gadget.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -52,7 +52,6 @@
 #include <asm/mach-types.h>
 
 #include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
 
 #include "omap_udc.h"
 /* bulk DMA seems to be behaving for both IN and OUT */
 #define        USE_DMA
 
+/* FIXME: OMAP2 currently has some problem in DMA mode */
+#ifdef CONFIG_ARCH_OMAP2
+#undef USE_DMA
+#endif
+
 /* ISO too */
 #define        USE_ISO
 
@@ -101,7 +105,7 @@ static unsigned fifo_mode = 0;
  * boot parameter "omap_udc:fifo_mode=42"
  */
 module_param (fifo_mode, uint, 0);
-MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
+MODULE_PARM_DESC (fifo_mode, "endpoint configuration");
 
 #ifdef USE_DMA
 static unsigned use_dma = 1;
@@ -124,7 +128,7 @@ static const char driver_desc [] = DRIVER_DESC;
 /*-------------------------------------------------------------------------*/
 
 /* there's a notion of "current endpoint" for modifying endpoint
- * state, and PIO access to its FIFO.  
+ * state, and PIO access to its FIFO.
  */
 
 static void use_ep(struct omap_ep *ep, u16 select)
@@ -167,7 +171,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
        maxp = le16_to_cpu (desc->wMaxPacketSize);
        if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
                                && maxp != ep->maxpacket)
-                       || desc->wMaxPacketSize > ep->maxpacket
+                       || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
                        || !desc->wMaxPacketSize) {
                DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
                return -ERANGE;
@@ -214,7 +218,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
        ep->has_dma = 0;
        ep->lch = -1;
        use_ep(ep, UDC_EP_SEL);
-       UDC_CTRL_REG = UDC_RESET_EP;
+       UDC_CTRL_REG = udc->clr_halt;
        ep->ackwait = 0;
        deselect_ep();
 
@@ -253,7 +257,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
        }
 
        spin_lock_irqsave(&ep->udc->lock, flags);
-       ep->desc = 0;
+       ep->desc = NULL;
        nuke (ep, -ESHUTDOWN);
        ep->ep.maxpacket = ep->maxpacket;
        ep->has_dma = 0;
@@ -270,13 +274,12 @@ static int omap_ep_disable(struct usb_ep *_ep)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_request *
-omap_alloc_request(struct usb_ep *ep, int gfp_flags)
+omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
 {
        struct omap_req *req;
 
-       req = kmalloc(sizeof *req, gfp_flags);
+       req = kzalloc(sizeof(*req), gfp_flags);
        if (req) {
-               memset (req, 0, sizeof *req);
                req->req.dma = DMA_ADDR_INVALID;
                INIT_LIST_HEAD (&req->queue);
        }
@@ -299,7 +302,7 @@ omap_alloc_buffer(
        struct usb_ep   *_ep,
        unsigned        bytes,
        dma_addr_t      *dma,
-       int             gfp_flags
+       gfp_t           gfp_flags
 )
 {
        void            *retval;
@@ -388,13 +391,13 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
 
 /*-------------------------------------------------------------------------*/
 
-#define        FIFO_FULL       (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
-#define        FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL)
+#define UDC_FIFO_FULL          (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
+#define UDC_FIFO_UNWRITABLE    (UDC_EP_HALTED | UDC_FIFO_FULL)
 
 #define FIFO_EMPTY     (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
 #define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
 
-static inline int 
+static inline int
 write_packet(u8 *buf, struct omap_req *req, unsigned max)
 {
        unsigned        len;
@@ -433,7 +436,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
 
        /* PIO-IN isn't double buffered except for iso */
        ep_stat = UDC_STAT_FLG_REG;
-       if (ep_stat & FIFO_UNWRITABLE)
+       if (ep_stat & UDC_FIFO_UNWRITABLE)
                return 0;
 
        count = ep->ep.maxpacket;
@@ -459,7 +462,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
        return is_last;
 }
 
-static inline int 
+static inline int
 read_packet(u8 *buf, struct omap_req *req, unsigned avail)
 {
        unsigned        len;
@@ -504,7 +507,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
                if (ep_stat & UDC_EP_HALTED)
                        break;
 
-               if (ep_stat & FIFO_FULL)
+               if (ep_stat & UDC_FIFO_FULL)
                        avail = ep->ep.maxpacket;
                else  {
                        avail = UDC_RXFSTAT_REG;
@@ -538,6 +541,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
 
 /*-------------------------------------------------------------------------*/
 
+static inline dma_addr_t dma_csac(unsigned lch)
+{
+       dma_addr_t      csac;
+
+       /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+        * read before the DMA controller finished disabling the channel.
+        */
+       csac = OMAP_DMA_CSAC_REG(lch);
+       if (csac == 0)
+               csac = OMAP_DMA_CSAC_REG(lch);
+       return csac;
+}
+
+static inline dma_addr_t dma_cdac(unsigned lch)
+{
+       dma_addr_t      cdac;
+
+       /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+        * read before the DMA controller finished disabling the channel.
+        */
+       cdac = OMAP_DMA_CDAC_REG(lch);
+       if (cdac == 0)
+               cdac = OMAP_DMA_CDAC_REG(lch);
+       return cdac;
+}
+
 static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
 {
        dma_addr_t      end;
@@ -548,7 +577,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
        if (cpu_is_omap15xx())
                return 0;
 
-       end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+       end = dma_csac(ep->lch);
        if (end == ep->dma_counter)
                return 0;
 
@@ -559,14 +588,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
 }
 
 #define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
-               ? OMAP_DMA_CSAC(x) /* really: CPC */ \
-               : OMAP_DMA_CDAC(x))
+               ? OMAP_DMA_CSAC_REG(x) /* really: CPC */ \
+               : dma_cdac(x))
 
 static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
 {
        dma_addr_t      end;
 
-       end = omap_readw(DMA_DEST_LAST(ep->lch));
+       end = DMA_DEST_LAST(ep->lch);
        if (end == ep->dma_counter)
                return 0;
 
@@ -593,24 +622,26 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
                                : OMAP_DMA_SYNC_ELEMENT;
 
        /* measure length in either bytes or packets */
-       if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+       if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
                        || (cpu_is_omap15xx() && length < ep->maxpacket)) {
                txdma_ctrl = UDC_TXN_EOT | length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               length, 1, sync_mode);
+                               length, 1, sync_mode, 0, 0);
        } else {
                length = min(length / ep->maxpacket,
                                (unsigned) UDC_TXN_TSC + 1);
-               txdma_ctrl = length;
-               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               ep->ep.maxpacket, length, sync_mode);
+               txdma_ctrl = length;
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                               ep->ep.maxpacket >> 1, length, sync_mode,
+                               0, 0);
                length *= ep->maxpacket;
        }
        omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
-               OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
+               OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+               0, 0);
 
        omap_start_dma(ep->lch);
-       ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
+       ep->dma_counter = dma_csac(ep->lch);
        UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
        UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
        req->dma_bytes = length;
@@ -650,12 +681,14 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
        packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
        packets = min(packets, (unsigned)UDC_RXN_TC + 1);
        req->dma_bytes = packets * ep->ep.maxpacket;
-       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                       ep->ep.maxpacket, packets,
-                       OMAP_DMA_SYNC_ELEMENT);
+       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                       ep->ep.maxpacket >> 1, packets,
+                       OMAP_DMA_SYNC_ELEMENT,
+                       0, 0);
        omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
-               OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
-       ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
+               OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
+               0, 0);
+       ep->dma_counter = DMA_DEST_LAST(ep->lch);
 
        UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
        UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -666,7 +699,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
 }
 
 static void
-finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
+finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
 {
        u16     count;
 
@@ -674,6 +707,8 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
                ep->dma_counter = (u16) (req->req.dma + req->req.actual);
        count = dma_dest_len(ep, req->req.dma + req->req.actual);
        count += req->req.actual;
+       if (one)
+               count--;
        if (count <= req->req.length)
                req->req.actual = count;
 
@@ -722,7 +757,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
                if (!list_empty(&ep->queue)) {
                        req = container_of(ep->queue.next,
                                        struct omap_req, queue);
-                       finish_out_dma(ep, req, 0);
+                       finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB);
                }
                UDC_IRQ_SRC_REG = UDC_RXN_EOT;
 
@@ -747,7 +782,7 @@ static void dma_error(int lch, u16 ch_status, void *data)
        struct omap_ep  *ep = data;
 
        /* if ch_status & OMAP_DMA_DROP_IRQ ... */
-       /* if ch_status & OMAP_DMA_TOUT_IRQ ... */
+       /* if ch_status & OMAP1_DMA_TOUT_IRQ ... */
        ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status);
 
        /* complete current transfer ... */
@@ -763,7 +798,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                reg = UDC_TXDMA_CFG_REG;
        else
                reg = UDC_RXDMA_CFG_REG;
-       reg |= 1 << 12;         /* "pulse" activated */
+       reg |= UDC_DMA_REQ;             /* "pulse" activated */
 
        ep->dma_channel = 0;
        ep->lch = -1;
@@ -787,20 +822,32 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_TXDMA_CFG_REG = reg;
+                       /* EMIFF */
+                       omap_set_dma_src_burst_mode(ep->lch,
+                                               OMAP_DMA_DATA_BURST_4);
+                       omap_set_dma_src_data_pack(ep->lch, 1);
+                       /* TIPB */
                        omap_set_dma_dest_params(ep->lch,
                                OMAP_DMA_PORT_TIPB,
                                OMAP_DMA_AMODE_CONSTANT,
-                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+                               0, 0);
                }
        } else {
                status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_RXDMA_CFG_REG = reg;
+                       /* TIPB */
                        omap_set_dma_src_params(ep->lch,
                                OMAP_DMA_PORT_TIPB,
                                OMAP_DMA_AMODE_CONSTANT,
-                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+                               (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
+                               0, 0);
+                       /* EMIFF */
+                       omap_set_dma_dest_burst_mode(ep->lch,
+                                               OMAP_DMA_DATA_BURST_4);
+                       omap_set_dma_dest_data_pack(ep->lch, 1);
                }
        }
        if (status)
@@ -811,7 +858,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 
                /* channel type P: hw synch (fifo) */
                if (!cpu_is_omap15xx())
-                       omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
+                       OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
        }
 
 just_restart:
@@ -856,18 +903,22 @@ static void dma_channel_release(struct omap_ep *ep)
        if (!list_empty(&ep->queue))
                req = container_of(ep->queue.next, struct omap_req, queue);
        else
-               req = 0;
+               req = NULL;
 
-       active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
+       active = ((1 << 7) & OMAP_DMA_CCR_REG(ep->lch)) != 0;
 
        DBG("%s release %s %cxdma%d %p\n", ep->ep.name,
                        active ? "active" : "idle",
                        (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
                        ep->dma_channel - 1, req);
 
+       /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before
+        * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them.
+        */
+
        /* wait till current packet DMA finishes, and fifo empties */
        if (ep->bEndpointAddress & USB_DIR_IN) {
-               UDC_TXDMA_CFG_REG &= ~mask;
+               UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
                if (req) {
                        finish_in_dma(ep, req, -ECONNRESET);
@@ -880,13 +931,13 @@ static void dma_channel_release(struct omap_ep *ep)
                while (UDC_TXDMA_CFG_REG & mask)
                        udelay(10);
        } else {
-               UDC_RXDMA_CFG_REG &= ~mask;
+               UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
 
                /* dma empties the fifo */
                while (UDC_RXDMA_CFG_REG & mask)
                        udelay(10);
                if (req)
-                       finish_out_dma(ep, req, -ECONNRESET);
+                       finish_out_dma(ep, req, -ECONNRESET, 0);
        }
        omap_free_dma(ep->lch);
        ep->dma_channel = 0;
@@ -898,7 +949,7 @@ static void dma_channel_release(struct omap_ep *ep)
 /*-------------------------------------------------------------------------*/
 
 static int
-omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 {
        struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
        struct omap_req *req = container_of(_req, struct omap_req, req);
@@ -997,18 +1048,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                                        UDC_IRQ_EN_REG = irq_en;
                                }
 
-                               /* STATUS is reverse direction */
-                               UDC_EP_NUM_REG = is_in
-                                               ? UDC_EP_SEL
-                                               : (UDC_EP_SEL|UDC_EP_DIR);
+                               /* STATUS for zero length DATA stages is
+                                * always an IN ... even for IN transfers,
+                                * a wierd case which seem to stall OMAP.
+                                */
+                               UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
                                UDC_CTRL_REG = UDC_CLR_EP;
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
-                               UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR;
+                               UDC_EP_NUM_REG = UDC_EP_DIR;
 
                                /* cleanup */
                                udc->ep0_pending = 0;
                                done(ep, req, 0);
-                               req = 0;
+                               req = NULL;
 
                        /* non-empty DATA stage */
                        } else if (is_in) {
@@ -1029,7 +1081,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
                        (is_in ? next_in_dma : next_out_dma)(ep, req);
                else if (req) {
                        if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
-                               req = 0;
+                               req = NULL;
                        deselect_ep();
                        if (!is_in) {
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1041,7 +1093,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
 
 irq_wait:
        /* irq handler advances the queue */
-       if (req != 0)
+       if (req != NULL)
                list_add_tail(&req->queue, &ep->queue);
        spin_unlock_irqrestore(&udc->lock, flags);
 
@@ -1077,7 +1129,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
                 */
                dma_channel_release(ep);
                dma_channel_claim(ep, channel);
-       } else 
+       } else
                done(ep, req, -ECONNRESET);
        spin_unlock_irqrestore(&ep->udc->lock, flags);
        return 0;
@@ -1113,7 +1165,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
 
                /* IN endpoints must already be idle */
                if ((ep->bEndpointAddress & USB_DIR_IN)
-                               && !list_empty(&ep->queue)) { 
+                               && !list_empty(&ep->queue)) {
                        status = -EAGAIN;
                        goto done;
                }
@@ -1140,7 +1192,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
                                dma_channel_claim(ep, channel);
                } else {
                        use_ep(ep, 0);
-                       UDC_CTRL_REG = UDC_RESET_EP;
+                       UDC_CTRL_REG = ep->udc->clr_halt;
                        ep->ackwait = 0;
                        if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1238,6 +1290,8 @@ static int can_pullup(struct omap_udc *udc)
 
 static void pullup_enable(struct omap_udc *udc)
 {
+       udc->gadget.dev.parent->power.power_state = PMSG_ON;
+       udc->gadget.dev.power.power_state = PMSG_ON;
        UDC_SYSCON1_REG |= UDC_PULLUP_EN;
 #ifndef CONFIG_USB_OTG
        if (!cpu_is_omap15xx())
@@ -1256,6 +1310,23 @@ static void pullup_disable(struct omap_udc *udc)
        UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
 
+static struct omap_udc *udc;
+
+static void omap_udc_enable_clock(int enable)
+{
+       if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL)
+               return;
+
+       if (enable) {
+               clk_enable(udc->dc_clk);
+               clk_enable(udc->hhc_clk);
+               udelay(100);
+       } else {
+               clk_disable(udc->hhc_clk);
+               clk_disable(udc->dc_clk);
+       }
+}
+
 /*
  * Called by whatever detects VBUS sessions:  external transceiver
  * driver, or maybe GPIO0 VBUS IRQ.  May request 48 MHz clock.
@@ -1276,10 +1347,22 @@ static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
                else
                        FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
        }
+       if (udc->dc_clk != NULL && is_active) {
+               if (!udc->clk_requested) {
+                       omap_udc_enable_clock(1);
+                       udc->clk_requested = 1;
+               }
+       }
        if (can_pullup(udc))
                pullup_enable(udc);
        else
                pullup_disable(udc);
+       if (udc->dc_clk != NULL && !is_active) {
+               if (udc->clk_requested) {
+                       omap_udc_enable_clock(0);
+                       udc->clk_requested = 0;
+               }
+       }
        spin_unlock_irqrestore(&udc->lock, flags);
        return 0;
 }
@@ -1382,7 +1465,7 @@ static void update_otg(struct omap_udc *udc)
 static void ep0_irq(struct omap_udc *udc, u16 irq_src)
 {
        struct omap_ep  *ep0 = &udc->ep[0];
-       struct omap_req *req = 0;
+       struct omap_req *req = NULL;
 
        ep0->irqs++;
 
@@ -1399,7 +1482,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                }
        }
 
-       /* IN/OUT packets mean we're in the DATA or STATUS stage.  
+       /* IN/OUT packets mean we're in the DATA or STATUS stage.
         * This driver uses only uses protocol stalls (ep0 never halts),
         * and if we got this far the gadget driver already had a
         * chance to stall.  Tries to be forgiving of host oddities.
@@ -1438,7 +1521,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                                if (req)
                                        done(ep0, req, 0);
                        }
-                       req = 0;
+                       req = NULL;
                } else if (stat & UDC_STALL) {
                        UDC_CTRL_REG = UDC_CLR_HALT;
                        UDC_EP_NUM_REG = UDC_EP_DIR;
@@ -1467,7 +1550,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                                } else if (stat == 0)
                                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                                UDC_EP_NUM_REG = 0;
-                               
+
                                /* activate status stage */
                                if (stat == 1) {
                                        done(ep0, req, 0);
@@ -1511,9 +1594,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        u.word[3] = UDC_DATA_REG;
                        UDC_EP_NUM_REG = 0;
                } while (UDC_IRQ_SRC_REG & UDC_SETUP);
-               le16_to_cpus (&u.r.wValue);
-               le16_to_cpus (&u.r.wIndex);
-               le16_to_cpus (&u.r.wLength);
+
+#define        w_value         le16_to_cpup (&u.r.wValue)
+#define        w_index         le16_to_cpup (&u.r.wIndex)
+#define        w_length        le16_to_cpup (&u.r.wLength)
 
                /* Delegate almost all control requests to the gadget driver,
                 * except for a handful of ch9 status/feature requests that
@@ -1529,11 +1613,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* udc needs to know when ep != 0 is valid */
                        if (u.r.bRequestType != USB_RECIP_DEVICE)
                                goto delegate;
-                       if (u.r.wLength != 0)
+                       if (w_length != 0)
                                goto do_stall;
                        udc->ep0_set_config = 1;
-                       udc->ep0_reset_config = (u.r.wValue == 0);
-                       VDBG("set config %d\n", u.r.wValue);
+                       udc->ep0_reset_config = (w_value == 0);
+                       VDBG("set config %d\n", w_value);
 
                        /* update udc NOW since gadget driver may start
                         * queueing requests immediately; clear config
@@ -1549,23 +1633,28 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* clear endpoint halt */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       ep = &udc->ep[u.r.wIndex & 0xf];
+                       ep = &udc->ep[w_index & 0xf];
                        if (ep != ep0) {
-                               if (u.r.wIndex & USB_DIR_IN)
+                               if (w_index & USB_DIR_IN)
                                        ep += 16;
                                if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
                                                || !ep->desc)
                                        goto do_stall;
                                use_ep(ep, 0);
-                               UDC_CTRL_REG = UDC_RESET_EP;
+                               UDC_CTRL_REG = udc->clr_halt;
                                ep->ackwait = 0;
                                if (!(ep->bEndpointAddress & USB_DIR_IN)) {
                                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                                        ep->ackwait = 1 + ep->double_buf;
                                }
+                               /* NOTE:  assumes the host behaves sanely,
+                                * only clearing real halts.  Else we may
+                                * need to kill pending transfers and then
+                                * restart the queue... very messy for DMA!
+                                */
                        }
                        VDBG("%s halt cleared by host\n", ep->name);
                        goto ep0out_status_stage;
@@ -1573,11 +1662,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
                        /* set endpoint halt */
                        if (u.r.bRequestType != USB_RECIP_ENDPOINT)
                                goto delegate;
-                       if (u.r.wValue != USB_ENDPOINT_HALT
-                                       || u.r.wLength != 0)
+                       if (w_value != USB_ENDPOINT_HALT
+                                       || w_length != 0)
                                goto do_stall;
-                       ep = &udc->ep[u.r.wIndex & 0xf];
-                       if (u.r.wIndex & USB_DIR_IN)
+                       ep = &udc->ep[w_index & 0xf];
+                       if (w_index & USB_DIR_IN)
                                ep += 16;
                        if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
                                        || ep == ep0 || !ep->desc)
@@ -1615,13 +1704,13 @@ ep0out_status_stage:
                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                        UDC_EP_NUM_REG = UDC_EP_DIR;
                        status = 0;
-                       VDBG("GET_STATUS, interface %d\n", u.r.wIndex);
+                       VDBG("GET_STATUS, interface %d\n", w_index);
                        /* next, status stage */
                        break;
                default:
 delegate:
                        /* activate the ep0out fifo right away */
-                       if (!udc->ep0_in && u.r.wLength) {
+                       if (!udc->ep0_in && w_length) {
                                UDC_EP_NUM_REG = 0;
                                UDC_CTRL_REG = UDC_SET_FIFO_EN;
                        }
@@ -1632,7 +1721,11 @@ delegate:
                         */
                        VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
                                u.r.bRequestType, u.r.bRequest,
-                               u.r.wValue, u.r.wIndex, u.r.wLength);
+                               w_value, w_index, w_length);
+
+#undef w_value
+#undef w_index
+#undef w_length
 
                        /* The gadget driver may return an error here,
                         * causing an immediate protocol stall.
@@ -1734,8 +1827,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
                                        udc->driver->suspend(&udc->gadget);
                                        spin_lock(&udc->lock);
                                }
+                               if (udc->transceiver)
+                                       otg_set_suspend(udc->transceiver, 1);
                        } else {
                                VDBG("resume\n");
+                               if (udc->transceiver)
+                                       otg_set_suspend(udc->transceiver, 0);
                                if (udc->gadget.speed == USB_SPEED_FULL
                                                && udc->driver->resume) {
                                        spin_unlock(&udc->lock);
@@ -1759,8 +1856,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
        UDC_IRQ_SRC_REG = UDC_DS_CHG;
 }
 
-static irqreturn_t
-omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
+static irqreturn_t omap_udc_irq(int irq, void *_udc)
 {
        struct omap_udc *udc = _udc;
        u16             irq_src;
@@ -1811,7 +1907,7 @@ static void pio_out_timer(unsigned long _ep)
 
        spin_lock_irqsave(&ep->udc->lock, flags);
        if (!list_empty(&ep->queue) && ep->ackwait) {
-               use_ep(ep, 0);
+               use_ep(ep, UDC_EP_SEL);
                stat_flg = UDC_STAT_FLG_REG;
 
                if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
@@ -1821,19 +1917,18 @@ static void pio_out_timer(unsigned long _ep)
                        VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
                        req = container_of(ep->queue.next,
                                        struct omap_req, queue);
-                       UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
                        (void) read_fifo(ep, req);
                        UDC_EP_NUM_REG = ep->bEndpointAddress;
                        UDC_CTRL_REG = UDC_SET_FIFO_EN;
                        ep->ackwait = 1 + ep->double_buf;
-               }
+               } else
+                       deselect_ep();
        }
        mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
        spin_unlock_irqrestore(&ep->udc->lock, flags);
 }
 
-static irqreturn_t
-omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
 {
        u16             epn_stat, irq_src;
        irqreturn_t     status = IRQ_NONE;
@@ -1912,8 +2007,7 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
 }
 
 #ifdef USE_ISO
-static irqreturn_t
-omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
 {
        struct omap_udc *udc = _dev;
        struct omap_ep  *ep;
@@ -1975,7 +2069,17 @@ omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
 
 /*-------------------------------------------------------------------------*/
 
-static struct omap_udc *udc;
+static inline int machine_needs_vbus_session(void)
+{
+       return (machine_is_omap_innovator()
+               || machine_is_omap_osk()
+               || machine_is_omap_apollon()
+#ifndef CONFIG_MACH_OMAP_H4_OTG
+               || machine_is_omap_h4()
+#endif
+               || machine_is_sx1()
+               );
+}
 
 int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 {
@@ -1990,7 +2094,6 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                        // FIXME if otg, check:  driver->is_otg
                        || driver->speed < USB_SPEED_FULL
                        || !driver->bind
-                       || !driver->unbind
                        || !driver->setup)
                return -EINVAL;
 
@@ -2013,16 +2116,19 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        udc->softconnect = 1;
 
        /* hook up the driver */
-       driver->driver.bus = 0;
+       driver->driver.bus = NULL;
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(1);
+
        status = driver->bind (&udc->gadget);
        if (status) {
                DBG("bind to %s --> %d\n", driver->driver.name, status);
-               udc->gadget.dev.driver = 0;
-               udc->driver = 0;
+               udc->gadget.dev.driver = NULL;
+               udc->driver = NULL;
                goto done;
        }
        DBG("bound to driver %s\n", driver->driver.name);
@@ -2034,9 +2140,11 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                status = otg_set_peripheral(udc->transceiver, &udc->gadget);
                if (status < 0) {
                        ERR("can't bind to transceiver\n");
-                       driver->unbind (&udc->gadget);
-                       udc->gadget.dev.driver = 0;
-                       udc->driver = 0;
+                       if (driver->unbind) {
+                               driver->unbind (&udc->gadget);
+                               udc->gadget.dev.driver = NULL;
+                               udc->driver = NULL;
+                       }
                        goto done;
                }
        } else {
@@ -2049,10 +2157,12 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
        /* boards that don't have VBUS sensing can't autogate 48MHz;
         * can't enter deep sleep while a gadget driver is active.
         */
-       if (machine_is_omap_innovator() || machine_is_omap_osk())
+       if (machine_needs_vbus_session())
                omap_vbus_session(&udc->gadget, 1);
 
 done:
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(0);
        return status;
 }
 EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -2064,14 +2174,17 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
        if (!udc)
                return -ENODEV;
-       if (!driver || driver != udc->driver)
+       if (!driver || driver != udc->driver || !driver->unbind)
                return -EINVAL;
 
-       if (machine_is_omap_innovator() || machine_is_omap_osk())
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(1);
+
+       if (machine_needs_vbus_session())
                omap_vbus_session(&udc->gadget, 0);
 
        if (udc->transceiver)
-               (void) otg_set_peripheral(udc->transceiver, 0);
+               (void) otg_set_peripheral(udc->transceiver, NULL);
        else
                pullup_disable(udc);
 
@@ -2080,10 +2193,11 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        spin_unlock_irqrestore(&udc->lock, flags);
 
        driver->unbind(&udc->gadget);
-       udc->gadget.dev.driver = 0;
-       udc->driver = 0;
-
+       udc->gadget.dev.driver = NULL;
+       udc->driver = NULL;
 
+       if (udc->dc_clk != NULL)
+               omap_udc_enable_clock(0);
        DBG("unregistered driver '%s'\n", driver->driver.name);
        return status;
 }
@@ -2166,7 +2280,7 @@ static char *trx_mode(unsigned m, int enabled)
        case 0:         return enabled ? "*6wire" : "unused";
        case 1:         return "4wire";
        case 2:         return "3wire";
-       case 3:         return "6wire";
+       case 3:         return "6wire";
        default:        return "unknown";
        }
 }
@@ -2175,17 +2289,24 @@ static int proc_otg_show(struct seq_file *s)
 {
        u32             tmp;
        u32             trans;
+       char            *ctrl_name;
 
        tmp = OTG_REV_REG;
-       trans = USB_TRANSCEIVER_CTRL_REG;
-       seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
-               tmp >> 4, tmp & 0xf, trans);
+       if (cpu_is_omap24xx()) {
+               ctrl_name = "control_devconf";
+               trans = CONTROL_DEVCONF_REG;
+       } else {
+               ctrl_name = "tranceiver_ctrl";
+               trans = USB_TRANSCEIVER_CTRL_REG;
+       }
+       seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
+               tmp >> 4, tmp & 0xf, ctrl_name, trans);
        tmp = OTG_SYSCON_1_REG;
        seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
                        FOURBITS "\n", tmp,
                trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
                trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
-               (USB0_TRX_MODE(tmp) == 0)
+               (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710())
                        ? "internal"
                        : trx_mode(USB0_TRX_MODE(tmp), 1),
                (tmp & OTG_IDLE_EN) ? " !otg" : "",
@@ -2235,6 +2356,7 @@ static int proc_otg_show(struct seq_file *s)
        seq_printf(s, "otg_outctrl %04x" "\n", tmp);
        tmp = OTG_TEST_REG;
        seq_printf(s, "otg_test    %04x" "\n", tmp);
+       return 0;
 }
 
 static int proc_udc_show(struct seq_file *s, void *_)
@@ -2253,7 +2375,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
                driver_desc,
                use_dma ?  " (dma)" : "");
 
-       tmp = UDC_REV_REG & 0xff; 
+       tmp = UDC_REV_REG & 0xff;
        seq_printf(s,
                "UDC rev %d.%d, fifo mode %d, gadget %s\n"
                "hmc %d, transceiver %s\n",
@@ -2261,11 +2383,16 @@ static int proc_udc_show(struct seq_file *s, void *_)
                fifo_mode,
                udc->driver ? udc->driver->driver.name : "(none)",
                HMC,
-               udc->transceiver ? udc->transceiver->label : "(none)");
-       seq_printf(s, "ULPD control %04x req %04x status %04x\n",
-               __REG16(ULPD_CLOCK_CTRL),
-               __REG16(ULPD_SOFT_REQ),
-               __REG16(ULPD_STATUS_REQ));
+               udc->transceiver
+                       ? udc->transceiver->label
+                       : ((cpu_is_omap1710() || cpu_is_omap24xx())
+                               ? "external" : "(none)"));
+       if (cpu_class_is_omap1()) {
+               seq_printf(s, "ULPD control %04x req %04x status %04x\n",
+                       __REG16(ULPD_CLOCK_CTRL),
+                       __REG16(ULPD_SOFT_REQ),
+                       __REG16(ULPD_STATUS_REQ));
+       }
 
        /* OTG controller registers */
        if (!cpu_is_omap15xx())
@@ -2378,10 +2505,10 @@ static int proc_udc_show(struct seq_file *s, void *_)
 
 static int proc_udc_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, proc_udc_show, 0);
+       return single_open(file, proc_udc_show, NULL);
 }
 
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
        .open           = proc_udc_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -2399,7 +2526,7 @@ static void create_proc_file(void)
 
 static void remove_proc_file(void)
 {
-       remove_proc_entry(proc_filename, 0);
+       remove_proc_entry(proc_filename, NULL);
 }
 
 #else
@@ -2414,6 +2541,10 @@ static inline void remove_proc_file(void) {}
 /* Before this controller can enumerate, we need to pick an endpoint
  * configuration, or "fifo_mode"  That involves allocating 2KB of packet
  * buffer space among the endpoints we'll be operating.
+ *
+ * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
+ * UDC_SYSCON_1_REG.CFG_LOCK is set can now work.  We won't use that
+ * capability yet though.
  */
 static unsigned __init
 omap_ep_setup(char *name, u8 addr, u8 type,
@@ -2446,9 +2577,10 @@ omap_ep_setup(char *name, u8 addr, u8 type,
                dbuf = 1;
        } else {
                /* double-buffering "not supported" on 15xx,
-                * and ignored for PIO-IN on 16xx
+                * and ignored for PIO-IN on newer chips
+                * (for more reliable behavior)
                 */
-               if (!use_dma || cpu_is_omap15xx())
+               if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
                        dbuf = 0;
 
                switch (maxp) {
@@ -2491,7 +2623,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
        ep->bEndpointAddress = addr;
        ep->bmAttributes = type;
        ep->double_buf = dbuf;
-       ep->udc = udc; 
+       ep->udc = udc;
 
        ep->ep.name = ep->name;
        ep->ep.ops = &omap_ep_ops;
@@ -2505,7 +2637,7 @@ static void omap_udc_release(struct device *dev)
 {
        complete(udc->done);
        kfree (udc);
-       udc = 0;
+       udc = NULL;
 }
 
 static int __init
@@ -2524,11 +2656,10 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        /* UDC_PULLUP_EN gates the chip clock */
        // OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 
-       udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+       udc = kzalloc(sizeof(*udc), GFP_KERNEL);
        if (!udc)
                return -ENOMEM;
 
-       memset(udc, 0, sizeof *udc);
        spin_lock_init (&udc->lock);
 
        udc->gadget.ops = &omap_gadget_ops;
@@ -2577,23 +2708,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        case 1:
                OMAP_BULK_EP("ep1in",  USB_DIR_IN  | 1);
                OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+               OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
+
                OMAP_BULK_EP("ep3in",  USB_DIR_IN  | 3);
                OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
+               OMAP_INT_EP("ep10in",  USB_DIR_IN  | 10, 16);
 
                OMAP_BULK_EP("ep5in",  USB_DIR_IN  | 5);
                OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+               OMAP_INT_EP("ep11in",  USB_DIR_IN  | 11, 16);
+
                OMAP_BULK_EP("ep6in",  USB_DIR_IN  | 6);
                OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
+               OMAP_INT_EP("ep12in",  USB_DIR_IN  | 12, 16);
 
                OMAP_BULK_EP("ep7in",  USB_DIR_IN  | 7);
                OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+               OMAP_INT_EP("ep13in",  USB_DIR_IN  | 13, 16);
+               OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16);
+
                OMAP_BULK_EP("ep8in",  USB_DIR_IN  | 8);
                OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
+               OMAP_INT_EP("ep14in",  USB_DIR_IN  | 14, 16);
+               OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16);
+
+               OMAP_BULK_EP("ep15in",  USB_DIR_IN  | 15);
+               OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15);
 
-               OMAP_INT_EP("ep9in",   USB_DIR_IN  | 9, 16);
-               OMAP_INT_EP("ep10out", USB_DIR_IN  | 10, 16);
-               OMAP_INT_EP("ep11in",  USB_DIR_IN  | 9, 16);
-               OMAP_INT_EP("ep12out", USB_DIR_IN  | 10, 16);
                break;
 
 #ifdef USE_ISO
@@ -2635,23 +2776,44 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        return 0;
 }
 
-static int __init omap_udc_probe(struct device *dev)
+static int __init omap_udc_probe(struct platform_device *pdev)
 {
-       struct platform_device  *odev = to_platform_device(dev);
        int                     status = -ENODEV;
        int                     hmc;
-       struct otg_transceiver  *xceiv = 0;
-       const char              *type = 0;
-       struct omap_usb_config  *config = dev->platform_data;
+       struct otg_transceiver  *xceiv = NULL;
+       const char              *type = NULL;
+       struct omap_usb_config  *config = pdev->dev.platform_data;
+       struct clk              *dc_clk;
+       struct clk              *hhc_clk;
 
        /* NOTE:  "knows" the order of the resources! */
-       if (!request_mem_region(odev->resource[0].start, 
-                       odev->resource[0].end - odev->resource[0].start + 1,
+       if (!request_mem_region(pdev->resource[0].start,
+                       pdev->resource[0].end - pdev->resource[0].start + 1,
                        driver_name)) {
                DBG("request_mem_region failed\n");
                return -EBUSY;
        }
 
+       if (cpu_is_omap16xx()) {
+               dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
+               hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck");
+               BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+               /* can't use omap_udc_enable_clock yet */
+               clk_enable(dc_clk);
+               clk_enable(hhc_clk);
+               udelay(100);
+       }
+
+       if (cpu_is_omap24xx()) {
+               dc_clk = clk_get(&pdev->dev, "usb_fck");
+               hhc_clk = clk_get(&pdev->dev, "usb_l4_ick");
+               BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
+               /* can't use omap_udc_enable_clock yet */
+               clk_enable(dc_clk);
+               clk_enable(hhc_clk);
+               udelay(100);
+       }
+
        INFO("OMAP UDC rev %d.%d%s\n",
                UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
                config->otg ? ", Mini-AB" : "");
@@ -2661,7 +2823,7 @@ static int __init omap_udc_probe(struct device *dev)
                hmc = HMC_1510;
                type = "(unknown)";
 
-               if (machine_is_omap_innovator()) {
+               if (machine_is_omap_innovator() || machine_is_sx1()) {
                        /* just set up software VBUS detect, and then
                         * later rig it so we always report VBUS.
                         * FIXME without really sensing VBUS, we can't
@@ -2676,132 +2838,200 @@ static int __init omap_udc_probe(struct device *dev)
                        FUNC_MUX_CTRL_0_REG = tmp;
                }
        } else {
+               /* The transceiver may package some GPIO logic or handle
+                * loopback and/or transceiverless setup; if we find one,
+                * use it.  Except for OTG, we don't _need_ to talk to one;
+                * but not having one probably means no VBUS detection.
+                */
+               xceiv = otg_get_transceiver();
+               if (xceiv)
+                       type = xceiv->label;
+               else if (config->otg) {
+                       DBG("OTG requires external transceiver!\n");
+                       goto cleanup0;
+               }
+
                hmc = HMC_1610;
+
+               if (cpu_is_omap24xx()) {
+                       /* this could be transceiverless in one of the
+                        * "we don't need to know" modes.
+                        */
+                       type = "external";
+                       goto known;
+               }
+
                switch (hmc) {
+               case 0:                 /* POWERUP DEFAULT == 0 */
+               case 4:
+               case 12:
+               case 20:
+                       if (!cpu_is_omap1710()) {
+                               type = "integrated";
+                               break;
+                       }
+                       /* FALL THROUGH */
                case 3:
                case 11:
                case 16:
                case 19:
                case 25:
-                       xceiv = otg_get_transceiver();
                        if (!xceiv) {
                                DBG("external transceiver not registered!\n");
-                               if (config->otg)
-                                       goto cleanup0;
-                               type = "(unknown external)";
-                       } else
-                               type = xceiv->label;
-                       break;
-               case 0:                 /* POWERUP DEFAULT == 0 */
-               case 4:
-               case 12:
-               case 20:
-                       type = "INTEGRATED";
+                               type = "unknown";
+                       }
                        break;
                case 21:                        /* internal loopback */
-                       type = "(loopback)";
+                       type = "loopback";
                        break;
                case 14:                        /* transceiverless */
-                       type = "(none)";
+                       if (cpu_is_omap1710())
+                               goto bad_on_1710;
+                       /* FALL THROUGH */
+               case 13:
+               case 15:
+                       type = "no";
                        break;
 
                default:
+bad_on_1710:
                        ERR("unrecognized UDC HMC mode %d\n", hmc);
-                       return -ENODEV;
+                       goto cleanup0;
                }
        }
-       INFO("hmc mode %d, transceiver %s\n", hmc, type);
+known:
+       INFO("hmc mode %d, %s transceiver\n", hmc, type);
 
        /* a "gadget" abstracts/virtualizes the controller */
-       status = omap_udc_setup(odev, xceiv);
+       status = omap_udc_setup(pdev, xceiv);
        if (status) {
                goto cleanup0;
        }
-       xceiv = 0;
+       xceiv = NULL;
        // "udc" is now valid
        pullup_disable(udc);
 #if    defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
        udc->gadget.is_otg = (config->otg != 0);
 #endif
 
+       /* starting with omap1710 es2.0, clear toggle is a separate bit */
+       if (UDC_REV_REG >= 0x61)
+               udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
+       else
+               udc->clr_halt = UDC_RESET_EP;
+
        /* USB general purpose IRQ:  ep0, state changes, dma, etc */
-       status = request_irq(odev->resource[1].start, omap_udc_irq,
-                       SA_SAMPLE_RANDOM, driver_name, udc);
+       status = request_irq(pdev->resource[1].start, omap_udc_irq,
+                       IRQF_SAMPLE_RANDOM, driver_name, udc);
        if (status != 0) {
-               ERR( "can't get irq %ld, err %d\n",
-                       odev->resource[1].start, status);
+               ERR("can't get irq %d, err %d\n",
+                       (int) pdev->resource[1].start, status);
                goto cleanup1;
        }
 
        /* USB "non-iso" IRQ (PIO for all but ep0) */
-       status = request_irq(odev->resource[2].start, omap_udc_pio_irq,
-                       SA_SAMPLE_RANDOM, "omap_udc pio", udc);
+       status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
+                       IRQF_SAMPLE_RANDOM, "omap_udc pio", udc);
        if (status != 0) {
-               ERR( "can't get irq %ld, err %d\n",
-                       odev->resource[2].start, status);
+               ERR("can't get irq %d, err %d\n",
+                       (int) pdev->resource[2].start, status);
                goto cleanup2;
        }
 #ifdef USE_ISO
-       status = request_irq(odev->resource[3].start, omap_udc_iso_irq,
-                       SA_INTERRUPT, "omap_udc iso", udc);
+       status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
+                       IRQF_DISABLED, "omap_udc iso", udc);
        if (status != 0) {
-               ERR("can't get irq %ld, err %d\n",
-                       odev->resource[3].start, status);
+               ERR("can't get irq %d, err %d\n",
+                       (int) pdev->resource[3].start, status);
                goto cleanup3;
        }
 #endif
+       if (cpu_is_omap16xx()) {
+               udc->dc_clk = dc_clk;
+               udc->hhc_clk = hhc_clk;
+               clk_disable(hhc_clk);
+               clk_disable(dc_clk);
+       }
+
+       if (cpu_is_omap24xx()) {
+               udc->dc_clk = dc_clk;
+               udc->hhc_clk = hhc_clk;
+               /* FIXME OMAP2 don't release hhc & dc clock */
+#if 0
+               clk_disable(hhc_clk);
+               clk_disable(dc_clk);
+#endif
+       }
 
        create_proc_file();
-       device_add(&udc->gadget.dev);
-       return 0;
-
+       status = device_add(&udc->gadget.dev);
+       if (!status)
+               return status;
+       /* If fail, fall through */
 #ifdef USE_ISO
 cleanup3:
-       free_irq(odev->resource[2].start, udc);
+       free_irq(pdev->resource[2].start, udc);
 #endif
 
 cleanup2:
-       free_irq(odev->resource[1].start, udc);
+       free_irq(pdev->resource[1].start, udc);
 
 cleanup1:
        kfree (udc);
-       udc = 0;
+       udc = NULL;
 
 cleanup0:
        if (xceiv)
                put_device(xceiv->dev);
-       release_mem_region(odev->resource[0].start,
-                       odev->resource[0].end - odev->resource[0].start + 1);
+
+       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+               clk_disable(hhc_clk);
+               clk_disable(dc_clk);
+               clk_put(hhc_clk);
+               clk_put(dc_clk);
+       }
+
+       release_mem_region(pdev->resource[0].start,
+                       pdev->resource[0].end - pdev->resource[0].start + 1);
+
        return status;
 }
 
-static int __exit omap_udc_remove(struct device *dev)
+static int __exit omap_udc_remove(struct platform_device *pdev)
 {
-       struct platform_device  *odev = to_platform_device(dev);
-       DECLARE_COMPLETION(done);
+       DECLARE_COMPLETION_ONSTACK(done);
 
        if (!udc)
                return -ENODEV;
+       if (udc->driver)
+               return -EBUSY;
 
        udc->done = &done;
 
        pullup_disable(udc);
        if (udc->transceiver) {
                put_device(udc->transceiver->dev);
-               udc->transceiver = 0;
+               udc->transceiver = NULL;
        }
        UDC_SYSCON1_REG = 0;
 
        remove_proc_file();
 
 #ifdef USE_ISO
-       free_irq(odev->resource[3].start, udc);
+       free_irq(pdev->resource[3].start, udc);
 #endif
-       free_irq(odev->resource[2].start, udc);
-       free_irq(odev->resource[1].start, udc);
+       free_irq(pdev->resource[2].start, udc);
+       free_irq(pdev->resource[1].start, udc);
+
+       if (udc->dc_clk) {
+               if (udc->clk_requested)
+                       omap_udc_enable_clock(0);
+               clk_put(udc->hhc_clk);
+               clk_put(udc->dc_clk);
+       }
 
-       release_mem_region(odev->resource[0].start,
-                       odev->resource[0].end - odev->resource[0].start + 1);
+       release_mem_region(pdev->resource[0].start,
+                       pdev->resource[0].end - pdev->resource[0].start + 1);
 
        device_unregister(&udc->gadget.dev);
        wait_for_completion(&done);
@@ -2809,26 +3039,39 @@ static int __exit omap_udc_remove(struct device *dev)
        return 0;
 }
 
-static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
+/* suspend/resume/wakeup from sysfs (echo > power/state) or when the
+ * system is forced into deep sleep
+ *
+ * REVISIT we should probably reject suspend requests when there's a host
+ * session active, rather than disconnecting, at least on boards that can
+ * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT).  And in any case, we need to
+ * make host resumes and VBUS detection trigger OMAP wakeup events; that
+ * may involve talking to an external transceiver (e.g. isp1301).
+ */
+
+static int omap_udc_suspend(struct platform_device *dev, pm_message_t message)
 {
-       if (level != 0)
-               return 0;
+       u32     devstat;
+
+       devstat = UDC_DEVSTAT_REG;
+
+       /* we're requesting 48 MHz clock if the pullup is enabled
+        * (== we're attached to the host) and we're not suspended,
+        * which would prevent entry to deep sleep...
+        */
+       if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
+               WARN("session active; suspend requires disconnect\n");
+               omap_pullup(&udc->gadget, 0);
+       }
 
-       DBG("suspend, state %d\n", state);
-       omap_pullup(&udc->gadget, 0);
        udc->gadget.dev.power.power_state = PMSG_SUSPEND;
        udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
        return 0;
 }
 
-static int omap_udc_resume(struct device *dev, u32 level)
+static int omap_udc_resume(struct platform_device *dev)
 {
-       if (level != 0)
-               return 0;
-
        DBG("resume + wakeup/SRP\n");
-       udc->gadget.dev.parent->power.power_state = PMSG_ON;
-       udc->gadget.dev.power.power_state = PMSG_ON;
        omap_pullup(&udc->gadget, 1);
 
        /* maybe the host would enumerate us if we nudged it */
@@ -2838,13 +3081,15 @@ static int omap_udc_resume(struct device *dev, u32 level)
 
 /*-------------------------------------------------------------------------*/
 
-static struct device_driver udc_driver = {
-       .name           = (char *) driver_name,
-       .bus            = &platform_bus_type,
+static struct platform_driver udc_driver = {
        .probe          = omap_udc_probe,
        .remove         = __exit_p(omap_udc_remove),
        .suspend        = omap_udc_suspend,
        .resume         = omap_udc_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = (char *) driver_name,
+       },
 };
 
 static int __init udc_init(void)
@@ -2855,13 +3100,13 @@ static int __init udc_init(void)
 #endif
                "%s\n", driver_desc,
                use_dma ?  " (dma)" : "");
-       return driver_register(&udc_driver);
+       return platform_driver_register(&udc_driver);
 }
 module_init(udc_init);
 
 static void __exit udc_exit(void)
 {
-       driver_unregister(&udc_driver);
+       platform_driver_unregister(&udc_driver);
 }
 module_exit(udc_exit);