usb: musb: wake the device before ulpi transfers
musb can be suspended at the time some other driver wants to do ulpi transfers using usb_phy_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 usb_phy so that pm_runtime_* functions can be used. Cc: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Grazvydas Ignotas <notasas@gmail.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
692933b2cc
commit
bf070bc141
|
@ -137,6 +137,9 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
|
|||
int i = 0;
|
||||
u8 r;
|
||||
u8 power;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(phy->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 usb_phy *phy, 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(phy->io_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
|
||||
|
@ -171,6 +181,9 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
|
|||
int i = 0;
|
||||
u8 r = 0;
|
||||
u8 power;
|
||||
int ret = 0;
|
||||
|
||||
pm_runtime_get_sync(phy->io_dev);
|
||||
|
||||
/* Make sure the transceiver is not in low power mode */
|
||||
power = musb_readb(addr, MUSB_POWER);
|
||||
|
@ -184,15 +197,20 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
|
|||
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(phy->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;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ struct usb_phy {
|
|||
|
||||
struct usb_otg *otg;
|
||||
|
||||
struct device *io_dev;
|
||||
struct usb_phy_io_ops *io_ops;
|
||||
void __iomem *io_priv;
|
||||
|
||||
|
|
Loading…
Reference in a new issue