/******************************************************************************
 *            I.MX6 make menuconfig OTG to slave only mode
 * 声明:
 *     本文通过跟踪代码的方式来了解如何将I.MX6的OTG的Host模式去掉,仅仅剩下
 * slave模式,主要是有些场合仅仅需要slave模式。
 *
 *                                      2015-9-5 晴 深圳 南山平山村 曾剑锋
 *****************************************************************************/




<kernel path>/drivers/usb/otg/fsl_otg.c

    static int __init fsl_usb_otg_init(void)       <----------------------------+
    {                                                                           |
        printk(KERN_INFO DRIVER_DESC " loaded, %s\n", 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\n");            |               |
    }                                                           |               |
                                                                |               |
    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                                    |
 +--------------------------------------------+                                |
                                              V                                |
<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                                                        |
 +----------------------------------+                                                              |
                                    V                                                              |
<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])    |