summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun Li <r65092@freescale.com>2009-07-29 18:47:35 +0800
committerJustin Waters <justin.waters@timesys.com>2009-10-13 11:05:08 -0400
commita9067a441adcab98b64e720c024698b2727c6476 (patch)
tree64937ef0912d3926785bd90c6eff548253b0d6ed
parentcf2f19f6dc70139450f22df6a04f5392fd567307 (diff)
ENGR00114795 fix usb OTG co-work with remote wakeup issue.
This patch fix OTG pin-detect failure issue. via sysfs set power/wakeup, i.MX51 can: Put usb phy into low power mode when system enters stop or standby mode; Enable usb device remote wakeup system by Vbus and usb host remote wakeup system by device connection or disconnection. Signed-off-by: Li Jun <r65092@freescale.com>
-rw-r--r--arch/arm/configs/imx51_defconfig16
-rw-r--r--arch/arm/mach-mx3/mxc_pm.c9
-rw-r--r--arch/arm/mach-mx3/usb.h8
-rw-r--r--arch/arm/mach-mx3/usb_h2.c10
-rw-r--r--arch/arm/mach-mx51/usb_h1.c9
-rw-r--r--arch/arm/mach-stmp3xxx/stmp378x_devb.c11
-rw-r--r--arch/arm/plat-mxc/include/mach/fsl_usb.h12
-rw-r--r--arch/arm/plat-mxc/usb_common.c105
-rw-r--r--arch/arm/plat-mxc/utmixc.c41
-rw-r--r--drivers/usb/core/hcd.c34
-rw-r--r--drivers/usb/gadget/Kconfig6
-rw-r--r--drivers/usb/gadget/arcotg_udc.c166
-rw-r--r--drivers/usb/gadget/arcotg_udc.h16
-rw-r--r--drivers/usb/gadget/file_storage.c2
-rw-r--r--drivers/usb/host/Kconfig16
-rw-r--r--drivers/usb/host/ehci-arc.c64
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/otg/fsl_otg.h5
-rw-r--r--include/linux/fsl_devices.h1
-rw-r--r--include/linux/usb/ehci_def.h1
20 files changed, 271 insertions, 263 deletions
diff --git a/arch/arm/configs/imx51_defconfig b/arch/arm/configs/imx51_defconfig
index 2f221258c673..376d1d437cb0 100644
--- a/arch/arm/configs/imx51_defconfig
+++ b/arch/arm/configs/imx51_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.28
-# Fri Aug 7 13:18:04 2009
+# Sat Aug 8 16:45:02 2009
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -206,7 +206,6 @@ CONFIG_ARCH_MXC_HAS_NFC_V3_2=y
CONFIG_MXC_TZIC=y
CONFIG_DMA_ZONE_SIZE=64
CONFIG_UTMI_MXC=y
-CONFIG_UTMI_MXC_OTG=y
# CONFIG_MXC_PWM is not set
#
@@ -1265,7 +1264,7 @@ CONFIG_USB=y
CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
CONFIG_USB_SUSPEND=y
-CONFIG_USB_OTG=y
+# CONFIG_USB_OTG is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
@@ -1279,15 +1278,9 @@ CONFIG_USB_OTG=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ARC=y
CONFIG_USB_EHCI_ARC_H1=y
-CONFIG_USB_EHCI_ARC_H2=y
-# CONFIG_USB_EHCI_ARC_H2_WAKE_UP is not set
-CONFIG_USB_EHCI_ARC_OTG=y
-# CONFIG_USB_EHCI_ARC_OTG_WAKE_UP is not set
+# CONFIG_USB_EHCI_ARC_H2 is not set
+# CONFIG_USB_EHCI_ARC_OTG is not set
# CONFIG_USB_STATIC_IRAM is not set
-# CONFIG_USB_EHCI_FSL_MC13783 is not set
-# CONFIG_USB_EHCI_FSL_1301 is not set
-# CONFIG_USB_EHCI_FSL_1504 is not set
-CONFIG_USB_EHCI_FSL_UTMI=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
@@ -1384,7 +1377,6 @@ CONFIG_USB_ARC=y
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
CONFIG_USB_GADGET_ARC_OTG=y
-# CONFIG_USB_GADGET_WAKE_UP is not set
# CONFIG_USB_GADGET_FSL_MC13783 is not set
# CONFIG_USB_GADGET_FSL_1301 is not set
# CONFIG_USB_GADGET_FSL_1504 is not set
diff --git a/arch/arm/mach-mx3/mxc_pm.c b/arch/arm/mach-mx3/mxc_pm.c
index 4b96f0f9b6ba..3fcce2472983 100644
--- a/arch/arm/mach-mx3/mxc_pm.c
+++ b/arch/arm/mach-mx3/mxc_pm.c
@@ -333,16 +333,9 @@ void mxc_pm_lowpower(int mode)
MXC_CCM_CCMR_SBYCS |
(lpm << MXC_CCM_CCMR_LPM_OFFSET));
- /* wake up by keypad and usbotg */
+ /* wake up by keypad */
reg = __raw_readl(MXC_CCM_WIMR);
reg &= ~(1 << 18);
-#if defined(CONFIG_USB_GADGET_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
- reg &= ~(1 << 5);
-#endif
-#ifdef CONFIG_USB_EHCI_ARC_H2_WAKE_UP
- reg &= ~(1 << 6);
-#endif
__raw_writel(reg, MXC_CCM_WIMR);
flush_cache_all();
diff --git a/arch/arm/mach-mx3/usb.h b/arch/arm/mach-mx3/usb.h
index bd8779157759..5a7170367773 100644
--- a/arch/arm/mach-mx3/usb.h
+++ b/arch/arm/mach-mx3/usb.h
@@ -62,14 +62,8 @@ static struct fsl_usb2_platform_data __maybe_unused dr_13783_config;
#ifdef CONFIG_USB_EHCI_ARC_OTG
static inline void dr_register_host(struct resource *r, int rs)
{
- struct platform_device *dr_pdev;
-
PDATA->operating_mode = DR_HOST_MODE;
- dr_pdev = host_pdev_register(r, rs, PDATA);
-#ifdef CONFIG_USB_EHCI_ARC_OTG_WAKE_UP
- /* set host may and should wakeup */
- device_init_wakeup(&(dr_pdev->dev), 1);
-#endif
+ host_pdev_register(r, rs, PDATA);
}
#else
static inline void dr_register_host(struct resource *r, int rs)
diff --git a/arch/arm/mach-mx3/usb_h2.c b/arch/arm/mach-mx3/usb_h2.c
index ea51a27a3430..d47f26b18a93 100644
--- a/arch/arm/mach-mx3/usb_h2.c
+++ b/arch/arm/mach-mx3/usb_h2.c
@@ -47,8 +47,6 @@ static struct resource usbh2_resources[] = {
static int __init usbh2_init(void)
{
- struct platform_device *h2_pdev;
-
pr_debug("%s: \n", __func__);
if (machine_is_mx31_3ds()) {
@@ -64,12 +62,8 @@ static int __init usbh2_init(void)
usbh2_config.xcvr_pwr->regu2 = usbh2_regux;
}
- h2_pdev = host_pdev_register(usbh2_resources,
- ARRAY_SIZE(usbh2_resources), &usbh2_config);
-#ifdef CONFIG_USB_EHCI_ARC_H2_WAKE_UP
- /* set host2 may and should wakeup */
- device_init_wakeup(&(h2_pdev->dev), 1);
-#endif
+ host_pdev_register(usbh2_resources, ARRAY_SIZE(usbh2_resources),
+ &usbh2_config);
return 0;
}
module_init(usbh2_init);
diff --git a/arch/arm/mach-mx51/usb_h1.c b/arch/arm/mach-mx51/usb_h1.c
index 78085e69a5b4..8f9610c16930 100644
--- a/arch/arm/mach-mx51/usb_h1.c
+++ b/arch/arm/mach-mx51/usb_h1.c
@@ -64,6 +64,10 @@ EXPORT_SYMBOL(gpio_usbh1_setback_stp);
static void gpio_usbh1_inactive(void)
{
+ /* Signal only used on MX51-3DS for reset to PHY.*/
+ if (machine_is_mx51_3ds())
+ mxc_free_iomux(MX51_PIN_EIM_D17, IOMUX_CONFIG_GPIO);
+
mxc_request_gpio(MX51_PIN_USBH1_STP);
mxc_free_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_GPIO);
}
@@ -96,8 +100,9 @@ static int __init usbh1_init(void)
{
pr_debug("%s: \n", __func__);
- host_pdev_register(usbh1_resources, ARRAY_SIZE(usbh1_resources),
- &usbh1_config);
+ host_pdev_register(usbh1_resources,
+ ARRAY_SIZE(usbh1_resources), &usbh1_config);
+
return 0;
}
diff --git a/arch/arm/mach-stmp3xxx/stmp378x_devb.c b/arch/arm/mach-stmp3xxx/stmp378x_devb.c
index 95fd9afd8015..a22e202c7294 100644
--- a/arch/arm/mach-stmp3xxx/stmp378x_devb.c
+++ b/arch/arm/mach-stmp3xxx/stmp378x_devb.c
@@ -236,6 +236,17 @@ static int usb_phy_enable(struct platform_device *pdev)
return 0;
}
+int usb_host_wakeup_irq(struct device *wkup_dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(usb_host_wakeup_irq);
+
+void usb_host_set_wakeup(struct device *wkup_dev, bool para)
+{
+}
+EXPORT_SYMBOL(usb_host_set_wakeup);
+
static struct stmp37xx_spi_platform_data enc_data = {
.irq_pin = PINID_SSP1_DATA1,
.hw_init = stmp37xx_spi_enc_init,
diff --git a/arch/arm/plat-mxc/include/mach/fsl_usb.h b/arch/arm/plat-mxc/include/mach/fsl_usb.h
index 0ee6ea0e7b1f..f1650602f996 100644
--- a/arch/arm/plat-mxc/include/mach/fsl_usb.h
+++ b/arch/arm/plat-mxc/include/mach/fsl_usb.h
@@ -48,10 +48,20 @@ static inline void fsl_platform_set_host_mode(struct usb_hcd *hcd)
writel(temp | USBMODE_CM_HOST, hcd->regs + 0x1a8);
}
-/* Needed for i2c/serial transceivers */
+/* Needed for enable PP and i2c/serial transceivers */
static inline void
fsl_platform_set_vbus_power(struct fsl_usb2_platform_data *pdata, int on)
{
+ u32 temp;
+
+ /* HCSPARAMS */
+ temp = readl(pdata->regs + 0x104);
+ /* Port Power Control */
+ if (temp & HCSPARAMS_PPC) {
+ temp = readl(pdata->regs + FSL_SOC_USB_PORTSC1);
+ writel(temp | PORT_POWER, pdata->regs + FSL_SOC_USB_PORTSC1);
+ }
+
if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power)
pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on);
}
diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c
index 9fe77394ac0e..17473a13fa95 100644
--- a/arch/arm/plat-mxc/usb_common.c
+++ b/arch/arm/plat-mxc/usb_common.c
@@ -397,24 +397,21 @@ static int usb_register_remote_wakeup(struct platform_device *pdev)
{
pr_debug("%s: pdev=0x%p \n", __func__, pdev);
- if (device_may_wakeup(&pdev->dev)) {
- struct resource *res;
- int irq;
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no IRQ. Check %s setup!\n",
- pdev->dev.bus_id);
- return -ENODEV;
- }
- irq = res->start;
- enable_irq_wake(irq);
-
- return 0;
+ struct resource *res;
+ int irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ pdev->dev.bus_id);
+ return -ENODEV;
}
+ irq = res->start;
+ pdev->dev.power.can_wakeup = 1;
+ enable_irq_wake(irq);
- return -EINVAL;
+ return 0;
}
extern void gpio_usbh1_setback_stp(void);
@@ -466,7 +463,7 @@ int fsl_usb_host_init(struct platform_device *pdev)
xops->init(xops);
if (usb_register_remote_wakeup(pdev))
- pr_debug("Host is not a wakeup source.\n");
+ pr_debug("%s port is not a wakeup source.\n", pdata->name);
if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
if (cpu_is_mx35()) {
@@ -480,14 +477,17 @@ int fsl_usb_host_init(struct platform_device *pdev)
} else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
if (cpu_is_mx51()) {
#ifdef CONFIG_USB_EHCI_ARC_H1
- if (pdata->name == "Host 1") {
+ if (!strcmp("Host 1", pdata->name)) {
usbh1_set_ulpi_xcvr();
- if (cpu_is_mx51())
- gpio_usbh1_setback_stp();
+ if (cpu_is_mx51()) {
+ gpio_usbh1_setback_stp();
+ /* disable remote wakeup irq */
+ USBCTRL &= ~UCTRL_H1WIE;
}
+ }
#endif
#ifdef CONFIG_USB_EHCI_ARC_H2
- if (pdata->name == "Host 2") {
+ if (!strcmp("Host 2", pdata->name)) {
usbh2_set_ulpi_xcvr();
if (cpu_is_mx51())
gpio_usbh2_setback_stp();
@@ -497,10 +497,6 @@ int fsl_usb_host_init(struct platform_device *pdev)
usbh2_set_ulpi_xcvr();
}
- if (pdata->name == "Host 2")
- /* disable remote wakeup irq */
- USBCTRL &= ~UCTRL_H2WIE;
-
pr_debug("%s: %s success\n", __func__, pdata->name);
return 0;
}
@@ -690,7 +686,7 @@ static void otg_set_utmi_xcvr(void)
}
USBCTRL &= ~UCTRL_OPM; /* OTG Power Mask */
- USBCTRL |= UCTRL_OWIE; /* OTG Wakeup Intr Enable */
+ USBCTRL &= ~UCTRL_OWIE; /* OTG Wakeup Intr Disable */
/* set UTMI xcvr */
tmp = UOG_PORTSC1 & ~PORTSC_PTS_MASK;
@@ -717,9 +713,6 @@ static void otg_set_utmi_xcvr(void)
USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_UTMI_ENABLE;
}
- if (UOG_HCSPARAMS & HCSPARAMS_PPC)
- UOG_PORTSC1 |= PORTSC_PORT_POWER;
-
/* need to reset the controller here so that the ID pin
* is correctly detected.
*/
@@ -775,9 +768,6 @@ int usbotg_init(struct platform_device *pdev)
if (xops->init)
xops->init(xops);
- if (usb_register_remote_wakeup(pdev))
- pr_debug("DR is not a wakeup source.\n");
-
if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
if (pdata->operating_mode == FSL_USB2_DR_HOST) {
otg_set_serial_host();
@@ -792,11 +782,11 @@ int usbotg_init(struct platform_device *pdev)
} else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
otg_set_utmi_xcvr();
}
-
- /* disable remote wakeup irq */
- USBCTRL &= ~UCTRL_OWIE;
}
+ if (usb_register_remote_wakeup(pdev))
+ pr_debug("DR is not a wakeup source.\n");
+
otg_used++;
pr_debug("%s: success\n", __func__);
return 0;
@@ -827,37 +817,44 @@ void usbotg_uninit(struct fsl_usb2_platform_data *pdata)
}
EXPORT_SYMBOL(usbotg_uninit);
-#if defined(CONFIG_USB_EHCI_ARC_H2_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
-int usb_wakeup_irq(struct device *wkup_dev)
+int usb_host_wakeup_irq(struct device *wkup_dev)
{
int wakeup_req = 0;
struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data;
- if (pdata->name == "Host 2")
- wakeup_req = USBCTRL & UCTRL_H2WIR;
- else if (pdata->name == "DR")
+ if (!strcmp("Host 1", pdata->name)) {
+ wakeup_req = USBCTRL & UCTRL_H1WIR;
+ } else if (!strcmp("DR", pdata->name)) {
wakeup_req = USBCTRL & UCTRL_OWIR;
+ /* If DR is in device mode, let udc handle it */
+ if (wakeup_req && ((UOG_USBMODE & 0x3) == 0x2))
+ wakeup_req = 0;
+ }
return wakeup_req;
}
-EXPORT_SYMBOL(usb_wakeup_irq);
+EXPORT_SYMBOL(usb_host_wakeup_irq);
-void usb_wakeup_set(struct device *wkup_dev, int para)
+void usb_host_set_wakeup(struct device *wkup_dev, bool para)
{
struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data;
- if (pdata->name == "Host 2") {
- if (para)
- USBCTRL |= UCTRL_H2WIE;
- else
- USBCTRL &= ~UCTRL_H2WIE;
- } else if (pdata->name == "DR") {
- if (para)
+ /* If this device may wakeup */
+ if (device_may_wakeup(wkup_dev) && para)
+ if (!strcmp("Host 1", pdata->name)) {
+ USBCTRL |= UCTRL_H1WIE;
+ } else if (!strcmp("DR", pdata->name)) {
USBCTRL |= UCTRL_OWIE;
- else
+ /* Enable OTG ID Wakeup */
+ USBCTRL_HOST2 |= (1 << 5);
+ }
+
+ if (!para)
+ if (!strcmp("Host 1", pdata->name))
+ USBCTRL &= ~UCTRL_H1WIE;
+ else if (!strcmp("DR", pdata->name)) {
USBCTRL &= ~UCTRL_OWIE;
- }
+ USBCTRL_HOST2 &= ~(1 << 5);
+ }
}
-EXPORT_SYMBOL(usb_wakeup_set);
-#endif
+EXPORT_SYMBOL(usb_host_set_wakeup);
diff --git a/arch/arm/plat-mxc/utmixc.c b/arch/arm/plat-mxc/utmixc.c
index 0f3dba7234c4..308d79344a01 100644
--- a/arch/arm/plat-mxc/utmixc.c
+++ b/arch/arm/plat-mxc/utmixc.c
@@ -28,10 +28,20 @@
#include <asm/mach-types.h>
static struct regulator *usbotg_regux;
-static struct regulator *usbotg_regux1;
static void usb_utmi_init(struct fsl_xcvr_ops *this)
{
+#if defined(CONFIG_MXC_PMIC_MC13892_MODULE) || defined(CONFIG_MXC_PMIC_MC13892)
+ if (machine_is_mx51_3ds()) {
+ unsigned int value;
+
+ /* VUSBIN */
+ pmic_read_reg(REG_USB1, &value, 0xffffff);
+ value |= 0x1;
+ value |= (0x1 << 3);
+ pmic_write_reg(REG_USB1, value, 0xffffff);
+ }
+#endif
}
static void usb_utmi_uninit(struct fsl_xcvr_ops *this)
@@ -62,35 +72,6 @@ static void set_power(struct fsl_xcvr_ops *this,
regulator_disable(usbotg_regux);
regulator_put(usbotg_regux);
}
-#if defined(CONFIG_MXC_PMIC_MC13892_MODULE) || defined(CONFIG_MXC_PMIC_MC13892)
- } else if (machine_is_mx51_3ds()) {
- unsigned int value;
-
- if (on) {
- usbotg_regux = regulator_get(dev, "SWBST");
- regulator_enable(usbotg_regux);
- } else {
- regulator_disable(usbotg_regux);
- regulator_put(usbotg_regux);
- }
-
- /* VUSBIN */
- pmic_read_reg(REG_USB1, &value, 0xffffff);
- if (on)
- value |= 0x1;
- else
- value &= ~0x1;
- pmic_write_reg(REG_USB1, value, 0xffffff);
-
- /* VUSBEN */
- if (on) {
- usbotg_regux1 = regulator_get(dev, "VUSB");
- regulator_enable(usbotg_regux1);
- } else {
- regulator_disable(usbotg_regux1);
- regulator_put(usbotg_regux1);
- }
-#endif
}
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0221294a4e3f..3208360664c8 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -117,10 +117,9 @@ static inline int is_root_hub(struct usb_device *udev)
return (udev->parent == NULL);
}
-#if defined(CONFIG_USB_EHCI_ARC_H2_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
-extern int usb_wakeup_irq(struct device *wkup_dev);
-extern void usb_wakeup_set(struct device *wkup_dev, int para);
+#if CONFIG_PM
+extern int usb_host_wakeup_irq(struct device *wkup_dev);
+extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
#endif
/*-------------------------------------------------------------------------*/
@@ -1729,22 +1728,19 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
* assume it's never used.
*/
local_irq_save(flags);
-#if defined(CONFIG_USB_EHCI_ARC_H2_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
- /* if receive a remote wakeup interrrupt when suspend */
- if (usb_wakeup_irq(hcd->self.controller)) {
- /* disable remote wake up irq */
- usb_wakeup_set(hcd->self.controller, 0);
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- rc = hcd->driver->irq(hcd);
- } else if (unlikely(hcd->state == HC_STATE_HALT ||
- !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
- rc = IRQ_NONE;
-#else
- if (unlikely(hcd->state == HC_STATE_HALT ||
- !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ /* if receive a remote wakeup interrrupt after suspend */
+ if (usb_host_wakeup_irq(hcd->self.controller)) {
+ /* disable remote wake up irq */
+ usb_host_set_wakeup(hcd->self.controller, false);
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ hcd->driver->irq(hcd);
+ rc = IRQ_HANDLED;
+ } else
+ rc = IRQ_NONE;
+ } else if (unlikely(hcd->state == HC_STATE_HALT)) {
rc = IRQ_NONE;
-#endif
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE;
} else {
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 71fe9ca3a15d..09284dee18b3 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -487,12 +487,6 @@ config USB_GADGET_ARC_OTG
help
Enable support for the Freescale Dual Role port in peripheral mode.
-config USB_GADGET_WAKE_UP
- bool "Support gadget wake up by DR port"
- depends on USB_GADGET_ARC_OTG && ARCH_MXC
- default n
- help
- Enable system wake up from SR or DSM mode by connected host.
choice
prompt "Select transceiver for DR port"
depends on USB_GADGET_ARC_OTG
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 40df0fb754e6..250d5e9b95ac 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -256,6 +256,64 @@ static void nuke(struct fsl_ep *ep, int status)
Internal Hardware related function
------------------------------------------------------------------*/
+static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
+{
+ u32 temp;
+
+ if (!device_may_wakeup(&(udc->pdata->pdev->dev)))
+ return;
+
+ temp = fsl_readl(&dr_regs->portsc1);
+ if ((enable) && !(temp & PORTSCX_PHY_LOW_POWER_SPD)) {
+ temp |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(temp, &dr_regs->portsc1);
+
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(false);
+ } else if ((!enable) && (temp & PORTSCX_PHY_LOW_POWER_SPD)) {
+ if (udc_controller->pdata->usb_clock_for_pm)
+ udc_controller->pdata->usb_clock_for_pm(true);
+
+ temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(temp, &dr_regs->portsc1);
+ }
+}
+
+static void dr_wake_up_enable(struct fsl_udc *udc, bool enable)
+{
+ u32 temp;
+
+ temp = fsl_readl(&dr_regs->usbctrl);
+
+ if (!enable) {
+ temp &= ~USB_CTRL_OTG_WUIE;
+ fsl_writel(temp, &dr_regs->usbctrl);
+
+ /* OTG vbus Wakeup disable */
+ temp = fsl_readl(&dr_regs->uh2ctrl);
+ temp &= ~USB_UH2_OVBWK_EN;
+ fsl_writel(temp, &dr_regs->uh2ctrl);
+
+ /* disable conf2 */
+ temp = fsl_readl(&dr_regs->phyctrl0);
+ temp &= ~PHY_CTRL0_CONF2;
+ fsl_writel(temp, &dr_regs->phyctrl0);
+ } else if (device_may_wakeup(&(udc->pdata->pdev->dev))) {
+ temp |= USB_CTRL_OTG_WUIE;
+ fsl_writel(temp, &dr_regs->usbctrl);
+
+ /* OTG vbus wakeup enable */
+ temp = fsl_readl(&dr_regs->uh2ctrl);
+ temp |= USB_UH2_OVBWK_EN;
+ fsl_writel(temp, &dr_regs->uh2ctrl);
+
+ /* enable conf2 */
+ temp = fsl_readl(&dr_regs->phyctrl0);
+ temp |= PHY_CTRL0_CONF2;
+ fsl_writel(temp, &dr_regs->phyctrl0);
+ }
+}
+
static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp = 0, portctrl = 0;
@@ -1864,20 +1922,14 @@ static void suspend_irq(struct fsl_udc *udc)
udc->driver->suspend(&udc->gadget);
}
-#ifdef CONFIG_USB_GADGET_WAKE_UP
/* Process Wake up interrupt */
static void wake_up_irq(struct fsl_udc *udc)
{
- u32 irq_src;
-
pr_debug("%s\n", __func__);
/* disable wake up irq */
- irq_src = fsl_readl(&dr_regs->usbctrl);
- irq_src &= ~USB_CTRL_OTG_WUIE;
- fsl_writel(irq_src, &dr_regs->usbctrl);
+ dr_wake_up_enable(udc, false);
}
-#endif
static void bus_resume(struct fsl_udc *udc)
{
@@ -1968,28 +2020,31 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
irqreturn_t status = IRQ_NONE;
unsigned long flags;
-#ifdef CONFIG_USB_GADGET_WAKE_UP
- spin_lock_irqsave(&udc->lock, flags);
- /* check USBCTRL register to see if wake up irq */
- irq_src = fsl_readl(&dr_regs->usbctrl);
- if (irq_src & USB_CTRL_OTG_WUIR) {
- wake_up_irq(udc);
- irq_src = fsl_readl(&dr_regs->usbsts) &
- fsl_readl(&dr_regs->usbintr);
- if (irq_src)
- udc->stopped = 0;
- else
- status = IRQ_HANDLED;
+ /* when udc is stopped, only handle wake up irq */
+ if (udc->stopped) {
+ if (!device_may_wakeup(&(udc->pdata->pdev->dev)))
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ /* check to see if wake up irq */
+ irq_src = fsl_readl(&dr_regs->usbctrl);
+ if (irq_src & USB_CTRL_OTG_WUIR) {
+ wake_up_irq(udc);
+ irq_src = fsl_readl(&dr_regs->usbsts) &
+ fsl_readl(&dr_regs->usbintr);
+ spin_unlock_irqrestore(&udc->lock, flags);
+ if (irq_src)
+ /* Some udc irq to be handled */
+ udc->stopped = 0;
+ else
+ return IRQ_HANDLED;
+ } else {
+ /* If udc is stopped and irq is not wake up */
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return IRQ_NONE;
+ }
}
- spin_unlock_irqrestore(&udc->lock, flags);
-
- if (status == IRQ_HANDLED)
- return IRQ_HANDLED;
-#endif
- /* Disable ISR for OTG host mode */
- if (udc->stopped)
- return IRQ_NONE;
spin_lock_irqsave(&udc->lock, flags);
irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
/* Clear notification bits */
@@ -2095,6 +2150,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
/* Suspend the controller until OTG enable it */
udc_controller->stopped = 1;
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
+ dr_wake_up_enable(udc_controller, true);
+ dr_phy_low_power_mode(udc_controller, true);
/* export udc suspend/resume call to OTG */
udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend;
@@ -2840,13 +2897,20 @@ static int udc_suspend(struct fsl_udc *udc)
return 0;
}
+ udc->stopped = 1;
+ /* if the suspend is not for switch to host in otg mode */
+ if ((!(udc->gadget.is_otg)) ||
+ (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+ dr_wake_up_enable(udc, true);
+ dr_phy_low_power_mode(udc, true);
+ }
+
/* stop the controller */
usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
fsl_writel(usbcmd, &dr_regs->usbcmd);
printk(KERN_INFO "USB Gadget suspended\n");
- udc->stopped = 1;
return 0;
}
@@ -2856,35 +2920,10 @@ static int udc_suspend(struct fsl_udc *udc)
-----------------------------------------------------------------*/
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
{
- unsigned int port_status, temp;
-
if ((udc_controller->usb_state > USB_STATE_POWERED) &&
(udc_controller->usb_state < USB_STATE_SUSPENDED))
return -EBUSY;
-#ifdef CONFIG_USB_GADGET_WAKE_UP
- temp = fsl_readl(&dr_regs->usbctrl);
- /* if usb wake up irq is disabled, enable it */
- if (!(temp & USB_CTRL_OTG_WUIE)) {
- temp |= USB_CTRL_OTG_WUIE;
- fsl_writel(temp, &dr_regs->usbctrl);
- }
-#else
- temp = fsl_readl(&dr_regs->usbctrl);
- /* if usb wake up irq is enabled, disable it */
- if (temp & USB_CTRL_OTG_WUIE) {
- temp &= ~USB_CTRL_OTG_WUIE;
- fsl_writel(temp, &dr_regs->usbctrl);
- }
-#endif
-
- /* close UBS PHY clock if PHCD is 0 */
- port_status = fsl_readl(&dr_regs->portsc1);
- if (!(port_status & PORTSCX_PHY_LOW_POWER_SPD)) {
- port_status |= PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(port_status, &dr_regs->portsc1);
- }
-
return udc_suspend(udc_controller);
}
@@ -2909,22 +2948,9 @@ static int fsl_udc_resume(struct platform_device *pdev)
/* Enable DR irq reg and set controller Run */
if (udc_controller->stopped) {
- u32 temp;
-
-#ifdef CONFIG_USB_GADGET_WAKE_UP
- /* disable wake up irq */
- temp = fsl_readl(&dr_regs->usbctrl);
- temp &= ~UCTRL_OWIE;
- fsl_writel(temp, &dr_regs->usbctrl);
-#endif
-
- /* Enable PHY clock if it's disabled */
- temp = fsl_readl(&dr_regs->portsc1);
- if (temp & PORTSCX_PHY_LOW_POWER_SPD) {
- temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(temp, &dr_regs->portsc1);
- mdelay(1);
- }
+ dr_wake_up_enable(udc_controller, false);
+ dr_phy_low_power_mode(udc_controller, false);
+ mdelay(1);
dr_controller_setup(udc_controller);
dr_controller_run(udc_controller);
@@ -2958,7 +2984,7 @@ static int __init udc_init(void)
return platform_driver_register(&udc_driver);
}
-late_initcall(udc_init);
+module_init(udc_init);
static void __exit udc_exit(void)
{
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index fbdb3203f12e..e7cca079e184 100644
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -101,7 +101,15 @@ struct usb_dr_device {
u32 endptcomplete; /* Endpoint Complete Register */
u32 endptctrl[8 * 2]; /* Endpoint Control Registers */
u32 res8[256];
+#ifdef CONFIG_ARCH_MX51
+ u32 res9[128]; /* i.MX51 start from 0x800 */
+#endif
u32 usbctrl;
+ u32 otgmirror;
+ u32 phyctrl0;
+ u32 phyctrl1;
+ u32 ctrl1;
+ u32 uh2ctrl;
};
/* non-EHCI USB system interface registers (Big Endian) */
@@ -344,7 +352,15 @@ struct usb_sys_interface {
#define USB_CTRL_ULPI_INT0EN (0x00000001)
#define USB_CTRL_OTG_WUIR (0x80000000)
#define USB_CTRL_OTG_WUIE (0x08000000)
+#define USB_CTRL_OTG_VWUE (0x00001000)
+#define USB_CTRL_OTG_IWUE (0x00100000)
+
+/* PHY control0 Register Bit Masks */
+#define PHY_CTRL0_CONF2 (1 << 26)
+/* USB UH2 CTRL Register Bits */
+#define USB_UH2_OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
+#define USB_UH2_OIDWK_EN (1 << 5) /* OTG ID Wakeup Enable */
/*!
* Endpoint Queue Head data struct
* Rem: all the variables of qh are LittleEndian Mode
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 58e278e24f7c..2529b1f578e6 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -4148,7 +4148,7 @@ static int __init fsg_init(void)
kref_put(&fsg->ref, fsg_release);
return rc;
}
-late_initcall(fsg_init);
+module_init(fsg_init);
static void __exit fsg_cleanup(void)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 78bbd6ee55ad..4e539e30f1f6 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -65,14 +65,6 @@ config USB_EHCI_ARC_H2
---help---
Enable support for the USB Host2 port.
-config USB_EHCI_ARC_H2_WAKE_UP
- bool "Support wake up from Freescale Host2 port"
- depends on PM && USB_EHCI_ARC_H2
- default n
- ---help---
- Enable support system wake up from Host2 port usb device
- connection and disconnection.
-
config USB_EHCI_ARC_OTG
bool "Support for DR host port on Freescale controller"
depends on USB_EHCI_ARC
@@ -80,14 +72,6 @@ config USB_EHCI_ARC_OTG
---help---
Enable support for the USB OTG port in HS/FS Host mode.
-config USB_EHCI_ARC_OTG_WAKE_UP
- bool "Support wake up from Freescale OTG port"
- depends on PM && ARCH_MXC && USB_EHCI_ARC_OTG
- default n
- ---help---
- Enable support system wake up from Host1 port usb device
- connection and disconnection.
-
config USB_STATIC_IRAM
bool "Use IRAM for USB"
depends on USB_EHCI_ARC
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index f1617e9e90c3..c91634d68c0c 100644
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -115,7 +115,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
struct resource *res;
int irq;
int retval;
- u32 temp;
pr_debug("initializing FSL-SOC USB Controller\n");
@@ -245,6 +244,12 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
}
#endif
+ if (pdata->suspended) {
+ pdata->suspended = 0;
+ if (pdata->already_suspended)
+ pdata->already_suspended = 0;
+ }
+
fsl_platform_set_ahb_burst(hcd);
ehci_testmode_init(hcd_to_ehci(hcd));
return retval;
@@ -421,8 +426,6 @@ static const struct hc_driver ehci_fsl_hc_driver = {
static int ehci_fsl_drv_probe(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
if (usb_disabled())
return -ENODEV;
@@ -431,21 +434,19 @@ static int ehci_fsl_drv_probe(struct platform_device *pdev)
static int ehci_fsl_drv_remove(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_hcd_fsl_remove(hcd, pdev);
return 0;
}
-static int ehci_fsl_drv_shutdown(struct platform_device *pdev)
+static void ehci_fsl_drv_shutdown(struct platform_device *pdev)
{
- struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
usb_hcd_platform_shutdown(pdev);
}
#ifdef CONFIG_PM
+extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
/* suspend/resume, section 4.3 */
/* These routines rely on the bus (pci, platform, etc)
@@ -455,16 +456,12 @@ static int ehci_fsl_drv_shutdown(struct platform_device *pdev)
*
* They're also used for turning on/off the port when doing OTG.
*/
-#if defined(CONFIG_USB_EHCI_ARC_H2_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
-extern void usb_wakeup_set(struct device *wkup_dev, int para);
-#endif
static int ehci_fsl_drv_suspend(struct platform_device *pdev,
pm_message_t message)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- u32 tmp;
+ u32 tmp, port_status;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
#ifdef DEBUG
@@ -492,6 +489,7 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
printk(KERN_INFO "USB Host suspended\n");
+ port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
hcd->state = HC_STATE_SUSPENDED;
pdev->dev.power.power_state = PMSG_SUSPEND;
@@ -520,16 +518,26 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);
pdata->suspended = 1;
-#if defined(CONFIG_USB_EHCI_ARC_H2_WAKE_UP) || \
- defined(CONFIG_USB_EHCI_ARC_OTG_WAKE_UP)
- /* enable remote wake up irq */
- usb_wakeup_set(&(pdev->dev), 1);
+
+ if (!device_may_wakeup(&(pdev->dev))) {
+ /* clear PP to cut power to the port */
+ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ tmp &= ~PORT_POWER;
+ ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
+ return 0;
+ }
+
+ /* device_may_wakeup */
+ if (!((ehci->transceiver) &&
+ (readl(hcd->regs + 0x1A4) & (1 << 8)))) {
+ /* enable remote wake up irq */
+ usb_host_set_wakeup(&(pdev->dev), true);
/* We CAN NOT enable wake up by connetion and disconnection
* concurrently */
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
/* if there is no usb device connectted */
- if (tmp & PORT_CONNECT) {
+ if (port_status & PORT_CONNECT) {
/* enable wake up by usb device disconnection */
tmp |= PORT_WKDISC_E;
tmp &= ~(PORT_WKOC_E | PORT_WKCONN_E);
@@ -547,14 +555,10 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
/* Disable PHY clock */
tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- tmp |= PORT_PHCD;
- ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
-#else
- /* clear PP to cut power to the port */
- tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- tmp &= ~PORT_POWER;
+ tmp |= (1 << 23);
ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
-#endif
+ }
+
return 0;
}
@@ -565,8 +569,6 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
u32 tmp;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- printk(KERN_INFO "USB Host resumed\n");
-
pr_debug("%s('%s'): suspend=%d already_suspended=%d\n", __func__,
pdata->name, pdata->suspended, pdata->already_suspended);
@@ -585,6 +587,15 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
return 0;
}
+ if (device_may_wakeup(&(pdev->dev))) {
+ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
+ if (tmp & (1 << 23)) {
+ tmp &= ~(1 << 23);
+ ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
+ msleep(10);
+ }
+ }
+
pdata->suspended = 0;
pr_debug("%s resuming...\n", __func__);
@@ -613,6 +624,7 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
usb_hcd_resume_root_hub(hcd);
+ printk(KERN_INFO "USB Host resumed\n");
return 0;
}
#endif /* CONFIG_USB_OTG */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 58bd08e2898f..50b6fa08e987 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1133,7 +1133,7 @@ err_debug:
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
}
-late_initcall(ehci_hcd_init);
+module_init(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/otg/fsl_otg.h
index c358045fe7c6..03e232112b83 100644
--- a/drivers/usb/otg/fsl_otg.h
+++ b/drivers/usb/otg/fsl_otg.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2008 Freescale Semiconductor, Inc.
+/* Copyright 2005-2009 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -348,6 +348,9 @@ struct usb_dr_mmap {
u32 pri_ctrl; /* Priority Control Register */
u32 si_ctrl; /* System Interface Control Register */
u8 res10[236];
+#ifdef CONFIG_ARCH_MX51
+ u32 res11[128];
+#endif
u32 control; /* General Purpose Control Register */
};
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 8b3b8ee565b6..de0c37d08b6c 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -119,6 +119,7 @@ struct fsl_usb2_platform_data {
struct fsl_xcvr_power *xcvr_pwr;
int (*gpio_usb_active) (void);
void (*gpio_usb_inactive) (void);
+ void (*usb_clock_for_pm) (bool);
unsigned big_endian_mmio : 1;
unsigned big_endian_desc : 1;
unsigned es : 1; /* need USBMODE:ES */
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
index 19acf0f2bc0e..5b88e36c9103 100644
--- a/include/linux/usb/ehci_def.h
+++ b/include/linux/usb/ehci_def.h
@@ -101,7 +101,6 @@ struct ehci_regs {
/* PORTSC: offset 0x44 */
u32 port_status [0]; /* up to N_PORTS */
/* 31:23 reserved */
-#define PORT_PHCD (1<<23) /* PHY Low Power Suspend */
#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */