diff options
| author | Grazvydas Ignotas <notasas@gmail.com> | 2012-03-21 10:35:52 -0400 |
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2012-04-10 12:11:48 -0400 |
| commit | bf070bc14178f1458e7eccd76316ac24f76f1890 (patch) | |
| tree | 7d4569f916eb4718476c788aae853edde40c79cf | |
| parent | 692933b2ccfce02400dc8360a97acde2846e8541 (diff) | |
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>
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 31 | ||||
| -rw-r--r-- | 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 239214626ec5..66aaccf04490 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) | |||
| 137 | int i = 0; | 137 | int i = 0; |
| 138 | u8 r; | 138 | u8 r; |
| 139 | u8 power; | 139 | u8 power; |
| 140 | int ret; | ||
| 141 | |||
| 142 | pm_runtime_get_sync(phy->io_dev); | ||
| 140 | 143 | ||
| 141 | /* Make sure the transceiver is not in low power mode */ | 144 | /* Make sure the transceiver is not in low power mode */ |
| 142 | power = musb_readb(addr, MUSB_POWER); | 145 | power = musb_readb(addr, MUSB_POWER); |
| @@ -154,15 +157,22 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset) | |||
| 154 | while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) | 157 | while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) |
| 155 | & MUSB_ULPI_REG_CMPLT)) { | 158 | & MUSB_ULPI_REG_CMPLT)) { |
| 156 | i++; | 159 | i++; |
| 157 | if (i == 10000) | 160 | if (i == 10000) { |
| 158 | return -ETIMEDOUT; | 161 | ret = -ETIMEDOUT; |
| 162 | goto out; | ||
| 163 | } | ||
| 159 | 164 | ||
| 160 | } | 165 | } |
| 161 | r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); | 166 | r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); |
| 162 | r &= ~MUSB_ULPI_REG_CMPLT; | 167 | r &= ~MUSB_ULPI_REG_CMPLT; |
| 163 | musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); | 168 | musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); |
| 164 | 169 | ||
| 165 | return musb_readb(addr, MUSB_ULPI_REG_DATA); | 170 | ret = musb_readb(addr, MUSB_ULPI_REG_DATA); |
| 171 | |||
| 172 | out: | ||
| 173 | pm_runtime_put(phy->io_dev); | ||
| 174 | |||
| 175 | return ret; | ||
| 166 | } | 176 | } |
| 167 | 177 | ||
| 168 | static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) | 178 | 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) | |||
| 171 | int i = 0; | 181 | int i = 0; |
| 172 | u8 r = 0; | 182 | u8 r = 0; |
| 173 | u8 power; | 183 | u8 power; |
| 184 | int ret = 0; | ||
| 185 | |||
| 186 | pm_runtime_get_sync(phy->io_dev); | ||
| 174 | 187 | ||
| 175 | /* Make sure the transceiver is not in low power mode */ | 188 | /* Make sure the transceiver is not in low power mode */ |
| 176 | power = musb_readb(addr, MUSB_POWER); | 189 | power = musb_readb(addr, MUSB_POWER); |
| @@ -184,15 +197,20 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) | |||
| 184 | while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) | 197 | while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) |
| 185 | & MUSB_ULPI_REG_CMPLT)) { | 198 | & MUSB_ULPI_REG_CMPLT)) { |
| 186 | i++; | 199 | i++; |
| 187 | if (i == 10000) | 200 | if (i == 10000) { |
| 188 | return -ETIMEDOUT; | 201 | ret = -ETIMEDOUT; |
| 202 | goto out; | ||
| 203 | } | ||
| 189 | } | 204 | } |
| 190 | 205 | ||
| 191 | r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); | 206 | r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); |
| 192 | r &= ~MUSB_ULPI_REG_CMPLT; | 207 | r &= ~MUSB_ULPI_REG_CMPLT; |
| 193 | musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); | 208 | musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); |
| 194 | 209 | ||
| 195 | return 0; | 210 | out: |
| 211 | pm_runtime_put(phy->io_dev); | ||
| 212 | |||
| 213 | return ret; | ||
| 196 | } | 214 | } |
| 197 | #else | 215 | #else |
| 198 | #define musb_ulpi_read NULL | 216 | #define musb_ulpi_read NULL |
| @@ -1908,6 +1926,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) | |||
| 1908 | } | 1926 | } |
| 1909 | 1927 | ||
| 1910 | if (!musb->xceiv->io_ops) { | 1928 | if (!musb->xceiv->io_ops) { |
| 1929 | musb->xceiv->io_dev = musb->controller; | ||
| 1911 | musb->xceiv->io_priv = musb->mregs; | 1930 | musb->xceiv->io_priv = musb->mregs; |
| 1912 | musb->xceiv->io_ops = &musb_ulpi_access; | 1931 | musb->xceiv->io_ops = &musb_ulpi_access; |
| 1913 | } | 1932 | } |
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index f67810f8f21b..38ab3f46346f 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h | |||
| @@ -94,6 +94,7 @@ struct usb_phy { | |||
| 94 | 94 | ||
| 95 | struct usb_otg *otg; | 95 | struct usb_otg *otg; |
| 96 | 96 | ||
| 97 | struct device *io_dev; | ||
| 97 | struct usb_phy_io_ops *io_ops; | 98 | struct usb_phy_io_ops *io_ops; |
| 98 | void __iomem *io_priv; | 99 | void __iomem *io_priv; |
| 99 | 100 | ||
