Commit 9e74d601de8adb0fe96e100e459ac52f2ddd47f3
Committed by
Felipe Balbi
1 parent
89c1d2e7b5
Exists in
master
and in
6 other branches
usb: gadget: renesas_usbhs: add data/status stage handler
mod_host needs data/status stage handler Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Showing 2 changed files with 150 additions and 0 deletions Side-by-side Diff
drivers/usb/renesas_usbhs/fifo.c
... | ... | @@ -321,6 +321,151 @@ |
321 | 321 | } |
322 | 322 | |
323 | 323 | /* |
324 | + * DCP status stage | |
325 | + */ | |
326 | +static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done) | |
327 | +{ | |
328 | + struct usbhs_pipe *pipe = pkt->pipe; | |
329 | + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
330 | + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ | |
331 | + struct device *dev = usbhs_priv_to_dev(priv); | |
332 | + int ret; | |
333 | + | |
334 | + usbhs_pipe_disable(pipe); | |
335 | + | |
336 | + ret = usbhsf_fifo_select(pipe, fifo, 1); | |
337 | + if (ret < 0) { | |
338 | + dev_err(dev, "%s() faile\n", __func__); | |
339 | + return ret; | |
340 | + } | |
341 | + | |
342 | + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
343 | + | |
344 | + usbhsf_fifo_clear(pipe, fifo); | |
345 | + usbhsf_send_terminator(pipe, fifo); | |
346 | + | |
347 | + usbhsf_fifo_unselect(pipe, fifo); | |
348 | + | |
349 | + usbhsf_tx_irq_ctrl(pipe, 1); | |
350 | + usbhs_pipe_enable(pipe); | |
351 | + | |
352 | + return ret; | |
353 | +} | |
354 | + | |
355 | +static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done) | |
356 | +{ | |
357 | + struct usbhs_pipe *pipe = pkt->pipe; | |
358 | + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
359 | + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ | |
360 | + struct device *dev = usbhs_priv_to_dev(priv); | |
361 | + int ret; | |
362 | + | |
363 | + usbhs_pipe_disable(pipe); | |
364 | + | |
365 | + ret = usbhsf_fifo_select(pipe, fifo, 0); | |
366 | + if (ret < 0) { | |
367 | + dev_err(dev, "%s() fail\n", __func__); | |
368 | + return ret; | |
369 | + } | |
370 | + | |
371 | + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
372 | + usbhsf_fifo_clear(pipe, fifo); | |
373 | + | |
374 | + usbhsf_fifo_unselect(pipe, fifo); | |
375 | + | |
376 | + usbhsf_rx_irq_ctrl(pipe, 1); | |
377 | + usbhs_pipe_enable(pipe); | |
378 | + | |
379 | + return ret; | |
380 | + | |
381 | +} | |
382 | + | |
383 | +static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done) | |
384 | +{ | |
385 | + struct usbhs_pipe *pipe = pkt->pipe; | |
386 | + | |
387 | + if (pkt->handler == &usbhs_dcp_status_stage_in_handler) | |
388 | + usbhsf_tx_irq_ctrl(pipe, 0); | |
389 | + else | |
390 | + usbhsf_rx_irq_ctrl(pipe, 0); | |
391 | + | |
392 | + pkt->actual = pkt->length; | |
393 | + *is_done = 1; | |
394 | + | |
395 | + return 0; | |
396 | +} | |
397 | + | |
398 | +struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = { | |
399 | + .prepare = usbhs_dcp_dir_switch_to_write, | |
400 | + .try_run = usbhs_dcp_dir_switch_done, | |
401 | +}; | |
402 | + | |
403 | +struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = { | |
404 | + .prepare = usbhs_dcp_dir_switch_to_read, | |
405 | + .try_run = usbhs_dcp_dir_switch_done, | |
406 | +}; | |
407 | + | |
408 | +/* | |
409 | + * DCP data stage (push) | |
410 | + */ | |
411 | +static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done) | |
412 | +{ | |
413 | + struct usbhs_pipe *pipe = pkt->pipe; | |
414 | + | |
415 | + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
416 | + | |
417 | + /* | |
418 | + * change handler to PIO push | |
419 | + */ | |
420 | + pkt->handler = &usbhs_fifo_pio_push_handler; | |
421 | + | |
422 | + return pkt->handler->prepare(pkt, is_done); | |
423 | +} | |
424 | + | |
425 | +struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = { | |
426 | + .prepare = usbhsf_dcp_data_stage_try_push, | |
427 | +}; | |
428 | + | |
429 | +/* | |
430 | + * DCP data stage (pop) | |
431 | + */ | |
432 | +static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt, | |
433 | + int *is_done) | |
434 | +{ | |
435 | + struct usbhs_pipe *pipe = pkt->pipe; | |
436 | + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
437 | + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); | |
438 | + | |
439 | + if (usbhs_pipe_is_busy(pipe)) | |
440 | + return 0; | |
441 | + | |
442 | + /* | |
443 | + * prepare pop for DCP should | |
444 | + * - change DCP direction, | |
445 | + * - clear fifo | |
446 | + * - DATA1 | |
447 | + */ | |
448 | + usbhs_pipe_disable(pipe); | |
449 | + | |
450 | + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
451 | + | |
452 | + usbhsf_fifo_select(pipe, fifo, 0); | |
453 | + usbhsf_fifo_clear(pipe, fifo); | |
454 | + usbhsf_fifo_unselect(pipe, fifo); | |
455 | + | |
456 | + /* | |
457 | + * change handler to PIO pop | |
458 | + */ | |
459 | + pkt->handler = &usbhs_fifo_pio_pop_handler; | |
460 | + | |
461 | + return pkt->handler->prepare(pkt, is_done); | |
462 | +} | |
463 | + | |
464 | +struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = { | |
465 | + .prepare = usbhsf_dcp_data_stage_prepare_pop, | |
466 | +}; | |
467 | + | |
468 | +/* | |
324 | 469 | * PIO push handler |
325 | 470 | */ |
326 | 471 | static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) |
drivers/usb/renesas_usbhs/fifo.h
... | ... | @@ -85,6 +85,11 @@ |
85 | 85 | extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler; |
86 | 86 | extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler; |
87 | 87 | |
88 | +extern struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler; | |
89 | +extern struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler; | |
90 | + | |
91 | +extern struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler; | |
92 | +extern struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler; | |
88 | 93 | |
89 | 94 | void usbhs_pkt_init(struct usbhs_pkt *pkt); |
90 | 95 | void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, |