patch to latest usbhost patch
[kernel-power] / usbhost / usb / musb / musb_core.c
index 6adab83..27c7948 100644 (file)
@@ -142,6 +142,59 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
 
+
+
+inline void mbusywait(int ms)
+{
+       unsigned long end_time = jiffies + msecs_to_jiffies(ms);
+       while(time_before(jiffies,end_time))
+               cpu_relax();
+
+}
+
+void musb_force_term(void __iomem *addr, enum musb_term term)
+{
+       u8 r;
+
+
+       r = musb_ulpi_readb(addr, ISP1704_OTG_CTRL);
+       r |= ISP1704_OTG_CTRL_DP_PULLDOWN | ISP1704_OTG_CTRL_DM_PULLDOWN;
+       musb_ulpi_writeb(addr, ISP1704_OTG_CTRL, r);
+
+       r = musb_ulpi_readb(addr, ISP1704_FUNC_CTRL);
+
+       switch(term) {
+
+       case MUSB_TERM_HOST_HIGHSPEED:
+               r &= ~ISP1704_FUNC_CTRL_XCVRSELECT;
+               r &= ~ISP1704_FUNC_CTRL_TERMSELECT;
+               r &= ~ISP1704_FUNC_CTRL_OPMODE;
+               break;
+
+       case MUSB_TERM_HOST_FULLSPEED:
+               r |= 1 << ISP1704_FUNC_CTRL_XCVRSELECT_SHIFT;
+               r |= ISP1704_FUNC_CTRL_TERMSELECT;
+               r &= ~ISP1704_FUNC_CTRL_OPMODE;
+               break;
+
+       case MUSB_TERM_HOST_LOWSPEED:
+               r |= 2 << ISP1704_FUNC_CTRL_XCVRSELECT_SHIFT;
+               r |= ISP1704_FUNC_CTRL_TERMSELECT;
+               r &= ~ISP1704_FUNC_CTRL_OPMODE;
+               break;
+
+       default:
+               ERR("Unknown musb termination\n");
+               return;
+       }
+
+       r |= ISP1704_OTG_CTRL_IDPULLUP;
+       musb_ulpi_writeb(addr, ISP1704_FUNC_CTRL, r);
+
+}
+
+
+
 static inline int musb_verify_charger(void __iomem *addr)
 {
        u8 r, ret = 0;
@@ -220,6 +273,8 @@ static int musb_charger_detect(struct musb *musb)
 
        u8              vdat = 0;
        u8              r;
+       u8 testmode;
+       testmode = musb_readb(musb->mregs,MUSB_TESTMODE);
 
        msleep(5);
 
@@ -297,7 +352,7 @@ static int musb_charger_detect(struct musb *musb)
                        break;
        }
 
-       if (vdat) {
+       if (vdat && !(testmode & MUSB_TEST_FORCE_HOST)) {
                /* REVISIT: This code works only with dedicated chargers!
                 * When support for HOST/HUB chargers is added, don't
                 * forget this.
@@ -349,7 +404,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
 
        prefetch((u8 *)src);
 
-       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+       DBG(6, "%cX ep%d fifo %p count %d buf %p\n",
                        'T', hw_ep->epnum, fifo, len, src);
 
        /* we can't assume unaligned reads work */
@@ -387,7 +442,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 {
        void __iomem *fifo = hw_ep->fifo;
 
-       DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+       DBG(6, "%cX ep%d fifo %p count %d buf %p\n",
                        'R', hw_ep->epnum, fifo, len, dst);
 
        /* we can't assume unaligned writes work */
@@ -490,7 +545,6 @@ void musb_otg_timer_func(unsigned long data)
 {
        struct musb     *musb = (struct musb *)data;
        unsigned long   flags;
-
        spin_lock_irqsave(&musb->lock, flags);
        switch (musb->xceiv->state) {
        case OTG_STATE_B_WAIT_ACON:
@@ -572,10 +626,19 @@ void musb_hnp_stop(struct musb *musb)
 static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                u8 devctl, u8 power)
 {
+       u8 testmode;
        irqreturn_t handled = IRQ_NONE;
        void __iomem *mbase = musb->mregs;
        u8 r;
 
+       testmode = musb_readb(mbase,MUSB_TESTMODE);
+  if(testmode & MUSB_TEST_FORCE_HOST) {
+               if(int_usb & MUSB_INTR_SESSREQ) {
+                       DBG(1,"Piggybacking CONNECT on SESS REQ\n");
+                       musb->int_usb |= MUSB_INTR_CONNECT;
+               } 
+       }
+
        DBG(3, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
                int_usb);
 
@@ -630,6 +693,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                } else {
                        switch (musb->xceiv->state) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
+                       case OTG_STATE_A_WAIT_BCON:
+                       case OTG_STATE_A_HOST:
                        case OTG_STATE_A_SUSPEND:
                                /* possibly DISCONNECT is upcoming */
                                musb->xceiv->state = OTG_STATE_A_HOST;
@@ -678,7 +743,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                 * be discarded silently.
                 */
                if ((devctl & MUSB_DEVCTL_VBUS)
-                   && !(devctl & MUSB_DEVCTL_BDEVICE)) {
+                   && host_mode(musb->mregs)) {
                        musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
                        musb->ep0_stage = MUSB_EP0_START;
                        musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -796,9 +861,15 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                        + msecs_to_jiffies(musb->a_wait_bcon));
                        break;
                case OTG_STATE_A_HOST:
+                       if(testmode & MUSB_TEST_FORCE_HOST) {
+                               //                              musb->int_usb |= MUSB_INTR_RESUME;
+                               break;
+                       }
+
                        musb->xceiv->state = OTG_STATE_A_SUSPEND;
                        musb->is_active = is_otg_enabled(musb)
                                        && musb->xceiv->host->b_hnp_enable;
+
                        break;
                case OTG_STATE_B_HOST:
                        /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -818,6 +889,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                musb->is_active = 1;
                set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 
+
                musb->ep0_stage = MUSB_EP0_START;
 
 #ifdef CONFIG_USB_MUSB_OTG
@@ -836,9 +908,65 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                musb->port1_status |= USB_PORT_STAT_CONNECTION
                                        |(USB_PORT_STAT_C_CONNECTION << 16);
 
-               /* high vs full speed is just a guess until after reset */
-               if (devctl & MUSB_DEVCTL_LSDEV)
-                       musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+               if (testmode & MUSB_TEST_FORCE_HOST) {
+                       u8 r,reg;
+      void __iomem *mbase = musb->mregs;
+
+                       musb_force_term(musb->mregs,MUSB_TERM_HOST_HIGHSPEED);
+
+                       r = musb_ulpi_readb(mbase, ISP1704_DEBUG);
+                       DBG(1,"Linestate %x\n",r);
+                       switch(r) {
+                       case 2:
+                               musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+                               reg = musb_readb(mbase, MUSB_TESTMODE);
+                               reg &= ~MUSB_TEST_FORCE_FS;
+                               reg &= ~MUSB_TEST_FORCE_HS;
+                               musb_writeb(mbase, MUSB_TESTMODE, reg);
+
+                               reg = musb_readb(mbase, MUSB_POWER);
+                               reg &= ~MUSB_POWER_HSENAB;
+                               musb_writeb(mbase, MUSB_POWER, reg);
+
+                               musb_force_term(musb->mregs,MUSB_TERM_HOST_LOWSPEED);
+                               break;
+                       case 1:
+                               /*High or full speed*/
+                               reg = musb_readb(mbase, MUSB_TESTMODE);
+                               if(reg &  MUSB_TEST_FORCE_HS) {
+                                       /*High speed*/
+                                       reg &= ~MUSB_TEST_FORCE_FS;
+                                       musb_writeb(mbase, MUSB_TESTMODE, reg);
+
+                                       reg = musb_readb(mbase, MUSB_POWER);
+                                       reg |= MUSB_POWER_HSENAB;
+                                       musb_writeb(mbase, MUSB_POWER, reg);
+                               } else {
+                                       /*Full speed*/
+                                       reg |= MUSB_TEST_FORCE_FS;
+                                       musb_writeb(mbase, MUSB_TESTMODE, reg);
+
+                                       reg = musb_readb(mbase, MUSB_POWER);
+                                       reg &= ~MUSB_POWER_HSENAB;
+                                       musb_writeb(mbase, MUSB_POWER, reg);
+                               }
+
+                               musb_force_term(mbase,MUSB_TERM_HOST_FULLSPEED);
+
+                               break;
+                       case 0:
+                       case 3:
+                               /*invalid*/
+                               WARNING("Invalid line state of %d\n",r);
+                               break;
+                               
+                       }
+               } else {
+
+                       /* high vs full speed is just a guess until after reset */
+                       if (devctl & MUSB_DEVCTL_LSDEV)
+                               musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+               }
 
                if (hcd->status_urb)
                        usb_hcd_poll_rh_status(hcd);
@@ -974,6 +1102,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb->ignore_disconnect = 1;
                                musb_g_reset(musb);
                                /* FALLTHROUGH */
+                       case OTG_STATE_A_HOST:
+                               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                        case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
                                DBG(1, "HNP: Setting timer as %s\n",
                                                otg_state_string(musb));
@@ -2421,8 +2551,7 @@ bad_config:
                DBG(1, "%s mode, status %d, devctl %02x %c\n",
                        "HOST", status,
                        musb_readb(musb->mregs, MUSB_DEVCTL),
-                       (musb_readb(musb->mregs, MUSB_DEVCTL)
-                                       & MUSB_DEVCTL_BDEVICE
+                               (!host_mode(musb->mregs)
                                ? 'B' : 'A'));
 
        } else /* peripheral is enabled */ {