Hi, >-----Original Message----- >From: Kevin Hilman [mailto:khilman@xxxxxxxxxxxxxxxxxxx] >Sent: Thursday, August 26, 2010 5:44 AM >To: Kalliguddi, Hema >Cc: linux-omap@xxxxxxxxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx; >Basak, Partha; Felipe Balbi; Tony Lindgren; Cousson, Benoit; >Paul Walmsley >Subject: Re: [PATCH 8/8 v2] usb : musb: Using runtime pm apis for musb. > >Hema HK <hemahk@xxxxxx> writes: > >> 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> >> Cc: Cousson, Benoit <b-cousson@xxxxxx> >> Cc: Paul Walmsley <paul@xxxxxxxxx> >> --- >> arch/arm/mach-omap2/pm34xx.c | 8 ++- >> arch/arm/mach-omap2/usb-musb.c | 86 >++++++++++++++++++++++++++++++-- >> arch/arm/plat-omap/include/plat/usb.h | 9 +++- >> drivers/usb/musb/musb_core.c | 12 +++++ >> drivers/usb/musb/omap2430.c | 65 >+++++-------------------- >> include/linux/usb/musb.h | 8 +++ >> 6 files changed, 127 insertions(+), 61 deletions(-) >> >> diff --git a/arch/arm/mach-omap2/pm34xx.c >b/arch/arm/mach-omap2/pm34xx.c >> index 7b34201..0eb39b3 100644 >> --- a/arch/arm/mach-omap2/pm34xx.c >> +++ b/arch/arm/mach-omap2/pm34xx.c >> @@ -418,7 +418,9 @@ void omap_sram_idle(void) >> 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); > >Presumably the 'disable_clk' is meant to mean "no need to save context, >just disable clock", in which case the function name is not really >accurate anymore. > >What is needed is just a general function that takes the next power >state and let the function internals make the decision. The idle loop >should not have IP-specific logic in it. > >I don't really want any IP specific logic in this part of the >idle loop. >What I really would like to see is all of this driver specific stuff >moved out of the core idle path and done before interrupts are >disabled. > >If we can do this before interrups are disabled (a bit earlier in the >CPUidle path), then we can just use the normal runtime PM API and not >have to handle the special cases of doing all this black magic inside >the core idle path. > This can be done. I will have a generic usb idle and wakeup functions defined and will be called with next/previous core state as parameter and call Before/after the interrupts are disabled/enabled as you suggested, and handle the required cases in the musb module. I will post the patch with changes after testing. >> } >> } >> >> @@ -462,7 +464,9 @@ void omap_sram_idle(void) >> 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); >> diff --git a/arch/arm/mach-omap2/usb-musb.c >b/arch/arm/mach-omap2/usb-musb.c >> index 9d10440..b7736d2 100644 >> --- a/arch/arm/mach-omap2/usb-musb.c >> +++ b/arch/arm/mach-omap2/usb-musb.c >> @@ -23,6 +23,7 @@ >> #include <linux/clk.h> >> #include <linux/dma-mapping.h> >> #include <linux/io.h> >> +#include <linux/pm_runtime.h> >> >> #include <linux/usb/musb.h> >> >> @@ -64,13 +65,32 @@ static struct musb_hdrc_platform_data >musb_plat = { >> /* supports clock autogating */ >> .clk_autogated = 1, >> }; >> +static int usb_idle_hwmod(struct omap_device *od) >> +{ >> + struct omap_hwmod *oh = *od->hwmods; >> + if (irqs_disabled()) >> + _omap_hwmod_idle(oh); >> + else >> + omap_device_idle_hwmods(od); >> + return 0; >> +} >> + >> +static int usb_enable_hwmod(struct omap_device *od) >> +{ >> + struct omap_hwmod *oh = *od->hwmods; >> + if (irqs_disabled()) >> + _omap_hwmod_enable(oh); >> + else >> + omap_device_enable_hwmods(od); >> + return 0; >> +} > >see above. Please move the musb pre-idle outside of the interrupts >disabled part of the idle loop and you can get rid of this special >handling. Agreed. > >> static u64 musb_dmamask = DMA_BIT_MASK(32); >> >> static struct omap_device_pm_latency omap_musb_latency[] = { >> { >> - .deactivate_func = omap_device_idle_hwmods, >> - .activate_func = omap_device_enable_hwmods, >> + .deactivate_func = usb_idle_hwmod, >> + .activate_func = usb_enable_hwmod, >> .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, >> }, >> }; >> @@ -100,6 +120,8 @@ void __init usb_musb_init(struct >omap_musb_board_data *board_data) >> musb_plat.power = board_data->power >> 1; >> musb_plat.mode = board_data->mode; >> musb_plat.extvbus = board_data->extvbus; >> + musb_plat.enable_wakeup = omap_device_enable_wakeup; >> + musb_plat.disable_wakeup = omap_device_disable_wakeup; >> pdata = &musb_plat; >> oh_p = oh; >> od = omap_device_build(name, bus_id, oh, pdata, >> @@ -120,7 +142,7 @@ void __init usb_musb_init(struct >omap_musb_board_data *board_data) >> >> } >> >> -void musb_context_save_restore(int save) >> +void musb_context_save_restore(enum musb_state state) >> { >> struct omap_hwmod *oh = oh_p; >> struct omap_device *od; >> @@ -145,10 +167,62 @@ void musb_context_save_restore(int save) >> >> if (!pdata->is_usb_active(dev)) { >> >> - if (save) >> + switch (state) { >> + case save_context: >> + /* As per the OMAP USBOTG >specicifcation, >> + * if USB device is not active >and attempting >> + * to core off then save the context, >> + * set the sysconfig reg to >force standby >> + * force idle and disable the clock. >> + */ >> + oh->flags |= HWMOD_SWSUP_SIDLE >> + | HWMOD_SWSUP_MSTANDBY; >> pm->suspend(dev); >> - else >> + pm_runtime_put_sync(dev); >> + >> + break; >> + >> + case disable_clk: >> + /* If the USB device not active then >> + * set the sysconfig setting >> + * to force standby force idle and >> + * disable the clock. >> + */ >> + oh->flags |= HWMOD_SWSUP_SIDLE >> + | HWMOD_SWSUP_MSTANDBY; >> + pm_runtime_put_sync(dev); >> + >> + break; >> + >> + case restore_context: >> + /* As per the OMAP USBOTG >specicifcation, >> + * configure the USB into smart >idle and smart >> + * standbyduring active. Enable the >> + * clock, set the sysconfig >back to smart idle >> + * and smart stndby and restore >the context >> + * after wakeup from core-off. >> + */ >> + oh->flags &= ~(HWMOD_SWSUP_SIDLE >> + | HWMOD_SWSUP_MSTANDBY); >> + pm_runtime_get_sync(dev); >> 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); >> + pm_runtime_get_sync(dev); >> + >> + break; >> + >> + default: >> + break; >> + } >> } >> } >> } >> @@ -157,7 +231,7 @@ void musb_context_save_restore(int save) >> void __init usb_musb_init(struct omap_musb_board_data *board_data) >> { >> } >> -void musb_context_save_restore(int save) >> +void musb_context_save_restore(enum musb_state state) >> { >> } >> #endif /* CONFIG_USB_MUSB_SOC */ >> diff --git a/arch/arm/plat-omap/include/plat/usb.h >b/arch/arm/plat-omap/include/plat/usb.h >> index ed2b41a..82b8618 100644 >> --- a/arch/arm/plat-omap/include/plat/usb.h >> +++ b/arch/arm/plat-omap/include/plat/usb.h >> @@ -71,6 +71,13 @@ struct omap_musb_board_data { >> 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_ehci_init(const struct >ehci_hcd_omap_platform_data *pdata); >> 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 >> >> >> diff --git a/drivers/usb/musb/musb_core.c >b/drivers/usb/musb/musb_core.c >> index 8510e55..e875c83 100644 >> --- a/drivers/usb/musb/musb_core.c >> +++ b/drivers/usb/musb/musb_core.c >> @@ -2456,9 +2456,21 @@ static int musb_resume_noirq(struct >device *dev) >> 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) >> diff --git a/drivers/usb/musb/omap2430.c >b/drivers/usb/musb/omap2430.c >> index dcba935..d83b644 100644 >> --- a/drivers/usb/musb/omap2430.c >> +++ b/drivers/usb/musb/omap2430.c >> @@ -31,6 +31,8 @@ >> #include <linux/list.h> >> #include <linux/clk.h> >> #include <linux/io.h> >> +#include <linux/pm_runtime.h> >> +#include <linux/platform_device.h> >> >> #include <plat/mux.h> >> >> @@ -219,22 +221,6 @@ int __init musb_platform_init(struct musb *musb) >> } >> >> 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) { >> @@ -274,16 +260,6 @@ void musb_platform_save_context(struct >musb *musb, >> */ >> 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); >> } >> @@ -298,18 +274,15 @@ void >musb_platform_restore_context(struct musb *musb, >> 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 | >ENABLEWAKEUP); >> } >> #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 platform_device *pdev = to_platform_device(dev); >> >> if (!musb->clock) >> return 0; >> @@ -318,17 +291,9 @@ static int musb_platform_suspend(struct >musb *musb) >> l = musb_readl(musb->mregs, OTG_FORCESTDBY); >> 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(pdev); >> 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; >> } >> @@ -336,21 +301,17 @@ static int >musb_platform_suspend(struct musb *musb) >> 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 platform_device *pdev = to_platform_device(dev); >> >> 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->enable_wakeup(pdev); > >I think you mean ->disable_wakeup() here, right? > No I meant enable_wakeup only here. When smart idle/standby is enabled, wakeup bit has to be set to generate the s-wakeup when the devie is in idle and system is in ret. >Also, remember that usage of the runtime PM API is usecount based, and >the low level functions are only called when the usecount transitions >to/from zero. > >Therefore, anything you want to happen when the actual HW transition >happens should be done in the drivers .runtime_suspend & >.runtime_resume >callbacks instead of done when you call the runtime PM API. > It is a good idea to call the enable_wakeup in runtime_suspend and runtime_resume APIs. >Alternatively, don't do this from the driver at all. Your device layer >already has customized hooks for the idle transitions. Just do it >there, and avoid the need to add another pdata hook. If this is called in the driver's runtime_suspend resume then it will be taken care. > >> l = musb_readl(musb->mregs, OTG_FORCESTDBY); >> l &= ~ENABLEFORCE; /* disable MSTANDBY */ >> musb_writel(musb->mregs, OTG_FORCESTDBY, l); > >Shouldn't this part be removed too? > It does not make sense when smart ilde and smart standby is enabled. I can remove this. >> diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h >> index da134ab..20b2cc8 100644 >> --- a/include/linux/usb/musb.h >> +++ b/include/linux/usb/musb.h >> @@ -93,6 +93,8 @@ struct musb_hdrc_config { >> >> }; >> >> +struct platform_device; >> + >> struct musb_hdrc_platform_data { >> /* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */ >> u8 mode; >> @@ -132,6 +134,12 @@ struct musb_hdrc_platform_data { >> >> /* indiates whether clock is autogated */ >> int clk_autogated; >> + >> + /* set the enable wakeup bit of sysconfig register */ >> + int (*enable_wakeup)(struct platform_device *pdev); >> + >> + /* Clear the enable wakeup bit of sysconfig register */ >> + int (*disable_wakeup)(struct platform_device *pdev); >> }; > -- 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