aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/renesas_usbhs/fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/renesas_usbhs/fifo.c')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
new file mode 100644
index 000000000000..3fd3adf90541
--- /dev/null
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -0,0 +1,211 @@
1/*
2 * Renesas USB driver
3 *
4 * Copyright (C) 2011 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
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.
11 *
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
15 *
16 */
17#include <linux/delay.h>
18#include <linux/io.h>
19#include "./common.h"
20#include "./pipe.h"
21
22/*
23 * FIFO ctrl
24 */
25static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
26{
27 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
28
29 usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
30}
31
32static int usbhsf_fifo_barrier(struct usbhs_priv *priv)
33{
34 int timeout = 1024;
35
36 do {
37 /* The FIFO port is accessible */
38 if (usbhs_read(priv, CFIFOCTR) & FRDY)
39 return 0;
40
41 udelay(10);
42 } while (timeout--);
43
44 return -EBUSY;
45}
46
47static void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
48{
49 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
50
51 if (!usbhs_pipe_is_dcp(pipe))
52 usbhsf_fifo_barrier(priv);
53
54 usbhs_write(priv, CFIFOCTR, BCLR);
55}
56
57static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
58{
59 return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
60}
61
62static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
63{
64 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
65 struct device *dev = usbhs_priv_to_dev(priv);
66 int timeout = 1024;
67 u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
68 u16 base = usbhs_pipe_number(pipe); /* CURPIPE */
69
70 if (usbhs_pipe_is_dcp(pipe))
71 base |= (1 == write) << 5; /* ISEL */
72
73 /* "base" will be used below */
74 usbhs_write(priv, CFIFOSEL, base | MBW_32);
75
76 /* check ISEL and CURPIPE value */
77 while (timeout--) {
78 if (base == (mask & usbhs_read(priv, CFIFOSEL)))
79 return 0;
80 udelay(10);
81 }
82
83 dev_err(dev, "fifo select error\n");
84
85 return -EIO;
86}
87
88/*
89 * PIO fifo functions
90 */
91int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
92{
93 return usbhsf_fifo_select(pipe, 1);
94}
95
96int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len)
97{
98 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
99 void __iomem *addr = priv->base + CFIFO;
100 int maxp = usbhs_pipe_get_maxpacket(pipe);
101 int total_len;
102 int i, ret;
103
104 ret = usbhs_pipe_is_accessible(pipe);
105 if (ret < 0)
106 return ret;
107
108 ret = usbhsf_fifo_select(pipe, 1);
109 if (ret < 0)
110 return ret;
111
112 ret = usbhsf_fifo_barrier(priv);
113 if (ret < 0)
114 return ret;
115
116 len = min(len, maxp);
117 total_len = len;
118
119 /*
120 * FIXME
121 *
122 * 32-bit access only
123 */
124 if (len >= 4 &&
125 !((unsigned long)buf & 0x03)) {
126 iowrite32_rep(addr, buf, len / 4);
127 len %= 4;
128 buf += total_len - len;
129 }
130
131 /* the rest operation */
132 for (i = 0; i < len; i++)
133 iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
134
135 if (total_len < maxp)
136 usbhsf_send_terminator(pipe);
137
138 return total_len;
139}
140
141int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
142{
143 int ret;
144
145 /*
146 * select pipe and enable it to prepare packet receive
147 */
148 ret = usbhsf_fifo_select(pipe, 0);
149 if (ret < 0)
150 return ret;
151
152 usbhs_pipe_enable(pipe);
153
154 return ret;
155}
156
157int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len)
158{
159 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
160 void __iomem *addr = priv->base + CFIFO;
161 int rcv_len;
162 int i, ret;
163 int total_len;
164 u32 data = 0;
165
166 ret = usbhsf_fifo_select(pipe, 0);
167 if (ret < 0)
168 return ret;
169
170 ret = usbhsf_fifo_barrier(priv);
171 if (ret < 0)
172 return ret;
173
174 rcv_len = usbhsf_fifo_rcv_len(priv);
175
176 /*
177 * Buffer clear if Zero-Length packet
178 *
179 * see
180 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
181 */
182 if (0 == rcv_len) {
183 usbhsf_fifo_clear(pipe);
184 return 0;
185 }
186
187 len = min(rcv_len, len);
188 total_len = len;
189
190 /*
191 * FIXME
192 *
193 * 32-bit access only
194 */
195 if (len >= 4 &&
196 !((unsigned long)buf & 0x03)) {
197 ioread32_rep(addr, buf, len / 4);
198 len %= 4;
199 buf += rcv_len - len;
200 }
201
202 /* the rest operation */
203 for (i = 0; i < len; i++) {
204 if (!(i & 0x03))
205 data = ioread32(addr);
206
207 buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
208 }
209
210 return total_len;
211}