Commit 4f712e01 authored by Ajay Kumar Gupta's avatar Ajay Kumar Gupta Committed by Greg Kroah-Hartman

usb: 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: default avatarAnand Gadiyar <gadiyar@ti.com>
Signed-off-by: default avatarAjay Kumar Gupta <ajay.gupta@ti.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8af6096c
...@@ -2167,6 +2167,148 @@ static int __exit musb_remove(struct platform_device *pdev) ...@@ -2167,6 +2167,148 @@ static int __exit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static struct musb_context_registers musb_context;
void musb_save_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
if (is_host_enabled(musb)) {
musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
}
musb_context.power = musb_readb(musb_base, MUSB_POWER);
musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
musb_context.index = musb_readb(musb_base, MUSB_INDEX);
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);
if (musb->dyn_fifo) {
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);
}
if (is_host_enabled(musb)) {
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].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);
musb_platform_save_context(&musb_context);
}
void musb_restore_context(struct musb *musb)
{
int i;
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
musb_platform_restore_context(&musb_context);
if (is_host_enabled(musb)) {
musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
}
musb_writeb(musb_base, MUSB_POWER, musb_context.power);
musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
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);
if (musb->dyn_fifo) {
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);
}
if (is_host_enabled(musb)) {
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_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);
}
static int musb_suspend(struct device *dev) static int musb_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
...@@ -2188,6 +2330,8 @@ static int musb_suspend(struct device *dev) ...@@ -2188,6 +2330,8 @@ static int musb_suspend(struct device *dev)
*/ */
} }
musb_save_context(musb);
if (musb->set_clock) if (musb->set_clock)
musb->set_clock(musb->clock, 0); musb->set_clock(musb->clock, 0);
else else
...@@ -2209,6 +2353,8 @@ static int musb_resume_noirq(struct device *dev) ...@@ -2209,6 +2353,8 @@ static int musb_resume_noirq(struct device *dev)
else else
clk_enable(musb->clock); clk_enable(musb->clock);
musb_restore_context(musb);
/* for static cmos like DaVinci, register values were preserved /* for static cmos like DaVinci, register values were preserved
* unless for some reason the whole soc powered down or the USB * unless for some reason the whole soc powered down or the USB
* module got reset through the PSC (vs just being disabled). * module got reset through the PSC (vs just being disabled).
......
...@@ -454,6 +454,45 @@ struct musb { ...@@ -454,6 +454,45 @@ struct musb {
#endif #endif
}; };
#ifdef CONFIG_PM
struct musb_csr_regs {
/* FIFO registers */
u16 txmaxp, txcsr, rxmaxp, rxcsr;
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) || defined(CONFIG_ARCH_OMAP2430)
u32 otg_sysconfig, otg_forcestandby;
#endif
u8 power;
u16 intrtxe, intrrxe;
u8 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) static inline void musb_set_vbus(struct musb *musb, int is_on)
{ {
musb->board_set_vbus(musb, is_on); musb->board_set_vbus(musb, is_on);
......
...@@ -326,6 +326,26 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) ...@@ -326,6 +326,26 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
musb_writew(mbase, MUSB_RXFIFOADD, 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) static inline u8 musb_read_configdata(void __iomem *mbase)
{ {
musb_writeb(mbase, MUSB_INDEX, 0); musb_writeb(mbase, MUSB_INDEX, 0);
...@@ -381,6 +401,36 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, ...@@ -381,6 +401,36 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
qh_h_port_reg); 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 */ #else /* CONFIG_BLACKFIN */
#define USB_BASE USB_FADDR #define USB_BASE USB_FADDR
...@@ -460,6 +510,22 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) ...@@ -460,6 +510,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) static inline u8 musb_read_configdata(void __iomem *mbase)
{ {
return 0; return 0;
...@@ -505,6 +571,30 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, ...@@ -505,6 +571,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 /* CONFIG_BLACKFIN */
#endif /* __MUSB_REGS_H__ */ #endif /* __MUSB_REGS_H__ */
...@@ -255,6 +255,22 @@ int __init musb_platform_init(struct musb *musb) ...@@ -255,6 +255,22 @@ int __init musb_platform_init(struct musb *musb)
return 0; 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) int musb_platform_suspend(struct musb *musb)
{ {
u32 l; u32 l;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment