Blame view
drivers/usb/renesas_usbhs/fifo.c
33.9 KB
e8d548d54 usb: renesas_usbh... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* * Renesas USB driver * * Copyright (C) 2011 Renesas Solutions Corp. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include <linux/delay.h> #include <linux/io.h> |
9c646cfc3 USB / Renesas: Fi... |
19 |
#include <linux/scatterlist.h> |
cc502bb74 renesas_usbhs: cl... |
20 21 |
#include "common.h" #include "pipe.h" |
e8d548d54 usb: renesas_usbh... |
22 |
|
d3af90a5e usb: renesas_usbh... |
23 |
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) |
5ea439945 usb: renesas_usbh... |
24 |
#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) |
d3af90a5e usb: renesas_usbh... |
25 |
|
d77e3f4e1 usb: renesas_usbh... |
26 |
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ |
e8d548d54 usb: renesas_usbh... |
27 |
/* |
233f519d2 usb: renesas_usbh... |
28 29 30 31 |
* packet initialize */ void usbhs_pkt_init(struct usbhs_pkt *pkt) { |
233f519d2 usb: renesas_usbh... |
32 33 34 35 36 |
INIT_LIST_HEAD(&pkt->node); } /* * packet control function |
4bd048115 usb: renesas_usbh... |
37 |
*/ |
97664a207 usb: renesas_usbh... |
38 |
static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) |
dad67397f usb: renesas_usbh... |
39 40 41 42 43 44 45 46 47 |
{ struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); struct device *dev = usbhs_priv_to_dev(priv); dev_err(dev, "null handler "); return -EINVAL; } |
fcb42e232 usb: renesas_usbh... |
48 |
static const struct usbhs_pkt_handle usbhsf_null_handler = { |
dad67397f usb: renesas_usbh... |
49 50 51 |
.prepare = usbhsf_null_handle, .try_run = usbhsf_null_handle, }; |
659d49540 usb: renesas_usbh... |
52 |
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, |
b331872b8 usb: gadget: rene... |
53 54 |
void (*done)(struct usbhs_priv *priv, struct usbhs_pkt *pkt), |
3edeee389 usb: renesas_usbh... |
55 |
void *buf, int len, int zero, int sequence) |
6acb95d4e usb: renesas_usbh... |
56 |
{ |
dad67397f usb: renesas_usbh... |
57 58 |
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); |
97664a207 usb: renesas_usbh... |
59 |
unsigned long flags; |
b331872b8 usb: gadget: rene... |
60 61 62 63 64 |
if (!done) { dev_err(dev, "no done function "); return; } |
a2c76b83f usb: renesas_usbh... |
65 66 |
/******************** spin lock ********************/ usbhs_lock(priv, flags); |
0c6ef985c usb: gadget: rene... |
67 |
if (!pipe->handler) { |
dad67397f usb: renesas_usbh... |
68 69 |
dev_err(dev, "no handler function "); |
0c6ef985c usb: gadget: rene... |
70 |
pipe->handler = &usbhsf_null_handler; |
dad67397f usb: renesas_usbh... |
71 |
} |
d52612869 usb: renesas_usbh... |
72 |
list_move_tail(&pkt->node, &pipe->list); |
6acb95d4e usb: renesas_usbh... |
73 |
|
0c6ef985c usb: gadget: rene... |
74 75 76 77 78 |
/* * each pkt must hold own handler. * because handler might be changed by its situation. * dma handler -> pio handler. */ |
659d49540 usb: renesas_usbh... |
79 80 |
pkt->pipe = pipe; pkt->buf = buf; |
0c6ef985c usb: gadget: rene... |
81 |
pkt->handler = pipe->handler; |
659d49540 usb: renesas_usbh... |
82 83 84 |
pkt->length = len; pkt->zero = zero; pkt->actual = 0; |
b331872b8 usb: gadget: rene... |
85 |
pkt->done = done; |
3edeee389 usb: renesas_usbh... |
86 |
pkt->sequence = sequence; |
97664a207 usb: renesas_usbh... |
87 88 89 |
usbhs_unlock(priv, flags); /******************** spin unlock ******************/ |
6acb95d4e usb: renesas_usbh... |
90 |
} |
97664a207 usb: renesas_usbh... |
91 |
static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) |
6acb95d4e usb: renesas_usbh... |
92 93 94 |
{ list_del_init(&pkt->node); } |
97664a207 usb: renesas_usbh... |
95 |
static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) |
6acb95d4e usb: renesas_usbh... |
96 97 98 |
{ if (list_empty(&pipe->list)) return NULL; |
d52612869 usb: renesas_usbh... |
99 |
return list_first_entry(&pipe->list, struct usbhs_pkt, node); |
6acb95d4e usb: renesas_usbh... |
100 |
} |
2743e7f90 usb: renesas_usbh... |
101 102 103 104 105 106 107 108 109 |
static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, struct usbhs_pkt *pkt); #define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) #define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map); |
97664a207 usb: renesas_usbh... |
110 111 112 |
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
2743e7f90 usb: renesas_usbh... |
113 |
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); |
97664a207 usb: renesas_usbh... |
114 115 116 117 |
unsigned long flags; /******************** spin lock ********************/ usbhs_lock(priv, flags); |
2743e7f90 usb: renesas_usbh... |
118 |
usbhs_pipe_disable(pipe); |
97664a207 usb: renesas_usbh... |
119 120 |
if (!pkt) pkt = __usbhsf_pkt_get(pipe); |
2743e7f90 usb: renesas_usbh... |
121 122 123 124 125 126 127 128 129 130 |
if (pkt) { struct dma_chan *chan = NULL; if (fifo) chan = usbhsf_dma_chan_get(fifo, pkt); if (chan) { dmaengine_terminate_all(chan); usbhsf_fifo_clear(pipe, fifo); usbhsf_dma_unmap(pkt); } |
97664a207 usb: renesas_usbh... |
131 |
__usbhsf_pkt_del(pkt); |
2743e7f90 usb: renesas_usbh... |
132 133 134 135 |
} if (fifo) usbhsf_fifo_unselect(pipe, fifo); |
97664a207 usb: renesas_usbh... |
136 137 138 139 140 141 |
usbhs_unlock(priv, flags); /******************** spin unlock ******************/ return pkt; } |
51b8a0218 usb: gadget: rene... |
142 143 144 145 146 147 148 |
enum { USBHSF_PKT_PREPARE, USBHSF_PKT_TRY_RUN, USBHSF_PKT_DMA_DONE, }; static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) |
97664a207 usb: renesas_usbh... |
149 150 |
{ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
97664a207 usb: renesas_usbh... |
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
struct usbhs_pkt *pkt; struct device *dev = usbhs_priv_to_dev(priv); int (*func)(struct usbhs_pkt *pkt, int *is_done); unsigned long flags; int ret = 0; int is_done = 0; /******************** spin lock ********************/ usbhs_lock(priv, flags); pkt = __usbhsf_pkt_get(pipe); if (!pkt) goto __usbhs_pkt_handler_end; switch (type) { case USBHSF_PKT_PREPARE: func = pkt->handler->prepare; break; case USBHSF_PKT_TRY_RUN: func = pkt->handler->try_run; break; |
e73a9891b usb: renesas_usbh... |
172 173 174 |
case USBHSF_PKT_DMA_DONE: func = pkt->handler->dma_done; break; |
97664a207 usb: renesas_usbh... |
175 |
default: |
984e833c2 usb: fix typo in ... |
176 177 |
dev_err(dev, "unknown pkt handler "); |
97664a207 usb: renesas_usbh... |
178 179 |
goto __usbhs_pkt_handler_end; } |
894f2fc44 usb: renesas_usbh... |
180 181 |
if (likely(func)) ret = func(pkt, &is_done); |
97664a207 usb: renesas_usbh... |
182 183 184 185 186 187 188 |
if (is_done) __usbhsf_pkt_del(pkt); __usbhs_pkt_handler_end: usbhs_unlock(priv, flags); /******************** spin unlock ******************/ |
0432eed00 usb: renesas_usbh... |
189 |
if (is_done) { |
b331872b8 usb: gadget: rene... |
190 |
pkt->done(priv, pkt); |
0432eed00 usb: renesas_usbh... |
191 192 |
usbhs_pkt_start(pipe); } |
97664a207 usb: renesas_usbh... |
193 194 195 |
return ret; } |
51b8a0218 usb: gadget: rene... |
196 197 198 199 |
void usbhs_pkt_start(struct usbhs_pipe *pipe) { usbhsf_pkt_handler(pipe, USBHSF_PKT_PREPARE); } |
4bd048115 usb: renesas_usbh... |
200 |
/* |
659d49540 usb: renesas_usbh... |
201 202 |
* irq enable/disable function */ |
3192fcb23 usb: renesas_usbh... |
203 204 |
#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e) #define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e) |
659d49540 usb: renesas_usbh... |
205 206 207 208 209 210 211 212 |
#define usbhsf_irq_callback_ctrl(pipe, status, enable) \ ({ \ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ u16 status = (1 << usbhs_pipe_number(pipe)); \ if (!mod) \ return; \ if (enable) \ |
3192fcb23 usb: renesas_usbh... |
213 |
mod->status |= status; \ |
659d49540 usb: renesas_usbh... |
214 |
else \ |
3192fcb23 usb: renesas_usbh... |
215 |
mod->status &= ~status; \ |
659d49540 usb: renesas_usbh... |
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
usbhs_irq_callback_update(priv, mod); \ }) static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable) { /* * And DCP pipe can NOT use "ready interrupt" for "send" * it should use "empty" interrupt. * see * "Operation" - "Interrupt Function" - "BRDY Interrupt" * * on the other hand, normal pipe can use "ready interrupt" for "send" * even though it is single/double buffer */ if (usbhs_pipe_is_dcp(pipe)) usbhsf_irq_empty_ctrl(pipe, enable); else usbhsf_irq_ready_ctrl(pipe, enable); } static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable) { usbhsf_irq_ready_ctrl(pipe, enable); } /* |
e8d548d54 usb: renesas_usbh... |
242 243 |
* FIFO ctrl */ |
d3af90a5e usb: renesas_usbh... |
244 245 |
static void usbhsf_send_terminator(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) |
e8d548d54 usb: renesas_usbh... |
246 247 |
{ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
d3af90a5e usb: renesas_usbh... |
248 |
usbhs_bset(priv, fifo->ctr, BVAL, BVAL); |
e8d548d54 usb: renesas_usbh... |
249 |
} |
d3af90a5e usb: renesas_usbh... |
250 251 |
static int usbhsf_fifo_barrier(struct usbhs_priv *priv, struct usbhs_fifo *fifo) |
e8d548d54 usb: renesas_usbh... |
252 253 254 255 256 |
{ int timeout = 1024; do { /* The FIFO port is accessible */ |
d3af90a5e usb: renesas_usbh... |
257 |
if (usbhs_read(priv, fifo->ctr) & FRDY) |
e8d548d54 usb: renesas_usbh... |
258 259 260 261 262 263 264 |
return 0; udelay(10); } while (timeout--); return -EBUSY; } |
d3af90a5e usb: renesas_usbh... |
265 266 |
static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) |
e8d548d54 usb: renesas_usbh... |
267 268 269 270 |
{ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); if (!usbhs_pipe_is_dcp(pipe)) |
d3af90a5e usb: renesas_usbh... |
271 |
usbhsf_fifo_barrier(priv, fifo); |
e8d548d54 usb: renesas_usbh... |
272 |
|
d3af90a5e usb: renesas_usbh... |
273 |
usbhs_write(priv, fifo->ctr, BCLR); |
e8d548d54 usb: renesas_usbh... |
274 |
} |
d3af90a5e usb: renesas_usbh... |
275 276 |
static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, struct usbhs_fifo *fifo) |
e8d548d54 usb: renesas_usbh... |
277 |
{ |
d3af90a5e usb: renesas_usbh... |
278 |
return usbhs_read(priv, fifo->ctr) & DTLN_MASK; |
e8d548d54 usb: renesas_usbh... |
279 |
} |
d77e3f4e1 usb: renesas_usbh... |
280 281 282 283 284 285 286 287 |
static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); usbhs_pipe_select_fifo(pipe, NULL); usbhs_write(priv, fifo->sel, 0); } |
d3af90a5e usb: renesas_usbh... |
288 289 290 |
static int usbhsf_fifo_select(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo, int write) |
e8d548d54 usb: renesas_usbh... |
291 292 293 294 295 296 |
{ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); int timeout = 1024; u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ |
d77e3f4e1 usb: renesas_usbh... |
297 298 299 |
if (usbhs_pipe_is_busy(pipe) || usbhsf_fifo_is_busy(fifo)) return -EBUSY; |
923520715 usb: gadget: rene... |
300 |
if (usbhs_pipe_is_dcp(pipe)) { |
e8d548d54 usb: renesas_usbh... |
301 |
base |= (1 == write) << 5; /* ISEL */ |
923520715 usb: gadget: rene... |
302 303 304 |
if (usbhs_mod_is_host(priv)) usbhs_dcp_dir_for_host(pipe, write); } |
e8d548d54 usb: renesas_usbh... |
305 |
/* "base" will be used below */ |
5ea439945 usb: renesas_usbh... |
306 307 308 309 |
if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo)) usbhs_write(priv, fifo->sel, base); else usbhs_write(priv, fifo->sel, base | MBW_32); |
e8d548d54 usb: renesas_usbh... |
310 311 312 |
/* check ISEL and CURPIPE value */ while (timeout--) { |
d77e3f4e1 usb: renesas_usbh... |
313 314 |
if (base == (mask & usbhs_read(priv, fifo->sel))) { usbhs_pipe_select_fifo(pipe, fifo); |
e8d548d54 usb: renesas_usbh... |
315 |
return 0; |
d77e3f4e1 usb: renesas_usbh... |
316 |
} |
e8d548d54 usb: renesas_usbh... |
317 318 319 320 321 322 323 324 325 326 |
udelay(10); } dev_err(dev, "fifo select error "); return -EIO; } /* |
9e74d601d usb: gadget: rene... |
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
* DCP status stage */ static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ struct device *dev = usbhs_priv_to_dev(priv); int ret; usbhs_pipe_disable(pipe); ret = usbhsf_fifo_select(pipe, fifo, 1); if (ret < 0) { dev_err(dev, "%s() faile ", __func__); return ret; } usbhs_pipe_sequence_data1(pipe); /* DATA1 */ usbhsf_fifo_clear(pipe, fifo); usbhsf_send_terminator(pipe, fifo); usbhsf_fifo_unselect(pipe, fifo); usbhsf_tx_irq_ctrl(pipe, 1); usbhs_pipe_enable(pipe); return ret; } static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ struct device *dev = usbhs_priv_to_dev(priv); int ret; usbhs_pipe_disable(pipe); ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) { dev_err(dev, "%s() fail ", __func__); return ret; } usbhs_pipe_sequence_data1(pipe); /* DATA1 */ usbhsf_fifo_clear(pipe, fifo); usbhsf_fifo_unselect(pipe, fifo); usbhsf_rx_irq_ctrl(pipe, 1); usbhs_pipe_enable(pipe); return ret; } static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; if (pkt->handler == &usbhs_dcp_status_stage_in_handler) usbhsf_tx_irq_ctrl(pipe, 0); else usbhsf_rx_irq_ctrl(pipe, 0); pkt->actual = pkt->length; *is_done = 1; return 0; } |
fcb42e232 usb: renesas_usbh... |
402 |
const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = { |
9e74d601d usb: gadget: rene... |
403 404 405 |
.prepare = usbhs_dcp_dir_switch_to_write, .try_run = usbhs_dcp_dir_switch_done, }; |
fcb42e232 usb: renesas_usbh... |
406 |
const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = { |
9e74d601d usb: gadget: rene... |
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
.prepare = usbhs_dcp_dir_switch_to_read, .try_run = usbhs_dcp_dir_switch_done, }; /* * DCP data stage (push) */ static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; usbhs_pipe_sequence_data1(pipe); /* DATA1 */ /* * change handler to PIO push */ pkt->handler = &usbhs_fifo_pio_push_handler; return pkt->handler->prepare(pkt, is_done); } |
fcb42e232 usb: renesas_usbh... |
427 |
const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = { |
9e74d601d usb: gadget: rene... |
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
.prepare = usbhsf_dcp_data_stage_try_push, }; /* * DCP data stage (pop) */ static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); if (usbhs_pipe_is_busy(pipe)) return 0; /* * prepare pop for DCP should * - change DCP direction, * - clear fifo * - DATA1 */ usbhs_pipe_disable(pipe); usbhs_pipe_sequence_data1(pipe); /* DATA1 */ usbhsf_fifo_select(pipe, fifo, 0); usbhsf_fifo_clear(pipe, fifo); usbhsf_fifo_unselect(pipe, fifo); /* * change handler to PIO pop */ pkt->handler = &usbhs_fifo_pio_pop_handler; return pkt->handler->prepare(pkt, is_done); } |
fcb42e232 usb: renesas_usbh... |
465 |
const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = { |
9e74d601d usb: gadget: rene... |
466 467 468 469 |
.prepare = usbhsf_dcp_data_stage_prepare_pop, }; /* |
233f519d2 usb: renesas_usbh... |
470 |
* PIO push handler |
e8d548d54 usb: renesas_usbh... |
471 |
*/ |
0cb7e61d1 usb: renesas_usbh... |
472 |
static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) |
e8d548d54 usb: renesas_usbh... |
473 |
{ |
4bd048115 usb: renesas_usbh... |
474 |
struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d54 usb: renesas_usbh... |
475 |
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d49540 usb: renesas_usbh... |
476 |
struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5e usb: renesas_usbh... |
477 478 |
struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ void __iomem *addr = priv->base + fifo->port; |
659d49540 usb: renesas_usbh... |
479 |
u8 *buf; |
e8d548d54 usb: renesas_usbh... |
480 481 |
int maxp = usbhs_pipe_get_maxpacket(pipe); int total_len; |
4bd048115 usb: renesas_usbh... |
482 |
int i, ret, len; |
97664a207 usb: renesas_usbh... |
483 |
int is_short; |
e8d548d54 usb: renesas_usbh... |
484 |
|
3edeee389 usb: renesas_usbh... |
485 486 |
usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ |
1c90ee0b3 usb: renesas_usbh... |
487 |
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); |
d3af90a5e usb: renesas_usbh... |
488 |
ret = usbhsf_fifo_select(pipe, fifo, 1); |
e8d548d54 usb: renesas_usbh... |
489 |
if (ret < 0) |
d77e3f4e1 usb: renesas_usbh... |
490 |
return 0; |
e8d548d54 usb: renesas_usbh... |
491 |
|
dad67397f usb: renesas_usbh... |
492 |
ret = usbhs_pipe_is_accessible(pipe); |
4ef85e0f6 usb: renesas_usbh... |
493 494 495 |
if (ret < 0) { /* inaccessible pipe is not an error */ ret = 0; |
659d49540 usb: renesas_usbh... |
496 |
goto usbhs_fifo_write_busy; |
4ef85e0f6 usb: renesas_usbh... |
497 |
} |
e8d548d54 usb: renesas_usbh... |
498 |
|
d3af90a5e usb: renesas_usbh... |
499 |
ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d54 usb: renesas_usbh... |
500 |
if (ret < 0) |
659d49540 usb: renesas_usbh... |
501 |
goto usbhs_fifo_write_busy; |
e8d548d54 usb: renesas_usbh... |
502 |
|
659d49540 usb: renesas_usbh... |
503 504 505 506 507 |
buf = pkt->buf + pkt->actual; len = pkt->length - pkt->actual; len = min(len, maxp); total_len = len; is_short = total_len < maxp; |
e8d548d54 usb: renesas_usbh... |
508 509 510 511 512 513 |
/* * FIXME * * 32-bit access only */ |
659d49540 usb: renesas_usbh... |
514 |
if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d54 usb: renesas_usbh... |
515 516 517 518 519 520 521 522 |
iowrite32_rep(addr, buf, len / 4); len %= 4; buf += total_len - len; } /* the rest operation */ for (i = 0; i < len; i++) iowrite8(buf[i], addr + (0x03 - (i & 0x03))); |
659d49540 usb: renesas_usbh... |
523 524 525 526 527 528 |
/* * variable update */ pkt->actual += total_len; if (pkt->actual < pkt->length) |
97664a207 usb: renesas_usbh... |
529 |
*is_done = 0; /* there are remainder data */ |
659d49540 usb: renesas_usbh... |
530 |
else if (is_short) |
97664a207 usb: renesas_usbh... |
531 |
*is_done = 1; /* short packet */ |
659d49540 usb: renesas_usbh... |
532 |
else |
97664a207 usb: renesas_usbh... |
533 |
*is_done = !pkt->zero; /* send zero packet ? */ |
659d49540 usb: renesas_usbh... |
534 535 536 537 538 |
/* * pipe/irq handling */ if (is_short) |
d3af90a5e usb: renesas_usbh... |
539 |
usbhsf_send_terminator(pipe, fifo); |
e8d548d54 usb: renesas_usbh... |
540 |
|
97664a207 usb: renesas_usbh... |
541 |
usbhsf_tx_irq_ctrl(pipe, !*is_done); |
8355b2b30 usb: renesas_usbh... |
542 |
usbhs_pipe_running(pipe, !*is_done); |
4bd048115 usb: renesas_usbh... |
543 |
usbhs_pipe_enable(pipe); |
659d49540 usb: renesas_usbh... |
544 545 546 |
dev_dbg(dev, " send %d (%d/ %d/ %d/ %d) ", usbhs_pipe_number(pipe), |
97664a207 usb: renesas_usbh... |
547 |
pkt->length, pkt->actual, *is_done, pkt->zero); |
659d49540 usb: renesas_usbh... |
548 |
|
d77e3f4e1 usb: renesas_usbh... |
549 |
usbhsf_fifo_unselect(pipe, fifo); |
4bd048115 usb: renesas_usbh... |
550 |
return 0; |
659d49540 usb: renesas_usbh... |
551 552 |
usbhs_fifo_write_busy: |
d77e3f4e1 usb: renesas_usbh... |
553 |
usbhsf_fifo_unselect(pipe, fifo); |
659d49540 usb: renesas_usbh... |
554 555 556 557 558 |
/* * pipe is busy. * retry in interrupt */ usbhsf_tx_irq_ctrl(pipe, 1); |
8355b2b30 usb: renesas_usbh... |
559 |
usbhs_pipe_running(pipe, 1); |
659d49540 usb: renesas_usbh... |
560 561 |
return ret; |
e8d548d54 usb: renesas_usbh... |
562 |
} |
8355b2b30 usb: renesas_usbh... |
563 564 565 566 567 568 569 |
static int usbhsf_pio_prepare_push(struct usbhs_pkt *pkt, int *is_done) { if (usbhs_pipe_is_running(pkt->pipe)) return 0; return usbhsf_pio_try_push(pkt, is_done); } |
fcb42e232 usb: renesas_usbh... |
570 |
const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { |
8355b2b30 usb: renesas_usbh... |
571 |
.prepare = usbhsf_pio_prepare_push, |
0cb7e61d1 usb: renesas_usbh... |
572 |
.try_run = usbhsf_pio_try_push, |
dad67397f usb: renesas_usbh... |
573 |
}; |
233f519d2 usb: renesas_usbh... |
574 575 576 |
/* * PIO pop handler */ |
97664a207 usb: renesas_usbh... |
577 |
static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d54 usb: renesas_usbh... |
578 |
{ |
dad67397f usb: renesas_usbh... |
579 |
struct usbhs_pipe *pipe = pkt->pipe; |
e73d42f15 usb: renesas_usbh... |
580 581 |
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); |
d77e3f4e1 usb: renesas_usbh... |
582 583 584 |
if (usbhs_pipe_is_busy(pipe)) return 0; |
e8d548d54 usb: renesas_usbh... |
585 |
|
8355b2b30 usb: renesas_usbh... |
586 587 |
if (usbhs_pipe_is_running(pipe)) return 0; |
e8d548d54 usb: renesas_usbh... |
588 |
/* |
d77e3f4e1 usb: renesas_usbh... |
589 |
* pipe enable to prepare packet receive |
e8d548d54 usb: renesas_usbh... |
590 |
*/ |
3edeee389 usb: renesas_usbh... |
591 592 |
usbhs_pipe_data_sequence(pipe, pkt->sequence); pkt->sequence = -1; /* -1 sequence will be ignored */ |
e8d548d54 usb: renesas_usbh... |
593 |
|
e73d42f15 usb: renesas_usbh... |
594 595 |
if (usbhs_pipe_is_dcp(pipe)) usbhsf_fifo_clear(pipe, fifo); |
1c90ee0b3 usb: renesas_usbh... |
596 |
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); |
e8d548d54 usb: renesas_usbh... |
597 |
usbhs_pipe_enable(pipe); |
8355b2b30 usb: renesas_usbh... |
598 |
usbhs_pipe_running(pipe, 1); |
659d49540 usb: renesas_usbh... |
599 |
usbhsf_rx_irq_ctrl(pipe, 1); |
e8d548d54 usb: renesas_usbh... |
600 |
|
d3af90a5e usb: renesas_usbh... |
601 |
return 0; |
e8d548d54 usb: renesas_usbh... |
602 |
} |
0cb7e61d1 usb: renesas_usbh... |
603 |
static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d54 usb: renesas_usbh... |
604 |
{ |
4bd048115 usb: renesas_usbh... |
605 |
struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d54 usb: renesas_usbh... |
606 |
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d49540 usb: renesas_usbh... |
607 |
struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5e usb: renesas_usbh... |
608 609 |
struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ void __iomem *addr = priv->base + fifo->port; |
659d49540 usb: renesas_usbh... |
610 611 612 |
u8 *buf; u32 data = 0; int maxp = usbhs_pipe_get_maxpacket(pipe); |
4bd048115 usb: renesas_usbh... |
613 |
int rcv_len, len; |
e8d548d54 usb: renesas_usbh... |
614 |
int i, ret; |
4bd048115 usb: renesas_usbh... |
615 |
int total_len = 0; |
e8d548d54 usb: renesas_usbh... |
616 |
|
d3af90a5e usb: renesas_usbh... |
617 |
ret = usbhsf_fifo_select(pipe, fifo, 0); |
e8d548d54 usb: renesas_usbh... |
618 |
if (ret < 0) |
d77e3f4e1 usb: renesas_usbh... |
619 |
return 0; |
e8d548d54 usb: renesas_usbh... |
620 |
|
d3af90a5e usb: renesas_usbh... |
621 |
ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d54 usb: renesas_usbh... |
622 |
if (ret < 0) |
d77e3f4e1 usb: renesas_usbh... |
623 |
goto usbhs_fifo_read_busy; |
e8d548d54 usb: renesas_usbh... |
624 |
|
d3af90a5e usb: renesas_usbh... |
625 |
rcv_len = usbhsf_fifo_rcv_len(priv, fifo); |
e8d548d54 usb: renesas_usbh... |
626 |
|
659d49540 usb: renesas_usbh... |
627 628 629 630 |
buf = pkt->buf + pkt->actual; len = pkt->length - pkt->actual; len = min(len, rcv_len); total_len = len; |
e8d548d54 usb: renesas_usbh... |
631 |
/* |
6ff5d09bd usb: gadget: rene... |
632 633 634 635 636 637 638 639 640 641 |
* update actual length first here to decide disable pipe. * if this pipe keeps BUF status and all data were popped, * then, next interrupt/token will be issued again */ pkt->actual += total_len; if ((pkt->actual == pkt->length) || /* receive all data */ (total_len < maxp)) { /* short packet */ *is_done = 1; usbhsf_rx_irq_ctrl(pipe, 0); |
8355b2b30 usb: renesas_usbh... |
642 |
usbhs_pipe_running(pipe, 0); |
93fb9127c usb: renesas_usbh... |
643 644 645 646 647 648 649 650 |
/* * If function mode, since this controller is possible to enter * Control Write status stage at this timing, this driver * should not disable the pipe. If such a case happens, this * controller is not able to complete the status stage. */ if (!usbhs_mod_is_host(priv) && !usbhs_pipe_is_dcp(pipe)) usbhs_pipe_disable(pipe); /* disable pipe first */ |
6ff5d09bd usb: gadget: rene... |
651 652 653 |
} /* |
e8d548d54 usb: renesas_usbh... |
654 655 656 657 658 659 |
* Buffer clear if Zero-Length packet * * see * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" */ if (0 == rcv_len) { |
3edeee389 usb: renesas_usbh... |
660 |
pkt->zero = 1; |
d3af90a5e usb: renesas_usbh... |
661 |
usbhsf_fifo_clear(pipe, fifo); |
4bd048115 usb: renesas_usbh... |
662 |
goto usbhs_fifo_read_end; |
e8d548d54 usb: renesas_usbh... |
663 |
} |
e8d548d54 usb: renesas_usbh... |
664 665 666 667 668 |
/* * FIXME * * 32-bit access only */ |
659d49540 usb: renesas_usbh... |
669 |
if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d54 usb: renesas_usbh... |
670 671 |
ioread32_rep(addr, buf, len / 4); len %= 4; |
659d49540 usb: renesas_usbh... |
672 |
buf += total_len - len; |
e8d548d54 usb: renesas_usbh... |
673 674 675 676 677 678 679 680 681 |
} /* the rest operation */ for (i = 0; i < len; i++) { if (!(i & 0x03)) data = ioread32(addr); buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; } |
4bd048115 usb: renesas_usbh... |
682 |
usbhs_fifo_read_end: |
97664a207 usb: renesas_usbh... |
683 684 685 686 |
dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d) ", usbhs_pipe_number(pipe), pkt->length, pkt->actual, *is_done, pkt->zero); |
d77e3f4e1 usb: renesas_usbh... |
687 688 689 690 |
usbhs_fifo_read_busy: usbhsf_fifo_unselect(pipe, fifo); return ret; |
e8d548d54 usb: renesas_usbh... |
691 |
} |
dad67397f usb: renesas_usbh... |
692 |
|
fcb42e232 usb: renesas_usbh... |
693 |
const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = { |
dad67397f usb: renesas_usbh... |
694 |
.prepare = usbhsf_prepare_pop, |
0cb7e61d1 usb: renesas_usbh... |
695 |
.try_run = usbhsf_pio_try_pop, |
dad67397f usb: renesas_usbh... |
696 697 698 |
}; /* |
233f519d2 usb: renesas_usbh... |
699 |
* DCP ctrol statge handler |
dad67397f usb: renesas_usbh... |
700 |
*/ |
97664a207 usb: renesas_usbh... |
701 |
static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) |
dad67397f usb: renesas_usbh... |
702 |
{ |
97664a207 usb: renesas_usbh... |
703 |
usbhs_dcp_control_transfer_done(pkt->pipe); |
dad67397f usb: renesas_usbh... |
704 |
|
97664a207 usb: renesas_usbh... |
705 |
*is_done = 1; |
dad67397f usb: renesas_usbh... |
706 707 708 |
return 0; } |
fcb42e232 usb: renesas_usbh... |
709 |
const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { |
dad67397f usb: renesas_usbh... |
710 711 712 713 714 |
.prepare = usbhsf_ctrl_stage_end, .try_run = usbhsf_ctrl_stage_end, }; /* |
e73a9891b usb: renesas_usbh... |
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
* DMA fifo functions */ static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, struct usbhs_pkt *pkt) { if (&usbhs_fifo_dma_push_handler == pkt->handler) return fifo->tx_chan; if (&usbhs_fifo_dma_pop_handler == pkt->handler) return fifo->rx_chan; return NULL; } static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { struct usbhs_fifo *fifo; |
3a2634a5b usb: renesas_usbh... |
733 |
int i; |
e73a9891b usb: renesas_usbh... |
734 |
|
3a2634a5b usb: renesas_usbh... |
735 736 737 738 739 |
usbhs_for_each_dfifo(priv, fifo, i) { if (usbhsf_dma_chan_get(fifo, pkt) && !usbhsf_fifo_is_busy(fifo)) return fifo; } |
e73a9891b usb: renesas_usbh... |
740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
return NULL; } #define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) #define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo, u16 dreqe) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); usbhs_bset(priv, fifo->sel, DREQE, dreqe); } |
e73a9891b usb: renesas_usbh... |
754 755 756 757 758 |
static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
c3cdcac78 usb: renesas_usbh... |
759 760 |
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); |
e73a9891b usb: renesas_usbh... |
761 |
|
c3cdcac78 usb: renesas_usbh... |
762 |
return info->dma_map_ctrl(chan->device->dev, pkt, map); |
e73a9891b usb: renesas_usbh... |
763 764 765 |
} static void usbhsf_dma_complete(void *arg); |
6e4b74e46 usb: renesas: fix... |
766 |
static void xfer_work(struct work_struct *work) |
e73a9891b usb: renesas_usbh... |
767 |
{ |
6e4b74e46 usb: renesas: fix... |
768 |
struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); |
e73a9891b usb: renesas_usbh... |
769 |
struct usbhs_pipe *pipe = pkt->pipe; |
4fdef6983 usb: renesas_usbh... |
770 |
struct usbhs_fifo *fifo; |
e73a9891b usb: renesas_usbh... |
771 |
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
e73a9891b usb: renesas_usbh... |
772 |
struct dma_async_tx_descriptor *desc; |
4fdef6983 usb: renesas_usbh... |
773 |
struct dma_chan *chan; |
e73a9891b usb: renesas_usbh... |
774 |
struct device *dev = usbhs_priv_to_dev(priv); |
55ba4e5ed USB-renesas: move... |
775 |
enum dma_transfer_direction dir; |
4fdef6983 usb: renesas_usbh... |
776 777 778 779 780 781 |
unsigned long flags; usbhs_lock(priv, flags); fifo = usbhs_pipe_to_fifo(pipe); if (!fifo) goto xfer_work_end; |
e73a9891b usb: renesas_usbh... |
782 |
|
4fdef6983 usb: renesas_usbh... |
783 |
chan = usbhsf_dma_chan_get(fifo, pkt); |
55ba4e5ed USB-renesas: move... |
784 |
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; |
e73a9891b usb: renesas_usbh... |
785 |
|
2f0de9d84 usb: renesas_usbh... |
786 787 |
desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual, pkt->trans, dir, |
16052827d dmaengine/dma_sla... |
788 |
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
e73a9891b usb: renesas_usbh... |
789 |
if (!desc) |
4fdef6983 usb: renesas_usbh... |
790 |
goto xfer_work_end; |
e73a9891b usb: renesas_usbh... |
791 792 793 |
desc->callback = usbhsf_dma_complete; desc->callback_param = pipe; |
ab330cf38 usb: renesas_usbh... |
794 795 |
pkt->cookie = dmaengine_submit(desc); if (pkt->cookie < 0) { |
e73a9891b usb: renesas_usbh... |
796 797 |
dev_err(dev, "Failed to submit dma descriptor "); |
4fdef6983 usb: renesas_usbh... |
798 |
goto xfer_work_end; |
e73a9891b usb: renesas_usbh... |
799 800 801 802 803 |
} dev_dbg(dev, " %s %d (%d/ %d) ", fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); |
8355b2b30 usb: renesas_usbh... |
804 |
usbhs_pipe_running(pipe, 1); |
e73a9891b usb: renesas_usbh... |
805 |
usbhsf_dma_start(pipe, fifo); |
9b53d9af7 usb: renesas_usbh... |
806 |
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); |
e73a9891b usb: renesas_usbh... |
807 |
dma_async_issue_pending(chan); |
9b53d9af7 usb: renesas_usbh... |
808 |
usbhs_pipe_enable(pipe); |
4fdef6983 usb: renesas_usbh... |
809 810 811 |
xfer_work_end: usbhs_unlock(priv, flags); |
e73a9891b usb: renesas_usbh... |
812 |
} |
233f519d2 usb: renesas_usbh... |
813 814 815 |
/* * DMA push handler */ |
e73a9891b usb: renesas_usbh... |
816 817 818 819 820 821 822 |
static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo; int len = pkt->length - pkt->actual; int ret; |
ab330cf38 usb: renesas_usbh... |
823 |
uintptr_t align_mask; |
e73a9891b usb: renesas_usbh... |
824 825 826 827 828 829 |
if (usbhs_pipe_is_busy(pipe)) return 0; /* use PIO if packet is less than pio_dma_border or pipe is DCP */ if ((len < usbhs_get_dparam(priv, pio_dma_border)) || |
700aa7ff8 usb: renesas_usbh... |
830 |
usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC)) |
e73a9891b usb: renesas_usbh... |
831 |
goto usbhsf_pio_prepare_push; |
ab330cf38 usb: renesas_usbh... |
832 833 |
/* check data length if this driver don't use USB-DMAC */ if (!usbhs_get_dparam(priv, has_usb_dmac) && len & 0x7) |
e73a9891b usb: renesas_usbh... |
834 |
goto usbhsf_pio_prepare_push; |
ab330cf38 usb: renesas_usbh... |
835 836 837 838 |
/* check buffer alignment */ align_mask = usbhs_get_dparam(priv, has_usb_dmac) ? USBHS_USB_DMAC_XFER_SIZE - 1 : 0x7; if ((uintptr_t)(pkt->buf + pkt->actual) & align_mask) |
9a12d0976 usb: renesas_usbh... |
839 |
goto usbhsf_pio_prepare_push; |
8355b2b30 usb: renesas_usbh... |
840 841 842 |
/* return at this time if the pipe is running */ if (usbhs_pipe_is_running(pipe)) return 0; |
e73a9891b usb: renesas_usbh... |
843 844 845 846 |
/* get enable DMA fifo */ fifo = usbhsf_get_dma_fifo(priv, pkt); if (!fifo) goto usbhsf_pio_prepare_push; |
e73a9891b usb: renesas_usbh... |
847 848 |
ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) |
e789ece18 usb: renesas_usbh... |
849 850 851 852 |
goto usbhsf_pio_prepare_push; if (usbhsf_dma_map(pkt) < 0) goto usbhsf_pio_prepare_push_unselect; |
e73a9891b usb: renesas_usbh... |
853 854 |
pkt->trans = len; |
6490865c6 usb: renesas_usbh... |
855 |
usbhsf_tx_irq_ctrl(pipe, 0); |
6e4b74e46 usb: renesas: fix... |
856 857 |
INIT_WORK(&pkt->work, xfer_work); schedule_work(&pkt->work); |
e73a9891b usb: renesas_usbh... |
858 859 |
return 0; |
e789ece18 usb: renesas_usbh... |
860 861 |
usbhsf_pio_prepare_push_unselect: usbhsf_fifo_unselect(pipe, fifo); |
e73a9891b usb: renesas_usbh... |
862 863 864 865 866 867 868 869 870 871 872 873 |
usbhsf_pio_prepare_push: /* * change handler to PIO */ pkt->handler = &usbhs_fifo_pio_push_handler; return pkt->handler->prepare(pkt, is_done); } static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; |
c0ed8b23b usb: renesas_usbh... |
874 |
int is_short = pkt->trans % usbhs_pipe_get_maxpacket(pipe); |
e73a9891b usb: renesas_usbh... |
875 |
|
c0ed8b23b usb: renesas_usbh... |
876 877 878 879 880 881 882 883 |
pkt->actual += pkt->trans; if (pkt->actual < pkt->length) *is_done = 0; /* there are remainder data */ else if (is_short) *is_done = 1; /* short packet */ else *is_done = !pkt->zero; /* send zero packet? */ |
e73a9891b usb: renesas_usbh... |
884 |
|
8355b2b30 usb: renesas_usbh... |
885 |
usbhs_pipe_running(pipe, !*is_done); |
e73a9891b usb: renesas_usbh... |
886 887 888 889 |
usbhsf_dma_stop(pipe, pipe->fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); |
c0ed8b23b usb: renesas_usbh... |
890 891 892 893 894 |
if (!*is_done) { /* change handler to PIO */ pkt->handler = &usbhs_fifo_pio_push_handler; return pkt->handler->try_run(pkt, is_done); } |
e73a9891b usb: renesas_usbh... |
895 896 |
return 0; } |
fcb42e232 usb: renesas_usbh... |
897 |
const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { |
e73a9891b usb: renesas_usbh... |
898 899 900 |
.prepare = usbhsf_dma_prepare_push, .dma_done = usbhsf_dma_push_done, }; |
233f519d2 usb: renesas_usbh... |
901 902 903 |
/* * DMA pop handler */ |
ab330cf38 usb: renesas_usbh... |
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
static int usbhsf_dma_prepare_pop_with_rx_irq(struct usbhs_pkt *pkt, int *is_done) { return usbhsf_prepare_pop(pkt, is_done); } static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo; int ret; if (usbhs_pipe_is_busy(pipe)) return 0; /* use PIO if packet is less than pio_dma_border or pipe is DCP */ if ((pkt->length < usbhs_get_dparam(priv, pio_dma_border)) || |
700aa7ff8 usb: renesas_usbh... |
924 |
usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC)) |
ab330cf38 usb: renesas_usbh... |
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
goto usbhsf_pio_prepare_pop; fifo = usbhsf_get_dma_fifo(priv, pkt); if (!fifo) goto usbhsf_pio_prepare_pop; if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1)) goto usbhsf_pio_prepare_pop; usbhs_pipe_config_change_bfre(pipe, 1); ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) goto usbhsf_pio_prepare_pop; if (usbhsf_dma_map(pkt) < 0) goto usbhsf_pio_prepare_pop_unselect; /* DMA */ /* * usbhs_fifo_dma_pop_handler :: prepare * enabled irq to come here. * but it is no longer needed for DMA. disable it. */ usbhsf_rx_irq_ctrl(pipe, 0); pkt->trans = pkt->length; INIT_WORK(&pkt->work, xfer_work); schedule_work(&pkt->work); return 0; usbhsf_pio_prepare_pop_unselect: usbhsf_fifo_unselect(pipe, fifo); usbhsf_pio_prepare_pop: /* * change handler to PIO */ pkt->handler = &usbhs_fifo_pio_pop_handler; usbhs_pipe_config_change_bfre(pipe, 0); return pkt->handler->prepare(pkt, is_done); } static int usbhsf_dma_prepare_pop(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); if (usbhs_get_dparam(priv, has_usb_dmac)) return usbhsf_dma_prepare_pop_with_usb_dmac(pkt, is_done); else return usbhsf_dma_prepare_pop_with_rx_irq(pkt, is_done); } static int usbhsf_dma_try_pop_with_rx_irq(struct usbhs_pkt *pkt, int *is_done) |
e73a9891b usb: renesas_usbh... |
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
{ struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo; int len, ret; if (usbhs_pipe_is_busy(pipe)) return 0; if (usbhs_pipe_is_dcp(pipe)) goto usbhsf_pio_prepare_pop; /* get enable DMA fifo */ fifo = usbhsf_get_dma_fifo(priv, pkt); if (!fifo) goto usbhsf_pio_prepare_pop; |
c9ae0c91b usb: gadget: rene... |
999 |
if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ |
9a12d0976 usb: renesas_usbh... |
1000 |
goto usbhsf_pio_prepare_pop; |
e73a9891b usb: renesas_usbh... |
1001 1002 1003 1004 1005 1006 1007 |
ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) goto usbhsf_pio_prepare_pop; /* use PIO if packet is less than pio_dma_border */ len = usbhsf_fifo_rcv_len(priv, fifo); len = min(pkt->length - pkt->actual, len); |
77975eec1 usb: renesas_usbh... |
1008 |
if (len & 0x7) /* 8byte alignment */ |
e73a9891b usb: renesas_usbh... |
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
goto usbhsf_pio_prepare_pop_unselect; if (len < usbhs_get_dparam(priv, pio_dma_border)) goto usbhsf_pio_prepare_pop_unselect; ret = usbhsf_fifo_barrier(priv, fifo); if (ret < 0) goto usbhsf_pio_prepare_pop_unselect; if (usbhsf_dma_map(pkt) < 0) goto usbhsf_pio_prepare_pop_unselect; /* DMA */ /* * usbhs_fifo_dma_pop_handler :: prepare * enabled irq to come here. * but it is no longer needed for DMA. disable it. */ usbhsf_rx_irq_ctrl(pipe, 0); pkt->trans = len; |
6e4b74e46 usb: renesas: fix... |
1031 1032 |
INIT_WORK(&pkt->work, xfer_work); schedule_work(&pkt->work); |
e73a9891b usb: renesas_usbh... |
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 |
return 0; usbhsf_pio_prepare_pop_unselect: usbhsf_fifo_unselect(pipe, fifo); usbhsf_pio_prepare_pop: /* * change handler to PIO */ pkt->handler = &usbhs_fifo_pio_pop_handler; return pkt->handler->try_run(pkt, is_done); } |
ab330cf38 usb: renesas_usbh... |
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 |
static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); BUG_ON(usbhs_get_dparam(priv, has_usb_dmac)); return usbhsf_dma_try_pop_with_rx_irq(pkt, is_done); } static int usbhsf_dma_pop_done_with_rx_irq(struct usbhs_pkt *pkt, int *is_done) |
e73a9891b usb: renesas_usbh... |
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
{ struct usbhs_pipe *pipe = pkt->pipe; int maxp = usbhs_pipe_get_maxpacket(pipe); usbhsf_dma_stop(pipe, pipe->fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); pkt->actual += pkt->trans; if ((pkt->actual == pkt->length) || /* receive all data */ (pkt->trans < maxp)) { /* short packet */ *is_done = 1; |
8355b2b30 usb: renesas_usbh... |
1070 |
usbhs_pipe_running(pipe, 0); |
e73a9891b usb: renesas_usbh... |
1071 1072 |
} else { /* re-enable */ |
8355b2b30 usb: renesas_usbh... |
1073 |
usbhs_pipe_running(pipe, 0); |
e73a9891b usb: renesas_usbh... |
1074 1075 1076 1077 1078 |
usbhsf_prepare_pop(pkt, is_done); } return 0; } |
ab330cf38 usb: renesas_usbh... |
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 |
static size_t usbhs_dma_calc_received_size(struct usbhs_pkt *pkt, struct dma_chan *chan, int dtln) { struct usbhs_pipe *pipe = pkt->pipe; struct dma_tx_state state; size_t received_size; int maxp = usbhs_pipe_get_maxpacket(pipe); dmaengine_tx_status(chan, pkt->cookie, &state); received_size = pkt->length - state.residue; if (dtln) { received_size -= USBHS_USB_DMAC_XFER_SIZE; received_size &= ~(maxp - 1); received_size += dtln; } return received_size; } static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); int rcv_len; /* * Since the driver disables rx_irq in DMA mode, the interrupt handler * cannot the BRDYSTS. So, the function clears it here because the * driver may use PIO mode next time. */ usbhs_xxxsts_clear(priv, BRDYSTS, usbhs_pipe_number(pipe)); rcv_len = usbhsf_fifo_rcv_len(priv, fifo); usbhsf_fifo_clear(pipe, fifo); pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len); usbhsf_dma_stop(pipe, fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); /* The driver can assume the rx transaction is always "done" */ *is_done = 1; return 0; } static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); if (usbhs_get_dparam(priv, has_usb_dmac)) return usbhsf_dma_pop_done_with_usb_dmac(pkt, is_done); else return usbhsf_dma_pop_done_with_rx_irq(pkt, is_done); } |
fcb42e232 usb: renesas_usbh... |
1138 |
const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { |
ab330cf38 usb: renesas_usbh... |
1139 |
.prepare = usbhsf_dma_prepare_pop, |
e73a9891b usb: renesas_usbh... |
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 |
.try_run = usbhsf_dma_try_pop, .dma_done = usbhsf_dma_pop_done }; /* * DMA setting */ static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) { struct sh_dmae_slave *slave = param; /* * FIXME * * usbhs doesn't recognize id = 0 as valid DMA */ |
f19b7e0db usb: renesas_usbh... |
1156 |
if (0 == slave->shdma_slave.slave_id) |
e73a9891b usb: renesas_usbh... |
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
return false; chan->private = slave; return true; } static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo) { if (fifo->tx_chan) dma_release_channel(fifo->tx_chan); if (fifo->rx_chan) dma_release_channel(fifo->rx_chan); fifo->tx_chan = NULL; fifo->rx_chan = NULL; } |
6e3f53ab5 usb: renesas_usbh... |
1174 |
static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo) |
e73a9891b usb: renesas_usbh... |
1175 |
{ |
e73a9891b usb: renesas_usbh... |
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 |
dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); fifo->tx_chan = dma_request_channel(mask, usbhsf_dma_filter, &fifo->tx_slave); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter, &fifo->rx_slave); |
6e3f53ab5 usb: renesas_usbh... |
1187 |
} |
7a96b7846 usb: renesas_usbh... |
1188 1189 |
static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo, int channel) |
abd2dbf6b usb: renesas_usbh... |
1190 |
{ |
7a96b7846 usb: renesas_usbh... |
1191 |
char name[16]; |
7cc99f1e9 usb: renesas_usbh... |
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 |
/* * To avoid complex handing for DnFIFOs, the driver uses each * DnFIFO as TX or RX direction (not bi-direction). * So, the driver uses odd channels for TX, even channels for RX. */ snprintf(name, sizeof(name), "ch%d", channel); if (channel & 1) { fifo->tx_chan = dma_request_slave_channel_reason(dev, name); if (IS_ERR(fifo->tx_chan)) fifo->tx_chan = NULL; } else { fifo->rx_chan = dma_request_slave_channel_reason(dev, name); if (IS_ERR(fifo->rx_chan)) fifo->rx_chan = NULL; } |
abd2dbf6b usb: renesas_usbh... |
1207 |
} |
7a96b7846 usb: renesas_usbh... |
1208 1209 |
static void usbhsf_dma_init(struct usbhs_priv *priv, struct usbhs_fifo *fifo, int channel) |
6e3f53ab5 usb: renesas_usbh... |
1210 1211 |
{ struct device *dev = usbhs_priv_to_dev(priv); |
abd2dbf6b usb: renesas_usbh... |
1212 |
if (dev->of_node) |
7a96b7846 usb: renesas_usbh... |
1213 |
usbhsf_dma_init_dt(dev, fifo, channel); |
abd2dbf6b usb: renesas_usbh... |
1214 1215 |
else usbhsf_dma_init_pdev(fifo); |
e73a9891b usb: renesas_usbh... |
1216 1217 |
if (fifo->tx_chan || fifo->rx_chan) |
4ce688056 usb: renesas_usbh... |
1218 1219 |
dev_dbg(dev, "enable DMAEngine (%s%s%s) ", |
e73a9891b usb: renesas_usbh... |
1220 1221 1222 1223 1224 1225 |
fifo->name, fifo->tx_chan ? "[TX]" : " ", fifo->rx_chan ? "[RX]" : " "); } /* |
dad67397f usb: renesas_usbh... |
1226 1227 1228 1229 1230 1231 |
* irq functions */ static int usbhsf_irq_empty(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhs_pipe *pipe; |
dad67397f usb: renesas_usbh... |
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 |
struct device *dev = usbhs_priv_to_dev(priv); int i, ret; if (!irq_state->bempsts) { dev_err(dev, "debug %s !! ", __func__); return -EIO; } dev_dbg(dev, "irq empty [0x%04x] ", irq_state->bempsts); /* * search interrupted "pipe" * not "uep". */ usbhs_for_each_pipe_with_dcp(pipe, priv, i) { if (!(irq_state->bempsts & (1 << i))) continue; |
51b8a0218 usb: gadget: rene... |
1251 |
ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); |
dad67397f usb: renesas_usbh... |
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 |
if (ret < 0) dev_err(dev, "irq_empty run_error %d : %d ", i, ret); } return 0; } static int usbhsf_irq_ready(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhs_pipe *pipe; |
dad67397f usb: renesas_usbh... |
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
struct device *dev = usbhs_priv_to_dev(priv); int i, ret; if (!irq_state->brdysts) { dev_err(dev, "debug %s !! ", __func__); return -EIO; } dev_dbg(dev, "irq ready [0x%04x] ", irq_state->brdysts); /* * search interrupted "pipe" * not "uep". */ usbhs_for_each_pipe_with_dcp(pipe, priv, i) { if (!(irq_state->brdysts & (1 << i))) continue; |
51b8a0218 usb: gadget: rene... |
1283 |
ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); |
dad67397f usb: renesas_usbh... |
1284 1285 1286 1287 1288 1289 1290 |
if (ret < 0) dev_err(dev, "irq_ready run_error %d : %d ", i, ret); } return 0; } |
e73a9891b usb: renesas_usbh... |
1291 1292 1293 1294 1295 1296 |
static void usbhsf_dma_complete(void *arg) { struct usbhs_pipe *pipe = arg; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); int ret; |
51b8a0218 usb: gadget: rene... |
1297 |
ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_DMA_DONE); |
e73a9891b usb: renesas_usbh... |
1298 1299 1300 1301 1302 |
if (ret < 0) dev_err(dev, "dma_complete run_error %d : %d ", usbhs_pipe_number(pipe), ret); } |
cdeb79431 usb: renesas_usbh... |
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 |
void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ /* clear DCP FIFO of transmission */ if (usbhsf_fifo_select(pipe, fifo, 1) < 0) return; usbhsf_fifo_clear(pipe, fifo); usbhsf_fifo_unselect(pipe, fifo); /* clear DCP FIFO of reception */ if (usbhsf_fifo_select(pipe, fifo, 0) < 0) return; usbhsf_fifo_clear(pipe, fifo); usbhsf_fifo_unselect(pipe, fifo); } |
dad67397f usb: renesas_usbh... |
1320 1321 1322 1323 1324 1325 |
/* * fifo init */ void usbhs_fifo_init(struct usbhs_priv *priv) { struct usbhs_mod *mod = usbhs_mod_get_current(priv); |
d77e3f4e1 usb: renesas_usbh... |
1326 |
struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); |
3a2634a5b usb: renesas_usbh... |
1327 1328 |
struct usbhs_fifo *dfifo; int i; |
dad67397f usb: renesas_usbh... |
1329 1330 1331 1332 1333 |
mod->irq_empty = usbhsf_irq_empty; mod->irq_ready = usbhsf_irq_ready; mod->irq_bempsts = 0; mod->irq_brdysts = 0; |
d77e3f4e1 usb: renesas_usbh... |
1334 1335 |
cfifo->pipe = NULL; |
3a2634a5b usb: renesas_usbh... |
1336 1337 |
usbhs_for_each_dfifo(priv, dfifo, i) dfifo->pipe = NULL; |
dad67397f usb: renesas_usbh... |
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 |
} void usbhs_fifo_quit(struct usbhs_priv *priv) { struct usbhs_mod *mod = usbhs_mod_get_current(priv); mod->irq_empty = NULL; mod->irq_ready = NULL; mod->irq_bempsts = 0; mod->irq_brdysts = 0; } |
d3af90a5e usb: renesas_usbh... |
1349 |
|
53e734b1e usb: renesas_usbh... |
1350 |
#define __USBHS_DFIFO_INIT(priv, fifo, channel, fifo_port) \ |
3a2634a5b usb: renesas_usbh... |
1351 1352 1353 |
do { \ fifo = usbhsf_get_dnfifo(priv, channel); \ fifo->name = "D"#channel"FIFO"; \ |
53e734b1e usb: renesas_usbh... |
1354 |
fifo->port = fifo_port; \ |
3a2634a5b usb: renesas_usbh... |
1355 1356 1357 1358 1359 1360 |
fifo->sel = D##channel##FIFOSEL; \ fifo->ctr = D##channel##FIFOCTR; \ fifo->tx_slave.shdma_slave.slave_id = \ usbhs_get_dparam(priv, d##channel##_tx_id); \ fifo->rx_slave.shdma_slave.slave_id = \ usbhs_get_dparam(priv, d##channel##_rx_id); \ |
7a96b7846 usb: renesas_usbh... |
1361 |
usbhsf_dma_init(priv, fifo, channel); \ |
3a2634a5b usb: renesas_usbh... |
1362 |
} while (0) |
53e734b1e usb: renesas_usbh... |
1363 1364 1365 1366 |
#define USBHS_DFIFO_INIT(priv, fifo, channel) \ __USBHS_DFIFO_INIT(priv, fifo, channel, D##channel##FIFO) #define USBHS_DFIFO_INIT_NO_PORT(priv, fifo, channel) \ __USBHS_DFIFO_INIT(priv, fifo, channel, 0) |
d3af90a5e usb: renesas_usbh... |
1367 1368 1369 1370 1371 1372 |
int usbhs_fifo_probe(struct usbhs_priv *priv) { struct usbhs_fifo *fifo; /* CFIFO */ fifo = usbhsf_get_cfifo(priv); |
e73a9891b usb: renesas_usbh... |
1373 |
fifo->name = "CFIFO"; |
d3af90a5e usb: renesas_usbh... |
1374 1375 1376 |
fifo->port = CFIFO; fifo->sel = CFIFOSEL; fifo->ctr = CFIFOCTR; |
3a2634a5b usb: renesas_usbh... |
1377 1378 1379 |
/* DFIFO */ USBHS_DFIFO_INIT(priv, fifo, 0); USBHS_DFIFO_INIT(priv, fifo, 1); |
d3cf6a4b0 usb: renesas_usbh... |
1380 1381 |
USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 2); USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 3); |
e73a9891b usb: renesas_usbh... |
1382 |
|
d3af90a5e usb: renesas_usbh... |
1383 1384 1385 1386 1387 |
return 0; } void usbhs_fifo_remove(struct usbhs_priv *priv) { |
3a2634a5b usb: renesas_usbh... |
1388 1389 1390 1391 1392 |
struct usbhs_fifo *fifo; int i; usbhs_for_each_dfifo(priv, fifo, i) usbhsf_dma_quit(priv, fifo); |
d3af90a5e usb: renesas_usbh... |
1393 |
} |