usb: renesas_usbhs: divide data transfer functions
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / usb / renesas_usbhs / fifo.c
blob098388489813c9a10d3766854af69a922d5e0200
1 /*
2 * Renesas USB driver
4 * Copyright (C) 2011 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 #include <linux/delay.h>
18 #include <linux/io.h>
19 #include "./common.h"
20 #include "./pipe.h"
23 * packet info function
25 void usbhs_pkt_update(struct usbhs_pkt *pkt,
26 struct usbhs_pipe *pipe,
27 void *buf, int len)
29 pkt->pipe = pipe;
30 pkt->buf = buf;
31 pkt->length = len;
32 pkt->actual = 0;
33 pkt->maxp = 0;
37 * FIFO ctrl
39 static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
41 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
43 usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
46 static int usbhsf_fifo_barrier(struct usbhs_priv *priv)
48 int timeout = 1024;
50 do {
51 /* The FIFO port is accessible */
52 if (usbhs_read(priv, CFIFOCTR) & FRDY)
53 return 0;
55 udelay(10);
56 } while (timeout--);
58 return -EBUSY;
61 static void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
63 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
65 if (!usbhs_pipe_is_dcp(pipe))
66 usbhsf_fifo_barrier(priv);
68 usbhs_write(priv, CFIFOCTR, BCLR);
71 static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
73 return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
76 static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
78 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
79 struct device *dev = usbhs_priv_to_dev(priv);
80 int timeout = 1024;
81 u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
82 u16 base = usbhs_pipe_number(pipe); /* CURPIPE */
84 if (usbhs_pipe_is_dcp(pipe))
85 base |= (1 == write) << 5; /* ISEL */
87 /* "base" will be used below */
88 usbhs_write(priv, CFIFOSEL, base | MBW_32);
90 /* check ISEL and CURPIPE value */
91 while (timeout--) {
92 if (base == (mask & usbhs_read(priv, CFIFOSEL)))
93 return 0;
94 udelay(10);
97 dev_err(dev, "fifo select error\n");
99 return -EIO;
103 * PIO fifo functions
105 int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
107 return usbhsf_fifo_select(pipe, 1);
110 int usbhs_fifo_write(struct usbhs_pkt *pkt)
112 struct usbhs_pipe *pipe = pkt->pipe;
113 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
114 struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
115 void __iomem *addr = priv->base + CFIFO;
116 int maxp = usbhs_pipe_get_maxpacket(pipe);
117 int total_len;
118 u8 *buf = pkt->buf;
119 int i, ret, len;
121 ret = usbhs_pipe_is_accessible(pipe);
122 if (ret < 0)
123 return ret;
125 ret = usbhsf_fifo_select(pipe, 1);
126 if (ret < 0)
127 return ret;
129 ret = usbhsf_fifo_barrier(priv);
130 if (ret < 0)
131 return ret;
133 len = min(pkt->length, maxp);
134 total_len = len;
137 * FIXME
139 * 32-bit access only
141 if (len >= 4 &&
142 !((unsigned long)buf & 0x03)) {
143 iowrite32_rep(addr, buf, len / 4);
144 len %= 4;
145 buf += total_len - len;
148 /* the rest operation */
149 for (i = 0; i < len; i++)
150 iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
152 if (total_len < maxp)
153 usbhsf_send_terminator(pipe);
155 usbhs_pipe_enable(pipe);
157 /* update pkt */
158 if (info->tx_done) {
159 pkt->actual = total_len;
160 pkt->maxp = maxp;
161 info->tx_done(pkt);
164 return 0;
167 int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
169 int ret;
172 * select pipe and enable it to prepare packet receive
174 ret = usbhsf_fifo_select(pipe, 0);
175 if (ret < 0)
176 return ret;
178 usbhs_pipe_enable(pipe);
180 return ret;
183 int usbhs_fifo_read(struct usbhs_pkt *pkt)
185 struct usbhs_pipe *pipe = pkt->pipe;
186 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
187 struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
188 void __iomem *addr = priv->base + CFIFO;
189 u8 *buf = pkt->buf;
190 int rcv_len, len;
191 int i, ret;
192 int total_len = 0;
193 u32 data = 0;
195 ret = usbhsf_fifo_select(pipe, 0);
196 if (ret < 0)
197 return ret;
199 ret = usbhsf_fifo_barrier(priv);
200 if (ret < 0)
201 return ret;
203 rcv_len = usbhsf_fifo_rcv_len(priv);
206 * Buffer clear if Zero-Length packet
208 * see
209 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
211 if (0 == rcv_len) {
212 usbhsf_fifo_clear(pipe);
213 goto usbhs_fifo_read_end;
216 len = min(rcv_len, pkt->length);
217 total_len = len;
220 * FIXME
222 * 32-bit access only
224 if (len >= 4 &&
225 !((unsigned long)buf & 0x03)) {
226 ioread32_rep(addr, buf, len / 4);
227 len %= 4;
228 buf += rcv_len - len;
231 /* the rest operation */
232 for (i = 0; i < len; i++) {
233 if (!(i & 0x03))
234 data = ioread32(addr);
236 buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
239 usbhs_fifo_read_end:
240 if (info->rx_done) {
241 /* update pkt */
242 pkt->actual = total_len;
243 pkt->maxp = usbhs_pipe_get_maxpacket(pipe);
244 info->rx_done(pkt);
247 return 0;