]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/usb/gadget/s3c-hsotg.c
USB: s3c-hsotg: Ensure FIFOs are fully flushed after layout
[net-next-2.6.git] / drivers / usb / gadget / s3c-hsotg.c
index 1f73b485732d1b74028064e37193ce6f56021718..26193eceb3231d48c06e98b29a09cf9849b319f5 100644 (file)
@@ -297,6 +297,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
  */
 static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
 {
+       unsigned int ep;
+       unsigned int addr;
+       unsigned int size;
+       int timeout;
+       u32 val;
+
        /* the ryu 2.6.24 release ahs
           writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
           writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
@@ -310,6 +316,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
        writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
               S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
               hsotg->regs + S3C_GNPTXFSIZ);
+
+       /* arange all the rest of the TX FIFOs, as some versions of this
+        * block have overlapping default addresses. This also ensures
+        * that if the settings have been changed, then they are set to
+        * known values. */
+
+       /* start at the end of the GNPTXFSIZ, rounded up */
+       addr = 2048 + 1024;
+       size = 768;
+
+       /* currently we allocate TX FIFOs for all possible endpoints,
+        * and assume that they are all the same size. */
+
+       for (ep = 0; ep <= 15; ep++) {
+               val = addr;
+               val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
+               addr += size;
+
+               writel(val, hsotg->regs + S3C_DPTXFSIZn(ep));
+       }
+
+       /* according to p428 of the design guide, we need to ensure that
+        * all fifos are flushed before continuing */
+
+       writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh |
+              S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL);
+
+       /* wait until the fifos are both flushed */
+       timeout = 100;
+       while (1) {
+               val = readl(hsotg->regs + S3C_GRSTCTL);
+
+               if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0)
+                       break;
+
+               if (--timeout == 0) {
+                       dev_err(hsotg->dev,
+                               "%s: timeout flushing fifos (GRSTCTL=%08x)\n",
+                               __func__, val);
+               }
+
+               udelay(1);
+       }
+
+       dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout);
 }
 
 /**
@@ -2574,6 +2625,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
               hsotg->regs + S3C_DCTL);
 
+       /* must be at-least 3ms to allow bus to see disconnect */
+       msleep(3);
+
        /* remove the soft-disconnect and let's go */
        __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
 
@@ -2730,6 +2784,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
 
        writel(0, hsotg->regs + S3C_DAINTMSK);
 
+       /* Be in disconnected state until gadget is registered */
+       __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
+
        if (0) {
                /* post global nak until we're ready */
                writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,