musb can be suspended at the time some other driver wants to do ulpi transfers using otg_io_* functions, and that can cause data abort, as it happened with isp1704_charger: http://article.gmane.org/gmane.linux.kernel/1226122 Add pm_runtime to ulpi functions to rectify this. This also adds io_dev to otg_transceiver so that pm_runtime can be used. Cc: Felipe Contreras <felipe.contreras@xxxxxxxxx> Signed-off-by: Grazvydas Ignotas <notasas@xxxxxxxxx> --- drivers/usb/musb/musb_core.c | 31 +++++++++++++++++++++++++------ include/linux/usb/otg.h | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 19543c9..ca9d74a 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -137,6 +137,9 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) int i = 0; u8 r; u8 power; + int ret; + + pm_runtime_get_sync(otg->io_dev); /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); @@ -154,15 +157,22 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) & MUSB_ULPI_REG_CMPLT)) { i++; - if (i == 10000) - return -ETIMEDOUT; + if (i == 10000) { + ret = -ETIMEDOUT; + goto out; + } } r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); r &= ~MUSB_ULPI_REG_CMPLT; musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - return musb_readb(addr, MUSB_ULPI_REG_DATA); + ret = musb_readb(addr, MUSB_ULPI_REG_DATA); + +out: + pm_runtime_put(otg->io_dev); + + return ret; } static int musb_ulpi_write(struct otg_transceiver *otg, @@ -172,6 +182,9 @@ static int musb_ulpi_write(struct otg_transceiver *otg, int i = 0; u8 r = 0; u8 power; + int ret = 0; + + pm_runtime_get_sync(otg->io_dev); /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); @@ -185,15 +198,20 @@ static int musb_ulpi_write(struct otg_transceiver *otg, while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) & MUSB_ULPI_REG_CMPLT)) { i++; - if (i == 10000) - return -ETIMEDOUT; + if (i == 10000) { + ret = -ETIMEDOUT; + goto out; + } } r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); r &= ~MUSB_ULPI_REG_CMPLT; musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - return 0; +out: + pm_runtime_put(otg->io_dev); + + return ret; } #else #define musb_ulpi_read NULL @@ -1908,6 +1926,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) } if (!musb->xceiv->io_ops) { + musb->xceiv->io_dev = musb->controller; musb->xceiv->io_priv = musb->mregs; musb->xceiv->io_ops = &musb_ulpi_access; } diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index d87f44f..308b699 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -71,6 +71,7 @@ struct otg_transceiver { struct usb_bus *host; struct usb_gadget *gadget; + struct device *io_dev; struct otg_io_access_ops *io_ops; void __iomem *io_priv; -- 1.7.0.4 -- 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