RK2928 USB modified
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg / usbdev_rk2928.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 #ifdef CONFIG_ARCH_RK2928\r
15 \r
16 #define GRF_REG_BASE RK2928_GRF_BASE\r
17 #define USBOTG_SIZE    RK2928_USBOTG20_SIZE\r
18 #define USBGRF_SOC_STATUS0      (GRF_REG_BASE+0x14c)\r
19 #define USBGRF_UOC0_CON5        (GRF_REG_BASE+0x17c)\r
20 #define USBGRF_UOC1_CON5        (GRF_REG_BASE+0x194)\r
21 \r
22 \r
23 int dwc_otg_check_dpdm(void)\r
24 {\r
25         static uint8_t * reg_base = 0;\r
26     volatile unsigned int * otg_dctl;\r
27     volatile unsigned int * otg_gotgctl;\r
28     volatile unsigned int * otg_hprt0;\r
29     int bus_status = 0;\r
30     unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5);//@lyz modify UOC0_CON2 to CON5\r
31     \r
32     // softreset & clockgate //@lyz modify RK2928_CRU_BASE\r
33     *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5);    // otg0 phy clkgate\r
34     udelay(3);\r
35     *(unsigned int*)(RK2928_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5);    // otg0 phy clkgate\r
36     dsb();\r
37     *(unsigned int*)(RK2928_CRU_BASE+0xd4) = ((1<<5)<<16);    // otg0 phy clkgate\r
38     *(unsigned int*)(RK2928_CRU_BASE+0xe4) = ((1<<13)<<16);   // otg0 hclk clkgate\r
39     *(unsigned int*)(RK2928_CRU_BASE+0xf4) = ((3<<10)<<16);    // hclk usb clkgate//@lyz to be check\r
40     \r
41     // exit phy suspend \r
42         *otg_phy_con1 = ((0x01<<0)<<16);    // exit suspend.@lyz\r
43     \r
44     // soft connect\r
45     if(reg_base == 0){\r
46         reg_base = ioremap(RK2928_USBOTG20_PHYS,USBOTG_SIZE);//@lyz\r
47         if(!reg_base){\r
48             bus_status = -1;\r
49             goto out;\r
50         }\r
51     }\r
52     mdelay(105);\r
53     printk("regbase %p 0x%x, otg_phy_con%p, 0x%x\n",\r
54         reg_base, *(reg_base), otg_phy_con1, *otg_phy_con1);\r
55     otg_dctl = (unsigned int * )(reg_base+0x804);\r
56     otg_gotgctl = (unsigned int * )(reg_base);\r
57     otg_hprt0 = (unsigned int * )(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);\r
58     if(*otg_gotgctl &(1<<19)){\r
59         bus_status = 1;\r
60         *otg_dctl &= ~(0x01<<1);//@lyz exit soft-disconnect mode\r
61         mdelay(50);    // delay about 10ms\r
62     // check dp,dm\r
63         if((*otg_hprt0 & 0xc00)==0xc00)//@lyz check hprt[11:10] \r
64             bus_status = 2;\r
65     }\r
66 out:\r
67     return bus_status;\r
68 }\r
69 \r
70 EXPORT_SYMBOL(dwc_otg_check_dpdm);\r
71 \r
72 \r
73 #ifdef CONFIG_USB20_OTG\r
74 /*DWC_OTG*/\r
75 static struct resource usb20_otg_resource[] = {\r
76         {\r
77                 .start = IRQ_USB_OTG,\r
78                 .end   = IRQ_USB_OTG,\r
79                 .flags = IORESOURCE_IRQ,\r
80         },\r
81         {\r
82                 .start = RK2928_USBOTG20_PHYS,\r
83                 .end   = RK2928_USBOTG20_PHYS + RK2928_USBOTG20_SIZE - 1,\r
84                 .flags = IORESOURCE_MEM,\r
85         },\r
86 \r
87 };\r
88 \r
89 void usb20otg_hw_init(void)\r
90 {\r
91 #ifndef CONFIG_USB20_HOST\r
92     // close USB 2.0 HOST phy and clock\r
93     unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON5);\r
94     *otg_phy_con1 = 0x1D5 |(0x1ff<<16);   // enter suspend.\r
95 #endif\r
96     // usb phy config init\r
97 \r
98     // other hardware init\r
99     rk30_mux_api_set(GPIO3C1_OTG_DRVVBUS_NAME, GPIO3C_OTG_DRVVBUS);    \r
100 }\r
101 void usb20otg_phy_suspend(void* pdata, int suspend)\r
102 {\r
103     struct dwc_otg_platform_data *usbpdata=pdata;\r
104     unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON5);\r
105     if(suspend){\r
106         *otg_phy_con1 = 0x1D5 |(0x1ff<<16);   // enter suspend.\r
107         usbpdata->phy_status = 1;\r
108     }\r
109     else{\r
110         *otg_phy_con1 = (0x01<<16);    // exit suspend.\r
111         usbpdata->phy_status = 0;\r
112     }\r
113 }\r
114 void usb20otg_soft_reset(void)\r
115 {\r
116 #if 1\r
117     cru_set_soft_reset(SOFT_RST_USBOTG0, true);\r
118     cru_set_soft_reset(SOFT_RST_USBPHY0, true);\r
119     cru_set_soft_reset(SOFT_RST_OTGC0, true);\r
120     udelay(1);\r
121 \r
122     cru_set_soft_reset(SOFT_RST_USBOTG0, false);\r
123     cru_set_soft_reset(SOFT_RST_USBPHY0, false);\r
124     cru_set_soft_reset(SOFT_RST_OTGC0, false);\r
125     mdelay(1);\r
126 #endif\r
127 }\r
128 void usb20otg_clock_init(void* pdata)\r
129 {\r
130     struct dwc_otg_platform_data *usbpdata=pdata;\r
131     struct clk* ahbclk,*phyclk;\r
132     ahbclk = clk_get(NULL, "hclk_otg0");\r
133     phyclk = clk_get(NULL, "otgphy0");\r
134         usbpdata->phyclk = phyclk;\r
135         usbpdata->ahbclk = ahbclk;\r
136 }\r
137 void usb20otg_clock_enable(void* pdata, int enable)\r
138 {\r
139     struct dwc_otg_platform_data *usbpdata=pdata;\r
140     #if 1\r
141     if(enable){\r
142         clk_enable(usbpdata->ahbclk);\r
143         clk_enable(usbpdata->phyclk);\r
144     }\r
145     else{\r
146    // clk_disable(usbpdata->phyclk);   /* otg/host20 use the same phyclk, so can't disable phyclk in case host20 is used.*/ \r
147         clk_disable(usbpdata->ahbclk);    \r
148     }\r
149     #endif\r
150 }\r
151 int usb20otg_get_status(int id)\r
152 {\r
153     int ret = -1;\r
154     unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
155     switch(id)\r
156     {\r
157         case USB_STATUS_BVABLID:\r
158             // bvalid in grf\r
159             ret = (usbgrf_status &(1<<7));\r
160             break;\r
161         case USB_STATUS_DPDM:\r
162             // dpdm in grf\r
163             ret = (usbgrf_status &(3<<8));\r
164             break;\r
165         case USB_STATUS_ID:\r
166             // id in grf\r
167             ret = (usbgrf_status &(1<<10));\r
168             break;\r
169         default:\r
170             break;\r
171     }\r
172     return ret;\r
173 }\r
174 void usb20otg_power_enable(int enable)\r
175 {\r
176 }\r
177 struct dwc_otg_platform_data usb20otg_pdata = {\r
178     .phyclk = NULL,\r
179     .ahbclk = NULL,\r
180     .busclk = NULL,\r
181     .phy_status = 0,\r
182     .hw_init=usb20otg_hw_init,\r
183     .phy_suspend=usb20otg_phy_suspend,\r
184     .soft_reset=usb20otg_soft_reset,\r
185     .clock_init=usb20otg_clock_init,\r
186     .clock_enable=usb20otg_clock_enable,\r
187     .get_status=usb20otg_get_status,\r
188 };\r
189 \r
190 struct platform_device device_usb20_otg = {\r
191         .name             = "usb20_otg",\r
192         .id               = -1,\r
193         .num_resources    = ARRAY_SIZE(usb20_otg_resource),\r
194         .resource         = usb20_otg_resource,\r
195         .dev            = {\r
196                 .platform_data  = &usb20otg_pdata,\r
197         },\r
198 };\r
199 #endif\r
200 #ifdef CONFIG_USB20_HOST\r
201 static struct resource usb20_host_resource[] = {\r
202     {\r
203         .start = IRQ_USB_HOST,\r
204         .end   = IRQ_USB_HOST,\r
205         .flags = IORESOURCE_IRQ,\r
206     },\r
207     {\r
208         .start = RK2928_USBHOST20_PHYS,\r
209         .end   = RK2928_USBHOST20_PHYS + RK2928_USBHOST20_SIZE - 1,\r
210         .flags = IORESOURCE_MEM,\r
211     },\r
212 \r
213 };\r
214 \r
215 void usb20host_hw_init(void)\r
216 {\r
217     // usb phy config init\r
218     *(unsigned int *)(USBGRF_UOC0_CON5+4) = 0x07e00350;\r
219     // other haredware init\r
220     \r
221 }\r
222 void usb20host_phy_suspend(void* pdata, int suspend)\r
223 {\r
224     struct dwc_otg_platform_data *usbpdata=pdata;\r
225     unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON5);\r
226     if(suspend){\r
227         *otg_phy_con1 = 0x1D5 |(0x1ff<<16);   // enter suspend.\r
228         usbpdata->phy_status = 1;\r
229     }\r
230     else{\r
231         *otg_phy_con1 = (0x01<<16);    // exit suspend.\r
232         usbpdata->phy_status = 0;\r
233     }\r
234 }\r
235 void usb20host_soft_reset(void)\r
236 {\r
237 #if 1\r
238     cru_set_soft_reset(SOFT_RST_USBOTG1, true);\r
239     cru_set_soft_reset(SOFT_RST_USBPHY1, true);\r
240     cru_set_soft_reset(SOFT_RST_OTGC1, true);\r
241     udelay(1);\r
242 \r
243     cru_set_soft_reset(SOFT_RST_USBOTG1, false);\r
244     cru_set_soft_reset(SOFT_RST_USBPHY1, false);\r
245     cru_set_soft_reset(SOFT_RST_OTGC1, false);\r
246     mdelay(1);\r
247 #endif\r
248 }\r
249 void usb20host_clock_init(void* pdata)\r
250 {\r
251     struct dwc_otg_platform_data *usbpdata=pdata;\r
252     struct clk* ahbclk,*phyclk;\r
253     ahbclk = clk_get(NULL, "hclk_otg1");\r
254     phyclk = clk_get(NULL, "otgphy1");\r
255         usbpdata->phyclk = phyclk;\r
256         usbpdata->ahbclk = ahbclk;\r
257 }\r
258 void usb20host_clock_enable(void* pdata, int enable)\r
259 {\r
260     struct dwc_otg_platform_data *usbpdata=pdata;\r
261     #if 1\r
262     if(enable){\r
263         clk_enable(usbpdata->ahbclk);\r
264         clk_enable(usbpdata->phyclk);\r
265     }\r
266     else{\r
267         clk_disable(usbpdata->phyclk);\r
268         clk_disable(usbpdata->ahbclk);\r
269     }\r
270     #endif\r
271 }\r
272 int usb20host_get_status(int id)\r
273 {\r
274     int ret = -1;\r
275     unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);\r
276     switch(id)\r
277     {\r
278         case USB_STATUS_BVABLID:\r
279             // bvalid in grf\r
280             ret = (usbgrf_status &(1<<12));\r
281             break;\r
282         case USB_STATUS_DPDM:\r
283             // dpdm in grf\r
284             ret = (usbgrf_status &(3<<13));\r
285             break;\r
286         case USB_STATUS_ID:\r
287             // id in grf\r
288             ret = 0;\r
289             break;\r
290         default:\r
291             break;\r
292     }\r
293     return ret;\r
294 }\r
295 void usb20host_power_enable(int enable)\r
296 {\r
297 }\r
298 struct dwc_otg_platform_data usb20host_pdata = {\r
299     .phyclk = NULL,\r
300     .ahbclk = NULL,\r
301     .busclk = NULL,\r
302     .phy_status = 0,\r
303     .hw_init=usb20host_hw_init,\r
304     .phy_suspend=usb20host_phy_suspend,\r
305     .soft_reset=usb20host_soft_reset,\r
306     .clock_init=usb20host_clock_init,\r
307     .clock_enable=usb20host_clock_enable,\r
308     .get_status=usb20host_get_status,\r
309 };\r
310 \r
311 struct platform_device device_usb20_host = {\r
312     .name             = "usb20_host",\r
313     .id               = -1,\r
314     .num_resources    = ARRAY_SIZE(usb20_host_resource),\r
315     .resource         = usb20_host_resource,\r
316     .dev                = {\r
317                 .platform_data  = &usb20host_pdata,\r
318         },\r
319 };\r
320 #endif\r
321 static int __init usbdev_init_devices(void)\r
322 {\r
323 #ifdef CONFIG_USB20_OTG\r
324         platform_device_register(&device_usb20_otg);\r
325 #endif\r
326 #ifdef CONFIG_USB20_HOST\r
327         platform_device_register(&device_usb20_host);\r
328 #endif\r
329 }\r
330 arch_initcall(usbdev_init_devices);\r
331 #endif\r
332 \r