Commit 64cfd3f9645bebdadd4c867db5efcf8b7a568f77
Committed by
Marek Vasut
1 parent
e82a316d7f
Exists in
master
and in
53 other branches
usb: gadget: add Faraday FOTG210 USB gadget support
The Faraday FOTG210 is an OTG chip which could operate as either an EHCI Host or a USB Device at a time. Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com> CC: Marek Vasut <marex@denx.de>
Showing 3 changed files with 957 additions and 0 deletions Inline Diff
drivers/usb/gadget/Makefile
1 | # | 1 | # |
2 | # (C) Copyright 2000-2007 | 2 | # (C) Copyright 2000-2007 |
3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. | 3 | # Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
4 | # | 4 | # |
5 | # See file CREDITS for list of people who contributed to this | 5 | # See file CREDITS for list of people who contributed to this |
6 | # project. | 6 | # project. |
7 | # | 7 | # |
8 | # This program is free software; you can redistribute it and/or | 8 | # This program is free software; you can redistribute it and/or |
9 | # modify it under the terms of the GNU General Public License as | 9 | # modify it under the terms of the GNU General Public License as |
10 | # published by the Free Software Foundation; either version 2 of | 10 | # published by the Free Software Foundation; either version 2 of |
11 | # the License, or (at your option) any later version. | 11 | # the License, or (at your option) any later version. |
12 | # | 12 | # |
13 | # This program is distributed in the hope that it will be useful, | 13 | # This program is distributed in the hope that it will be useful, |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | # GNU General Public License for more details. | 16 | # GNU General Public License for more details. |
17 | # | 17 | # |
18 | # You should have received a copy of the GNU General Public License | 18 | # You should have received a copy of the GNU General Public License |
19 | # along with this program; if not, write to the Free Software | 19 | # along with this program; if not, write to the Free Software |
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
21 | # MA 02111-1307 USA | 21 | # MA 02111-1307 USA |
22 | # | 22 | # |
23 | 23 | ||
24 | include $(TOPDIR)/config.mk | 24 | include $(TOPDIR)/config.mk |
25 | 25 | ||
26 | LIB := $(obj)libusb_gadget.o | 26 | LIB := $(obj)libusb_gadget.o |
27 | 27 | ||
28 | # if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER) | 28 | # if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER) |
29 | # Everytime you forget how crufty makefiles can get things like | 29 | # Everytime you forget how crufty makefiles can get things like |
30 | # this remind you... | 30 | # this remind you... |
31 | ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER)) | 31 | ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER)) |
32 | COBJS-y += epautoconf.o config.o usbstring.o | 32 | COBJS-y += epautoconf.o config.o usbstring.o |
33 | endif | 33 | endif |
34 | 34 | ||
35 | # new USB gadget layer dependencies | 35 | # new USB gadget layer dependencies |
36 | ifdef CONFIG_USB_GADGET | 36 | ifdef CONFIG_USB_GADGET |
37 | COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o | 37 | COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o |
38 | COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o | ||
38 | COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o | 39 | COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o |
39 | COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o | 40 | COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o |
40 | endif | 41 | endif |
41 | ifdef CONFIG_USB_ETHER | 42 | ifdef CONFIG_USB_ETHER |
42 | COBJS-y += ether.o | 43 | COBJS-y += ether.o |
43 | COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o | 44 | COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o |
44 | COBJS-$(CONFIG_MV_UDC) += mv_udc.o | 45 | COBJS-$(CONFIG_MV_UDC) += mv_udc.o |
45 | COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o | 46 | COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o |
46 | else | 47 | else |
47 | # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE | 48 | # Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE |
48 | ifdef CONFIG_USB_DEVICE | 49 | ifdef CONFIG_USB_DEVICE |
49 | COBJS-y += core.o | 50 | COBJS-y += core.o |
50 | COBJS-y += ep0.o | 51 | COBJS-y += ep0.o |
51 | COBJS-$(CONFIG_DW_UDC) += designware_udc.o | 52 | COBJS-$(CONFIG_DW_UDC) += designware_udc.o |
52 | COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o | 53 | COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o |
53 | COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o | 54 | COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o |
54 | COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o | 55 | COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o |
55 | COBJS-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o | 56 | COBJS-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o |
56 | endif | 57 | endif |
57 | endif | 58 | endif |
58 | 59 | ||
59 | COBJS := $(COBJS-y) | 60 | COBJS := $(COBJS-y) |
60 | SRCS := $(COBJS:.o=.c) | 61 | SRCS := $(COBJS:.o=.c) |
61 | OBJS := $(addprefix $(obj),$(COBJS)) | 62 | OBJS := $(addprefix $(obj),$(COBJS)) |
62 | 63 | ||
63 | all: $(LIB) | 64 | all: $(LIB) |
64 | 65 | ||
65 | $(LIB): $(obj).depend $(OBJS) | 66 | $(LIB): $(obj).depend $(OBJS) |
66 | $(call cmd_link_o_target, $(OBJS)) | 67 | $(call cmd_link_o_target, $(OBJS)) |
67 | 68 | ||
68 | ######################################################################### | 69 | ######################################################################### |
69 | 70 | ||
70 | # defines $(obj).depend target | 71 | # defines $(obj).depend target |
71 | include $(SRCTREE)/rules.mk | 72 | include $(SRCTREE)/rules.mk |
72 | 73 | ||
73 | sinclude $(obj).depend | 74 | sinclude $(obj).depend |
74 | 75 | ||
75 | ######################################################################### | 76 | ######################################################################### |
76 | 77 |
drivers/usb/gadget/fotg210.c
File was created | 1 | /* | |
2 | * Faraday USB 2.0 OTG Controller | ||
3 | * | ||
4 | * (C) Copyright 2010 Faraday Technology | ||
5 | * Dante Su <dantesu@faraday-tech.com> | ||
6 | * | ||
7 | * This file is released under the terms of GPL v2 and any later version. | ||
8 | * See the file COPYING in the root directory of the source tree for details. | ||
9 | */ | ||
10 | |||
11 | #include <common.h> | ||
12 | #include <command.h> | ||
13 | #include <config.h> | ||
14 | #include <net.h> | ||
15 | #include <malloc.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/errno.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/usb/ch9.h> | ||
20 | #include <linux/usb/gadget.h> | ||
21 | |||
22 | #include <usb/fotg210.h> | ||
23 | |||
24 | #define CFG_NUM_ENDPOINTS 4 | ||
25 | #define CFG_EP0_MAX_PACKET_SIZE 64 | ||
26 | #define CFG_EPX_MAX_PACKET_SIZE 512 | ||
27 | |||
28 | #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ | ||
29 | |||
30 | struct fotg210_chip; | ||
31 | |||
32 | struct fotg210_ep { | ||
33 | struct usb_ep ep; | ||
34 | |||
35 | uint maxpacket; | ||
36 | uint id; | ||
37 | uint stopped; | ||
38 | |||
39 | struct list_head queue; | ||
40 | struct fotg210_chip *chip; | ||
41 | const struct usb_endpoint_descriptor *desc; | ||
42 | }; | ||
43 | |||
44 | struct fotg210_request { | ||
45 | struct usb_request req; | ||
46 | struct list_head queue; | ||
47 | struct fotg210_ep *ep; | ||
48 | }; | ||
49 | |||
50 | struct fotg210_chip { | ||
51 | struct usb_gadget gadget; | ||
52 | struct usb_gadget_driver *driver; | ||
53 | struct fotg210_regs *regs; | ||
54 | uint8_t irq; | ||
55 | uint16_t addr; | ||
56 | int pullup; | ||
57 | enum usb_device_state state; | ||
58 | struct fotg210_ep ep[1 + CFG_NUM_ENDPOINTS]; | ||
59 | }; | ||
60 | |||
61 | static struct usb_endpoint_descriptor ep0_desc = { | ||
62 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
63 | .bDescriptorType = USB_DT_ENDPOINT, | ||
64 | .bEndpointAddress = USB_DIR_IN, | ||
65 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | ||
66 | }; | ||
67 | |||
68 | static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in) | ||
69 | { | ||
70 | return (id < 0) ? 0 : ((id & 0x03) + 1); | ||
71 | } | ||
72 | |||
73 | static inline int ep_to_fifo(struct fotg210_chip *chip, int id) | ||
74 | { | ||
75 | return (id <= 0) ? -1 : ((id - 1) & 0x03); | ||
76 | } | ||
77 | |||
78 | static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr) | ||
79 | { | ||
80 | int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK; | ||
81 | struct fotg210_regs *regs = chip->regs; | ||
82 | |||
83 | if (ep_addr & USB_DIR_IN) { | ||
84 | /* reset endpoint */ | ||
85 | setbits_le32(®s->iep[ep - 1], IEP_RESET); | ||
86 | mdelay(1); | ||
87 | clrbits_le32(®s->iep[ep - 1], IEP_RESET); | ||
88 | /* clear endpoint stall */ | ||
89 | clrbits_le32(®s->iep[ep - 1], IEP_STALL); | ||
90 | } else { | ||
91 | /* reset endpoint */ | ||
92 | setbits_le32(®s->oep[ep - 1], OEP_RESET); | ||
93 | mdelay(1); | ||
94 | clrbits_le32(®s->oep[ep - 1], OEP_RESET); | ||
95 | /* clear endpoint stall */ | ||
96 | clrbits_le32(®s->oep[ep - 1], OEP_STALL); | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int fotg210_reset(struct fotg210_chip *chip) | ||
103 | { | ||
104 | struct fotg210_regs *regs = chip->regs; | ||
105 | uint32_t i; | ||
106 | |||
107 | chip->state = USB_STATE_POWERED; | ||
108 | |||
109 | /* chip enable */ | ||
110 | writel(DEVCTRL_EN, ®s->dev_ctrl); | ||
111 | |||
112 | /* device address reset */ | ||
113 | chip->addr = 0; | ||
114 | writel(0, ®s->dev_addr); | ||
115 | |||
116 | /* set idle counter to 7ms */ | ||
117 | writel(7, ®s->idle); | ||
118 | |||
119 | /* disable all interrupts */ | ||
120 | writel(IMR_MASK, ®s->imr); | ||
121 | writel(GIMR_MASK, ®s->gimr); | ||
122 | writel(GIMR0_MASK, ®s->gimr0); | ||
123 | writel(GIMR1_MASK, ®s->gimr1); | ||
124 | writel(GIMR2_MASK, ®s->gimr2); | ||
125 | |||
126 | /* clear interrupts */ | ||
127 | writel(ISR_MASK, ®s->isr); | ||
128 | writel(0, ®s->gisr); | ||
129 | writel(0, ®s->gisr0); | ||
130 | writel(0, ®s->gisr1); | ||
131 | writel(0, ®s->gisr2); | ||
132 | |||
133 | /* chip reset */ | ||
134 | setbits_le32(®s->dev_ctrl, DEVCTRL_RESET); | ||
135 | mdelay(10); | ||
136 | if (readl(®s->dev_ctrl) & DEVCTRL_RESET) { | ||
137 | printf("fotg210: chip reset failed\n"); | ||
138 | return -1; | ||
139 | } | ||
140 | |||
141 | /* CX FIFO reset */ | ||
142 | setbits_le32(®s->cxfifo, CXFIFO_CXFIFOCLR); | ||
143 | mdelay(10); | ||
144 | if (readl(®s->cxfifo) & CXFIFO_CXFIFOCLR) { | ||
145 | printf("fotg210: ep0 fifo reset failed\n"); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | /* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */ | ||
150 | writel(EPMAP14_DEFAULT, ®s->epmap14); | ||
151 | writel(EPMAP58_DEFAULT, ®s->epmap58); | ||
152 | writel(FIFOMAP_DEFAULT, ®s->fifomap); | ||
153 | writel(0, ®s->fifocfg); | ||
154 | for (i = 0; i < 8; ++i) { | ||
155 | writel(CFG_EPX_MAX_PACKET_SIZE, ®s->iep[i]); | ||
156 | writel(CFG_EPX_MAX_PACKET_SIZE, ®s->oep[i]); | ||
157 | } | ||
158 | |||
159 | /* FIFO reset */ | ||
160 | for (i = 0; i < 4; ++i) { | ||
161 | writel(FIFOCSR_RESET, ®s->fifocsr[i]); | ||
162 | mdelay(10); | ||
163 | if (readl(®s->fifocsr[i]) & FIFOCSR_RESET) { | ||
164 | printf("fotg210: fifo%d reset failed\n", i); | ||
165 | return -1; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | /* enable only device interrupt and triggered at level-high */ | ||
170 | writel(IMR_IRQLH | IMR_HOST | IMR_OTG, ®s->imr); | ||
171 | writel(ISR_MASK, ®s->isr); | ||
172 | /* disable EP0 IN/OUT interrupt */ | ||
173 | writel(GIMR0_CXOUT | GIMR0_CXIN, ®s->gimr0); | ||
174 | /* disable EPX IN+SPK+OUT interrupts */ | ||
175 | writel(GIMR1_MASK, ®s->gimr1); | ||
176 | /* disable wakeup+idle+dma+zlp interrupts */ | ||
177 | writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN | ||
178 | | GIMR2_ZLPRX | GIMR2_ZLPTX, ®s->gimr2); | ||
179 | /* enable all group interrupt */ | ||
180 | writel(0, ®s->gimr); | ||
181 | |||
182 | /* suspend delay = 3 ms */ | ||
183 | writel(3, ®s->idle); | ||
184 | |||
185 | /* turn-on device interrupts */ | ||
186 | setbits_le32(®s->dev_ctrl, DEVCTRL_GIRQ_EN); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask) | ||
192 | { | ||
193 | struct fotg210_regs *regs = chip->regs; | ||
194 | int ret = -1; | ||
195 | ulong ts; | ||
196 | |||
197 | for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { | ||
198 | if ((readl(®s->cxfifo) & mask) != mask) | ||
199 | continue; | ||
200 | ret = 0; | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | if (ret) | ||
205 | printf("fotg210: cx/ep0 timeout\n"); | ||
206 | |||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req) | ||
211 | { | ||
212 | struct fotg210_chip *chip = ep->chip; | ||
213 | struct fotg210_regs *regs = chip->regs; | ||
214 | uint32_t tmp, ts; | ||
215 | uint8_t *buf = req->req.buf + req->req.actual; | ||
216 | uint32_t len = req->req.length - req->req.actual; | ||
217 | int fifo = ep_to_fifo(chip, ep->id); | ||
218 | int ret = -EBUSY; | ||
219 | |||
220 | /* 1. init dma buffer */ | ||
221 | if (len > ep->maxpacket) | ||
222 | len = ep->maxpacket; | ||
223 | |||
224 | /* 2. wait for dma ready (hardware) */ | ||
225 | for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { | ||
226 | if (!(readl(®s->dma_ctrl) & DMACTRL_START)) { | ||
227 | ret = 0; | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | if (ret) { | ||
232 | printf("fotg210: dma busy\n"); | ||
233 | req->req.status = ret; | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | /* 3. DMA target setup */ | ||
238 | if (ep->desc->bEndpointAddress & USB_DIR_IN) | ||
239 | flush_dcache_range((ulong)buf, (ulong)buf + len); | ||
240 | else | ||
241 | invalidate_dcache_range((ulong)buf, (ulong)buf + len); | ||
242 | |||
243 | writel(virt_to_phys(buf), ®s->dma_addr); | ||
244 | |||
245 | if (ep->desc->bEndpointAddress & USB_DIR_IN) { | ||
246 | if (ep->id == 0) { | ||
247 | /* Wait until cx/ep0 fifo empty */ | ||
248 | fotg210_cxwait(chip, CXFIFO_CXFIFOE); | ||
249 | writel(DMAFIFO_CX, ®s->dma_fifo); | ||
250 | } else { | ||
251 | /* Wait until epx fifo empty */ | ||
252 | fotg210_cxwait(chip, CXFIFO_FIFOE(fifo)); | ||
253 | writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); | ||
254 | } | ||
255 | writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, ®s->dma_ctrl); | ||
256 | } else { | ||
257 | uint32_t blen; | ||
258 | |||
259 | if (ep->id == 0) { | ||
260 | writel(DMAFIFO_CX, ®s->dma_fifo); | ||
261 | do { | ||
262 | blen = CXFIFO_BYTES(readl(®s->cxfifo)); | ||
263 | } while (blen < len); | ||
264 | } else { | ||
265 | writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); | ||
266 | blen = FIFOCSR_BYTES(readl(®s->fifocsr[fifo])); | ||
267 | } | ||
268 | len = (len < blen) ? len : blen; | ||
269 | writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, ®s->dma_ctrl); | ||
270 | } | ||
271 | |||
272 | /* 4. DMA start */ | ||
273 | setbits_le32(®s->dma_ctrl, DMACTRL_START); | ||
274 | |||
275 | /* 5. DMA wait */ | ||
276 | ret = -EBUSY; | ||
277 | for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { | ||
278 | tmp = readl(®s->gisr2); | ||
279 | /* DMA complete */ | ||
280 | if (tmp & GISR2_DMAFIN) { | ||
281 | ret = 0; | ||
282 | break; | ||
283 | } | ||
284 | /* DMA error */ | ||
285 | if (tmp & GISR2_DMAERR) { | ||
286 | printf("fotg210: dma error\n"); | ||
287 | break; | ||
288 | } | ||
289 | /* resume, suspend, reset */ | ||
290 | if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) { | ||
291 | printf("fotg210: dma reset by host\n"); | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | /* 7. DMA target reset */ | ||
297 | if (ret) | ||
298 | writel(DMACTRL_ABORT | DMACTRL_CLRFF, ®s->dma_ctrl); | ||
299 | |||
300 | writel(0, ®s->gisr2); | ||
301 | writel(0, ®s->dma_fifo); | ||
302 | |||
303 | req->req.status = ret; | ||
304 | if (!ret) | ||
305 | req->req.actual += len; | ||
306 | else | ||
307 | printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret); | ||
308 | |||
309 | return len; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * result of setup packet | ||
314 | */ | ||
315 | #define CX_IDLE 0 | ||
316 | #define CX_FINISH 1 | ||
317 | #define CX_STALL 2 | ||
318 | |||
319 | static void fotg210_setup(struct fotg210_chip *chip) | ||
320 | { | ||
321 | int id, ret = CX_IDLE; | ||
322 | uint32_t tmp[2]; | ||
323 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp; | ||
324 | struct fotg210_regs *regs = chip->regs; | ||
325 | |||
326 | /* | ||
327 | * If this is the first Cx 8 byte command, | ||
328 | * we can now query USB mode (high/full speed; USB 2.0/USB 1.0) | ||
329 | */ | ||
330 | if (chip->state == USB_STATE_POWERED) { | ||
331 | chip->state = USB_STATE_DEFAULT; | ||
332 | if (readl(®s->otgcsr) & OTGCSR_DEV_B) { | ||
333 | /* Mini-B */ | ||
334 | if (readl(®s->dev_ctrl) & DEVCTRL_HS) { | ||
335 | puts("fotg210: HS\n"); | ||
336 | chip->gadget.speed = USB_SPEED_HIGH; | ||
337 | /* SOF mask timer = 1100 ticks */ | ||
338 | writel(SOFMTR_TMR(1100), ®s->sof_mtr); | ||
339 | } else { | ||
340 | puts("fotg210: FS\n"); | ||
341 | chip->gadget.speed = USB_SPEED_FULL; | ||
342 | /* SOF mask timer = 10000 ticks */ | ||
343 | writel(SOFMTR_TMR(10000), ®s->sof_mtr); | ||
344 | } | ||
345 | } else { | ||
346 | printf("fotg210: mini-A?\n"); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* switch data port to ep0 */ | ||
351 | writel(DMAFIFO_CX, ®s->dma_fifo); | ||
352 | /* fetch 8 bytes setup packet */ | ||
353 | tmp[0] = readl(®s->ep0_data); | ||
354 | tmp[1] = readl(®s->ep0_data); | ||
355 | /* release data port */ | ||
356 | writel(0, ®s->dma_fifo); | ||
357 | |||
358 | if (req->bRequestType & USB_DIR_IN) | ||
359 | ep0_desc.bEndpointAddress = USB_DIR_IN; | ||
360 | else | ||
361 | ep0_desc.bEndpointAddress = USB_DIR_OUT; | ||
362 | |||
363 | ret = CX_IDLE; | ||
364 | |||
365 | if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { | ||
366 | switch (req->bRequest) { | ||
367 | case USB_REQ_SET_CONFIGURATION: | ||
368 | debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF); | ||
369 | if (!(req->wValue & 0x00FF)) { | ||
370 | chip->state = USB_STATE_ADDRESS; | ||
371 | writel(chip->addr, ®s->dev_addr); | ||
372 | } else { | ||
373 | chip->state = USB_STATE_CONFIGURED; | ||
374 | writel(chip->addr | DEVADDR_CONF, | ||
375 | ®s->dev_addr); | ||
376 | } | ||
377 | ret = CX_IDLE; | ||
378 | break; | ||
379 | |||
380 | case USB_REQ_SET_ADDRESS: | ||
381 | debug("fotg210: set_addr(0x%04X)\n", req->wValue); | ||
382 | chip->state = USB_STATE_ADDRESS; | ||
383 | chip->addr = req->wValue & DEVADDR_ADDR_MASK; | ||
384 | ret = CX_FINISH; | ||
385 | writel(chip->addr, ®s->dev_addr); | ||
386 | break; | ||
387 | |||
388 | case USB_REQ_CLEAR_FEATURE: | ||
389 | debug("fotg210: clr_feature(%d, %d)\n", | ||
390 | req->bRequestType & 0x03, req->wValue); | ||
391 | switch (req->wValue) { | ||
392 | case 0: /* [Endpoint] halt */ | ||
393 | ep_reset(chip, req->wIndex); | ||
394 | ret = CX_FINISH; | ||
395 | break; | ||
396 | case 1: /* [Device] remote wake-up */ | ||
397 | case 2: /* [Device] test mode */ | ||
398 | default: | ||
399 | ret = CX_STALL; | ||
400 | break; | ||
401 | } | ||
402 | break; | ||
403 | |||
404 | case USB_REQ_SET_FEATURE: | ||
405 | debug("fotg210: set_feature(%d, %d)\n", | ||
406 | req->wValue, req->wIndex & 0xf); | ||
407 | switch (req->wValue) { | ||
408 | case 0: /* Endpoint Halt */ | ||
409 | id = req->wIndex & 0xf; | ||
410 | setbits_le32(®s->iep[id - 1], IEP_STALL); | ||
411 | setbits_le32(®s->oep[id - 1], OEP_STALL); | ||
412 | ret = CX_FINISH; | ||
413 | break; | ||
414 | case 1: /* Remote Wakeup */ | ||
415 | case 2: /* Test Mode */ | ||
416 | default: | ||
417 | ret = CX_STALL; | ||
418 | break; | ||
419 | } | ||
420 | break; | ||
421 | |||
422 | case USB_REQ_GET_STATUS: | ||
423 | debug("fotg210: get_status\n"); | ||
424 | ret = CX_STALL; | ||
425 | break; | ||
426 | |||
427 | case USB_REQ_SET_DESCRIPTOR: | ||
428 | debug("fotg210: set_descriptor\n"); | ||
429 | ret = CX_STALL; | ||
430 | break; | ||
431 | |||
432 | case USB_REQ_SYNCH_FRAME: | ||
433 | debug("fotg210: sync frame\n"); | ||
434 | ret = CX_STALL; | ||
435 | break; | ||
436 | } | ||
437 | } /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */ | ||
438 | |||
439 | if (ret == CX_IDLE && chip->driver->setup) { | ||
440 | if (chip->driver->setup(&chip->gadget, req) < 0) | ||
441 | ret = CX_STALL; | ||
442 | else | ||
443 | ret = CX_FINISH; | ||
444 | } | ||
445 | |||
446 | switch (ret) { | ||
447 | case CX_FINISH: | ||
448 | setbits_le32(®s->cxfifo, CXFIFO_CXFIN); | ||
449 | break; | ||
450 | |||
451 | case CX_STALL: | ||
452 | setbits_le32(®s->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN); | ||
453 | printf("fotg210: cx_stall!\n"); | ||
454 | break; | ||
455 | |||
456 | case CX_IDLE: | ||
457 | debug("fotg210: cx_idle?\n"); | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * fifo - FIFO id | ||
465 | * zlp - zero length packet | ||
466 | */ | ||
467 | static void fotg210_recv(struct fotg210_chip *chip, int ep_id) | ||
468 | { | ||
469 | struct fotg210_regs *regs = chip->regs; | ||
470 | struct fotg210_ep *ep = chip->ep + ep_id; | ||
471 | struct fotg210_request *req; | ||
472 | int len; | ||
473 | |||
474 | if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) { | ||
475 | printf("fotg210: ep%d recv, invalid!\n", ep->id); | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | if (list_empty(&ep->queue)) { | ||
480 | printf("fotg210: ep%d recv, drop!\n", ep->id); | ||
481 | return; | ||
482 | } | ||
483 | |||
484 | req = list_first_entry(&ep->queue, struct fotg210_request, queue); | ||
485 | len = fotg210_dma(ep, req); | ||
486 | if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) { | ||
487 | list_del_init(&req->queue); | ||
488 | if (req->req.complete) | ||
489 | req->req.complete(&ep->ep, &req->req); | ||
490 | } | ||
491 | |||
492 | if (ep->id > 0 && list_empty(&ep->queue)) { | ||
493 | setbits_le32(®s->gimr1, | ||
494 | GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | * USB Gadget Layer | ||
500 | */ | ||
501 | static int fotg210_ep_enable( | ||
502 | struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | ||
503 | { | ||
504 | struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); | ||
505 | struct fotg210_chip *chip = ep->chip; | ||
506 | struct fotg210_regs *regs = chip->regs; | ||
507 | int id = ep_to_fifo(chip, ep->id); | ||
508 | int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; | ||
509 | |||
510 | if (!_ep || !desc | ||
511 | || desc->bDescriptorType != USB_DT_ENDPOINT | ||
512 | || le16_to_cpu(desc->wMaxPacketSize) == 0) { | ||
513 | printf("fotg210: bad ep or descriptor\n"); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | ep->desc = desc; | ||
518 | ep->stopped = 0; | ||
519 | |||
520 | if (in) | ||
521 | setbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_IN)); | ||
522 | |||
523 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
524 | case USB_ENDPOINT_XFER_CONTROL: | ||
525 | return -EINVAL; | ||
526 | |||
527 | case USB_ENDPOINT_XFER_ISOC: | ||
528 | setbits_le32(®s->fifocfg, | ||
529 | FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC)); | ||
530 | break; | ||
531 | |||
532 | case USB_ENDPOINT_XFER_BULK: | ||
533 | setbits_le32(®s->fifocfg, | ||
534 | FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK)); | ||
535 | break; | ||
536 | |||
537 | case USB_ENDPOINT_XFER_INT: | ||
538 | setbits_le32(®s->fifocfg, | ||
539 | FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR)); | ||
540 | break; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static int fotg210_ep_disable(struct usb_ep *_ep) | ||
547 | { | ||
548 | struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); | ||
549 | struct fotg210_chip *chip = ep->chip; | ||
550 | struct fotg210_regs *regs = chip->regs; | ||
551 | int id = ep_to_fifo(chip, ep->id); | ||
552 | |||
553 | ep->desc = NULL; | ||
554 | ep->stopped = 1; | ||
555 | |||
556 | clrbits_le32(®s->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK)); | ||
557 | clrbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK)); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static struct usb_request *fotg210_ep_alloc_request( | ||
563 | struct usb_ep *_ep, gfp_t gfp_flags) | ||
564 | { | ||
565 | struct fotg210_request *req = malloc(sizeof(*req)); | ||
566 | |||
567 | if (req) { | ||
568 | memset(req, 0, sizeof(*req)); | ||
569 | INIT_LIST_HEAD(&req->queue); | ||
570 | } | ||
571 | return &req->req; | ||
572 | } | ||
573 | |||
574 | static void fotg210_ep_free_request( | ||
575 | struct usb_ep *_ep, struct usb_request *_req) | ||
576 | { | ||
577 | struct fotg210_request *req; | ||
578 | |||
579 | req = container_of(_req, struct fotg210_request, req); | ||
580 | free(req); | ||
581 | } | ||
582 | |||
583 | static int fotg210_ep_queue( | ||
584 | struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) | ||
585 | { | ||
586 | struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); | ||
587 | struct fotg210_chip *chip = ep->chip; | ||
588 | struct fotg210_regs *regs = chip->regs; | ||
589 | struct fotg210_request *req; | ||
590 | |||
591 | req = container_of(_req, struct fotg210_request, req); | ||
592 | if (!_req || !_req->complete || !_req->buf | ||
593 | || !list_empty(&req->queue)) { | ||
594 | printf("fotg210: invalid request to ep%d\n", ep->id); | ||
595 | return -EINVAL; | ||
596 | } | ||
597 | |||
598 | if (!chip || chip->state == USB_STATE_SUSPENDED) { | ||
599 | printf("fotg210: request while chip suspended\n"); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | req->req.actual = 0; | ||
604 | req->req.status = -EINPROGRESS; | ||
605 | |||
606 | if (req->req.length == 0) { | ||
607 | req->req.status = 0; | ||
608 | if (req->req.complete) | ||
609 | req->req.complete(&ep->ep, &req->req); | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | if (ep->id == 0) { | ||
614 | do { | ||
615 | int len = fotg210_dma(ep, req); | ||
616 | if (len < ep->ep.maxpacket) | ||
617 | break; | ||
618 | if (ep->desc->bEndpointAddress & USB_DIR_IN) | ||
619 | udelay(100); | ||
620 | } while (req->req.length > req->req.actual); | ||
621 | } else { | ||
622 | if (ep->desc->bEndpointAddress & USB_DIR_IN) { | ||
623 | do { | ||
624 | int len = fotg210_dma(ep, req); | ||
625 | if (len < ep->ep.maxpacket) | ||
626 | break; | ||
627 | } while (req->req.length > req->req.actual); | ||
628 | } else { | ||
629 | list_add_tail(&req->queue, &ep->queue); | ||
630 | clrbits_le32(®s->gimr1, | ||
631 | GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) { | ||
636 | if (req->req.complete) | ||
637 | req->req.complete(&ep->ep, &req->req); | ||
638 | } | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) | ||
644 | { | ||
645 | struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); | ||
646 | struct fotg210_request *req; | ||
647 | |||
648 | /* make sure it's actually queued on this endpoint */ | ||
649 | list_for_each_entry(req, &ep->queue, queue) { | ||
650 | if (&req->req == _req) | ||
651 | break; | ||
652 | } | ||
653 | if (&req->req != _req) | ||
654 | return -EINVAL; | ||
655 | |||
656 | /* remove the request */ | ||
657 | list_del_init(&req->queue); | ||
658 | |||
659 | /* update status & invoke complete callback */ | ||
660 | if (req->req.status == -EINPROGRESS) { | ||
661 | req->req.status = -ECONNRESET; | ||
662 | if (req->req.complete) | ||
663 | req->req.complete(_ep, &req->req); | ||
664 | } | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static int fotg210_ep_halt(struct usb_ep *_ep, int halt) | ||
670 | { | ||
671 | struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); | ||
672 | struct fotg210_chip *chip = ep->chip; | ||
673 | struct fotg210_regs *regs = chip->regs; | ||
674 | int ret = -1; | ||
675 | |||
676 | debug("fotg210: ep%d halt=%d\n", ep->id, halt); | ||
677 | |||
678 | /* Endpoint STALL */ | ||
679 | if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) { | ||
680 | if (halt) { | ||
681 | /* wait until all ep fifo empty */ | ||
682 | fotg210_cxwait(chip, 0xf00); | ||
683 | /* stall */ | ||
684 | if (ep->desc->bEndpointAddress & USB_DIR_IN) { | ||
685 | setbits_le32(®s->iep[ep->id - 1], | ||
686 | IEP_STALL); | ||
687 | } else { | ||
688 | setbits_le32(®s->oep[ep->id - 1], | ||
689 | OEP_STALL); | ||
690 | } | ||
691 | } else { | ||
692 | if (ep->desc->bEndpointAddress & USB_DIR_IN) { | ||
693 | clrbits_le32(®s->iep[ep->id - 1], | ||
694 | IEP_STALL); | ||
695 | } else { | ||
696 | clrbits_le32(®s->oep[ep->id - 1], | ||
697 | OEP_STALL); | ||
698 | } | ||
699 | } | ||
700 | ret = 0; | ||
701 | } | ||
702 | |||
703 | return ret; | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | * activate/deactivate link with host. | ||
708 | */ | ||
709 | static void pullup(struct fotg210_chip *chip, int is_on) | ||
710 | { | ||
711 | struct fotg210_regs *regs = chip->regs; | ||
712 | |||
713 | if (is_on) { | ||
714 | if (!chip->pullup) { | ||
715 | chip->state = USB_STATE_POWERED; | ||
716 | chip->pullup = 1; | ||
717 | /* enable the chip */ | ||
718 | setbits_le32(®s->dev_ctrl, DEVCTRL_EN); | ||
719 | /* clear unplug bit (BIT0) */ | ||
720 | clrbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); | ||
721 | } | ||
722 | } else { | ||
723 | chip->state = USB_STATE_NOTATTACHED; | ||
724 | chip->pullup = 0; | ||
725 | chip->addr = 0; | ||
726 | writel(chip->addr, ®s->dev_addr); | ||
727 | /* set unplug bit (BIT0) */ | ||
728 | setbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); | ||
729 | /* disable the chip */ | ||
730 | clrbits_le32(®s->dev_ctrl, DEVCTRL_EN); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | static int fotg210_pullup(struct usb_gadget *_gadget, int is_on) | ||
735 | { | ||
736 | struct fotg210_chip *chip; | ||
737 | |||
738 | chip = container_of(_gadget, struct fotg210_chip, gadget); | ||
739 | |||
740 | debug("fotg210: pullup=%d\n", is_on); | ||
741 | |||
742 | pullup(chip, is_on); | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static int fotg210_get_frame(struct usb_gadget *_gadget) | ||
748 | { | ||
749 | struct fotg210_chip *chip; | ||
750 | struct fotg210_regs *regs; | ||
751 | |||
752 | chip = container_of(_gadget, struct fotg210_chip, gadget); | ||
753 | regs = chip->regs; | ||
754 | |||
755 | return SOFFNR_FNR(readl(®s->sof_fnr)); | ||
756 | } | ||
757 | |||
758 | static struct usb_gadget_ops fotg210_gadget_ops = { | ||
759 | .get_frame = fotg210_get_frame, | ||
760 | .pullup = fotg210_pullup, | ||
761 | }; | ||
762 | |||
763 | static struct usb_ep_ops fotg210_ep_ops = { | ||
764 | .enable = fotg210_ep_enable, | ||
765 | .disable = fotg210_ep_disable, | ||
766 | .queue = fotg210_ep_queue, | ||
767 | .dequeue = fotg210_ep_dequeue, | ||
768 | .set_halt = fotg210_ep_halt, | ||
769 | .alloc_request = fotg210_ep_alloc_request, | ||
770 | .free_request = fotg210_ep_free_request, | ||
771 | }; | ||
772 | |||
773 | static struct fotg210_chip controller = { | ||
774 | .regs = (void __iomem *)CONFIG_FOTG210_BASE, | ||
775 | .gadget = { | ||
776 | .name = "fotg210_udc", | ||
777 | .ops = &fotg210_gadget_ops, | ||
778 | .ep0 = &controller.ep[0].ep, | ||
779 | .speed = USB_SPEED_UNKNOWN, | ||
780 | .is_dualspeed = 1, | ||
781 | .is_otg = 0, | ||
782 | .is_a_peripheral = 0, | ||
783 | .b_hnp_enable = 0, | ||
784 | .a_hnp_support = 0, | ||
785 | .a_alt_hnp_support = 0, | ||
786 | }, | ||
787 | .ep[0] = { | ||
788 | .id = 0, | ||
789 | .ep = { | ||
790 | .name = "ep0", | ||
791 | .ops = &fotg210_ep_ops, | ||
792 | }, | ||
793 | .desc = &ep0_desc, | ||
794 | .chip = &controller, | ||
795 | .maxpacket = CFG_EP0_MAX_PACKET_SIZE, | ||
796 | }, | ||
797 | .ep[1] = { | ||
798 | .id = 1, | ||
799 | .ep = { | ||
800 | .name = "ep1", | ||
801 | .ops = &fotg210_ep_ops, | ||
802 | }, | ||
803 | .chip = &controller, | ||
804 | .maxpacket = CFG_EPX_MAX_PACKET_SIZE, | ||
805 | }, | ||
806 | .ep[2] = { | ||
807 | .id = 2, | ||
808 | .ep = { | ||
809 | .name = "ep2", | ||
810 | .ops = &fotg210_ep_ops, | ||
811 | }, | ||
812 | .chip = &controller, | ||
813 | .maxpacket = CFG_EPX_MAX_PACKET_SIZE, | ||
814 | }, | ||
815 | .ep[3] = { | ||
816 | .id = 3, | ||
817 | .ep = { | ||
818 | .name = "ep3", | ||
819 | .ops = &fotg210_ep_ops, | ||
820 | }, | ||
821 | .chip = &controller, | ||
822 | .maxpacket = CFG_EPX_MAX_PACKET_SIZE, | ||
823 | }, | ||
824 | .ep[4] = { | ||
825 | .id = 4, | ||
826 | .ep = { | ||
827 | .name = "ep4", | ||
828 | .ops = &fotg210_ep_ops, | ||
829 | }, | ||
830 | .chip = &controller, | ||
831 | .maxpacket = CFG_EPX_MAX_PACKET_SIZE, | ||
832 | }, | ||
833 | }; | ||
834 | |||
835 | int usb_gadget_handle_interrupts(void) | ||
836 | { | ||
837 | struct fotg210_chip *chip = &controller; | ||
838 | struct fotg210_regs *regs = chip->regs; | ||
839 | uint32_t id, st, isr, gisr; | ||
840 | |||
841 | isr = readl(®s->isr) & (~readl(®s->imr)); | ||
842 | gisr = readl(®s->gisr) & (~readl(®s->gimr)); | ||
843 | if (!(isr & ISR_DEV) || !gisr) | ||
844 | return 0; | ||
845 | |||
846 | writel(ISR_DEV, ®s->isr); | ||
847 | |||
848 | /* CX interrupts */ | ||
849 | if (gisr & GISR_GRP0) { | ||
850 | st = readl(®s->gisr0); | ||
851 | writel(0, ®s->gisr0); | ||
852 | |||
853 | if (st & GISR0_CXERR) | ||
854 | printf("fotg210: cmd error\n"); | ||
855 | |||
856 | if (st & GISR0_CXABORT) | ||
857 | printf("fotg210: cmd abort\n"); | ||
858 | |||
859 | if (st & GISR0_CXSETUP) /* setup */ | ||
860 | fotg210_setup(chip); | ||
861 | else if (st & GISR0_CXEND) /* command finish */ | ||
862 | setbits_le32(®s->cxfifo, CXFIFO_CXFIN); | ||
863 | } | ||
864 | |||
865 | /* FIFO interrupts */ | ||
866 | if (gisr & GISR_GRP1) { | ||
867 | st = readl(®s->gisr1); | ||
868 | for (id = 0; id < 4; ++id) { | ||
869 | if (st & GISR1_RX_FIFO(id)) | ||
870 | fotg210_recv(chip, fifo_to_ep(chip, id, 0)); | ||
871 | } | ||
872 | } | ||
873 | |||
874 | /* Device Status Interrupts */ | ||
875 | if (gisr & GISR_GRP2) { | ||
876 | st = readl(®s->gisr2); | ||
877 | writel(0, ®s->gisr2); | ||
878 | |||
879 | if (st & GISR2_RESET) | ||
880 | printf("fotg210: reset by host\n"); | ||
881 | else if (st & GISR2_SUSPEND) | ||
882 | printf("fotg210: suspend/removed\n"); | ||
883 | else if (st & GISR2_RESUME) | ||
884 | printf("fotg210: resume\n"); | ||
885 | |||
886 | /* Errors */ | ||
887 | if (st & GISR2_ISOCERR) | ||
888 | printf("fotg210: iso error\n"); | ||
889 | if (st & GISR2_ISOCABT) | ||
890 | printf("fotg210: iso abort\n"); | ||
891 | if (st & GISR2_DMAERR) | ||
892 | printf("fotg210: dma error\n"); | ||
893 | } | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | int usb_gadget_register_driver(struct usb_gadget_driver *driver) | ||
899 | { | ||
900 | int i, ret = 0; | ||
901 | struct fotg210_chip *chip = &controller; | ||
902 | |||
903 | if (!driver || !driver->bind || !driver->setup) { | ||
904 | puts("fotg210: bad parameter.\n"); | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | |||
908 | INIT_LIST_HEAD(&chip->gadget.ep_list); | ||
909 | for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) { | ||
910 | struct fotg210_ep *ep = chip->ep + i; | ||
911 | |||
912 | ep->ep.maxpacket = ep->maxpacket; | ||
913 | INIT_LIST_HEAD(&ep->queue); | ||
914 | |||
915 | if (ep->id == 0) { | ||
916 | ep->stopped = 0; | ||
917 | } else { | ||
918 | ep->stopped = 1; | ||
919 | list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | if (fotg210_reset(chip)) { | ||
924 | puts("fotg210: reset failed.\n"); | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | |||
928 | ret = driver->bind(&chip->gadget); | ||
929 | if (ret) { | ||
930 | debug("fotg210: driver->bind() returned %d\n", ret); | ||
931 | return ret; | ||
932 | } | ||
933 | chip->driver = driver; | ||
934 | |||
935 | return ret; | ||
936 | } | ||
937 | |||
938 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | ||
939 | { | ||
940 | struct fotg210_chip *chip = &controller; | ||
941 | |||
942 | driver->unbind(&chip->gadget); | ||
943 | chip->driver = NULL; | ||
944 | |||
945 | pullup(chip, 0); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 |
drivers/usb/gadget/gadget_chips.h
1 | /* | 1 | /* |
2 | * USB device controllers have lots of quirks. Use these macros in | 2 | * USB device controllers have lots of quirks. Use these macros in |
3 | * gadget drivers or other code that needs to deal with them, and which | 3 | * gadget drivers or other code that needs to deal with them, and which |
4 | * autoconfigures instead of using early binding to the hardware. | 4 | * autoconfigures instead of using early binding to the hardware. |
5 | * | 5 | * |
6 | * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by | 6 | * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by |
7 | * some config file that gets updated as new hardware is supported. | 7 | * some config file that gets updated as new hardware is supported. |
8 | * (And avoiding all runtime comparisons in typical one-choice configs!) | 8 | * (And avoiding all runtime comparisons in typical one-choice configs!) |
9 | * | 9 | * |
10 | * NOTE: some of these controller drivers may not be available yet. | 10 | * NOTE: some of these controller drivers may not be available yet. |
11 | * Some are available on 2.4 kernels; several are available, but not | 11 | * Some are available on 2.4 kernels; several are available, but not |
12 | * yet pushed in the 2.6 mainline tree. | 12 | * yet pushed in the 2.6 mainline tree. |
13 | * | 13 | * |
14 | * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and | 14 | * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and |
15 | * Remy Bohmer <linux@bohmer.net> | 15 | * Remy Bohmer <linux@bohmer.net> |
16 | */ | 16 | */ |
17 | #ifdef CONFIG_USB_GADGET_NET2280 | 17 | #ifdef CONFIG_USB_GADGET_NET2280 |
18 | #define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) | 18 | #define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) |
19 | #else | 19 | #else |
20 | #define gadget_is_net2280(g) 0 | 20 | #define gadget_is_net2280(g) 0 |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | #ifdef CONFIG_USB_GADGET_AMD5536UDC | 23 | #ifdef CONFIG_USB_GADGET_AMD5536UDC |
24 | #define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) | 24 | #define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) |
25 | #else | 25 | #else |
26 | #define gadget_is_amd5536udc(g) 0 | 26 | #define gadget_is_amd5536udc(g) 0 |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #ifdef CONFIG_USB_GADGET_DUMMY_HCD | 29 | #ifdef CONFIG_USB_GADGET_DUMMY_HCD |
30 | #define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) | 30 | #define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) |
31 | #else | 31 | #else |
32 | #define gadget_is_dummy(g) 0 | 32 | #define gadget_is_dummy(g) 0 |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | #ifdef CONFIG_USB_GADGET_PXA2XX | 35 | #ifdef CONFIG_USB_GADGET_PXA2XX |
36 | #define gadget_is_pxa(g) (!strcmp("pxa2xx_udc", (g)->name)) | 36 | #define gadget_is_pxa(g) (!strcmp("pxa2xx_udc", (g)->name)) |
37 | #else | 37 | #else |
38 | #define gadget_is_pxa(g) 0 | 38 | #define gadget_is_pxa(g) 0 |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | #ifdef CONFIG_USB_GADGET_GOKU | 41 | #ifdef CONFIG_USB_GADGET_GOKU |
42 | #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) | 42 | #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) |
43 | #else | 43 | #else |
44 | #define gadget_is_goku(g) 0 | 44 | #define gadget_is_goku(g) 0 |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | /* SH3 UDC -- not yet ported 2.4 --> 2.6 */ | 47 | /* SH3 UDC -- not yet ported 2.4 --> 2.6 */ |
48 | #ifdef CONFIG_USB_GADGET_SUPERH | 48 | #ifdef CONFIG_USB_GADGET_SUPERH |
49 | #define gadget_is_sh(g) (!strcmp("sh_udc", (g)->name)) | 49 | #define gadget_is_sh(g) (!strcmp("sh_udc", (g)->name)) |
50 | #else | 50 | #else |
51 | #define gadget_is_sh(g) 0 | 51 | #define gadget_is_sh(g) 0 |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | /* not yet stable on 2.6 (would help "original Zaurus") */ | 54 | /* not yet stable on 2.6 (would help "original Zaurus") */ |
55 | #ifdef CONFIG_USB_GADGET_SA1100 | 55 | #ifdef CONFIG_USB_GADGET_SA1100 |
56 | #define gadget_is_sa1100(g) (!strcmp("sa1100_udc", (g)->name)) | 56 | #define gadget_is_sa1100(g) (!strcmp("sa1100_udc", (g)->name)) |
57 | #else | 57 | #else |
58 | #define gadget_is_sa1100(g) 0 | 58 | #define gadget_is_sa1100(g) 0 |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | /* handhelds.org tree (?) */ | 61 | /* handhelds.org tree (?) */ |
62 | #ifdef CONFIG_USB_GADGET_MQ11XX | 62 | #ifdef CONFIG_USB_GADGET_MQ11XX |
63 | #define gadget_is_mq11xx(g) (!strcmp("mq11xx_udc", (g)->name)) | 63 | #define gadget_is_mq11xx(g) (!strcmp("mq11xx_udc", (g)->name)) |
64 | #else | 64 | #else |
65 | #define gadget_is_mq11xx(g) 0 | 65 | #define gadget_is_mq11xx(g) 0 |
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | #ifdef CONFIG_USB_GADGET_OMAP | 68 | #ifdef CONFIG_USB_GADGET_OMAP |
69 | #define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) | 69 | #define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) |
70 | #else | 70 | #else |
71 | #define gadget_is_omap(g) 0 | 71 | #define gadget_is_omap(g) 0 |
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | /* not yet ported 2.4 --> 2.6 */ | 74 | /* not yet ported 2.4 --> 2.6 */ |
75 | #ifdef CONFIG_USB_GADGET_N9604 | 75 | #ifdef CONFIG_USB_GADGET_N9604 |
76 | #define gadget_is_n9604(g) (!strcmp("n9604_udc", (g)->name)) | 76 | #define gadget_is_n9604(g) (!strcmp("n9604_udc", (g)->name)) |
77 | #else | 77 | #else |
78 | #define gadget_is_n9604(g) 0 | 78 | #define gadget_is_n9604(g) 0 |
79 | #endif | 79 | #endif |
80 | 80 | ||
81 | /* various unstable versions available */ | 81 | /* various unstable versions available */ |
82 | #ifdef CONFIG_USB_GADGET_PXA27X | 82 | #ifdef CONFIG_USB_GADGET_PXA27X |
83 | #define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) | 83 | #define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) |
84 | #else | 84 | #else |
85 | #define gadget_is_pxa27x(g) 0 | 85 | #define gadget_is_pxa27x(g) 0 |
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | #ifdef CONFIG_USB_GADGET_ATMEL_USBA | 88 | #ifdef CONFIG_USB_GADGET_ATMEL_USBA |
89 | #define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) | 89 | #define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) |
90 | #else | 90 | #else |
91 | #define gadget_is_atmel_usba(g) 0 | 91 | #define gadget_is_atmel_usba(g) 0 |
92 | #endif | 92 | #endif |
93 | 93 | ||
94 | #ifdef CONFIG_USB_GADGET_S3C2410 | 94 | #ifdef CONFIG_USB_GADGET_S3C2410 |
95 | #define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) | 95 | #define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) |
96 | #else | 96 | #else |
97 | #define gadget_is_s3c2410(g) 0 | 97 | #define gadget_is_s3c2410(g) 0 |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | #ifdef CONFIG_USB_GADGET_AT91 | 100 | #ifdef CONFIG_USB_GADGET_AT91 |
101 | #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) | 101 | #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) |
102 | #else | 102 | #else |
103 | #define gadget_is_at91(g) 0 | 103 | #define gadget_is_at91(g) 0 |
104 | #endif | 104 | #endif |
105 | 105 | ||
106 | /* status unclear */ | 106 | /* status unclear */ |
107 | #ifdef CONFIG_USB_GADGET_IMX | 107 | #ifdef CONFIG_USB_GADGET_IMX |
108 | #define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) | 108 | #define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) |
109 | #else | 109 | #else |
110 | #define gadget_is_imx(g) 0 | 110 | #define gadget_is_imx(g) 0 |
111 | #endif | 111 | #endif |
112 | 112 | ||
113 | #ifdef CONFIG_USB_GADGET_FSL_USB2 | 113 | #ifdef CONFIG_USB_GADGET_FSL_USB2 |
114 | #define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) | 114 | #define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) |
115 | #else | 115 | #else |
116 | #define gadget_is_fsl_usb2(g) 0 | 116 | #define gadget_is_fsl_usb2(g) 0 |
117 | #endif | 117 | #endif |
118 | 118 | ||
119 | /* Mentor high speed function controller */ | 119 | /* Mentor high speed function controller */ |
120 | /* from Montavista kernel (?) */ | 120 | /* from Montavista kernel (?) */ |
121 | #ifdef CONFIG_USB_GADGET_MUSBHSFC | 121 | #ifdef CONFIG_USB_GADGET_MUSBHSFC |
122 | #define gadget_is_musbhsfc(g) (!strcmp("musbhsfc_udc", (g)->name)) | 122 | #define gadget_is_musbhsfc(g) (!strcmp("musbhsfc_udc", (g)->name)) |
123 | #else | 123 | #else |
124 | #define gadget_is_musbhsfc(g) 0 | 124 | #define gadget_is_musbhsfc(g) 0 |
125 | #endif | 125 | #endif |
126 | 126 | ||
127 | /* Mentor high speed "dual role" controller, in peripheral role */ | 127 | /* Mentor high speed "dual role" controller, in peripheral role */ |
128 | #ifdef CONFIG_MUSB_GADGET | 128 | #ifdef CONFIG_MUSB_GADGET |
129 | #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) | 129 | #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) |
130 | #else | 130 | #else |
131 | #define gadget_is_musbhdrc(g) 0 | 131 | #define gadget_is_musbhdrc(g) 0 |
132 | #endif | 132 | #endif |
133 | 133 | ||
134 | /* from Montavista kernel (?) */ | 134 | /* from Montavista kernel (?) */ |
135 | #ifdef CONFIG_USB_GADGET_MPC8272 | 135 | #ifdef CONFIG_USB_GADGET_MPC8272 |
136 | #define gadget_is_mpc8272(g) (!strcmp("mpc8272_udc", (g)->name)) | 136 | #define gadget_is_mpc8272(g) (!strcmp("mpc8272_udc", (g)->name)) |
137 | #else | 137 | #else |
138 | #define gadget_is_mpc8272(g) 0 | 138 | #define gadget_is_mpc8272(g) 0 |
139 | #endif | 139 | #endif |
140 | 140 | ||
141 | #ifdef CONFIG_USB_GADGET_M66592 | 141 | #ifdef CONFIG_USB_GADGET_M66592 |
142 | #define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) | 142 | #define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) |
143 | #else | 143 | #else |
144 | #define gadget_is_m66592(g) 0 | 144 | #define gadget_is_m66592(g) 0 |
145 | #endif | 145 | #endif |
146 | 146 | ||
147 | #ifdef CONFIG_USB_GADGET_MV | 147 | #ifdef CONFIG_USB_GADGET_MV |
148 | #define gadget_is_mv(g) (!strcmp("mv_udc", (g)->name)) | 148 | #define gadget_is_mv(g) (!strcmp("mv_udc", (g)->name)) |
149 | #else | 149 | #else |
150 | #define gadget_is_mv(g) 0 | 150 | #define gadget_is_mv(g) 0 |
151 | #endif | 151 | #endif |
152 | 152 | ||
153 | #ifdef CONFIG_USB_GADGET_FOTG210 | ||
154 | #define gadget_is_fotg210(g) (!strcmp("fotg210_udc", (g)->name)) | ||
155 | #else | ||
156 | #define gadget_is_fotg210(g) 0 | ||
157 | #endif | ||
158 | |||
153 | /* | 159 | /* |
154 | * CONFIG_USB_GADGET_SX2 | 160 | * CONFIG_USB_GADGET_SX2 |
155 | * CONFIG_USB_GADGET_AU1X00 | 161 | * CONFIG_USB_GADGET_AU1X00 |
156 | * ... | 162 | * ... |
157 | */ | 163 | */ |
158 | 164 | ||
159 | /** | 165 | /** |
160 | * usb_gadget_controller_number - support bcdDevice id convention | 166 | * usb_gadget_controller_number - support bcdDevice id convention |
161 | * @gadget: the controller being driven | 167 | * @gadget: the controller being driven |
162 | * | 168 | * |
163 | * Return a 2-digit BCD value associated with the peripheral controller, | 169 | * Return a 2-digit BCD value associated with the peripheral controller, |
164 | * suitable for use as part of a bcdDevice value, or a negative error code. | 170 | * suitable for use as part of a bcdDevice value, or a negative error code. |
165 | * | 171 | * |
166 | * NOTE: this convention is purely optional, and has no meaning in terms of | 172 | * NOTE: this convention is purely optional, and has no meaning in terms of |
167 | * any USB specification. If you want to use a different convention in your | 173 | * any USB specification. If you want to use a different convention in your |
168 | * gadget driver firmware -- maybe a more formal revision ID -- feel free. | 174 | * gadget driver firmware -- maybe a more formal revision ID -- feel free. |
169 | * | 175 | * |
170 | * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) | 176 | * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) |
171 | * to change their behavior accordingly. For example it might help avoiding | 177 | * to change their behavior accordingly. For example it might help avoiding |
172 | * some chip bug. | 178 | * some chip bug. |
173 | */ | 179 | */ |
174 | static inline int usb_gadget_controller_number(struct usb_gadget *gadget) | 180 | static inline int usb_gadget_controller_number(struct usb_gadget *gadget) |
175 | { | 181 | { |
176 | if (gadget_is_net2280(gadget)) | 182 | if (gadget_is_net2280(gadget)) |
177 | return 0x01; | 183 | return 0x01; |
178 | else if (gadget_is_dummy(gadget)) | 184 | else if (gadget_is_dummy(gadget)) |
179 | return 0x02; | 185 | return 0x02; |
180 | else if (gadget_is_pxa(gadget)) | 186 | else if (gadget_is_pxa(gadget)) |
181 | return 0x03; | 187 | return 0x03; |
182 | else if (gadget_is_sh(gadget)) | 188 | else if (gadget_is_sh(gadget)) |
183 | return 0x04; | 189 | return 0x04; |
184 | else if (gadget_is_sa1100(gadget)) | 190 | else if (gadget_is_sa1100(gadget)) |
185 | return 0x05; | 191 | return 0x05; |
186 | else if (gadget_is_goku(gadget)) | 192 | else if (gadget_is_goku(gadget)) |
187 | return 0x06; | 193 | return 0x06; |
188 | else if (gadget_is_mq11xx(gadget)) | 194 | else if (gadget_is_mq11xx(gadget)) |
189 | return 0x07; | 195 | return 0x07; |
190 | else if (gadget_is_omap(gadget)) | 196 | else if (gadget_is_omap(gadget)) |
191 | return 0x08; | 197 | return 0x08; |
192 | else if (gadget_is_n9604(gadget)) | 198 | else if (gadget_is_n9604(gadget)) |
193 | return 0x09; | 199 | return 0x09; |
194 | else if (gadget_is_pxa27x(gadget)) | 200 | else if (gadget_is_pxa27x(gadget)) |
195 | return 0x10; | 201 | return 0x10; |
196 | else if (gadget_is_s3c2410(gadget)) | 202 | else if (gadget_is_s3c2410(gadget)) |
197 | return 0x11; | 203 | return 0x11; |
198 | else if (gadget_is_at91(gadget)) | 204 | else if (gadget_is_at91(gadget)) |
199 | return 0x12; | 205 | return 0x12; |
200 | else if (gadget_is_imx(gadget)) | 206 | else if (gadget_is_imx(gadget)) |
201 | return 0x13; | 207 | return 0x13; |
202 | else if (gadget_is_musbhsfc(gadget)) | 208 | else if (gadget_is_musbhsfc(gadget)) |
203 | return 0x14; | 209 | return 0x14; |
204 | else if (gadget_is_musbhdrc(gadget)) | 210 | else if (gadget_is_musbhdrc(gadget)) |
205 | return 0x15; | 211 | return 0x15; |
206 | else if (gadget_is_mpc8272(gadget)) | 212 | else if (gadget_is_mpc8272(gadget)) |
207 | return 0x16; | 213 | return 0x16; |
208 | else if (gadget_is_atmel_usba(gadget)) | 214 | else if (gadget_is_atmel_usba(gadget)) |
209 | return 0x17; | 215 | return 0x17; |
210 | else if (gadget_is_fsl_usb2(gadget)) | 216 | else if (gadget_is_fsl_usb2(gadget)) |
211 | return 0x18; | 217 | return 0x18; |
212 | else if (gadget_is_amd5536udc(gadget)) | 218 | else if (gadget_is_amd5536udc(gadget)) |
213 | return 0x19; | 219 | return 0x19; |
214 | else if (gadget_is_m66592(gadget)) | 220 | else if (gadget_is_m66592(gadget)) |
215 | return 0x20; | 221 | return 0x20; |
216 | else if (gadget_is_mv(gadget)) | 222 | else if (gadget_is_mv(gadget)) |
217 | return 0x21; | 223 | return 0x21; |
224 | else if (gadget_is_fotg210(gadget)) | ||
225 | return 0x22; | ||
218 | return -ENOENT; | 226 | return -ENOENT; |
219 | } | 227 | } |
220 | 228 |