static int msm_hsic_pm_resume(struct device *dev) { int ret; struct usb_hcd *hcd = dev_get_drvdata(dev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); dev_dbg(dev, "ehci-msm-hsic PM resume\n"); dbg_log_event(NULL, "PM Resume", 0); if (device_may_wakeup(dev)) disable_irq_wake(hcd->irq); /* * Keep HSIC in Low Power Mode if system is resumed * by any other wakeup source. HSIC is resumed later * when remote wakeup is received or interface driver * start I/O. */ if (!atomic_read(&mehci->pm_usage_cnt) && pm_runtime_suspended(dev)) return 0; ret = msm_hsic_resume(mehci); if (ret) return ret; /* Bring the device to full powered state upon system resume */ pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; }
static void mxhci_hsic_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { struct xhci_plat_data *pdata = dev->platform_data; struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(xhci_to_hcd(xhci)); /* * As of now platform drivers don't provide MSI support so we ensure * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ xhci->quirks |= XHCI_PLAT; /* Single port controller using out of band remote wakeup */ if (mxhci->wakeup_irq) xhci->quirks |= XHCI_NO_SELECTIVE_SUSPEND; /* * Observing hw tr deq pointer getting stuck to a noop trb * when aborting transfer during suspend. Reset tr deq pointer * to start of the first seg of the xfer ring. */ xhci->quirks |= XHCI_TR_DEQ_RESET_QUIRK; if (!pdata) return; if (pdata->vendor == SYNOPSIS_DWC3_VENDOR && pdata->revision < 0x230A) xhci->quirks |= XHCI_PORTSC_DELAY; }
static ssize_t config_imod_store(struct device *pdev, struct device_attribute *attr, const char *buff, size_t size) { struct usb_hcd *hcd = dev_get_drvdata(pdev); struct xhci_hcd *xhci; struct mxhci_hsic_hcd *mxhci; u32 temp; u32 imod; unsigned long flags; sscanf(buff, "%u", &imod); imod &= ER_IRQ_INTERVAL_MASK; mxhci = hcd_to_hsic(hcd); xhci = hcd_to_xhci(hcd); if (mxhci->in_lpm) return -EACCES; spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->ir_set->irq_control); temp &= ~ER_IRQ_INTERVAL_MASK; temp |= imod; xhci_writel(xhci, temp, &xhci->ir_set->irq_control); spin_unlock_irqrestore(&xhci->lock, flags); return size; }
static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd) { struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); int val; val = ulpi_read(mehci, HSIC_DBG1); val &= ~ULPI_MANUAL_ENABLE; ulpi_write(mehci, val, HSIC_DBG1); }
static int mxhci_hsic_runtime_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(hcd); dev_dbg(dev, "xhci msm runtime resume\n"); xhci_dbg_log_event(&dbg_hsic, NULL, "Run Time PM Resume", 0); return mxhci_hsic_resume(mxhci); }
static int msm_hsic_runtime_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); dev_dbg(dev, "EHCI runtime resume\n"); dbg_log_event(NULL, "Run Time PM Resume", 0); return msm_hsic_resume(mehci); }
static int msm_hsic_pm_suspend_noirq(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); if (mehci->async_int) { dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n"); return -EBUSY; } return 0; }
static int mxhci_hsic_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(hcd); u32 reg; /* disable STROBE_PAD_CTL */ reg = readl_relaxed(TLMM_GPIO_HSIC_STROBE_PAD_CTL); writel_relaxed(reg & 0xfdffffff, TLMM_GPIO_HSIC_STROBE_PAD_CTL); /* disable DATA_PAD_CTL */ reg = readl_relaxed(TLMM_GPIO_HSIC_DATA_PAD_CTL); writel_relaxed(reg & 0xfdffffff, TLMM_GPIO_HSIC_DATA_PAD_CTL); mb(); device_remove_file(&pdev->dev, &dev_attr_config_imod); /* If the device was removed no need to call pm_runtime_disable */ if (pdev->dev.power.power_state.event != PM_EVENT_INVALID) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); usb_remove_hcd(xhci->shared_hcd); usb_put_hcd(xhci->shared_hcd); usb_remove_hcd(hcd); if (mxhci->wakeup_irq_enabled) disable_irq_wake(mxhci->wakeup_irq); mxhci->bus_vote = false; cancel_work_sync(&mxhci->bus_vote_w); if (mxhci->bus_perf_client) msm_bus_scale_unregister_client(mxhci->bus_perf_client); destroy_workqueue(mxhci->wq); device_init_wakeup(&pdev->dev, 0); mxhci_hsic_init_vddcx(mxhci, 0); mxhci_hsic_init_clocks(mxhci, 0); mxhci_msm_config_gdsc(mxhci, 0); wakeup_source_trash(&mxhci->ws); usb_put_hcd(hcd); return 0; }
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd) { struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); if (!(readl_relaxed(USB_PORTSC) & PORT_PE)) { dbg_log_event(NULL, "RH suspend attempt failed", 0); dev_dbg(mehci->dev, "%s:port is not enabled skip suspend\n", __func__); return -EAGAIN; } dbg_log_event(NULL, "Suspend RH", 0); return ehci_bus_suspend(hcd); }
static void dump_hsic_regs(struct usb_hcd *hcd) { int i; struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); if (atomic_read(&mehci->in_lpm)) return; for (i = USB_REG_START_OFFSET; i <= USB_REG_END_OFFSET; i += 0x10) pr_info("%p: %08x\t%08x\t%08x\t%08x\n", hcd->regs + i, readl_relaxed(hcd->regs + i), readl_relaxed(hcd->regs + i + 4), readl_relaxed(hcd->regs + i + 8), readl_relaxed(hcd->regs + i + 0xc)); }
static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate) { struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); int val; switch (linestate) { case PORT_RESET: val = ulpi_read(mehci, HSIC_DBG1); val |= ULPI_MANUAL_ENABLE; val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE); ulpi_write(mehci, val, HSIC_DBG1); break; default: pr_info("%s: Unknown linestate:%0x\n", __func__, linestate); } }
static int ehci_hsic_bus_resume(struct usb_hcd *hcd) { struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 temp; struct task_struct *resume_thread = NULL; mehci->resume_status = 0; resume_thread = kthread_run(msm_hsic_resume_thread, mehci, "hsic_resume_thread"); if (IS_ERR(resume_thread)) { pr_err("Error creating resume thread:%lu\n", PTR_ERR(resume_thread)); return PTR_ERR(resume_thread); } wait_for_completion(&mehci->rt_completion); if (mehci->resume_status < 0) return mehci->resume_status; dbg_log_event(NULL, "FPR: Wokeup", 0); spin_lock_irq(&ehci->lock); (void) ehci_readl(ehci, &ehci->regs->command); temp = 0; if (ehci->async->qh_next.qh) temp |= CMD_ASE; if (ehci->periodic_sched) temp |= CMD_PSE; if (temp) { ehci->command |= temp; ehci_writel(ehci, ehci->command, &ehci->regs->command); } ehci->next_statechange = jiffies + msecs_to_jiffies(5); hcd->state = HC_STATE_RUNNING; ehci->rh_state = EHCI_RH_RUNNING; /* Now we can safely re-enable irqs */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq(&ehci->lock); return 0; }
static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data; if (pdata && pdata->swfi_latency) pm_qos_remove_request(&mehci->pm_qos_req_dma); if (mehci->peripheral_status_irq) free_irq(mehci->peripheral_status_irq, mehci); if (mehci->wakeup_irq) { if (mehci->wakeup_irq_enabled) disable_irq_wake(mehci->wakeup_irq); free_irq(mehci->wakeup_irq, mehci); } /* * If the update request is called after unregister, the request will * fail. Results are undefined if unregister is called in the middle of * update request. */ mehci->bus_vote = false; cancel_work_sync(&mehci->bus_vote_w); if (mehci->bus_perf_client) msm_bus_scale_unregister_client(mehci->bus_perf_client); ehci_hsic_msm_debugfs_cleanup(); device_init_wakeup(&pdev->dev, 0); pm_runtime_set_suspended(&pdev->dev); destroy_workqueue(ehci_wq); usb_remove_hcd(hcd); msm_hsic_config_gpios(mehci, 0); msm_hsic_init_vddcx(mehci, 0); msm_hsic_init_clocks(mehci, 0); wake_lock_destroy(&mehci->wlock); iounmap(hcd->regs); usb_put_hcd(hcd); return 0; }
static int mxhci_hsic_pm_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(hcd); dev_dbg(dev, "xhci-msm PM suspend\n"); xhci_dbg_log_event(&dbg_hsic, NULL, "PM Suspend", 0); if (!mxhci->in_lpm) { dev_dbg(dev, "abort suspend\n"); return -EBUSY; } if (device_may_wakeup(dev)) enable_irq_wake(hcd->irq); return 0; }
static int mxhci_hsic_bus_suspend(struct usb_hcd *hcd) { struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(hcd->primary_hcd); int ret; /* don't miss connect bus state from peripheral for USB 2.0 root hub */ if (usb_hcd_is_primary_hcd(hcd) && !(readl_relaxed(MSM_HSIC_PORTSC) & PORT_PE)) { dev_err(mxhci->dev, "%s: port is not enabled; skip suspend\n", __func__); return -EAGAIN; } ret = xhci_bus_suspend(hcd); xhci_dbg_log_event(&dbg_hsic, NULL, "Suspend RH", ret); return ret; }
static int ehci_hsic_reset(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); int retval; mehci->timer = USB_HS_GPTIMER_BASE; ehci->caps = USB_CAPLENGTH; ehci->regs = USB_CAPLENGTH + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache the data to minimize the chip reads*/ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); hcd->has_tt = 1; ehci->sbrn = HCD_USB2; retval = ehci_halt(ehci); if (retval) return retval; /* data structure init */ retval = ehci_init(hcd); if (retval) return retval; retval = ehci_reset(ehci); if (retval) return retval; /* bursts of unspecified length. */ writel_relaxed(0, USB_AHBBURST); /* Use the AHB transactor */ writel_relaxed(0x08, USB_AHBMODE); /* Disable streaming mode and select host mode */ writel_relaxed(0x13, USB_USBMODE); ehci_port_power(ehci, 1); return 0; }
static int msm_hsic_pm_suspend(struct device *dev) { int ret; struct usb_hcd *hcd = dev_get_drvdata(dev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); dev_dbg(dev, "ehci-msm-hsic PM suspend\n"); dbg_log_event(NULL, "PM Suspend", 0); if (device_may_wakeup(dev)) enable_irq_wake(hcd->irq); ret = msm_hsic_suspend(mehci); if (ret && device_may_wakeup(dev)) disable_irq_wake(hcd->irq); return ret; }
static int msm_hsic_pm_resume(struct device *dev) { int ret; struct usb_hcd *hcd = dev_get_drvdata(dev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); dbg_log_event(NULL, "PM Resume", 0); if (device_may_wakeup(dev)) disable_irq_wake(hcd->irq); ret = msm_hsic_resume(mehci); if (ret) return ret; /* Bring the device to full powered state upon system resume */ pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; }
static ssize_t config_imod_show(struct device *pdev, struct device_attribute *attr, char *buff) { struct usb_hcd *hcd = dev_get_drvdata(pdev); struct xhci_hcd *xhci; struct mxhci_hsic_hcd *mxhci; u32 temp; unsigned long flags; mxhci = hcd_to_hsic(hcd); xhci = hcd_to_xhci(hcd); if (mxhci->in_lpm) return -EACCES; spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->ir_set->irq_control) & ER_IRQ_INTERVAL_MASK; spin_unlock_irqrestore(&xhci->lock, flags); return snprintf(buff, PAGE_SIZE, "%08x\n", temp); }
static int mxhci_hsic_pm_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct mxhci_hsic_hcd *mxhci = hcd_to_hsic(hcd); unsigned long flags; int ret; dev_dbg(dev, "xhci-msm PM resume\n"); xhci_dbg_log_event(&dbg_hsic, NULL, "PM Resume", 0); if (device_may_wakeup(dev)) disable_irq_wake(hcd->irq); /* * Keep HSIC in Low Power Mode if system is resumed * by any other wakeup source. HSIC is resumed later * when remote wakeup is received or interface driver * start I/O. */ spin_lock_irqsave(&mxhci->wakeup_lock, flags); if (!mxhci->pm_usage_cnt && pm_runtime_suspended(dev)) { spin_unlock_irqrestore(&mxhci->wakeup_lock, flags); return 0; } spin_unlock_irqrestore(&mxhci->wakeup_lock, flags); ret = mxhci_hsic_resume(mxhci); if (ret) return ret; /* Bring the device to full powered state upon system resume */ pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; }
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); u32 status; if (atomic_read(&mehci->in_lpm)) { disable_irq_nosync(hcd->irq); dev_dbg(mehci->dev, "phy async intr\n"); mehci->async_int = true; pm_runtime_get(mehci->dev); return IRQ_HANDLED; } status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_GPTIMER0_INTERRUPT) { int timeleft; dbg_log_event(NULL, "FPR: gpt0_isr", 0); timeleft = GPT_CNT(ehci_readl(ehci, &mehci->timer->gptimer1_ctrl)); if (timeleft) { ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) | CMD_RUN, &ehci->regs->command); } else mehci->resume_again = 1; dbg_log_event(NULL, "FPR: timeleft", timeleft); complete(&mehci->gpt0_completion); ehci_writel(ehci, STS_GPTIMER0_INTERRUPT, &ehci->regs->status); } return ehci_irq(hcd); }
static int __devexit ehci_hsic_msm_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data; if (pdata && pdata->swfi_latency) pm_qos_remove_request(&mehci->pm_qos_req_dma); if (mehci->peripheral_status_irq) free_irq(mehci->peripheral_status_irq, mehci); if (mehci->wakeup_irq) { if (mehci->wakeup_irq_enabled) disable_irq_wake(mehci->wakeup_irq); free_irq(mehci->wakeup_irq, mehci); } if (mehci->bus_perf_client) msm_bus_scale_unregister_client(mehci->bus_perf_client); ehci_hsic_msm_debugfs_cleanup(); device_init_wakeup(&pdev->dev, 0); pm_runtime_set_suspended(&pdev->dev); usb_remove_hcd(hcd); msm_hsic_config_gpios(mehci, 0); msm_hsic_init_vddcx(mehci, 0); msm_hsic_init_clocks(mehci, 0); wake_lock_destroy(&mehci->wlock); iounmap(hcd->regs); usb_put_hcd(hcd); 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 __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; }