diff options
-rw-r--r-- | arch/arm/mach-mx28/usb_dr.c | 56 | ||||
-rw-r--r-- | arch/arm/mach-mx28/usb_h1.c | 31 | ||||
-rw-r--r-- | arch/arm/plat-mxs/usb_wakeup.c | 21 |
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); |