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; }
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_resume_common(struct dwc3 *dwc, pm_message_t msg) { unsigned long flags; int ret; u32 reg; /* Bring core to D0 state */ dwc3_set_usb_core_power(dwc, true); ret = dwc3_core_init(dwc); if (ret) return ret; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_DEVICE: ret = dwc3_core_init_for_resume(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); spin_unlock_irqrestore(&dwc->lock, flags); break; case DWC3_GCTL_PRTCAP_HOST: if (!PMSG_IS_AUTO(msg)) { ret = dwc3_core_init_for_resume(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); break; } /* Restore GUSB2PHYCFG bits that were modified in suspend */ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); if (dwc->dis_u2_susphy_quirk) reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); phy_pm_runtime_get_sync(dwc->usb2_generic_phy); phy_pm_runtime_get_sync(dwc->usb3_generic_phy); break; case DWC3_GCTL_PRTCAP_OTG: /* nothing to do on runtime_resume */ if (PMSG_IS_AUTO(msg)) break; ret = dwc3_core_init(dwc); if (ret) return ret; dwc3_set_prtcap(dwc, dwc->current_dr_role); dwc3_otg_init(dwc); if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) { dwc3_otg_host_init(dwc); } else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { spin_lock_irqsave(&dwc->lock, flags); dwc3_gadget_resume(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } break; default: /* do nothing */ break; } 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 void __dwc3_set_mode(struct work_struct *work) { struct dwc3 *dwc = work_to_dwc(work); unsigned long flags; int ret; if (dwc->dr_mode != USB_DR_MODE_OTG) return; if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) dwc3_otg_update(dwc, 0); if (!dwc->desired_dr_role) return; if (dwc->desired_dr_role == dwc->current_dr_role) return; if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) return; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_HOST: dwc3_host_exit(dwc); break; case DWC3_GCTL_PRTCAP_DEVICE: dwc3_gadget_exit(dwc); dwc3_event_buffers_cleanup(dwc); break; case DWC3_GCTL_PRTCAP_OTG: dwc3_otg_exit(dwc); spin_lock_irqsave(&dwc->lock, flags); dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; spin_unlock_irqrestore(&dwc->lock, flags); dwc3_otg_update(dwc, 1); break; default: break; } spin_lock_irqsave(&dwc->lock, flags); dwc3_set_prtcap(dwc, dwc->desired_dr_role); spin_unlock_irqrestore(&dwc->lock, flags); switch (dwc->desired_dr_role) { case DWC3_GCTL_PRTCAP_HOST: ret = dwc3_host_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize host\n"); } else { 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); phy_calibrate(dwc->usb2_generic_phy); } break; case DWC3_GCTL_PRTCAP_DEVICE: dwc3_event_buffers_setup(dwc); 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) dev_err(dwc->dev, "failed to initialize peripheral\n"); break; case DWC3_GCTL_PRTCAP_OTG: dwc3_otg_init(dwc); dwc3_otg_update(dwc, 0); break; default: break; } }