summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorRoger Quadros2014-02-04 14:29:33 +0100
committerFelipe Balbi2014-02-18 17:32:26 +0100
commit33f8d75f5771993ef16ed6bd56d7210f54226203 (patch)
tree5b00defb25c73b993608528758489ef67a0ac6ea /drivers/usb
parentusb: musb: host: Fix SuperSpeed hub enumeration (diff)
downloadkernel-qcow2-linux-33f8d75f5771993ef16ed6bd56d7210f54226203.tar.gz
kernel-qcow2-linux-33f8d75f5771993ef16ed6bd56d7210f54226203.tar.xz
kernel-qcow2-linux-33f8d75f5771993ef16ed6bd56d7210f54226203.zip
usb: musb: core: Fix remote-wakeup resume
During resume don't touch SUSPENDM/RESUME bits of POWER register while restoring controller context. These bits might be changed by the controller during resume operation and so will be different than what they were during suspend. e.g. SUSPENDM bit is set by software during USB global suspend but automatically cleared by the controller during remote wakeup or during resume. Setting this bit back while restoring context causes undesired behaviour. i.e. Babble interrupt is generated and USB is broken. Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/musb/musb_core.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index fc192ad9cc6a..a501542dfeb5 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2157,11 +2157,19 @@ static void musb_restore_context(struct musb *musb)
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
+ u8 power;
musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
- musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+
+ /* Don't affect SUSPENDM/RESUME bits in POWER reg */
+ power = musb_readb(musb_base, MUSB_POWER);
+ power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME;
+ musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME);
+ power |= musb->context.power;
+ musb_writeb(musb_base, MUSB_POWER, power);
+
musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);