diff options
| author | Grazvydas Ignotas <notasas@gmail.com> | 2012-03-21 16:35:52 +0200 | 
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2012-04-10 19:11:48 +0300 | 
| commit | bf070bc14178f1458e7eccd76316ac24f76f1890 (patch) | |
| tree | 7d4569f916eb4718476c788aae853edde40c79cf /drivers/usb/musb/musb_core.c | |
| parent | 692933b2ccfce02400dc8360a97acde2846e8541 (diff) | |
| download | olio-linux-3.10-bf070bc14178f1458e7eccd76316ac24f76f1890.tar.xz olio-linux-3.10-bf070bc14178f1458e7eccd76316ac24f76f1890.zip  | |
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>
Diffstat (limited to 'drivers/usb/musb/musb_core.c')
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 31 | 
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 239214626ec..66aaccf0449 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 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;  	}  |