USB: support rk3168/rk3188 usb host
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / usbdev_rk30.c
index 819838baa2917b7344ea8b5ecc6c3303abd9e3f2..02aeecc5ef209cf3cafd77edfd3959b934f5e42b 100755 (executable)
 #include <mach/cru.h>\r
 \r
 #include "usbdev_rk.h"\r
-#ifdef CONFIG_ARCH_RK30\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
-#ifdef CONFIG_ARCH_RK3066B\r
+#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
 #define USBGRF_SOC_STATUS0     (GRF_REG_BASE+0xac)\r
-#define USBGRF_UOC0_CON2       (GRF_REG_BASE+0x118) // USBGRF_UOC0_CON3\r
-#define USBGRF_UOC1_CON2       (GRF_REG_BASE+0x128) // USBGRF_UOC1_CON3\r
+#define USBGRF_UOC0_CON2       (GRF_REG_BASE+0x114)\r
+#define USBGRF_UOC0_CON3       (GRF_REG_BASE+0x118)\r
+#define USBGRF_UOC1_CON2       (GRF_REG_BASE+0x124)\r
+#define USBGRF_UOC1_CON3       (GRF_REG_BASE+0x128)\r
+\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_ARCH_RK3188) \r
+#define RK3066B_HOST_DRV_VBUS RK30_PIN0_PC0\r
+#define RK3066B_OTG_DRV_VBUS  RK30_PIN3_PD5\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
-//#define USB_IOMUX_INIT(a,b) rk30_mux_api_set(a,b)\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
@@ -44,35 +105,59 @@ static struct resource usb20_otg_resource[] = {
 void usb20otg_hw_init(void)\r
 {\r
 #ifndef CONFIG_USB20_HOST\r
-    // close USB 2.0 HOST phy and clock\r
-    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-    *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\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
-    // usb phy config init\r
-\r
-    // other haredware init\r
-#ifdef CONFIG_ARCH_RK3066B\r
-    rk30_mux_api_set(GPIO3D5_PWM2_JTAGTCK_OTGDRVVBUS_NAME, GPIO3D_OTGDRVVBUS);\r
+#endif\r
+        // usb phy config init\r
+    \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
+        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
-    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
+#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
-#if 1\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
@@ -82,7 +167,6 @@ void usb20otg_soft_reset(void)
     cru_set_soft_reset(SOFT_RST_USBPHY0, false);\r
     cru_set_soft_reset(SOFT_RST_OTGC0, false);\r
     mdelay(1);\r
-#endif\r
 }\r
 void usb20otg_clock_init(void* pdata)\r
 {\r
@@ -96,7 +180,7 @@ void usb20otg_clock_init(void* pdata)
 void usb20otg_clock_enable(void* pdata, int enable)\r
 {\r
     struct dwc_otg_platform_data *usbpdata=pdata;\r
-    #if 1\r
+\r
     if(enable){\r
         clk_enable(usbpdata->ahbclk);\r
         clk_enable(usbpdata->phyclk);\r
@@ -105,34 +189,61 @@ void usb20otg_clock_enable(void* pdata, int enable)
         clk_disable(usbpdata->phyclk);\r
         clk_disable(usbpdata->ahbclk);\r
     }\r
-    #endif\r
 }\r
 int usb20otg_get_status(int id)\r
 {\r
-    int ret = -1;\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
+#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
-    switch(id)\r
+    if(0 == enable)//disable\r
     {\r
-        case 0x01:\r
-            // bvalid in grf\r
-            ret = (usbgrf_status &0x20000);\r
-            break;\r
-        case 0x02:\r
-            // dpdm in grf\r
-            ret = (usbgrf_status &(3<<18));\r
-            break;\r
-        case 0x03:\r
-            // id in grf\r
-            ret = (usbgrf_status &(1<<20));\r
-            break;\r
-        default:\r
-            break;\r
+        gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_LOW); \r
+\r
     }\r
-    return ret;\r
-}\r
-void usb20otg_power_enable(int enable)\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
@@ -144,6 +255,9 @@ struct dwc_otg_platform_data usb20otg_pdata = {
     .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
 };\r
 \r
 struct platform_device device_usb20_otg = {\r
@@ -175,28 +289,47 @@ void usb20host_hw_init(void)
     // usb phy config init\r
 \r
     // other haredware init\r
-#ifdef CONFIG_ARCH_RK3066B\r
-    rk30_mux_api_set(GPIO3D6_PWM3_JTAGTMS_HOSTDRVVBUS_NAME, GPIO3D_HOSTDRVVBUS);\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
-    struct dwc_otg_platform_data *usbpdata=pdata;\r
-    unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
-    if(suspend){\r
-        *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
-        usbpdata->phy_status = 0;\r
-    }\r
-    else{\r
-        *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
-        usbpdata->phy_status = 1;\r
-    }\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
-#if 1\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
@@ -206,7 +339,6 @@ void usb20host_soft_reset(void)
     cru_set_soft_reset(SOFT_RST_USBPHY1, false);\r
     cru_set_soft_reset(SOFT_RST_OTGC1, false);\r
     mdelay(1);\r
-#endif\r
 }\r
 void usb20host_clock_init(void* pdata)\r
 {\r
@@ -220,7 +352,7 @@ void usb20host_clock_init(void* pdata)
 void usb20host_clock_enable(void* pdata, int enable)\r
 {\r
     struct dwc_otg_platform_data *usbpdata=pdata;\r
-    #if 1\r
+    \r
     if(enable){\r
         clk_enable(usbpdata->ahbclk);\r
         clk_enable(usbpdata->phyclk);\r
@@ -229,7 +361,6 @@ void usb20host_clock_enable(void* pdata, int enable)
         clk_disable(usbpdata->phyclk);\r
         clk_disable(usbpdata->ahbclk);\r
     }\r
-    #endif\r
 }\r
 int usb20host_get_status(int id)\r
 {\r
@@ -237,6 +368,20 @@ int usb20host_get_status(int id)
     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
@@ -249,14 +394,35 @@ int usb20host_get_status(int id)
             // 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
+\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
@@ -268,6 +434,9 @@ struct dwc_otg_platform_data usb20host_pdata = {
     .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
@@ -288,6 +457,7 @@ static int __init usbdev_init_devices(void)
 #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
\ No newline at end of file
+#endif\r