Skip to content

Commit

Permalink
usb: musb: wake the device before ulpi transfers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Grazvydas Ignotas authored and Felipe Balbi committed Apr 10, 2012
1 parent 692933b commit bf070bc
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
31 changes: 25 additions & 6 deletions drivers/usb/musb/musb_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions include/linux/usb/otg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit bf070bc

Please sign in to comment.