aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2011-01-12 10:47:42 +0800
committerPeter Chen <peter.chen@freescale.com>2011-01-12 11:14:45 +0800
commitd570035407de42cc073610b59fe988dc9a0e4293 (patch)
tree374d6c17d0144eda5f4b04e9fa0d2dec4135dca9
parent9703ad72ecce2c38d3e26a1aa4bfd0b141000151 (diff)
ENGR00137872-1 mx28_msl: move wakeup handle from driver to MSL
There were two places to handle wakeup irq routine, one is MSL, The other is at driver. It increases the complexity for maintaining and reading. So, in this serial of patches, I move the wakeup irq handler from the driver to MSL. The main changes like belows: For wakeup event, classify the wakeup event like below: enum usb_wakeup_event { WAKEUP_EVENT_INVALID, WAKEUP_EVENT_VBUS, WAKEUP_EVENT_ID, WAKEUP_EVENT_DPDM, }; For host driver, it is better to delete ehci_fsl_pre_irq, and put related wakeup operation to usb_wakeup thread at MSL code. As at MSL, It can't touch usb hcd struct, I have exported one function at fsl host driver to handle hcd issues. For device driver, move wake_up_irq to usb_wakeup thread at MSL code Revert the commit that changing mutex_lock to spin_lock_irqsave at udc_resume. The reason is the clock related function should not be called at irq_disabled situations and interrupt context. Signed-off-by: Peter Chen <peter.chen@freescale.com>
-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);