USB: support usb otg and host20 functions
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / usbdev_rk30.c
old mode 100755 (executable)
new mode 100644 (file)
index d7c21d0..cb4da87
-#include <linux/kernel.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/delay.h>\r
-#include <linux/dma-mapping.h>\r
-#include <linux/clk.h>\r
-\r
-#include <mach/irqs.h>\r
-#include <mach/gpio.h>\r
-#include <mach/iomux.h>\r
-#include <mach/cru.h>\r
-\r
-#include "usbdev_rk.h"\r
-#include "dwc_otg_regs.h" \r
-\r
-#if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK3188)\r
-\r
-#define GRF_REG_BASE   RK30_GRF_BASE   \r
-#define USBOTG_SIZE    RK30_USBOTG20_SIZE\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-#define USBGRF_SOC_STATUS0     (GRF_REG_BASE+0xac)\r
-#define USBGRF_UOC0_CON0       (GRF_REG_BASE+0x10c)\r
-#define USBGRF_UOC0_CON2       (GRF_REG_BASE+0x114)\r
-#define USBGRF_UOC0_CON3       (GRF_REG_BASE+0x118)\r
-#define USBGRF_UOC1_CON0       (GRF_REG_BASE+0x11C)\r
-#define USBGRF_UOC1_CON2       (GRF_REG_BASE+0x124)\r
-#define USBGRF_UOC1_CON3       (GRF_REG_BASE+0x128)\r
-#define USBGRF_UOC3_CON0       (GRF_REG_BASE+0x138)\r
-\r
-#define USBGRF_UOC2_CON0       (GRF_REG_BASE+0x12C)\r
-#if defined(CONFIG_SOC_RK3066B) || defined(CONFIG_SOC_RK3108) \r
-#define RK3066B_HOST_DRV_VBUS RK30_PIN0_PD7\r
-#define RK3066B_OTG_DRV_VBUS  RK30_PIN0_PD6\r
-#elif defined(CONFIG_SOC_RK3168) || defined(CONFIG_SOC_RK3188) || defined(CONFIG_SOC_RK3168M) || defined(CONFIG_SOC_RK3188M)\r
-#define RK3066B_HOST_DRV_VBUS RK30_PIN0_PC0\r
-#define RK3066B_OTG_DRV_VBUS  RK30_PIN3_PD5\r
-#elif defined(CONFIG_SOC_RK3028)\r
-#define RK3066B_HOST_DRV_VBUS RK30_PIN1_PA4\r
-#define RK3066B_OTG_DRV_VBUS  RK30_PIN3_PD7\r
-#endif\r
-\r
-#else\r
-#define USBGRF_SOC_STATUS0     (GRF_REG_BASE+0x15c)\r
-#define USBGRF_UOC0_CON2       (GRF_REG_BASE+0x184)\r
-#define USBGRF_UOC1_CON2       (GRF_REG_BASE+0x190)\r
-#endif\r
-\r
-int dwc_otg_check_dpdm(void)\r
-{\r
-       static uint8_t * reg_base = 0;\r
-    volatile unsigned int * otg_dctl;\r
-    volatile unsigned int * otg_gotgctl;\r
-    volatile unsigned int * otg_hprt0;\r
-    int bus_status = 0;\r
-    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
-    \r
-    // softreset & clockgate \r
-    *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5);    // otg0 phy clkgate\r
-    udelay(3);\r
-    *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5);    // otg0 phy clkgate\r
-    dsb();\r
-    *(unsigned int*)(RK30_CRU_BASE+0xd4) = ((1<<5)<<16);    // otg0 phy clkgate\r
-    *(unsigned int*)(RK30_CRU_BASE+0xe4) = ((1<<13)<<16);   // otg0 hclk clkgate\r
-    *(unsigned int*)(RK30_CRU_BASE+0xe0) = ((3<<5)<<16);    // hclk usb clkgate\r
-    \r
-    // exit phy suspend \r
-        *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-    \r
-    // soft connect\r
-    if(reg_base == 0){\r
-        reg_base = ioremap(RK30_USBOTG20_PHYS,USBOTG_SIZE);\r
-        if(!reg_base){\r
-            bus_status = -1;\r
-            goto out;\r
-        }\r
-    }\r
-    mdelay(105);\r
-    printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n",\r
-        reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1);\r
-    otg_dctl = (unsigned int * )(reg_base+0x804);\r
-    otg_gotgctl = (unsigned int * )(reg_base);\r
-    otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);\r
-    if(*otg_gotgctl &(1<<19)){\r
-        bus_status = 1;\r
-        *otg_dctl &= ~2;\r
-        mdelay(50);    // delay about 10ms\r
-    // check dp,dm\r
-        if((*otg_hprt0 & 0xc00)==0xc00)\r
-            bus_status = 2;\r
-    }\r
-out:\r
-    return bus_status;\r
-}\r
-\r
-EXPORT_SYMBOL(dwc_otg_check_dpdm);\r
-\r
-#ifdef CONFIG_USB20_OTG\r
-/*DWC_OTG*/\r
-static struct resource usb20_otg_resource[] = {\r
-       {\r
-               .start = IRQ_USB_OTG,\r
-               .end   = IRQ_USB_OTG,\r
-               .flags = IORESOURCE_IRQ,\r
-       },\r
-       {\r
-               .start = RK30_USBOTG20_PHYS,\r
-               .end   = RK30_USBOTG20_PHYS + RK30_USBOTG20_SIZE - 1,\r
-               .flags = IORESOURCE_MEM,\r
-       },\r
-\r
-};\r
-\r
-void usb20otg_hw_init(void)\r
-{\r
-#ifndef CONFIG_USB20_HOST\r
-        // close USB 2.0 HOST phy and clock\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-        unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC1_CON3);\r
-        *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16);     //enable soft control\r
-        *otg_phy_con2 =  0x2A|(0x3F<<16);               // enter suspend   \r
-#else\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-        *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
-#endif\r
-#endif\r
-        // usb phy config init\r
-#ifdef CONFIG_ARCH_RK3188\r
-        //usb phy enter usb mode\r
-        unsigned int * otg_phy_con3 = (unsigned int*)(USBGRF_UOC0_CON0);\r
-        *otg_phy_con3 = (0x0300 << 16);\r
-       //Disconnect Threshold Adjustment\r
-       *otg_phy_con3 = (0x07<<1)|((0x07<<1)<<16);      \r
-#endif    \r
-        // other haredware init\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-        //GPIO init\r
-        gpio_request(RK3066B_OTG_DRV_VBUS, NULL);\r
-        gpio_direction_output(RK3066B_OTG_DRV_VBUS, GPIO_LOW);\r
-#else\r
-        rk30_mux_api_set(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_OTG_DRV_VBUS);\r
-#endif\r
-}\r
-\r
-void usb20otg_phy_suspend(void* pdata, int suspend)\r
-{\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-        struct dwc_otg_platform_data *usbpdata=pdata;\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
-        unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC0_CON3);\r
-        if(suspend){\r
-            *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16); ;   //enable soft control\r
-            *otg_phy_con2 =  0x2A|(0x3F<<16);;              // enter suspend\r
-            usbpdata->phy_status = 1;\r
-        }\r
-        else{\r
-            *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-            usbpdata->phy_status = 0;\r
-        }\r
-#else\r
-        struct dwc_otg_platform_data *usbpdata=pdata;\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
-        if(suspend){\r
-            *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
-            usbpdata->phy_status = 1;\r
-        }\r
-        else{\r
-            *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-            usbpdata->phy_status = 0;\r
-        }\r
-#endif\r
-}\r
-void usb20otg_soft_reset(void)\r
-{\r
-    cru_set_soft_reset(SOFT_RST_USBOTG0, true);\r
-    cru_set_soft_reset(SOFT_RST_USBPHY0, true);\r
-    cru_set_soft_reset(SOFT_RST_OTGC0, true);\r
-    udelay(1);\r
-\r
-    cru_set_soft_reset(SOFT_RST_USBOTG0, false);\r
-    cru_set_soft_reset(SOFT_RST_USBPHY0, false);\r
-    cru_set_soft_reset(SOFT_RST_OTGC0, false);\r
-    mdelay(1);\r
-}\r
-void usb20otg_clock_init(void* pdata)\r
-{\r
-    struct dwc_otg_platform_data *usbpdata=pdata;\r
-    struct clk* ahbclk,*phyclk;\r
-    ahbclk = clk_get(NULL, "hclk_otg0");\r
-    phyclk = clk_get(NULL, "otgphy0");\r
-       usbpdata->phyclk = phyclk;\r
-       usbpdata->ahbclk = ahbclk;\r
-}\r
-void usb20otg_clock_enable(void* pdata, int enable)\r
-{\r
-    struct dwc_otg_platform_data *usbpdata=pdata;\r
-\r
-    if(enable){\r
-        clk_enable(usbpdata->ahbclk);\r
-        clk_enable(usbpdata->phyclk);\r
-    }\r
-    else{\r
-        clk_disable(usbpdata->phyclk);\r
-        clk_disable(usbpdata->ahbclk);\r
-    }\r
-}\r
-int usb20otg_get_status(int id)\r
-{\r
-        int ret = -1;\r
-        unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
-        switch(id)\r
-        {\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-            case USB_STATUS_BVABLID:\r
-                // bvalid in grf\r
-                ret = (usbgrf_status &(1<<10));\r
-                break;\r
-            case USB_STATUS_DPDM:\r
-                // dpdm in grf\r
-                ret = (usbgrf_status &(3<<11));\r
-                break;\r
-            case USB_STATUS_ID:\r
-                // id in grf\r
-                ret = (usbgrf_status &(1<<13));\r
-                break;\r
-#else\r
-            case USB_STATUS_BVABLID:\r
-                // bvalid in grf\r
-                ret = (usbgrf_status &0x20000);\r
-                break;\r
-            case USB_STATUS_DPDM:\r
-                // dpdm in grf\r
-                ret = (usbgrf_status &(3<<18));\r
-                break;\r
-            case USB_STATUS_ID:\r
-                // id in grf\r
-                ret = (usbgrf_status &(1<<20));\r
-                break;\r
-#endif\r
-            default:\r
-                break;\r
-        }\r
-        return ret;\r
-}\r
-\r
-#ifdef CONFIG_RK_USB_UART\r
-void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)\r
-{\r
-       unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON0);\r
-             \r
-       if(1 == enter_usb_uart_mode){  //enter uart mode\r
-               /*note: can't disable otg here! If otg disable, the ID change\r
-               *interrupt can't be triggered when otg cable connect without\r
-               *device.At the same time, uart can't be used normally \r
-               */\r
-               //*otg_phy_con1 = (0x10 | (0x10 << 16));//otg disable\r
-               *otg_phy_con1 = (0x0300 | (0x0300 << 16));//bypass dm       \r
-       }\r
-       if(0 == enter_usb_uart_mode){  //enter usb mode \r
-               *otg_phy_con1 = (0x0300 << 16); //bypass dm disable\r
-               //*otg_phy_con1 = (0x10 << 16);//otg enable             \r
-       }\r
-}\r
-#endif\r
-\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-void usb20otg_power_enable(int enable)\r
-{ \r
-    unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
-    if(0 == enable)//disable\r
-    {\r
-        gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_LOW); \r
-\r
-    }\r
-    if(1 == enable)//enable\r
-    {\r
-        gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_HIGH); \r
-    }   \r
-}\r
-#endif\r
-struct dwc_otg_platform_data usb20otg_pdata = {\r
-    .phyclk = NULL,\r
-    .ahbclk = NULL,\r
-    .busclk = NULL,\r
-    .phy_status = 0,\r
-    .hw_init=usb20otg_hw_init,\r
-    .phy_suspend=usb20otg_phy_suspend,\r
-    .soft_reset=usb20otg_soft_reset,\r
-    .clock_init=usb20otg_clock_init,\r
-    .clock_enable=usb20otg_clock_enable,\r
-    .get_status=usb20otg_get_status,\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-    .power_enable=usb20otg_power_enable,\r
-#endif\r
-#ifdef CONFIG_RK_USB_UART\r
-    .dwc_otg_uart_mode=dwc_otg_uart_mode,\r
-#endif\r
-};\r
-\r
-struct platform_device device_usb20_otg = {\r
-       .name             = "usb20_otg",\r
-       .id               = -1,\r
-       .num_resources    = ARRAY_SIZE(usb20_otg_resource),\r
-       .resource         = usb20_otg_resource,\r
-       .dev            = {\r
-               .platform_data  = &usb20otg_pdata,\r
-       },\r
-};\r
-#endif\r
-#ifdef CONFIG_USB20_HOST\r
-static struct resource usb20_host_resource[] = {\r
-    {\r
-        .start = IRQ_USB_HOST,\r
-        .end   = IRQ_USB_HOST,\r
-        .flags = IORESOURCE_IRQ,\r
-    },\r
-    {\r
-        .start = RK30_USBHOST20_PHYS,\r
-        .end   = RK30_USBHOST20_PHYS + RK30_USBHOST20_SIZE - 1,\r
-        .flags = IORESOURCE_MEM,\r
-    },\r
-\r
-};\r
-void usb20host_hw_init(void)\r
-{\r
-    // usb phy config init\r
-#ifdef CONFIG_ARCH_RK3188\r
-    //Disconnect Threshold Adjustment\r
-    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON0);\r
-    *otg_phy_con1 = (0x07<<1)|((0x07<<1)<<16);\r
-#endif    \r
-\r
-    // other haredware init\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-    gpio_request(RK3066B_HOST_DRV_VBUS, NULL);\r
-    gpio_direction_output(RK3066B_HOST_DRV_VBUS, GPIO_HIGH);\r
-#else\r
-    rk30_mux_api_set(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A_HOST_DRV_VBUS);\r
-#endif\r
-}\r
-void usb20host_phy_suspend(void* pdata, int suspend)\r
-{ \r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-        struct dwc_otg_platform_data *usbpdata=pdata;\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-        unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC1_CON3);\r
-        if(suspend)\r
-        {\r
-            *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16); ;   //enable soft control\r
-            *otg_phy_con2 =  0x2A|(0x3F<<16);;                     // enter suspend\r
-            usbpdata->phy_status = 1;\r
-        }\r
-        else\r
-        {\r
-            *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-            usbpdata->phy_status = 0;\r
-        }   \r
-#else\r
-        struct dwc_otg_platform_data *usbpdata=pdata;\r
-        unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-        if(suspend)\r
-        {\r
-            *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
-            usbpdata->phy_status = 1;\r
-        }\r
-        else\r
-        {\r
-            *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-            usbpdata->phy_status = 0;\r
-        }\r
-#endif \r
-}\r
-void usb20host_soft_reset(void)\r
-{\r
-    cru_set_soft_reset(SOFT_RST_USBOTG1, true);\r
-    cru_set_soft_reset(SOFT_RST_USBPHY1, true);\r
-    cru_set_soft_reset(SOFT_RST_OTGC1, true);\r
-    udelay(5);\r
-\r
-    cru_set_soft_reset(SOFT_RST_USBOTG1, false);\r
-    cru_set_soft_reset(SOFT_RST_USBPHY1, false);\r
-    cru_set_soft_reset(SOFT_RST_OTGC1, false);\r
-    mdelay(2);\r
-}\r
-void usb20host_clock_init(void* pdata)\r
-{\r
-    struct dwc_otg_platform_data *usbpdata=pdata;\r
-    struct clk* ahbclk,*phyclk;\r
-    ahbclk = clk_get(NULL, "hclk_otg1");\r
-    phyclk = clk_get(NULL, "otgphy1");\r
-       usbpdata->phyclk = phyclk;\r
-       usbpdata->ahbclk = ahbclk;\r
-}\r
-void usb20host_clock_enable(void* pdata, int enable)\r
-{\r
-    struct dwc_otg_platform_data *usbpdata=pdata;\r
-    \r
-    if(enable){\r
-        clk_enable(usbpdata->ahbclk);\r
-        clk_enable(usbpdata->phyclk);\r
-    }\r
-    else{\r
-        clk_disable(usbpdata->phyclk);\r
-        clk_disable(usbpdata->ahbclk);\r
-    }\r
-}\r
-int usb20host_get_status(int id)\r
-{\r
-    int ret = -1;\r
-    unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
-    switch(id)\r
-    {\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-        case USB_STATUS_BVABLID:\r
-            // bvalid in grf\r
-            ret = (usbgrf_status &(1<<17));\r
-            break;\r
-        case USB_STATUS_DPDM:\r
-            // dpdm in grf\r
-            ret = (usbgrf_status &(3<<18));\r
-            break;\r
-        case USB_STATUS_ID:\r
-            // id in grf\r
-            ret = (usbgrf_status &(1<<20));\r
-            break;\r
-#else\r
-        case USB_STATUS_BVABLID:\r
-            // bvalid in grf\r
-            ret = (usbgrf_status &(1<<22));\r
-            break;\r
-        case USB_STATUS_DPDM:\r
-            // dpdm in grf\r
-            ret = (usbgrf_status &(3<<23));\r
-            break;\r
-        case USB_STATUS_ID:\r
-            // id in grf\r
-            ret = 0;\r
-            break;\r
-#endif\r
-        default:\r
-            break;\r
-    }\r
-    return ret;\r
-}\r
-\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-void usb20host_power_enable(int enable)\r
-{ \r
-\r
-    if(0 == enable)//disable\r
-    {\r
-        //ret = gpio_request(RK3066B_HOST_DRV_VBUS, NULL);\r
-        //if (ret != 0) {\r
-        //    gpio_free(RK3066B_HOST_DRV_VBUS);\r
-        //}\r
-        //gpio_direction_output(RK3066B_HOST_DRV_VBUS, 1);\r
-        //gpio_set_value(RK3066B_HOST_DRV_VBUS, 0);\r
-        //printk("!!!!!!!!!!!!!!!!!!!disable host power!!!!!!!!!!!!!!!!!!\n");\r
-    }\r
-\r
-    if(1 == enable)//enable\r
-    {\r
-        gpio_set_value(RK3066B_HOST_DRV_VBUS, GPIO_HIGH);\r
-        //printk("!!!!!!!!!!!!!!!!!!!!!enable host power!!!!!!!!!!!!!!!!!!\n");\r
-    }   \r
-}\r
-#endif\r
-struct dwc_otg_platform_data usb20host_pdata = {\r
-    .phyclk = NULL,\r
-    .ahbclk = NULL,\r
-    .busclk = NULL,\r
-    .phy_status = 0,\r
-    .hw_init=usb20host_hw_init,\r
-    .phy_suspend=usb20host_phy_suspend,\r
-    .soft_reset=usb20host_soft_reset,\r
-    .clock_init=usb20host_clock_init,\r
-    .clock_enable=usb20host_clock_enable,\r
-    .get_status=usb20host_get_status,\r
-#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
-    .power_enable=usb20host_power_enable,\r
-#endif    \r
-};\r
-\r
-struct platform_device device_usb20_host = {\r
-    .name             = "usb20_host",\r
-    .id               = -1,\r
-    .num_resources    = ARRAY_SIZE(usb20_host_resource),\r
-    .resource         = usb20_host_resource,\r
-       .dev            = {\r
-               .platform_data  = &usb20host_pdata,\r
-       },\r
-};\r
-#endif\r
-#ifdef CONFIG_USB_EHCI_RK\r
-void rkehci_hw_init(void)\r
-{\r
-       unsigned int * phy_con0 = (unsigned int*)(USBGRF_UOC2_CON0);\r
-       unsigned int * phy_con1 = (unsigned int*)(USBGRF_UOC1_CON0);\r
-       unsigned int * phy_con2 = (unsigned int*)(USBGRF_UOC0_CON0);\r
-       unsigned int * phy_con3 = (unsigned int*)(USBGRF_UOC3_CON0);\r
-       // usb phy config init\r
-       // hsic phy config init, set hsicphy_txsrtune\r
-       *phy_con0 = ((0xf<<6)<<16)|(0xf<<6);\r
-\r
-       // other haredware init\r
-       // set common_on, in suspend mode, otg/host PLL blocks remain powered\r
-#ifdef CONFIG_ARCH_RK3188\r
-       *phy_con1 = (1<<16)|0;\r
-#else\r
-       *phy_con2 = (1<<16)|0;\r
-#endif\r
-       /* change INCR to INCR16 or INCR8(beats less than 16)\r
-        * or INCR4(beats less than 8) or SINGLE(beats less than 4)\r
-        */\r
-       *phy_con3 = 0x00ff00bc;\r
-}\r
-\r
-void rkehci_clock_init(void* pdata)\r
-{\r
-       struct rkehci_platform_data *usbpdata=pdata;\r
-\r
-#ifdef CONFIG_ARCH_RK3188  \r
-       struct clk *clk_otg, *clk_hs;\r
-\r
-       /* By default, hsicphy_480m's parent is otg phy 480MHz clk\r
-        * rk3188 must use host phy 480MHz clk\r
-        */\r
-       clk_hs = clk_get(NULL, "hsicphy_480m");\r
-       clk_otg = clk_get(NULL, "otgphy1_480m");\r
-       clk_set_parent(clk_hs, clk_otg);\r
-#endif\r
-\r
-       usbpdata->hclk_hsic = clk_get(NULL, "hclk_hsic");\r
-       usbpdata->hsic_phy_480m = clk_get(NULL, "hsicphy_480m");\r
-       usbpdata->hsic_phy_12m = clk_get(NULL, "hsicphy_12m");\r
-}\r
-\r
-void rkehci_clock_enable(void* pdata, int enable)\r
-{\r
-       struct rkehci_platform_data *usbpdata=pdata;\r
-\r
-       if(enable == usbpdata->clk_status)\r
-               return;\r
-\r
-       if(enable){\r
-               clk_enable(usbpdata->hclk_hsic);\r
-               clk_enable(usbpdata->hsic_phy_480m);\r
-               clk_enable(usbpdata->hsic_phy_12m);\r
-               usbpdata->clk_status = 1;\r
-       }else{\r
-               clk_disable(usbpdata->hsic_phy_12m);\r
-               clk_disable(usbpdata->hsic_phy_480m);\r
-               clk_disable(usbpdata->hclk_hsic);\r
-               usbpdata->clk_status = 0;\r
-       }\r
-}\r
-\r
-void rkehci_soft_reset(void)\r
-{\r
-       unsigned int * phy_con0 = (unsigned int*)(USBGRF_UOC2_CON0);\r
-\r
-       cru_set_soft_reset(SOFT_RST_HSICPHY, true);\r
-       udelay(12);\r
-       cru_set_soft_reset(SOFT_RST_HSICPHY, false);\r
-       mdelay(2);\r
-\r
-       *phy_con0 = ((1<<10)<<16)|(1<<10);\r
-       udelay(2);\r
-       *phy_con0 = ((1<<10)<<16)|(0<<10);\r
-       udelay(2);\r
-\r
-       cru_set_soft_reset(SOFT_RST_HSIC_AHB, true);\r
-       udelay(2);\r
-       cru_set_soft_reset(SOFT_RST_HSIC_AHB, false);\r
-       udelay(2);\r
-}\r
-\r
-struct rkehci_platform_data rkehci_pdata = {\r
-       .hclk_hsic = NULL,\r
-       .hsic_phy_12m = NULL,\r
-       .hsic_phy_480m = NULL,\r
-       .clk_status = -1,\r
-       .hw_init = rkehci_hw_init,\r
-       .clock_init = rkehci_clock_init,\r
-       .clock_enable = rkehci_clock_enable,\r
-       .soft_reset = rkehci_soft_reset,\r
-};\r
-\r
-static struct resource resources_hsusb_host[] = {\r
-    {\r
-        .start = IRQ_HSIC,\r
-        .end   = IRQ_HSIC,\r
-        .flags = IORESOURCE_IRQ,\r
-    },\r
-    {\r
-        .start = RK30_HSIC_PHYS,\r
-        .end   = RK30_HSIC_PHYS + RK30_HSIC_SIZE - 1,\r
-        .flags = IORESOURCE_MEM,\r
-    },\r
-};\r
-\r
-struct platform_device device_hsusb_host = {\r
-    .name           = "rk_hsusb_host",\r
-    .id             = -1,\r
-    .num_resources  = ARRAY_SIZE(resources_hsusb_host),\r
-    .resource       = resources_hsusb_host,\r
-    .dev            = {\r
-        .coherent_dma_mask      = 0xffffffff,\r
-        .platform_data  = &rkehci_pdata,\r
-    },\r
-};\r
-#endif\r
-\r
-static int __init usbdev_init_devices(void)\r
-{\r
-#ifdef CONFIG_USB_EHCI_RK\r
-       platform_device_register(&device_hsusb_host);\r
-#endif\r
-#ifdef CONFIG_USB20_OTG\r
-       platform_device_register(&device_usb20_otg);\r
-#endif\r
-#ifdef CONFIG_USB20_HOST\r
-       platform_device_register(&device_usb20_host);\r
-#endif\r
-    return 0;\r
-}\r
-arch_initcall(usbdev_init_devices);\r
-#endif\r
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include "usbdev_rk.h"
+#include "dwc_otg_regs.h"
+
+static struct dwc_otg_control_usb *control_usb;
+
+int dwc_otg_check_dpdm(void)
+{
+       int bus_status = 0;
+       return bus_status;
+}
+
+EXPORT_SYMBOL(dwc_otg_check_dpdm);
+
+#ifdef CONFIG_USB20_OTG
+
+void usb20otg_hw_init(void)
+{
+#ifndef CONFIG_USB20_HOST
+       unsigned int * otg_phy_con1 = (control_usb->grf_uoc1_base + 0x8);
+       unsigned int * otg_phy_con2 = (control_usb->grf_uoc1_base + 0xc);
+       *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16);     //enable soft control
+       *otg_phy_con2 = 0x2A|(0x3F<<16);               // enter suspend
+#endif
+       /* usb phy config init
+        * usb phy enter usb mode */
+       unsigned int * otg_phy_con3 = (control_usb->grf_uoc0_base);
+       *otg_phy_con3 = (0x0300 << 16);
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+       gpio_direction_output(control_usb->otg_gpios->gpio, 0);
+}
+
+void usb20otg_phy_suspend(void* pdata, int suspend)
+{
+       struct dwc_otg_platform_data *usbpdata=pdata;
+       unsigned int * otg_phy_con1 = (control_usb->grf_uoc0_base + 0x8);
+       unsigned int * otg_phy_con2 = (control_usb->grf_uoc0_base + 0xc);
+
+       if(suspend){
+               *otg_phy_con1 = (0x01<<2)|((0x01<<2)<<16);      //enable soft control
+               *otg_phy_con2 = 0x2A|(0x3F<<16);                // enter suspend
+               usbpdata->phy_status = 1;
+       }else{
+               *otg_phy_con1 = ((0x01<<2)<<16);                // exit suspend.
+               usbpdata->phy_status = 0;
+       }
+}
+
+void usb20otg_soft_reset(void)
+{
+}
+
+void usb20otg_clock_init(void* pdata)
+{
+       /*
+       struct dwc_otg_platform_data *usbpdata=pdata;
+       struct clk* ahbclk,*phyclk;
+
+       ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg0");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_otg0\n");
+               return;
+       }
+
+       phyclk = devm_clk_get(usbpdata->dev, "otgphy0");
+       if (IS_ERR(phyclk)) {
+               dev_err(usbpdata->dev, "Failed to get otgphy0\n");
+               return;
+       }
+
+       usbpdata->phyclk = phyclk;
+       usbpdata->ahbclk = ahbclk;*/
+}
+
+void usb20otg_clock_enable(void* pdata, int enable)
+{
+       /*
+       struct dwc_otg_platform_data *usbpdata=pdata;
+
+       if(enable){
+               clk_prepare_enable(usbpdata->ahbclk);
+               clk_prepare_enable(usbpdata->phyclk);
+       }else{
+               clk_disable_unprepare(usbpdata->ahbclk);
+               clk_disable_unprepare(usbpdata->phyclk);
+       }
+       */
+}
+
+int usb20otg_get_status(int id)
+{
+       int ret = -1;
+       unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
+
+       switch(id){
+               case USB_STATUS_BVABLID:
+                       // bvalid in grf
+                       ret = (usbgrf_status &(1<<10));
+                       break;
+               case USB_STATUS_DPDM:
+                       // dpdm in grf
+                       ret = (usbgrf_status &(3<<11));
+                       break;
+               case USB_STATUS_ID:
+                       // id in grf
+                       ret = (usbgrf_status &(1<<13));
+                       break;
+               default:
+                       break;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_RK_USB_UART
+void dwc_otg_uart_mode(void* pdata, int enter_usb_uart_mode)
+{
+       unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc0_base);
+
+       if(1 == enter_usb_uart_mode){
+               /* enter uart mode
+                * note: can't disable otg here! If otg disable, the ID change
+                * interrupt can't be triggered when otg cable connect without
+                * device.At the same time, uart can't be used normally
+                */
+               *otg_phy_con1 = (0x0300 | (0x0300 << 16));      //bypass dm
+       }else if(0 == enter_usb_uart_mode){
+               /* enter usb mode */
+               *otg_phy_con1 = (0x0300 << 16);                 //bypass dm disable
+       }
+}
+#endif
+
+void usb20otg_power_enable(int enable)
+{
+       if(0 == enable){//disable otg_drv power
+               gpio_set_value(control_usb->otg_gpios->gpio, 0);
+       }else if(1 == enable){//enable otg_drv power
+               gpio_set_value(control_usb->otg_gpios->gpio, 1);
+       }
+}
+
+struct dwc_otg_platform_data usb20otg_pdata = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .busclk = NULL,
+       .phy_status = 0,
+       .hw_init=usb20otg_hw_init,
+       .phy_suspend=usb20otg_phy_suspend,
+       .soft_reset=usb20otg_soft_reset,
+       .clock_init=usb20otg_clock_init,
+       .clock_enable=usb20otg_clock_enable,
+       .get_status=usb20otg_get_status,
+       .power_enable=usb20otg_power_enable,
+#ifdef CONFIG_RK_USB_UART
+       .dwc_otg_uart_mode=dwc_otg_uart_mode,
+#endif
+};
+
+#endif
+
+#ifdef CONFIG_USB20_HOST
+void usb20host_hw_init(void)
+{
+       /* usb phy config init */
+
+       /* other haredware init,include:
+        * DRV_VBUS GPIO init */
+       gpio_direction_output(control_usb->host_gpios->gpio, 1);
+
+}
+
+void usb20host_phy_suspend(void* pdata, int suspend)
+{
+       struct dwc_otg_platform_data *usbpdata=pdata;
+       unsigned int * otg_phy_con1 = (unsigned int*)(control_usb->grf_uoc1_base + 0x8);
+       unsigned int * otg_phy_con2 = (unsigned int*)(control_usb->grf_uoc1_base + 0xc);
+
+       if(suspend){
+               *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16);     // enable soft control
+               *otg_phy_con2 =  0x2A|(0x3F<<16);               // enter suspend
+               usbpdata->phy_status = 1;
+       }else{
+               *otg_phy_con1 = ((0x01<<2)<<16);                // exit suspend.
+               usbpdata->phy_status = 0;
+       }
+}
+
+void usb20host_soft_reset(void)
+{
+}
+
+void usb20host_clock_init(void* pdata)
+{
+       /*
+       struct dwc_otg_platform_data *usbpdata=pdata;
+       struct clk* ahbclk,*phyclk;
+
+       ahbclk = devm_clk_get(usbpdata->dev, "hclk_otg1");
+       if (IS_ERR(ahbclk)) {
+               dev_err(usbpdata->dev, "Failed to get hclk_otg1\n");
+               return;
+       }
+
+       phyclk = devm_clk_get(usbpdata->dev, "otgphy1");
+       if (IS_ERR(phyclk)) {
+               dev_err(usbpdata->dev, "Failed to get otgphy1\n");
+               return;
+       }
+
+       usbpdata->phyclk = phyclk;
+       usbpdata->ahbclk = ahbclk;*/
+}
+
+void usb20host_clock_enable(void* pdata, int enable)
+{
+       /*
+       struct dwc_otg_platform_data *usbpdata=pdata;
+
+       if(enable){
+               clk_prepare_enable(usbpdata->ahbclk);
+               clk_prepare_enable(usbpdata->phyclk);
+       }else{
+               clk_disable_unprepare(usbpdata->ahbclk);
+               clk_disable_unprepare(usbpdata->phyclk);
+       }*/
+}
+
+int usb20host_get_status(int id)
+{
+       int ret = -1;
+       unsigned int usbgrf_status = *(unsigned int*)(control_usb->grf_soc_status0);
+
+       switch(id){
+               case USB_STATUS_BVABLID:
+                       // bvalid in grf
+                       ret = (usbgrf_status &(1<<17));
+                       break;
+               case USB_STATUS_DPDM:
+                       // dpdm in grf
+                       ret = (usbgrf_status &(3<<18));
+                       break;
+               case USB_STATUS_ID:
+                       // id in grf
+                       ret = (usbgrf_status &(1<<20));
+                       break;
+               default:
+                       break;
+       }
+
+       return ret;
+}
+
+void usb20host_power_enable(int enable)
+{
+       if(0 == enable){//disable host_drv power
+               //do not disable power in default
+       }else if(1 == enable){//enable host_drv power
+               gpio_set_value(control_usb->host_gpios->gpio, 1);
+       }
+}
+
+struct dwc_otg_platform_data usb20host_pdata = {
+       .phyclk = NULL,
+       .ahbclk = NULL,
+       .busclk = NULL,
+       .phy_status = 0,
+       .hw_init=usb20host_hw_init,
+       .phy_suspend=usb20host_phy_suspend,
+       .soft_reset=usb20host_soft_reset,
+       .clock_init=usb20host_clock_init,
+       .clock_enable=usb20host_clock_enable,
+       .get_status=usb20host_get_status,
+       .power_enable=usb20host_power_enable,
+};
+#endif
+
+static int dwc_otg_control_usb_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int gpio, err;
+       struct device_node *np = pdev->dev.of_node;
+
+       control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),GFP_KERNEL);
+       if (!control_usb) {
+               dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_SOC_STATUS0");
+       control_usb->grf_soc_status0 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(control_usb->grf_soc_status0))
+               return PTR_ERR(control_usb->grf_soc_status0);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC0_BASE");
+       control_usb->grf_uoc0_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(control_usb->grf_uoc0_base))
+               return PTR_ERR(control_usb->grf_uoc0_base);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                               "GRF_UOC1_BASE");
+       control_usb->grf_uoc1_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(control_usb->grf_uoc1_base))
+               return PTR_ERR(control_usb->grf_uoc1_base);
+
+       control_usb->host_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+
+       gpio =  of_get_named_gpio(np, "gpios", 0);
+       if(!gpio_is_valid(gpio)){
+               dev_err(&pdev->dev, "invalid host gpio%d\n", gpio);
+               return -EINVAL;
+       }
+       control_usb->host_gpios->gpio = gpio;
+       err = devm_gpio_request(&pdev->dev, gpio, "host_drv_gpio");
+       if (err) {
+               dev_err(&pdev->dev,
+                       "failed to request GPIO%d for host_drv\n",
+                       gpio);
+               return err;
+       }
+
+       control_usb->otg_gpios = devm_kzalloc(&pdev->dev, sizeof(struct gpio), GFP_KERNEL);
+
+       gpio =  of_get_named_gpio(np, "gpios", 1);
+       if(!gpio_is_valid(gpio)){
+               dev_err(&pdev->dev, "invalid otg gpio%d\n", gpio);
+               return -EINVAL;
+       }
+       control_usb->otg_gpios->gpio = gpio;
+       err = devm_gpio_request(&pdev->dev, gpio, "otg_drv_gpio");
+       if (err) {
+               dev_err(&pdev->dev,
+                       "failed to request GPIO%d for otg_drv\n",
+                       gpio);
+               return err;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dwc_otg_control_usb_id_table[] = {
+       { .compatible = "rockchip,dwc-control-usb" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dwc_otg_control_usb_id_table);
+#endif
+
+static struct platform_driver dwc_otg_control_usb_driver = {
+       .probe          = dwc_otg_control_usb_probe,
+       .driver         = {
+               .name   = "dwc-control-usb",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(dwc_otg_control_usb_id_table),
+       },
+};
+
+static int __init dwc_otg_control_usb_init(void)
+{
+       return platform_driver_register(&dwc_otg_control_usb_driver);
+}
+subsys_initcall(dwc_otg_control_usb_init);
+
+static void __exit dwc_otg_control_usb_exit(void)
+{
+       platform_driver_unregister(&dwc_otg_control_usb_driver);
+}
+
+module_exit(dwc_otg_control_usb_exit);
+MODULE_ALIAS("platform: dwc_control_usb");
+MODULE_AUTHOR("RockChip Inc.");
+MODULE_DESCRIPTION("RockChip Control Module USB Driver");
+MODULE_LICENSE("GPL v2");