https://www.cnblogs.com/newjiang/p/15675746.html
如果dr_mode为device,则初始化gadget。
如果dr_mode为host,需要初始化xHCI驱动。在dwc3_host_init函数的最后调用platform_device_add(xhci)添加platform device(xhci-hcd),用于匹配xHCI driver(xHCI driver为platform driver),参照第3节。
如果dr_mode为otg,需要根据extcon来选定一个角色(host或者device)进行初始化,所以还需要extcon驱动的支持,参照第2节
https://blog.youkuaiyun.com/z1026544682/article/details/101023041?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-8-101023041-blog-124888836.235^v43^pc_blog_bottom_relevance_base6&spm=1001.2101.3001.4242.5&utm_relevant_index=11
对于设备树节点中的reg属性(地址),通过type=IORESOURCE_MEM来获得;
对于设备树节点中的interrupts属性(中断),通过type=IORESOURCE_IRQ来获得;
怎么获取转换为platform_device的设备树节点中的非标准属性,比如pin(pin=xxx)?
对于根节点"/ { };",会保存在一个全局变量of_root里面( device_node类型)。可以通过访问该全局变量(代表根节点),得到任意一个节点,得到节点后可以读出属性。
于是,可以使用内核提供的函数,直接访问device_node,从而读出这些属性。
这些函数可以分为3来:找到节点,找到属性,获取属性的值。这些函数位于内核源码include/linux/of.h。
/* Tertiary USB port related controller */
usb2: ssusb@a400000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xa400000 0x100000>;
reg-names = "core_base";
iommus = <&apps_smmu 0x0800 0x0>;
qcom,iommu-dma = "bypass";
#address-cells = <1>;
#size-cells = <1>;
ranges;
dma-ranges;
interrupts-extended = <&pdc 127 IRQ_TYPE_EDGE_RISING>,
<&pdc 126 IRQ_TYPE_EDGE_RISING>,
<&pdc 129 IRQ_TYPE_EDGE_RISING>,
<&pdc 128 IRQ_TYPE_EDGE_RISING>,
<&pdc 131 IRQ_TYPE_EDGE_RISING>,
<&pdc 130 IRQ_TYPE_EDGE_RISING>,
<&pdc 133 IRQ_TYPE_EDGE_RISING>,
<&pdc 132 IRQ_TYPE_EDGE_RISING>,
<&pdc 16 IRQ_TYPE_LEVEL_HIGH>,
<&pdc 17 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "dp_hs_phy_irq", "dm_hs_phy_irq",
"dp_hs_phy_irq1", "dm_hs_phy_irq1",
"dp_hs_phy_irq2", "dm_hs_phy_irq2",
"dp_hs_phy_irq3", "dm_hs_phy_irq3",
"ss_phy_irq", "ss_phy_irq1";
qcom,use-pdc-interrupts;
USB3_GDSC-supply = <&gcc_usb30_mp_gdsc>;
clocks = <&gcc GCC_USB30_MP_MASTER_CLK>,
<&gcc GCC_CFG_NOC_USB3_MP_AXI_CLK>,
<&gcc GCC_AGGRE_USB3_MP_AXI_CLK>,
<&gcc GCC_USB30_MP_MOCK_UTMI_CLK>,
<&gcc GCC_USB30_MP_SLEEP_CLK>,
<&gcc GCC_AGGRE_USB_NOC_AXI_CLK>,
<&gcc GCC_AGGRE_USB_NOC_NORTH_AXI_CLK>,
<&gcc GCC_AGGRE_USB_NOC_SOUTH_AXI_CLK>,
<&gcc GCC_SYS_NOC_USB_AXI_CLK>;
clock-names = "core_clk", "iface_clk", "bus_aggr_clk",
"utmi_clk", "sleep_clk", "noc_aggr_clk",
"noc_aggr_north_clk", "noc_aggr_south_clk",
"noc_sys_clk";
resets = <&gcc GCC_USB30_MP_BCR>;
reset-names = "core_reset";
qcom,core-clk-rate = <200000000>;
qcom,ignore-wakeup-src-in-hostmode;
status = "disabled";
dwc3@a400000 {
compatible = "snps,dwc3";
reg = <0xa400000 0xd93c>;
interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
usb-phy = <&usb2_phy2>, <&usb_qmp_phy0>,
<&usb2_phy3>, <&usb_qmp_phy1>,
<&usb2_phy4>, <&usb_nop_phy>,
<&usb2_phy5>, <&usb_nop_phy>;
linux,sysdev_is_parent;
snps,disable-clk-gating;
snps,has-lpm-erratum;
snps,hird-threshold = /bits/ 8 <0x0>;
snps,ssp-u3-u0-quirk;
snps,is-utmi-l1-suspend;
snps,dis_u3_susphy_quirk;
maximum-speed = "super-speed-plus";
dr_mode = "host";
};
dwc3_probe 匹配compatible = "snps,dwc3";
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 reg = <0xa400000 0xd93c>;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
dwc->reg_phys = res->start;//0xa400000
dwc->xhci_resources[0].start = res->start;//0xa400000
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 = 133
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;
//获取reg 虚拟地址
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);
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;
}
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);
pm_runtime_disable(&pdev->dev);
clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks);
assert_reset:
reset_control_assert(dwc->reset);
destroy_workqueue(dwc->dwc_wq);
err0:
return ret;
}
dwc3_core_init_mode
static int __maybe_unused 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[0])
otg_set_vbus(dwc->usb2_phy[0]->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;
}
dwc->vbus_active = true;
break;
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy[0])
otg_set_vbus(dwc->usb2_phy[0]->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;
}
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;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
return -EINVAL;
}
return 0;
}
dwc3_host_init
int dwc3_host_init(struct dwc3 *dwc)
{
struct property_entry props[6];
struct platform_device *xhci;
int ret, irq;
struct resource *res;
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int prop_idx = 0;
struct property_entry imod_prop;
//获取中断号133
irq = dwc3_host_get_irq(dwc);
if (irq < 0)
return irq;
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ, "host");
if (!res)
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
"dwc_usb3");
if (!res)
// //获取中断寄存器地址interrupts
res = platform_get_resource(dwc3_pdev, IORESOURCE_IRQ, 0);
if (!res)
return -ENOMEM;
dwc->xhci_resources[1].start = irq;
dwc->xhci_resources[1].end = irq;
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
//分配一个name=xhci-hcd platform_device结构提初始化
xhci = platform_device_alloc("xhc