static int exynos_xhci_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_xhci_hcd *exynos_xhci; struct usb_hcd *hcd; struct xhci_hcd *xhci; int retval = 0; dev_dbg(dev, "%s\n", __func__); exynos_xhci = dev_get_drvdata(dev); if (!exynos_xhci) return -EINVAL; hcd = exynos_xhci->hcd; if (!hcd) return -EINVAL; if (dev->power.is_suspended) { dev_dbg(dev, "xhci is system suspended\n"); return 0; } /* Userspace may try to access host when DRD is in B-Dev mode */ if (exynos_drd_try_get(pdev)) { dev_dbg(dev, "%s: cannot get DRD\n", __func__); return -EAGAIN; } pm_runtime_get_sync(exynos_xhci->dev->parent); /* * Parent device (DRD core) resumes before its child (xHCI). * Since we "get" DRD when it's already active, we need to * reconfigure PHY here, so PHY tuning took effect. */ if (exynos_xhci->core->ops->phy_set) exynos_xhci->core->ops->phy_set(exynos_xhci->core); if (exynos_xhci->core->ops->change_mode) exynos_xhci->core->ops->change_mode(exynos_xhci->core, true); if (exynos_xhci->core->ops->core_init) exynos_xhci->core->ops->core_init(exynos_xhci->core); xhci = hcd_to_xhci(hcd); retval = xhci_resume(xhci, 0); if (retval < 0) dev_err(dev, "%s: cannot start xHC\n", __func__); /* * In xhci_resume(), config values(AHB bus and los_bias) are intialized. * So after called xhci_resume(), set the config values again. */ if (exynos_xhci->core->ops->config) exynos_xhci->core->ops->config(exynos_xhci->core); return retval; }
static int exynos_xhci_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_xhci_hcd *exynos_xhci; struct usb_hcd *hcd; struct xhci_hcd *xhci; int retval = 0; #ifdef CONFIG_PM_RUNTIME dev_dbg(dev, "%s: usage_count = %d\n", __func__, atomic_read(&dev->power.usage_count)); #endif exynos_xhci = dev_get_drvdata(dev); if (!exynos_xhci) return -EINVAL; hcd = exynos_xhci->hcd; if (!hcd) return -EINVAL; if (exynos_drd_try_get(pdev)) { dev_err(dev, "%s: cannot get DRD\n", __func__); return -EAGAIN; } /* Wake up and initialize DRD core */ pm_runtime_get_sync(dev->parent); if (exynos_xhci->core->ops->change_mode) exynos_xhci->core->ops->change_mode(exynos_xhci->core, true); if (exynos_xhci->core->ops->core_init) exynos_xhci->core->ops->core_init(exynos_xhci->core); xhci = hcd_to_xhci(hcd); retval = xhci_resume(xhci, 0); if (retval < 0) dev_err(dev, "%s: cannot start xHC\n", __func__); /* * In xhci_resume(), config values(AHB bus and los_bias) are intialized. * So after called xhci_resume(), set the config values again. */ if (exynos_xhci->core->ops->config) exynos_xhci->core->ops->config(exynos_xhci->core); /* Update runtime PM status and clear runtime_error */ pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); return retval; }
static int __devinit exynos_xhci_probe(struct platform_device *pdev) { struct dwc3_exynos_data *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; const struct hc_driver *driver = &exynos_xhci_hc_driver; struct exynos_xhci_hcd *exynos_xhci; struct usb_hcd *hcd; struct xhci_hcd *xhci; struct resource *res; int irq; int err; if (usb_disabled()) return -ENODEV; if (!pdata) { dev_err(dev, "No platform data defined\n"); return -ENODEV; } exynos_xhci = devm_kzalloc(dev, sizeof(struct exynos_xhci_hcd), GFP_KERNEL); if (!exynos_xhci) { dev_err(dev, "Not enough memory\n"); return -ENOMEM; } exynos_xhci->dev = dev; exynos_xhci->pdata = pdata; exynos_xhci->core = exynos_drd_bind(pdev); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "Failed to get IRQ\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "Failed to get I/O memory\n"); return -ENXIO; } /* Create and add primary HCD */ hcd = usb_create_hcd(driver, dev, dev_name(dev)); if (!hcd) { dev_err(dev, "Failed to create primary HCD\n"); return -ENOMEM; } exynos_xhci->hcd = hcd; /* Rewrite driver data with our structure */ platform_set_drvdata(pdev, exynos_xhci); hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); if (!devm_request_mem_region(dev, res->start, resource_size(res), dev_name(dev))) { dev_err(dev, "Failed to reserve registers\n"); err = -ENOENT; goto put_hcd; } hcd->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!hcd->regs) { dev_err(dev, "Failed to remap I/O memory\n"); err = -ENOMEM; goto put_hcd; } hcd->regs -= EXYNOS_USB3_XHCI_REG_START; err = exynos_drd_try_get(pdev); if (err) { /* REVISIT: what shall we do if UDC is already running */ dev_err(dev, "Failed to access DRD\n"); goto put_hcd; } /* Wake up and initialize DRD core */ pm_runtime_get_sync(dev->parent); if (exynos_xhci->core->ops->change_mode) exynos_xhci->core->ops->change_mode(exynos_xhci->core, true); if (exynos_xhci->core->ops->core_init) exynos_xhci->core->ops->core_init(exynos_xhci->core); err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { dev_err(dev, "Failed to add primary HCD\n"); goto put_hcd; } /* Create and add shared HCD */ xhci = hcd_to_xhci(hcd); exynos_xhci_dbg = xhci; xhci->shared_hcd = usb_create_shared_hcd(driver, dev, dev_name(dev), hcd); if (!xhci->shared_hcd) { dev_err(dev, "Failed to create shared HCD\n"); err = -ENOMEM; goto remove_hcd; } xhci->shared_hcd->regs = hcd->regs; /* * Set the xHCI pointer before exynos_xhci_setup() * (aka hcd_driver.reset) is called by usb_add_hcd(). */ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; err = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (err) { dev_err(dev, "Failed to add shared HCD\n"); goto put_usb3_hcd; } pm_runtime_set_active(dev); pm_runtime_enable(dev); if (exynos_xhci->core->otg) { err = otg_set_host(exynos_xhci->core->otg, &hcd->self); if (err) { dev_err(dev, "Unable to bind hcd to DRD switch\n"); goto remove_usb3_hcd; } } return 0; remove_usb3_hcd: pm_runtime_disable(dev); usb_remove_hcd(xhci->shared_hcd); put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); remove_hcd: usb_remove_hcd(hcd); put_hcd: usb_put_hcd(hcd); return err; }