dwc3_probe
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res, dwc_res;
struct dwc3 *dwc;
int ret;
void __iomem *regs;
int irq;
char dma_ipc_log_ctx_name[40];
if (count >= DWC_CTRL_COUNT) {
dev_err(dev, "Err dwc instance %d >= %d available\n",
count, DWC_CTRL_COUNT);
ret = -EINVAL;
return ret;
}
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
if (!dwc)
return -ENOMEM;
dwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
dwc->reg_phys = res->start;
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;
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3",
dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
return -ENODEV;
}
if (notify_event)
/* will be enabled in dwc3_msm_resume() */
disable_irq(irq);
dwc->irq = irq;
/*
* Request memory region but exclude xHCI regs,
* since it will be requested by the xhci-plat driver.
*/
dwc_res = *res;
dwc_res.start += DWC3_GLOBALS_REGS_START;
regs = devm_ioremap_resource(dev, &dwc_res);
if (IS_ERR(regs))
return PTR_ERR(regs);
dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
if (!dwc->dwc_wq) {
dev_err(dev,
"%s: Unable to create workqueue dwc_wq\n", __func__);
goto err0;
}
INIT_WORK(&dwc->bh_work, dwc3_bh_work);
dwc->regs = regs;
dwc->regs_size = resource_size(&dwc_res);
dwc3_get_properties(dwc);
dwc->reset = devm_reset_control_array_get(dev, true, true);
if (IS_ERR(dwc->reset))
return PTR_ERR(dwc->reset);
if (dev->of_node) {
ret = devm_clk_bulk_get_all(dev, &dwc->clks);
if (ret == -EPROBE_DEFER)
goto err0;
/*
* Clocks are optional, but new DT platforms should support all
* clocks as required by the DT-binding.
*/
if (ret < 0)
dwc->num_clks = 0;
else
dwc->num_clks = ret;
}
ret = dwc3_extract_num_phys(dwc);
if (ret) {
dev_err(dwc->dev, "Unable to extract number of PHYs\n");
goto err0;
}
dwc->usb2_phy = devm_kzalloc(dwc->dev,
sizeof(*dwc->usb2_phy) * dwc->num_hsphy, GFP_KERNEL);
dwc->usb3_phy = devm_kzalloc(dwc->dev,
sizeof(*dwc->usb3_phy) * dwc->num_ssphy, GFP_KERNEL);
ret = reset_control_deassert(dwc->reset);
if (ret)
goto err0;
ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks);
if (ret)
goto assert_reset;
platform_set_drvdata(pdev, dwc);
init_waitqueue_head(&dwc->wait_linkstate);
spin_lock_init(&dwc->lock);
pm_runtime_no_callbacks(dev);
pm_runtime_set_active(dev);
if (dwc->enable_bus_suspend) {
pm_runtime_set_autosuspend_delay(dev,
DWC3_DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
}
pm_runtime_enable(dev);
pm_runtime_forbid(dev);
//分配event buf的dma地址
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 err1;
}
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err2;
dwc3_debugfs_init(dwc);
if (!notify_event) {
ret = dwc3_core_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize core: %d\n",
ret);
goto err3;
}
//将event buf 的dma 物理地址写入寄存器
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err3;
}
ret = dwc3_core_init_mode(dwc);
if (ret) {
dwc3_event_buffers_cleanup(dwc);
goto err3;
}
} else if (dwc->dr_mode == USB_DR_MODE_OTG ||
dwc->dr_mode == USB_DR_MODE_PERIPHERAL) {
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dwc->dev, "gadget init failed %d\n", ret);
goto err3;
}
}
dwc->dwc_ipc_log_ctxt = ipc_log_context_create(NUM_LOG_PAGES,
dev_name(dwc->dev), 0);
if (!dwc->dwc_ipc_log_ctxt)
dev_dbg(dwc->dev, "ipc_log_ctxt is not available\n");
snprintf(dma_ipc_log_ctx_name, sizeof(dma_ipc_log_ctx_name),
"%s.ep_events", dev_name(dwc->dev));
dwc->dwc_dma_ipc_log_ctxt = ipc_log_context_create(2 * NUM_LOG_PAGES,
dma_ipc_log_ctx_name, 0);
if (!dwc->dwc_dma_ipc_log_ctxt)
dev_dbg(dwc->dev, "ipc_log_ctxt for ep_events is not available\n");
dwc3_instance[count] = dwc;
dwc->index = count;
count++;
pm_runtime_allow(dev);
return 0;
err3:
dwc3_debugfs_exit(dwc);
dwc3_free_scratch_buffers(dwc);
err2:
dwc3_free_event_buffers(dwc);
err1:
pm_runtime_allow(&pdev->dev);