USB: support rk3168/rk3188 usb host
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / usbdev_rk30.c
1 #include <linux/kernel.h>\r
2 #include <linux/platform_device.h>\r
3 #include <linux/delay.h>\r
4 #include <linux/dma-mapping.h>\r
5 #include <linux/clk.h>\r
6 \r
7 #include <mach/irqs.h>\r
8 #include <mach/gpio.h>\r
9 #include <mach/iomux.h>\r
10 #include <mach/cru.h>\r
11 \r
12 #include "usbdev_rk.h"\r
13 #include "dwc_otg_regs.h" \r
14 \r
15 #if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK3188)\r
16 \r
17 #define GRF_REG_BASE    RK30_GRF_BASE   \r
18 #define USBOTG_SIZE     RK30_USBOTG20_SIZE\r
19 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
20 #define USBGRF_SOC_STATUS0      (GRF_REG_BASE+0xac)\r
21 #define USBGRF_UOC0_CON2        (GRF_REG_BASE+0x114)\r
22 #define USBGRF_UOC0_CON3        (GRF_REG_BASE+0x118)\r
23 #define USBGRF_UOC1_CON2        (GRF_REG_BASE+0x124)\r
24 #define USBGRF_UOC1_CON3        (GRF_REG_BASE+0x128)\r
25 \r
26 #if defined(CONFIG_SOC_RK3066B) || defined(CONFIG_SOC_RK3108) \r
27 #define RK3066B_HOST_DRV_VBUS RK30_PIN0_PD7\r
28 #define RK3066B_OTG_DRV_VBUS  RK30_PIN0_PD6\r
29 #elif defined(CONFIG_SOC_RK3168) || defined(CONFIG_ARCH_RK3188) \r
30 #define RK3066B_HOST_DRV_VBUS RK30_PIN0_PC0\r
31 #define RK3066B_OTG_DRV_VBUS  RK30_PIN3_PD5\r
32 #endif\r
33 \r
34 #else\r
35 #define USBGRF_SOC_STATUS0      (GRF_REG_BASE+0x15c)\r
36 #define USBGRF_UOC0_CON2        (GRF_REG_BASE+0x184)\r
37 #define USBGRF_UOC1_CON2        (GRF_REG_BASE+0x190)\r
38 #endif\r
39 \r
40 int dwc_otg_check_dpdm(void)\r
41 {\r
42         static uint8_t * reg_base = 0;\r
43     volatile unsigned int * otg_dctl;\r
44     volatile unsigned int * otg_gotgctl;\r
45     volatile unsigned int * otg_hprt0;\r
46     int bus_status = 0;\r
47     unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
48     \r
49     // softreset & clockgate \r
50     *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5);    // otg0 phy clkgate\r
51     udelay(3);\r
52     *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5);    // otg0 phy clkgate\r
53     dsb();\r
54     *(unsigned int*)(RK30_CRU_BASE+0xd4) = ((1<<5)<<16);    // otg0 phy clkgate\r
55     *(unsigned int*)(RK30_CRU_BASE+0xe4) = ((1<<13)<<16);   // otg0 hclk clkgate\r
56     *(unsigned int*)(RK30_CRU_BASE+0xe0) = ((3<<5)<<16);    // hclk usb clkgate\r
57     \r
58     // exit phy suspend \r
59         *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
60     \r
61     // soft connect\r
62     if(reg_base == 0){\r
63         reg_base = ioremap(RK30_USBOTG20_PHYS,USBOTG_SIZE);\r
64         if(!reg_base){\r
65             bus_status = -1;\r
66             goto out;\r
67         }\r
68     }\r
69     mdelay(105);\r
70     printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n",\r
71         reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1);\r
72     otg_dctl = (unsigned int * )(reg_base+0x804);\r
73     otg_gotgctl = (unsigned int * )(reg_base);\r
74     otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);\r
75     if(*otg_gotgctl &(1<<19)){\r
76         bus_status = 1;\r
77         *otg_dctl &= ~2;\r
78         mdelay(50);    // delay about 10ms\r
79     // check dp,dm\r
80         if((*otg_hprt0 & 0xc00)==0xc00)\r
81             bus_status = 2;\r
82     }\r
83 out:\r
84     return bus_status;\r
85 }\r
86 \r
87 EXPORT_SYMBOL(dwc_otg_check_dpdm);\r
88 \r
89 #ifdef CONFIG_USB20_OTG\r
90 /*DWC_OTG*/\r
91 static struct resource usb20_otg_resource[] = {\r
92         {\r
93                 .start = IRQ_USB_OTG,\r
94                 .end   = IRQ_USB_OTG,\r
95                 .flags = IORESOURCE_IRQ,\r
96         },\r
97         {\r
98                 .start = RK30_USBOTG20_PHYS,\r
99                 .end   = RK30_USBOTG20_PHYS + RK30_USBOTG20_SIZE - 1,\r
100                 .flags = IORESOURCE_MEM,\r
101         },\r
102 \r
103 };\r
104 \r
105 void usb20otg_hw_init(void)\r
106 {\r
107 #ifndef CONFIG_USB20_HOST\r
108         // close USB 2.0 HOST phy and clock\r
109 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
110         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
111         unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC1_CON3);\r
112         *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16);     //enable soft control\r
113         *otg_phy_con2 =  0x2A|(0x3F<<16);               // enter suspend   \r
114 #else\r
115         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
116         *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
117 #endif\r
118 #endif\r
119         // usb phy config init\r
120     \r
121         // other haredware init\r
122 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
123         //GPIO init\r
124         gpio_request(RK3066B_OTG_DRV_VBUS, NULL);\r
125         gpio_direction_output(RK3066B_OTG_DRV_VBUS, GPIO_LOW);\r
126 #else\r
127         rk30_mux_api_set(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_OTG_DRV_VBUS);\r
128 #endif\r
129 }\r
130 \r
131 void usb20otg_phy_suspend(void* pdata, int suspend)\r
132 {\r
133 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
134         struct dwc_otg_platform_data *usbpdata=pdata;\r
135         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
136         unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC0_CON3);\r
137         if(suspend){\r
138             *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16); ;   //enable soft control\r
139             *otg_phy_con2 =  0x2A|(0x3F<<16);;              // enter suspend\r
140             usbpdata->phy_status = 1;\r
141         }\r
142         else{\r
143             *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
144             usbpdata->phy_status = 0;\r
145         }\r
146 #else\r
147         struct dwc_otg_platform_data *usbpdata=pdata;\r
148         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);\r
149         if(suspend){\r
150             *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
151             usbpdata->phy_status = 1;\r
152         }\r
153         else{\r
154             *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
155             usbpdata->phy_status = 0;\r
156         }\r
157 #endif\r
158 }\r
159 void usb20otg_soft_reset(void)\r
160 {\r
161     cru_set_soft_reset(SOFT_RST_USBOTG0, true);\r
162     cru_set_soft_reset(SOFT_RST_USBPHY0, true);\r
163     cru_set_soft_reset(SOFT_RST_OTGC0, true);\r
164     udelay(1);\r
165 \r
166     cru_set_soft_reset(SOFT_RST_USBOTG0, false);\r
167     cru_set_soft_reset(SOFT_RST_USBPHY0, false);\r
168     cru_set_soft_reset(SOFT_RST_OTGC0, false);\r
169     mdelay(1);\r
170 }\r
171 void usb20otg_clock_init(void* pdata)\r
172 {\r
173     struct dwc_otg_platform_data *usbpdata=pdata;\r
174     struct clk* ahbclk,*phyclk;\r
175     ahbclk = clk_get(NULL, "hclk_otg0");\r
176     phyclk = clk_get(NULL, "otgphy0");\r
177         usbpdata->phyclk = phyclk;\r
178         usbpdata->ahbclk = ahbclk;\r
179 }\r
180 void usb20otg_clock_enable(void* pdata, int enable)\r
181 {\r
182     struct dwc_otg_platform_data *usbpdata=pdata;\r
183 \r
184     if(enable){\r
185         clk_enable(usbpdata->ahbclk);\r
186         clk_enable(usbpdata->phyclk);\r
187     }\r
188     else{\r
189         clk_disable(usbpdata->phyclk);\r
190         clk_disable(usbpdata->ahbclk);\r
191     }\r
192 }\r
193 int usb20otg_get_status(int id)\r
194 {\r
195         int ret = -1;\r
196         unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
197         switch(id)\r
198         {\r
199 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
200             case USB_STATUS_BVABLID:\r
201                 // bvalid in grf\r
202                 ret = (usbgrf_status &(1<<10));\r
203                 break;\r
204             case USB_STATUS_DPDM:\r
205                 // dpdm in grf\r
206                 ret = (usbgrf_status &(3<<11));\r
207                 break;\r
208             case USB_STATUS_ID:\r
209                 // id in grf\r
210                 ret = (usbgrf_status &(1<<13));\r
211                 break;\r
212 #else\r
213             case USB_STATUS_BVABLID:\r
214                 // bvalid in grf\r
215                 ret = (usbgrf_status &0x20000);\r
216                 break;\r
217             case USB_STATUS_DPDM:\r
218                 // dpdm in grf\r
219                 ret = (usbgrf_status &(3<<18));\r
220                 break;\r
221             case USB_STATUS_ID:\r
222                 // id in grf\r
223                 ret = (usbgrf_status &(1<<20));\r
224                 break;\r
225 #endif\r
226             default:\r
227                 break;\r
228         }\r
229         return ret;\r
230 }\r
231  \r
232 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
233 void usb20otg_power_enable(int enable)\r
234\r
235     unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
236     if(0 == enable)//disable\r
237     {\r
238         gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_LOW); \r
239 \r
240     }\r
241     if(1 == enable)//enable\r
242     {\r
243         gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_HIGH); \r
244     }   \r
245 }\r
246 #endif\r
247 struct dwc_otg_platform_data usb20otg_pdata = {\r
248     .phyclk = NULL,\r
249     .ahbclk = NULL,\r
250     .busclk = NULL,\r
251     .phy_status = 0,\r
252     .hw_init=usb20otg_hw_init,\r
253     .phy_suspend=usb20otg_phy_suspend,\r
254     .soft_reset=usb20otg_soft_reset,\r
255     .clock_init=usb20otg_clock_init,\r
256     .clock_enable=usb20otg_clock_enable,\r
257     .get_status=usb20otg_get_status,\r
258 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
259     .power_enable=usb20otg_power_enable,\r
260 #endif    \r
261 };\r
262 \r
263 struct platform_device device_usb20_otg = {\r
264         .name             = "usb20_otg",\r
265         .id               = -1,\r
266         .num_resources    = ARRAY_SIZE(usb20_otg_resource),\r
267         .resource         = usb20_otg_resource,\r
268         .dev            = {\r
269                 .platform_data  = &usb20otg_pdata,\r
270         },\r
271 };\r
272 #endif\r
273 #ifdef CONFIG_USB20_HOST\r
274 static struct resource usb20_host_resource[] = {\r
275     {\r
276         .start = IRQ_USB_HOST,\r
277         .end   = IRQ_USB_HOST,\r
278         .flags = IORESOURCE_IRQ,\r
279     },\r
280     {\r
281         .start = RK30_USBHOST20_PHYS,\r
282         .end   = RK30_USBHOST20_PHYS + RK30_USBHOST20_SIZE - 1,\r
283         .flags = IORESOURCE_MEM,\r
284     },\r
285 \r
286 };\r
287 void usb20host_hw_init(void)\r
288 {\r
289     // usb phy config init\r
290 \r
291     // other haredware init\r
292 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
293     gpio_request(RK3066B_HOST_DRV_VBUS, NULL);\r
294     gpio_direction_output(RK3066B_HOST_DRV_VBUS, GPIO_HIGH);\r
295 #else\r
296     rk30_mux_api_set(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A_HOST_DRV_VBUS);\r
297 #endif\r
298 }\r
299 void usb20host_phy_suspend(void* pdata, int suspend)\r
300\r
301 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
302         struct dwc_otg_platform_data *usbpdata=pdata;\r
303         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
304         unsigned int * otg_phy_con2 = (unsigned int*)(USBGRF_UOC1_CON3);\r
305         if(suspend)\r
306         {\r
307             *otg_phy_con1 =  (0x01<<2)|((0x01<<2)<<16); ;   //enable soft control\r
308             *otg_phy_con2 =  0x2A|(0x3F<<16);;                     // enter suspend\r
309             usbpdata->phy_status = 1;\r
310         }\r
311         else\r
312         {\r
313             *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
314             usbpdata->phy_status = 0;\r
315         }   \r
316 #else\r
317         struct dwc_otg_platform_data *usbpdata=pdata;\r
318         unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);\r
319         if(suspend)\r
320         {\r
321             *otg_phy_con1 = 0x554|(0xfff<<16);   // enter suspend.\r
322             usbpdata->phy_status = 1;\r
323         }\r
324         else\r
325         {\r
326             *otg_phy_con1 = ((0x01<<2)<<16);    // exit suspend.\r
327             usbpdata->phy_status = 0;\r
328         }\r
329 #endif \r
330 }\r
331 void usb20host_soft_reset(void)\r
332 {\r
333     cru_set_soft_reset(SOFT_RST_USBOTG1, true);\r
334     cru_set_soft_reset(SOFT_RST_USBPHY1, true);\r
335     cru_set_soft_reset(SOFT_RST_OTGC1, true);\r
336     udelay(1);\r
337 \r
338     cru_set_soft_reset(SOFT_RST_USBOTG1, false);\r
339     cru_set_soft_reset(SOFT_RST_USBPHY1, false);\r
340     cru_set_soft_reset(SOFT_RST_OTGC1, false);\r
341     mdelay(1);\r
342 }\r
343 void usb20host_clock_init(void* pdata)\r
344 {\r
345     struct dwc_otg_platform_data *usbpdata=pdata;\r
346     struct clk* ahbclk,*phyclk;\r
347     ahbclk = clk_get(NULL, "hclk_otg1");\r
348     phyclk = clk_get(NULL, "otgphy1");\r
349         usbpdata->phyclk = phyclk;\r
350         usbpdata->ahbclk = ahbclk;\r
351 }\r
352 void usb20host_clock_enable(void* pdata, int enable)\r
353 {\r
354     struct dwc_otg_platform_data *usbpdata=pdata;\r
355     \r
356     if(enable){\r
357         clk_enable(usbpdata->ahbclk);\r
358         clk_enable(usbpdata->phyclk);\r
359     }\r
360     else{\r
361         clk_disable(usbpdata->phyclk);\r
362         clk_disable(usbpdata->ahbclk);\r
363     }\r
364 }\r
365 int usb20host_get_status(int id)\r
366 {\r
367     int ret = -1;\r
368     unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
369     switch(id)\r
370     {\r
371 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
372         case USB_STATUS_BVABLID:\r
373             // bvalid in grf\r
374             ret = (usbgrf_status &(1<<17));\r
375             break;\r
376         case USB_STATUS_DPDM:\r
377             // dpdm in grf\r
378             ret = (usbgrf_status &(3<<18));\r
379             break;\r
380         case USB_STATUS_ID:\r
381             // id in grf\r
382             ret = (usbgrf_status &(1<<20));\r
383             break;\r
384 #else\r
385         case USB_STATUS_BVABLID:\r
386             // bvalid in grf\r
387             ret = (usbgrf_status &(1<<22));\r
388             break;\r
389         case USB_STATUS_DPDM:\r
390             // dpdm in grf\r
391             ret = (usbgrf_status &(3<<23));\r
392             break;\r
393         case USB_STATUS_ID:\r
394             // id in grf\r
395             ret = 0;\r
396             break;\r
397 #endif\r
398         default:\r
399             break;\r
400     }\r
401     return ret;\r
402 }\r
403 \r
404 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
405 void usb20host_power_enable(int enable)\r
406\r
407 \r
408     if(0 == enable)//disable\r
409     {\r
410         //ret = gpio_request(RK3066B_HOST_DRV_VBUS, NULL);\r
411         //if (ret != 0) {\r
412         //    gpio_free(RK3066B_HOST_DRV_VBUS);\r
413         //}\r
414         //gpio_direction_output(RK3066B_HOST_DRV_VBUS, 1);\r
415         //gpio_set_value(RK3066B_HOST_DRV_VBUS, 0);\r
416         //printk("!!!!!!!!!!!!!!!!!!!disable host power!!!!!!!!!!!!!!!!!!\n");\r
417     }\r
418 \r
419     if(1 == enable)//enable\r
420     {\r
421         gpio_set_value(RK3066B_HOST_DRV_VBUS, GPIO_HIGH);\r
422         //printk("!!!!!!!!!!!!!!!!!!!!!enable host power!!!!!!!!!!!!!!!!!!\n");\r
423     }   \r
424 }\r
425 #endif\r
426 struct dwc_otg_platform_data usb20host_pdata = {\r
427     .phyclk = NULL,\r
428     .ahbclk = NULL,\r
429     .busclk = NULL,\r
430     .phy_status = 0,\r
431     .hw_init=usb20host_hw_init,\r
432     .phy_suspend=usb20host_phy_suspend,\r
433     .soft_reset=usb20host_soft_reset,\r
434     .clock_init=usb20host_clock_init,\r
435     .clock_enable=usb20host_clock_enable,\r
436     .get_status=usb20host_get_status,\r
437 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)\r
438     .power_enable=usb20host_power_enable,\r
439 #endif    \r
440 };\r
441 \r
442 struct platform_device device_usb20_host = {\r
443     .name             = "usb20_host",\r
444     .id               = -1,\r
445     .num_resources    = ARRAY_SIZE(usb20_host_resource),\r
446     .resource         = usb20_host_resource,\r
447         .dev            = {\r
448                 .platform_data  = &usb20host_pdata,\r
449         },\r
450 };\r
451 #endif\r
452 static int __init usbdev_init_devices(void)\r
453 {\r
454 #ifdef CONFIG_USB20_OTG\r
455         platform_device_register(&device_usb20_otg);\r
456 #endif\r
457 #ifdef CONFIG_USB20_HOST\r
458         platform_device_register(&device_usb20_host);\r
459 #endif\r
460     return 0;\r
461 }\r
462 arch_initcall(usbdev_init_devices);\r
463 #endif\r