summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx5/usb_dr.c
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2010-09-27 09:58:28 +0800
committerAlejandro Gonzalez <alex.gonzalez@digi.com>2011-01-17 14:56:46 +0100
commit26392f4a9b4271179bf2a4489c22fe5fd7cb3ff2 (patch)
tree6e052560c7d4be76039a8376b77165ff9080231c /arch/arm/mach-mx5/usb_dr.c
parent8d83d99cf904615cac28f47576b1d946c9f956db (diff)
ENGR00131616-1 usb: restructure lower power mode and wakeup function
MSL part (squashed with ENGR00131775) Mainly includes restruct low power mode and wakeup function for all usb modes. 1. Move more kernel common code changes to fsl driver. 2. Fix kinds of otg bugs 3. At idle mode all usb clock and related phy clock will be closed. 4. Wakeup function are fully verified for all usb modes (device, host and otg mode) 5. The modifications are verified at mx50 platform at 2.6.35 6. utmirc.c should also be enabled for non-host mode, otherwise, there will be a null pointer error. Signed-off-by: Hu Hui <b29976@freescale.com> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Dinh Nguyen <Dinh.Nguyen@freescale.com>
Diffstat (limited to 'arch/arm/mach-mx5/usb_dr.c')
-rw-r--r--arch/arm/mach-mx5/usb_dr.c112
1 files changed, 92 insertions, 20 deletions
diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c
index 0286c7a9ff2c..6373f54bc267 100644
--- a/arch/arm/mach-mx5/usb_dr.c
+++ b/arch/arm/mach-mx5/usb_dr.c
@@ -18,12 +18,11 @@
#include <linux/fsl_devices.h>
#include <mach/arc_otg.h>
#include <mach/hardware.h>
+#include <asm/delay.h>
#include "usb.h"
-
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 +39,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",
};
@@ -80,29 +78,99 @@ 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)
-{
- if (get_usb_mode(pdata) == FSL_USB_DR_DEVICE) {
- if (enable) {
+/* Below two macros are used at otg mode to indicate usb mode*/
+#define ENABLED_BY_HOST (0x1 << 0)
+#define ENABLED_BY_DEVICE (0x1 << 1)
+static u32 wakeup_irq_enable_src; /* only useful at otg mode */
+static void __wakeup_irq_enable(bool on, int source)
+ {
+ /* 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) {
+#ifdef CONFIG_MXC_OTG
+ 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;
}
+#else
+ USBCTRL |= UCTRL_OWIE;
+ USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2;
+#endif
} else {
- if (enable) {
- USBCTRL |= UCTRL_OWIE;
- USBCTRL_HOST2 |= (1 << 5);
- } else {
- USBCTRL &= ~UCTRL_OWIE;
- USBCTRL_HOST2 &= ~(1 << 5);
+ 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);
+ }
+}
+
+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) {
+ pr_debug("host wakeup enable\n");
+ USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN;
+ } else {
+ pr_debug("host wakeup disable\n");
+ USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+
+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) {
+ pr_debug("device wakeup enable\n");
+ USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN;
+ } else {
+ pr_debug("device wakeup disable\n");
+ USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
+ }
+}
+
+static u32 low_power_enable_src; /* only useful at otg mode */
+static void __phy_lowpower_suspend(bool enable, int source)
+{
+ if (enable) {
+ low_power_enable_src |= source;
+#ifdef CONFIG_MXC_OTG
+ if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ pr_debug("phy lowpower enabled\n");
+ UOG_PORTSC1 |= PORTSC_PHCD;
}
+#else
+ UOG_PORTSC1 |= PORTSC_PHCD;
+#endif
+ } else {
+ pr_debug("phy lowpower disable\n");
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
+ low_power_enable_src &= ~source;
}
}
+static void _host_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_HOST);
+}
+
+static void _device_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE);
+}
+
static void usbotg_clock_gate(bool on)
{
struct clk *usb_clk;
@@ -125,11 +193,11 @@ static void usbotg_clock_gate(bool on)
clk_disable(usb_clk);
clk_put(usb_clk);
} else {
- usb_clk = clk_get(NULL, "usboh3_clk");
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
- usb_clk = clk_get(NULL, "usb_phy1_clk");
+ usb_clk = clk_get(NULL, "usboh3_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
@@ -153,11 +221,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