aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/r8a66597-udc.h
diff options
context:
space:
mode:
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>2009-08-19 00:59:39 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-19 21:25:30 -0400
commitc41442474a26984abaa094e96e42182868eab658 (patch)
tree729f53db686fe5539f07e9aec623936e686f8ab9 /drivers/usb/gadget/r8a66597-udc.h
parent24d76195d124986b7702821b8b6cc85942b13146 (diff)
usb: gadget: R8A66597 peripheral controller support.
While in-tree support for the R8A66597 host side has been supported for some time, the peripheral side has so far been unsupported. This adds a new USB gadget driver which bridges the gap and finally wires up the peripheral side as well. Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Tested-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/usb/gadget/r8a66597-udc.h')
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h249
1 files changed, 249 insertions, 0 deletions
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
new file mode 100644
index 000000000000..a2464bf337c8
--- /dev/null
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -0,0 +1,249 @@
1/*
2 * R8A66597 UDC
3 *
4 * Copyright (C) 2007-2009 Renesas Solutions Corp.
5 *
6 * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 */
22
23#ifndef __R8A66597_H__
24#define __R8A66597_H__
25
26#include <linux/usb/r8a66597.h>
27
28#define R8A66597_MAX_SAMPLING 10
29
30#define R8A66597_MAX_NUM_PIPE 8
31#define R8A66597_MAX_NUM_BULK 3
32#define R8A66597_MAX_NUM_ISOC 2
33#define R8A66597_MAX_NUM_INT 2
34
35#define R8A66597_BASE_PIPENUM_BULK 3
36#define R8A66597_BASE_PIPENUM_ISOC 1
37#define R8A66597_BASE_PIPENUM_INT 6
38
39#define R8A66597_BASE_BUFNUM 6
40#define R8A66597_MAX_BUFNUM 0x4F
41
42#define is_bulk_pipe(pipenum) \
43 ((pipenum >= R8A66597_BASE_PIPENUM_BULK) && \
44 (pipenum < (R8A66597_BASE_PIPENUM_BULK + R8A66597_MAX_NUM_BULK)))
45#define is_interrupt_pipe(pipenum) \
46 ((pipenum >= R8A66597_BASE_PIPENUM_INT) && \
47 (pipenum < (R8A66597_BASE_PIPENUM_INT + R8A66597_MAX_NUM_INT)))
48#define is_isoc_pipe(pipenum) \
49 ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \
50 (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC)))
51
52struct r8a66597_pipe_info {
53 u16 pipe;
54 u16 epnum;
55 u16 maxpacket;
56 u16 type;
57 u16 interval;
58 u16 dir_in;
59};
60
61struct r8a66597_request {
62 struct usb_request req;
63 struct list_head queue;
64};
65
66struct r8a66597_ep {
67 struct usb_ep ep;
68 struct r8a66597 *r8a66597;
69
70 struct list_head queue;
71 unsigned busy:1;
72 unsigned internal_ccpl:1; /* use only control */
73
74 /* this member can able to after r8a66597_enable */
75 unsigned use_dma:1;
76 u16 pipenum;
77 u16 type;
78 const struct usb_endpoint_descriptor *desc;
79 /* register address */
80 unsigned char fifoaddr;
81 unsigned char fifosel;
82 unsigned char fifoctr;
83 unsigned char fifotrn;
84 unsigned char pipectr;
85};
86
87struct r8a66597 {
88 spinlock_t lock;
89 unsigned long reg;
90
91 struct r8a66597_platdata *pdata;
92
93 struct usb_gadget gadget;
94 struct usb_gadget_driver *driver;
95
96 struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE];
97 struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE];
98 struct r8a66597_ep *epaddr2ep[16];
99
100 struct timer_list timer;
101 struct usb_request *ep0_req; /* for internal request */
102 u16 ep0_data; /* for internal request */
103 u16 old_vbus;
104 u16 scount;
105 u16 old_dvsq;
106
107 /* pipe config */
108 unsigned short bi_bufnum; /* bulk and isochronous's bufnum */
109 unsigned char bulk;
110 unsigned char interrupt;
111 unsigned char isochronous;
112 unsigned char num_dma;
113
114 unsigned irq_sense_low:1;
115};
116
117#define gadget_to_r8a66597(_gadget) \
118 container_of(_gadget, struct r8a66597, gadget)
119#define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget)
120
121static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
122{
123 return inw(r8a66597->reg + offset);
124}
125
126static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
127 unsigned long offset, u16 *buf,
128 int len)
129{
130 if (r8a66597->pdata->on_chip) {
131 unsigned long fifoaddr = r8a66597->reg + offset;
132 unsigned long count;
133 union {
134 unsigned long dword;
135 unsigned char byte[4];
136 } data;
137 unsigned char *pb;
138 int i;
139
140 count = len / 4;
141 insl(fifoaddr, buf, count);
142
143 if (len & 0x00000003) {
144 data.dword = inl(fifoaddr);
145 pb = (unsigned char *)buf + count * 4;
146 for (i = 0; i < (len & 0x00000003); i++)
147 pb[i] = data.byte[i];
148 }
149 } else {
150 len = (len + 1) / 2;
151 insw(r8a66597->reg + offset, buf, len);
152 }
153}
154
155static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
156 unsigned long offset)
157{
158 outw(val, r8a66597->reg + offset);
159}
160
161static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
162 unsigned long offset, u16 *buf,
163 int len)
164{
165 unsigned long fifoaddr = r8a66597->reg + offset;
166
167 if (r8a66597->pdata->on_chip) {
168 unsigned long count;
169 unsigned char *pb;
170 int i;
171
172 count = len / 4;
173 outsl(fifoaddr, buf, count);
174
175 if (len & 0x00000003) {
176 pb = (unsigned char *)buf + count * 4;
177 for (i = 0; i < (len & 0x00000003); i++) {
178 if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
179 outb(pb[i], fifoaddr + i);
180 else
181 outb(pb[i], fifoaddr + 3 - i);
182 }
183 }
184 } else {
185 int odd = len & 0x0001;
186
187 len = len / 2;
188 outsw(fifoaddr, buf, len);
189 if (unlikely(odd)) {
190 buf = &buf[len];
191 outb((unsigned char)*buf, fifoaddr);
192 }
193 }
194}
195
196static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
197 u16 val, u16 pat, unsigned long offset)
198{
199 u16 tmp;
200 tmp = r8a66597_read(r8a66597, offset);
201 tmp = tmp & (~pat);
202 tmp = tmp | val;
203 r8a66597_write(r8a66597, tmp, offset);
204}
205
206static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
207{
208 u16 clock = 0;
209
210 switch (pdata->xtal) {
211 case R8A66597_PLATDATA_XTAL_12MHZ:
212 clock = XTAL12;
213 break;
214 case R8A66597_PLATDATA_XTAL_24MHZ:
215 clock = XTAL24;
216 break;
217 case R8A66597_PLATDATA_XTAL_48MHZ:
218 clock = XTAL48;
219 break;
220 default:
221 printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
222 break;
223 }
224
225 return clock;
226}
227
228#define r8a66597_bclr(r8a66597, val, offset) \
229 r8a66597_mdfy(r8a66597, 0, val, offset)
230#define r8a66597_bset(r8a66597, val, offset) \
231 r8a66597_mdfy(r8a66597, val, 0, offset)
232
233#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
234
235#define enable_irq_ready(r8a66597, pipenum) \
236 enable_pipe_irq(r8a66597, pipenum, BRDYENB)
237#define disable_irq_ready(r8a66597, pipenum) \
238 disable_pipe_irq(r8a66597, pipenum, BRDYENB)
239#define enable_irq_empty(r8a66597, pipenum) \
240 enable_pipe_irq(r8a66597, pipenum, BEMPENB)
241#define disable_irq_empty(r8a66597, pipenum) \
242 disable_pipe_irq(r8a66597, pipenum, BEMPENB)
243#define enable_irq_nrdy(r8a66597, pipenum) \
244 enable_pipe_irq(r8a66597, pipenum, NRDYENB)
245#define disable_irq_nrdy(r8a66597, pipenum) \
246 disable_pipe_irq(r8a66597, pipenum, NRDYENB)
247
248#endif /* __R8A66597_H__ */
249