diff options
author | Cliff Cai <cliff.cai@analog.com> | 2010-03-25 07:25:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:35 -0400 |
commit | ff927addd62d33ab95cd83208e7db3ff37fdac18 (patch) | |
tree | b3925a7902af88e96123fcea478cff3a580a584c /drivers/usb/musb/blackfin.c | |
parent | b0f9da7e02776a8c5ad61b9e24feebf7b12a7243 (diff) |
USB: musb: support host/gadget role switching on Blackfin parts
Signed-off-by: Cliff Cai <cliff.cai@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/musb/blackfin.c')
-rw-r--r-- | drivers/usb/musb/blackfin.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index eb4392f904e4..8052e7659ac8 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c | |||
@@ -170,6 +170,13 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci) | |||
170 | retval = musb_interrupt(musb); | 170 | retval = musb_interrupt(musb); |
171 | } | 171 | } |
172 | 172 | ||
173 | /* Start sampling ID pin, when plug is removed from MUSB */ | ||
174 | if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE | ||
175 | || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { | ||
176 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | ||
177 | musb->a_wait_bcon = TIMER_DELAY; | ||
178 | } | ||
179 | |||
173 | spin_unlock_irqrestore(&musb->lock, flags); | 180 | spin_unlock_irqrestore(&musb->lock, flags); |
174 | 181 | ||
175 | return retval; | 182 | return retval; |
@@ -180,6 +187,7 @@ static void musb_conn_timer_handler(unsigned long _musb) | |||
180 | struct musb *musb = (void *)_musb; | 187 | struct musb *musb = (void *)_musb; |
181 | unsigned long flags; | 188 | unsigned long flags; |
182 | u16 val; | 189 | u16 val; |
190 | static u8 toggle; | ||
183 | 191 | ||
184 | spin_lock_irqsave(&musb->lock, flags); | 192 | spin_lock_irqsave(&musb->lock, flags); |
185 | switch (musb->xceiv->state) { | 193 | switch (musb->xceiv->state) { |
@@ -187,10 +195,44 @@ static void musb_conn_timer_handler(unsigned long _musb) | |||
187 | case OTG_STATE_A_WAIT_BCON: | 195 | case OTG_STATE_A_WAIT_BCON: |
188 | /* Start a new session */ | 196 | /* Start a new session */ |
189 | val = musb_readw(musb->mregs, MUSB_DEVCTL); | 197 | val = musb_readw(musb->mregs, MUSB_DEVCTL); |
198 | val &= ~MUSB_DEVCTL_SESSION; | ||
199 | musb_writew(musb->mregs, MUSB_DEVCTL, val); | ||
190 | val |= MUSB_DEVCTL_SESSION; | 200 | val |= MUSB_DEVCTL_SESSION; |
191 | musb_writew(musb->mregs, MUSB_DEVCTL, val); | 201 | musb_writew(musb->mregs, MUSB_DEVCTL, val); |
202 | /* Check if musb is host or peripheral. */ | ||
203 | val = musb_readw(musb->mregs, MUSB_DEVCTL); | ||
204 | |||
205 | if (!(val & MUSB_DEVCTL_BDEVICE)) { | ||
206 | gpio_set_value(musb->config->gpio_vrsel, 1); | ||
207 | musb->xceiv->state = OTG_STATE_A_WAIT_BCON; | ||
208 | } else { | ||
209 | gpio_set_value(musb->config->gpio_vrsel, 0); | ||
210 | /* Ignore VBUSERROR and SUSPEND IRQ */ | ||
211 | val = musb_readb(musb->mregs, MUSB_INTRUSBE); | ||
212 | val &= ~MUSB_INTR_VBUSERROR; | ||
213 | musb_writeb(musb->mregs, MUSB_INTRUSBE, val); | ||
192 | 214 | ||
215 | val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; | ||
216 | musb_writeb(musb->mregs, MUSB_INTRUSB, val); | ||
217 | if (is_otg_enabled(musb)) | ||
218 | musb->xceiv->state = OTG_STATE_B_IDLE; | ||
219 | else | ||
220 | musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB); | ||
221 | } | ||
222 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | ||
223 | break; | ||
224 | case OTG_STATE_B_IDLE: | ||
225 | |||
226 | if (!is_peripheral_enabled(musb)) | ||
227 | break; | ||
228 | /* Start a new session. It seems that MUSB needs taking | ||
229 | * some time to recognize the type of the plug inserted? | ||
230 | */ | ||
193 | val = musb_readw(musb->mregs, MUSB_DEVCTL); | 231 | val = musb_readw(musb->mregs, MUSB_DEVCTL); |
232 | val |= MUSB_DEVCTL_SESSION; | ||
233 | musb_writew(musb->mregs, MUSB_DEVCTL, val); | ||
234 | val = musb_readw(musb->mregs, MUSB_DEVCTL); | ||
235 | |||
194 | if (!(val & MUSB_DEVCTL_BDEVICE)) { | 236 | if (!(val & MUSB_DEVCTL_BDEVICE)) { |
195 | gpio_set_value(musb->config->gpio_vrsel, 1); | 237 | gpio_set_value(musb->config->gpio_vrsel, 1); |
196 | musb->xceiv->state = OTG_STATE_A_WAIT_BCON; | 238 | musb->xceiv->state = OTG_STATE_A_WAIT_BCON; |
@@ -205,12 +247,27 @@ static void musb_conn_timer_handler(unsigned long _musb) | |||
205 | val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; | 247 | val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; |
206 | musb_writeb(musb->mregs, MUSB_INTRUSB, val); | 248 | musb_writeb(musb->mregs, MUSB_INTRUSB, val); |
207 | 249 | ||
208 | val = MUSB_POWER_HSENAB; | 250 | /* Toggle the Soft Conn bit, so that we can response to |
209 | musb_writeb(musb->mregs, MUSB_POWER, val); | 251 | * the inserting of either A-plug or B-plug. |
252 | */ | ||
253 | if (toggle) { | ||
254 | val = musb_readb(musb->mregs, MUSB_POWER); | ||
255 | val &= ~MUSB_POWER_SOFTCONN; | ||
256 | musb_writeb(musb->mregs, MUSB_POWER, val); | ||
257 | toggle = 0; | ||
258 | } else { | ||
259 | val = musb_readb(musb->mregs, MUSB_POWER); | ||
260 | val |= MUSB_POWER_SOFTCONN; | ||
261 | musb_writeb(musb->mregs, MUSB_POWER, val); | ||
262 | toggle = 1; | ||
263 | } | ||
264 | /* The delay time is set to 1/4 second by default, | ||
265 | * shortening it, if accelerating A-plug detection | ||
266 | * is needed in OTG mode. | ||
267 | */ | ||
268 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4); | ||
210 | } | 269 | } |
211 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | ||
212 | break; | 270 | break; |
213 | |||
214 | default: | 271 | default: |
215 | DBG(1, "%s state not handled\n", otg_state_string(musb)); | 272 | DBG(1, "%s state not handled\n", otg_state_string(musb)); |
216 | break; | 273 | break; |
@@ -222,7 +279,7 @@ static void musb_conn_timer_handler(unsigned long _musb) | |||
222 | 279 | ||
223 | void musb_platform_enable(struct musb *musb) | 280 | void musb_platform_enable(struct musb *musb) |
224 | { | 281 | { |
225 | if (is_host_enabled(musb)) { | 282 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) { |
226 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | 283 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); |
227 | musb->a_wait_bcon = TIMER_DELAY; | 284 | musb->a_wait_bcon = TIMER_DELAY; |
228 | } | 285 | } |
@@ -256,7 +313,7 @@ static int bfin_set_power(struct otg_transceiver *x, unsigned mA) | |||
256 | 313 | ||
257 | void musb_platform_try_idle(struct musb *musb, unsigned long timeout) | 314 | void musb_platform_try_idle(struct musb *musb, unsigned long timeout) |
258 | { | 315 | { |
259 | if (is_host_enabled(musb)) | 316 | if (!is_otg_enabled(musb) && is_host_enabled(musb)) |
260 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); | 317 | mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); |
261 | } | 318 | } |
262 | 319 | ||