static void ohci_quirk_nec_worker(struct work_struct *work) { struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); int status; status = ohci_restart(ohci); if (status != 0) ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", "ohci_restart", status); }
/* caller has locked the root hub */ static int ohci_bus_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; int status = -EINPROGRESS; unsigned long flags; if (time_before (jiffies, ohci->next_statechange)) msleep(5); spin_lock_irqsave (&ohci->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { spin_unlock_irqrestore (&ohci->lock, flags); return -ESHUTDOWN; } ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { /* this can happen after resuming a swsusp snapshot */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); status = -EBUSY; /* this happens when pmcore resumes HC then root */ } else { ohci_dbg (ohci, "duplicate resume\n"); status = 0; } } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); ohci_dbg (ohci, "resume root hub\n"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: /* this can happen after resuming a swsusp snapshot */ ohci_dbg (ohci, "snapshot resume? reinit\n"); status = -EBUSY; break; default: /* RESET, we lost power */ ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } spin_unlock_irqrestore (&ohci->lock, flags); if (status == -EBUSY) { (void) ohci_init (ohci); return ohci_restart (ohci); } if (status != -EINPROGRESS) return status; temp = ohci->num_ports; enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; ohci_writel (ohci, RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]); } /* Some controllers (lucent erratum) need extra-long delays */ msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); return -EBUSY; } /* disable old schedule state, reinit from scratch */ ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent); ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); msleep (3); temp = ohci->hc_control; temp &= OHCI_CTRL_RWC; temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control = temp; ohci_writel (ohci, temp, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ msleep (10); /* keep it alive for more than ~5x suspend + resume costs */ ohci->next_statechange = jiffies + STATECHANGE_DELAY; /* maybe turn schedules back on */ enables = 0; temp = 0; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) { ohci_writel (ohci, find_head (ohci->ed_controltail)->dma, &ohci->regs->ed_controlhead); enables |= OHCI_CTRL_CLE; temp |= OHCI_CLF; } if (ohci->ed_bulktail) { ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma, &ohci->regs->ed_bulkhead); enables |= OHCI_CTRL_BLE; temp |= OHCI_BLF; } } if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; if (enables) { ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); ohci->hc_control |= enables; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); if (temp) ohci_writel (ohci, temp, &ohci->regs->cmdstatus); (void) ohci_readl (ohci, &ohci->regs->control); } return 0; }
/* caller has locked the root hub */ static int ohci_hub_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); u32 temp, enables; int status = -EINPROGRESS; #if defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) //FOR PULLING VENUS_USB_HOST_WRAPPER BIT6 HIGH BEFOR RESUME OHCI PORT outl(inl(VENUS_USB_HOST_WRAPPER)| 1<<6, VENUS_USB_HOST_WRAPPER); (void) ohci_init (ohci); return ohci_restart (ohci); #endif /* defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) */ if (time_before (jiffies, ohci->next_statechange)) msleep(5); spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { /* this can happen after suspend-to-disk */ if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); status = -EBUSY; /* this happens when pmcore resumes HC then root */ } else { ohci_dbg (ohci, "duplicate resume\n"); status = 0; } } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: #ifdef CONFIG_REALTEK_VENUS_USB //cfyeh+ //for pulling VENUS_USB_HOST_WRAPPER bit6 high befor resume OHCI port outl(inl(VENUS_USB_HOST_WRAPPER)| 1<<6, VENUS_USB_HOST_WRAPPER); #endif /* CONFIG_REALTEK_VENUS_USB */ //cfyeh- ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); ohci_dbg (ohci, "resume root hub\n"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: ohci_dbg (ohci, "already resumed\n"); status = 0; break; default: /* RESET, we lost power */ ohci_dbg (ohci, "root hub hardware reset\n"); status = -EBUSY; } spin_unlock_irq (&ohci->lock); if (status == -EBUSY) { (void) ohci_init (ohci); return ohci_restart (ohci); } if (status != -EINPROGRESS) return status; temp = roothub_a (ohci) & RH_A_NDP; enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; ohci_writel (ohci, RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]); } /* Some controllers (lucent erratum) need extra-long delays */ hcd->state = HC_STATE_RESUMING; mdelay (20 /* usb 11.5.1.10 */ + 15); temp = ohci_readl (ohci, &ohci->regs->control); temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); return -EBUSY; } /* disable old schedule state, reinit from scratch */ ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent); ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); msleep (3); temp = OHCI_CONTROL_INIT | OHCI_USB_OPER; if (hcd->can_wakeup) temp |= OHCI_CTRL_RWC; ohci->hc_control = temp; ohci_writel (ohci, temp, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ msleep (10); /* keep it alive for ~5x suspend + resume costs */ ohci->next_statechange = jiffies + msecs_to_jiffies (250); /* maybe turn schedules back on */ enables = 0; temp = 0; if (!ohci->ed_rm_list) { if (ohci->ed_controltail) { ohci_writel (ohci, find_head (ohci->ed_controltail)->dma, &ohci->regs->ed_controlhead); enables |= OHCI_CTRL_CLE; temp |= OHCI_CLF; } if (ohci->ed_bulktail) { ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma, &ohci->regs->ed_bulkhead); enables |= OHCI_CTRL_BLE; temp |= OHCI_BLF; } } if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; if (enables) { ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); ohci->hc_control |= enables; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); if (temp) ohci_writel (ohci, temp, &ohci->regs->cmdstatus); (void) ohci_readl (ohci, &ohci->regs->control); } hcd->state = HC_STATE_RUNNING; return 0; }