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
7 #include <mach/irqs.h>
\r
8 #include <mach/gpio.h>
\r
9 #include <mach/iomux.h>
\r
10 #include <mach/cru.h>
\r
12 #include "usbdev_rk.h"
\r
13 #include "dwc_otg_regs.h"
\r
15 #if defined(CONFIG_ARCH_RK30) || defined(CONFIG_ARCH_RK3188)
\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
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
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
40 int dwc_otg_check_dpdm(void)
\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
47 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);
\r
49 // softreset & clockgate
\r
50 *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(7<<5); // otg0 phy clkgate
\r
52 *(unsigned int*)(RK30_CRU_BASE+0x120) = ((7<<5)<<16)|(0<<5); // otg0 phy clkgate
\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
58 // exit phy suspend
\r
59 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
\r
63 reg_base = ioremap(RK30_USBOTG20_PHYS,USBOTG_SIZE);
\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
78 mdelay(50); // delay about 10ms
\r
80 if((*otg_hprt0 & 0xc00)==0xc00)
\r
87 EXPORT_SYMBOL(dwc_otg_check_dpdm);
\r
89 #ifdef CONFIG_USB20_OTG
\r
91 static struct resource usb20_otg_resource[] = {
\r
93 .start = IRQ_USB_OTG,
\r
95 .flags = IORESOURCE_IRQ,
\r
98 .start = RK30_USBOTG20_PHYS,
\r
99 .end = RK30_USBOTG20_PHYS + RK30_USBOTG20_SIZE - 1,
\r
100 .flags = IORESOURCE_MEM,
\r
105 void usb20otg_hw_init(void)
\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
115 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);
\r
116 *otg_phy_con1 = 0x554|(0xfff<<16); // enter suspend.
\r
119 // usb phy config init
\r
121 // other haredware init
\r
122 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
\r
124 gpio_request(RK3066B_OTG_DRV_VBUS, NULL);
\r
125 gpio_direction_output(RK3066B_OTG_DRV_VBUS, GPIO_LOW);
\r
127 rk30_mux_api_set(GPIO0A5_OTGDRVVBUS_NAME, GPIO0A_OTG_DRV_VBUS);
\r
131 void usb20otg_phy_suspend(void* pdata, int suspend)
\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
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
143 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
\r
144 usbpdata->phy_status = 0;
\r
147 struct dwc_otg_platform_data *usbpdata=pdata;
\r
148 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC0_CON2);
\r
150 *otg_phy_con1 = 0x554|(0xfff<<16); // enter suspend.
\r
151 usbpdata->phy_status = 1;
\r
154 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
\r
155 usbpdata->phy_status = 0;
\r
159 void usb20otg_soft_reset(void)
\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
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
171 void usb20otg_clock_init(void* pdata)
\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
180 void usb20otg_clock_enable(void* pdata, int enable)
\r
182 struct dwc_otg_platform_data *usbpdata=pdata;
\r
185 clk_enable(usbpdata->ahbclk);
\r
186 clk_enable(usbpdata->phyclk);
\r
189 clk_disable(usbpdata->phyclk);
\r
190 clk_disable(usbpdata->ahbclk);
\r
193 int usb20otg_get_status(int id)
\r
196 unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);
\r
199 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
\r
200 case USB_STATUS_BVABLID:
\r
202 ret = (usbgrf_status &(1<<10));
\r
204 case USB_STATUS_DPDM:
\r
206 ret = (usbgrf_status &(3<<11));
\r
208 case USB_STATUS_ID:
\r
210 ret = (usbgrf_status &(1<<13));
\r
213 case USB_STATUS_BVABLID:
\r
215 ret = (usbgrf_status &0x20000);
\r
217 case USB_STATUS_DPDM:
\r
219 ret = (usbgrf_status &(3<<18));
\r
221 case USB_STATUS_ID:
\r
223 ret = (usbgrf_status &(1<<20));
\r
232 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
\r
233 void usb20otg_power_enable(int enable)
\r
235 unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);
\r
236 if(0 == enable)//disable
\r
238 gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_LOW);
\r
241 if(1 == enable)//enable
\r
243 gpio_set_value(RK3066B_OTG_DRV_VBUS, GPIO_HIGH);
\r
247 struct dwc_otg_platform_data usb20otg_pdata = {
\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
263 struct platform_device device_usb20_otg = {
\r
264 .name = "usb20_otg",
\r
266 .num_resources = ARRAY_SIZE(usb20_otg_resource),
\r
267 .resource = usb20_otg_resource,
\r
269 .platform_data = &usb20otg_pdata,
\r
273 #ifdef CONFIG_USB20_HOST
\r
274 static struct resource usb20_host_resource[] = {
\r
276 .start = IRQ_USB_HOST,
\r
277 .end = IRQ_USB_HOST,
\r
278 .flags = IORESOURCE_IRQ,
\r
281 .start = RK30_USBHOST20_PHYS,
\r
282 .end = RK30_USBHOST20_PHYS + RK30_USBHOST20_SIZE - 1,
\r
283 .flags = IORESOURCE_MEM,
\r
287 void usb20host_hw_init(void)
\r
289 // usb phy config init
\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
296 rk30_mux_api_set(GPIO0A6_HOSTDRVVBUS_NAME, GPIO0A_HOST_DRV_VBUS);
\r
299 void usb20host_phy_suspend(void* pdata, int suspend)
\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
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
313 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
\r
314 usbpdata->phy_status = 0;
\r
317 struct dwc_otg_platform_data *usbpdata=pdata;
\r
318 unsigned int * otg_phy_con1 = (unsigned int*)(USBGRF_UOC1_CON2);
\r
321 *otg_phy_con1 = 0x554|(0xfff<<16); // enter suspend.
\r
322 usbpdata->phy_status = 1;
\r
326 *otg_phy_con1 = ((0x01<<2)<<16); // exit suspend.
\r
327 usbpdata->phy_status = 0;
\r
331 void usb20host_soft_reset(void)
\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
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
343 void usb20host_clock_init(void* pdata)
\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
352 void usb20host_clock_enable(void* pdata, int enable)
\r
354 struct dwc_otg_platform_data *usbpdata=pdata;
\r
357 clk_enable(usbpdata->ahbclk);
\r
358 clk_enable(usbpdata->phyclk);
\r
361 clk_disable(usbpdata->phyclk);
\r
362 clk_disable(usbpdata->ahbclk);
\r
365 int usb20host_get_status(int id)
\r
368 unsigned int usbgrf_status = *(unsigned int*)(USBGRF_SOC_STATUS0);
\r
371 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
\r
372 case USB_STATUS_BVABLID:
\r
374 ret = (usbgrf_status &(1<<17));
\r
376 case USB_STATUS_DPDM:
\r
378 ret = (usbgrf_status &(3<<18));
\r
380 case USB_STATUS_ID:
\r
382 ret = (usbgrf_status &(1<<20));
\r
385 case USB_STATUS_BVABLID:
\r
387 ret = (usbgrf_status &(1<<22));
\r
389 case USB_STATUS_DPDM:
\r
391 ret = (usbgrf_status &(3<<23));
\r
393 case USB_STATUS_ID:
\r
404 #if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
\r
405 void usb20host_power_enable(int enable)
\r
408 if(0 == enable)//disable
\r
410 //ret = gpio_request(RK3066B_HOST_DRV_VBUS, NULL);
\r
412 // gpio_free(RK3066B_HOST_DRV_VBUS);
\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
419 if(1 == enable)//enable
\r
421 gpio_set_value(RK3066B_HOST_DRV_VBUS, GPIO_HIGH);
\r
422 //printk("!!!!!!!!!!!!!!!!!!!!!enable host power!!!!!!!!!!!!!!!!!!\n");
\r
426 struct dwc_otg_platform_data usb20host_pdata = {
\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
442 struct platform_device device_usb20_host = {
\r
443 .name = "usb20_host",
\r
445 .num_resources = ARRAY_SIZE(usb20_host_resource),
\r
446 .resource = usb20_host_resource,
\r
448 .platform_data = &usb20host_pdata,
\r
452 static int __init usbdev_init_devices(void)
\r
454 #ifdef CONFIG_USB20_OTG
\r
455 platform_device_register(&device_usb20_otg);
\r
457 #ifdef CONFIG_USB20_HOST
\r
458 platform_device_register(&device_usb20_host);
\r
462 arch_initcall(usbdev_init_devices);
\r