static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, struct urb *urb) { hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval; if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { hcd_to_bus(hcd)->bandwidth_isoc_reqs--; } else { hcd_to_bus(hcd)->bandwidth_int_reqs--; } }
/** * Schedules an interrupt or isochronous transfer in the periodic schedule. * * @param hcd The HCD state structure for the DWC OTG controller. * @param qh QH for the periodic transfer. The QH should already contain the * scheduling information. * * @return 0 if successful, negative error code otherwise. */ static int schedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) { int status = 0; status = periodic_channel_available(hcd); if (status) { DWC_NOTICE("%s: No host channel available for periodic " "transfer.\n", __func__); return status; } status = check_periodic_bandwidth(hcd, qh); if (status) { DWC_NOTICE("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); return status; } status = check_max_xfer_size(hcd, qh); if (status) { DWC_NOTICE("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); return status; } /* Always start in the inactive schedule. */ list_add_tail(&qh->qh_list_entry, &hcd->periodic_sched_inactive); /* Reserve the periodic channel. */ hcd->periodic_channels++; /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs += qh->usecs; /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_allocated += qh->usecs / qh->interval; if (qh->ep_type == USB_ENDPOINT_XFER_INT) { hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_int_reqs++; DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n", qh, qh->usecs, qh->interval); } else { hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_isoc_reqs++; DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n", qh, qh->usecs, qh->interval); } return status; }
/* * We need to register our own PCI probe function (instead of the USB core's * function) in order to create a second roothub under xHCI. */ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; struct xhci_hcd *xhci; struct hc_driver *driver; struct usb_hcd *hcd; driver = (struct hc_driver *)id->driver_data; /* Register the USB 2.0 roothub. * FIXME: USB core must know to register the USB 2.0 roothub first. * This is sort of silly, because we could just set the HCD driver flags * to say USB 2.0, but I'm not sure what the implications would be in * the other parts of the HCD code. */ retval = usb_hcd_pci_probe(dev, id); if (retval) return retval; /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, pci_name(dev), hcd); if (!xhci->shared_hcd) { retval = -ENOMEM; goto dealloc_usb2_hcd; } /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; retval = usb_add_hcd(xhci->shared_hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ /* We know the LPM timeout algorithms for this host, let the USB core * enable and disable LPM for devices under the USB 3.0 roothub. */ if (xhci->quirks & XHCI_LPM_SUPPORT) hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1; return 0; put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); dealloc_usb2_hcd: usb_hcd_pci_remove(dev); return retval; }
static int ehci_hub_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub; int port; int status = 0; if (root->dev.power.power_state != 0) return 0; if (time_before (jiffies, ehci->next_statechange)) return -EAGAIN; del_timer_sync(&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); /* suspend any active/unsuspended ports, maybe allow wakeup */ while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; u32 t1 = readl (reg) & ~PORT_RWC_BITS; u32 t2 = t1; if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) t2 |= PORT_SUSPEND; if (ehci->hcd.remote_wakeup) t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; else t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); writel (t2, reg); } } /* stop schedules, then turn off HC and clean any completed work */ if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); ehci->command = readl (&ehci->regs->command); writel (ehci->command & ~CMD_RUN, &ehci->regs->command); if (ehci->reclaim) end_unlink_async(ehci, NULL); ehci_work(ehci, NULL); (void) handshake (&ehci->regs->status, STS_HALT, STS_HALT, 2000); root->dev.power.power_state = 3; ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); return status; }
/** * Schedules an interrupt or isochronous transfer in the periodic schedule. */ static int schedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) { int status; struct usb_bus *bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd)); int frame; status = find_uframe(hcd, qh); frame = -1; if (status == 0) { frame = 7; } else { if (status > 0) frame = status - 1; } /* Set the new frame up */ if (frame > -1) { qh->sched_frame &= ~0x7; qh->sched_frame |= (frame & 7); } if (status != -1) status = 0; if (status) { pr_notice("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); return status; } status = check_max_xfer_size(hcd, qh); if (status) { pr_notice("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); return status; } /* Always start in the inactive schedule. */ list_add_tail(&qh->qh_list_entry, &hcd->periodic_sched_inactive); /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs += qh->usecs; /* * Update average periodic bandwidth claimed and # periodic reqs for * usbfs. */ bus->bandwidth_allocated += qh->usecs / qh->interval; if (qh->ep_type == USB_ENDPOINT_XFER_INT) bus->bandwidth_int_reqs++; else bus->bandwidth_isoc_reqs++; return status; }
/** * Removes an interrupt or isochronous transfer from the periodic schedule. * * @param hcd The HCD state structure for the DWC OTG controller. * @param qh QH for the periodic transfer. */ static void deschedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) { list_del_init(&qh->qh_list_entry); /* Release the periodic channel reservation. */ hcd->periodic_channels--; /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs -= qh->usecs; /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_allocated -= qh->usecs / qh->interval; if (qh->ep_type == USB_ENDPOINT_XFER_INT) { hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_int_reqs--; DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n", qh, qh->usecs, qh->interval); } else { hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_isoc_reqs--; DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n", qh, qh->usecs, qh->interval); } }
static int ehci_omap_bus_resume(struct usb_hcd *hcd) { struct ehci_hcd_omap *omap = platform_get_drvdata(to_platform_device(hcd->self.controller)); struct ehci_hcd *ehci = omap->ehci; struct usb_bus *bus = hcd_to_bus(hcd); int ret; #ifdef CONFIG_LOGIC_OMAP3530_USB3320_HACK /* Remove the GPIO hack; this allows the controller to talk to the PHY again */ usb3320_hack_remove(); #endif // CONFIG_LOGIC_OMAP3530_USB3320_HACK ehci_omap_dev_resume(bus->controller); omap_init_uhh_registers(omap, hcd); /* Initial setup code from the EHCI driver */ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; ehci_writel(ehci, ehci->command, &ehci->regs->command); dbg_cmd (ehci, "init", ehci->command); ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ /* Give it time to sink in */ msleep(5); /* reset the USB PHY */ if (omap->phy_reset) ehci_omap_phy_reset(omap); ehci_writel(omap->ehci, CMD_RUN, &omap->ehci->regs->command); msleep(1); ehci_port_power(ehci, 1); msleep(1); ret = ehci_bus_resume(hcd); return ret; }
/** Initializes the DWC_otg controller and its root hub and prepares it for host * mode operation. Activates the root port. Returns 0 on success and a negative * error code on failure. */ int hcd_start(struct usb_hcd *hcd) { dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); struct usb_bus *bus; DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); bus = hcd_to_bus(hcd); hcd->state = HC_STATE_RUNNING; if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) { return 0; } /* Initialize and connect root hub if one is not already attached */ if (bus->root_hub) { DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); /* Inform the HUB driver to resume. */ usb_hcd_resume_root_hub(hcd); } return 0; }
static int ehci_omap_bus_suspend(struct usb_hcd *hcd) { struct usb_bus *bus = hcd_to_bus(hcd); int ret; #ifdef CONFIG_LOGIC_OMAP3530_USB3320_HACK struct ehci_hcd_omap *omap = platform_get_drvdata(to_platform_device( hcd->self.controller)); struct ehci_hcd *ehci = omap->ehci; int ports = HCS_N_PORTS (omap->ehci->hcs_params); int i; // Manually suspend the ports HERE. We want to be able to switch to // GPIO lines before it shuts down the controller entirely; // Otherwise, it'll wake up the PHY again. for(i=0;i<ports;++i) { u32 __iomem *status_reg = &omap->ehci->regs->port_status[i]; u32 temp = ehci_readl(omap->ehci, status_reg); if((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) continue; ehci_writel(omap->ehci, temp | PORT_SUSPEND, status_reg); set_bit(i, &ehci->suspended_ports); } msleep(1); usb3320_hack_install(); #endif ret = ehci_bus_suspend(hcd); ehci_omap_dev_suspend(bus->controller); return ret; }
/** * Removes an interrupt or isochronous transfer from the periodic schedule. */ static void deschedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh) { struct usb_bus *bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd)); int i; list_del_init(&qh->qh_list_entry); /* Update claimed usecs per (micro)frame. */ hcd->periodic_usecs -= qh->usecs; for (i = 0; i < 8; i++) { hcd->frame_usecs[i] += qh->frame_usecs[i]; qh->frame_usecs[i] = 0; } /* * Update average periodic bandwidth claimed and # periodic reqs for * usbfs. */ bus->bandwidth_allocated -= qh->usecs / qh->interval; if (qh->ep_type == USB_ENDPOINT_XFER_INT) bus->bandwidth_int_reqs--; else bus->bandwidth_isoc_reqs--; }
static int xen_dbgp_op(struct usb_hcd *hcd, int op) { const struct device *ctrlr = hcd_to_bus(hcd)->controller; struct physdev_dbgp_op dbgp; if (!xen_initial_domain()) return 0; dbgp.op = op; #ifdef CONFIG_PCI if (ctrlr->bus == &pci_bus_type) { const struct pci_dev *pdev = to_pci_dev(ctrlr); dbgp.u.pci.seg = pci_domain_nr(pdev->bus); dbgp.u.pci.bus = pdev->bus->number; dbgp.u.pci.devfn = pdev->devfn; dbgp.bus = PHYSDEVOP_DBGP_BUS_PCI; } else #endif dbgp.bus = PHYSDEVOP_DBGP_BUS_UNKNOWN; return HYPERVISOR_physdev_op(PHYSDEVOP_dbgp_op, &dbgp); }
static int ehci_msm2_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; struct msm_hcd *mhcd; struct pinctrl_state *set_state; const struct msm_usb_host_platform_data *pdata; char pdev_name[PDEV_NAME_LEN]; int ret; dev_dbg(&pdev->dev, "ehci_msm2 probe\n"); /* * Fail probe in case of uicc till userspace activates driver through * sysfs entry. */ if (!uicc_card_present && pdev->dev.of_node && of_property_read_bool( pdev->dev.of_node, "qcom,usb2-enable-uicc")) return -ENODEV; hcd = usb_create_hcd(&ehci_msm2_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } mhcd = hcd_to_mhcd(hcd); mhcd->dev = &pdev->dev; mhcd->xo_clk = clk_get(&pdev->dev, "xo"); if (IS_ERR(mhcd->xo_clk)) { ret = PTR_ERR(mhcd->xo_clk); mhcd->xo_clk = NULL; if (ret == -EPROBE_DEFER) goto put_hcd; } ret = msm_ehci_init_clocks(mhcd, 1); if (ret) goto xo_put; if (pdev->dev.of_node) { dev_dbg(&pdev->dev, "device tree enabled\n"); pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev); } if (!pdev->dev.platform_data) dev_dbg(&pdev->dev, "No platform data given\n"); pdata = pdev->dev.platform_data; if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &ehci_msm_dma_mask; if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { dev_err(&pdev->dev, "Unable to get IRQ resource\n"); ret = hcd->irq; goto deinit_clocks; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to get memory resource\n"); ret = -ENODEV; goto deinit_clocks; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto deinit_clocks; } spin_lock_init(&mhcd->wakeup_lock); mhcd->async_irq = platform_get_irq_byname(pdev, "async_irq"); if (mhcd->async_irq < 0) { dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n"); mhcd->async_irq = 0; } else { ret = request_irq(mhcd->async_irq, msm_async_irq, IRQF_TRIGGER_RISING, "msm_ehci_host", mhcd); if (ret) { dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); goto unmap; } disable_irq(mhcd->async_irq); } snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id); if (mhcd->xo_clk) ret = clk_prepare_enable(mhcd->xo_clk); if (ret) { dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n", __func__, ret); goto free_xo_handle; } /* Get pinctrl if target uses pinctrl */ mhcd->hsusb_pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(mhcd->hsusb_pinctrl)) { if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) { dev_err(&pdev->dev, "Error encountered while getting pinctrl"); ret = PTR_ERR(mhcd->hsusb_pinctrl); goto devote_xo_handle; } pr_debug("Target does not use pinctrl\n"); mhcd->hsusb_pinctrl = NULL; } if (mhcd->hsusb_pinctrl) { set_state = pinctrl_lookup_state(mhcd->hsusb_pinctrl, "ehci_active"); if (IS_ERR(set_state)) { pr_err("cannot get hsusb pinctrl active state\n"); ret = PTR_ERR(set_state); goto devote_xo_handle; } ret = pinctrl_select_state(mhcd->hsusb_pinctrl, set_state); if (ret) { pr_err("cannot set hsusb pinctrl active state\n"); goto devote_xo_handle; } } if (pdata && gpio_is_valid(pdata->resume_gpio)) { mhcd->resume_gpio = pdata->resume_gpio; ret = devm_gpio_request(&pdev->dev, mhcd->resume_gpio, "hsusb_resume"); if (ret) { dev_err(&pdev->dev, "resume gpio(%d) request failed:%d\n", mhcd->resume_gpio, ret); mhcd->resume_gpio = -EINVAL; } else { /* to override ehci_bus_resume from ehci-hcd library */ ehci_bus_resume_func = ehci_msm2_hc_driver.bus_resume; ehci_msm2_hc_driver.bus_resume = msm_ehci_bus_resume_with_gpio; } } if (pdata && gpio_is_valid(pdata->ext_hub_reset_gpio)) { ret = devm_gpio_request(&pdev->dev, pdata->ext_hub_reset_gpio, "hsusb_reset"); if (ret) { dev_err(&pdev->dev, "reset gpio(%d) request failed:%d\n", pdata->ext_hub_reset_gpio, ret); goto pinctrl_sleep; } else { /* reset external hub */ gpio_direction_output(pdata->ext_hub_reset_gpio, 0); /* * Hub reset should be asserted for minimum 5microsec * before deasserting. */ usleep_range(5, 1000); gpio_direction_output(pdata->ext_hub_reset_gpio, 1); } } spin_lock_init(&mhcd->wakeup_lock); ret = msm_ehci_init_vddcx(mhcd, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize VDDCX\n"); ret = -ENODEV; goto pinctrl_sleep; } ret = msm_ehci_config_vddcx(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); goto deinit_vddcx; } ret = msm_ehci_ldo_init(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); goto deinit_vddcx; } ret = msm_ehci_ldo_enable(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg enable failed\n"); goto deinit_ldo; } ret = msm_ehci_init_vbus(mhcd, 1); if (ret) goto disable_ldo; hcd->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); if (IS_ERR(hcd->phy)) { if (PTR_ERR(hcd->phy) == -EPROBE_DEFER) { dev_dbg(&pdev->dev, "usb-phy not probed yet\n"); ret = -EPROBE_DEFER; goto vbus_deinit; } hcd->phy = NULL; } if (hcd->phy) usb_phy_init(hcd->phy); else if (pdata && pdata->use_sec_phy) mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL2; else mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL; ret = msm_hsusb_reset(mhcd); if (ret) { dev_err(&pdev->dev, "hsusb PHY initialization failed\n"); goto vbus_deinit; } ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (ret) { dev_err(&pdev->dev, "unable to register HCD\n"); goto vbus_deinit; } pdata = mhcd->dev->platform_data; if (pdata && (!pdata->dock_connect_irq || !irq_read_line(pdata->dock_connect_irq))) msm_ehci_vbus_power(mhcd, 1); /* For peripherals directly conneted to downstream port of root hub * and require to drive suspend and resume by controller driver instead * of root hub. */ if (pdata) mhcd->ehci.no_selective_suspend = pdata->no_selective_suspend; mhcd->wakeup_irq = platform_get_irq_byname(pdev, "wakeup_irq"); if (mhcd->wakeup_irq > 0) { dev_dbg(&pdev->dev, "wakeup irq:%d\n", mhcd->wakeup_irq); irq_set_status_flags(mhcd->wakeup_irq, IRQ_NOAUTOEN); ret = request_irq(mhcd->wakeup_irq, msm_hsusb_wakeup_irq, IRQF_TRIGGER_HIGH, "msm_hsusb_wakeup", mhcd); if (ret) { dev_err(&pdev->dev, "request_irq(%d) failed:%d\n", mhcd->wakeup_irq, ret); mhcd->wakeup_irq = 0; } } else { mhcd->wakeup_irq = 0; } device_init_wakeup(&pdev->dev, 1); wakeup_source_init(&mhcd->ws, dev_name(&pdev->dev)); pm_stay_awake(mhcd->dev); INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work); /* * This pdev->dev is assigned parent of root-hub by USB core, * hence, runtime framework automatically calls this driver's * runtime APIs based on root-hub's state. */ /* configure pmic_gpio_irq for D+ change */ if (pdata && pdata->pmic_gpio_dp_irq) mhcd->pmic_gpio_dp_irq = pdata->pmic_gpio_dp_irq; if (mhcd->pmic_gpio_dp_irq) { ret = request_threaded_irq(mhcd->pmic_gpio_dp_irq, NULL, msm_ehci_host_wakeup_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "msm_ehci_host_wakeup", mhcd); if (!ret) { disable_irq_nosync(mhcd->pmic_gpio_dp_irq); } else { dev_err(&pdev->dev, "request_irq(%d) failed: %d\n", mhcd->pmic_gpio_dp_irq, ret); mhcd->pmic_gpio_dp_irq = 0; } } pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); if (ehci_debugfs_init(mhcd) < 0) dev_err(mhcd->dev, "%s: debugfs init failed\n", __func__); return 0; vbus_deinit: msm_ehci_init_vbus(mhcd, 0); disable_ldo: msm_ehci_ldo_enable(mhcd, 0); deinit_ldo: msm_ehci_ldo_init(mhcd, 0); deinit_vddcx: msm_ehci_init_vddcx(mhcd, 0); pinctrl_sleep: if (mhcd->hsusb_pinctrl) { set_state = pinctrl_lookup_state(mhcd->hsusb_pinctrl, "ehci_sleep"); if (IS_ERR(set_state)) pr_err("cannot get hsusb pinctrl sleep state\n"); else pinctrl_select_state(mhcd->hsusb_pinctrl, set_state); } devote_xo_handle: if (mhcd->xo_clk) clk_disable_unprepare(mhcd->xo_clk); free_xo_handle: if (mhcd->xo_clk) { clk_put(mhcd->xo_clk); mhcd->xo_clk = NULL; } if (mhcd->async_irq) free_irq(mhcd->async_irq, mhcd); unmap: iounmap(hcd->regs); deinit_clocks: msm_ehci_init_clocks(mhcd, 0); xo_put: if (mhcd->xo_clk) clk_put(mhcd->xo_clk); put_hcd: usb_put_hcd(hcd); return ret; }
static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; struct msm_hsic_hcd *mehci; struct msm_hsic_host_platform_data *pdata; int ret; dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n"); /* After parent device's probe is executed, it will be put in suspend * mode. When child device's probe is called, driver core is not * resuming parent device due to which parent will be in suspend even * though child is active. Hence resume the parent device explicitly. */ if (pdev->dev.parent) pm_runtime_get_sync(pdev->dev.parent); hcd = usb_create_hcd(&msm_hsic_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { dev_err(&pdev->dev, "Unable to get IRQ resource\n"); ret = hcd->irq; goto put_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to get memory resource\n"); ret = -ENODEV; goto put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto put_hcd; } mehci = hcd_to_hsic(hcd); mehci->dev = &pdev->dev; pdata = mehci->dev->platform_data; mehci->ehci.susp_sof_bug = 1; mehci->ehci.reset_sof_bug = 1; mehci->ehci.resume_sof_bug = 1; if (pdata) mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh; res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "peripheral_status_irq"); if (res) mehci->peripheral_status_irq = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup"); if (res) { mehci->wakeup_gpio = res->start; mehci->wakeup_irq = MSM_GPIO_TO_INT(res->start); dev_dbg(mehci->dev, "wakeup_irq: %d\n", mehci->wakeup_irq); } ret = msm_hsic_init_clocks(mehci, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize clocks\n"); ret = -ENODEV; goto unmap; } ret = msm_hsic_init_vddcx(mehci, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize VDDCX\n"); ret = -ENODEV; goto deinit_clocks; } init_completion(&mehci->rt_completion); init_completion(&mehci->gpt0_completion); ret = msm_hsic_reset(mehci); if (ret) { dev_err(&pdev->dev, "unable to initialize PHY\n"); goto deinit_vddcx; } ehci_wq = create_singlethread_workqueue("ehci_wq"); if (!ehci_wq) { dev_err(&pdev->dev, "unable to create workqueue\n"); ret = -ENOMEM; goto deinit_vddcx; } INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w); ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (ret) { dev_err(&pdev->dev, "unable to register HCD\n"); goto unconfig_gpio; } device_init_wakeup(&pdev->dev, 1); wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev)); wake_lock(&mehci->wlock); if (mehci->peripheral_status_irq) { ret = request_threaded_irq(mehci->peripheral_status_irq, NULL, hsic_peripheral_status_change, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED, "hsic_peripheral_status", mehci); if (ret) dev_err(&pdev->dev, "%s:request_irq:%d failed:%d", __func__, mehci->peripheral_status_irq, ret); } /* configure wakeup irq */ if (mehci->wakeup_irq) { ret = request_irq(mehci->wakeup_irq, msm_hsic_wakeup_irq, IRQF_TRIGGER_HIGH, "msm_hsic_wakeup", mehci); if (!ret) { disable_irq_nosync(mehci->wakeup_irq); } else { dev_err(&pdev->dev, "request_irq(%d) failed: %d\n", mehci->wakeup_irq, ret); mehci->wakeup_irq = 0; } } ret = ehci_hsic_msm_debugfs_init(mehci); if (ret) dev_dbg(&pdev->dev, "mode debugfs file is" "not available\n"); if (pdata && pdata->bus_scale_table) { mehci->bus_perf_client = msm_bus_scale_register_client(pdata->bus_scale_table); /* Configure BUS performance parameters for MAX bandwidth */ if (mehci->bus_perf_client) { mehci->bus_vote = true; queue_work(ehci_wq, &mehci->bus_vote_w); } else { dev_err(&pdev->dev, "%s: Failed to register BUS " "scaling client!!\n", __func__); } } __mehci = mehci; /* * This pdev->dev is assigned parent of root-hub by USB core, * hence, runtime framework automatically calls this driver's * runtime APIs based on root-hub's state. */ pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); /* Decrement the parent device's counter after probe. * As child is active, parent will not be put into * suspend mode. */ if (pdev->dev.parent) pm_runtime_put_sync(pdev->dev.parent); return 0; unconfig_gpio: destroy_workqueue(ehci_wq); msm_hsic_config_gpios(mehci, 0); deinit_vddcx: msm_hsic_init_vddcx(mehci, 0); deinit_clocks: msm_hsic_init_clocks(mehci, 0); unmap: iounmap(hcd->regs); put_hcd: usb_put_hcd(hcd); return ret; }
static int xhci_plat_probe(struct platform_device *pdev) { const struct hc_driver *driver; struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; int ret; int irq; if (usb_disabled()) return -ENODEV; driver = &xhci_plat_xhci_driver; irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) return -ENOMEM; hcd_to_bus(hcd)->skip_resume = true; hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&pdev->dev, "controller already in use\n"); ret = -EBUSY; goto put_hcd; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_dbg(&pdev->dev, "error mapping memory\n"); ret = -EFAULT; goto release_mem_region; } pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto unmap_registers; /* USB 2.0 roothub is stored in the platform_device now. */ hcd = dev_get_drvdata(&pdev->dev); xhci = hcd_to_xhci(hcd); xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { ret = -ENOMEM; goto dealloc_usb2_hcd; } hcd_to_bus(xhci->shared_hcd)->skip_resume = true; /* * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto put_usb3_hcd; phy = usb_get_transceiver(); /* Register with OTG if present, ignore USB2 OTG using other PHY */ if (phy && phy->otg && !(phy->flags & ENABLE_SECONDARY_PHY)) { dev_dbg(&pdev->dev, "%s otg support available\n", __func__); ret = otg_set_host(phy->otg, &hcd->self); if (ret) { dev_err(&pdev->dev, "%s otg_set_host failed\n", __func__); usb_put_transceiver(phy); goto put_usb3_hcd; } } else { pm_runtime_no_callbacks(&pdev->dev); } pm_runtime_put(&pdev->dev); return 0; put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); dealloc_usb2_hcd: usb_remove_hcd(hcd); unmap_registers: iounmap(hcd->regs); release_mem_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); put_hcd: usb_put_hcd(hcd); return ret; }
/* caller owns root->serialize, and should reset/reinit on error */ static int ehci_hub_resume (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub; u32 temp; int i; if (!root->dev.power.power_state) return 0; if (time_before (jiffies, ehci->next_statechange)) return -EAGAIN; /* re-init operational registers in case we lost power */ if (readl (&ehci->regs->intr_enable) == 0) { writel (INTR_MASK, &ehci->regs->intr_enable); writel (0, &ehci->regs->segment); writel (ehci->periodic_dma, &ehci->regs->frame_list); writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); /* FIXME will this work even (pci) vAUX was lost? */ } /* restore CMD_RUN, framelist size, and irq threshold */ writel (ehci->command, &ehci->regs->command); /* take ports out of suspend */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { temp = readl (&ehci->regs->port_status [i]); temp &= ~(PORT_RWC_BITS | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); if (temp & PORT_SUSPEND) { ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; } writel (temp, &ehci->regs->port_status [i]); } i = HCS_N_PORTS (ehci->hcs_params); msleep (20); while (i--) { temp = readl (&ehci->regs->port_status [i]); if ((temp & PORT_SUSPEND) == 0) continue; temp &= ~(PORT_RWC_BITS | PORT_RESUME); writel (temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } (void) readl (&ehci->regs->command); /* maybe re-activate the schedule(s) */ temp = 0; if (ehci->async->qh_next.qh) temp |= CMD_ASE; if (ehci->periodic_sched) temp |= CMD_PSE; if (temp) writel (ehci->command | temp, &ehci->regs->command); root->dev.power.power_state = 0; ehci->next_statechange = jiffies + msecs_to_jiffies(5); ehci->hcd.state = USB_STATE_RUNNING; return 0; }
/* Electrical test support */ static void host_write_port(u8 port, const char *buf) { struct usb_bus *bus; struct ehci_hcd *ehci = hcd_to_ehci(ghcd); u32 port_status; u32 cmd; /* Reset Device */ if (!strncmp(buf, "reset", 5)) { printk(KERN_INFO "\n RESET PORT \n"); bus = hcd_to_bus(ghcd); if (bus->root_hub->children[port]) usb_reset_device(bus->root_hub->children[port]); } if (!strncmp(buf, "t-j", 3)) { printk(KERN_INFO "\n TEST_J \n"); #ifdef CONFIG_PM /* Suspend bus first */ ehci_bus_suspend(ghcd); #endif port_status = ehci_readl(ehci, &ehci->regs->port_status[port]); cmd = ehci_readl(ehci, &ehci->regs->command); port_status |= 1<<16; /* Test_Packet on Port2 */ ehci_writel(ehci, port_status, &ehci->regs->port_status[port]); cmd |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } if (!strncmp(buf, "t-k", 3)) { printk(KERN_INFO "\n TEST_K \n"); #ifdef CONFIG_PM /* Suspend bus first */ ehci_bus_suspend(ghcd); #endif port_status = ehci_readl(ehci, &ehci->regs->port_status[port]); cmd = ehci_readl(ehci, &ehci->regs->command); port_status |= 2<<16; /* Test_Packet on Port2 */ ehci_writel(ehci, port_status, &ehci->regs->port_status[port]); cmd |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } if (!strncmp(buf, "t-se0", 5)) { printk(KERN_INFO "\n TEST_SE0_NAK \n"); #ifdef CONFIG_PM /* Suspend bus first */ ehci_bus_suspend(ghcd); #endif port_status = ehci_readl(ehci, &ehci->regs->port_status[port]); cmd = ehci_readl(ehci, &ehci->regs->command); port_status |= 3<<16; /* Test_Packet on Port2 */ ehci_writel(ehci, port_status, &ehci->regs->port_status[port]); cmd |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } /* Send test packet on suspended port */ if (!strncmp(buf, "t-pkt", 5)) { printk(KERN_INFO "\n TEST_PACKET \n"); #ifdef CONFIG_PM /* Suspend bus first */ ehci_bus_suspend(ghcd); #endif port_status = ehci_readl(ehci, &ehci->regs->port_status[port]); cmd = ehci_readl(ehci, &ehci->regs->command); /* Set Test packet bit */ port_status |= 4<<16; /* Test_Packet on Port2 */ ehci_writel(ehci, port_status, &ehci->regs->port_status[port]); cmd |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } if (!strncmp(buf, "t-force", 7)) { printk(KERN_INFO "\n TEST_FORCE \n"); #ifdef CONFIG_PM /* Suspend bus first */ ehci_bus_suspend(ghcd); #endif port_status = ehci_readl(ehci, &ehci->regs->port_status[port]); cmd = ehci_readl(ehci, &ehci->regs->command); port_status |= 5<<16; /* Test_Packet on Port2 */ ehci_writel(ehci, port_status, &ehci->regs->port_status[port]); cmd |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } }
static int ohci_hub_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub; int status = 0; if (root->dev.power.power_state != 0) return 0; if (time_before (jiffies, ohci->next_statechange)) return -EAGAIN; spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (&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; writel (ohci->hc_control, &ohci->regs->control); (void) ohci_readl (&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 succeed; } ohci_dbg (ohci, "suspend root hub\n"); /* First stop any processing */ ohci->hcd.state = USB_STATE_QUIESCING; if (ohci->hc_control & OHCI_SCHED_ENABLES) { int limit; ohci->hc_control &= ~OHCI_SCHED_ENABLES; writel (ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (&ohci->regs->control); writel (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->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->hcca), NULL); writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ if (ohci->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; writel (ohci->hc_control, &ohci->regs->control); (void) ohci_readl (&ohci->regs->control); /* no resumes until devices finish suspending */ ohci->next_statechange = jiffies + msecs_to_jiffies (5); succeed: /* it's not USB_STATE_SUSPENDED unless access to this * hub from the non-usb side (PCI, SOC, etc) stopped */ root->dev.power.power_state = 3; done: spin_unlock_irq (&ohci->lock); return status; }
static int __devinit ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; struct msm_usb_host_platform_data *pdata; int retval; struct msmusb_hcd *mhcd; hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) return -ENOMEM; hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { usb_put_hcd(hcd); return hcd->irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { usb_put_hcd(hcd); return -ENODEV; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); mhcd = hcd_to_mhcd(hcd); spin_lock_init(&mhcd->lock); mhcd->in_lpm = 0; mhcd->running = 0; device_init_wakeup(&pdev->dev, 1); pdata = pdev->dev.platform_data; if (PHY_TYPE(pdata->phy_info) == USB_PHY_UNDEFINED) { usb_put_hcd(hcd); return -ENODEV; } hcd->power_budget = pdata->power_budget; mhcd->pdata = pdata; INIT_WORK(&mhcd->lpm_exit_work, usb_lpm_exit_w); wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev)); pdata->ebi1_clk = clk_get(&pdev->dev, "core_clk"); if (IS_ERR(pdata->ebi1_clk)) pdata->ebi1_clk = NULL; else clk_set_rate(pdata->ebi1_clk, INT_MAX); retval = msm_xusb_init_host(pdev, mhcd); if (retval < 0) { wake_lock_destroy(&mhcd->wlock); usb_put_hcd(hcd); clk_put(pdata->ebi1_clk); } pm_runtime_enable(&pdev->dev); return retval; }
static int __devinit ehci_msm2_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; struct msm_hcd *mhcd; const struct msm_usb_host_platform_data *pdata; char pdev_name[PDEV_NAME_LEN]; int ret; int res_gpio; dev_info(&pdev->dev, "ehci_msm2 probe\n"); /* If there is no WAN device present, we don't need to start the EHCI stack */ if(!wan_present()) return -ENODEV; if (pdev->dev.of_node) { dev_dbg(&pdev->dev, "device tree enabled\n"); pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev); } if (!pdev->dev.platform_data) dev_dbg(&pdev->dev, "No platform data given\n"); if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &ehci_msm_dma_mask; if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&msm_hc2_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { dev_err(&pdev->dev, "Unable to get IRQ resource\n"); ret = hcd->irq; goto put_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to get memory resource\n"); ret = -ENODEV; goto put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto put_hcd; } mhcd = hcd_to_mhcd(hcd); mhcd->dev = &pdev->dev; spin_lock_init(&mhcd->wakeup_lock); mhcd->async_irq = platform_get_irq_byname(pdev, "async_irq"); if (mhcd->async_irq < 0) { dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n"); mhcd->async_irq = 0; } else { ret = request_irq(mhcd->async_irq, msm_async_irq, IRQF_TRIGGER_RISING, "msm_ehci_host", mhcd); if (ret) { dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n"); goto unmap; } disable_irq(mhcd->async_irq); } snprintf(pdev_name, PDEV_NAME_LEN, "%s.%d", pdev->name, pdev->id); mhcd->xo_clk = clk_get(&pdev->dev, "xo"); if (!IS_ERR(mhcd->xo_clk)) { ret = clk_prepare_enable(mhcd->xo_clk); } else { mhcd->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, pdev_name); if (IS_ERR(mhcd->xo_handle)) { dev_err(&pdev->dev, "%s fail to get handle for X0 D0\n", __func__); ret = PTR_ERR(mhcd->xo_handle); goto free_async_irq; } else { ret = msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_ON); } } if (ret) { dev_err(&pdev->dev, "%s failed to vote for TCXO %d\n", __func__, ret); goto free_xo_handle; } if (pdev->dev.of_node) { res_gpio = of_get_named_gpio(pdev->dev.of_node, "usb2,resume-gpio", 0); if (res_gpio < 0){ res_gpio = 0; goto devote_xo_handle; } mhcd->resume_gpio = res_gpio; gpio_request(mhcd->resume_gpio, "USB2_RESUME"); } else { res = platform_get_resource_byname(pdev, IORESOURCE_IO, "resume_gpio"); if (res) { dev_dbg(&pdev->dev, "resume_gpio:%d\n", res->start); mhcd->resume_gpio = res->start; } } if(pdev->dev.of_node){ res_gpio = of_get_named_gpio(pdev->dev.of_node, "usb2,wakeup-gpio", 0); if (res_gpio < 0){ res_gpio = 0; goto devote_xo_handle; } mhcd->wakeup_gpio = res_gpio; } else { res = platform_get_resource_byname(pdev, IORESOURCE_IO, "wakeup_gpio"); if (res) { dev_dbg(&pdev->dev, "wakeup gpio:%d\n", res->start); mhcd->wakeup_gpio = res->start; } } if (pdev->dev.of_node) mhcd->wakeup_irq = gpio_to_irq(mhcd->wakeup_gpio); else mhcd->wakeup_irq = platform_get_irq_byname(pdev, "wakeup_irq"); if (mhcd->wakeup_irq > 0) { dev_dbg(&pdev->dev, "wakeup irq:%d\n", res->start); irq_set_status_flags(mhcd->wakeup_irq, IRQ_NOAUTOEN); ret = request_irq(mhcd->wakeup_irq, msm_hsusb_wakeup_irq, IRQF_TRIGGER_HIGH, "msm_hsusb_wakeup", mhcd); if (ret) { dev_err(&pdev->dev, "request_irq(%d) failed:%d\n", mhcd->wakeup_irq, ret); mhcd->wakeup_irq = 0; } } else { mhcd->wakeup_irq = 0; } spin_lock_init(&mhcd->wakeup_lock); ret = msm_ehci_init_clocks(mhcd, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize clocks\n"); ret = -ENODEV; goto devote_xo_handle; } ret = msm_ehci_init_vddcx(mhcd, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize VDDCX\n"); ret = -ENODEV; goto deinit_clocks; } ret = msm_ehci_config_vddcx(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); goto deinit_vddcx; } ret = msm_ehci_ldo_init(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); goto deinit_vddcx; } ret = msm_ehci_ldo_enable(mhcd, 1); if (ret) { dev_err(&pdev->dev, "hsusb vreg enable failed\n"); goto deinit_ldo; } ret = msm_ehci_init_vbus(mhcd, 1); if (ret) { dev_err(&pdev->dev, "unable to get vbus\n"); goto disable_ldo; } pdata = mhcd->dev->platform_data; if (pdata && pdata->use_sec_phy) mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL2; else mhcd->usb_phy_ctrl_reg = USB_PHY_CTRL; ret = msm_hsusb_reset(mhcd); if (ret) { dev_err(&pdev->dev, "hsusb PHY initialization failed\n"); goto vbus_deinit; } if( pdata && pdata->phy_sof_workaround) { /* defer bus suspend until RH suspend */ mhcd->ehci.susp_sof_bug = 1; mhcd->ehci.resume_sof_bug = 1; } ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (ret) { dev_err(&pdev->dev, "unable to register HCD\n"); goto vbus_deinit; } if (pdata && (!pdata->dock_connect_irq || !irq_read_line(pdata->dock_connect_irq))) msm_ehci_vbus_power(mhcd, 1); device_init_wakeup(&pdev->dev, 1); wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev)); wake_lock(&mhcd->wlock); INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work); /* * This pdev->dev is assigned parent of root-hub by USB core, * hence, runtime framework automatically calls this driver's * runtime APIs based on root-hub's state. */ /* configure pmic_gpio_irq for D+ change */ if (pdata && pdata->pmic_gpio_dp_irq) mhcd->pmic_gpio_dp_irq = pdata->pmic_gpio_dp_irq; if (mhcd->pmic_gpio_dp_irq) { ret = request_threaded_irq(mhcd->pmic_gpio_dp_irq, NULL, msm_ehci_host_wakeup_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "msm_ehci_host_wakeup", mhcd); if (!ret) { disable_irq_nosync(mhcd->pmic_gpio_dp_irq); } else { dev_err(&pdev->dev, "request_irq(%d) failed: %d\n", mhcd->pmic_gpio_dp_irq, ret); mhcd->pmic_gpio_dp_irq = 0; } } if (pdata && pdata->pd_rework_installed) mhcd->flags |= ALLOW_EHCI_RETENTION; pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; vbus_deinit: msm_ehci_init_vbus(mhcd, 0); disable_ldo: msm_ehci_ldo_enable(mhcd, 0); deinit_ldo: msm_ehci_ldo_init(mhcd, 0); deinit_vddcx: msm_ehci_init_vddcx(mhcd, 0); deinit_clocks: msm_ehci_init_clocks(mhcd, 0); devote_xo_handle: if (!IS_ERR(mhcd->xo_clk)) clk_disable_unprepare(mhcd->xo_clk); else msm_xo_mode_vote(mhcd->xo_handle, MSM_XO_MODE_OFF); if(mhcd->wakeup_irq) free_irq(mhcd->wakeup_irq, mhcd); if(mhcd->resume_gpio) gpio_free(mhcd->resume_gpio); free_xo_handle: if (!IS_ERR(mhcd->xo_clk)) clk_put(mhcd->xo_clk); else msm_xo_put(mhcd->xo_handle); free_async_irq: if (mhcd->async_irq) free_irq(mhcd->async_irq, mhcd); unmap: iounmap(hcd->regs); put_hcd: usb_put_hcd(hcd); return ret; }
/* 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 (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 == USB_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: ohci_dbg (ohci, "odd resume\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) need extra-long delays */ ohci->hcd.state = USB_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); 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 (ohci->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_to_bus (&ohci->hcd)->bandwidth_isoc_reqs || hcd_to_bus (&ohci->hcd)->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); } ohci->hcd.state = USB_STATE_RUNNING; return 0; }
static int mxhci_hsic_probe(struct platform_device *pdev) { struct hc_driver *driver; struct device_node *node = pdev->dev.of_node; struct mxhci_hsic_hcd *mxhci; struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; unsigned int reg; int ret; int irq; u32 tmp[3]; if (usb_disabled()) return -ENODEV; driver = &mxhci_hsic_hc_driver; pdev->dev.dma_mask = &dma_mask; /* dbg log event settings */ dbg_hsic.log_events = enable_dbg_log; dbg_hsic.log_payload = enable_payload_log; dbg_hsic.inep_log_mask = ep_addr_rxdbg_mask; dbg_hsic.outep_log_mask = ep_addr_rxdbg_mask; /* usb2.0 root hub */ driver->hcd_priv_size = sizeof(struct mxhci_hsic_hcd); hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) return -ENOMEM; irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENODEV; goto put_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENODEV; goto put_hcd; } hcd_to_bus(hcd)->skip_resume = true; hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = devm_request_and_ioremap(&pdev->dev, res); if (!hcd->regs) { dev_err(&pdev->dev, "error mapping memory\n"); ret = -EFAULT; goto put_hcd; } mxhci = hcd_to_hsic(hcd); mxhci->dev = &pdev->dev; mxhci->strobe = of_get_named_gpio(node, "hsic,strobe-gpio", 0); if (mxhci->strobe < 0) { ret = -EINVAL; goto put_hcd; } mxhci->data = of_get_named_gpio(node, "hsic,data-gpio", 0); if (mxhci->data < 0) { ret = -EINVAL; goto put_hcd; } ret = of_property_read_u32_array(node, "qcom,vdd-voltage-level", tmp, ARRAY_SIZE(tmp)); if (!ret) { mxhci->vdd_no_vol_level = tmp[0]; mxhci->vdd_low_vol_level = tmp[1]; mxhci->vdd_high_vol_level = tmp[2]; } else { dev_err(&pdev->dev, "failed to read qcom,vdd-voltage-level property\n"); ret = -EINVAL; goto put_hcd; } ret = mxhci_msm_config_gdsc(mxhci, 1); if (ret) { dev_err(&pdev->dev, "unable to configure hsic gdsc\n"); goto put_hcd; } ret = mxhci_hsic_init_clocks(mxhci, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize clocks\n"); goto put_hcd; } ret = mxhci_hsic_init_vddcx(mxhci, 1); if (ret) { dev_err(&pdev->dev, "unable to initialize vddcx\n"); goto deinit_clocks; } mxhci_hsic_reset(mxhci); /* HSIC phy caliberation:set periodic caliberation interval ~2.048sec */ mxhci_hsic_ulpi_write(mxhci, 0xFF, MSM_HSIC_IO_CAL_PER); /* Enable periodic IO calibration in HSIC_CFG register */ mxhci_hsic_ulpi_write(mxhci, 0xA8, MSM_HSIC_CFG); /* Configure Strobe and Data GPIOs to enable HSIC */ ret = mxhci_hsic_config_gpios(mxhci); if (ret) { dev_err(mxhci->dev, " gpio configuarion failed\n"); goto deinit_vddcx; } /* enable STROBE_PAD_CTL */ reg = readl_relaxed(TLMM_GPIO_HSIC_STROBE_PAD_CTL); writel_relaxed(reg | 0x2000000, TLMM_GPIO_HSIC_STROBE_PAD_CTL); /* enable DATA_PAD_CTL */ reg = readl_relaxed(TLMM_GPIO_HSIC_DATA_PAD_CTL); writel_relaxed(reg | 0x2000000, TLMM_GPIO_HSIC_DATA_PAD_CTL); mb(); /* Enable LPM in Sleep mode and suspend mode */ reg = readl_relaxed(MSM_HSIC_CTRL_REG); reg |= CTRLREG_PLL_CTRL_SLEEP | CTRLREG_PLL_CTRL_SUSP; writel_relaxed(reg, MSM_HSIC_CTRL_REG); if (of_property_read_bool(node, "qti,disable-hw-clk-gating")) { reg = readl_relaxed(MSM_HSIC_GCTL); writel_relaxed((reg | GCTL_DSBLCLKGTNG), MSM_HSIC_GCTL); } /* enable pwr event irq for LPM_IN_L2_IRQ */ writel_relaxed(LPM_IN_L2_IRQ_MASK, MSM_HSIC_PWR_EVNT_IRQ_MASK); mxhci->wakeup_irq = platform_get_irq_byname(pdev, "wakeup_irq"); if (mxhci->wakeup_irq < 0) { mxhci->wakeup_irq = 0; dev_err(&pdev->dev, "failed to init wakeup_irq\n"); } else { /* enable wakeup irq only when entering lpm */ irq_set_status_flags(mxhci->wakeup_irq, IRQ_NOAUTOEN); ret = devm_request_irq(&pdev->dev, mxhci->wakeup_irq, mxhci_hsic_wakeup_irq, 0, "mxhci_hsic_wakeup", mxhci); if (ret) { dev_err(&pdev->dev, "request irq failed (wakeup irq)\n"); goto deinit_vddcx; } } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto deinit_vddcx; hcd = dev_get_drvdata(&pdev->dev); xhci = hcd_to_xhci(hcd); /* USB 3.0 roothub */ /* no need for another instance of mxhci */ driver->hcd_priv_size = sizeof(struct xhci_hcd *); xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { ret = -ENOMEM; goto remove_usb2_hcd; } hcd_to_bus(xhci->shared_hcd)->skip_resume = true; /* * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) * is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto put_usb3_hcd; spin_lock_init(&mxhci->wakeup_lock); mxhci->pwr_event_irq = platform_get_irq_byname(pdev, "pwr_event_irq"); if (mxhci->pwr_event_irq < 0) { dev_err(&pdev->dev, "platform_get_irq for pwr_event_irq failed\n"); goto remove_usb3_hcd; } ret = devm_request_irq(&pdev->dev, mxhci->pwr_event_irq, mxhci_hsic_pwr_event_irq, 0, "mxhci_hsic_pwr_evt", mxhci); if (ret) { dev_err(&pdev->dev, "request irq failed (pwr event irq)\n"); goto remove_usb3_hcd; } init_completion(&mxhci->phy_in_lpm); mxhci->wq = create_singlethread_workqueue("mxhci_wq"); if (!mxhci->wq) { dev_err(&pdev->dev, "unable to create workqueue\n"); ret = -ENOMEM; goto remove_usb3_hcd; } INIT_WORK(&mxhci->bus_vote_w, mxhci_hsic_bus_vote_w); mxhci->bus_scale_table = msm_bus_cl_get_pdata(pdev); if (!mxhci->bus_scale_table) { dev_dbg(&pdev->dev, "bus scaling is disabled\n"); } else { mxhci->bus_perf_client = msm_bus_scale_register_client(mxhci->bus_scale_table); /* Configure BUS performance parameters for MAX bandwidth */ if (mxhci->bus_perf_client) { mxhci->bus_vote = true; queue_work(mxhci->wq, &mxhci->bus_vote_w); } else { dev_err(&pdev->dev, "%s: bus scaling client reg err\n", __func__); ret = -ENODEV; goto delete_wq; } } ret = device_create_file(&pdev->dev, &dev_attr_config_imod); if (ret) dev_dbg(&pdev->dev, "%s: unable to create imod sysfs entry\n", __func__); /* Enable HSIC PHY */ mxhci_hsic_ulpi_write(mxhci, 0x01, MSM_HSIC_CFG_SET); device_init_wakeup(&pdev->dev, 1); wakeup_source_init(&mxhci->ws, dev_name(&pdev->dev)); pm_stay_awake(mxhci->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; delete_wq: destroy_workqueue(mxhci->wq); remove_usb3_hcd: usb_remove_hcd(xhci->shared_hcd); put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); remove_usb2_hcd: usb_remove_hcd(hcd); deinit_vddcx: mxhci_hsic_init_vddcx(mxhci, 0); deinit_clocks: mxhci_hsic_init_clocks(mxhci, 0); put_hcd: usb_put_hcd(hcd); return ret; }
static int ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; int ret; dev_dbg(&pdev->dev, "ehci_msm proble\n"); if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &msm_ehci_dma_mask; if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&ehci_msm_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { dev_err(&pdev->dev, "Unable to get IRQ resource\n"); ret = hcd->irq; goto put_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to get memory resource\n"); ret = -ENODEV; goto put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto put_hcd; } /* * OTG driver takes care of PHY initialization, clock management, * powering up VBUS, mapping of registers address space and power * management. */ phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(phy)) { dev_err(&pdev->dev, "unable to find transceiver\n"); ret = -ENODEV; goto put_hcd; } ret = otg_set_host(phy->otg, &hcd->self); if (ret < 0) { dev_err(&pdev->dev, "unable to register with transceiver\n"); goto put_hcd; } hcd->phy = phy; device_init_wakeup(&pdev->dev, 1); pm_runtime_enable(&pdev->dev); msm_bam_set_usb_host_dev(&pdev->dev); return 0; put_hcd: usb_put_hcd(hcd); return ret; }
static int ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct resource *res; int ret; dev_dbg(&pdev->dev, "ehci_msm proble\n"); hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } hcd_to_bus(hcd)->skip_resume = true; hcd->irq = platform_get_irq(pdev, 0); if (hcd->irq < 0) { dev_err(&pdev->dev, "Unable to get IRQ resource\n"); ret = hcd->irq; goto put_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to get memory resource\n"); ret = -ENODEV; goto put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; goto put_hcd; } /* * OTG driver takes care of PHY initialization, clock management, * powering up VBUS, mapping of registers address space and power * management. */ phy = usb_get_transceiver(); if (!phy) { dev_err(&pdev->dev, "unable to find transceiver\n"); ret = -ENODEV; goto unmap; } ret = otg_set_host(phy->otg, &hcd->self); if (ret < 0) { dev_err(&pdev->dev, "unable to register with transceiver\n"); goto put_transceiver; } hcd_to_ehci(hcd)->transceiver = phy; device_init_wakeup(&pdev->dev, 1); pm_runtime_enable(&pdev->dev); return 0; put_transceiver: usb_put_transceiver(phy); unmap: iounmap(hcd->regs); put_hcd: usb_put_hcd(hcd); return ret; }