From 2b65475db2df6c0b7ebb8960e77e3aaf27147bda Mon Sep 17 00:00:00 2001 From: Ajay Kumar Gupta Date: Thu, 3 Sep 2009 17:07:40 +0530 Subject: [PATCH 15/16] musb: Add context save and restore support Adding support for MUSB register save and restore during system suspend and resume. Changes: - Added musb_save/restore_context() functions - Added platform specific musb_platform_save/restore_context() to handle platform specific jobs. - Maintaining BlackFin compatibility by adding read/write functions for registers which are not available in BlackFin Tested system suspend and resume on OMAP3EVM board. Signed-off-by: Anand Gadiyar Signed-off-by: Ajay Kumar Gupta --- drivers/usb/musb/musb_core.c | 157 +++++++++++++++++++++++++++++++++++++++++- drivers/usb/musb/musb_core.h | 39 ++++++++++ drivers/usb/musb/musb_regs.h | 90 ++++++++++++++++++++++++ drivers/usb/musb/omap2430.c | 16 ++++ 4 files changed, 300 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f5ca435..0de19da 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2165,20 +2165,169 @@ static int __devexit musb_remove(struct platform_device *pdev) #ifdef CONFIG_PM +static struct musb_context_registers musb_context; + +void musb_save_context(void __iomem *musb_base) +{ + int i; + + musb_platform_save_context(&musb_context); + + musb_context.faddr = musb_readb(musb_base, MUSB_FADDR); + musb_context.power = musb_readb(musb_base, MUSB_POWER); + musb_context.intrtx = musb_readw(musb_base, MUSB_INTRTX); + musb_context.intrrx = musb_readw(musb_base, MUSB_INTRRX); + musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); + musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); + musb_context.intrusb = musb_readb(musb_base, MUSB_INTRUSB); + musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); + musb_context.frame = musb_readw(musb_base, MUSB_FRAME); + musb_context.index = musb_readb(musb_base, MUSB_INDEX); + musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE); + musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL); + + for (i = 0; i < MUSB_C_NUM_EPS; ++i) { + musb_writeb(musb_base, MUSB_INDEX, i); + musb_context.index_regs[i].txmaxp = + musb_readw(musb_base, 0x10 + MUSB_TXMAXP); + musb_context.index_regs[i].txcsr = + musb_readw(musb_base, 0x10 + MUSB_TXCSR); + musb_context.index_regs[i].rxmaxp = + musb_readw(musb_base, 0x10 + MUSB_RXMAXP); + musb_context.index_regs[i].rxcsr = + musb_readw(musb_base, 0x10 + MUSB_RXCSR); + musb_context.index_regs[i].rxcount = + musb_readw(musb_base, 0x10 + MUSB_RXCOUNT); + musb_context.index_regs[i].txtype = + musb_readb(musb_base, 0x10 + MUSB_TXTYPE); + musb_context.index_regs[i].txinterval = + musb_readb(musb_base, 0x10 + MUSB_TXINTERVAL); + musb_context.index_regs[i].rxtype = + musb_readb(musb_base, 0x10 + MUSB_RXTYPE); + musb_context.index_regs[i].rxinterval = + musb_readb(musb_base, 0x10 + MUSB_RXINTERVAL); + + musb_context.index_regs[i].txfifoadd = + musb_read_txfifoadd(musb_base); + musb_context.index_regs[i].rxfifoadd = + musb_read_rxfifoadd(musb_base); + musb_context.index_regs[i].txfifosz = + musb_read_txfifosz(musb_base); + musb_context.index_regs[i].rxfifosz = + musb_read_rxfifosz(musb_base); + + musb_context.index_regs[i].txfunaddr = + musb_read_txfunaddr(musb_base, i); + musb_context.index_regs[i].txhubaddr = + musb_read_txhubaddr(musb_base, i); + musb_context.index_regs[i].txhubport = + musb_read_txhubport(musb_base, i); + + musb_context.index_regs[i].rxfunaddr = + musb_read_rxfunaddr(musb_base, i); + musb_context.index_regs[i].rxhubaddr = + musb_read_rxhubaddr(musb_base, i); + musb_context.index_regs[i].rxhubport = + musb_read_rxhubport(musb_base, i); + } + + musb_writeb(musb_base, MUSB_INDEX, musb_context.index); +} + +void musb_restore_context(void __iomem *musb_base) +{ + int i; + void __iomem *ep_target_regs; + + musb_writeb(musb_base, MUSB_FADDR, musb_context.faddr); + musb_writeb(musb_base, MUSB_POWER, musb_context.power); + musb_writew(musb_base, MUSB_INTRTX, musb_context.intrtx); + musb_writew(musb_base, MUSB_INTRRX, musb_context.intrrx); + musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe); + musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe); + musb_writeb(musb_base, MUSB_INTRUSB, musb_context.intrusb); + musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe); + musb_writew(musb_base, MUSB_FRAME, musb_context.frame); + musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode); + musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl); + + + for (i = 0; i < MUSB_C_NUM_EPS; ++i) { + musb_writeb(musb_base, MUSB_INDEX, i); + musb_writew(musb_base, 0x10 + MUSB_TXMAXP, + musb_context.index_regs[i].txmaxp); + musb_writew(musb_base, 0x10 + MUSB_TXCSR, + musb_context.index_regs[i].txcsr); + musb_writew(musb_base, 0x10 + MUSB_RXMAXP, + musb_context.index_regs[i].rxmaxp); + musb_writew(musb_base, 0x10 + MUSB_RXCSR, + musb_context.index_regs[i].rxcsr); + musb_writew(musb_base, 0x10 + MUSB_RXCOUNT, + musb_context.index_regs[i].rxcount); + musb_writeb(musb_base, 0x10 + MUSB_TXTYPE, + musb_context.index_regs[i].txtype); + musb_writeb(musb_base, 0x10 + MUSB_TXINTERVAL, + musb_context.index_regs[i].txinterval); + musb_writeb(musb_base, 0x10 + MUSB_RXTYPE, + musb_context.index_regs[i].rxtype); + musb_writeb(musb_base, 0x10 + MUSB_RXINTERVAL, + musb_context.index_regs[i].rxinterval); + + musb_write_txfifosz(musb_base, + musb_context.index_regs[i].txfifosz); + musb_write_rxfifosz(musb_base, + musb_context.index_regs[i].rxfifosz); + musb_write_txfifoadd(musb_base, + musb_context.index_regs[i].txfifoadd); + musb_write_rxfifoadd(musb_base, + musb_context.index_regs[i].rxfifoadd); + + musb_write_txfunaddr(musb_base, i, + musb_context.index_regs[i].txfunaddr); + musb_write_txhubaddr(musb_base, i, + musb_context.index_regs[i].txhubaddr); + musb_write_txhubport(musb_base, i, + musb_context.index_regs[i].txhubport); + + ep_target_regs = musb_read_target_reg_base(i, musb_base); + + musb_write_rxfunaddr(ep_target_regs, + musb_context.index_regs[i].rxfunaddr); + musb_write_rxhubaddr(ep_target_regs, + musb_context.index_regs[i].rxhubaddr); + musb_write_rxhubport(ep_target_regs, + musb_context.index_regs[i].rxhubport); + } + + musb_writeb(musb_base, MUSB_INDEX, musb_context.index); + + musb_platform_restore_context(&musb_context); +} + static int musb_suspend(struct platform_device *pdev, pm_message_t message) { unsigned long flags; struct musb *musb = dev_to_musb(&pdev->dev); + u8 reg; if (!musb->clock) return 0; spin_lock_irqsave(&musb->lock, flags); + musb_save_context(musb->mregs); + if (is_peripheral_active(musb)) { - /* FIXME force disconnect unless we know USB will wake - * the system up quickly enough to respond ... + /* System is entering into suspend where gadget would not be + * able to respond to host and thus it will be in an unknown + * state for host.Re-enumemation of gadget is required after + * resume to make the gadget functional thus doing a force + * disconnect. */ + reg = musb_readb(musb->mregs, MUSB_POWER); + reg &= ~MUSB_POWER_SOFTCONN; + musb_writeb(musb->mregs, MUSB_POWER, reg); + } else if (is_host_active(musb)) { /* we know all the children are suspended; sometimes * they will even be wakeup-enabled. @@ -2205,6 +2354,8 @@ static int musb_resume_early(struct platform_device *pdev) else clk_enable(musb->clock); + musb_restore_context(musb->mregs); + /* for static cmos like DaVinci, register values were preserved * unless for some reason the whole soc powered down or the USB * module got reset through the PSC (vs just being disabled). @@ -2215,6 +2366,8 @@ static int musb_resume_early(struct platform_device *pdev) #else #define musb_suspend NULL #define musb_resume_early NULL +#define musb_save_context do {} while (0) +#define musb_restore_context do {} while (0) #endif static struct platform_driver musb_driver = { diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b0b4fbd..4568a8e 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -446,6 +446,45 @@ struct musb { #endif }; +#ifdef CONFIG_PM +struct musb_csr_regs { + /* FIFO registers */ + u16 txmaxp, txcsr, rxmaxp, rxcsr, rxcount; + u16 rxfifoadd, txfifoadd; + u8 txtype, txinterval, rxtype, rxinterval; + u8 rxfifosz, txfifosz; + u8 txfunaddr, txhubaddr, txhubport; + u8 rxfunaddr, rxhubaddr, rxhubport; +}; + +struct musb_context_registers { + +#if defined(CONFIG_ARCH_OMAP34XX) + u32 otg_sysconfig, otg_forcestandby; +#endif + u8 faddr, power; + u16 intrtx, intrrx, intrtxe, intrrxe; + u8 intrusb, intrusbe; + u16 frame; + u8 index, testmode; + + u8 devctl, misc; + + struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; +}; + +#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430) +extern void musb_platform_save_context(struct musb_context_registers + *musb_context); +extern void musb_platform_restore_context(struct musb_context_registers + *musb_context); +#else +#define musb_platform_save_context(x) do {} while (0) +#define musb_platform_restore_context(x) do {} while (0) +#endif + +#endif + static inline void musb_set_vbus(struct musb *musb, int is_on) { musb->board_set_vbus(musb, is_on); diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index fbfd3fd..a8e19da 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -321,6 +321,26 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) musb_writew(mbase, MUSB_RXFIFOADD, c_off); } +static inline u8 musb_read_txfifosz(void __iomem *mbase) +{ + return musb_readb(mbase, MUSB_TXFIFOSZ); +} + +static inline u16 musb_read_txfifoadd(void __iomem *mbase) +{ + return musb_readw(mbase, MUSB_TXFIFOADD); +} + +static inline u8 musb_read_rxfifosz(void __iomem *mbase) +{ + return musb_readb(mbase, MUSB_RXFIFOSZ); +} + +static inline u16 musb_read_rxfifoadd(void __iomem *mbase) +{ + return musb_readw(mbase, MUSB_RXFIFOADD); +} + static inline u8 musb_read_configdata(void __iomem *mbase) { musb_writeb(mbase, MUSB_INDEX, 0); @@ -376,6 +396,36 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, qh_h_port_reg); } +static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR)); +} + +static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR)); +} + +static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT)); +} + +static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR)); +} + +static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR)); +} + +static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) +{ + return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT)); +} + #else /* CONFIG_BLACKFIN */ #define USB_BASE USB_FADDR @@ -464,6 +514,22 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) { } +static inline u8 musb_read_txfifosz(void __iomem *mbase) +{ +} + +static inline u16 musb_read_txfifoadd(void __iomem *mbase) +{ +} + +static inline u8 musb_read_rxfifosz(void __iomem *mbase) +{ +} + +static inline u16 musb_read_rxfifoadd(void __iomem *mbase) +{ +} + static inline u8 musb_read_configdata(void __iomem *mbase) { return 0; @@ -509,6 +575,30 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, { } +static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum) +{ +} + +static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum) +{ +} + +static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum) +{ +} + +static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum) +{ +} + +static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) +{ +} + +static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum) +{ +} + #endif /* CONFIG_BLACKFIN */ #endif /* __MUSB_REGS_H__ */ diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 3487520..84af3b3 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -255,6 +255,22 @@ int __init musb_platform_init(struct musb *musb) return 0; } +#ifdef CONFIG_PM +void musb_platform_save_context(struct musb_context_registers + *musb_context) +{ + musb_context->otg_sysconfig = omap_readl(OTG_SYSCONFIG); + musb_context->otg_forcestandby = omap_readl(OTG_FORCESTDBY); +} + +void musb_platform_restore_context(struct musb_context_registers + *musb_context) +{ + omap_writel(musb_context->otg_sysconfig, OTG_SYSCONFIG); + omap_writel(musb_context->otg_forcestandby, OTG_FORCESTDBY); +} +#endif + int musb_platform_suspend(struct musb *musb) { u32 l; -- 1.6.2.4