diff options
Diffstat (limited to 'arch/arm/mach-mx5/usb_dr.c')
-rw-r--r-- | arch/arm/mach-mx5/usb_dr.c | 176 |
1 files changed, 159 insertions, 17 deletions
diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c index 658583b65ab6..4f36379b8d64 100644 --- a/arch/arm/mach-mx5/usb_dr.c +++ b/arch/arm/mach-mx5/usb_dr.c @@ -18,12 +18,12 @@ #include <linux/fsl_devices.h> #include <mach/arc_otg.h> #include <mach/hardware.h> +#include <asm/delay.h> #include "usb.h" #if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC) static int usbotg_init_ext(struct platform_device *pdev); static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata); -static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable); static void usbotg_clock_gate(bool on); /* @@ -40,7 +40,6 @@ static struct fsl_usb2_platform_data dr_utmi_config = { .gpio_usb_active = gpio_usbotg_hs_active, .gpio_usb_inactive = gpio_usbotg_hs_inactive, .usb_clock_for_pm = usbotg_clock_gate, - .wake_up_enable = _wake_up_enable, .transceiver = "utmi", }; @@ -48,6 +47,13 @@ static struct fsl_usb2_platform_data dr_utmi_config = { static int usbotg_init_ext(struct platform_device *pdev) { struct clk *usb_clk; + if (cpu_is_mx50()) { + usb_clk = clk_get(&pdev->dev, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + return usbotg_init(pdev); + } usb_clk = clk_get(NULL, "usboh3_clk"); clk_enable(usb_clk); @@ -69,6 +75,15 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) { struct clk *usb_clk; + if (cpu_is_mx50()) { + usb_clk = clk_get(&pdata->pdev->dev, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usbotg_uninit(pdata); + return; + } + usb_clk = clk_get(NULL, "usboh3_clk"); clk_disable(usb_clk); clk_put(usb_clk); @@ -80,33 +95,149 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata) usbotg_uninit(pdata); } -static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +#define ENABLED_BY_HOST (0x1 << 0) +#define ENABLED_BY_DEVICE (0x1 << 1) +#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC) +/* Below two macros are used at otg mode to indicate usb mode*/ +static u32 wakeup_irq_enable_src = 0; +static void __wakeup_irq_enable(bool on, int source) { - if (get_usb_mode(pdata) == FSL_USB_DR_DEVICE) { - if (enable) { + /* otg host and device share the OWIE bit, only when host and device + * all enable the wakeup irq, we can enable the OWIE bit + */ + if (on) { + wakeup_irq_enable_src |= source; + if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { USBCTRL |= UCTRL_OWIE; - USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; - } else { - USBCTRL &= ~UCTRL_OWIE; - USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; - USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + printk("OTG wakeup irq is enabled\n"); } - } else { - if (enable) { - USBCTRL |= UCTRL_OWIE; - USBCTRL_HOST2 |= (1 << 5); - } else { - USBCTRL &= ~UCTRL_OWIE; - USBCTRL_HOST2 &= ~(1 << 5); + }else { + printk("OTG wakeup irq disable\n"); + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + USBCTRL &= ~UCTRL_OWIE; + wakeup_irq_enable_src &= ~source; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} +#else +static void __wakeup_irq_enable(bool on, int source) +{ + if (on) { + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; + }else { + USBCTRL &= ~UCTRL_OWIE; + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} +#endif + +#ifdef CONFIG_USB_EHCI_ARC_OTG +static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_HOST); + /* host only care the ID change wakeup event */ + if (enable) { + USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN; + }else { + USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN; + /* The interrupt must be disabled for at least 2 clock + * cycles of the standby clock(32k Hz) , that is 0.0625 ms*/ + udelay(100); + } +} +#endif + +#ifdef CONFIG_USB_GADGET_ARC +static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_DEVICE); + /* if udc is not used by any gadget, we can not enable the vbus wakeup */ + if (!pdata->port_enables) + { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + return; + } + if (enable) { + USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; + }else { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + } +} +#endif + +#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC) +static u32 low_power_enable_src = 0; +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + low_power_enable_src |= source; + if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + UOG_PORTSC1 |= PORTSC_PHCD; + printk("OTG phy lowpower enable\n"); } + }else { + printk("OTG phy lowpower disable\n"); + UOG_PORTSC1 &= ~PORTSC_PHCD; + low_power_enable_src &= ~source; + } +} +#else +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + UOG_PORTSC1 |= PORTSC_PHCD; + }else { + UOG_PORTSC1 &= ~PORTSC_PHCD; } } +#endif + +#ifdef CONFIG_USB_EHCI_ARC_OTG +static void _host_phy_lowpower_suspend(bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_HOST); +} +#endif + +#ifdef CONFIG_USB_GADGET_ARC +static void _device_phy_lowpower_suspend(bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE); +} +#endif static void usbotg_clock_gate(bool on) { struct clk *usb_clk; + if (cpu_is_mx50()) { + if (on) { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } else { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } + return; + } + if (on) { usb_clk = clk_get(NULL, "usb_ahb_clk"); clk_enable(usb_clk); @@ -140,6 +271,13 @@ static void usbotg_clock_gate(bool on) } #endif +void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus) +{ +#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC) + dr_utmi_config.platform_driver_vbus = driver_vbus; +#endif +} + void __init mx5_usb_dr_init(void) { #ifdef CONFIG_USB_OTG @@ -149,11 +287,15 @@ void __init mx5_usb_dr_init(void) #endif #ifdef CONFIG_USB_EHCI_ARC_OTG dr_utmi_config.operating_mode = DR_HOST_MODE; + dr_utmi_config.wake_up_enable = _host_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend; platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config)); platform_device_register(&mxc_usbdr_host_device); #endif #ifdef CONFIG_USB_GADGET_ARC dr_utmi_config.operating_mode = DR_UDC_MODE; + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend; platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config)); platform_device_register(&mxc_usbdr_udc_device); #endif |