static ssize_t dwc3_mode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; struct dwc3 *dwc = s->private; unsigned long flags; u32 mode = 0; char buf[32]; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; if (!strncmp(buf, "host", 4)) mode |= DWC3_GCTL_PRTCAP_HOST; if (!strncmp(buf, "device", 6)) mode |= DWC3_GCTL_PRTCAP_DEVICE; if (!strncmp(buf, "otg", 3)) mode |= DWC3_GCTL_PRTCAP_OTG; if (mode) { spin_lock_irqsave(&dwc->lock, flags); dwc3_set_mode(dwc, mode); spin_unlock_irqrestore(&dwc->lock, flags); } return count; }
/** * dwc3_otg_start_peripheral - bind/unbind the peripheral controller. * * @otg: Pointer to the otg_transceiver structure. * @gadget: pointer to the usb_gadget structure. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; if (!otg->gadget) return -EINVAL; if (on) { dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n", __func__, otg->gadget->name); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); usb_phy_notify_connect(dotg->dwc->usb3_phy, USB_SPEED_SUPER); /* Core reset is not required during start peripheral. Only * DBM reset is required, hence perform only DBM reset here */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, false); dwc3_set_mode(dotg->dwc, DWC3_GCTL_PRTCAP_DEVICE); usb_gadget_vbus_connect(otg->gadget); } else { dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n", __func__, otg->gadget->name); usb_gadget_vbus_disconnect(otg->gadget); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); usb_phy_notify_disconnect(dotg->dwc->usb3_phy, USB_SPEED_SUPER); dwc3_gadget_usb3_phy_suspend(dotg->dwc, false); } return 0; }
static int ipq_xhci_core_init(struct ipq_xhci *ipq, unsigned int ipq_base) { int ret = 0; /* Configure the usb core clock */ usb_ss_core_clock_config(0, gboard_param->usb_core_mnd_value.m_value, gboard_param->usb_core_mnd_value.n_value, gboard_param->usb_core_mnd_value.d_value, gboard_param->clk_dummy); /* Configure the usb core clock */ usb_ss_utmi_clock_config(0, gboard_param->usb_utmi_mnd_value.m_value, gboard_param->usb_utmi_mnd_value.n_value, gboard_param->usb_utmi_mnd_value.d_value, gboard_param->clk_dummy); usb30_common_pre_init(0, ipq_base); uw_ssusb_pre_init(ipq_base); ret = dwc3_core_init(ipq->dwc3_reg); if (ret) { debug("%s:failed to initialize core\n", __func__); return ret; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(ipq->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); return ret; }
static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci) { int ret = 0; ret = dwc3_core_init(fsl_xhci->dwc3_reg); if (ret) { debug("%s:failed to initialize core\n", __func__); return ret; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); /* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */ dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT); /* Change beat burst and outstanding pipelined transfers requests */ fsl_xhci_set_beat_burst_length(fsl_xhci->dwc3_reg); /* * A-010151: The dwc3 phy TSMC 28-nm HPM 0.9/1.8 V does not * reliably support Rx Detect in P3 mode(P3 is the default * setting). Therefore, some USB3.0 devices may not be detected * reliably in Super Speed mode. So, USB controller to configure * USB in P2 mode whenever the Receive Detect feature is required. * whenever the Receive Detect feature is required. */ if (has_erratum_a010151()) clrsetbits_le32(&fsl_xhci->dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_DISRXDETP3, DWC3_GUSB3PIPECTL_DISRXDETP3); return ret; }
static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, false); phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize gadget\n"); return ret; } break; case USB_DR_MODE_HOST: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); if (dwc->usb2_phy) otg_set_vbus(dwc->usb2_phy->otg, true); phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST); phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize host\n"); return ret; } phy_calibrate(dwc->usb2_generic_phy); break; case USB_DR_MODE_OTG: INIT_WORK(&dwc->drd_work, __dwc3_set_mode); ret = dwc3_drd_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to initialize dual-role\n"); return ret; } #if IS_ENABLED(CONFIG_USB_DWC3_OTG) dwc->current_dr_role = 0; dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); #endif break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } return 0; }
static int dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); return ret; } break; case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; } break; case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); return ret; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); return -EINVAL; } return 0; }
static void dwc3_otg_set_host_mode(struct dwc3_otg *dotg) { struct dwc3 *dwc = dotg->dwc; u32 reg; if (dotg->regs) { reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg &= ~DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); } else { dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); } }
static void dwc3_otg_set_peripheral_mode(struct dwc3_otg *dotg) { struct dwc3 *dwc = dotg->dwc; u32 reg; if (dotg->regs) { reg = dwc3_readl(dotg->regs, DWC3_OCTL); reg |= DWC3_OTG_OCTL_PERIMODE; dwc3_writel(dotg->regs, DWC3_OCTL, reg); } else { dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); } }
static int amlogic_xhci_core_init(struct amlogic_xhci *amlogic) { int ret; ret = dwc3_core_init(amlogic->dwc3_reg); if (ret) { debug("failed to initialize core\n"); return -EINVAL; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(amlogic->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); return 0; }
static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci) { int ret = 0; ret = dwc3_core_init(zynqmp_xhci->dwc3_reg); if (ret) { debug("%s:failed to initialize core\n", __func__); return ret; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(zynqmp_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); return ret; }
static int exynos_xhci_core_init(struct exynos_xhci *exynos) { int ret; exynos5_usb3_phy_init(exynos->usb3_phy); ret = dwc3_core_init(exynos->dwc3_reg); if (ret) { debug("failed to initialize core\n"); return -EINVAL; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); return 0; }
static int omap_xhci_core_init(struct omap_xhci *omap) { int ret = 0; omap_enable_phy(omap); ret = dwc3_core_init(omap->dwc3_reg); if (ret) { debug("%s:failed to initialize core\n", __func__); return ret; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); return ret; }
static int fsl_xhci_core_init(struct fsl_xhci *fsl_xhci) { int ret = 0; ret = dwc3_core_init(fsl_xhci->dwc3_reg); if (ret) { debug("%s:failed to initialize core\n", __func__); return ret; } /* We are hard-coding DWC3 core to Host Mode */ dwc3_set_mode(fsl_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); /* Set GFLADJ_30MHZ as 20h as per XHCI spec default value */ dwc3_set_fladj(fsl_xhci->dwc3_reg, GFLADJ_30MHZ_DEFAULT); return ret; }
static ssize_t dwc3_mode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; struct dwc3 *dwc = s->private; u32 mode = 0; char buf[32]; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; if (!strncmp(buf, "host", 4)) mode = DWC3_GCTL_PRTCAP_HOST; if (!strncmp(buf, "device", 6)) mode = DWC3_GCTL_PRTCAP_DEVICE; if (!strncmp(buf, "otg", 3)) mode = DWC3_GCTL_PRTCAP_OTG; dwc3_set_mode(dwc, mode); return count; }
int __devinit dwc3_probe(struct platform_device *pdev) { struct dwc3 *dwc; #if !defined(CONFIG_DRA7XX) u8 vali; #endif int ret = -ENOMEM; void __iomem *regs; void *mem; u8 mode; /* Initialize all the clocks (system clocks/ optional clocks etc) */ /* USB_OTG_SS_CLKSTCTRL */ writel(USB_OTG_SS_OPTFCLKEN_REFCLK960M | USB_OTG_SS_MODULEMODE_HW, CM_L3INIT_USB_OTG_SS_CLKCTRL); /* OCP2SCP1 register for PHY register access */ writel(OCP2SCP1_MODULEMODE_HW, CM_L3INIT_OCP2SCP1_CLKCTRL); /* Turn on 32K AON clk */ writel(USB_PHY_CORE_OPTFCLKEN_CLK32K, CM_COREAON_USB_PHY_CORE_CLKCTRL); /* Setting CM_L3INIT_CLKSTCTRL to NO sleep */ writel(L3INIT_CLKSTCTRL_NOSLEEP, CM_L3INIT_CLKSTCTRL); /* Setting USBOTGSS_SYSCONFIG to NO idle */ writel((SYSCONFIG_DMADISABLE | SYSCONFIG_STANDBY_SMART | SYSCONFIG_IDLEMODE), USBOTGSS_SYSCONFIG); /* Initialize the wrapper registers */ dwc3_wrapper_init(); mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(&pdev->dev, "not enough memory\n"); goto err0; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; global_dwc3 = dwc; dwc->regs = CONFIG_USB_DWC3_UDC_REGS; dwc->regs_size = DWC3_USB_REGS_SIZE; dwc->dev = &pdev->dev; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; else if (!strncmp("full", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; else if (!strncmp("low", maximum_speed, 3)) dwc->maximum_speed = DWC3_DCFG_LOWSPEED; else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); pm_runtime_forbid(&pdev->dev); dwc3_cache_hwparams(dwc); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(&pdev->dev, "failed to initialize core\n"); goto err3; } omap_usb2_suspend(0); omap_usb3_suspend(0); ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err0; } mode = DWC3_MODE_DEVICE /*DWC3_MODE(dwc->hwparams.hwparams0)*/; switch (mode) { case DWC3_MODE_DEVICE: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize gadget\n"); goto err4; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); goto err4; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize host\n"); goto err4; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(&pdev->dev, "failed to initialize gadget\n"); goto err4; } break; default: dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode); goto err4; } dwc->mode = mode; #if !defined(CONFIG_DRA7XX) /* Enable the VBUS comparator in the palmas chip */ palmas_i2c_read_u8(0x49, 0x1C, &vali); palmas_i2c_write_u8(0x49, 0x53, 0x1); /* Wait for the vbus line state interrupt */ do { palmas_i2c_read_u8(0x49, 0x1C, &vali); } while (!(vali & 0x80)); #endif return 0; err4: dwc3_core_exit(dwc); err3: iounmap(regs); kfree(dwc->mem); err0: return ret; }
static int dwc3_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; struct device *dev = &pdev->dev; int ret = -ENOMEM; void __iomem *regs; void *mem; u8 mode; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); return -ENOMEM; } regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); /* * if -ENXIO is returned, it means PHY layer wasn't * enabled, so it makes no sense to return -EPROBE_DEFER * in that case, since no PHY driver will ever probe. */ if (ret == -ENXIO) return ret; dev_err(dev, "no usb2 phy configured\n"); return -EPROBE_DEFER; } if (IS_ERR(dwc->usb3_phy)) { ret = PTR_ERR(dwc->usb3_phy); /* * if -ENXIO is returned, it means PHY layer wasn't * enabled, so it makes no sense to return -EPROBE_DEFER * in that case, since no PHY driver will ever probe. */ if (ret == -ENXIO) return ret; dev_err(dev, "no usb3 phy configured\n"); return -EPROBE_DEFER; } usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; else if (!strncmp("full", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; else if (!strncmp("low", maximum_speed, 3)) dwc->maximum_speed = DWC3_DCFG_LOWSPEED; else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); dwc3_cache_hwparams(dwc); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err0; } ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err0; } ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err1; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) mode = DWC3_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) mode = DWC3_MODE_DEVICE; else mode = DWC3_MODE_DRD; switch (mode) { case DWC3_MODE_DEVICE: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err2; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err2; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err2; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err2; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); goto err2; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err3; } pm_runtime_allow(dev); return 0; err3: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; case DWC3_MODE_HOST: dwc3_host_exit(dwc); break; case DWC3_MODE_DRD: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; default: /* do nothing */ break; } err2: dwc3_event_buffers_cleanup(dwc); err1: dwc3_core_exit(dwc); err0: dwc3_free_event_buffers(dwc); return ret; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; struct usb_hcd *hcd; int ret = 0; if (!dwc->xhci) return -EINVAL; if (!dotg->vbus_otg) { dotg->vbus_otg = devm_regulator_get(dwc->dev->parent, "vbus_dwc3"); if (IS_ERR(dotg->vbus_otg)) { dev_err(dwc->dev, "Failed to get vbus regulator\n"); ret = PTR_ERR(dotg->vbus_otg); dotg->vbus_otg = 0; return ret; } } if (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); ret = regulator_enable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to enable vbus_otg\n"); dwc3_otg_notify_host_mode(otg, 0); return ret; } dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* * WORKAROUND: currently host mode suspend isn't working well. * Disable xHCI's runtime PM for now. */ pm_runtime_disable(&dwc->xhci->dev); hcd = platform_get_drvdata(dwc->xhci); otg->host = &hcd->self; dwc3_gadget_usb3_phy_suspend(dwc, true); } else { dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__); ret = regulator_disable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to disable vbus_otg\n"); return ret; } dbg_event(0xFF, "StHost get", 0); pm_runtime_get(dwc->dev); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); dwc3_otg_notify_host_mode(otg, on); otg->host = NULL; platform_device_del(dwc->xhci); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); dbg_event(0xFF, "StHost put", 0); pm_runtime_put(dwc->dev); } return 0; }
static int __devinit dwc3_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; struct device *dev = &pdev->dev; int ret = -ENOMEM; void __iomem *regs; void *mem; u8 mode; bool host_only_mode; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; if (!dev->dma_mask) dev->dma_mask = &dwc3_dma_mask; if (!dev->coherent_dma_mask) dev->coherent_dma_mask = DMA_BIT_MASK(64); dwc->notify_event = notify_event; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); return -ENOMEM; } regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; else if (!strncmp("full", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; else if (!strncmp("low", maximum_speed, 3)) dwc->maximum_speed = DWC3_DCFG_LOWSPEED; else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); host_only_mode = of_property_read_bool(node, "host-only-mode"); dwc->no_set_vbus_power = of_property_read_bool(node, "no-set-vbus-power"); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); return ret; } mode = DWC3_MODE(dwc->hwparams.hwparams0); /* Override mode if user selects host-only config with DRD core */ if (host_only_mode && (mode == DWC3_MODE_DRD)) { dev_dbg(dev, "host only mode selected\n"); mode = DWC3_MODE_HOST; } switch (mode) { case DWC3_MODE_DEVICE: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err1; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err1; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_otg_init(dwc); if (ret) { dev_err(dev, "failed to initialize otg\n"); goto err1; } ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); dwc3_otg_exit(dwc); goto err1; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); goto err1; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); goto err1; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err2; } dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_INITIALIZATION_EVENT); return 0; err2: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; case DWC3_MODE_HOST: dwc3_host_exit(dwc); break; case DWC3_MODE_DRD: dwc3_gadget_exit(dwc); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); break; default: /* do nothing */ break; } err1: dwc3_core_exit(dwc); return ret; }
static int __devinit dwc3_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; struct device *dev = &pdev->dev; int ret = -ENOMEM; void __iomem *regs; void *mem; u8 mode; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1] = *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0] = *res; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); return -ENOMEM; } regs = devm_ioremap(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; else if (!strncmp("full", maximum_speed, 4)) dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; else if (!strncmp("low", maximum_speed, 3)) dwc->maximum_speed = DWC3_DCFG_LOWSPEED; else dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; if (of_get_property(node, "tx-fifo-resize", NULL)) dwc->needs_fifo_resize = true; pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); return ret; } mode = DWC3_MODE(dwc->hwparams.hwparams0); switch (mode) { case DWC3_MODE_DEVICE: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err1; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err1; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_otg_init(dwc); if (ret) { dev_err(dev, "failed to initialize otg\n"); goto err1; } ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); dwc3_otg_exit(dwc); goto err1; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); goto err1; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); goto err1; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err2; } return 0; err2: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; case DWC3_MODE_HOST: dwc3_host_exit(dwc); break; case DWC3_MODE_DRD: dwc3_gadget_exit(dwc); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); break; default: /* do nothing */ break; } err1: dwc3_core_exit(dwc); return ret; }
static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dwc3_platform_data *pdata = dev_get_platdata(dev); struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; int ret = -ENOMEM; void __iomem *regs; void *mem; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } if (node) { dwc->maximum_speed = of_usb_get_maximum_speed(node); dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); dwc->dr_mode = of_usb_get_dr_mode(node); } else if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->dr_mode = pdata->dr_mode; } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } /* default to superspeed if no maximum_speed passed */ if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); if (ret == -ENXIO || ret == -ENODEV) { dwc->usb2_phy = NULL; } else if (ret == -EPROBE_DEFER) { return ret; } else { dev_err(dev, "no usb2 phy configured\n"); return ret; } } if (IS_ERR(dwc->usb3_phy)) { ret = PTR_ERR(dwc->usb3_phy); if (ret == -ENXIO || ret == -ENODEV) { dwc->usb3_phy = NULL; } else if (ret == -EPROBE_DEFER) { return ret; } else { dev_err(dev, "no usb3 phy configured\n"); return ret; } } dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); if (ret == -ENOSYS || ret == -ENODEV) { dwc->usb2_generic_phy = NULL; } else if (ret == -EPROBE_DEFER) { return ret; } else { dev_err(dev, "no usb2 phy configured\n"); return ret; } } dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); if (IS_ERR(dwc->usb3_generic_phy)) { ret = PTR_ERR(dwc->usb3_generic_phy); if (ret == -ENOSYS || ret == -ENODEV) { dwc->usb3_generic_phy = NULL; } else if (ret == -EPROBE_DEFER) { return ret; } else { dev_err(dev, "no usb3 phy configured\n"); return ret; } } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; res->start += DWC3_GLOBALS_REGS_START; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); dwc3_cache_hwparams(dwc); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err0; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) dwc->dr_mode = USB_DR_MODE_PERIPHERAL; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) dwc->dr_mode = USB_DR_MODE_OTG; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err0; } usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err1; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err_usb2phy_power; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err_usb3phy_power; } switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err2; } break; case USB_DR_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err2; } break; case USB_DR_MODE_OTG: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err2; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err2; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); goto err2; } ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err3; } pm_runtime_allow(dev); return 0; err3: switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_gadget_exit(dwc); break; case USB_DR_MODE_HOST: dwc3_host_exit(dwc); break; case USB_DR_MODE_OTG: dwc3_host_exit(dwc); dwc3_gadget_exit(dwc); break; default: /* do nothing */ break; } err2: dwc3_event_buffers_cleanup(dwc); err_usb3phy_power: phy_power_off(dwc->usb3_generic_phy); err_usb2phy_power: phy_power_off(dwc->usb2_generic_phy); err1: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_core_exit(dwc); err0: dwc3_free_event_buffers(dwc); return ret; }
static int dwc3_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct resource *res; struct dwc3 *dwc; struct device *dev = &pdev->dev; int ret = -ENOMEM; void __iomem *regs; void *mem; u8 mode; bool host_only_mode; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) { dev_err(dev, "not enough memory\n"); return -ENOMEM; } dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; dwc->notify_event = notify_event; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); return -ENOMEM; } regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } dwc->core_reset_after_phy_init = of_property_read_bool(node, "core_reset_after_phy_init"); dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); host_only_mode = of_property_read_bool(node, "host-only-mode"); dwc->maximum_speed = of_usb_get_maximum_speed(node); if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } /* default to superspeed if no maximum_speed passed */ if (dwc->maximum_speed == USB_SPEED_UNKNOWN) dwc->maximum_speed = USB_SPEED_SUPER; if (IS_ERR(dwc->usb2_phy)) { ret = PTR_ERR(dwc->usb2_phy); /* * if -ENXIO is returned, it means PHY layer wasn't * enabled, so it makes no sense to return -EPROBE_DEFER * in that case, since no PHY driver will ever probe. */ if (ret == -ENXIO) return ret; dev_err(dev, "no usb2 phy configured\n"); return -EPROBE_DEFER; } if (IS_ERR(dwc->usb3_phy)) { ret = PTR_ERR(dwc->usb2_phy); /* * if -ENXIO is returned, it means PHY layer wasn't * enabled, so it makes no sense to return -EPROBE_DEFER * in that case, since no PHY driver will ever probe. */ if (ret == -ENXIO) return ret; dev_err(dev, "no usb3 phy configured\n"); return -EPROBE_DEFER; } usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); dwc3_cache_hwparams(dwc); if (!dwc->ev_buffs) { ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err0; } } dwc->nominal_elastic_buffer = of_property_read_bool(node, "nominal-elastic-buffer"); ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err0; } ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err1; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) mode = DWC3_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) mode = DWC3_MODE_DEVICE; else mode = DWC3_MODE_DRD; /* Override mode if user selects host-only config with DRD core */ if (host_only_mode && (mode == DWC3_MODE_DRD)) { dev_dbg(dev, "host only mode selected\n"); mode = DWC3_MODE_HOST; } switch (mode) { case DWC3_MODE_DEVICE: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); goto err2; } break; case DWC3_MODE_HOST: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); goto err2; } break; case DWC3_MODE_DRD: dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_otg_init(dwc); if (ret) { dev_err(dev, "failed to initialize otg\n"); goto err1; } ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); dwc3_otg_exit(dwc); goto err1; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); goto err2; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); goto err2; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err3; } dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_INITIALIZATION_EVENT); return 0; err3: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); break; case DWC3_MODE_HOST: dwc3_host_exit(dwc); break; case DWC3_MODE_DRD: dwc3_gadget_exit(dwc); dwc3_host_exit(dwc); dwc3_otg_exit(dwc); break; default: /* do nothing */ break; } err2: dwc3_event_buffers_cleanup(dwc); err1: dwc3_core_exit(dwc); err0: dwc3_free_event_buffers(dwc); return ret; }
/** * dwc3_otg_start_host - helper function for starting/stoping the host controller driver. * * @otg: Pointer to the otg_transceiver structure. * @on: start / stop the host controller driver. * * Returns 0 on success otherwise negative errno. */ static int dwc3_otg_start_host(struct usb_otg *otg, int on) { struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg); struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; struct dwc3 *dwc = dotg->dwc; struct usb_hcd *hcd; int ret = 0; if (!dwc->xhci) return -EINVAL; if (!dotg->vbus_otg) { dotg->vbus_otg = devm_regulator_get(dwc->dev->parent, "vbus_dwc3"); if (IS_ERR(dotg->vbus_otg)) { dev_err(dwc->dev, "Failed to get vbus regulator\n"); ret = PTR_ERR(dotg->vbus_otg); dotg->vbus_otg = 0; return ret; } } if (on) { dev_dbg(otg->phy->dev, "%s: turn on host\n", __func__); dwc3_otg_notify_host_mode(otg, on); usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); /* register ocp notification */ if (ext_xceiv && ext_xceiv->ext_ocp_notification.notify) { ret = regulator_register_ocp_notification( dotg->vbus_otg, &ext_xceiv->ext_ocp_notification); if (ret) dev_err(otg->phy->dev, "unable to register ocp\n"); } ret = regulator_enable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to enable vbus_otg\n"); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* The delay between enabling regulator and adding the platform device is needed to succeed in the enumeration for certain devices. */ usleep(10000); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is * enabled for xhci device. Due to this, disable_depth becomes * greater than one and runtimepm is not enabled for next microA * connect. Fix this by calling pm_runtime_init for xhci device. */ pm_runtime_init(&dwc->xhci->dev); ret = platform_device_add(dwc->xhci); if (ret) { dev_err(otg->phy->dev, "%s: failed to add XHCI pdev ret=%d\n", __func__, ret); regulator_disable(dotg->vbus_otg); dwc3_otg_notify_host_mode(otg, 0); return ret; } /* * WORKAROUND: avoids entering a suspend state, because PMIC * is damaged by known issue when attempt to suspend. */ wake_lock(&dotg->host_wakelock); /* * WORKAROUND: currently host mode suspend isn't working well. * Disable xHCI's runtime PM for now. */ pm_runtime_disable(&dwc->xhci->dev); if (no_device_timeout_enable) { dotg->no_device_timeout_enabled = 1; dotg->device_count = 0; dotg->retry_count = 0; dotg->usbdev_nb.notifier_call = dwc3_usbdev_notify; usb_register_notify(&dotg->usbdev_nb); dwc3_otg_start_no_device_work(dotg, true); } hcd = platform_get_drvdata(dwc->xhci); otg->host = &hcd->self; dwc3_gadget_usb3_phy_suspend(dwc, true); } else { dev_dbg(otg->phy->dev, "%s: turn off host\n", __func__); ret = regulator_disable(dotg->vbus_otg); if (ret) { dev_err(otg->phy->dev, "unable to disable vbus_otg\n"); return ret; } dbg_event(0xFF, "StHost get", 0); /* unregister ocp notification */ if (ext_xceiv && ext_xceiv->ext_ocp_notification.notify) { ret = regulator_register_ocp_notification( dotg->vbus_otg, NULL); if (ret) dev_err(otg->phy->dev, "unable to unregister ocp\n"); } pm_runtime_get(dwc->dev); usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH); dwc3_otg_notify_host_mode(otg, on); otg->host = NULL; if (dotg->no_device_timeout_enabled) { dotg->no_device_timeout_enabled = 0; dwc3_otg_start_no_device_work(dotg, false); usb_unregister_notify(&dotg->usbdev_nb); } platform_device_del(dwc->xhci); /* WORKAROUND: delays execution of the block-reset because it * causes HWWD if ext_xceive access the HW during block reset. */ usleep(10000); if (wake_lock_active(&dotg->host_wakelock)) wake_unlock(&dotg->host_wakelock); /* * Perform USB hardware RESET (both core reset and DBM reset) * when moving from host to peripheral. This is required for * peripheral mode to work. */ if (ext_xceiv && ext_xceiv->ext_block_reset) ext_xceiv->ext_block_reset(ext_xceiv, true); dwc3_gadget_usb3_phy_suspend(dwc, false); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); /* re-init core and OTG registers as block reset clears these */ dwc3_post_host_reset_core_init(dwc); dbg_event(0xFF, "StHost put", 0); pm_runtime_put(dwc->dev); } return 0; }