diff options
author | Jun Li <r65092@freescale.com> | 2009-07-29 18:47:35 +0800 |
---|---|---|
committer | Justin Waters <justin.waters@timesys.com> | 2009-10-13 11:05:08 -0400 |
commit | a9067a441adcab98b64e720c024698b2727c6476 (patch) | |
tree | 64937ef0912d3926785bd90c6eff548253b0d6ed | |
parent | cf2f19f6dc70139450f22df6a04f5392fd567307 (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_defconfig | 16 | ||||
-rw-r--r-- | arch/arm/mach-mx3/mxc_pm.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-mx3/usb.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-mx3/usb_h2.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-mx51/usb_h1.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-stmp3xxx/stmp378x_devb.c | 11 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/fsl_usb.h | 12 | ||||
-rw-r--r-- | arch/arm/plat-mxc/usb_common.c | 105 | ||||
-rw-r--r-- | arch/arm/plat-mxc/utmixc.c | 41 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 34 | ||||
-rw-r--r-- | drivers/usb/gadget/Kconfig | 6 | ||||
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 166 | ||||
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.h | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-arc.c | 64 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/otg/fsl_otg.h | 5 | ||||
-rw-r--r-- | include/linux/fsl_devices.h | 1 | ||||
-rw-r--r-- | include/linux/usb/ehci_def.h | 1 |
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) */ |