]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/isp116x-hcd.c
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6-omap-h63xx.git] / drivers / usb / host / isp116x-hcd.c
index 76cb496c5836ca3f222cbe688bf67fe2d6a2f1f7..ddb8fc5914663536d45b1c3be6b056f3630e2e88 100644 (file)
@@ -83,7 +83,7 @@
 #include "../core/hcd.h"
 #include "isp116x.h"
 
-#define DRIVER_VERSION "08 Apr 2005"
+#define DRIVER_VERSION "05 Aug 2005"
 #define DRIVER_DESC    "ISP116x USB Host Controller Driver"
 
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -326,7 +326,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                                        usb_settoggle(udev, ep->epnum,
                                                      ep->nextpid ==
                                                      USB_PID_OUT,
-                                                     PTD_GET_TOGGLE(ptd) ^ 1);
+                                                     PTD_GET_TOGGLE(ptd));
+                               urb->actual_length += PTD_GET_COUNT(ptd);
                                urb->status = cc_to_error[TD_DATAUNDERRUN];
                                spin_unlock(&urb->lock);
                                continue;
@@ -629,17 +630,15 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
                        ERR("Unrecoverable error\n");
                        /* What should we do here? Reset?  */
                }
-               if (intstat & HCINT_RHSC) {
-                       isp116x->rhstatus =
-                           isp116x_read_reg32(isp116x, HCRHSTATUS);
-                       isp116x->rhport[0] =
-                           isp116x_read_reg32(isp116x, HCRHPORT1);
-                       isp116x->rhport[1] =
-                           isp116x_read_reg32(isp116x, HCRHPORT2);
-               }
+               if (intstat & HCINT_RHSC)
+                       /* When root hub or any of its ports is going
+                          to come out of suspend, it may take more
+                          than 10ms for status bits to stabilize. */
+                       mod_timer(&hcd->rh_timer, jiffies
+                                 + msecs_to_jiffies(20) + 1);
                if (intstat & HCINT_RD) {
                        DBG("---- remote wakeup\n");
-                       schedule_work(&isp116x->rh_resume);
+                       usb_hcd_resume_root_hub(hcd);
                        ret = IRQ_HANDLED;
                }
                irqstat &= ~HCuPINT_OPR;
@@ -695,7 +694,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
                               struct usb_host_endpoint *hep, struct urb *urb,
-                              unsigned mem_flags)
+                              gfp_t mem_flags)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        struct usb_device *udev = urb->dev;
@@ -717,7 +716,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        }
        /* avoid all allocations within spinlocks: request or endpoint */
        if (!hep->hcpriv) {
-               ep = kcalloc(1, sizeof *ep, mem_flags);
+               ep = kzalloc(sizeof *ep, mem_flags);
                if (!ep)
                        return -ENOMEM;
        }
@@ -925,20 +924,27 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        int ports, i, changed = 0;
+       unsigned long flags;
 
        if (!HC_IS_RUNNING(hcd->state))
                return -ESHUTDOWN;
 
-       ports = isp116x->rhdesca & RH_A_NDP;
+       /* Report no status change now, if we are scheduled to be
+          called later */
+       if (timer_pending(&hcd->rh_timer))
+               return 0;
 
-       /* init status */
+       ports = isp116x->rhdesca & RH_A_NDP;
+       spin_lock_irqsave(&isp116x->lock, flags);
+       isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
        if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
                buf[0] = changed = 1;
        else
                buf[0] = 0;
 
        for (i = 0; i < ports; i++) {
-               u32 status = isp116x->rhport[i];
+               u32 status = isp116x->rhport[i] =
+                   isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1);
 
                if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
                              | RH_PS_OCIC | RH_PS_PRSC)) {
@@ -947,6 +953,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
                        continue;
                }
        }
+       spin_unlock_irqrestore(&isp116x->lock, flags);
        return changed;
 }
 
@@ -1153,7 +1160,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd,
 
 #ifdef CONFIG_PM
 
-static int isp116x_hub_suspend(struct usb_hcd *hcd)
+static int isp116x_bus_suspend(struct usb_hcd *hcd)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        unsigned long flags;
@@ -1193,7 +1200,7 @@ static int isp116x_hub_suspend(struct usb_hcd *hcd)
        return ret;
 }
 
-static int isp116x_hub_resume(struct usb_hcd *hcd)
+static int isp116x_bus_resume(struct usb_hcd *hcd)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        u32 val;
@@ -1256,21 +1263,11 @@ static int isp116x_hub_resume(struct usb_hcd *hcd)
        return 0;
 }
 
-static void isp116x_rh_resume(void *_hcd)
-{
-       struct usb_hcd *hcd = _hcd;
-
-       usb_resume_device(hcd->self.root_hub);
-}
 
 #else
 
-#define        isp116x_hub_suspend     NULL
-#define        isp116x_hub_resume      NULL
-
-static void isp116x_rh_resume(void *_hcd)
-{
-}
+#define        isp116x_bus_suspend     NULL
+#define        isp116x_bus_resume      NULL
 
 #endif
 
@@ -1463,10 +1460,6 @@ static int isp116x_sw_reset(struct isp116x *isp116x)
        return ret;
 }
 
-/*
-  Reset. Tries to perform platform-specific hardware
-  reset first; falls back to software reset.
-*/
 static int isp116x_reset(struct usb_hcd *hcd)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -1474,17 +1467,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
        u16 clkrdy = 0;
        int ret = 0, timeout = 15 /* ms */ ;
 
-       if (isp116x->board && isp116x->board->reset) {
-               /* Hardware reset */
-               isp116x->board->reset(hcd->self.controller, 1);
-               msleep(10);
-               if (isp116x->board->clock)
-                       isp116x->board->clock(hcd->self.controller, 1);
-               msleep(1);
-               isp116x->board->reset(hcd->self.controller, 0);
-       } else
-               ret = isp116x_sw_reset(isp116x);
-
+       ret = isp116x_sw_reset(isp116x);
        if (ret)
                return ret;
 
@@ -1501,10 +1484,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
                ERR("Clock not ready after 20ms\n");
                /* After sw_reset the clock won't report to be ready, if
                   H_WAKEUP pin is high. */
-               if (!isp116x->board || !isp116x->board->reset)
-                       ERR("The driver does not support hardware wakeup.\n");
-                       ERR("Please make sure that the H_WAKEUP pin "
-                               "is pulled low!\n");
+               ERR("Please make sure that the H_WAKEUP pin is pulled low!\n");
                ret = -ENODEV;
        }
        return ret;
@@ -1527,15 +1507,7 @@ static void isp116x_stop(struct usb_hcd *hcd)
        isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
        spin_unlock_irqrestore(&isp116x->lock, flags);
 
-       /* Put the chip into reset state */
-       if (isp116x->board && isp116x->board->reset)
-               isp116x->board->reset(hcd->self.controller, 0);
-       else
-               isp116x_sw_reset(isp116x);
-
-       /* Stop the clock */
-       if (isp116x->board && isp116x->board->clock)
-               isp116x->board->clock(hcd->self.controller, 0);
+       isp116x_sw_reset(isp116x);
 }
 
 /*
@@ -1561,6 +1533,9 @@ static int isp116x_start(struct usb_hcd *hcd)
                return -ENODEV;
        }
 
+       /* To be removed in future */
+       hcd->uses_new_polling = 1;
+
        isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
        isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
 
@@ -1569,7 +1544,7 @@ static int isp116x_start(struct usb_hcd *hcd)
        if (board->sel15Kres)
                val |= HCHWCFG_15KRSEL;
        /* Remote wakeup won't work without working clock */
-       if (board->clknotstop || board->remote_wakeup_enable)
+       if (board->remote_wakeup_enable)
                val |= HCHWCFG_CLKNOTSTOP;
        if (board->oc_enable)
                val |= HCHWCFG_ANALOG_OC;
@@ -1580,16 +1555,13 @@ static int isp116x_start(struct usb_hcd *hcd)
        isp116x_write_reg16(isp116x, HCHWCFG, val);
 
        /* ----- Root hub conf */
-       val = 0;
-       /* AN10003_1.pdf recommends NPS to be always 1 */
-       if (board->no_power_switching)
-               val |= RH_A_NPS;
-       if (board->power_switching_mode)
-               val |= RH_A_PSM;
-       if (board->potpg)
-               val |= (board->potpg << 24) & RH_A_POTPGT;
-       else
-               val |= (25 << 24) & RH_A_POTPGT;
+       val = (25 << 24) & RH_A_POTPGT;
+       /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+          be always set. Yet, instead, we request individual port
+          power switching. */
+       val |= RH_A_PSM;
+       /* Report overcurrent per port */
+       val |= RH_A_OCPM;
        isp116x_write_reg32(isp116x, HCRHDESCA, val);
        isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
 
@@ -1619,9 +1591,6 @@ static int isp116x_start(struct usb_hcd *hcd)
 
        /* Go operational */
        val = HCCONTROL_USB_OPER;
-       /* Remote wakeup connected - NOT SUPPORTED */
-       /*  if (board->remote_wakeup_connected)
-          val |= HCCONTROL_RWC;  */
        if (board->remote_wakeup_enable)
                val |= HCCONTROL_RWE;
        isp116x_write_reg32(isp116x, HCCONTROL, val);
@@ -1657,8 +1626,8 @@ static struct hc_driver isp116x_hc_driver = {
 
        .hub_status_data = isp116x_hub_status_data,
        .hub_control = isp116x_hub_control,
-       .hub_suspend = isp116x_hub_suspend,
-       .hub_resume = isp116x_hub_resume,
+       .bus_suspend = isp116x_bus_suspend,
+       .bus_resume = isp116x_bus_resume,
 };
 
 /*----------------------------------------------------------------*/
@@ -1670,7 +1639,7 @@ static int __init_or_module isp116x_remove(struct device *dev)
        struct platform_device *pdev;
        struct resource *res;
 
-       if(!hcd)
+       if (!hcd)
                return 0;
        isp116x = hcd_to_isp116x(hcd);
        pdev = container_of(dev, struct platform_device, dev);
@@ -1753,7 +1722,6 @@ static int __init isp116x_probe(struct device *dev)
        isp116x->addr_reg = addr_reg;
        spin_lock_init(&isp116x->lock);
        INIT_LIST_HEAD(&isp116x->async);
-       INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
        isp116x->board = dev->platform_data;
 
        if (!isp116x->board) {
@@ -1795,22 +1763,13 @@ static int __init isp116x_probe(struct device *dev)
 /*
   Suspend of platform device
 */
-static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase)
+static int isp116x_suspend(struct device *dev, pm_message_t state)
 {
        int ret = 0;
-       struct usb_hcd *hcd = dev_get_drvdata(dev);
-
-       VDBG("%s: state %x, phase %x\n", __func__, state, phase);
 
-       if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN)
-               return 0;
+       VDBG("%s: state %x\n", __func__, state);
 
-       ret = usb_suspend_device(hcd->self.root_hub, state);
-       if (!ret) {
-               dev->power.power_state = state;
-               INFO("%s suspended\n", hcd_name);
-       } else
-               ERR("%s suspend failed\n", hcd_name);
+       dev->power.power_state = state;
 
        return ret;
 }
@@ -1818,21 +1777,14 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase)
 /*
   Resume platform device
 */
-static int isp116x_resume(struct device *dev, u32 phase)
+static int isp116x_resume(struct device *dev)
 {
        int ret = 0;
-       struct usb_hcd *hcd = dev_get_drvdata(dev);
 
-       VDBG("%s:  state %x, phase %x\n", __func__, dev->power.power_state,
-            phase);
-       if (phase != RESUME_POWER_ON)
-               return 0;
+       VDBG("%s:  state %x\n", __func__, dev->power.power_state);
+
+       dev->power.power_state = PMSG_ON;
 
-       ret = usb_resume_device(hcd->self.root_hub);
-       if (!ret) {
-               dev->power.power_state = PMSG_ON;
-               VDBG("%s resumed\n", (char *)hcd_name);
-       }
        return ret;
 }