/****************************************************************************** * IMX6 OTG set as slave device hacking * 声明: * 1. 本代码解析使用了倒序的方式跟踪内核驱动代码,从驱动反推需求; * 2. 代码解析的目标是找到OTG设置成Host、Slave设备的宏定义; * 3. 根据2中的宏定义,看make menuconfig中是否存在可直接裁剪的选项。 * * 2015-8-7 晴 深圳 南山平山村 曾剑锋 *****************************************************************************/ <kernel path>/drivers/usb/otg/fsl_otg.c static int __init fsl_usb_otg_init(void) <----------------------------+ { | printk(KERN_INFO DRIVER_DESC " loaded, %s ", DRIVER_VERSION); | return platform_driver_register(&fsl_otg_driver); | } | | | | static void __exit fsl_usb_otg_exit(void) +-------------+ | { | | platform_driver_unregister(&fsl_otg_driver); | | printk(KERN_INFO DRIVER_DESC " unloaded "); | | } | | | | subsys_initcall(fsl_usb_otg_init); --------------------|---------------+ module_exit(fsl_usb_otg_exit); | | MODULE_DESCRIPTION(DRIVER_INFO); | MODULE_AUTHOR(DRIVER_AUTHOR); | MODULE_LICENSE("GPL"); | | | struct platform_driver fsl_otg_driver = { <-------------+ .probe = fsl_otg_probe, .remove = fsl_otg_remove, .driver = { .name = driver_name, --------+ .owner = THIS_MODULE, | }, | }; | V static const char driver_name[] = "fsl-usb2-otg"; -------------+ | | <kernel path>/arch/arm$ grep fsl-usb2-otg * -R | Binary file boot/Image matches | mach-mx5/devices.c: .name = "fsl-usb2-otg", | ...... | Binary file plat-mxc/devices/built-in.o matches V plat-mxc/devices/platform-fsl-usb2-otg.c: const char *name = "fsl-usb2-otg"; Binary file plat-mxc/built-in.o matches | | | <kernel path>/arch/arm/plat-mxc/devices/platform-fsl-usb2-otg.c | #define imx_fsl_usb2_otg_data_entry_single(soc) | { | .iobase = soc ## _USB_OTG_BASE_ADDR, | .irq = soc ## _INT_USB_OTG, | } | | | #ifdef CONFIG_SOC_IMX6Q | const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst = | imx_fsl_usb2_otg_data_entry_single(MX6Q); | #endif /* ifdef CONFIG_SOC_IMX6Q */ | | struct platform_device *__init imx_add_fsl_usb2_otg( ----------+ | const struct imx_fsl_usb2_otg_data *data, | | const struct fsl_usb2_platform_data *pdata) | | { | | struct resource res[] = { | | { | | .start = data->iobase, | | .end = data->iobase + SZ_512 - 1, | | .flags = IORESOURCE_MEM, | | }, { | | .start = data->irq, | | .end = data->irq, | | .flags = IORESOURCE_IRQ, | | }, | | }; | | | | int ret = -ENOMEM; | | const char *name = "fsl-usb2-otg"; <-------------------------|---+ int id = -1; | unsigned int num_resources = ARRAY_SIZE(res); | size_t size_data = sizeof(*pdata); | u64 dmamask = DMA_BIT_MASK(32); | struct platform_device *pdev; | | pdev = platform_device_alloc(name, id); | if (!pdev) | goto err; | | if (dmamask) { | /* | * This memory isn't freed when the device is put, | * I don't have a nice idea for that though. Conceptually | * dma_mask in struct device should not be a pointer. | * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 | */ | pdev->dev.dma_mask = | kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); | if (!pdev->dev.dma_mask) | /* ret is still -ENOMEM; */ | goto err; | | *pdev->dev.dma_mask = dmamask; | pdev->dev.coherent_dma_mask = dmamask; | } | | ret = platform_device_add_resources(pdev, res, num_resources); | if (ret) | goto err; | | if (data) { | ret = platform_device_add_data(pdev, pdata, size_data); | if (ret) | goto err; | } | | return pdev; | err: | if (dmamask) | kfree(pdev->dev.dma_mask); | platform_device_put(pdev); | return ERR_PTR(ret); | } | EXPORT_SYMBOL(imx_add_fsl_usb2_otg); | | <kernel path>/arch/arm$ grep imx_add_fsl_usb2_otg * -R <-------------+ Binary file boot/Image matches mach-mx6/devices-imx6q.h: imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata) ----------+ ...... | plat-mxc/devices/platform-fsl-usb2-otg.c:struct platform_device *__init imx_add_fsl_usb2_otg( | plat-mxc/devices/platform-fsl-usb2-otg.c:EXPORT_SYMBOL(imx_add_fsl_usb2_otg); | Binary file plat-mxc/built-in.o matches | | <kernel path>/arch/arm/mach-mx6/devices-imx6q.h | extern const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst; | #define imx6q_add_fsl_usb2_otg(pdata) -------------------+ | imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata) <------------------*------+ | <kernel path>/arch/arm$ grep imx6q_add_fsl_usb2_otg * -R | Binary file mach-mx6/.usb_dr.c.swp matches | mach-mx6/devices-imx6q.h:#define imx6q_add_fsl_usb2_otg(pdata) | mach-mx6/devices-imx6q.h:#define imx6q_add_fsl_usb2_otg_wakeup(pdata) | mach-mx6/usb_dr.c: pdev[i] = imx6q_add_fsl_usb2_otg(&dr_utmi_config); | mach-mx6/usb_dr.c: pdev_wakeup = imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config); | | <kernel path>/arch/arm/mach-mx6/usb_dr.c | static int __init mx6_usb_dr_init(void) | { | int i = 0; | void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); | struct imx_fsl_usb2_wakeup_data imx6q_fsl_otg_wakeup_data = | imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 0, OTG); | struct imx_mxc_ehci_data __maybe_unused imx6q_mxc_ehci_otg_data = | imx_mxc_ehci_data_entry_single(MX6Q, 0, OTG); | struct imx_fsl_usb2_udc_data __maybe_unused imx6q_fsl_usb2_udc_data = | imx_fsl_usb2_udc_data_entry_single(MX6Q); | struct imx_fsl_usb2_otg_data __maybe_unused imx6q_fsl_usb2_otg_data = | imx_fsl_usb2_otg_data_entry_single(MX6Q); | | /* Some phy and power's special controls for otg | * 1. The external charger detector needs to be disabled | * or the signal at DP will be poor | * 2. The EN_USB_CLKS is always enabled. | * The PLL's power is controlled by usb and others who | * use pll3 too. | */ | __raw_writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B | | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B, | anatop_base_addr + HW_ANADIG_USB1_CHRG_DETECT); | __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, | anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET); | mx6_get_otghost_vbus_func(&mx6_set_usb_otg_vbus); | dr_utmi_config.platform_driver_vbus = mx6_set_usb_otg_vbus; | | #ifdef CONFIG_USB_OTG | /* wake_up_enable is useless, just for usb_register_remote_wakeup execution*/ | dr_utmi_config.wake_up_enable = _device_wakeup_enable; | dr_utmi_config.operating_mode = FSL_USB2_DR_OTG; | dr_utmi_config.wakeup_pdata = &dr_wakeup_config; | pdev[i] = imx6q_add_fsl_usb2_otg(&dr_utmi_config); <------------------------+ dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; i++; #endif #ifdef CONFIG_USB_EHCI_ARC_OTG -------------------------+ dr_utmi_config.operating_mode = DR_HOST_MODE; | dr_utmi_config.wake_up_enable = _host_wakeup_enable; | if (usb_icbug_swfix_need()) { | dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend_swfix; | dr_utmi_config.platform_rh_resume = _host_platform_rh_resume_swfix; | } else { | dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend; | dr_utmi_config.platform_rh_resume = _host_platform_rh_resume; | } | dr_utmi_config.platform_set_disconnect_det = fsl_platform_otg_set_usb_phy_dis; | dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend; | dr_utmi_config.is_wakeup_event = _is_host_wakeup; | dr_utmi_config.wakeup_pdata = &dr_wakeup_config; | dr_utmi_config.wakeup_handler = host_wakeup_handler; | dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; | pdev[i] = imx6q_add_fsl_ehci_otg(&dr_utmi_config); | dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; | i++; | #endif | #ifdef CONFIG_USB_GADGET_ARC | dr_utmi_config.operating_mode = DR_UDC_MODE; | dr_utmi_config.wake_up_enable = _device_wakeup_enable; | dr_utmi_config.platform_rh_suspend = NULL; | dr_utmi_config.platform_rh_resume = NULL; | dr_utmi_config.platform_set_disconnect_det = NULL; | dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend; | dr_utmi_config.is_wakeup_event = _is_device_wakeup; | dr_utmi_config.wakeup_pdata = &dr_wakeup_config; | dr_utmi_config.wakeup_handler = device_wakeup_handler; | dr_utmi_config.charger_base_addr = anatop_base_addr; | dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; | pdev[i] = imx6q_add_fsl_usb2_udc(&dr_utmi_config); | dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; | i++; | #endif | devnum = i; | /* register wakeup device */ | pdev_wakeup = imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config); | for (i = 0; i < devnum; i++) { | platform_device_add(pdev[i]); | ((struct fsl_usb2_platform_data *)(pdev[i]->dev.platform_data))->wakeup_pdata = | (struct fsl_usb2_wakeup_platform_data *)(pdev_wakeup->dev.platform_data); | } | | return 0; | } | module_init(mx6_usb_dr_init); | | <kernel path>$ make menuconfig | | Symbol: USB_EHCI_ARC_OTG [=n] <--------------------------------*--------------------+ │ Type : boolean | │ Prompt: Support for DR host port on Freescale controller | │ Defined at drivers/usb/host/Kconfig:80 | │ Depends on: USB_SUPPORT [=y] && USB_EHCI_ARC [=y] | │ Location: | │ -> Device Drivers | │ -> USB support (USB_SUPPORT [=y]) | │ -> Support for Freescale controller (USB_EHCI_ARC [=y]) |