diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs/mod.c')
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 81 |
1 files changed, 60 insertions, 21 deletions
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index a577f8f4064c..053f86d70009 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c | |||
@@ -58,7 +58,7 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) | |||
58 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); | 58 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); |
59 | 59 | ||
60 | info->irq_vbus = usbhsm_autonomy_irq_vbus; | 60 | info->irq_vbus = usbhsm_autonomy_irq_vbus; |
61 | priv->pfunc->get_vbus = usbhsm_autonomy_get_vbus; | 61 | priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus; |
62 | 62 | ||
63 | usbhs_irq_callback_update(priv, NULL); | 63 | usbhs_irq_callback_update(priv, NULL); |
64 | } | 64 | } |
@@ -93,8 +93,9 @@ struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id) | |||
93 | return ret; | 93 | return ret; |
94 | } | 94 | } |
95 | 95 | ||
96 | int usbhs_mod_is_host(struct usbhs_priv *priv, struct usbhs_mod *mod) | 96 | int usbhs_mod_is_host(struct usbhs_priv *priv) |
97 | { | 97 | { |
98 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | ||
98 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); | 99 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); |
99 | 100 | ||
100 | if (!mod) | 101 | if (!mod) |
@@ -139,13 +140,17 @@ int usbhs_mod_probe(struct usbhs_priv *priv) | |||
139 | /* | 140 | /* |
140 | * install host/gadget driver | 141 | * install host/gadget driver |
141 | */ | 142 | */ |
142 | ret = usbhs_mod_gadget_probe(priv); | 143 | ret = usbhs_mod_host_probe(priv); |
143 | if (ret < 0) | 144 | if (ret < 0) |
144 | return ret; | 145 | return ret; |
145 | 146 | ||
147 | ret = usbhs_mod_gadget_probe(priv); | ||
148 | if (ret < 0) | ||
149 | goto mod_init_host_err; | ||
150 | |||
146 | /* irq settings */ | 151 | /* irq settings */ |
147 | ret = request_irq(priv->irq, usbhs_interrupt, | 152 | ret = request_irq(priv->irq, usbhs_interrupt, |
148 | IRQF_DISABLED, dev_name(dev), priv); | 153 | 0, dev_name(dev), priv); |
149 | if (ret) { | 154 | if (ret) { |
150 | dev_err(dev, "irq request err\n"); | 155 | dev_err(dev, "irq request err\n"); |
151 | goto mod_init_gadget_err; | 156 | goto mod_init_gadget_err; |
@@ -155,12 +160,15 @@ int usbhs_mod_probe(struct usbhs_priv *priv) | |||
155 | 160 | ||
156 | mod_init_gadget_err: | 161 | mod_init_gadget_err: |
157 | usbhs_mod_gadget_remove(priv); | 162 | usbhs_mod_gadget_remove(priv); |
163 | mod_init_host_err: | ||
164 | usbhs_mod_host_remove(priv); | ||
158 | 165 | ||
159 | return ret; | 166 | return ret; |
160 | } | 167 | } |
161 | 168 | ||
162 | void usbhs_mod_remove(struct usbhs_priv *priv) | 169 | void usbhs_mod_remove(struct usbhs_priv *priv) |
163 | { | 170 | { |
171 | usbhs_mod_host_remove(priv); | ||
164 | usbhs_mod_gadget_remove(priv); | 172 | usbhs_mod_gadget_remove(priv); |
165 | free_irq(priv->irq, priv); | 173 | free_irq(priv->irq, priv); |
166 | } | 174 | } |
@@ -168,20 +176,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv) | |||
168 | /* | 176 | /* |
169 | * status functions | 177 | * status functions |
170 | */ | 178 | */ |
171 | int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state) | ||
172 | { | ||
173 | switch (irq_state->dvstctr & RHST) { | ||
174 | case RHST_LOW_SPEED: | ||
175 | return USB_SPEED_LOW; | ||
176 | case RHST_FULL_SPEED: | ||
177 | return USB_SPEED_FULL; | ||
178 | case RHST_HIGH_SPEED: | ||
179 | return USB_SPEED_HIGH; | ||
180 | } | ||
181 | |||
182 | return USB_SPEED_UNKNOWN; | ||
183 | } | ||
184 | |||
185 | int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) | 179 | int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) |
186 | { | 180 | { |
187 | int state = irq_state->intsts0 & DVSQ_MASK; | 181 | int state = irq_state->intsts0 & DVSQ_MASK; |
@@ -221,8 +215,6 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv, | |||
221 | state->intsts0 = usbhs_read(priv, INTSTS0); | 215 | state->intsts0 = usbhs_read(priv, INTSTS0); |
222 | state->intsts1 = usbhs_read(priv, INTSTS1); | 216 | state->intsts1 = usbhs_read(priv, INTSTS1); |
223 | 217 | ||
224 | state->dvstctr = usbhs_read(priv, DVSTCTR); | ||
225 | |||
226 | /* mask */ | 218 | /* mask */ |
227 | if (mod) { | 219 | if (mod) { |
228 | state->brdysts = usbhs_read(priv, BRDYSTS); | 220 | state->brdysts = usbhs_read(priv, BRDYSTS); |
@@ -269,6 +261,8 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) | |||
269 | * see also | 261 | * see also |
270 | * usbhs_irq_setting_update | 262 | * usbhs_irq_setting_update |
271 | */ | 263 | */ |
264 | |||
265 | /* INTSTS0 */ | ||
272 | if (irq_state.intsts0 & VBINT) | 266 | if (irq_state.intsts0 & VBINT) |
273 | usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); | 267 | usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); |
274 | 268 | ||
@@ -284,15 +278,38 @@ static irqreturn_t usbhs_interrupt(int irq, void *data) | |||
284 | if (irq_state.intsts0 & BRDY) | 278 | if (irq_state.intsts0 & BRDY) |
285 | usbhs_mod_call(priv, irq_ready, priv, &irq_state); | 279 | usbhs_mod_call(priv, irq_ready, priv, &irq_state); |
286 | 280 | ||
281 | /* INTSTS1 */ | ||
282 | if (irq_state.intsts1 & ATTCH) | ||
283 | usbhs_mod_call(priv, irq_attch, priv, &irq_state); | ||
284 | |||
285 | if (irq_state.intsts1 & DTCH) | ||
286 | usbhs_mod_call(priv, irq_dtch, priv, &irq_state); | ||
287 | |||
288 | if (irq_state.intsts1 & SIGN) | ||
289 | usbhs_mod_call(priv, irq_sign, priv, &irq_state); | ||
290 | |||
291 | if (irq_state.intsts1 & SACK) | ||
292 | usbhs_mod_call(priv, irq_sack, priv, &irq_state); | ||
293 | |||
287 | return IRQ_HANDLED; | 294 | return IRQ_HANDLED; |
288 | } | 295 | } |
289 | 296 | ||
290 | void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) | 297 | void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) |
291 | { | 298 | { |
292 | u16 intenb0 = 0; | 299 | u16 intenb0 = 0; |
300 | u16 intenb1 = 0; | ||
293 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); | 301 | struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); |
294 | 302 | ||
303 | /* | ||
304 | * BEMPENB/BRDYENB are picky. | ||
305 | * below method is required | ||
306 | * | ||
307 | * - clear INTSTS0 | ||
308 | * - update BEMPENB/BRDYENB | ||
309 | * - update INTSTS0 | ||
310 | */ | ||
295 | usbhs_write(priv, INTENB0, 0); | 311 | usbhs_write(priv, INTENB0, 0); |
312 | usbhs_write(priv, INTENB1, 0); | ||
296 | 313 | ||
297 | usbhs_write(priv, BEMPENB, 0); | 314 | usbhs_write(priv, BEMPENB, 0); |
298 | usbhs_write(priv, BRDYENB, 0); | 315 | usbhs_write(priv, BRDYENB, 0); |
@@ -310,6 +327,9 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) | |||
310 | intenb0 |= VBSE; | 327 | intenb0 |= VBSE; |
311 | 328 | ||
312 | if (mod) { | 329 | if (mod) { |
330 | /* | ||
331 | * INTSTS0 | ||
332 | */ | ||
313 | if (mod->irq_ctrl_stage) | 333 | if (mod->irq_ctrl_stage) |
314 | intenb0 |= CTRE; | 334 | intenb0 |= CTRE; |
315 | 335 | ||
@@ -322,7 +342,26 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) | |||
322 | usbhs_write(priv, BRDYENB, mod->irq_brdysts); | 342 | usbhs_write(priv, BRDYENB, mod->irq_brdysts); |
323 | intenb0 |= BRDYE; | 343 | intenb0 |= BRDYE; |
324 | } | 344 | } |
345 | |||
346 | /* | ||
347 | * INTSTS1 | ||
348 | */ | ||
349 | if (mod->irq_attch) | ||
350 | intenb1 |= ATTCHE; | ||
351 | |||
352 | if (mod->irq_attch) | ||
353 | intenb1 |= DTCHE; | ||
354 | |||
355 | if (mod->irq_sign) | ||
356 | intenb1 |= SIGNE; | ||
357 | |||
358 | if (mod->irq_sack) | ||
359 | intenb1 |= SACKE; | ||
325 | } | 360 | } |
326 | 361 | ||
327 | usbhs_write(priv, INTENB0, intenb0); | 362 | if (intenb0) |
363 | usbhs_write(priv, INTENB0, intenb0); | ||
364 | |||
365 | if (intenb1) | ||
366 | usbhs_write(priv, INTENB1, intenb1); | ||
328 | } | 367 | } |