summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2010-11-19 18:19:53 +0800
committerPeter Chen <peter.chen@freescale.com>2010-11-25 16:44:00 +0800
commit4db1a9fb8ae04e26171bcc623c117fcff4661d0b (patch)
tree87dc2955bb2051bf4c34c9c71043e6426bcad83e
parent0f8ae79234cb8315ced1fc74a25f733ba7b95249 (diff)
ENGR00134056-1 MSL: mx28 add low power mode and wakeup support for otg port
Add low power mode and wakeup support for mx28 otg port, and the host1 and otg port are fully verified for low power mode and wakeup function. Signed-off-by: Peter Chen <peter.chen@freescale.com>
-rw-r--r--arch/arm/mach-mx28/usb_dr.c402
-rw-r--r--arch/arm/mach-mx28/usb_h1.c61
-rw-r--r--arch/arm/plat-mxs/usb_common.c39
-rw-r--r--arch/arm/plat-mxs/usb_wakeup.c18
4 files changed, 430 insertions, 90 deletions
diff --git a/arch/arm/mach-mx28/usb_dr.c b/arch/arm/mach-mx28/usb_dr.c
index 50a2f8b381af..ba3af8c437c5 100644
--- a/arch/arm/mach-mx28/usb_dr.c
+++ b/arch/arm/mach-mx28/usb_dr.c
@@ -19,33 +19,329 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/gpio.h>
#include <mach/irqs.h>
+#include <mach/arc_otg.h>
#include "usb.h"
#include "mx28_pins.h"
#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_AUART2_TX)
+extern int clk_get_usecount(struct clk *clk);
+static struct clk *usb_clk;
+static struct clk *usb_phy_clk;
+
+void fsl_phy_usb_utmi_init(struct fsl_xcvr_ops *this)
+{
+}
+
+void fsl_phy_usb_utmi_uninit(struct fsl_xcvr_ops *this)
+{
+}
+
+/*!
+ * set vbus power
+ *
+ * @param view viewport register
+ * @param on power on or off
+ */
+void fsl_phy_set_power(struct fsl_xcvr_ops *this,
+ struct fsl_usb2_platform_data *pdata, int on)
+{
+ /* USB_POWER_ENABLE_PIN have request at pin init*/
+ if (pdata->phy_regs != USBPHY1_PHYS_ADDR) {
+ pr_debug("%s: on is %d\n", __func__, on);
+ gpio_direction_output(USB_POWER_ENABLE, on);
+ gpio_set_value(USB_POWER_ENABLE, on);
+ }
+}
static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat)
{
fsl_platform_set_usb_phy_dis(plat, 0);
}
-static int usbotg_init_ext(struct platform_device *pdev)
+static int internal_phy_clk_already_on;
+static void usbotg_internal_phy_clock_gate(bool on)
{
- struct clk *usb_clk;
+ u32 tmp;
+ void __iomem *phy_reg = IO_ADDRESS(USBPHY0_PHYS_ADDR);
+ if (on) {
+ internal_phy_clk_already_on += 1;
+ if (internal_phy_clk_already_on == 1) {
+ pr_debug ("%s, Clock on UTMI \n", __func__);
+ tmp = BM_USBPHY_CTRL_SFTRST | BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
+ } else {
+ internal_phy_clk_already_on -= 1;
+ if (internal_phy_clk_already_on == 0) {
+ pr_debug ("%s, Clock off UTMI \n", __func__);
+ tmp = BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
+ }
+ }
+ if (internal_phy_clk_already_on < 0)
+ printk(KERN_ERR "please check internal phy clock ON/OFF sequence \n");
+}
+static int usbotg_init_ext(struct platform_device *pdev)
+{
usb_clk = clk_get(NULL, "usb_clk0");
clk_enable(usb_clk);
clk_put(usb_clk);
+ usb_phy_clk = clk_get(NULL, "usb_phy_clk0");
+ clk_enable(usb_phy_clk);
+ clk_put(usb_phy_clk);
+
+ usbotg_internal_phy_clock_gate(true);
return usbotg_init(pdev);
}
+static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata)
+{
+ usbotg_uninit(pdata);
+
+ usbotg_internal_phy_clock_gate(false);
+ clk_disable(usb_phy_clk);
+ clk_disable(usb_clk);
+}
+
+static void usbotg_clock_gate(bool on)
+{
+ pr_debug("%s: on is %d\n", __func__, on);
+ if (on) {
+ clk_enable(usb_clk);
+ clk_enable(usb_phy_clk);
+ usbotg_internal_phy_clock_gate(on);
+ } else {
+ usbotg_internal_phy_clock_gate(on);
+ clk_disable(usb_phy_clk);
+ clk_disable(usb_clk);
+ }
+
+ pr_debug("usb_clk0_ref_count:%d, usb_phy_clk0_ref_count:%d\n", clk_get_usecount(usb_clk), clk_get_usecount(usb_phy_clk));
+}
+
+/* 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 low_power_enable_src; /* only useful at otg mode */
+static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+ void __iomem *usb_reg = pdata->regs;
+ u32 tmp;
+ pr_debug("DR: %s, enable is %d\n", __func__, enable);
+
+ if (enable) {
+ tmp = __raw_readl(usb_reg + UOG_PORTSC1);
+ tmp |= PORTSC_PHCD;
+ __raw_writel(tmp, usb_reg + UOG_PORTSC1);
+
+ pr_debug("%s, Poweroff UTMI \n", __func__);
+
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET);
+
+ pr_debug ("%s, Polling UTMI enter suspend \n", __func__);
+ while (tmp & BM_USBPHY_CTRL_UTMI_SUSPENDM)
+ tmp = __raw_readl(phy_reg + HW_USBPHY_CTRL);
+ } else {
+ tmp = (BM_USBPHY_PWD_TXPWDFS
+ | BM_USBPHY_PWD_TXPWDIBIAS
+ | BM_USBPHY_PWD_TXPWDV2I
+ | BM_USBPHY_PWD_RXPWDENV
+ | BM_USBPHY_PWD_RXPWD1PT1
+ | BM_USBPHY_PWD_RXPWDDIFF
+ | BM_USBPHY_PWD_RXPWDRX);
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+
+ tmp = __raw_readl(usb_reg + UOG_PORTSC1);
+ tmp &= ~PORTSC_PHCD;
+ __raw_writel(tmp, usb_reg + UOG_PORTSC1);
+ }
+}
+
+static void __phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable, int source)
+{
+ if (enable) {
+ low_power_enable_src |= source;
+#ifdef CONFIG_USB_OTG
+ if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ pr_debug("phy lowpower enabled\n");
+ enter_phy_lowpower_suspend(pdata, enable);
+ }
+#else
+ enter_phy_lowpower_suspend(pdata, enable);
+#endif
+ } else {
+ pr_debug("phy lowpower disable\n");
+ enter_phy_lowpower_suspend(pdata, enable);
+ low_power_enable_src &= ~source;
+ }
+}
+
+static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __phy_lowpower_suspend(pdata, enable, ENABLED_BY_HOST);
+}
+
+static void _device_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __phy_lowpower_suspend(pdata, enable, ENABLED_BY_DEVICE);
+}
+
+static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ u32 tmp;
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+
+ pr_debug("%s, enable is %d\n", __func__, enable);
+ if (enable) {
+ tmp = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+
+ __raw_writel(BM_USBPHY_CTRL_ENIRQWAKEUP, phy_reg + HW_USBPHY_CTRL_SET);
+ } else {
+ tmp = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+
+ __raw_writel(BM_USBPHY_CTRL_ENIRQWAKEUP, phy_reg + HW_USBPHY_CTRL_CLR);
+ /* The interrupt must be disabled for at least 3
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+static u32 wakeup_irq_enable_src; /* only useful at otg mode */
+static void __wakeup_irq_enable(struct fsl_usb2_platform_data *pdata, 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_USB_OTG
+ wakeup_irq_enable_src |= source;
+ if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ otg_wake_up_enable(pdata, on);
+ }
+#else
+ otg_wake_up_enable(pdata, on);
+#endif
+ } else {
+ otg_wake_up_enable(pdata, on);
+ 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)
+{
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+ u32 tmp;
+
+ __wakeup_irq_enable(pdata, enable, ENABLED_BY_HOST);
+ tmp = BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENDPDMCHG_WKUP;
+ /* host only care the ID change wakeup event */
+ if (enable) {
+ pr_debug("DR: host wakeup enable\n");
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
+ } else {
+ pr_debug("DR: host wakeup disable\n");
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+ /* 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)
+{
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+ u32 tmp;
+
+ tmp = BM_USBPHY_CTRL_ENVBUSCHG_WKUP | BM_USBPHY_CTRL_ENDPDMCHG_WKUP;
+ __wakeup_irq_enable(pdata, enable, ENABLED_BY_DEVICE);
+ /* if udc is not used by any gadget, we can not enable the vbus wakeup */
+ if (!pdata->port_enables) {
+ __raw_writel(BM_USBPHY_CTRL_ENVBUSCHG_WKUP, phy_reg + HW_USBPHY_CTRL_CLR);
+ return;
+ }
+ if (enable) {
+ pr_debug("device wakeup enable\n");
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
+ } else {
+ pr_debug("device wakeup disable\n");
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
+}
+
+static bool _is_host_wakeup(struct fsl_usb2_platform_data *pdata)
+{
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+ void __iomem *usb_reg = pdata->regs;
+ u32 wakeup_irq_bits, wakeup_req, otgsc;
+
+ pr_debug("%s\n", __func__);
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ otgsc = __raw_readl(usb_reg + UOG_OTGSC);
+
+ if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits)
+ wakeup_req = 1;
+
+ /* if ID change sts, it is a host wakeup event */
+ if (wakeup_req && (otgsc & OTGSC_IS_USB_ID)) {
+ pr_debug("otg host ID wakeup\n");
+ /* if host ID wakeup, we must clear the b session change sts */
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ __raw_writel(otgsc & (~OTGSC_IS_USB_ID), usb_reg + UOG_OTGSC);
+ return true;
+ }
+ if (wakeup_req /*&& (!((otgsc & OTGSC_IS_B_SESSION_VALID)))*/ && (!((otgsc & OTGSC_STS_USB_ID)))) {
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ pr_debug("otg host Remote wakeup\n");
+ return true;
+ }
+ return false;
+}
+
+static bool _is_device_wakeup(struct fsl_usb2_platform_data *pdata)
+{
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+ void __iomem *usb_reg = pdata->regs;
+ u32 wakeup_irq_bits, wakeup_req, otgsc;
+
+ pr_debug("%s\n", __func__);
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ otgsc = __raw_readl(usb_reg + UOG_OTGSC);
+ if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits) {
+ wakeup_req = 1;
+ }
+
+ /* if ID change sts, it is a host wakeup event */
+ if (wakeup_req && !(otgsc & OTGSC_IS_USB_ID) && (otgsc & OTGSC_IS_B_SESSION_VALID)) {
+ pr_debug("otg device wakeup\n");
+ /* if host ID wakeup, we must clear the b session change sts */
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ return true;
+ }
+
+ return false;
+}
+
/*
* platform data structs
* - Which one to use is determined by CONFIG options in usb.h
@@ -54,7 +350,8 @@ static int usbotg_init_ext(struct platform_device *pdev)
static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
.name = "DR",
.platform_init = usbotg_init_ext,
- .platform_uninit = usbotg_uninit,
+ .platform_uninit = usbotg_uninit_ext,
+ .usb_clock_for_pm = usbotg_clock_gate,
.phy_mode = FSL_USB2_PHY_UTMI_WIDE,
.power_budget = 500, /* 500 mA max power */
.platform_resume = usb_host_phy_resume,
@@ -131,44 +428,89 @@ static struct platform_device __maybe_unused dr_otg_device = {
.num_resources = ARRAY_SIZE(udc_resources),
};
+static struct resource usbotg_wakeup_resources[] = {
+ {
+ .start = IRQ_USB0_WAKEUP, /*wakeup irq*/
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_USB0, /* usb core irq */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxs_usbotg_wakeup_device = {
+ .name = "usb_wakeup",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(usbotg_wakeup_resources),
+ .resource = usbotg_wakeup_resources,
+};
+
+static struct fsl_usb2_wakeup_platform_data usbdr_wakeup_config = {
+ .name = "DR wakeup",
+ .usb_clock_for_pm = usbotg_clock_gate,
+};
static int __init usb_dr_init(void)
{
+ struct platform_device *pdev;
+
pr_debug("%s: \n", __func__);
+ dr_utmi_config.change_ahb_burst = 1;
+ dr_utmi_config.ahb_burst_mode = 0;
- dr_register_otg();
- dr_register_host(otg_resources, ARRAY_SIZE(otg_resources));
- dr_register_udc();
+#ifdef CONFIG_USB_OTG
+ dr_utmi_config.operating_mode = FSL_USB2_DR_OTG;
+ /* wake_up_enalbe is useless, just for usb_register_remote_wakeup execution*/
+ dr_utmi_config.wake_up_enable = _device_wakeup_enable;
+ dr_utmi_config.irq_delay = 0;
- PDATA->change_ahb_burst = 1;
- PDATA->ahb_burst_mode = 0;
- return 0;
-}
+ if (platform_device_register(&dr_otg_device))
+ printk(KERN_ERR "usb DR: can't register otg device\n");
+ else {
+ platform_device_add_data(&dr_otg_device, &dr_utmi_config, sizeof(dr_utmi_config));
+ usbdr_wakeup_config.usb_pdata[0] = dr_otg_device.dev.platform_data;
+ }
+#endif
-void fsl_phy_usb_utmi_init(struct fsl_xcvr_ops *this)
-{
-}
+#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;
+ dr_utmi_config.is_wakeup_event = _is_host_wakeup;
+ dr_utmi_config.irq_delay = 0;
+ pdev = host_pdev_register(otg_resources,
+ ARRAY_SIZE(otg_resources), &dr_utmi_config);
+ if (pdev)
+ usbdr_wakeup_config.usb_pdata[1] = pdev->dev.platform_data;
+ else
+ printk(KERN_ERR "usb DR: can't alloc platform device for host\n");
+#endif
-void fsl_phy_usb_utmi_uninit(struct fsl_xcvr_ops *this)
-{
-}
+#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;
+ dr_utmi_config.is_wakeup_event = _is_device_wakeup;
+ dr_utmi_config.irq_delay = 0;
-/*!
- * set vbus power
- *
- * @param view viewport register
- * @param on power on or off
- */
-void fsl_phy_set_power(struct fsl_xcvr_ops *this,
- struct fsl_usb2_platform_data *pdata, int on)
-{
- /* USB_POWER_ENABLE_PIN have request at pin init*/
- if (pdata->phy_regs != USBPHY1_PHYS_ADDR) {
- gpio_direction_output(USB_POWER_ENABLE, on);
- gpio_set_value(USB_POWER_ENABLE, on);
+ if (platform_device_register(&dr_udc_device))
+ printk(KERN_ERR "usb DR: can't register udc device\n");
+ else {
+ platform_device_add_data(&dr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config));
+ usbdr_wakeup_config.usb_pdata[2] = dr_udc_device.dev.platform_data;
}
-}
+#endif
+ mxs_usbotg_wakeup_device.dev.platform_data = &usbdr_wakeup_config;
+
+ if (platform_device_register(&mxs_usbotg_wakeup_device))
+ printk(KERN_ERR "usb DR wakeup device\n");
+ else
+ printk(KERN_INFO "usb DR wakeup device is registered\n");
+
+ return 0;
+}
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
fs_initcall(usb_dr_init);
#else
diff --git a/arch/arm/mach-mx28/usb_h1.c b/arch/arm/mach-mx28/usb_h1.c
index 2bda34f8b237..8bb5a16bb377 100644
--- a/arch/arm/mach-mx28/usb_h1.c
+++ b/arch/arm/mach-mx28/usb_h1.c
@@ -30,14 +30,37 @@
#include "usb.h"
extern int clk_get_usecount(struct clk *clk);
-struct clk *usb_clk;
-struct clk *usb_phy_clk;
+static struct clk *usb_clk;
+static struct clk *usb_phy_clk;
static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat)
{
fsl_platform_set_usb_phy_dis(plat, 0);
}
+static int internal_phy_clk_already_on;
+static void usbh1_internal_phy_clock_gate(bool on)
+{
+ u32 tmp;
+ void __iomem *phy_reg = IO_ADDRESS(USBPHY1_PHYS_ADDR);
+ if (on) {
+ internal_phy_clk_already_on += 1;
+ if (internal_phy_clk_already_on == 1) {
+ pr_debug ("%s, Clock on UTMI \n", __func__);
+ tmp = BM_USBPHY_CTRL_SFTRST | BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
+ } else {
+ internal_phy_clk_already_on -= 1;
+ if (internal_phy_clk_already_on == 0) {
+ pr_debug ("%s, Clock off UTMI \n", __func__);
+ tmp = BM_USBPHY_CTRL_CLKGATE;
+ __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
+ }
+ }
+ if (internal_phy_clk_already_on < 0)
+ printk(KERN_ERR "please check internal phy clock ON/OFF sequence \n");
+}
static int fsl_usb_host_init_ext(struct platform_device *pdev)
{
usb_clk = clk_get(NULL, "usb_clk1");
@@ -48,12 +71,14 @@ static int fsl_usb_host_init_ext(struct platform_device *pdev)
clk_enable(usb_phy_clk);
clk_put(usb_phy_clk);
+ usbh1_internal_phy_clock_gate(true);
return fsl_usb_host_init(pdev);
}
static void fsl_usb_host_uninit_ext(struct fsl_usb2_platform_data *pdata)
{
fsl_usb_host_uninit(pdata);
+ usbh1_internal_phy_clock_gate(false);
clk_disable(usb_phy_clk);
clk_disable(usb_clk);
}
@@ -68,23 +93,20 @@ static void usbh1_clock_gate(bool on)
clk_disable(usb_phy_clk);
clk_disable(usb_clk);
}
- pr_debug("usb_clk_ref_count:%d, usb_phy_clk_ref_count:%d\n", clk_get_usecount(usb_clk), clk_get_usecount(usb_phy_clk));
+ pr_debug("usb_clk1_ref_count:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_clk), clk_get_usecount(usb_phy_clk));
}
static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
{
- pr_debug("host1, %s, enable is %d\n", __func__, enable);
- void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
- void __iomem *usb_reg = pdata->regs;
u32 tmp;
+ void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
+
+ pr_debug("host1, %s, enable is %d\n", __func__, enable);
if (enable) {
tmp = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
__raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
tmp = (BM_USBPHY_CTRL_ENIRQWAKEUP
- | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE
- | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD
- | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE
| BM_USBPHY_CTRL_ENIDCHG_WKUP
| BM_USBPHY_CTRL_ENDPDMCHG_WKUP);
__raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
@@ -93,9 +115,6 @@ static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
__raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
tmp = (BM_USBPHY_CTRL_ENIRQWAKEUP
- | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE
- | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD
- | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE
| BM_USBPHY_CTRL_ENIDCHG_WKUP
| BM_USBPHY_CTRL_ENDPDMCHG_WKUP);
@@ -131,16 +150,7 @@ static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool ena
pr_debug ("%s, Polling UTMI enter suspend \n", __func__);
while (tmp & BM_USBPHY_CTRL_UTMI_SUSPENDM)
tmp = __raw_readl(phy_reg + HW_USBPHY_CTRL);
-
- pr_debug ("%s, Clock off UTMI \n", __func__);
- tmp = BM_USBPHY_CTRL_CLKGATE;
- __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_SET);
-
} else {
- pr_debug ("%s, Enable USB phy\n", __func__);
- tmp = BM_USBPHY_CTRL_SFTRST | BM_USBPHY_CTRL_CLKGATE;
- __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
-
tmp = (BM_USBPHY_PWD_TXPWDFS
| BM_USBPHY_PWD_TXPWDIBIAS
| BM_USBPHY_PWD_TXPWDV2I
@@ -158,9 +168,10 @@ static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool ena
static bool _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata)
{
- pr_debug("host1, %s\n", __func__);
void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
u32 tmp;
+
+ pr_debug("host1, %s\n", __func__);
tmp = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && tmp) {
__raw_writel(tmp, phy_reg + HW_USBPHY_CTRL_CLR);
@@ -217,18 +228,18 @@ static struct resource usbh1_wakeup_resources[] = {
struct platform_device mxs_usbh1_wakeup_device = {
.name = "usb_wakeup",
- .id = 1,
+ .id = 2,
.num_resources = ARRAY_SIZE(usbh1_wakeup_resources),
.resource = usbh1_wakeup_resources,
};
static int __init usbh1_init(void)
{
- pr_debug("%s: \n", __func__);
-
struct platform_device *pdev = host_pdev_register(usbh1_resources,
ARRAY_SIZE(usbh1_resources), &usbh1_config);
+ pr_debug("%s: \n", __func__);
+
/* the platform device(usb h1)'s pdata address has changed */
usbh1_wakeup_config.usb_pdata[0] = pdev->dev.platform_data;
mxs_usbh1_wakeup_device.dev.platform_data = &usbh1_wakeup_config;
diff --git a/arch/arm/plat-mxs/usb_common.c b/arch/arm/plat-mxs/usb_common.c
index d8503cc3c470..a3b18beb1be5 100644
--- a/arch/arm/plat-mxs/usb_common.c
+++ b/arch/arm/plat-mxs/usb_common.c
@@ -103,8 +103,6 @@ EXPORT_SYMBOL(fsl_platform_set_usb_phy_dis);
#if defined(CONFIG_USB_OTG)
-static struct otg_transceiver *xceiv;
-
static struct resource *otg_resources;
struct resource *otg_get_resources(void)
@@ -280,7 +278,6 @@ int usbotg_init(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
struct fsl_xcvr_ops *xops;
- u32 tmp;
pr_debug("%s: pdev=0x%p pdata=0x%p\n", __func__, pdev, pdata);
@@ -299,10 +296,6 @@ int usbotg_init(struct platform_device *pdev)
xops->init(xops);
usb_phy_enable(pdata);
}
- /* Enable internal Phy clock */
- tmp = __raw_readl(pdata->regs + UOG_PORTSC1);
- tmp &= ~PORTSC_PHCD;
- __raw_writel(tmp, pdata->regs + UOG_PORTSC1);
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG)) {
@@ -311,6 +304,9 @@ int usbotg_init(struct platform_device *pdev)
, IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_SET);
}
+ if (usb_register_remote_wakeup(pdev))
+ pr_debug("%s port is not a wakeup source.\n", pdata->name);
+
otg_used++;
pr_debug("%s: success\n", __func__);
return 0;
@@ -319,22 +315,11 @@ EXPORT_SYMBOL(usbotg_init);
void usbotg_uninit(struct fsl_usb2_platform_data *pdata)
{
- int tmp;
- struct clk *usb_clk;
pr_debug("%s\n", __func__);
if (pdata->xcvr_ops && pdata->xcvr_ops->uninit)
pdata->xcvr_ops->uninit(pdata->xcvr_ops);
- /* Disable internal Phy clock */
- tmp = __raw_readl(pdata->regs + UOG_PORTSC1);
- tmp |= PORTSC_PHCD;
- __raw_writel(tmp, pdata->regs + UOG_PORTSC1);
-
- usb_clk = clk_get(NULL, "usb_clk0");
- clk_disable(usb_clk);
- clk_put(usb_clk);
-
pdata->regs = NULL;
otg_used--;
}
@@ -376,7 +361,6 @@ EXPORT_SYMBOL(fsl_usb_host_init);
void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata)
{
- struct clk *usb_clk;
pr_debug("%s\n", __func__);
if (pdata->xcvr_ops && pdata->xcvr_ops->uninit)
@@ -395,11 +379,6 @@ void usb_debounce_id_pin(void)
mdelay(3);
}
EXPORT_SYMBOL(usb_debounce_id_pin);
-int usb_event_is_otg_wakeup(void)
-{
- return 0;
-}
-EXPORT_SYMBOL(usb_event_is_otg_wakeup);
int usb_host_wakeup_irq(struct device *wkup_dev)
{
return 0;
@@ -418,6 +397,18 @@ EXPORT_SYMBOL(usb_host_set_wakeup);
#define USBPHY_PHYS_ADDR USBPHY0_PHYS_ADDR
#endif
+int usb_event_is_otg_wakeup(void)
+{
+ u32 wakeup_irq_bits;
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+
+ if (__raw_readl(IO_ADDRESS(USBPHY_PHYS_ADDR) + HW_USBPHY_STATUS) && wakeup_irq_bits) {
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL(usb_event_is_otg_wakeup);
+
int fsl_is_usb_plugged(void)
{
return __raw_readl(IO_ADDRESS(USBPHY_PHYS_ADDR) + HW_USBPHY_STATUS) & \
diff --git a/arch/arm/plat-mxs/usb_wakeup.c b/arch/arm/plat-mxs/usb_wakeup.c
index 56e45052e0ff..1f619f184c15 100644
--- a/arch/arm/plat-mxs/usb_wakeup.c
+++ b/arch/arm/plat-mxs/usb_wakeup.c
@@ -21,6 +21,8 @@
#include <linux/mutex.h>
#include <linux/fsl_devices.h>
#include <linux/suspend.h>
+#include <linux/io.h>
+#include <mach/arc_otg.h>
struct wakeup_ctrl {
int wakeup_irq;
@@ -51,22 +53,16 @@ static bool usb2_is_in_lowpower(struct wakeup_ctrl *ctrl)
return false;
}
}
+
return true;
}
static void delay_process_wakeup(struct wakeup_ctrl *ctrl)
{
- int i;
- struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata;
disable_irq_nosync(ctrl->wakeup_irq);
if ((ctrl->usb_irq > 0) && (ctrl->wakeup_irq != ctrl->usb_irq))
disable_irq_nosync(ctrl->usb_irq);
- for (i = 0; i < 3; i++) {
- if (pdata->usb_pdata[i]) {
- pdata->usb_pdata[i]->irq_delay = 1;
- }
- }
complete(&ctrl->event);
}
@@ -86,6 +82,7 @@ static bool is_wakeup(struct fsl_usb2_platform_data *pdata)
{
if (pdata->is_wakeup_event)
return pdata->is_wakeup_event(pdata);
+
return false;
}
@@ -104,12 +101,11 @@ static void wakeup_event_handler(struct wakeup_ctrl *ctrl)
for (i = 0; i < 3; i++) {
struct fsl_usb2_platform_data *usb_pdata = pdata->usb_pdata[i];
if (usb_pdata) {
- usb_pdata->irq_delay = 0;
if (is_wakeup(usb_pdata)) {
- pr_debug("%s:%d\n", __func__, __LINE__);
usb_pdata->wakeup_event = 1;
- if (usb_pdata->usb_clock_for_pm)
- usb_pdata->usb_clock_for_pm(true);
+ if (usb2_is_in_lowpower(ctrl))
+ if (usb_pdata->usb_clock_for_pm)
+ usb_pdata->usb_clock_for_pm(true);
usb_pdata->lowpower = 0;
}
}