088bfd787e4a069e7cf05bfcde86df861c80276a
[pandora-kernel.git] / drivers / usb / renesas_usbhs / fifo.c
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  *              packet info function
24  */
25 void usbhs_pkt_init(struct usbhs_pkt *pkt)
26 {
27         INIT_LIST_HEAD(&pkt->node);
28 }
29
30 void usbhs_pkt_update(struct usbhs_pkt *pkt, void *buf, int len)
31 {
32         pkt->buf        = buf;
33         pkt->length     = len;
34         pkt->actual     = 0;
35         pkt->maxp       = 0;
36 }
37
38 void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
39 {
40         list_del_init(&pkt->node);
41         list_add_tail(&pkt->node, &pipe->list);
42
43         pkt->pipe = pipe;
44 }
45
46 void usbhs_pkt_pop(struct usbhs_pkt *pkt)
47 {
48         list_del_init(&pkt->node);
49 }
50
51 struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe)
52 {
53         if (list_empty(&pipe->list))
54                 return NULL;
55
56         return list_entry(pipe->list.next, struct usbhs_pkt, node);
57 }
58
59 /*
60  *              FIFO ctrl
61  */
62 static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
63 {
64         struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
65
66         usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
67 }
68
69 static int usbhsf_fifo_barrier(struct usbhs_priv *priv)
70 {
71         int timeout = 1024;
72
73         do {
74                 /* The FIFO port is accessible */
75                 if (usbhs_read(priv, CFIFOCTR) & FRDY)
76                         return 0;
77
78                 udelay(10);
79         } while (timeout--);
80
81         return -EBUSY;
82 }
83
84 static void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
85 {
86         struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
87
88         if (!usbhs_pipe_is_dcp(pipe))
89                 usbhsf_fifo_barrier(priv);
90
91         usbhs_write(priv, CFIFOCTR, BCLR);
92 }
93
94 static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
95 {
96         return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
97 }
98
99 static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
100 {
101         struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
102         struct device *dev = usbhs_priv_to_dev(priv);
103         int timeout = 1024;
104         u16 mask = ((1 << 5) | 0xF);            /* mask of ISEL | CURPIPE */
105         u16 base = usbhs_pipe_number(pipe);     /* CURPIPE */
106
107         if (usbhs_pipe_is_dcp(pipe))
108                 base |= (1 == write) << 5;      /* ISEL */
109
110         /* "base" will be used below  */
111         usbhs_write(priv, CFIFOSEL, base | MBW_32);
112
113         /* check ISEL and CURPIPE value */
114         while (timeout--) {
115                 if (base == (mask & usbhs_read(priv, CFIFOSEL)))
116                         return 0;
117                 udelay(10);
118         }
119
120         dev_err(dev, "fifo select error\n");
121
122         return -EIO;
123 }
124
125 /*
126  *              PIO fifo functions
127  */
128 int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
129 {
130         return usbhsf_fifo_select(pipe, 1);
131 }
132
133 int usbhs_fifo_write(struct usbhs_pkt *pkt)
134 {
135         struct usbhs_pipe *pipe = pkt->pipe;
136         struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
137         struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
138         void __iomem *addr = priv->base + CFIFO;
139         int maxp = usbhs_pipe_get_maxpacket(pipe);
140         int total_len;
141         u8 *buf = pkt->buf;
142         int i, ret, len;
143
144         ret = usbhs_pipe_is_accessible(pipe);
145         if (ret < 0)
146                 return ret;
147
148         ret = usbhsf_fifo_select(pipe, 1);
149         if (ret < 0)
150                 return ret;
151
152         ret = usbhsf_fifo_barrier(priv);
153         if (ret < 0)
154                 return ret;
155
156         len = min(pkt->length, maxp);
157         total_len = len;
158
159         /*
160          * FIXME
161          *
162          * 32-bit access only
163          */
164         if (len >= 4 &&
165             !((unsigned long)buf & 0x03)) {
166                 iowrite32_rep(addr, buf, len / 4);
167                 len %= 4;
168                 buf += total_len - len;
169         }
170
171         /* the rest operation */
172         for (i = 0; i < len; i++)
173                 iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
174
175         if (total_len < maxp)
176                 usbhsf_send_terminator(pipe);
177
178         usbhs_pipe_enable(pipe);
179
180         /* update pkt */
181         if (info->tx_done) {
182                 pkt->actual     = total_len;
183                 pkt->maxp       = maxp;
184                 info->tx_done(pkt);
185         }
186
187         return 0;
188 }
189
190 int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
191 {
192         int ret;
193
194         /*
195          * select pipe and enable it to prepare packet receive
196          */
197         ret = usbhsf_fifo_select(pipe, 0);
198         if (ret < 0)
199                 return ret;
200
201         usbhs_pipe_enable(pipe);
202
203         return ret;
204 }
205
206 int usbhs_fifo_read(struct usbhs_pkt *pkt)
207 {
208         struct usbhs_pipe *pipe = pkt->pipe;
209         struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
210         struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
211         void __iomem *addr = priv->base + CFIFO;
212         u8 *buf = pkt->buf;
213         int rcv_len, len;
214         int i, ret;
215         int total_len = 0;
216         u32 data = 0;
217
218         ret = usbhsf_fifo_select(pipe, 0);
219         if (ret < 0)
220                 return ret;
221
222         ret = usbhsf_fifo_barrier(priv);
223         if (ret < 0)
224                 return ret;
225
226         rcv_len = usbhsf_fifo_rcv_len(priv);
227
228         /*
229          * Buffer clear if Zero-Length packet
230          *
231          * see
232          * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
233          */
234         if (0 == rcv_len) {
235                 usbhsf_fifo_clear(pipe);
236                 goto usbhs_fifo_read_end;
237         }
238
239         len = min(rcv_len, pkt->length);
240         total_len = len;
241
242         /*
243          * FIXME
244          *
245          * 32-bit access only
246          */
247         if (len >= 4 &&
248             !((unsigned long)buf & 0x03)) {
249                 ioread32_rep(addr, buf, len / 4);
250                 len %= 4;
251                 buf += rcv_len - len;
252         }
253
254         /* the rest operation */
255         for (i = 0; i < len; i++) {
256                 if (!(i & 0x03))
257                         data = ioread32(addr);
258
259                 buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
260         }
261
262 usbhs_fifo_read_end:
263         if (info->rx_done) {
264                 /* update pkt */
265                 pkt->actual     = total_len;
266                 pkt->maxp       = usbhs_pipe_get_maxpacket(pipe);
267                 info->rx_done(pkt);
268         }
269
270         return 0;
271 }