From: Hema HK <hemahk@xxxxxx> Calling runtime pm APIs pm_runtime_put_sync() and pm_runtime_get_sync() for enabling/disabling the clocks,sysconfig settings. used omap_hwmod_enable_wakeup & omap_hwmod_disable_wakeup apis to set/clear the wakeup enable bit. Also need to put the USB in force standby and force idle mode when usb not used and set it back to smart idle and smart stndby after wakeup. these cases are handled using the oh flags. For omap3430 auto idle bit has to be disabled because of the errata.So using HWMOD_NO_OCP_AUTOIDLE flag for OMAP3430. Signed-off-by: Hema HK <hemahk@xxxxxx> Signed-off-by: Basak, Partha <p-basak2@xxxxxx> Cc: Felipe Balbi <felipe.balbi@xxxxxxxxx> Cc: Tony Lindgren <tony@xxxxxxxxxxx> Cc: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> --- arch/arm/mach-omap2/pm34xx.c | 10 +++- arch/arm/mach-omap2/usb-musb.c | 72 ++++++++++++++++++++++++++++++- arch/arm/plat-omap/include/plat/usb.h | 9 +++ drivers/usb/musb/musb_core.c | 12 +++++ drivers/usb/musb/omap2430.c | 77 +++++----------------------------- include/linux/usb/musb.h | 18 +++++++ 6 files changed, 126 insertions(+), 72 deletions(-) Index: linux-omap-pm/arch/arm/mach-omap2/pm34xx.c =================================================================== --- linux-omap-pm.orig/arch/arm/mach-omap2/pm34xx.c 2010-08-06 10:44:06.000000000 -0400 +++ linux-omap-pm/arch/arm/mach-omap2/pm34xx.c 2010-08-06 10:44:42.942112875 -0400 @@ -418,7 +418,9 @@ omap3_core_save_context(); omap3_prcm_save_context(); /* Save MUSB context */ - musb_context_save_restore(1); + musb_context_save_restore(save_context); + } else { + musb_context_save_restore(disable_clk); } } @@ -462,8 +464,10 @@ omap3_sram_restore_context(); omap2_sms_restore_context(); /* restore MUSB context */ - musb_context_save_restore(0); - } + musb_context_save_restore(restore_context); + } else { + musb_context_save_restore(enable_clk); + } omap_uart_resume_idle(0); omap_uart_resume_idle(1); if (core_next_state == PWRDM_POWER_OFF) Index: linux-omap-pm/arch/arm/mach-omap2/usb-musb.c =================================================================== --- linux-omap-pm.orig/arch/arm/mach-omap2/usb-musb.c 2010-08-06 10:44:06.000000000 -0400 +++ linux-omap-pm/arch/arm/mach-omap2/usb-musb.c 2010-08-06 10:44:42.942112875 -0400 @@ -25,11 +25,13 @@ #include <linux/io.h> #include <linux/usb/musb.h> +#include <linux/pm_runtime.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <plat/usb.h> #include <plat/omap_device.h> +#include <plat/omap_hwmod.h> #ifdef CONFIG_USB_MUSB_SOC @@ -99,6 +101,18 @@ musb_plat.board_data = board_data; musb_plat.power = board_data->power >> 1; musb_plat.mode = board_data->mode; + musb_plat.device_enable = omap_device_enable; + musb_plat.device_idle = omap_device_idle; + musb_plat.enable_wakeup = omap_device_enable_wakeup; + musb_plat.disable_wakeup = omap_device_disable_wakeup; + /* + * Errata 1.166 idle_req/ack is broken in omap3430 + * workaround is to disable the autodile bit for omap3430. + */ + if (cpu_is_omap3430()) + oh->flags |= HWMOD_NO_OCP_AUTOIDLE; + + musb_plat.oh = oh; pdata = &musb_plat; od = omap_device_build(name, bus_id, oh, pdata, @@ -120,7 +134,7 @@ } } -void musb_context_save_restore(int save) +void musb_context_save_restore(enum musb_state state) { struct omap_hwmod *oh = omap_hwmod_lookup("usb_otg_hs"); struct omap_device *od = oh->od; @@ -129,14 +143,64 @@ struct device_driver *drv = dev->driver; if (drv) { +#ifdef CONFIG_PM_RUNTIME struct musb_hdrc_platform_data *pdata = dev->platform_data; const struct dev_pm_ops *pm = drv->pm; - if (!pdata->is_usb_active(dev)) { - if (save) + if (!pdata->is_usb_active(dev)) { + switch (state) { + case save_context: + /* If the usb device not active then Save + * the context,set the sysconfig setting to + * force standby force idle during idle and + * disable the clock. + */ + oh->flags |= HWMOD_SWSUP_SIDLE + | HWMOD_SWSUP_MSTANDBY; pm->suspend(dev); - else + pdata->device_idle(pdev); + + break; + case disable_clk: + /* If the usb device not active then + * Save the context, set the sysconfig setting + * to force standby force idle during idle and + * disable the clock. + */ + + oh->flags |= HWMOD_SWSUP_SIDLE + | HWMOD_SWSUP_MSTANDBY; + pdata->device_idle(pdev); + + break; + + case restore_context: + /* Enable the clock, set the sysconfig + * back to smart idle and smart stndby after + * wakeup. restore the context. + */ + oh->flags &= ~(HWMOD_SWSUP_SIDLE + | HWMOD_SWSUP_MSTANDBY); + pdata->device_enable(pdev); pm->resume_noirq(dev); + + break; + + case enable_clk: + /* Set the sysconfig back to smart + * idle and smart stndby after wakeup and + * enable the clock + */ + oh->flags &= ~(HWMOD_SWSUP_SIDLE + | HWMOD_SWSUP_MSTANDBY); + pdata->device_enable(pdev); + + break; + + default: + break; + } +#endif } } } Index: linux-omap-pm/arch/arm/plat-omap/include/plat/usb.h =================================================================== --- linux-omap-pm.orig/arch/arm/plat-omap/include/plat/usb.h 2010-08-06 10:44:06.000000000 -0400 +++ linux-omap-pm/arch/arm/plat-omap/include/plat/usb.h 2010-08-06 10:44:42.942112875 -0400 @@ -71,6 +71,13 @@ unsigned extvbus:1; }; +enum musb_state { + save_context = 1, + disable_clk, + restore_context, + enable_clk, + }; + enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI}; extern void usb_musb_init(struct omap_musb_board_data *board_data); @@ -80,7 +87,7 @@ extern void usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata); /* For saving and restoring the musb context during off/wakeup*/ -extern void musb_context_save_restore(int save); +extern void musb_context_save_restore(enum musb_state state); #endif Index: linux-omap-pm/drivers/usb/musb/musb_core.c =================================================================== --- linux-omap-pm.orig/drivers/usb/musb/musb_core.c 2010-08-06 10:44:06.000000000 -0400 +++ linux-omap-pm/drivers/usb/musb/musb_core.c 2010-08-06 10:44:42.942112875 -0400 @@ -2447,9 +2447,21 @@ return 0; } +static int musb_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int musb_runtime_resume(struct device *dev) +{ + return 0; +} + static const struct dev_pm_ops musb_dev_pm_ops = { .suspend = musb_suspend, .resume_noirq = musb_resume_noirq, + .runtime_suspend = musb_runtime_suspend, + .runtime_resume = musb_runtime_resume, }; #define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) Index: linux-omap-pm/drivers/usb/musb/omap2430.c =================================================================== --- linux-omap-pm.orig/drivers/usb/musb/omap2430.c 2010-08-06 10:44:30.093914217 -0400 +++ linux-omap-pm/drivers/usb/musb/omap2430.c 2010-08-06 10:44:42.942112875 -0400 @@ -31,6 +31,7 @@ #include <linux/list.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/pm_runtime.h> #include <plat/mux.h> @@ -209,10 +210,6 @@ struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; -#if defined(CONFIG_ARCH_OMAP2430) - omap_cfg_reg(AE5_2430_USB0HS_STP); -#endif - /* We require some kind of external transceiver, hooked * up through ULPI. TWL4030-family PMICs include one, * which needs a driver, drivers aren't always needed. @@ -224,22 +221,6 @@ } musb_platform_resume(musb); - - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l &= ~ENABLEWAKEUP; /* disable wakeup */ - l &= ~NOSTDBY; /* remove possible nostdby */ - l |= SMARTSTDBY; /* enable smart standby */ - l &= ~AUTOIDLE; /* disable auto idle */ - l &= ~NOIDLE; /* remove possible noidle */ - l |= SMARTIDLE; /* enable smart idle */ - /* - * MUSB AUTOIDLE don't work in 3430. - * Workaround by Richard Woodruff/TI - */ - if (!cpu_is_omap3430()) - l |= AUTOIDLE; /* enable auto idle */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); - l = musb_readl(musb->mregs, OTG_INTERFSEL); if (data->interface_type == MUSB_INTERFACE_UTMI) { @@ -273,48 +254,26 @@ void musb_platform_save_context(struct musb *musb, struct musb_context_registers *musb_context) { - /* - * As per the omap-usbotg specification, configure it to forced standby - * and force idle mode when no activity on usb. - */ void __iomem *musb_base = musb->mregs; - musb_writel(musb_base, OTG_FORCESTDBY, 0); - - musb_writel(musb_base, OTG_SYSCONFIG, musb_readl(musb_base, - OTG_SYSCONFIG) & ~(NOSTDBY | SMARTSTDBY)); - - musb_writel(musb_base, OTG_SYSCONFIG, musb_readl(musb_base, - OTG_SYSCONFIG) & ~(AUTOIDLE)); - - musb_writel(musb_base, OTG_SYSCONFIG, musb_readl(musb_base, - OTG_SYSCONFIG) & ~(NOIDLE | SMARTIDLE)); - musb_writel(musb_base, OTG_FORCESTDBY, 1); } void musb_platform_restore_context(struct musb *musb, struct musb_context_registers *musb_context) { - /* - * As per the omap-usbotg specification, configure it smart standby - * and smart idle during operation. - */ void __iomem *musb_base = musb->mregs; musb_writel(musb_base, OTG_FORCESTDBY, 0); - - musb_writel(musb_base, OTG_SYSCONFIG, musb_readl(musb_base, - OTG_SYSCONFIG) | (SMARTSTDBY)); - - musb_writel(musb_base, OTG_SYSCONFIG, musb_readl(musb_base, - OTG_SYSCONFIG) | (SMARTIDLE)); } #endif static int musb_platform_suspend(struct musb *musb) { u32 l; + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct omap_hwmod *oh = pdata->oh; if (!musb->clock) return 0; @@ -324,16 +283,9 @@ l |= ENABLEFORCE; /* enable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l |= ENABLEWAKEUP; /* enable wakeup */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); - + pdata->enable_wakeup(oh->od); otg_set_suspend(musb->xceiv, 1); - - if (musb->set_clock) - musb->set_clock(musb->clock, 0); - else - clk_disable(musb->clock); + pm_runtime_put_sync(dev); return 0; } @@ -341,21 +293,18 @@ static int musb_platform_resume(struct musb *musb) { u32 l; + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct omap_hwmod *oh = pdata->oh; if (!musb->clock) return 0; otg_set_suspend(musb->xceiv, 0); - - if (musb->set_clock) - musb->set_clock(musb->clock, 1); - else - clk_enable(musb->clock); - - l = musb_readl(musb->mregs, OTG_SYSCONFIG); - l &= ~ENABLEWAKEUP; /* disable wakeup */ - musb_writel(musb->mregs, OTG_SYSCONFIG, l); - + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + pdata->disable_wakeup(oh->od); + pdata->enable_wakeup(oh->od); l = musb_readl(musb->mregs, OTG_FORCESTDBY); l &= ~ENABLEFORCE; /* disable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); Index: linux-omap-pm/include/linux/usb/musb.h =================================================================== --- linux-omap-pm.orig/include/linux/usb/musb.h 2010-08-06 10:44:06.000000000 -0400 +++ linux-omap-pm/include/linux/usb/musb.h 2010-08-06 10:44:42.946115274 -0400 @@ -10,6 +10,9 @@ #ifndef __LINUX_USB_MUSB_H #define __LINUX_USB_MUSB_H +#include <linux/platform_device.h> +#include <plat/omap_hwmod.h> + /* The USB role is defined by the connector used on the board, so long as * standards are being followed. (Developer boards sometimes won't.) */ @@ -129,6 +132,21 @@ /* check usb device active state*/ int (*is_usb_active)(struct device *dev); + + /* omap hwmod data structure */ + struct omap_hwmod *oh; + + /* enable clocks and set sysconfig register*/ + int (*device_enable)(struct platform_device *pdev); + + /* Disable clock and reset the sysconfig register settings*/ + int (*device_idle)(struct platform_device *pdev); + + /* set the enable wakeup bit of sysconfig register */ + int (*enable_wakeup)(struct omap_device *od); + + /* Clear the enable wakeup bit of sysconfig register */ + int (*disable_wakeup)(struct omap_device *od); }; -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html