-#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");