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 = &REGS->DEVICE;
76 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->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 = &regs->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 = &REGS->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 = &REGS->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 = &REGS->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 = &REGS->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 = &REGS->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 = &REGS->DEVICE;
346 	uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
347 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
419 	uint8_t for_in = USB_EP_GET_DIR(ep);
420 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
421 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
440 	uint8_t for_in = USB_EP_GET_DIR(ep);
441 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
442 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
461 	uint8_t for_in = USB_EP_GET_DIR(ep);
462 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
463 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
510 	uint8_t for_in = USB_EP_GET_DIR(ep);
511 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
512 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
536 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
537 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
556 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
557 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
599 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
600 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->DEVICE;
667 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
668 	UsbDeviceEndpoint *endpoint = &regs->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 = &REGS->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 = &regs->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