]>
Commit | Line | Data |
---|---|---|
7ed4eac4 JB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | ||
d678a59d | 3 | #include <common.h> |
7ed4eac4 JB |
4 | #include <linux/errno.h> |
5 | #include <linux/delay.h> | |
6 | #include <asm/gpio.h> | |
7 | #include <linux/list.h> | |
8 | #include <linux/bitfield.h> | |
9 | #include <linux/usb/ch9.h> | |
10 | #include <linux/usb/gadget.h> | |
11 | #include <malloc.h> | |
12 | #include <spi.h> | |
13 | #include <dm.h> | |
14 | #include <g_dnl.h> | |
15 | ||
16 | #define MAX3420_MAX_EPS 4 | |
17 | #define EP_MAX_PACKET 64 /* Same for all Endpoints */ | |
18 | #define EPNAME_SIZE 16 /* Buffer size for endpoint name */ | |
19 | ||
20 | #define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */ | |
21 | #define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */ | |
22 | ||
23 | /* SPI commands: */ | |
24 | #define MAX3420_SPI_ACK_MASK BIT(0) | |
25 | #define MAX3420_SPI_DIR_MASK BIT(1) | |
26 | #define MAX3420_SPI_REG_MASK GENMASK(7, 3) | |
27 | ||
28 | #define MAX3420_REG_EP0FIFO 0 | |
29 | #define MAX3420_REG_EP1FIFO 1 | |
30 | #define MAX3420_REG_EP2FIFO 2 | |
31 | #define MAX3420_REG_EP3FIFO 3 | |
32 | #define MAX3420_REG_SUDFIFO 4 | |
33 | #define MAX3420_REG_EP0BC 5 | |
34 | #define MAX3420_REG_EP1BC 6 | |
35 | #define MAX3420_REG_EP2BC 7 | |
36 | #define MAX3420_REG_EP3BC 8 | |
37 | ||
38 | #define MAX3420_REG_EPSTALLS 9 | |
39 | #define bACKSTAT BIT(6) | |
40 | #define bSTLSTAT BIT(5) | |
41 | #define bSTLEP3IN BIT(4) | |
42 | #define bSTLEP2IN BIT(3) | |
43 | #define bSTLEP1OUT BIT(2) | |
44 | #define bSTLEP0OUT BIT(1) | |
45 | #define bSTLEP0IN BIT(0) | |
46 | ||
47 | #define MAX3420_REG_CLRTOGS 10 | |
48 | #define bEP3DISAB BIT(7) | |
49 | #define bEP2DISAB BIT(6) | |
50 | #define bEP1DISAB BIT(5) | |
51 | #define bCTGEP3IN BIT(4) | |
52 | #define bCTGEP2IN BIT(3) | |
53 | #define bCTGEP1OUT BIT(2) | |
54 | ||
55 | #define MAX3420_REG_EPIRQ 11 | |
56 | #define MAX3420_REG_EPIEN 12 | |
57 | #define bSUDAVIRQ BIT(5) | |
58 | #define bIN3BAVIRQ BIT(4) | |
59 | #define bIN2BAVIRQ BIT(3) | |
60 | #define bOUT1DAVIRQ BIT(2) | |
61 | #define bOUT0DAVIRQ BIT(1) | |
62 | #define bIN0BAVIRQ BIT(0) | |
63 | ||
64 | #define MAX3420_REG_USBIRQ 13 | |
65 | #define MAX3420_REG_USBIEN 14 | |
66 | #define bOSCOKIRQ BIT(0) | |
67 | #define bRWUDNIRQ BIT(1) | |
68 | #define bBUSACTIRQ BIT(2) | |
69 | #define bURESIRQ BIT(3) | |
70 | #define bSUSPIRQ BIT(4) | |
71 | #define bNOVBUSIRQ BIT(5) | |
72 | #define bVBUSIRQ BIT(6) | |
73 | #define bURESDNIRQ BIT(7) | |
74 | ||
75 | #define MAX3420_REG_USBCTL 15 | |
76 | #define bHOSCSTEN BIT(7) | |
77 | #define bVBGATE BIT(6) | |
78 | #define bCHIPRES BIT(5) | |
79 | #define bPWRDOWN BIT(4) | |
80 | #define bCONNECT BIT(3) | |
81 | #define bSIGRWU BIT(2) | |
82 | ||
83 | #define MAX3420_REG_CPUCTL 16 | |
84 | #define bIE BIT(0) | |
85 | ||
86 | #define MAX3420_REG_PINCTL 17 | |
87 | #define bEP3INAK BIT(7) | |
88 | #define bEP2INAK BIT(6) | |
89 | #define bEP0INAK BIT(5) | |
90 | #define bFDUPSPI BIT(4) | |
91 | #define bINTLEVEL BIT(3) | |
92 | #define bPOSINT BIT(2) | |
93 | #define bGPXB BIT(1) | |
94 | #define bGPXA BIT(0) | |
95 | ||
96 | #define MAX3420_REG_REVISION 18 | |
97 | ||
98 | #define MAX3420_REG_FNADDR 19 | |
99 | #define FNADDR_MASK 0x7f | |
100 | ||
101 | #define MAX3420_REG_IOPINS 20 | |
102 | #define MAX3420_REG_IOPINS2 21 | |
103 | #define MAX3420_REG_GPINIRQ 22 | |
104 | #define MAX3420_REG_GPINIEN 23 | |
105 | #define MAX3420_REG_GPINPOL 24 | |
106 | #define MAX3420_REG_HIRQ 25 | |
107 | #define MAX3420_REG_HIEN 26 | |
108 | #define MAX3420_REG_MODE 27 | |
109 | #define MAX3420_REG_PERADDR 28 | |
110 | #define MAX3420_REG_HCTL 29 | |
111 | #define MAX3420_REG_HXFR 30 | |
112 | #define MAX3420_REG_HRSL 31 | |
113 | ||
114 | struct max3420_req { | |
115 | struct usb_request usb_req; | |
116 | struct list_head queue; | |
117 | struct max3420_ep *ep; | |
118 | }; | |
119 | ||
120 | struct max3420_ep { | |
121 | struct max3420_udc *udc; | |
122 | struct list_head queue; | |
123 | char name[EPNAME_SIZE]; | |
124 | unsigned int maxpacket; | |
125 | struct usb_ep ep_usb; | |
126 | int halted; | |
127 | int id; | |
128 | }; | |
129 | ||
130 | struct max3420_udc { | |
131 | struct max3420_ep ep[MAX3420_MAX_EPS]; | |
132 | struct usb_gadget_driver *driver; | |
133 | bool softconnect; | |
134 | struct usb_ctrlrequest setup; | |
135 | struct max3420_req ep0req; | |
136 | struct usb_gadget gadget; | |
137 | struct spi_slave *slave; | |
138 | struct udevice *dev; | |
139 | u8 ep0buf[64]; | |
140 | int remote_wkp; | |
141 | bool suspended; | |
142 | }; | |
143 | ||
144 | #define to_max3420_req(r) container_of((r), struct max3420_req, usb_req) | |
145 | #define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb) | |
146 | #define to_udc(g) container_of((g), struct max3420_udc, gadget) | |
147 | ||
148 | static void spi_ack_ctrl(struct max3420_udc *udc) | |
149 | { | |
150 | struct spi_slave *slave = udc->slave; | |
151 | u8 txdata[1]; | |
152 | ||
153 | txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1); | |
154 | spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); | |
155 | } | |
156 | ||
157 | static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat) | |
158 | { | |
159 | struct spi_slave *slave = udc->slave; | |
160 | u8 txdata[2], rxdata[2]; | |
161 | ||
162 | txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | | |
163 | FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) | | |
164 | FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); | |
165 | ||
166 | rxdata[0] = 0; | |
167 | rxdata[1] = 0; | |
168 | spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE); | |
169 | ||
170 | return rxdata[1]; | |
171 | } | |
172 | ||
173 | static u8 spi_rd8(struct max3420_udc *udc, u8 reg) | |
174 | { | |
175 | return spi_rd8_ack(udc, reg, 0); | |
176 | } | |
177 | ||
178 | static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat) | |
179 | { | |
180 | struct spi_slave *slave = udc->slave; | |
181 | u8 txdata[2]; | |
182 | ||
183 | txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | | |
184 | FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) | | |
185 | FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); | |
186 | txdata[1] = val; | |
187 | ||
188 | spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); | |
189 | } | |
190 | ||
191 | static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val) | |
192 | { | |
193 | spi_wr8_ack(udc, reg, val, 0); | |
194 | } | |
195 | ||
196 | static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) | |
197 | { | |
198 | struct spi_slave *slave = udc->slave; | |
199 | u8 txdata[1]; | |
200 | ||
201 | txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | | |
202 | FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD); | |
203 | ||
204 | spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); | |
205 | spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END); | |
206 | } | |
207 | ||
208 | static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) | |
209 | { | |
210 | struct spi_slave *slave = udc->slave; | |
211 | u8 txdata[1]; | |
212 | ||
213 | txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | | |
214 | FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR); | |
215 | ||
216 | spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); | |
217 | spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END); | |
218 | } | |
219 | ||
220 | /* 0 if not-connected */ | |
221 | int g_dnl_board_usb_cable_connected(void) | |
222 | { | |
223 | return 1; | |
224 | } | |
225 | ||
226 | static void spi_max3420_enable(struct max3420_ep *ep, int enable) | |
227 | { | |
228 | struct max3420_udc *udc = ep->udc; | |
229 | u8 epdis, epien; | |
230 | ||
231 | if (ep->id == 0) | |
232 | return; | |
233 | ||
234 | epien = spi_rd8(udc, MAX3420_REG_EPIEN); | |
235 | epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS); | |
236 | ||
237 | if (enable) { | |
238 | epdis &= ~BIT(ep->id + 4); | |
239 | epien |= BIT(ep->id + 1); | |
240 | } else { | |
241 | epdis |= BIT(ep->id + 4); | |
242 | epien &= ~BIT(ep->id + 1); | |
243 | } | |
244 | ||
245 | spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis); | |
246 | spi_wr8(udc, MAX3420_REG_EPIEN, epien); | |
247 | } | |
248 | ||
249 | static int | |
250 | max3420_ep_enable(struct usb_ep *_ep, | |
251 | const struct usb_endpoint_descriptor *desc) | |
252 | { | |
253 | struct max3420_ep *ep = to_max3420_ep(_ep); | |
254 | ||
255 | _ep->desc = desc; | |
256 | _ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff; | |
257 | ||
258 | spi_max3420_enable(ep, 1); | |
259 | ||
260 | return 0; | |
261 | } | |
262 | ||
263 | static void max3420_req_done(struct max3420_req *req, int status) | |
264 | { | |
265 | struct max3420_ep *ep = req->ep; | |
266 | ||
267 | if (req->usb_req.status == -EINPROGRESS) | |
268 | req->usb_req.status = status; | |
269 | else | |
270 | status = req->usb_req.status; | |
271 | ||
272 | if (status && status != -ESHUTDOWN) | |
273 | dev_err(ep->udc->dev, "%s done %p, status %d\n", | |
274 | ep->ep_usb.name, req, status); | |
275 | ||
276 | if (req->usb_req.complete) | |
277 | req->usb_req.complete(&ep->ep_usb, &req->usb_req); | |
278 | } | |
279 | ||
280 | static void max3420_ep_nuke(struct max3420_ep *ep, int status) | |
281 | { | |
282 | struct max3420_req *req, *r; | |
283 | ||
284 | list_for_each_entry_safe(req, r, &ep->queue, queue) { | |
285 | list_del_init(&req->queue); | |
286 | max3420_req_done(req, status); | |
287 | } | |
288 | } | |
289 | ||
290 | static int max3420_ep_disable(struct usb_ep *_ep) | |
291 | { | |
292 | struct max3420_ep *ep = to_max3420_ep(_ep); | |
293 | ||
294 | _ep->desc = NULL; | |
295 | max3420_ep_nuke(ep, -ESHUTDOWN); | |
296 | spi_max3420_enable(ep, 0); | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
301 | static struct usb_request * | |
302 | max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) | |
303 | { | |
304 | struct max3420_ep *ep = to_max3420_ep(_ep); | |
305 | struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags); | |
306 | ||
307 | if (!req) | |
308 | return NULL; | |
309 | ||
310 | req->ep = ep; | |
311 | INIT_LIST_HEAD(&req->queue); | |
312 | ||
313 | return &req->usb_req; | |
314 | } | |
315 | ||
316 | static void | |
317 | max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) | |
318 | { | |
319 | kfree(to_max3420_req(_req)); | |
320 | } | |
321 | ||
322 | static int | |
323 | max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) | |
324 | { | |
325 | struct max3420_req *req = to_max3420_req(_req); | |
326 | struct max3420_ep *ep = to_max3420_ep(_ep); | |
327 | ||
328 | _req->status = -EINPROGRESS; | |
329 | _req->actual = 0; | |
330 | list_add_tail(&req->queue, &ep->queue); | |
331 | ||
332 | return 0; | |
333 | } | |
334 | ||
335 | static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) | |
336 | { | |
337 | struct max3420_req *req = to_max3420_req(_req); | |
338 | ||
339 | list_del_init(&req->queue); | |
340 | max3420_req_done(req, -ECONNRESET); | |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
345 | static int max3420_ep_set_halt(struct usb_ep *_ep, int halt) | |
346 | { | |
347 | struct max3420_ep *ep = to_max3420_ep(_ep); | |
348 | struct max3420_udc *udc = ep->udc; | |
349 | u8 epstalls; | |
350 | ||
351 | if (ep->id == 0) /* can't stall EP0 */ | |
352 | return 0; | |
353 | ||
354 | epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS); | |
355 | if (halt) { | |
356 | ep->halted = 1; | |
357 | epstalls |= BIT(ep->id + 1); | |
358 | } else { | |
359 | u8 clrtogs; | |
360 | ||
361 | ep->halted = 0; | |
362 | epstalls &= ~BIT(ep->id + 1); | |
363 | clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS); | |
364 | clrtogs |= BIT(ep->id + 1); | |
365 | spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs); | |
366 | } | |
367 | spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT); | |
368 | ||
369 | return 0; | |
370 | } | |
371 | ||
372 | static const struct usb_ep_ops max3420_ep_ops = { | |
373 | .enable = max3420_ep_enable, | |
374 | .disable = max3420_ep_disable, | |
375 | .alloc_request = max3420_ep_alloc_request, | |
376 | .free_request = max3420_ep_free_request, | |
377 | .queue = max3420_ep_queue, | |
378 | .dequeue = max3420_ep_dequeue, | |
379 | .set_halt = max3420_ep_set_halt, | |
380 | }; | |
381 | ||
382 | static void __max3420_stop(struct max3420_udc *udc) | |
383 | { | |
384 | u8 val; | |
385 | ||
386 | /* Disable IRQ to CPU */ | |
387 | spi_wr8(udc, MAX3420_REG_CPUCTL, 0); | |
388 | ||
389 | val = spi_rd8(udc, MAX3420_REG_USBCTL); | |
390 | val |= bPWRDOWN; | |
391 | val |= bHOSCSTEN; | |
392 | spi_wr8(udc, MAX3420_REG_USBCTL, val); | |
393 | } | |
394 | ||
395 | static void __max3420_start(struct max3420_udc *udc) | |
396 | { | |
397 | u8 val; | |
398 | ||
399 | /* configure SPI */ | |
400 | spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); | |
401 | ||
402 | /* Chip Reset */ | |
403 | spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES); | |
404 | mdelay(5); | |
405 | spi_wr8(udc, MAX3420_REG_USBCTL, 0); | |
406 | ||
407 | /* Poll for OSC to stabilize */ | |
408 | while (1) { | |
409 | val = spi_rd8(udc, MAX3420_REG_USBIRQ); | |
410 | if (val & bOSCOKIRQ) | |
411 | break; | |
412 | cond_resched(); | |
413 | } | |
414 | ||
415 | /* Enable PULL-UP only when Vbus detected */ | |
416 | val = spi_rd8(udc, MAX3420_REG_USBCTL); | |
417 | val |= bVBGATE | bCONNECT; | |
418 | spi_wr8(udc, MAX3420_REG_USBCTL, val); | |
419 | ||
420 | val = bURESDNIRQ | bURESIRQ; | |
421 | spi_wr8(udc, MAX3420_REG_USBIEN, val); | |
422 | ||
423 | /* Enable only EP0 interrupts */ | |
424 | val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ; | |
425 | spi_wr8(udc, MAX3420_REG_EPIEN, val); | |
426 | ||
427 | /* Enable IRQ to CPU */ | |
428 | spi_wr8(udc, MAX3420_REG_CPUCTL, bIE); | |
429 | } | |
430 | ||
431 | static int max3420_udc_start(struct usb_gadget *gadget, | |
432 | struct usb_gadget_driver *driver) | |
433 | { | |
434 | struct max3420_udc *udc = to_udc(gadget); | |
435 | ||
436 | udc->driver = driver; | |
437 | udc->remote_wkp = 0; | |
438 | udc->softconnect = true; | |
439 | ||
440 | __max3420_start(udc); | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | static int max3420_udc_stop(struct usb_gadget *gadget) | |
446 | { | |
447 | struct max3420_udc *udc = to_udc(gadget); | |
448 | ||
449 | udc->driver = NULL; | |
450 | udc->softconnect = false; | |
451 | ||
452 | __max3420_stop(udc); | |
453 | ||
454 | return 0; | |
455 | } | |
456 | ||
457 | static int max3420_wakeup(struct usb_gadget *gadget) | |
458 | { | |
459 | struct max3420_udc *udc = to_udc(gadget); | |
460 | u8 usbctl; | |
461 | ||
462 | /* Only if wakeup allowed by host */ | |
463 | if (!udc->remote_wkp || !udc->suspended) | |
464 | return 0; | |
465 | ||
466 | /* Set Remote-Wakeup Signal*/ | |
467 | usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); | |
468 | usbctl |= bSIGRWU; | |
469 | spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); | |
470 | ||
471 | mdelay(5); | |
472 | ||
473 | /* Clear Remote-WkUp Signal*/ | |
474 | usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); | |
475 | usbctl &= ~bSIGRWU; | |
476 | spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); | |
477 | ||
478 | udc->suspended = false; | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
483 | static const struct usb_gadget_ops max3420_udc_ops = { | |
484 | .udc_start = max3420_udc_start, | |
485 | .udc_stop = max3420_udc_stop, | |
486 | .wakeup = max3420_wakeup, | |
487 | }; | |
488 | ||
489 | static struct usb_endpoint_descriptor ep0_desc = { | |
490 | .bLength = USB_DT_ENDPOINT_SIZE, | |
491 | .bDescriptorType = USB_DT_ENDPOINT, | |
492 | .bEndpointAddress = USB_DIR_OUT, | |
493 | .bmAttributes = USB_ENDPOINT_XFER_CONTROL, | |
494 | .wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET), | |
495 | }; | |
496 | ||
497 | static void max3420_getstatus(struct max3420_udc *udc) | |
498 | { | |
499 | struct max3420_ep *ep; | |
500 | u16 status = 0; | |
501 | ||
502 | switch (udc->setup.bRequestType & USB_RECIP_MASK) { | |
503 | case USB_RECIP_DEVICE: | |
504 | /* Get device status */ | |
505 | status = 0 << USB_DEVICE_SELF_POWERED; | |
506 | status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP); | |
507 | break; | |
508 | case USB_RECIP_INTERFACE: | |
509 | if (udc->driver->setup(&udc->gadget, &udc->setup) < 0) | |
510 | goto stall; | |
511 | break; | |
512 | case USB_RECIP_ENDPOINT: | |
513 | ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK]; | |
514 | if (ep->halted) | |
515 | status = 1 << USB_ENDPOINT_HALT; | |
516 | break; | |
517 | default: | |
518 | goto stall; | |
519 | } | |
520 | ||
521 | status = cpu_to_le16(status); | |
522 | spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2); | |
523 | spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1); | |
524 | return; | |
525 | stall: | |
526 | dev_err(udc->dev, "Can't respond to getstatus request\n"); | |
527 | spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); | |
528 | } | |
529 | ||
530 | static void max3420_set_clear_feature(struct max3420_udc *udc) | |
531 | { | |
532 | int set = udc->setup.bRequest == USB_REQ_SET_FEATURE; | |
533 | struct max3420_ep *ep; | |
534 | int id; | |
535 | ||
536 | switch (udc->setup.bRequestType) { | |
537 | case USB_RECIP_DEVICE: | |
538 | if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP) | |
539 | break; | |
540 | ||
541 | if (udc->setup.bRequest == USB_REQ_SET_FEATURE) | |
542 | udc->remote_wkp = 1; | |
543 | else | |
544 | udc->remote_wkp = 0; | |
545 | ||
546 | return spi_ack_ctrl(udc); | |
547 | ||
548 | case USB_RECIP_ENDPOINT: | |
549 | if (udc->setup.wValue != USB_ENDPOINT_HALT) | |
550 | break; | |
551 | ||
552 | id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; | |
553 | ep = &udc->ep[id]; | |
554 | ||
555 | max3420_ep_set_halt(&ep->ep_usb, set); | |
556 | return; | |
557 | default: | |
558 | break; | |
559 | } | |
560 | ||
561 | dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n"); | |
562 | spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); | |
563 | } | |
564 | ||
565 | static void max3420_handle_setup(struct max3420_udc *udc) | |
566 | { | |
567 | struct usb_ctrlrequest setup; | |
568 | u8 addr; | |
569 | ||
570 | spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); | |
571 | ||
572 | udc->setup = setup; | |
573 | udc->setup.wValue = cpu_to_le16(setup.wValue); | |
574 | udc->setup.wIndex = cpu_to_le16(setup.wIndex); | |
575 | udc->setup.wLength = cpu_to_le16(setup.wLength); | |
576 | ||
577 | switch (udc->setup.bRequest) { | |
578 | case USB_REQ_GET_STATUS: | |
579 | /* Data+Status phase form udc */ | |
580 | if ((udc->setup.bRequestType & | |
581 | (USB_DIR_IN | USB_TYPE_MASK)) != | |
582 | (USB_DIR_IN | USB_TYPE_STANDARD)) { | |
583 | break; | |
584 | } | |
585 | return max3420_getstatus(udc); | |
586 | case USB_REQ_SET_ADDRESS: | |
587 | /* Status phase from udc */ | |
588 | if (udc->setup.bRequestType != (USB_DIR_OUT | | |
589 | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) | |
590 | break; | |
591 | addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); | |
592 | dev_dbg(udc->dev, "Assigned Address=%d/%d\n", | |
593 | udc->setup.wValue, addr); | |
594 | return; | |
595 | case USB_REQ_CLEAR_FEATURE: | |
596 | case USB_REQ_SET_FEATURE: | |
597 | /* Requests with no data phase, status phase from udc */ | |
598 | if ((udc->setup.bRequestType & USB_TYPE_MASK) | |
599 | != USB_TYPE_STANDARD) | |
600 | break; | |
601 | return max3420_set_clear_feature(udc); | |
602 | default: | |
603 | break; | |
604 | } | |
605 | ||
606 | if (udc->driver->setup(&udc->gadget, &setup) < 0) { | |
607 | /* Stall EP0 */ | |
608 | spi_wr8(udc, MAX3420_REG_EPSTALLS, | |
609 | bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); | |
610 | } | |
611 | } | |
612 | ||
613 | static int do_data(struct max3420_udc *udc, int ep_id, int in) | |
614 | { | |
615 | struct max3420_ep *ep = &udc->ep[ep_id]; | |
616 | struct max3420_req *req; | |
617 | int done, length, psz; | |
618 | void *buf; | |
619 | ||
620 | if (list_empty(&ep->queue)) | |
621 | return 0; | |
622 | ||
623 | req = list_first_entry(&ep->queue, struct max3420_req, queue); | |
624 | buf = req->usb_req.buf + req->usb_req.actual; | |
625 | ||
626 | psz = ep->ep_usb.maxpacket; | |
627 | length = req->usb_req.length - req->usb_req.actual; | |
628 | length = min(length, psz); | |
629 | ||
630 | if (length == 0) { | |
631 | done = 1; | |
632 | goto xfer_done; | |
633 | } | |
634 | ||
635 | done = 0; | |
636 | if (in) { | |
637 | spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); | |
638 | spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length); | |
639 | if (length < psz) | |
640 | done = 1; | |
641 | } else { | |
642 | psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id); | |
643 | length = min(length, psz); | |
644 | spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); | |
645 | if (length < ep->ep_usb.maxpacket) | |
646 | done = 1; | |
647 | } | |
648 | ||
649 | req->usb_req.actual += length; | |
650 | ||
651 | if (req->usb_req.actual == req->usb_req.length) | |
652 | done = 1; | |
653 | ||
654 | xfer_done: | |
655 | if (done) { | |
656 | list_del_init(&req->queue); | |
657 | ||
658 | if (ep_id == 0) | |
659 | spi_ack_ctrl(udc); | |
660 | ||
661 | max3420_req_done(req, 0); | |
662 | } | |
663 | ||
664 | return 1; | |
665 | } | |
666 | ||
667 | static int max3420_handle_irqs(struct max3420_udc *udc) | |
668 | { | |
669 | u8 epien, epirq, usbirq, usbien, reg[4]; | |
670 | int ret = 0; | |
671 | ||
672 | spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4); | |
673 | epirq = reg[0]; | |
674 | epien = reg[1]; | |
675 | usbirq = reg[2]; | |
676 | usbien = reg[3]; | |
677 | ||
678 | usbirq &= usbien; | |
679 | epirq &= epien; | |
680 | ||
681 | if (epirq & bSUDAVIRQ) { | |
682 | spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ); | |
683 | max3420_handle_setup(udc); | |
684 | return 1; | |
685 | } | |
686 | ||
687 | if (usbirq & bVBUSIRQ) { | |
688 | spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ); | |
689 | dev_dbg(udc->dev, "Cable plugged in\n"); | |
690 | g_dnl_clear_detach(); | |
691 | return 1; | |
692 | } | |
693 | ||
694 | if (usbirq & bNOVBUSIRQ) { | |
695 | spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ); | |
696 | dev_dbg(udc->dev, "Cable pulled out\n"); | |
697 | g_dnl_trigger_detach(); | |
698 | return 1; | |
699 | } | |
700 | ||
701 | if (usbirq & bURESIRQ) { | |
702 | spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ); | |
703 | return 1; | |
704 | } | |
705 | ||
706 | if (usbirq & bURESDNIRQ) { | |
707 | spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ); | |
708 | spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ); | |
709 | spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ | |
710 | | bIN0BAVIRQ | bOUT0DAVIRQ); | |
711 | return 1; | |
712 | } | |
713 | ||
714 | if (usbirq & bSUSPIRQ) { | |
715 | spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ); | |
716 | dev_dbg(udc->dev, "USB Suspend - Enter\n"); | |
717 | udc->suspended = true; | |
718 | return 1; | |
719 | } | |
720 | ||
721 | if (usbirq & bBUSACTIRQ) { | |
722 | spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ); | |
723 | dev_dbg(udc->dev, "USB Suspend - Exit\n"); | |
724 | udc->suspended = false; | |
725 | return 1; | |
726 | } | |
727 | ||
728 | if (usbirq & bRWUDNIRQ) { | |
729 | spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ); | |
730 | dev_dbg(udc->dev, "Asked Host to wakeup\n"); | |
731 | return 1; | |
732 | } | |
733 | ||
734 | if (usbirq & bOSCOKIRQ) { | |
735 | spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ); | |
736 | dev_dbg(udc->dev, "Osc stabilized, start work\n"); | |
737 | return 1; | |
738 | } | |
739 | ||
740 | if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) { | |
741 | spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1); | |
742 | ret = 1; | |
743 | } | |
744 | ||
745 | if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1)) | |
746 | ret = 1; | |
747 | ||
748 | if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) { | |
749 | spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1); | |
750 | ret = 1; | |
751 | } | |
752 | ||
753 | if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1)) | |
754 | ret = 1; | |
755 | ||
756 | if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1)) | |
757 | ret = 1; | |
758 | ||
759 | return ret; | |
760 | } | |
761 | ||
762 | static int max3420_irq(struct max3420_udc *udc) | |
763 | { | |
764 | do_data(udc, 0, 1); /* get done with the EP0 ZLP */ | |
765 | ||
766 | return max3420_handle_irqs(udc); | |
767 | } | |
768 | ||
769 | static void max3420_setup_eps(struct max3420_udc *udc) | |
770 | { | |
771 | int i; | |
772 | ||
773 | INIT_LIST_HEAD(&udc->gadget.ep_list); | |
774 | INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list); | |
775 | ||
776 | for (i = 0; i < MAX3420_MAX_EPS; i++) { | |
777 | struct max3420_ep *ep = &udc->ep[i]; | |
778 | ||
779 | INIT_LIST_HEAD(&ep->queue); | |
780 | ||
781 | ep->id = i; | |
782 | ep->udc = udc; | |
783 | ep->ep_usb.ops = &max3420_ep_ops; | |
784 | ep->ep_usb.name = ep->name; | |
785 | ep->ep_usb.maxpacket = EP_MAX_PACKET; | |
786 | ||
787 | if (i == 0) { | |
788 | ep->ep_usb.desc = &ep0_desc; | |
789 | snprintf(ep->name, EPNAME_SIZE, "ep0"); | |
790 | continue; | |
791 | } | |
792 | ||
793 | list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list); | |
794 | ||
795 | if (i == 1) | |
796 | snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk"); | |
797 | else | |
798 | snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i); | |
799 | }; | |
800 | } | |
801 | ||
802 | static void max3420_setup_spi(struct max3420_udc *udc) | |
803 | { | |
804 | u8 reg[8]; | |
805 | ||
806 | spi_claim_bus(udc->slave); | |
807 | spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); | |
808 | /* configure SPI */ | |
809 | spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); | |
810 | } | |
811 | ||
812 | int dm_usb_gadget_handle_interrupts(struct udevice *dev) | |
813 | { | |
814 | struct max3420_udc *udc = dev_get_priv(dev); | |
815 | ||
816 | return max3420_irq(udc); | |
817 | } | |
818 | ||
819 | static int max3420_udc_probe(struct udevice *dev) | |
820 | { | |
821 | struct max3420_udc *udc = dev_get_priv(dev); | |
8a8d24bd | 822 | struct dm_spi_slave_plat *slave_pdata; |
7ed4eac4 | 823 | struct udevice *bus = dev->parent; |
8b85dfc6 | 824 | int busnum = dev_seq(bus); |
7ed4eac4 JB |
825 | unsigned int cs; |
826 | uint speed, mode; | |
827 | struct udevice *spid; | |
828 | ||
caa4daa2 | 829 | slave_pdata = dev_get_parent_plat(dev); |
7ed4eac4 JB |
830 | cs = slave_pdata->cs; |
831 | speed = slave_pdata->max_hz; | |
832 | mode = slave_pdata->mode; | |
61708bb0 PC |
833 | _spi_get_bus_and_cs(busnum, cs, speed, mode, false, "spi_generic_drv", |
834 | NULL, &spid, &udc->slave); | |
7ed4eac4 JB |
835 | |
836 | udc->dev = dev; | |
837 | udc->gadget.ep0 = &udc->ep[0].ep_usb; | |
838 | udc->gadget.max_speed = USB_SPEED_FULL; | |
839 | udc->gadget.speed = USB_SPEED_FULL; | |
840 | udc->gadget.is_dualspeed = 0; | |
841 | udc->gadget.ops = &max3420_udc_ops; | |
842 | udc->gadget.name = "max3420-udc"; | |
843 | ||
844 | max3420_setup_eps(udc); | |
845 | max3420_setup_spi(udc); | |
846 | ||
847 | usb_add_gadget_udc((struct device *)dev, &udc->gadget); | |
848 | ||
849 | return 0; | |
850 | } | |
851 | ||
852 | static int max3420_udc_remove(struct udevice *dev) | |
853 | { | |
854 | struct max3420_udc *udc = dev_get_priv(dev); | |
855 | ||
856 | usb_del_gadget_udc(&udc->gadget); | |
857 | ||
858 | spi_release_bus(udc->slave); | |
859 | ||
860 | return 0; | |
861 | } | |
862 | ||
863 | static const struct udevice_id max3420_ids[] = { | |
864 | { .compatible = "maxim,max3421-udc" }, | |
865 | { } | |
866 | }; | |
867 | ||
868 | U_BOOT_DRIVER(max3420_generic_udc) = { | |
869 | .name = "max3420-udc", | |
870 | .id = UCLASS_USB_GADGET_GENERIC, | |
871 | .of_match = max3420_ids, | |
872 | .probe = max3420_udc_probe, | |
873 | .remove = max3420_udc_remove, | |
41575d8e | 874 | .priv_auto = sizeof(struct max3420_udc), |
7ed4eac4 | 875 | }; |