static int /*__devinit*/ ohci_rtl819x_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); int ret; unsigned int fminterval; ret = ohci_init(ohci); if (ret < 0) return ret; #if 1 fminterval = 0x2edf; ohci_writel (ohci,(fminterval * 9) / 10, &ohci->regs->periodicstart); fminterval |= ((((fminterval - 210) * 6) / 7) << 16); ohci_writel (ohci, fminterval, &ohci->regs->fminterval); ohci_writel (ohci, 0x0628, &ohci->regs->lsthresh); /* default value from datasheet */ ohci_writel (ohci, 0x3e67, &ohci->regs->periodicstart); /* default value from datasheet */ #endif ret = ohci_run(ohci); if (ret < 0) goto err; return 0; err: ohci_stop(hcd); return ret; }
int s5p_ohci_port_power_off(struct platform_device *pdev) { struct s5p_ohci_hcd *s5p_ohci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ohci->hcd; struct ohci_hcd *ohci = hcd_to_ohci(hcd); ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); ohci_writel (ohci, RH_HS_LPS, &ohci->regs->roothub.status); return 0; }
static int ohci_brcm_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); unsigned long flags; int rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. */ spin_lock_irqsave(&ohci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); brcm_usb_suspend(hcd); bail: spin_unlock_irqrestore(&ohci->lock, flags); return rc; }
static int ohci_da8xx_init(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; struct da8xx_ohci_root_hub *hub = dev->platform_data; struct ohci_hcd *ohci = hcd_to_ohci(hcd); int result; u32 rh_a; dev_dbg(dev, "starting USB controller\n"); ohci_da8xx_clock(1); /* * DA830 only has 1 port connected to the pins but its HC root hub * register A reports 2 ports, thus we'll have to override it... */ ohci->num_ports = 1; result = ohci_init(ohci); if (result < 0) return result; /* * Since we're providing a board-specific root hub port power control * and over-current reporting, we have to override the HC root hub A * register's default value, so that ohci_hub_control() could return * the correct hub descriptor... */ rh_a = ohci_readl(ohci, &ohci->regs->roothub.a); rh_a &= ~(RH_A_POTPGT | RH_A_NPS | RH_A_NOCP); rh_a |= (hub->potpgt << 24) | RH_A_PSM | RH_A_OCPM; ohci_writel(ohci, rh_a, &ohci->regs->roothub.a); return result; }
static int ohci_hcd_au1xxx_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); unsigned long flags; int rc; rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. */ spin_lock_irqsave(&ohci->lock, flags); if (ohci->rh_state != OHCI_RH_SUSPENDED) { rc = -EINVAL; goto bail; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); bail: spin_unlock_irqrestore(&ohci->lock, flags); return rc; }
static int ohci_hcd_s5p_drv_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_ohci_platdata *pdata = pdev->dev.platform_data; struct s5p_ohci_hcd *s5p_ohci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ohci->hcd; #ifdef CONFIG_USB_EXYNOS_SWITCH struct ohci_hcd *ohci = hcd_to_ohci(hcd); #endif if (dev->power.is_suspended) return 0; if (pdata->phy_resume) pdata->phy_resume(pdev, S5P_USB_PHY_HOST); /* Mark hardware accessible again as we are out of D3 state by now */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); #ifdef CONFIG_USB_EXYNOS_SWITCH if (samsung_board_rev_is_0_0()) ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); #endif ohci_finish_controller_resume(hcd); return 0; }
static void ohci_exynos_stop(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); ohci_dump(ohci, 1); if (quirk_nec(ohci)) flush_work_sync(&ohci->nec_work); ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_usb_reset(ohci); free_irq(hcd->irq, hcd); hcd->irq = 0; if (quirk_zfmicro(ohci)) del_timer(&ohci->unlink_watchdog); if (quirk_amdiso(ohci)) usb_amd_dev_put(); remove_debug_files(ohci); ohci_mem_cleanup(ohci); if (ohci->hcca) { dma_free_coherent(hcd->self.controller, sizeof *ohci->hcca, ohci->hcca, ohci->hcca_dma); ohci->hcca = NULL; ohci->hcca_dma = 0; } }
static int exynos_ohci_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); struct usb_hcd *hcd = exynos_ohci->hcd; struct ohci_hcd *ohci = hcd_to_ohci(hcd); unsigned long flags; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ohci->lock, flags); if (ohci->rh_state != OHCI_RH_SUSPENDED && ohci->rh_state != OHCI_RH_HALTED) { spin_unlock_irqrestore(&ohci->lock, flags); err("Not ready %s", hcd->self.bus_name); return 0; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&ohci->lock, flags); if (pdata->phy_suspend) pdata->phy_suspend(pdev, S5P_USB_PHY_HOST); return 0; }
static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); unsigned long flags; int rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave (&ohci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); bail: spin_unlock_irqrestore (&ohci->lock, flags); return rc; }
static int ohci_da8xx_init(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; struct da8xx_ohci_root_hub *hub = dev->platform_data; struct ohci_hcd *ohci = hcd_to_ohci(hcd); int result; u32 rh_a; dev_dbg(dev, "starting USB controller\n"); ohci_da8xx_clock(1); ohci->num_ports = 1; result = ohci_init(ohci); if (result < 0) return result; rh_a = ohci_readl(ohci, &ohci->regs->roothub.a); if (hub->set_power) { rh_a &= ~RH_A_NPS; rh_a |= RH_A_PSM; } if (hub->get_oci) { rh_a &= ~RH_A_NOCP; rh_a |= RH_A_OCPM; } rh_a &= ~RH_A_POTPGT; rh_a |= hub->potpgt << 24; ohci_writel(ohci, rh_a, &ohci->regs->roothub.a); return result; }
int ohci_power(void *ohci, int is_on) { struct ohci_hcd *ohcip = (struct ohci_hcd *)ohci; int port; int temp; temp = roothub_a(ohcip); /* If NoPowerSwitching is true, just return */ if (temp & RH_A_NPS) { return 0; } /* If port switched, switch each port */ if (temp & RH_A_PSM) { for (port = ohcip->num_ports; port > 0; ) { (void) ohci_hub_control(ohci_to_hcd(ohcip), is_on ? SetPortFeature : ClearPortFeature, USB_PORT_FEAT_POWER, port--, NULL, 0); } } /* Else use Global Power */ else { temp = roothub_status(ohcip); if (is_on) { temp |= RH_HS_LPSC; /* SetGlobalPower */ } else { temp |= RH_HS_LPS; /* ClearGlobalPower */ } ohci_writel(ohcip, temp, &ohcip->regs->roothub.status); } return 0; }
/* ******************************************************************************* * sw_ohci_hcd_suspend * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int sw_ohci_hcd_suspend(struct device *dev) { struct sw_hci_hcd *sw_ohci = NULL; struct usb_hcd *hcd = NULL; struct ohci_hcd *ohci = NULL; unsigned long flags = 0; int rc = 0; if(dev == NULL){ DMSG_PANIC("ERR: Argment is invalid\n"); return 0; } hcd = dev_get_drvdata(dev); if(hcd == NULL){ DMSG_PANIC("ERR: hcd is null\n"); return 0; } sw_ohci = dev->platform_data; if(sw_ohci == NULL){ DMSG_PANIC("ERR: sw_ohci is null\n"); return 0; } if(sw_ohci->probe == 0){ DMSG_PANIC("ERR: sw_ohci is disable, can not suspend\n"); return 0; } ohci = hcd_to_ohci(hcd); if(ohci == NULL){ DMSG_PANIC("ERR: ohci is null\n"); return 0; } DMSG_INFO("[%s]: sw_ohci_hcd_suspend\n", sw_ohci->hci_name); /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ohci->lock, flags); ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&ohci->lock, flags); sw_stop_ohc(sw_ohci); return rc; }
int s5p_ohci_port_power_on(struct platform_device *pdev) { struct s5p_ohci_hcd *s5p_ohci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ohci->hcd; struct ohci_hcd *ohci = hcd_to_ohci(hcd); ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status); return 0; }
/* hcd->hub_irq_enable() */ static void ohci_rhsc_enable (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); spin_lock_irq(&ohci->lock); if (!ohci->autostop) del_timer(&hcd->rh_timer); /* Prevent next poll */ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); spin_unlock_irq(&ohci->lock); }
static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) { int result; struct ohci_hcd *ohci = hcd_to_ohci(hcd); ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, &ohci->regs->roothub.a); ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); result = ohci_run(ohci); if (result < 0) { err("can't start %s", hcd->self.bus_name); ohci_stop(hcd); } return result; }
static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) { int result; struct ohci_hcd *ohci = hcd_to_ohci(hcd); /* Handle root hub init quirk in spider south bridge. */ /* Also set PwrOn2PwrGood to 0x7f (254ms). */ ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, &ohci->regs->roothub.a); ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); result = ohci_run(ohci); if (result < 0) { err("can't start %s", hcd->self.bus_name); ohci_stop(hcd); } return result; }
static int ohci_hcd_s5p_drv_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_ohci_platdata *pdata = pdev->dev.platform_data; struct s5p_ohci_hcd *s5p_ohci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ohci->hcd; struct ohci_hcd *ohci = hcd_to_ohci(hcd); unsigned long flags; int rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ohci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) { spin_unlock_irqrestore(&ohci->lock, flags); err("Not ready %s", hcd->self.bus_name); return rc; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&ohci->lock, flags); #ifdef CONFIG_USB_EXYNOS_SWITCH if (samsung_board_rev_is_0_0()) ohci_writel (ohci, RH_HS_LPS, &ohci->regs->roothub.status); #endif if (pdata->phy_suspend) pdata->phy_suspend(pdev, S5P_USB_PHY_HOST); return rc; }
static int __devinit ohci_rtl8652_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); int ret; unsigned int fminterval; if ((ret = ohci_init(ohci)) < 0) return ret; fminterval = 0x2edf; ohci_writel (ohci,(fminterval * 9) / 10, &ohci->regs->periodicstart); fminterval |= ((((fminterval - 210) * 6) / 7) << 16); ohci_writel (ohci,fminterval, &ohci->regs->fminterval); ohci_writel (ohci,0x628, &ohci->regs->lsthresh); ohci_writel(ohci,0x3e67,&ohci->regs->periodicstart); if ((ret = ohci_run(ohci)) < 0) { err("can't start %s", hcd->self.bus_name); ohci_stop(hcd); return ret; } return 0; }
static int ohci_da8xx_reset(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); int result; u32 rh_a; dev_dbg(dev, "starting USB controller\n"); result = ohci_da8xx_enable(hcd); if (result < 0) return result; /* * DA8xx only have 1 port connected to the pins but the HC root hub * register A reports 2 ports, thus we'll have to override it... */ ohci->num_ports = 1; result = ohci_setup(hcd); if (result < 0) { ohci_da8xx_disable(hcd); return result; } /* * Since we're providing a board-specific root hub port power control * and over-current reporting, we have to override the HC root hub A * register's default value, so that ohci_hub_control() could return * the correct hub descriptor... */ rh_a = ohci_readl(ohci, &ohci->regs->roothub.a); if (ohci_da8xx_has_set_power(hcd)) { rh_a &= ~RH_A_NPS; rh_a |= RH_A_PSM; } if (ohci_da8xx_has_oci(hcd)) { rh_a &= ~RH_A_NOCP; rh_a |= RH_A_OCPM; } if (ohci_da8xx_has_potpgt(hcd)) { rh_a &= ~RH_A_POTPGT; rh_a |= hub->potpgt << 24; } ohci_writel(ohci, rh_a, &ohci->regs->roothub.a); return result; }
/* Following a power loss, we must prepare to regain control of the ports * we used to own. This means turning on the port power before ehci-hcd * tries to switch ownership. * * This isn't a 100% perfect solution. On most systems the OHCI controllers * lie at lower PCI addresses than the EHCI controller, so they will be * discovered (and hence resumed) first. But there is no guarantee things * will always work this way. If the EHCI controller is resumed first and * the OHCI ports are unpowered, then the handover will fail. */ static void prepare_for_handover(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); int port; /* Here we "know" root ports should always stay powered */ ohci_dbg(ohci, "powerup ports\n"); for (port = 0; port < ohci->num_ports; port++) ohci_writel(ohci, RH_PS_PPS, &ohci->regs->roothub.portstatus[port]); /* Flush those writes */ ohci_readl(ohci, &ohci->regs->control); msleep(20); }
static int ohci_brcm_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct ohci_regs __iomem *regs; regs = hcd->regs; ohci_writel(ohci, 1, ®s->cmdstatus); ohci_readl(ohci, ®s->cmdstatus); mdelay(10); ohci_hcd_init(ohci); ohci_init(ohci); ohci_run(ohci); hcd->state = HC_STATE_RUNNING; return 0; }
static int ohci_hcd_s5pv210_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); unsigned long flags; int rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ohci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); #if defined(CONFIG_SAMSUNG_PHONE_SVNET) || defined(CONFIG_SAMSUNG_LTE) || defined(CONFIG_UMTS_LINK_HSIC) #else printk(KERN_DEBUG "USB_PM ohci rt susp\n"); usb_host_phy_off(); #endif bail: spin_unlock_irqrestore(&ohci->lock, flags); return rc; }
static int ohci_hcd_spmp_drv_suspend(struct platform_device *pdev, pm_message_t message) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct spmp_ohci *spmpohci = (struct spmp_ohci *)hcd_to_ohci(hcd); unsigned long flags; int rc; rc = 0; /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ohci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable); /* make sure snapshot being resumed re-enumerates everything */ if (message.event == PM_EVENT_PRETHAW) ohci_usb_reset(ohci); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spmp_stop_ohc(spmpohci, &pdev->dev); bail: spin_unlock_irqrestore(&ohci->lock, flags); return rc; }
static int ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; int can_suspend; unsigned long flags; can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); spin_lock_irqsave (&ohci->lock, flags); /* handle autosuspended root: finish resuming before * letting khubd or root hub timer see state changes. */ if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || !HC_IS_RUNNING(hcd->state))) { can_suspend = 0; goto done; } /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n", ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ goto done; } /* init status */ if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) buf [0] = changed = 1; else buf [0] = 0; if (ohci->num_ports > 7) { buf [1] = 0; length++; } /* look at each port */ for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); /* can't autosuspend with active ports */ if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) can_suspend = 0; if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { changed = 1; if (i < 7) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); continue; } } /* after root hub changes, stop polling after debouncing * for a while and maybe kicking in autosuspend */ if (changed) { ohci->next_statechange = jiffies + STATECHANGE_DELAY; can_suspend = 0; } else if (time_before (jiffies, ohci->next_statechange)) { can_suspend = 0; } else { #ifdef CONFIG_PM can_suspend = can_suspend && !ohci->ed_rm_list && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) & ohci->hc_control) == OHCI_USB_OPER; #endif if (hcd->uses_new_polling) { hcd->poll_rh = 0; /* use INTR_RHSC iff INTR_RD won't apply */ if (!can_suspend) ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); } } done: spin_unlock_irqrestore (&ohci->lock, flags); #ifdef CONFIG_PM /* save power by autosuspending idle root hubs; * INTR_RD wakes us when there's work */ if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_bus_suspend (hcd); usb_unlock_device (hcd->self.root_hub); } #endif return changed ? length : 0; }
static int ohci_hub_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; unsigned long flags; #ifndef USB_FREE_IRQ_AT_SUSPEND_MODE #if defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) return 0; #endif /* defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) */ #endif /* USB_FREE_IRQ_AT_SUSPEND_MODE */ spin_lock_irqsave (&ohci->lock, flags); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: ohci_dbg (ohci, "resume/suspend?\n"); ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_RESET; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* FALL THROUGH */ case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: ohci_dbg (ohci, "already suspended\n"); goto done; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ hcd->state = HC_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); /* sched disables take effect on the next frame, * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); limit = 2000; while (limit > 0) { udelay (250); limit =- 250; if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_SF) break; } dl_done_list (ohci, NULL); mdelay (7); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (hcd->remote_wakeup) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; /* Suspend hub */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); done: if (status == 0) hcd->state = HC_STATE_SUSPENDED; spin_unlock_irqrestore (&ohci->lock, flags); return status; }
static int ohci_omap_init(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct omap_usb_config *config = hcd->self.controller->platform_data; int need_transceiver = (config->otg != 0); int ret; dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { ohci_to_hcd(ohci)->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ ohci_to_hcd(ohci)->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ need_transceiver = need_transceiver || machine_is_omap_h2() || machine_is_omap_h3(); if (cpu_is_omap16xx()) ocpi_enable(); #ifdef CONFIG_ARCH_OMAP_OTG if (need_transceiver) { ohci->transceiver = otg_get_transceiver(); if (ohci->transceiver) { int status = otg_set_host(ohci->transceiver, &ohci_to_hcd(ohci)->self); dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", ohci->transceiver->label, status); if (status) { if (ohci->transceiver) put_device(ohci->transceiver->dev); return status; } } else { dev_err(hcd->self.controller, "can't find transceiver\n"); return -ENODEV; } } #endif omap_ohci_clock_power(1); if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } if ((ret = ohci_init(ohci)) < 0) return ret; /* board-specific power switching and overcurrent support */ if (machine_is_omap_osk() || machine_is_omap_innovator()) { u32 rh = roothub_a (ohci); /* power switching (ganged by default) */ rh &= ~RH_A_NPS; /* TPS2045 switch for internal transceiver (port 1) */ if (machine_is_omap_osk()) { ohci_to_hcd(ohci)->power_budget = 250; rh &= ~RH_A_NOCP; /* gpio9 for overcurrent detction */ omap_cfg_reg(W8_1610_GPIO9); omap_request_gpio(9); omap_set_gpio_direction(9, 1 /* IN */); /* for paranoia's sake: disable USB.PUEN */ omap_cfg_reg(W4_USB_HIGHZ); } ohci_writel(ohci, rh, &ohci->regs->roothub.a); distrust_firmware = 0; } else if (machine_is_nokia770()) { /* We require a self-powered hub, which should have * plenty of power. */ ohci_to_hcd(ohci)->power_budget = 0; } /* FIXME khubd hub requests should manage power switching */ omap_ohci_transceiver_power(1); /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized * too, so all configured ports use the right signaling now. */ return 0; }
static int ohci_omap_reset(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); int need_transceiver = (config->otg != 0); int ret; dev_dbg(hcd->self.controller, "starting USB Controller\n"); if (config->otg) { hcd->self.otg_port = config->otg; /* default/minimum OTG power budget: 8 mA */ hcd->power_budget = 8; } /* boards can use OTG transceivers in non-OTG modes */ need_transceiver = need_transceiver || machine_is_omap_h2() || machine_is_omap_h3(); /* XXX OMAP16xx only */ if (config->ocpi_enable) config->ocpi_enable(); #ifdef CONFIG_USB_OTG if (need_transceiver) { hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!IS_ERR_OR_NULL(hcd->phy)) { int status = otg_set_host(hcd->phy->otg, &ohci_to_hcd(ohci)->self); dev_dbg(hcd->self.controller, "init %s phy, status %d\n", hcd->phy->label, status); if (status) { usb_put_phy(hcd->phy); return status; } } else { dev_err(hcd->self.controller, "can't find phy\n"); return -ENODEV; } ohci->start_hnp = start_hnp; } #endif omap_ohci_clock_power(1); if (cpu_is_omap15xx()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } ret = ohci_setup(hcd); if (ret < 0) return ret; if (config->otg || config->rwc) { ohci->hc_control = OHCI_CTRL_RWC; writel(OHCI_CTRL_RWC, &ohci->regs->control); } /* board-specific power switching and overcurrent support */ if (machine_is_omap_osk() || machine_is_omap_innovator()) { u32 rh = roothub_a (ohci); /* power switching (ganged by default) */ rh &= ~RH_A_NPS; /* TPS2045 switch for internal transceiver (port 1) */ if (machine_is_omap_osk()) { ohci_to_hcd(ohci)->power_budget = 250; rh &= ~RH_A_NOCP; /* gpio9 for overcurrent detction */ omap_cfg_reg(W8_1610_GPIO9); gpio_request(9, "OHCI overcurrent"); gpio_direction_input(9); /* for paranoia's sake: disable USB.PUEN */ omap_cfg_reg(W4_USB_HIGHZ); } ohci_writel(ohci, rh, &ohci->regs->roothub.a); ohci->flags &= ~OHCI_QUIRK_HUB_POWER; } else if (machine_is_nokia770()) { /* We require a self-powered hub, which should have * plenty of power. */ ohci_to_hcd(ohci)->power_budget = 0; } /* FIXME khubd hub requests should manage power switching */ omap_ohci_transceiver_power(1); /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized * too, so all configured ports use the right signaling now. */ return 0; }
static int ohci_bus_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; unsigned long flags; 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); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_RESUME: ohci_dbg (ohci, "resume/suspend?\n"); ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_RESET; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* FALL THROUGH */ case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: ohci_dbg (ohci, "already suspended\n"); goto done; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); /* sched disables take effect on the next frame, * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); limit = 2000; while (limit > 0) { udelay (250); limit =- 250; if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_SF) break; } dl_done_list (ohci, NULL); mdelay (7); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; /* Suspend hub ... this is the "global (to this bus) suspend" mode, * which doesn't imply ports will first be individually suspended. */ ohci->hc_control &= ~OHCI_CTRL_HCFS; ohci->hc_control |= OHCI_USB_SUSPEND; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); /* no timer polling */ hcd->poll_rh = 0; done: /* external suspend vs self autosuspend ... same effect */ if (status == 0) usb_hcd_suspend_root_hub(hcd); spin_unlock_irqrestore (&ohci->lock, flags); return status; }
/* hcd->hub_irq_enable() */ static void ohci_rhsc_enable (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); }
/* 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; }