1 /*
2 * Copyright (c) 2018 Google LLC.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT atmel_sam0_usb
8
9 #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL
10 #include <logging/log.h>
11 LOG_MODULE_REGISTER(usb_dc_sam0);
12
13 #include <usb/usb_device.h>
14 #include <soc.h>
15 #include <string.h>
16
17 #define NVM_USB_PAD_TRANSN_POS 45
18 #define NVM_USB_PAD_TRANSN_SIZE 5
19 #define NVM_USB_PAD_TRANSP_POS 50
20 #define NVM_USB_PAD_TRANSP_SIZE 5
21 #define NVM_USB_PAD_TRIM_POS 55
22 #define NVM_USB_PAD_TRIM_SIZE 3
23
24 #define USB_SAM0_IN_EP 0x80
25
26 #define REGS ((Usb *)DT_INST_REG_ADDR(0))
27 #define USB_NUM_ENDPOINTS DT_INST_PROP(0, num_bidir_endpoints)
28
29 /* The endpoint size stored in USB.PCKSIZE.SIZE */
30 enum usb_sam0_pcksize_size {
31 USB_SAM0_PCKSIZE_SIZE_8 = 0,
32 USB_SAM0_PCKSIZE_SIZE_16,
33 USB_SAM0_PCKSIZE_SIZE_32,
34 USB_SAM0_PCKSIZE_SIZE_64,
35 USB_SAM0_PCKSIZE_SIZE_128,
36 USB_SAM0_PCKSIZE_SIZE_256,
37 USB_SAM0_PCKSIZE_SIZE_512,
38 USB_SAM0_PCKSIZE_SIZE_1023,
39 };
40
41 static const uint16_t usb_sam0_pcksize_bytes[] = {
42 [USB_SAM0_PCKSIZE_SIZE_8] = 8,
43 [USB_SAM0_PCKSIZE_SIZE_16] = 16,
44 [USB_SAM0_PCKSIZE_SIZE_32] = 32,
45 [USB_SAM0_PCKSIZE_SIZE_64] = 64,
46 [USB_SAM0_PCKSIZE_SIZE_128] = 128,
47 [USB_SAM0_PCKSIZE_SIZE_256] = 256,
48 [USB_SAM0_PCKSIZE_SIZE_512] = 512,
49 [USB_SAM0_PCKSIZE_SIZE_1023] = 1023,
50 };
51
52 BUILD_ASSERT(ARRAY_SIZE(usb_sam0_pcksize_bytes) == 8);
53
54 struct usb_sam0_data {
55 UsbDeviceDescriptor descriptors[USB_NUM_ENDPOINTS];
56
57 usb_dc_status_callback cb;
58 usb_dc_ep_callback ep_cb[2][USB_NUM_ENDPOINTS];
59
60 uint8_t addr;
61 uint32_t out_at;
62 };
63
64 static struct usb_sam0_data usb_sam0_data_0;
65
usb_sam0_get_data(void)66 static struct usb_sam0_data *usb_sam0_get_data(void)
67 {
68 return &usb_sam0_data_0;
69 }
70
71 /* Handles interrupts on an endpoint */
usb_sam0_ep_isr(uint8_t ep)72 static void usb_sam0_ep_isr(uint8_t ep)
73 {
74 struct usb_sam0_data *data = usb_sam0_get_data();
75 UsbDevice *regs = ®S->DEVICE;
76 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep];
77 uint32_t intflag = endpoint->EPINTFLAG.reg;
78
79 endpoint->EPINTFLAG.reg = intflag;
80
81 if ((intflag & USB_DEVICE_EPINTFLAG_RXSTP) != 0U) {
82 /* Setup */
83 data->ep_cb[0][ep](ep, USB_DC_EP_SETUP);
84 }
85
86 if ((intflag & USB_DEVICE_EPINTFLAG_TRCPT0) != 0U) {
87 /* Out (to device) data received */
88 data->ep_cb[0][ep](ep, USB_DC_EP_DATA_OUT);
89 }
90
91 if ((intflag & USB_DEVICE_EPINTFLAG_TRCPT1) != 0U) {
92 /* In (to host) transmit complete */
93 data->ep_cb[1][ep](ep | USB_SAM0_IN_EP, USB_DC_EP_DATA_IN);
94
95 if (data->addr != 0U) {
96 /* Commit the pending address update. This
97 * must be done after the ack to the host
98 * completes else the ack will get dropped.
99 */
100 regs->DADD.reg = data->addr;
101 data->addr = 0U;
102 }
103 }
104 }
105
106 /* Top level interrupt handler */
usb_sam0_isr(void)107 static void usb_sam0_isr(void)
108 {
109 struct usb_sam0_data *data = usb_sam0_get_data();
110 UsbDevice *regs = ®S->DEVICE;
111 uint32_t intflag = regs->INTFLAG.reg;
112 uint32_t epint = regs->EPINTSMRY.reg;
113 uint8_t ep;
114
115 /* Acknowledge all interrupts */
116 regs->INTFLAG.reg = intflag;
117
118 if ((intflag & USB_DEVICE_INTFLAG_EORST) != 0U) {
119 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[0];
120
121 /* The device clears some of the configuration of EP0
122 * when it receives the EORST. Re-enable interrupts.
123 */
124 endpoint->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 |
125 USB_DEVICE_EPINTENSET_TRCPT1 |
126 USB_DEVICE_EPINTENSET_RXSTP;
127
128 data->cb(USB_DC_RESET, NULL);
129 }
130
131 /* Dispatch the endpoint interrupts */
132 for (ep = 0U; epint != 0U; epint >>= 1) {
133 /* Scan bit-by-bit as the Cortex-M0 doesn't have ffs */
134 if ((epint & 1) != 0U) {
135 usb_sam0_ep_isr(ep);
136 }
137 ep++;
138 }
139 }
140
141 /* Wait for the device to process the last config write */
usb_sam0_wait_syncbusy(void)142 static void usb_sam0_wait_syncbusy(void)
143 {
144 UsbDevice *regs = ®S->DEVICE;
145
146 while (regs->SYNCBUSY.reg != 0) {
147 }
148 }
149
150 /* Load the pad calibration from the built-in fuses */
usb_sam0_load_padcal(void)151 static void usb_sam0_load_padcal(void)
152 {
153 UsbDevice *regs = ®S->DEVICE;
154 uint32_t pad_transn;
155 uint32_t pad_transp;
156 uint32_t pad_trim;
157
158 #ifdef USB_FUSES_TRANSN_ADDR
159 pad_transn = *(uint32_t *)USB_FUSES_TRANSN_ADDR;
160 #else
161 pad_transn = (*((uint32_t *)(NVMCTRL_OTP4) +
162 (NVM_USB_PAD_TRANSN_POS / 32)) >>
163 (NVM_USB_PAD_TRANSN_POS % 32)) &
164 ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1);
165
166 if (pad_transn == 0x1F) {
167 pad_transn = 5U;
168 }
169 #endif
170
171 regs->PADCAL.bit.TRANSN = pad_transn;
172
173 #ifdef USB_FUSES_TRANSP_ADDR
174 pad_transp = *(uint32_t *)USB_FUSES_TRANSP_ADDR;
175 #else
176 pad_transp = (*((uint32_t *)(NVMCTRL_OTP4) +
177 (NVM_USB_PAD_TRANSP_POS / 32)) >>
178 (NVM_USB_PAD_TRANSP_POS % 32)) &
179 ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1);
180
181 if (pad_transp == 0x1F) {
182 pad_transp = 29U;
183 }
184 #endif
185
186 regs->PADCAL.bit.TRANSP = pad_transp;
187
188 #ifdef USB_FUSES_TRIM_ADDR
189 pad_trim = *(uint32_t *)USB_FUSES_TRIM_ADDR;
190 #else
191 pad_trim = (*((uint32_t *)(NVMCTRL_OTP4) +
192 (NVM_USB_PAD_TRIM_POS / 32)) >>
193 (NVM_USB_PAD_TRIM_POS % 32)) &
194 ((1 << NVM_USB_PAD_TRIM_SIZE) - 1);
195
196 if (pad_trim == 0x7) {
197 pad_trim = 3U;
198 }
199 #endif
200
201 regs->PADCAL.bit.TRIM = pad_trim;
202 }
203
204 #define SAM0_USB_IRQ_CONNECT(n) \
205 do { \
206 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, n, irq), \
207 DT_INST_IRQ_BY_IDX(0, n, priority), \
208 usb_sam0_isr, 0, 0); \
209 irq_enable(DT_INST_IRQ_BY_IDX(0, n, irq)); \
210 } while (0)
211
212 /* Attach by initializing the device */
usb_dc_attach(void)213 int usb_dc_attach(void)
214 {
215 UsbDevice *regs = ®S->DEVICE;
216 struct usb_sam0_data *data = usb_sam0_get_data();
217
218 #ifdef MCLK
219 /* Enable the clock in MCLK */
220 MCLK->APBBMASK.bit.USB_ = 1;
221
222 /* Enable the GCLK - use 48 MHz source */
223 GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN(2)
224 | GCLK_PCHCTRL_CHEN;
225
226 while (GCLK->SYNCBUSY.reg) {
227 }
228 #else
229 /* Enable the clock in PM */
230 PM->APBBMASK.bit.USB_ = 1;
231
232 /* Enable the GCLK */
233 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_USB | GCLK_CLKCTRL_GEN_GCLK0 |
234 GCLK_CLKCTRL_CLKEN;
235
236 while (GCLK->STATUS.bit.SYNCBUSY) {
237 }
238 #endif /* !MCLK */
239
240 /* Configure */
241 regs->CTRLA.bit.SWRST = 1;
242 usb_sam0_wait_syncbusy();
243
244 /* Change QOS values to have the best performance and correct USB
245 * behaviour
246 */
247 regs->QOSCTRL.bit.CQOS = 2;
248 regs->QOSCTRL.bit.DQOS = 2;
249
250 usb_sam0_load_padcal();
251
252 regs->CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_RUNSTDBY;
253 regs->CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_HS;
254
255 (void)memset(data->descriptors, 0, sizeof(data->descriptors));
256 regs->DESCADD.reg = (uintptr_t)&data->descriptors[0];
257
258 regs->INTENSET.reg = USB_DEVICE_INTENSET_EORST;
259
260 /* Connect and enable the interrupt */
261 #if DT_INST_IRQ_HAS_CELL(0, irq)
262 SAM0_USB_IRQ_CONNECT(0);
263 #endif
264 #if DT_INST_IRQ_HAS_IDX(0, 1)
265 SAM0_USB_IRQ_CONNECT(1);
266 #endif
267 #if DT_INST_IRQ_HAS_IDX(0, 2)
268 SAM0_USB_IRQ_CONNECT(2);
269 #endif
270 #if DT_INST_IRQ_HAS_IDX(0, 3)
271 SAM0_USB_IRQ_CONNECT(3);
272 #endif
273
274 /* Enable and attach */
275 regs->CTRLA.bit.ENABLE = 1;
276 usb_sam0_wait_syncbusy();
277 regs->CTRLB.bit.DETACH = 0;
278
279 return 0;
280 }
281
282 /* Detach from the bus */
usb_dc_detach(void)283 int usb_dc_detach(void)
284 {
285 UsbDevice *regs = ®S->DEVICE;
286
287 regs->CTRLB.bit.DETACH = 1;
288 usb_sam0_wait_syncbusy();
289
290 return 0;
291 }
292
293 /* Remove the interrupt and reset the device */
usb_dc_reset(void)294 int usb_dc_reset(void)
295 {
296 UsbDevice *regs = ®S->DEVICE;
297
298 irq_disable(DT_INST_IRQN(0));
299
300 regs->CTRLA.bit.SWRST = 1;
301 usb_sam0_wait_syncbusy();
302
303 return 0;
304 }
305
306 /* Queue a change in address. This is processed later when the
307 * current transfers are compelete.
308 */
usb_dc_set_address(const uint8_t addr)309 int usb_dc_set_address(const uint8_t addr)
310 {
311 struct usb_sam0_data *data = usb_sam0_get_data();
312
313 data->addr = addr | USB_DEVICE_DADD_ADDEN;
314
315 return 0;
316 }
317
usb_dc_set_status_callback(const usb_dc_status_callback cb)318 void usb_dc_set_status_callback(const usb_dc_status_callback cb)
319 {
320 struct usb_sam0_data *data = usb_sam0_get_data();
321
322 data->cb = cb;
323 }
324
usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)325 int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)
326 {
327 uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
328
329 if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx) {
330 LOG_ERR("invalid endpoint configuration");
331 return -1;
332 }
333
334 if (ep_idx > USB_NUM_ENDPOINTS) {
335 LOG_ERR("endpoint index/address too high");
336 return -1;
337 }
338
339 return 0;
340 }
341
usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg)342 int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg)
343 {
344 struct usb_sam0_data *data = usb_sam0_get_data();
345 UsbDevice *regs = ®S->DEVICE;
346 uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
347 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
348 UsbDeviceDescriptor *desc = &data->descriptors[ep_idx];
349 UsbDeviceDescBank *bank;
350 void *buf;
351 int type;
352 int size = -1;
353 int i;
354
355 /* Map the type to native type */
356 switch (cfg->ep_type) {
357 case USB_DC_EP_CONTROL:
358 type = 1;
359 break;
360 case USB_DC_EP_ISOCHRONOUS:
361 type = 2;
362 break;
363 case USB_DC_EP_BULK:
364 type = 3;
365 break;
366 case USB_DC_EP_INTERRUPT:
367 type = 4;
368 break;
369 default:
370 return -EINVAL;
371 }
372
373 /* Map the endpoint size to native size */
374 for (i = 0; i < ARRAY_SIZE(usb_sam0_pcksize_bytes); i++) {
375 if (usb_sam0_pcksize_bytes[i] == cfg->ep_mps) {
376 size = i;
377 break;
378 }
379 }
380
381 if (size < 0) {
382 return -EINVAL;
383 }
384
385 if (USB_EP_DIR_IS_IN(cfg->ep_addr)) {
386 bank = &desc->DeviceDescBank[1];
387 } else {
388 bank = &desc->DeviceDescBank[0];
389 }
390
391 buf = (void *)bank->ADDR.reg;
392
393 if (bank->PCKSIZE.bit.SIZE != size || buf == NULL) {
394 /* Release the previous buffer, if any */
395 k_free(buf);
396
397 buf = k_malloc(cfg->ep_mps);
398 if (buf == NULL) {
399 return -ENOMEM;
400 }
401 bank->PCKSIZE.bit.SIZE = size;
402 bank->ADDR.reg = (uintptr_t)buf;
403 }
404
405 if (USB_EP_DIR_IS_IN(cfg->ep_addr)) {
406 endpoint->EPCFG.bit.EPTYPE1 = type;
407 endpoint->EPSTATUSCLR.bit.BK1RDY = 1;
408 } else {
409 endpoint->EPCFG.bit.EPTYPE0 = type;
410 endpoint->EPSTATUSCLR.bit.BK0RDY = 1;
411 }
412
413 return 0;
414 }
415
usb_dc_ep_set_stall(const uint8_t ep)416 int usb_dc_ep_set_stall(const uint8_t ep)
417 {
418 UsbDevice *regs = ®S->DEVICE;
419 uint8_t for_in = USB_EP_GET_DIR(ep);
420 uint8_t ep_idx = USB_EP_GET_IDX(ep);
421 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
422
423 if (ep_idx >= USB_NUM_ENDPOINTS) {
424 LOG_ERR("endpoint index/address out of range");
425 return -1;
426 }
427
428 if (for_in) {
429 endpoint->EPSTATUSSET.bit.STALLRQ1 = 1;
430 } else {
431 endpoint->EPSTATUSSET.bit.STALLRQ0 = 1;
432 }
433
434 return 0;
435 }
436
usb_dc_ep_clear_stall(const uint8_t ep)437 int usb_dc_ep_clear_stall(const uint8_t ep)
438 {
439 UsbDevice *regs = ®S->DEVICE;
440 uint8_t for_in = USB_EP_GET_DIR(ep);
441 uint8_t ep_idx = USB_EP_GET_IDX(ep);
442 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
443
444 if (ep_idx >= USB_NUM_ENDPOINTS) {
445 LOG_ERR("endpoint index/address out of range");
446 return -1;
447 }
448
449 if (for_in) {
450 endpoint->EPSTATUSCLR.bit.STALLRQ1 = 1;
451 } else {
452 endpoint->EPSTATUSCLR.bit.STALLRQ0 = 1;
453 }
454
455 return 0;
456 }
457
usb_dc_ep_is_stalled(const uint8_t ep,uint8_t * stalled)458 int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
459 {
460 UsbDevice *regs = ®S->DEVICE;
461 uint8_t for_in = USB_EP_GET_DIR(ep);
462 uint8_t ep_idx = USB_EP_GET_IDX(ep);
463 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
464
465 if (ep_idx >= USB_NUM_ENDPOINTS) {
466 LOG_ERR("endpoint index/address out of range");
467 return -1;
468 }
469
470 if (stalled == NULL) {
471 LOG_ERR("parameter must not be NULL");
472 return -1;
473 }
474
475 if (for_in) {
476 *stalled = endpoint->EPSTATUS.bit.STALLRQ1;
477 } else {
478 *stalled = endpoint->EPSTATUS.bit.STALLRQ0;
479 }
480
481 return 0;
482 }
483
484 /* Halt the selected endpoint */
usb_dc_ep_halt(uint8_t ep)485 int usb_dc_ep_halt(uint8_t ep)
486 {
487 return usb_dc_ep_set_stall(ep);
488 }
489
490 /* Flush the selected endpoint */
usb_dc_ep_flush(uint8_t ep)491 int usb_dc_ep_flush(uint8_t ep)
492 {
493 uint8_t ep_idx = USB_EP_GET_IDX(ep);
494
495 if (ep_idx >= USB_NUM_ENDPOINTS) {
496 LOG_ERR("endpoint index/address out of range");
497 return -1;
498 }
499
500 /* TODO */
501 LOG_WRN("flush not implemented");
502
503 return 0;
504 }
505
506 /* Enable an endpoint and the endpoint interrupts */
usb_dc_ep_enable(const uint8_t ep)507 int usb_dc_ep_enable(const uint8_t ep)
508 {
509 UsbDevice *regs = ®S->DEVICE;
510 uint8_t for_in = USB_EP_GET_DIR(ep);
511 uint8_t ep_idx = USB_EP_GET_IDX(ep);
512 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
513
514 if (ep_idx >= USB_NUM_ENDPOINTS) {
515 LOG_ERR("endpoint index/address out of range");
516 return -EINVAL;
517 }
518
519 if (for_in) {
520 endpoint->EPSTATUSCLR.bit.BK1RDY = 1;
521 } else {
522 endpoint->EPSTATUSCLR.bit.BK0RDY = 1;
523 }
524
525 endpoint->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 |
526 USB_DEVICE_EPINTENSET_TRCPT1 |
527 USB_DEVICE_EPINTENSET_RXSTP;
528
529 return 0;
530 }
531
532 /* Disable the selected endpoint */
usb_dc_ep_disable(uint8_t ep)533 int usb_dc_ep_disable(uint8_t ep)
534 {
535 UsbDevice *regs = ®S->DEVICE;
536 uint8_t ep_idx = USB_EP_GET_IDX(ep);
537 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
538
539 if (ep_idx >= USB_NUM_ENDPOINTS) {
540 LOG_ERR("endpoint index/address out of range");
541 return -EINVAL;
542 }
543
544 endpoint->EPINTENCLR.reg = USB_DEVICE_EPINTENCLR_TRCPT0
545 | USB_DEVICE_EPINTENCLR_TRCPT1
546 | USB_DEVICE_EPINTENCLR_RXSTP;
547
548 return 0;
549 }
550
551 /* Write a single payload to the IN buffer on the endpoint */
usb_dc_ep_write(uint8_t ep,const uint8_t * buf,uint32_t len,uint32_t * ret_bytes)552 int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, uint32_t len, uint32_t *ret_bytes)
553 {
554 struct usb_sam0_data *data = usb_sam0_get_data();
555 UsbDevice *regs = ®S->DEVICE;
556 uint8_t ep_idx = USB_EP_GET_IDX(ep);
557 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
558 UsbDeviceDescriptor *desc = &data->descriptors[ep_idx];
559 uint32_t addr = desc->DeviceDescBank[1].ADDR.reg;
560 uint32_t capacity = usb_sam0_pcksize_bytes[
561 desc->DeviceDescBank[1].PCKSIZE.bit.SIZE];
562
563 if (ep_idx >= USB_NUM_ENDPOINTS) {
564 LOG_ERR("endpoint index/address out of range");
565 return -1;
566 }
567
568 if (endpoint->EPSTATUS.bit.BK1RDY) {
569 /* Write in progress, drop */
570 return -EAGAIN;
571 }
572
573 len = Z_MIN(len, capacity);
574
575 /* Note that this code does not use the hardware's
576 * multi-packet and automatic zero-length packet features as
577 * the upper layers in Zephyr implement these in code.
578 */
579 memcpy((void *)addr, buf, len);
580 desc->DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
581 desc->DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = len;
582 endpoint->EPINTFLAG.reg =
583 USB_DEVICE_EPINTFLAG_TRCPT1 | USB_DEVICE_EPINTFLAG_TRFAIL1;
584 endpoint->EPSTATUSSET.bit.BK1RDY = 1;
585
586 if (ret_bytes != NULL) {
587 *ret_bytes = len;
588 }
589
590 return 0;
591 }
592
593 /* Read data from an OUT endpoint */
usb_dc_ep_read_ex(uint8_t ep,uint8_t * buf,uint32_t max_data_len,uint32_t * read_bytes,bool wait)594 int usb_dc_ep_read_ex(uint8_t ep, uint8_t *buf, uint32_t max_data_len,
595 uint32_t *read_bytes, bool wait)
596 {
597 struct usb_sam0_data *data = usb_sam0_get_data();
598 UsbDevice *regs = ®S->DEVICE;
599 uint8_t ep_idx = USB_EP_GET_IDX(ep);
600 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
601 UsbDeviceDescriptor *desc = &data->descriptors[ep_idx];
602 uint32_t addr = desc->DeviceDescBank[0].ADDR.reg;
603 uint32_t bytes = desc->DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT;
604 uint32_t take;
605 int remain;
606
607 if (ep_idx >= USB_NUM_ENDPOINTS) {
608 LOG_ERR("endpoint index/address out of range");
609 return -1;
610 }
611
612 if (!endpoint->EPSTATUS.bit.BK0RDY) {
613 return -EAGAIN;
614 }
615
616 /* The code below emulates the Quark FIFO which the Zephyr USB
617 * API is based on. Reading with buf == NULL returns the
618 * number of bytes available and starts the read. The caller
619 * then keeps calling until all bytes are consumed which
620 * also marks the OUT buffer as freed.
621 */
622 if (buf == NULL) {
623 data->out_at = 0U;
624
625 if (read_bytes != NULL) {
626 *read_bytes = bytes;
627 }
628
629 return 0;
630 }
631
632 remain = bytes - data->out_at;
633 take = MIN(max_data_len, remain);
634 memcpy(buf, (uint8_t *)addr + data->out_at, take);
635
636 if (read_bytes != NULL) {
637 *read_bytes = take;
638 }
639
640 if (take == remain) {
641 if (!wait) {
642 endpoint->EPSTATUSCLR.bit.BK0RDY = 1;
643 data->out_at = 0U;
644 }
645 } else {
646 data->out_at += take;
647 }
648
649 return 0;
650 }
651
usb_dc_ep_read(uint8_t ep,uint8_t * buf,uint32_t max_data_len,uint32_t * read_bytes)652 int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, uint32_t *read_bytes)
653 {
654 return usb_dc_ep_read_ex(ep, buf, max_data_len, read_bytes, false);
655 }
656
usb_dc_ep_read_wait(uint8_t ep,uint8_t * buf,uint32_t max_data_len,uint32_t * read_bytes)657 int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len,
658 uint32_t *read_bytes)
659 {
660 return usb_dc_ep_read_ex(ep, buf, max_data_len, read_bytes, true);
661 }
662
usb_dc_ep_read_continue(uint8_t ep)663 int usb_dc_ep_read_continue(uint8_t ep)
664 {
665 struct usb_sam0_data *data = usb_sam0_get_data();
666 UsbDevice *regs = ®S->DEVICE;
667 uint8_t ep_idx = USB_EP_GET_IDX(ep);
668 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
669
670 if (ep_idx >= USB_NUM_ENDPOINTS) {
671 LOG_ERR("endpoint index/address out of range");
672 return -1;
673 }
674
675 endpoint->EPSTATUSCLR.bit.BK0RDY = 1;
676 data->out_at = 0U;
677
678 return 0;
679 }
680
usb_dc_ep_set_callback(const uint8_t ep,const usb_dc_ep_callback cb)681 int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
682 {
683 struct usb_sam0_data *data = usb_sam0_get_data();
684 uint8_t for_in = USB_EP_GET_DIR(ep);
685 uint8_t ep_idx = USB_EP_GET_IDX(ep);
686
687 if (ep_idx >= USB_NUM_ENDPOINTS) {
688 LOG_ERR("endpoint index/address out of range");
689 return -1;
690 }
691
692 data->ep_cb[for_in ? 1 : 0][ep_idx] = cb;
693
694 return 0;
695 }
696
usb_dc_ep_mps(const uint8_t ep)697 int usb_dc_ep_mps(const uint8_t ep)
698 {
699 struct usb_sam0_data *data = usb_sam0_get_data();
700 UsbDevice *regs = ®S->DEVICE;
701 uint8_t for_in = USB_EP_GET_DIR(ep);
702 uint8_t ep_idx = USB_EP_GET_IDX(ep);
703 UsbDeviceDescriptor *desc = &data->descriptors[ep_idx];
704 UsbDeviceEndpoint *endpoint = ®s->DeviceEndpoint[ep_idx];
705
706 if (ep_idx >= USB_NUM_ENDPOINTS) {
707 LOG_ERR("endpoint index/address out of range");
708 return -1;
709 }
710
711 if (for_in) {
712 /* if endpoint is not configured, this should return 0 */
713 if (endpoint->EPCFG.bit.EPTYPE1 == 0) {
714 return 0;
715 }
716
717 return usb_sam0_pcksize_bytes[
718 desc->DeviceDescBank[1].PCKSIZE.bit.SIZE];
719 } else {
720 /* if endpoint is not configured, this should return 0 */
721 if (endpoint->EPCFG.bit.EPTYPE0 == 0) {
722 return 0;
723 }
724
725 return usb_sam0_pcksize_bytes[
726 desc->DeviceDescBank[0].PCKSIZE.bit.SIZE];
727 }
728 }
729