/* * FIFO ctrl */ static void usbhsf_send_terminator(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); usbhs_bset(priv, fifo->ctr, BVAL, BVAL); }
/* * PIPEnTRN/PIPEnTRE functions */ static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); int num = usbhs_pipe_number(pipe); u16 reg; /* * It is impossible to calculate address, * since PIPEnTRN addresses were mapped randomly. */ #define CASE_PIPExTRN(a) \ case 0x ## a: \ reg = PIPE ## a ## TRN; \ break; switch (num) { CASE_PIPExTRN(1); CASE_PIPExTRN(2); CASE_PIPExTRN(3); CASE_PIPExTRN(4); CASE_PIPExTRN(5); CASE_PIPExTRN(B); CASE_PIPExTRN(C); CASE_PIPExTRN(D); CASE_PIPExTRN(E); CASE_PIPExTRN(F); CASE_PIPExTRN(9); CASE_PIPExTRN(A); default: dev_err(dev, "unknown pipe (%d)\n", num); return; } __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); }
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); }
/* * packet control function */ static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); struct device *dev = usbhs_priv_to_dev(priv); dev_err(dev, "null handler\n"); return -EINVAL; }
static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); if (!usbhs_pipe_is_dcp(pipe)) usbhsf_fifo_barrier(priv, fifo); usbhs_write(priv, fifo->ctr, BCLR); }
static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int offset = usbhsp_addr_offset(pipe); if (usbhs_pipe_is_dcp(pipe)) return usbhs_read(priv, DCPCTR); else return usbhs_read(priv, PIPEnCTR + offset); }
/* * DCPCTR/PIPEnCTR functions */ static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int offset = usbhsp_addr_offset(pipe); if (usbhs_pipe_is_dcp(pipe)) usbhs_bset(priv, DCPCTR, mask, val); else usbhs_bset(priv, PIPEnCTR + offset, mask, val); }
static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, u16 dcp_reg, u16 pipe_reg) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); if (usbhs_pipe_is_dcp(pipe)) return usbhs_read(priv, dcp_reg); else return usbhs_read(priv, pipe_reg); }
/* * DCP/PIPE functions */ static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, u16 dcp_reg, u16 pipe_reg, u16 mask, u16 val) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); if (usbhs_pipe_is_dcp(pipe)) usbhs_bset(priv, dcp_reg, mask, val); else usbhs_bset(priv, pipe_reg, mask, val); }
/* * 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\n",
static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 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; case USBHSF_PKT_DMA_DONE: func = pkt->handler->dma_done; break; default: dev_err(dev, "unknown pkt hander\n"); goto __usbhs_pkt_handler_end; } ret = func(pkt, &is_done); if (is_done) __usbhsf_pkt_del(pkt); __usbhs_pkt_handler_end: usbhs_unlock(priv, flags); /******************** spin unlock ******************/ if (is_done) { pkt->done(priv, pkt); usbhs_pkt_start(pipe); } return ret; }
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); unsigned long flags; /******************** spin lock ********************/ usbhs_lock(priv, flags); if (!pkt) pkt = __usbhsf_pkt_get(pipe); if (pkt) __usbhsf_pkt_del(pkt); usbhs_unlock(priv, flags); /******************** spin unlock ******************/ return pkt; }
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, void (*done)(struct usbhs_priv *priv, struct usbhs_pkt *pkt), void *buf, int len, int zero, int sequence) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); unsigned long flags; if (!done) { dev_err(dev, "no done function\n"); return; } /******************** spin lock ********************/ usbhs_lock(priv, flags); if (!pipe->handler) { dev_err(dev, "no handler function\n"); pipe->handler = &usbhsf_null_handler; } list_move_tail(&pkt->node, &pipe->list); /* * each pkt must hold own handler. * because handler might be changed by its situation. * dma handler -> pio handler. */ pkt->pipe = pipe; pkt->buf = buf; pkt->handler = pipe->handler; pkt->length = len; pkt->zero = zero; pkt->actual = 0; pkt->done = done; pkt->sequence = sequence; usbhs_unlock(priv, flags); /******************** spin unlock ******************/ }
/* * pipe control functions */ static void usbhsp_pipe_select(struct usbhs_pipe *pipe) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); /* * On pipe, this is necessary before * accesses to below registers. * * PIPESEL : usbhsp_pipe_select * PIPECFG : usbhsp_pipe_cfg_xxx * PIPEBUF : usbhsp_pipe_buf_xxx * PIPEMAXP : usbhsp_pipe_maxp_xxx * PIPEPERI */ /* * if pipe is dcp, no pipe is selected. * it is no problem, because dcp have its register */ usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); }
static int usbhsf_fifo_select(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo, int write) { 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 */ if (usbhs_pipe_is_busy(pipe) || usbhsf_fifo_is_busy(fifo)) return -EBUSY; if (usbhs_pipe_is_dcp(pipe)) { base |= (1 == write) << 5; /* ISEL */ if (usbhs_mod_is_host(priv)) usbhs_dcp_dir_for_host(pipe, write); } /* "base" will be used below */ 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); /* check ISEL and CURPIPE value */ while (timeout--) { if (base == (mask & usbhs_read(priv, fifo->sel))) { usbhs_pipe_select_fifo(pipe, fifo); return 0; } udelay(10); } dev_err(dev, "fifo select error\n"); return -EIO; }
static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int timeout = 1024; u16 val; /* * make sure.... * * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is * specified by the CURPIPE bits. * When changing the setting of this bit after changing * the PID bits for the selected pipe from BUF to NAK, * check that CSSTS = 0 and PBUSY = 0. */ /* * CURPIPE bit = 0 * * see also * "Operation" * - "Pipe Control" * - "Pipe Control Registers Switching Procedure" */ usbhs_write(priv, CFIFOSEL, 0); usbhs_pipe_disable(pipe); do { val = usbhsp_pipectrl_get(pipe); val &= CSSTS | PID_MASK; if (!val) return 0; udelay(10); } while (timeout--); return -EBUSY; }