diff --git a/drivers/power/axp_power/axp-chg.c b/drivers/power/axp_power/axp-chg.c index 40efb655007..5835db3b383 100755 --- a/drivers/power/axp_power/axp-chg.c +++ b/drivers/power/axp_power/axp-chg.c @@ -52,6 +52,12 @@ s32 axp_usb_det(void) } EXPORT_SYMBOL_GPL(axp_usb_det); +s32 axp_usb_vbus_output(int high) +{ + return 0; +} +EXPORT_SYMBOL_GPL(axp_usb_vbus_output); + static void axp_usb_ac_check_status(struct axp_charger *charger) { if (!axp_config->pmu_init_bc_en) { @@ -278,4 +284,3 @@ void axp_chg_exit(struct axp_charger *charger) } return; } - diff --git a/drivers/power/axp_power/axp-interface.c b/drivers/power/axp_power/axp-interface.c index d97d6bb9ccd..e41ab627271 100755 --- a/drivers/power/axp_power/axp-interface.c +++ b/drivers/power/axp_power/axp-interface.c @@ -8,6 +8,7 @@ s32 axp_usbcur(aw_charge_type type){ return 0; }; s32 axp_usbvol(aw_charge_type type){ return 0; }; s32 axp_usb_det(void){ return 0; }; +s32 axp_usb_vbus_output(int high){ return 0; }; s32 axp_powerkey_get(void){ return 0; }; void axp_powerkey_set(int value){}; u64 axp_read_power_sply(void){ return 0; }; diff --git a/drivers/usb/host/ehci_sunxi.c b/drivers/usb/host/ehci_sunxi.c index 34e01ca7359..730159e572a 100755 --- a/drivers/usb/host/ehci_sunxi.c +++ b/drivers/usb/host/ehci_sunxi.c @@ -33,18 +33,30 @@ static struct scene_lock ehci_standby_lock[4]; #define SUNXI_EHCI_NAME "sunxi-ehci" static const char ehci_name[] = SUNXI_EHCI_NAME; -#ifdef CONFIG_USB_SUNXI_EHCI0 +#ifdef CONFIG_USB_SUNXI_EHCI0 #define SUNXI_EHCI0_OF_MATCH "allwinner,sunxi-ehci0" #else #define SUNXI_EHCI0_OF_MATCH "null" #endif -#ifdef CONFIG_USB_SUNXI_EHCI1 +#ifdef CONFIG_USB_SUNXI_EHCI1 #define SUNXI_EHCI1_OF_MATCH "allwinner,sunxi-ehci1" #else #define SUNXI_EHCI1_OF_MATCH "null" #endif +#ifdef CONFIG_USB_SUNXI_EHCI2 +#define SUNXI_EHCI2_OF_MATCH "allwinner,sunxi-ehci2" +#else +#define SUNXI_EHCI2_OF_MATCH "null" +#endif + +#ifdef CONFIG_USB_SUNXI_EHCI3 +#define SUNXI_EHCI3_OF_MATCH "allwinner,sunxi-ehci3" +#else +#define SUNXI_EHCI3_OF_MATCH "null" +#endif + static struct sunxi_hci_hcd *g_sunxi_ehci[4]; static u32 ehci_first_probe[4] = {1, 1, 1, 1}; static u32 ehci_enable[4] = {1, 1, 1, 1}; @@ -641,7 +653,7 @@ static int sunxi_ehci_hcd_probe(struct platform_device *pdev) ret = init_sunxi_hci(pdev, SUNXI_USB_EHCI); if(ret != 0){ dev_err(&pdev->dev, "init_sunxi_hci is fail\n"); - return 0; + return -1; } sunxi_insmod_ehci(pdev); @@ -699,11 +711,11 @@ static void sunxi_ehci_hcd_shutdown(struct platform_device* pdev) } if(sunxi_ehci->probe == 0){ - DMSG_PANIC("ERR: %s, %s is disable, need not shutdown\n", __func__, sunxi_ehci->hci_name); + DMSG_INFO("%s, %s is disable, need not shutdown\n", __func__, sunxi_ehci->hci_name); return; } - DMSG_INFO("[%s]: ehci shutdown start\n", sunxi_ehci->hci_name); + pr_debug("[%s]: ehci shutdown start\n", sunxi_ehci->hci_name); #ifdef CONFIG_PM if(sunxi_ehci->wakeup_suspend){ scene_lock_destroy(&ehci_standby_lock[sunxi_ehci->usbc_no]); @@ -711,9 +723,14 @@ static void sunxi_ehci_hcd_shutdown(struct platform_device* pdev) #endif usb_hcd_platform_shutdown(pdev); - sunxi_stop_ehci(sunxi_ehci); + /* disable usb otg INTUSBE, To solve usb0 device mode catch audio udev on reboot system is fail*/ + if (sunxi_ehci->usbc_no == 0) + if (sunxi_ehci->otg_vbase) { + writel(0, (sunxi_ehci->otg_vbase + + SUNXI_USBC_REG_INTUSBE)); + } - DMSG_INFO("[%s]: ehci shutdown end\n", sunxi_ehci->hci_name); + pr_debug("[%s]: ehci shutdown end\n", sunxi_ehci->hci_name); return ; } @@ -745,7 +762,8 @@ static int sunxi_ehci_hcd_suspend(struct device *dev) } if(sunxi_ehci->probe == 0){ - DMSG_PANIC("[%s]: is disable, can not suspend\n", sunxi_ehci->hci_name); + DMSG_INFO("[%s]: is disable, can not suspend\n", + sunxi_ehci->hci_name); return 0; } @@ -796,7 +814,8 @@ static int sunxi_ehci_hcd_resume(struct device *dev) } if(sunxi_ehci->probe == 0){ - DMSG_PANIC("[%s]: is disable, can not resume\n", sunxi_ehci->hci_name); + DMSG_INFO("[%s]: is disable, can not resume\n", + sunxi_ehci->hci_name); return 0; } @@ -840,6 +859,8 @@ static const struct dev_pm_ops aw_ehci_pmops = { static const struct of_device_id sunxi_ehci_match[] = { {.compatible = SUNXI_EHCI0_OF_MATCH, }, {.compatible = SUNXI_EHCI1_OF_MATCH, }, + {.compatible = SUNXI_EHCI2_OF_MATCH, }, + {.compatible = SUNXI_EHCI3_OF_MATCH, }, {}, }; MODULE_DEVICE_TABLE(of, sunxi_ehci_match); @@ -905,4 +926,3 @@ int sunxi_usb_enable_ehci(__u32 usbc_no) return 0; } EXPORT_SYMBOL(sunxi_usb_enable_ehci); - diff --git a/drivers/usb/host/ohci_sunxi.c b/drivers/usb/host/ohci_sunxi.c index 625e2c55800..dea951df535 100755 --- a/drivers/usb/host/ohci_sunxi.c +++ b/drivers/usb/host/ohci_sunxi.c @@ -40,13 +40,24 @@ static const char ohci_name[] = SUNXI_OHCI_NAME; #define SUNXI_OHCI0_OF_MATCH "null" #endif - #if defined CONFIG_USB_SUNXI_OHCI1 && !defined SUNXI_USB_FPGA #define SUNXI_OHCI1_OF_MATCH "allwinner,sunxi-ohci1" #else #define SUNXI_OHCI1_OF_MATCH "null" #endif +#if defined CONFIG_USB_SUNXI_OHCI2 && !defined SUNXI_USB_FPGA +#define SUNXI_OHCI2_OF_MATCH "allwinner,sunxi-ohci2" +#else +#define SUNXI_OHCI2_OF_MATCH "null" +#endif + +#if defined CONFIG_USB_SUNXI_OHCI3 && !defined SUNXI_USB_FPGA +#define SUNXI_OHCI3_OF_MATCH "allwinner,sunxi-ohci3" +#else +#define SUNXI_OHCI3_OF_MATCH "null" +#endif + static struct sunxi_hci_hcd *g_sunxi_ohci[4]; static u32 ohci_first_probe[4] = {1, 1, 1, 1}; static u32 ohci_enable[4] = {1, 1, 1, 1}; @@ -359,12 +370,11 @@ static int sunxi_ohci_hcd_probe(struct platform_device *pdev) ret = init_sunxi_hci(pdev, SUNXI_USB_OHCI); if(ret != 0){ dev_err(&pdev->dev, "init_sunxi_hci is fail\n"); - return 0; + return -1; } sunxi_insmod_ohci(pdev); - sunxi_ohci = pdev->dev.platform_data; if(sunxi_ohci == NULL){ DMSG_PANIC("ERR: %s, sunxi_ohci is null\n", __func__); @@ -406,16 +416,16 @@ static void sunxi_ohci_hcd_shutdown(struct platform_device* pdev) sunxi_ohci = pdev->dev.platform_data; if(sunxi_ohci == NULL){ - DMSG_PANIC("ERR: sunxi_ohci is null\n"); + DMSG_PANIC("ERR: %s sunxi_ohci is null\n", __func__); return ; } if(sunxi_ohci->probe == 0){ - DMSG_PANIC("ERR: %s, %s is disable, need not shutdown\n", __func__, sunxi_ohci->hci_name); + DMSG_INFO("%s, %s is disable, need not shutdown\n", __func__, sunxi_ohci->hci_name); return ; } - DMSG_INFO("[%s]: ohci shutdown start\n", sunxi_ohci->hci_name); + pr_debug("[%s]: ohci shutdown start\n", sunxi_ohci->hci_name); #ifdef CONFIG_PM if(sunxi_ohci->wakeup_suspend){ @@ -423,9 +433,15 @@ static void sunxi_ohci_hcd_shutdown(struct platform_device* pdev) } #endif usb_hcd_platform_shutdown(pdev); - sunxi_stop_ohci(sunxi_ohci); - DMSG_INFO("[%s]: ohci shutdown end\n", sunxi_ohci->hci_name); + /* disable usb otg INTUSBE, To solve usb0 device mode catch audio udev on reboot system is fail*/ + if (sunxi_ohci->usbc_no == 0) + if (sunxi_ohci->otg_vbase) { + writel(0, (sunxi_ohci->otg_vbase + + SUNXI_USBC_REG_INTUSBE)); + } + + pr_debug("[%s]: ohci shutdown end\n", sunxi_ohci->hci_name); return; } @@ -457,7 +473,8 @@ static int sunxi_ohci_hcd_suspend(struct device *dev) } if(sunxi_ohci->probe == 0){ - DMSG_PANIC("[%s]: is disable, can not suspend\n", sunxi_ohci->hci_name); + DMSG_INFO("[%s]: is disable, can not suspend\n", + sunxi_ohci->hci_name); return 0; } @@ -480,6 +497,11 @@ static int sunxi_ohci_hcd_suspend(struct device *dev) val |= OHCI_INTR_RD; val |= OHCI_INTR_MIE; ohci_writel(ohci, val, &ohci->regs->intrenable); + + if(sunxi_ohci->clk_usbohci12m && sunxi_ohci->clk_losc){ + clk_set_parent(sunxi_ohci->clk_usbohci12m, sunxi_ohci->clk_losc); + } + }else{ DMSG_INFO("[%s]: sunxi_ohci_hcd_suspend\n", sunxi_ohci->hci_name); @@ -522,13 +544,18 @@ static int sunxi_ohci_hcd_resume(struct device *dev) } if(sunxi_ohci->probe == 0){ - DMSG_PANIC("[%s]: is disable, can not resume\n", sunxi_ohci->hci_name); + DMSG_INFO("[%s]: is disable, can not resume\n", + sunxi_ohci->hci_name); return 0; } if(sunxi_ohci->wakeup_suspend){ DMSG_INFO("[%s]: controller not suspend, need not resume\n", sunxi_ohci->hci_name); + if(sunxi_ohci->clk_usbohci12m && sunxi_ohci->clk_hoscx2){ + clk_set_parent(sunxi_ohci->clk_usbohci12m, sunxi_ohci->clk_hoscx2); + } + scene_unlock(&ohci_standby_lock[sunxi_ohci->usbc_no]); disable_wakeup_src(CPUS_USBMOUSE_SRC, 0); @@ -563,6 +590,8 @@ static const struct dev_pm_ops sunxi_ohci_pmops = { static const struct of_device_id sunxi_ohci_match[] = { {.compatible = SUNXI_OHCI0_OF_MATCH, }, {.compatible = SUNXI_OHCI1_OF_MATCH, }, + {.compatible = SUNXI_OHCI2_OF_MATCH, }, + {.compatible = SUNXI_OHCI3_OF_MATCH, }, {}, }; MODULE_DEVICE_TABLE(of, sunxi_ohci_match); @@ -629,4 +658,3 @@ int sunxi_usb_enable_ohci(__u32 usbc_no) return 0; } EXPORT_SYMBOL(sunxi_usb_enable_ohci); - diff --git a/drivers/usb/host/sunxi_hci.c b/drivers/usb/host/sunxi_hci.c index c2f17b71537..3221e3d561e 100755 --- a/drivers/usb/host/sunxi_hci.c +++ b/drivers/usb/host/sunxi_hci.c @@ -49,7 +49,7 @@ static DEFINE_MUTEX(usb_vbus_lock); static DEFINE_MUTEX(usb_clock_lock); #ifndef CONFIG_OF -static char* usbc_name[2] = {"usbc0", "usbc1"}; +static char *usbc_name[4] = {"usbc0", "usbc1", "usbc2", "usbc3"}; #endif #ifdef CONFIG_USB_SUNXI_USB_MANAGER @@ -58,16 +58,24 @@ int usb_otg_id_status(void); static struct sunxi_hci_hcd sunxi_ohci0; static struct sunxi_hci_hcd sunxi_ohci1; +static struct sunxi_hci_hcd sunxi_ohci2; +static struct sunxi_hci_hcd sunxi_ohci3; static struct sunxi_hci_hcd sunxi_ehci0; static struct sunxi_hci_hcd sunxi_ehci1; +static struct sunxi_hci_hcd sunxi_ehci2; +static struct sunxi_hci_hcd sunxi_ehci3; #define USBPHYC_REG_o_PHYCTL 0x0404 -atomic_t usb1_set_vbus_cnt; -atomic_t usb2_set_vbus_cnt; +atomic_t usb1_set_vbus_cnt = ATOMIC_INIT(0); +atomic_t usb2_set_vbus_cnt = ATOMIC_INIT(0); +atomic_t usb3_set_vbus_cnt = ATOMIC_INIT(0); +atomic_t usb4_set_vbus_cnt = ATOMIC_INIT(0); -atomic_t usb1_enable_passly_cnt; -atomic_t usb2_enable_passly_cnt; +atomic_t usb1_enable_passly_cnt = ATOMIC_INIT(0); +atomic_t usb2_enable_passly_cnt = ATOMIC_INIT(0); +atomic_t usb3_enable_passly_cnt = ATOMIC_INIT(0); +atomic_t usb4_enable_passly_cnt = ATOMIC_INIT(0); static s32 request_usb_regulator_io(struct sunxi_hci_hcd *sunxi_hci) { @@ -150,6 +158,14 @@ void __iomem *usb_phy_csr_write(struct sunxi_hci_hcd *sunxi_hci) return sunxi_hci->usb_vbase + SUNXI_HCI_PHY_CTRL; break; + case 2: + return sunxi_hci->usb_vbase + SUNXI_HCI_PHY_CTRL; + break; + + case 3: + return sunxi_hci->usb_vbase + SUNXI_HCI_PHY_CTRL; + break; + default: DMSG_PANIC("usb_phy_csr_write is fial in %d index\n", sunxi_hci->usbc_no); break; @@ -415,9 +431,49 @@ static int usb_get_hsic_phy_ctrl(int value, int enable) return value; } -static void usb_passby(struct sunxi_hci_hcd *sunxi_hci, u32 enable) +static void __usb_passby(struct sunxi_hci_hcd *sunxi_hci, u32 enable, + atomic_t *usb_enable_passly_cnt) { unsigned long reg_value = 0; + + reg_value = USBC_Readl(sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE); + if (enable && (atomic_read(usb_enable_passly_cnt) == 0)) { + if (sunxi_hci->hsic_flag) { + reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); + } else { + reg_value |= (1 << 10); /* AHB Master interface INCR8 enable */ + reg_value |= (1 << 9); /* AHB Master interface burst type INCR4 enable */ + reg_value |= (1 << 8); /* AHB Master interface INCRX align enable */ + if (sunxi_hci->usbc_no == HCI0_USBC_NO) +#ifdef SUNXI_USB_FPGA + reg_value |= (0 << 0); /* enable ULPI, disable UTMI */ +#else + reg_value |= (1 << 0); /* enable UTMI, disable ULPI */ +#endif + else + reg_value |= (1 << 0); /* ULPI bypass enable */ + } + } else if (!enable && (atomic_read(usb_enable_passly_cnt) == 1)) { + if (sunxi_hci->hsic_flag) { + reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); + } else { + reg_value &= ~(1 << 10); /* AHB Master interface INCR8 disable */ + reg_value &= ~(1 << 9); /* AHB Master interface burst type INCR4 disable */ + reg_value &= ~(1 << 8); /* AHB Master interface INCRX align disable */ + reg_value &= ~(1 << 0); /* ULPI bypass disable */ + } + } + USBC_Writel(reg_value, (sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE)); + + if (enable) { + atomic_add(1, usb_enable_passly_cnt); + } else { + atomic_sub(1, usb_enable_passly_cnt); + } +} + +static void usb_passby(struct sunxi_hci_hcd *sunxi_hci, u32 enable) +{ spinlock_t lock; unsigned long flags = 0; @@ -427,67 +483,15 @@ static void usb_passby(struct sunxi_hci_hcd *sunxi_hci, u32 enable) spin_lock_irqsave(&lock, flags); /*enable passby*/ - if(sunxi_hci->usbc_no == HCI0_USBC_NO){ - reg_value = USBC_Readl(sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE); - if(enable && (atomic_read(&usb1_enable_passly_cnt) == 0)){ - if(sunxi_hci->hsic_flag){ - reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); - }else{ - reg_value |= (1 << 10); /* AHB Master interface INCR8 enable */ - reg_value |= (1 << 9); /* AHB Master interface burst type INCR4 enable */ - reg_value |= (1 << 8); /* AHB Master interface INCRX align enable */ -#ifdef SUNXI_USB_FPGA - reg_value |= (0 << 0); /* enable ULPI, disable UTMI */ -#else - reg_value |= (1 << 0); /* enable UTMI, disable ULPI */ -#endif - } - }else if(!enable && (atomic_read(&usb1_enable_passly_cnt) == 1)){ - if(sunxi_hci->hsic_flag){ - reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); - }else{ - reg_value &= ~(1 << 10); /* AHB Master interface INCR8 disable */ - reg_value &= ~(1 << 9); /* AHB Master interface burst type INCR4 disable */ - reg_value &= ~(1 << 8); /* AHB Master interface INCRX align disable */ - reg_value &= ~(1 << 0); /* ULPI bypass disable */ - } - } - USBC_Writel(reg_value, (sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE)); - - if(enable){ - atomic_add(1, &usb1_enable_passly_cnt); - }else{ - atomic_sub(1, &usb1_enable_passly_cnt); - } - }else if(sunxi_hci->usbc_no == HCI1_USBC_NO){ - reg_value = USBC_Readl(sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE); - if(enable && (atomic_read(&usb2_enable_passly_cnt) == 0)){ - if(sunxi_hci->hsic_flag){ - reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); - }else{ - reg_value |= (1 << 10); /* AHB Master interface INCR8 enable */ - reg_value |= (1 << 9); /* AHB Master interface burst type INCR4 enable */ - reg_value |= (1 << 8); /* AHB Master interface INCRX align enable */ - reg_value |= (1 << 0); /* ULPI bypass enable */ - } - }else if(!enable && (atomic_read(&usb2_enable_passly_cnt) == 1)){ - if(sunxi_hci->hsic_flag){ - reg_value = usb_get_hsic_phy_ctrl(reg_value, enable); - }else{ - reg_value &= ~(1 << 10); /* AHB Master interface INCR8 disable */ - reg_value &= ~(1 << 9); /* AHB Master interface burst type INCR4 disable */ - reg_value &= ~(1 << 8); /* AHB Master interface INCRX align disable */ - reg_value &= ~(1 << 0); /* ULPI bypass disable */ - } - } - USBC_Writel(reg_value, (sunxi_hci->usb_vbase + SUNXI_USB_PMU_IRQ_ENABLE)); - - if(enable){ - atomic_add(1, &usb2_enable_passly_cnt); - }else{ - atomic_sub(1, &usb2_enable_passly_cnt); - } - }else{ + if (sunxi_hci->usbc_no == HCI0_USBC_NO) { + __usb_passby(sunxi_hci, enable, &usb1_enable_passly_cnt); + } else if (sunxi_hci->usbc_no == HCI1_USBC_NO) { + __usb_passby(sunxi_hci, enable, &usb2_enable_passly_cnt); + } else if (sunxi_hci->usbc_no == HCI2_USBC_NO) { + __usb_passby(sunxi_hci, enable, &usb3_enable_passly_cnt); + } else if (sunxi_hci->usbc_no == HCI3_USBC_NO) { + __usb_passby(sunxi_hci, enable, &usb4_enable_passly_cnt); + } else { DMSG_PANIC("EER: unkown usbc_no(%d)\n", sunxi_hci->usbc_no); spin_unlock_irqrestore(&lock, flags); @@ -616,8 +620,14 @@ void sunxi_set_host_hisc_rdy(struct sunxi_hci_hcd *sunxi_hci, int is_on) void sunxi_set_host_vbus(struct sunxi_hci_hcd *sunxi_hci, int is_on) { - if(sunxi_hci->drv_vbus_gpio_valid){ - __gpio_set_value(sunxi_hci->drv_vbus_gpio_set.gpio.gpio, is_on); + if (sunxi_hci->drv_vbus_type == USB_DRV_VBUS_TYPE_GIPO) { + if (sunxi_hci->drv_vbus_gpio_valid) + __gpio_set_value(sunxi_hci->drv_vbus_gpio_set.gpio.gpio, + is_on); + } else if (sunxi_hci->drv_vbus_type == USB_DRV_VBUS_TYPE_AXP) { +#if defined(CONFIG_AW_AXP) + axp_usb_vbus_output(is_on); +#endif } } @@ -666,8 +676,14 @@ static void __sunxi_set_vbus(struct sunxi_hci_hcd *sunxi_hci, int is_on) } #endif - if(sunxi_hci->drv_vbus_gpio_valid){ - __gpio_set_value(sunxi_hci->drv_vbus_gpio_set.gpio.gpio, is_on); + if (sunxi_hci->drv_vbus_type == USB_DRV_VBUS_TYPE_GIPO) { + if (sunxi_hci->drv_vbus_gpio_valid) + __gpio_set_value(sunxi_hci->drv_vbus_gpio_set.gpio.gpio, + is_on); + } else if (sunxi_hci->drv_vbus_type == USB_DRV_VBUS_TYPE_AXP) { +#if defined(CONFIG_AW_AXP) + axp_usb_vbus_output(is_on); +#endif } return; @@ -706,7 +722,27 @@ static void sunxi_set_vbus(struct sunxi_hci_hcd *sunxi_hci, int is_on) }else{ atomic_sub(1, &usb2_set_vbus_cnt); } - }else{ + } else if (sunxi_hci->usbc_no == HCI2_USBC_NO) { + if (is_on && (atomic_read(&usb3_set_vbus_cnt) == 0)) + __sunxi_set_vbus(sunxi_hci, is_on); /* power on */ + else if (!is_on && atomic_read(&usb3_set_vbus_cnt) == 1) + __sunxi_set_vbus(sunxi_hci, is_on); /* power off */ + + if (is_on) + atomic_add(1, &usb3_set_vbus_cnt); + else + atomic_sub(1, &usb3_set_vbus_cnt); + } else if (sunxi_hci->usbc_no == HCI3_USBC_NO) { + if (is_on && (atomic_read(&usb4_set_vbus_cnt) == 0)) + __sunxi_set_vbus(sunxi_hci, is_on); /* power on */ + else if (!is_on && atomic_read(&usb4_set_vbus_cnt) == 1) + __sunxi_set_vbus(sunxi_hci, is_on); /* power off */ + + if (is_on) + atomic_add(1, &usb4_set_vbus_cnt); + else + atomic_sub(1, &usb4_set_vbus_cnt); + } else { DMSG_INFO("[%s]: sunxi_set_vbus no: %d\n", sunxi_hci->hci_name, sunxi_hci->usbc_no); } @@ -747,6 +783,38 @@ static int sunxi_get_hci_base(struct platform_device *pdev, struct sunxi_hci_hcd return 0; } +static int sunxi_get_ohci_clock_src(struct platform_device *pdev, struct sunxi_hci_hcd *sunxi_hci) +{ + struct device_node *np = pdev->dev.of_node; + + sunxi_hci->clk_usbohci12m = of_clk_get(np, 2); + if (IS_ERR(sunxi_hci->clk_usbohci12m)) { + sunxi_hci->clk_usbohci12m = NULL; + DMSG_INFO("%s get usb clk_usbohci12m clk failed.\n", sunxi_hci->hci_name); + } + + sunxi_hci->clk_hoscx2 = of_clk_get(np, 3); + if (IS_ERR(sunxi_hci->clk_hoscx2)) { + sunxi_hci->clk_hoscx2 = NULL; + DMSG_INFO("%s get usb clk_hoscx2 clk failed.\n", sunxi_hci->hci_name); + } + + sunxi_hci->clk_hosc = of_clk_get(np, 4); + if (IS_ERR(sunxi_hci->clk_hosc)) { + sunxi_hci->clk_hosc = NULL; + DMSG_INFO("%s get usb clk_hosc failed.\n", sunxi_hci->hci_name); + } + + sunxi_hci->clk_losc = of_clk_get(np, 5); + if (IS_ERR(sunxi_hci->clk_losc)) { + sunxi_hci->clk_losc = NULL; + DMSG_INFO("%s get usb clk_losc clk failed.\n", sunxi_hci->hci_name); + } + + return 0; +} + + static int sunxi_get_hci_clock(struct platform_device *pdev, struct sunxi_hci_hcd *sunxi_hci) { struct device_node *np = pdev->dev.of_node; @@ -822,7 +890,6 @@ static int get_usb_cfg(struct platform_device *pdev, struct sunxi_hci_hcd *sunxi if(sunxi_hci->usbc_no == HCI1_USBC_NO){ ret = of_property_read_u32(usbc_np, KEY_USB_HSIC_USBED, &sunxi_hci->hsic_flag); if (ret) { - DMSG_PRINT("get %s usb_hsic_used is fail, %d\n", sunxi_hci->hci_name, -ret); sunxi_hci->hsic_flag = 0; } @@ -919,12 +986,27 @@ static int get_usb_cfg(struct platform_device *pdev, struct sunxi_hci_hcd *sunxi DMSG_PRINT("get %s wakeup_suspend is fail, %d\n", sunxi_hci->hci_name, -ret); } - sunxi_hci->drv_vbus_gpio_set.gpio.gpio = of_get_named_gpio(usbc_np, KEY_USB_DRVVBUS_GPIO, 0); - if(gpio_is_valid(sunxi_hci->drv_vbus_gpio_set.gpio.gpio)){ - sunxi_hci->drv_vbus_gpio_valid = 1; - }else{ + /* usbc drv_vbus */ + ret = of_property_read_string(usbc_np, KEY_USB_DRVVBUS_GPIO, + &sunxi_hci->drv_vbus_name); + if (ret) { + DMSG_PRINT("get drv_vbus is fail, %d\n", -ret); sunxi_hci->drv_vbus_gpio_valid = 0; - DMSG_PRINT("get %s drv_vbus_gpio is fail\n", sunxi_hci->hci_name); + } else { + if (strncmp(sunxi_hci->drv_vbus_name, "axp_ctrl", 8) == 0) { + sunxi_hci->drv_vbus_type = USB_DRV_VBUS_TYPE_AXP; + sunxi_hci->drv_vbus_gpio_valid = 0; + } else { + /* get drv vbus gpio */ + sunxi_hci->drv_vbus_gpio_set.gpio.gpio = of_get_named_gpio(usbc_np, + KEY_USB_DRVVBUS_GPIO, 0); + if (gpio_is_valid(sunxi_hci->drv_vbus_gpio_set.gpio.gpio)) { + sunxi_hci->drv_vbus_gpio_valid = 1; + sunxi_hci->drv_vbus_type = USB_DRV_VBUS_TYPE_GIPO; + } else { + sunxi_hci->drv_vbus_gpio_valid = 0; + } + } } /* usbc regulator_io */ @@ -969,16 +1051,30 @@ static int get_usb_cfg(struct platform_device *pdev, struct sunxi_hci_hcd *sunxi sunxi_hci->not_suspend = 0; } - /* usbc drv_vbus */ type = script_get_item(usbc_name[sunxi_hci->usbc_no], KEY_USB_DRVVBUS_GPIO, &sunxi_hci->drv_vbus_gpio_set); - if(type == SCIRPT_ITEM_VALUE_TYPE_PIO){ + if (type == SCIRPT_ITEM_VALUE_TYPE_PIO) { sunxi_hci->drv_vbus_gpio_valid = 1; - }else{ - DMSG_INFO("%s(drv vbus) is invalid\n", sunxi_hci->hci_name); + sunxi_hci->drv_vbus_type = USB_DRV_VBUS_TYPE_GIPO; + } else { sunxi_hci->drv_vbus_gpio_valid = 0; + sunxi_hci->drv_vbus_type = USB_DRV_VBUS_TYPE_NULL; } + if (sunxi_hci->drv_vbus_gpio_valid == 0) { + type = script_get_item(usbc_name[sunxi_hci->usbc_no], + KEY_USB_DRVVBUS_GPIO, + &sunxi_hci->drv_vbus_gpio_set); + if (type == SCIRPT_ITEM_VALUE_TYPE_STR) { + if (strncmp(item_temp.str, "axp_ctrl", 8) == 0) + sunxi_hci->drv_vbus_type = USB_DET_VBUS_TYPE_AXP; + else + sunxi_hci->drv_vbus_type = USB_DET_VBUS_TYPE_NULL; + } else { + DMSG_INFO("%s(drv vbus) is invalid\n", sunxi_hci->hci_name); + sunxi_hci->drv_vbus_type = USB_DET_VBUS_TYPE_NULL; + } + } /* get regulator io information */ type = script_get_item(usbc_name[sunxi_hci->usbc_no], KEY_USB_REGULATOR_IO, &item_temp); @@ -1118,12 +1214,6 @@ int init_sunxi_hci(struct platform_device *pdev, int usbc_type) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); #endif - atomic_set(&usb1_set_vbus_cnt, 0); - atomic_set(&usb2_set_vbus_cnt, 0); - - atomic_set(&usb1_enable_passly_cnt, 0); - atomic_set(&usb2_enable_passly_cnt, 0); - hci_num = sunxi_get_hci_num(pdev); switch(hci_num){ @@ -1151,6 +1241,30 @@ int init_sunxi_hci(struct platform_device *pdev, int usbc_type) } break; + case HCI2_USBC_NO: + usbc_no = HCI2_USBC_NO; + if (usbc_type == SUNXI_USB_EHCI) { + sunxi_hci = &sunxi_ehci2; + } else if (usbc_type == SUNXI_USB_OHCI) { + sunxi_hci = &sunxi_ohci2; + } else { + dev_err(&pdev->dev, "get hci num fail: %d\n", hci_num); + return -1; + } + break; + + case HCI3_USBC_NO: + usbc_no = HCI3_USBC_NO; + if (usbc_type == SUNXI_USB_EHCI) { + sunxi_hci = &sunxi_ehci3; + } else if (usbc_type == SUNXI_USB_OHCI) { + sunxi_hci = &sunxi_ohci3; + } else { + dev_err(&pdev->dev, "get hci num fail: %d\n", hci_num); + return -1; + } + break; + default: dev_err(&pdev->dev, "get hci num fail: %d\n", hci_num); return -1; @@ -1158,7 +1272,13 @@ int init_sunxi_hci(struct platform_device *pdev, int usbc_type) } ret = sunxi_get_hci_resource(pdev, sunxi_hci, usbc_no); + if (ret != 0) + return ret; + + + if(usbc_type == SUNXI_USB_OHCI){ + ret = sunxi_get_ohci_clock_src(pdev, sunxi_hci); + } return ret; } - diff --git a/drivers/usb/host/sunxi_hci.h b/drivers/usb/host/sunxi_hci.h index a85c352eb07..a6703ade283 100755 --- a/drivers/usb/host/sunxi_hci.h +++ b/drivers/usb/host/sunxi_hci.h @@ -4,7 +4,7 @@ * Allwinner Technology Co., Ltd. * yangnaitian, 2011-5-24, create this file * - * Include file for AW1623 HCI Host Controller Driver + * Include file for SUNXI HCI Host Controller Driver * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -24,6 +24,10 @@ #include #include +#if defined(CONFIG_AW_AXP) +extern s32 axp_usb_vbus_output(int high); +#endif + #define DMSG_ERR(format,args...) pr_err("hci: "format,##args) #define DMSG_PRINT(stuff...) printk(stuff) @@ -85,6 +89,7 @@ #define SUNXI_OTG_PHY_CTRL 0x410 #define SUNXI_OTG_PHY_CFG 0x420 #define SUNXI_OTG_PHY_STATUS 0x424 +#define SUNXI_USBC_REG_INTUSBE 0x0050 #define EHCI_CAP_OFFSET (0x00) #define EHCI_CAP_LEN (0x10) @@ -167,6 +172,12 @@ enum sunxi_usbc_type{ SUNXI_USB_OHCI, }; +enum usb_drv_vbus_type { + USB_DRV_VBUS_TYPE_NULL = 0, + USB_DRV_VBUS_TYPE_GIPO, + USB_DRV_VBUS_TYPE_AXP, +}; + struct sunxi_hci_hcd{ __u32 usbc_no; /* usb controller number */ __u32 irq_no; /* interrupt number */ @@ -215,7 +226,12 @@ struct sunxi_hci_hcd{ struct clk *mod_usbphy; /* PHY0 clock handle */ struct clk *hsic_usbphy; /* hsic clock handle */ struct clk *pll_hsic; /* pll_hsic clock handle */ - struct clk *clk_usbhsic12m; /* pll_hsic clock handle */ + struct clk *clk_usbhsic12m; /* pll_hsic clock handle */ + + struct clk *clk_usbohci12m; /* clk_usbohci12m clock handle */ + struct clk *clk_hoscx2; /* clk_hoscx2 clock handle */ + struct clk *clk_hosc; /* clk_hosc clock handle */ + struct clk *clk_losc; /* clk_losc clock handle */ __u32 clk_is_open; /* is usb clock open */ @@ -225,6 +241,8 @@ struct sunxi_hci_hcd{ const char *used_status; int regulator_value; struct regulator* regulator_io_hdle; + enum usb_drv_vbus_type drv_vbus_type; + const char *drv_vbus_name; u32 drv_vbus_gpio_valid; u32 usb_restrict_valid; __u8 power_flag; /* flag. power on or not */ @@ -289,4 +307,3 @@ int usb_phyx_tp_write(struct sunxi_hci_hcd *sunxi_hci, int addr, int data, int l int usb_phyx_tp_read(struct sunxi_hci_hcd *sunxi_hci, int addr, int len); #endif //__SUNXI_HCI_SUNXI_H__ -