aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-mx28/usb_dr.c56
-rw-r--r--arch/arm/mach-mx28/usb_h1.c31
-rw-r--r--arch/arm/plat-mxs/usb_wakeup.c21
3 files changed, 86 insertions, 22 deletions
diff --git a/arch/arm/mach-mx28/usb_dr.c b/arch/arm/mach-mx28/usb_dr.c
index 05eb706822ce..9a40751e094f 100644
--- a/arch/arm/mach-mx28/usb_dr.c
+++ b/arch/arm/mach-mx28/usb_dr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -34,7 +34,8 @@
extern int clk_get_usecount(struct clk *clk);
static struct clk *usb_clk;
static struct clk *usb_phy_clk;
-
+extern void fsl_usb_recover_hcd(struct platform_device *pdev);
+static struct platform_device *otg_host_pdev;
void fsl_phy_usb_utmi_init(struct fsl_xcvr_ops *this)
{
}
@@ -289,7 +290,7 @@ static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool ena
}
}
-static bool _is_host_wakeup(struct fsl_usb2_platform_data *pdata)
+static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata)
{
void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
void __iomem *usb_reg = pdata->regs;
@@ -308,17 +309,17 @@ static bool _is_host_wakeup(struct fsl_usb2_platform_data *pdata)
/* 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;
+ return WAKEUP_EVENT_ID;
}
- if (wakeup_req /*&& (!((otgsc & OTGSC_IS_B_SESSION_VALID)))*/ && (!((otgsc & OTGSC_STS_USB_ID)))) {
+ if (wakeup_req && (!(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 WAKEUP_EVENT_DPDM;
}
- return false;
+ return WAKEUP_EVENT_INVALID;
}
-static bool _is_device_wakeup(struct fsl_usb2_platform_data *pdata)
+static enum usb_wakeup_event _is_device_wakeup(struct fsl_usb2_platform_data *pdata)
{
void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
void __iomem *usb_reg = pdata->regs;
@@ -332,14 +333,39 @@ static bool _is_device_wakeup(struct fsl_usb2_platform_data *pdata)
}
/* if ID change sts, it is a host wakeup event */
- if (wakeup_req && !(otgsc & OTGSC_IS_USB_ID) && (otgsc & OTGSC_IS_B_SESSION_VALID)) {
+ if (wakeup_req && (otgsc & OTGSC_STS_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 WAKEUP_EVENT_VBUS;
}
- return false;
+ return WAKEUP_EVENT_INVALID;
+}
+
+static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _host_wakeup_enable(pdata, false);
+ _host_phy_lowpower_suspend(pdata, false);
+ fsl_usb_recover_hcd(otg_host_pdev);
+}
+
+static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _device_wakeup_enable(pdata, false);
+ _device_phy_lowpower_suspend(pdata, false);
+}
+
+static void usbotg_wakeup_event_clear(void)
+{
+ void __iomem *phy_reg = IO_ADDRESS(USBPHY0_PHYS_ADDR);
+ u32 wakeup_irq_bits;
+
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits) {
+ /* clear the wakeup interrupt status */
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
}
/*
@@ -449,6 +475,7 @@ struct platform_device mxs_usbotg_wakeup_device = {
static struct fsl_usb2_wakeup_platform_data usbdr_wakeup_config = {
.name = "DR wakeup",
.usb_clock_for_pm = usbotg_clock_gate,
+ .usb_wakeup_exhandle = usbotg_wakeup_event_clear,
};
static int __init usb_dr_init(void)
@@ -478,14 +505,16 @@ static int __init usb_dr_init(void)
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.wakeup_handler = host_wakeup_handler;
dr_utmi_config.is_wakeup_event = _is_host_wakeup;
dr_utmi_config.irq_delay = 0;
dr_utmi_config.wakeup_pdata = &usbdr_wakeup_config;
pdev = host_pdev_register(otg_resources,
ARRAY_SIZE(otg_resources), &dr_utmi_config);
- if (pdev)
+ if (pdev) {
usbdr_wakeup_config.usb_pdata[1] = pdev->dev.platform_data;
- else
+ otg_host_pdev = pdev;
+ } else
printk(KERN_ERR "usb DR: can't alloc platform device for host\n");
#endif
@@ -494,6 +523,7 @@ static int __init usb_dr_init(void)
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.wakeup_handler = device_wakeup_handler;
dr_utmi_config.irq_delay = 0;
dr_utmi_config.wakeup_pdata = &usbdr_wakeup_config;
diff --git a/arch/arm/mach-mx28/usb_h1.c b/arch/arm/mach-mx28/usb_h1.c
index f4d5ba40f254..0c36d8f04130 100644
--- a/arch/arm/mach-mx28/usb_h1.c
+++ b/arch/arm/mach-mx28/usb_h1.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -30,8 +30,10 @@
#include "usb.h"
extern int clk_get_usecount(struct clk *clk);
+extern void fsl_usb_recover_hcd(struct platform_device *pdev);
static struct clk *usb_clk;
static struct clk *usb_phy_clk;
+static struct platform_device *h1_pdev;
static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat)
{
@@ -166,7 +168,7 @@ static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool ena
}
}
-static bool _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata)
+static enum usb_wakeup_event _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata)
{
void __iomem *phy_reg = IO_ADDRESS(pdata->phy_regs);
u32 tmp;
@@ -175,11 +177,29 @@ static bool _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata)
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);
- return true;
+ return !WAKEUP_EVENT_INVALID;
} else
- return false;
+ return WAKEUP_EVENT_INVALID;
}
+static void h1_wakeup_handler(struct fsl_usb2_platform_data *pdata)
+{
+ _wake_up_enable(pdata, false);
+ _phy_lowpower_suspend(pdata, false);
+ fsl_usb_recover_hcd(h1_pdev);
+}
+
+static void usbh1_wakeup_event_clear(void)
+{
+ void __iomem *phy_reg = IO_ADDRESS(USBPHY1_PHYS_ADDR);
+ u32 wakeup_irq_bits;
+
+ wakeup_irq_bits = BM_USBPHY_CTRL_RESUME_IRQ | BM_USBPHY_CTRL_WAKEUP_IRQ;
+ if (__raw_readl(phy_reg + HW_USBPHY_CTRL) && wakeup_irq_bits) {
+ /* clear the wakeup interrupt status */
+ __raw_writel(wakeup_irq_bits, phy_reg + HW_USBPHY_CTRL_CLR);
+ }
+}
static struct fsl_usb2_platform_data usbh1_config = {
.name = "Host 1",
.platform_init = fsl_usb_host_init_ext,
@@ -193,6 +213,7 @@ static struct fsl_usb2_platform_data usbh1_config = {
.wake_up_enable = _wake_up_enable,
.phy_lowpower_suspend = _phy_lowpower_suspend,
.is_wakeup_event = _is_usbh1_wakeup,
+ .wakeup_handler = h1_wakeup_handler,
.phy_regs = USBPHY1_PHYS_ADDR,
};
@@ -200,6 +221,7 @@ static struct fsl_usb2_wakeup_platform_data usbh1_wakeup_config = {
.name = "USBH1 wakeup",
.usb_clock_for_pm = usbh1_clock_gate,
.usb_pdata = {&usbh1_config, NULL, NULL},
+ .usb_wakeup_exhandle = usbh1_wakeup_event_clear,
};
/* The resources for kinds of usb devices */
@@ -241,6 +263,7 @@ static int __init usbh1_init(void)
pdev = host_pdev_register(usbh1_resources,
ARRAY_SIZE(usbh1_resources), &usbh1_config);
+ h1_pdev = pdev;
pr_debug("%s: \n", __func__);
/* the platform device(usb h1)'s pdata address has changed */
diff --git a/arch/arm/plat-mxs/usb_wakeup.c b/arch/arm/plat-mxs/usb_wakeup.c
index ecefaeed519c..a020e85445f1 100644
--- a/arch/arm/plat-mxs/usb_wakeup.c
+++ b/arch/arm/plat-mxs/usb_wakeup.c
@@ -80,17 +80,19 @@ static irqreturn_t usb_wakeup_handler(int irq, void *_dev)
return ret;
}
-static bool is_wakeup(struct fsl_usb2_platform_data *pdata)
+static enum usb_wakeup_event is_wakeup(struct fsl_usb2_platform_data *pdata)
{
if (pdata->is_wakeup_event)
return pdata->is_wakeup_event(pdata);
-
- return false;
+ else
+ return WAKEUP_EVENT_INVALID;
}
static void wakeup_event_handler(struct wakeup_ctrl *ctrl)
{
struct fsl_usb2_wakeup_platform_data *pdata = ctrl->pdata;
+ int already_waked = 0;
+ enum usb_wakeup_event wakeup_evt;
int i;
wakeup_clk_gate(ctrl->pdata, true);
@@ -102,15 +104,24 @@ 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) {
- if (is_wakeup(usb_pdata)) {
- usb_pdata->wakeup_event = 1;
+ wakeup_evt = is_wakeup(usb_pdata);
+ if (wakeup_evt != WAKEUP_EVENT_INVALID) {
if (usb2_is_in_lowpower(ctrl))
if (usb_pdata->usb_clock_for_pm)
usb_pdata->usb_clock_for_pm(true);
usb_pdata->lowpower = 0;
+ already_waked = 1;
+ if (usb_pdata->wakeup_handler) {
+ usb_pdata->wakeup_handler(usb_pdata);
+ }
}
}
}
+
+ /* If nothing to wakeup, clear wakeup event */
+ if ((already_waked == 0) && pdata->usb_wakeup_exhandle)
+ pdata->usb_wakeup_exhandle();
+
wakeup_clk_gate(ctrl->pdata, false);
pdata->usb_wakeup_is_pending = false;
wake_up(&pdata->wq);