static void mv_otg_update_inputs(struct mv_otg *mvotg) { struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; u32 otgsc; otgsc = readl(&mvotg->op_regs->otgsc); if (mvotg->pdata->extern_attr & MV_USB_HAS_VBUS_DETECTION) { unsigned int vbus; pxa_usb_extern_call(mvotg->pdata->id, vbus, get_vbus, &vbus); if (vbus == VBUS_HIGH) { otg_ctrl->b_sess_vld = 1; otg_ctrl->b_sess_end = 0; } else { otg_ctrl->b_sess_vld = 0; otg_ctrl->b_sess_end = 1; } } else { otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); } if (mvotg->pdata->extern_attr & MV_USB_HAS_IDPIN_DETECTION) { unsigned int id; pxa_usb_extern_call(mvotg->pdata->id, idpin, get_idpin, &id); otg_ctrl->id = !!id; } else { otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); } if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) otg_ctrl->a_bus_req = 1; if (otg_force_host_mode) { otg_ctrl->id = 0; otg_ctrl->a_bus_req = 1; } otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); }
static int mv_ehci_remove(struct platform_device *pdev) { struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); struct usb_hcd *hcd = ehci_mv->hcd; if (hcd->rh_registered) usb_remove_hcd(hcd); if (!IS_ERR_OR_NULL(ehci_mv->otg)) otg_set_host(ehci_mv->otg->otg, NULL); if (ehci_mv->mode == MV_USB_MODE_HOST) { pxa_usb_extern_call(ehci_mv->pdata->id, vbus, set_vbus, 0); mv_ehci_disable(ehci_mv); clk_unprepare(ehci_mv->clk); } usb_put_hcd(hcd); return 0; }
static int mv_ehci_probe(struct platform_device *pdev) { struct mv_usb_platform_data *pdata; struct device *dev = &pdev->dev; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct ehci_hcd_mv *ehci_mv; struct resource *r; int retval = -ENODEV; u32 offset; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(&pdev->dev, "failed to allocate memory for platform_data\n"); return -ENODEV; } mv_ehci_dt_parse(pdev, pdata); /* * Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; if (!dev->coherent_dma_mask) dev->coherent_dma_mask = DMA_BIT_MASK(32); if (usb_disabled()) return -ENODEV; hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); if (!hcd) return -ENOMEM; ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); if (ehci_mv == NULL) { dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); retval = -ENOMEM; goto err_put_hcd; } platform_set_drvdata(pdev, ehci_mv); ehci_mv->pdata = pdata; ehci_mv->hcd = hcd; ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ehci_mv->clk)) { dev_err(&pdev->dev, "error getting clock\n"); retval = PTR_ERR(ehci_mv->clk); goto err_clear_drvdata; } clk_prepare(ehci_mv->clk); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { dev_err(&pdev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; goto err_clear_drvdata; } ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (ehci_mv->cap_regs == NULL) { dev_err(&pdev->dev, "failed to map I/O memory\n"); retval = -EFAULT; goto err_clear_drvdata; } ehci_mv->phy = devm_usb_get_phy_dev(&pdev->dev, MV_USB2_PHY_INDEX); if (IS_ERR_OR_NULL(ehci_mv->phy)) { retval = PTR_ERR(ehci_mv->phy); if (retval != -EPROBE_DEFER && retval != -ENODEV) dev_err(&pdev->dev, "failed to get the outer phy\n"); else { kfree(hcd->bandwidth_mutex); kfree(hcd); return -EPROBE_DEFER; } goto err_clear_drvdata; } retval = mv_ehci_enable(ehci_mv); if (retval) { dev_err(&pdev->dev, "init phy error %d\n", retval); goto err_clear_drvdata; } offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; ehci_mv->op_regs = (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); hcd->rsrc_start = r->start; hcd->rsrc_len = resource_size(r); hcd->regs = ehci_mv->op_regs; hcd->irq = platform_get_irq(pdev, 0); if (!hcd->irq) { dev_err(&pdev->dev, "Cannot get irq."); retval = -ENODEV; goto err_disable_clk; } ehci = hcd_to_ehci(hcd); ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; ehci_mv->mode = pdata->mode; if (ehci_mv->mode == MV_USB_MODE_OTG) { ehci_mv->otg = devm_usb_get_phy_dev(&pdev->dev, MV_USB2_OTG_PHY_INDEX); if (IS_ERR(ehci_mv->otg)) { retval = PTR_ERR(ehci_mv->otg); if (retval == -ENXIO) dev_info(&pdev->dev, "MV_USB_MODE_OTG " "must have CONFIG_USB_PHY enabled\n"); else if (retval != -EPROBE_DEFER) dev_err(&pdev->dev, "unable to find transceiver\n"); goto err_disable_clk; } retval = otg_set_host(ehci_mv->otg->otg, &hcd->self); if (retval < 0) { dev_err(&pdev->dev, "unable to register with transceiver\n"); retval = -ENODEV; goto err_disable_clk; } /* otg will enable clock before use as host */ mv_ehci_disable(ehci_mv); } else { pxa_usb_extern_call(pdata->id, vbus, set_vbus, 1); retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); if (retval) { dev_err(&pdev->dev, "failed to add hcd with err %d\n", retval); goto err_set_vbus; } } dev_info(&pdev->dev, "successful find EHCI device with regs 0x%p irq %d" " working in %s mode\n", hcd->regs, hcd->irq, ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); return 0; err_set_vbus: pxa_usb_extern_call(pdata->id, vbus, set_vbus, 0); err_disable_clk: mv_ehci_disable(ehci_mv); err_clear_drvdata: platform_set_drvdata(pdev, NULL); err_put_hcd: usb_put_hcd(hcd); return retval; }
static int mv_otg_probe(struct platform_device *pdev) { struct mv_usb_platform_data *pdata = pdev->dev.platform_data; struct mv_otg *mvotg; struct usb_otg *otg; struct resource *r; int retval = 0, i; struct device_node *np = pdev->dev.of_node; const __be32 *prop; unsigned int proplen; if (pdata == NULL) { dev_err(&pdev->dev, "failed to get platform data\n"); return -ENODEV; } mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); if (!mvotg) { dev_err(&pdev->dev, "failed to allocate memory!\n"); return -ENOMEM; } otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); if (!otg) return -ENOMEM; platform_set_drvdata(pdev, mvotg); mvotg->pdev = pdev; mvotg->pdata = pdata; mvotg->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(mvotg->clk)) return PTR_ERR(mvotg->clk); clk_prepare(mvotg->clk); mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); if (!mvotg->qwork) { dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); return -ENOMEM; } INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); /* OTG common part */ mvotg->pdev = pdev; mvotg->phy.dev = &pdev->dev; mvotg->phy.type = USB_PHY_TYPE_USB2; mvotg->phy.otg = otg; mvotg->phy.label = driver_name; mvotg->phy.state = OTG_STATE_UNDEFINED; otg->phy = &mvotg->phy; otg->set_host = mv_otg_set_host; otg->set_peripheral = mv_otg_set_peripheral; otg->set_vbus = mv_otg_set_vbus; mv_otg_phy_bind_device(mvotg); for (i = 0; i < OTG_TIMER_NUM; i++) init_timer(&mvotg->otg_ctrl.timer[i]); r = platform_get_resource(mvotg->pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "no I/O memory resource defined\n"); retval = -ENODEV; goto err_destroy_workqueue; } mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (mvotg->cap_regs == NULL) { dev_err(&pdev->dev, "failed to map I/O memory\n"); retval = -EFAULT; goto err_destroy_workqueue; } mvotg->outer_phy = devm_usb_get_phy_dev(&pdev->dev, MV_USB2_PHY_INDEX); if (IS_ERR_OR_NULL(mvotg->outer_phy)) { retval = PTR_ERR(mvotg->outer_phy); if (retval != -EPROBE_DEFER) dev_err(&pdev->dev, "can not find outer phy\n"); goto err_destroy_workqueue; } /* we will acces controller register, so enable the udc controller */ retval = mv_otg_enable_internal(mvotg); if (retval) { dev_err(&pdev->dev, "mv otg enable error %d\n", retval); goto err_destroy_workqueue; } mvotg->op_regs = (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); if (pdata->extern_attr & (MV_USB_HAS_VBUS_DETECTION | MV_USB_HAS_IDPIN_DETECTION)) { mvotg->notifier.notifier_call = mv_otg_notifier_callback; pxa_usb_register_notifier(mvotg->pdata->id, &mvotg->notifier); if (pdata->extern_attr & MV_USB_HAS_VBUS_DETECTION) { mvotg->clock_gating = 1; pxa_usb_extern_call(mvotg->pdata->id, vbus, init); } if (pdata->extern_attr & MV_USB_HAS_IDPIN_DETECTION) pxa_usb_extern_call(mvotg->pdata->id, idpin, init); } if (pdata->disable_otg_clock_gating) mvotg->clock_gating = 0; mv_otg_reset(mvotg); mv_otg_init_irq(mvotg); r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); if (r == NULL) { dev_err(&pdev->dev, "no IRQ resource defined\n"); retval = -ENODEV; goto err_disable_clk; } mvotg->irq = r->start; if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED, driver_name, mvotg)) { dev_err(&pdev->dev, "Request irq %d for OTG failed\n", mvotg->irq); mvotg->irq = 0; retval = -ENODEV; goto err_disable_clk; } retval = usb_add_phy_dev(&mvotg->phy); if (retval < 0) { dev_err(&pdev->dev, "can't register transceiver, %d\n", retval); goto err_disable_clk; } prop = of_get_property(np, "lpm-qos", &proplen); if (!prop) { pr_err("lpm-qos config in DT for mv_otg is not defined\n"); goto err_disable_clk; } else mvotg->lpm_qos = be32_to_cpup(prop); mvotg->qos_idle.name = mvotg->pdev->name; pm_qos_add_request(&mvotg->qos_idle, PM_QOS_CPUIDLE_BLOCK, PM_QOS_CPUIDLE_BLOCK_DEFAULT_VALUE); retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); if (retval < 0) { dev_dbg(&pdev->dev, "Can't register sysfs attr group: %d\n", retval); goto err_remove_otg_phy; } spin_lock_init(&mvotg->wq_lock); if (spin_trylock(&mvotg->wq_lock)) { mv_otg_run_state_machine(mvotg, 2 * HZ); spin_unlock(&mvotg->wq_lock); } dev_info(&pdev->dev, "successful probe OTG device %s clock gating.\n", mvotg->clock_gating ? "with" : "without"); device_init_wakeup(&pdev->dev, 1); return 0; err_remove_otg_phy: usb_remove_phy(&mvotg->phy); pm_qos_remove_request(&mvotg->qos_idle); err_disable_clk: mv_otg_disable_internal(mvotg); if (pdata->extern_attr & (MV_USB_HAS_VBUS_DETECTION | MV_USB_HAS_IDPIN_DETECTION)) pxa_usb_unregister_notifier(mvotg->pdata->id, &mvotg->notifier); err_destroy_workqueue: flush_workqueue(mvotg->qwork); destroy_workqueue(mvotg->qwork); return retval; }
static int mv_otg_set_vbus(struct usb_otg *otg, bool on) { struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy); return pxa_usb_extern_call(mvotg->pdata->id, vbus, set_vbus, on); }