1 /* usb_dc_dw.c - USB DesignWare device controller driver */
2 
3 #define DT_DRV_COMPAT snps_designware_usb
4 
5 /*
6  * Copyright (c) 2016 Intel Corporation.
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 /**
12  * @file
13  * @brief USB DesignWare device controller driver
14  *
15  * USB DesignWare device controller driver. The driver implements the low
16  * level control routines to deal directly with the hardware.
17  */
18 
19 #include <string.h>
20 #include <stdio.h>
21 #include <sys/byteorder.h>
22 #include <usb/usb_device.h>
23 #include "usb_dw_registers.h"
24 #include <soc.h>
25 
26 #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL
27 #include <logging/log.h>
28 LOG_MODULE_REGISTER(usb_dc_dw);
29 
30 /* Number of SETUP back-to-back packets */
31 #define USB_DW_SUP_CNT (1)
32 
33 /*
34  * USB endpoint private structure.
35  */
36 struct usb_ep_ctrl_prv {
37 	uint8_t ep_ena;
38 	uint8_t fifo_num;
39 	uint32_t fifo_size;
40 	uint16_t mps;         /* Max ep pkt size */
41 	usb_dc_ep_callback cb;/* Endpoint callback function */
42 	uint32_t data_len;
43 };
44 
45 /*
46  * USB controller private structure.
47  */
48 struct usb_dw_ctrl_prv {
49 	usb_dc_status_callback status_cb;
50 	struct usb_ep_ctrl_prv in_ep_ctrl[USB_DW_IN_EP_NUM];
51 	struct usb_ep_ctrl_prv out_ep_ctrl[USB_DW_OUT_EP_NUM];
52 	int n_tx_fifos;
53 	uint8_t attached;
54 };
55 
56 
57 static struct usb_dw_ctrl_prv usb_dw_ctrl;
58 
usb_dw_reg_dump(void)59 static void usb_dw_reg_dump(void)
60 {
61 	uint8_t i;
62 
63 	LOG_DBG("USB registers:  GOTGCTL : 0x%x  GOTGINT : 0x%x  GAHBCFG : "
64 		"0x%x", USB_DW->gotgctl, USB_DW->gotgint, USB_DW->gahbcfg);
65 	LOG_DBG("  GUSBCFG : 0x%x  GINTSTS : 0x%x  GINTMSK : 0x%x",
66 		USB_DW->gusbcfg, USB_DW->gintsts, USB_DW->gintmsk);
67 	LOG_DBG("  DCFG    : 0x%x  DCTL    : 0x%x  DSTS    : 0x%x",
68 		USB_DW->dcfg, USB_DW->dctl, USB_DW->dsts);
69 	LOG_DBG("  DIEPMSK : 0x%x  DOEPMSK : 0x%x  DAINT   : 0x%x",
70 		USB_DW->diepmsk, USB_DW->doepmsk, USB_DW->daint);
71 	LOG_DBG("  DAINTMSK: 0x%x  GHWCFG1 : 0x%x  GHWCFG2 : 0x%x",
72 		USB_DW->daintmsk, USB_DW->ghwcfg1, USB_DW->ghwcfg2);
73 	LOG_DBG("  GHWCFG3 : 0x%x  GHWCFG4 : 0x%x",
74 		USB_DW->ghwcfg3, USB_DW->ghwcfg4);
75 
76 	for (i = 0U; i < USB_DW_OUT_EP_NUM; i++) {
77 		LOG_DBG("\n  EP %d registers:    DIEPCTL : 0x%x    DIEPINT : "
78 			"0x%x", i, USB_DW->in_ep_reg[i].diepctl,
79 			USB_DW->in_ep_reg[i].diepint);
80 		LOG_DBG("    DIEPTSIZ: 0x%x    DIEPDMA : 0x%x    DOEPCTL : "
81 			"0x%x", USB_DW->in_ep_reg[i].dieptsiz,
82 			USB_DW->in_ep_reg[i].diepdma,
83 			USB_DW->out_ep_reg[i].doepctl);
84 		LOG_DBG("    DOEPINT : 0x%x    DOEPTSIZ: 0x%x    DOEPDMA : "
85 			"0x%x", USB_DW->out_ep_reg[i].doepint,
86 			USB_DW->out_ep_reg[i].doeptsiz,
87 			USB_DW->out_ep_reg[i].doepdma);
88 	}
89 }
90 
usb_dw_ep_is_valid(uint8_t ep)91 static uint8_t usb_dw_ep_is_valid(uint8_t ep)
92 {
93 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
94 
95 	/* Check if ep enabled */
96 	if ((USB_EP_DIR_IS_OUT(ep)) && ep_idx < USB_DW_OUT_EP_NUM) {
97 		return 1;
98 	} else if ((USB_EP_DIR_IS_IN(ep)) && ep_idx < USB_DW_IN_EP_NUM) {
99 		return 1;
100 	}
101 
102 	return 0;
103 }
104 
usb_dw_ep_is_enabled(uint8_t ep)105 static uint8_t usb_dw_ep_is_enabled(uint8_t ep)
106 {
107 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
108 
109 	/* Check if ep enabled */
110 	if ((USB_EP_DIR_IS_OUT(ep)) &&
111 	    usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena) {
112 		return 1;
113 	} else if ((USB_EP_DIR_IS_IN(ep)) &&
114 		   usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena) {
115 		return 1;
116 	}
117 
118 	return 0;
119 }
120 
usb_dw_udelay(uint32_t us)121 static inline void usb_dw_udelay(uint32_t us)
122 {
123 	k_busy_wait(us);
124 }
125 
usb_dw_reset(void)126 static int usb_dw_reset(void)
127 {
128 	uint32_t cnt = 0U;
129 
130 	/* Wait for AHB master idle state. */
131 	while (!(USB_DW->grstctl & USB_DW_GRSTCTL_AHB_IDLE)) {
132 		usb_dw_udelay(1);
133 
134 		if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
135 			LOG_ERR("USB reset HANG! AHB Idle GRSTCTL=0x%08x",
136 				USB_DW->grstctl);
137 			return -EIO;
138 		}
139 	}
140 
141 	/* Core Soft Reset */
142 	cnt = 0U;
143 	USB_DW->grstctl |= USB_DW_GRSTCTL_C_SFT_RST;
144 
145 	do {
146 		if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
147 			LOG_DBG("USB reset HANG! Soft Reset GRSTCTL=0x%08x",
148 				USB_DW->grstctl);
149 			return -EIO;
150 		}
151 		usb_dw_udelay(1);
152 	} while (USB_DW->grstctl & USB_DW_GRSTCTL_C_SFT_RST);
153 
154 	/* Wait for 3 PHY Clocks */
155 	usb_dw_udelay(100);
156 
157 	return 0;
158 }
159 
usb_dw_num_dev_eps(void)160 static int usb_dw_num_dev_eps(void)
161 {
162 	return (USB_DW->ghwcfg2 >> 10) & 0xf;
163 }
164 
usb_dw_flush_tx_fifo(int ep)165 static void usb_dw_flush_tx_fifo(int ep)
166 {
167 	int fnum = usb_dw_ctrl.in_ep_ctrl[ep].fifo_num;
168 
169 	USB_DW->grstctl = (fnum << 6) | (1<<5);
170 	while (USB_DW->grstctl & (1<<5)) {
171 	}
172 }
173 
usb_dw_tx_fifo_avail(int ep)174 static int usb_dw_tx_fifo_avail(int ep)
175 {
176 	return USB_DW->in_ep_reg[ep].dtxfsts &
177 		USB_DW_DTXFSTS_TXF_SPC_AVAIL_MASK;
178 }
179 
180 /* Choose a FIFO number for an IN endpoint */
usb_dw_set_fifo(uint8_t ep)181 static int usb_dw_set_fifo(uint8_t ep)
182 {
183 	int ep_idx = USB_EP_GET_IDX(ep);
184 	volatile uint32_t *reg = &USB_DW->in_ep_reg[ep_idx].diepctl;
185 	uint32_t val;
186 	int fifo = 0;
187 	int ded_fifo = !!(USB_DW->ghwcfg4 & USB_DW_HWCFG4_DEDFIFOMODE);
188 
189 	if (!ded_fifo) {
190 		/* No support for shared-FIFO mode yet, existing
191 		 * Zephyr hardware doesn't use it
192 		 */
193 		return -ENOTSUP;
194 	}
195 
196 	/* In dedicated-FIFO mode, all IN endpoints must have a unique
197 	 * FIFO number associated with them in the TXFNUM field of
198 	 * DIEPCTLx, with EP0 always being assigned to FIFO zero (the
199 	 * reset default, so we don't touch it).
200 	 *
201 	 * FIXME: would be better (c.f. the dwc2 driver in Linux) to
202 	 * choose a FIFO based on the hardware depth: we want the
203 	 * smallest one that fits our configured maximum packet size
204 	 * for the endpoint.  This just picks the next available one.
205 	 */
206 	if (ep_idx != 0) {
207 		fifo = ++usb_dw_ctrl.n_tx_fifos;
208 		if (fifo >= usb_dw_num_dev_eps()) {
209 			return -EINVAL;
210 		}
211 
212 		reg = &USB_DW->in_ep_reg[ep_idx].diepctl;
213 		val = *reg & ~USB_DW_DEPCTL_TXFNUM_MASK;
214 		val |= fifo << USB_DW_DEPCTL_TXFNUM_OFFSET;
215 		*reg = val;
216 	}
217 
218 	usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_num = fifo;
219 
220 	usb_dw_flush_tx_fifo(ep_idx);
221 
222 	val = usb_dw_tx_fifo_avail(ep_idx);
223 	usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_size = val;
224 
225 	return 0;
226 }
227 
usb_dw_ep_set(uint8_t ep,uint32_t ep_mps,enum usb_dc_ep_transfer_type ep_type)228 static int usb_dw_ep_set(uint8_t ep,
229 			 uint32_t ep_mps, enum usb_dc_ep_transfer_type ep_type)
230 {
231 	volatile uint32_t *p_depctl;
232 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
233 
234 	LOG_DBG("%s ep %x, mps %d, type %d", __func__, ep, ep_mps, ep_type);
235 
236 	if (USB_EP_DIR_IS_OUT(ep)) {
237 		p_depctl = &USB_DW->out_ep_reg[ep_idx].doepctl;
238 		usb_dw_ctrl.out_ep_ctrl[ep_idx].mps = ep_mps;
239 	} else {
240 		p_depctl = &USB_DW->in_ep_reg[ep_idx].diepctl;
241 		usb_dw_ctrl.in_ep_ctrl[ep_idx].mps = ep_mps;
242 	}
243 
244 	if (!ep_idx) {
245 		/* Set max packet size for EP0 */
246 		*p_depctl &= ~USB_DW_DEPCTL0_MSP_MASK;
247 
248 		switch (ep_mps) {
249 		case 8:
250 			*p_depctl |= USB_DW_DEPCTL0_MSP_8 <<
251 				USB_DW_DEPCTL_MSP_OFFSET;
252 			break;
253 		case 16:
254 			*p_depctl |= USB_DW_DEPCTL0_MSP_16 <<
255 				USB_DW_DEPCTL_MSP_OFFSET;
256 			break;
257 		case 32:
258 			*p_depctl |= USB_DW_DEPCTL0_MSP_32 <<
259 				USB_DW_DEPCTL_MSP_OFFSET;
260 			break;
261 		case 64:
262 			*p_depctl |= USB_DW_DEPCTL0_MSP_64 <<
263 				USB_DW_DEPCTL_MSP_OFFSET;
264 			break;
265 		default:
266 			return -EINVAL;
267 		}
268 		/* No need to set EP0 type */
269 	} else {
270 		/* Set max packet size for EP */
271 		if (ep_mps > (USB_DW_DEPCTLn_MSP_MASK >>
272 		    USB_DW_DEPCTL_MSP_OFFSET)) {
273 			return -EINVAL;
274 		}
275 
276 		*p_depctl &= ~USB_DW_DEPCTLn_MSP_MASK;
277 		*p_depctl |= ep_mps << USB_DW_DEPCTL_MSP_OFFSET;
278 
279 		/* Set endpoint type */
280 		*p_depctl &= ~USB_DW_DEPCTL_EP_TYPE_MASK;
281 
282 		switch (ep_type) {
283 		case USB_DC_EP_CONTROL:
284 			*p_depctl |= USB_DW_DEPCTL_EP_TYPE_CONTROL <<
285 				USB_DW_DEPCTL_EP_TYPE_OFFSET;
286 			break;
287 		case USB_DC_EP_BULK:
288 			*p_depctl |= USB_DW_DEPCTL_EP_TYPE_BULK <<
289 				USB_DW_DEPCTL_EP_TYPE_OFFSET;
290 			break;
291 		case USB_DC_EP_INTERRUPT:
292 			*p_depctl |= USB_DW_DEPCTL_EP_TYPE_INTERRUPT <<
293 				USB_DW_DEPCTL_EP_TYPE_OFFSET;
294 			break;
295 		default:
296 			return -EINVAL;
297 		}
298 
299 		/* sets the Endpoint Data PID to DATA0 */
300 		*p_depctl |= USB_DW_DEPCTL_SETDOPID;
301 	}
302 
303 	if (USB_EP_DIR_IS_IN(ep)) {
304 		int ret = usb_dw_set_fifo(ep);
305 
306 		if (ret) {
307 			return ret;
308 		}
309 	}
310 
311 	return 0;
312 }
313 
usb_dw_prep_rx(const uint8_t ep,uint8_t setup)314 static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup)
315 {
316 	enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep);
317 	uint32_t ep_mps = usb_dw_ctrl.out_ep_ctrl[ep_idx].mps;
318 
319 	/* Set max RX size to EP mps so we get an interrupt
320 	 * each time a packet is received
321 	 */
322 
323 	USB_DW->out_ep_reg[ep_idx].doeptsiz =
324 		(USB_DW_SUP_CNT << USB_DW_DOEPTSIZ_SUP_CNT_OFFSET) |
325 		(1 << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | ep_mps;
326 
327 	/* Clear NAK and enable ep */
328 	if (!setup) {
329 		USB_DW->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_CNAK;
330 	}
331 
332 	USB_DW->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_EP_ENA;
333 
334 	LOG_DBG("USB OUT EP%d armed", ep_idx);
335 }
336 
usb_dw_tx(uint8_t ep,const uint8_t * const data,uint32_t data_len)337 static int usb_dw_tx(uint8_t ep, const uint8_t *const data,
338 		uint32_t data_len)
339 {
340 	enum usb_dw_in_ep_idx ep_idx = USB_EP_GET_IDX(ep);
341 	uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space;
342 	uint32_t ep_mps = usb_dw_ctrl.in_ep_ctrl[ep_idx].mps;
343 	unsigned int key;
344 	uint32_t i;
345 
346 	/* Wait for FIFO space available */
347 	do {
348 		avail_space = usb_dw_tx_fifo_avail(ep_idx);
349 		if (avail_space == usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_size) {
350 			break;
351 		}
352 		/* Make sure we don't hog the CPU */
353 		k_yield();
354 	} while (1);
355 
356 	key = irq_lock();
357 
358 	avail_space *= 4U;
359 	if (!avail_space) {
360 		LOG_ERR("USB IN EP%d no space available, DTXFSTS %x", ep_idx,
361 			USB_DW->in_ep_reg[ep_idx].dtxfsts);
362 		irq_unlock(key);
363 		return -EAGAIN;
364 	}
365 
366 	/* For now tx-fifo sizes are not configured (cf usb_dw_set_fifo). Here
367 	 * we force available fifo size to be a multiple of ep mps in order to
368 	 * prevent splitting data incorrectly.
369 	 */
370 	avail_space -= avail_space % ep_mps;
371 	if (data_len > avail_space) {
372 		data_len = avail_space;
373 	}
374 
375 	if (data_len != 0U) {
376 		/* Get max packet size and packet count for ep */
377 		if (ep_idx == USB_DW_IN_EP_0) {
378 			max_pkt_cnt =
379 			    USB_DW_DIEPTSIZ0_PKT_CNT_MASK >>
380 			    USB_DW_DEPTSIZ_PKT_CNT_OFFSET;
381 			max_xfer_size =
382 			    USB_DW_DEPTSIZ0_XFER_SIZE_MASK >>
383 			    USB_DW_DEPTSIZ_XFER_SIZE_OFFSET;
384 		} else {
385 			max_pkt_cnt =
386 			    USB_DW_DIEPTSIZn_PKT_CNT_MASK >>
387 			    USB_DW_DEPTSIZ_PKT_CNT_OFFSET;
388 			max_xfer_size =
389 			    USB_DW_DEPTSIZn_XFER_SIZE_MASK >>
390 			    USB_DW_DEPTSIZ_XFER_SIZE_OFFSET;
391 		}
392 
393 		/* Check if transfer len is too big */
394 		if (data_len > max_xfer_size) {
395 			LOG_WRN("USB IN EP%d len too big (%d->%d)", ep_idx,
396 				data_len, max_xfer_size);
397 			data_len = max_xfer_size;
398 		}
399 
400 		/*
401 		 * Program the transfer size and packet count as follows:
402 		 *
403 		 * transfer size = N * ep_maxpacket + short_packet
404 		 * pktcnt = N + (short_packet exist ? 1 : 0)
405 		 */
406 
407 		pkt_cnt = (data_len + ep_mps - 1) / ep_mps;
408 		if (pkt_cnt > max_pkt_cnt) {
409 			LOG_WRN("USB IN EP%d pkt count too big (%d->%d)",
410 				ep_idx, pkt_cnt, pkt_cnt);
411 			pkt_cnt = max_pkt_cnt;
412 			data_len = pkt_cnt * ep_mps;
413 		}
414 	} else {
415 		/* Zero length packet */
416 		pkt_cnt = 1U;
417 	}
418 
419 	/* Set number of packets and transfer size */
420 	USB_DW->in_ep_reg[ep_idx].dieptsiz =
421 		(pkt_cnt << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | data_len;
422 
423 	/* Clear NAK and enable ep */
424 	USB_DW->in_ep_reg[ep_idx].diepctl |= (USB_DW_DEPCTL_EP_ENA |
425 					      USB_DW_DEPCTL_CNAK);
426 
427 	/*
428 	 * Write data to FIFO, make sure that we are protected against
429 	 * other USB register accesses.  According to "DesignWare Cores
430 	 * USB 1.1/2.0 Device Subsystem-AHB/VCI Databook": "During FIFO
431 	 * access, the application must not access the UDC/Subsystem
432 	 * registers or vendor registers (for ULPI mode). After starting
433 	 * to access a FIFO, the application must complete the transaction
434 	 * before accessing the register."
435 	 */
436 	for (i = 0U; i < data_len; i += 4U) {
437 		uint32_t val = data[i];
438 
439 		if (i + 1 < data_len) {
440 			val |= ((uint32_t)data[i+1]) << 8;
441 		}
442 		if (i + 2 < data_len) {
443 			val |= ((uint32_t)data[i+2]) << 16;
444 		}
445 		if (i + 3 < data_len) {
446 			val |= ((uint32_t)data[i+3]) << 24;
447 		}
448 
449 		USB_DW_EP_FIFO(ep_idx) = val;
450 	}
451 
452 	irq_unlock(key);
453 
454 	LOG_DBG("USB IN EP%d write %u bytes", ep_idx, data_len);
455 
456 	return data_len;
457 }
458 
usb_dw_init(void)459 static int usb_dw_init(void)
460 {
461 	uint8_t ep;
462 	int ret;
463 
464 	ret = usb_dw_reset();
465 	if (ret) {
466 		return ret;
467 	}
468 
469 #ifdef CONFIG_USB_DW_USB_2_0
470 	/* set the PHY interface to be 16-bit UTMI */
471 	USB_DW->gusbcfg = (USB_DW->gusbcfg & ~USB_DW_GUSBCFG_PHY_IF_MASK) |
472 		USB_DW_GUSBCFG_PHY_IF_16_BIT;
473 
474 	/* Set USB2.0 High Speed */
475 	USB_DW->dcfg |= USB_DW_DCFG_DEV_SPD_USB2_HS;
476 #else
477 	/* Set device speed to Full Speed */
478 	USB_DW->dcfg |= USB_DW_DCFG_DEV_SPD_FS;
479 #endif
480 
481 	/* Set NAK for all OUT EPs */
482 	for (ep = 0U; ep < USB_DW_OUT_EP_NUM; ep++) {
483 		USB_DW->out_ep_reg[ep].doepctl = USB_DW_DEPCTL_SNAK;
484 	}
485 
486 	/* Enable global interrupts */
487 	USB_DW->gintmsk = USB_DW_GINTSTS_OEP_INT |
488 		USB_DW_GINTSTS_IEP_INT |
489 		USB_DW_GINTSTS_ENUM_DONE |
490 		USB_DW_GINTSTS_USB_RST |
491 		USB_DW_GINTSTS_WK_UP_INT |
492 		USB_DW_GINTSTS_USB_SUSP;
493 
494 	/* Enable global interrupt */
495 	USB_DW->gahbcfg |= USB_DW_GAHBCFG_GLB_INTR_MASK;
496 
497 	/* Disable soft disconnect */
498 	USB_DW->dctl &= ~USB_DW_DCTL_SFT_DISCON;
499 
500 	usb_dw_reg_dump();
501 
502 	return 0;
503 }
504 
usb_dw_handle_reset(void)505 static void usb_dw_handle_reset(void)
506 {
507 	LOG_DBG("USB RESET event");
508 
509 	/* Inform upper layers */
510 	if (usb_dw_ctrl.status_cb) {
511 		usb_dw_ctrl.status_cb(USB_DC_RESET, NULL);
512 	}
513 
514 	/* Clear device address during reset. */
515 	USB_DW->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK;
516 
517 	/* enable global EP interrupts */
518 	USB_DW->doepmsk = 0U;
519 	USB_DW->gintmsk |= USB_DW_GINTSTS_RX_FLVL;
520 	USB_DW->diepmsk |= USB_DW_DIEPINT_XFER_COMPL;
521 }
522 
usb_dw_handle_enum_done(void)523 static void usb_dw_handle_enum_done(void)
524 {
525 	uint32_t speed;
526 
527 	speed = (USB_DW->dsts & ~USB_DW_DSTS_ENUM_SPD_MASK) >>
528 	    USB_DW_DSTS_ENUM_SPD_OFFSET;
529 
530 	LOG_DBG("USB ENUM DONE event, %s speed detected",
531 		speed == USB_DW_DSTS_ENUM_LS ? "Low" : "Full");
532 
533 	/* Inform upper layers */
534 	if (usb_dw_ctrl.status_cb) {
535 		usb_dw_ctrl.status_cb(USB_DC_CONNECTED, NULL);
536 	}
537 }
538 
539 /* USB ISR handler */
usb_dw_int_rx_flvl_handler(void)540 static inline void usb_dw_int_rx_flvl_handler(void)
541 {
542 	uint32_t grxstsp = USB_DW->grxstsp;
543 	uint32_t status, xfer_size;
544 	uint8_t ep_idx;
545 	usb_dc_ep_callback ep_cb;
546 
547 	/* Packet in RX FIFO */
548 
549 	ep_idx = grxstsp & USB_DW_GRXSTSR_EP_NUM_MASK;
550 	status = (grxstsp & USB_DW_GRXSTSR_PKT_STS_MASK) >>
551 		USB_DW_GRXSTSR_PKT_STS_OFFSET;
552 	xfer_size = (grxstsp & USB_DW_GRXSTSR_PKT_CNT_MASK) >>
553 		USB_DW_GRXSTSR_PKT_CNT_OFFSET;
554 
555 	LOG_DBG("USB OUT EP%u: RX_FLVL status %u, size %u",
556 		ep_idx, status, xfer_size);
557 
558 	usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len = xfer_size;
559 	ep_cb = usb_dw_ctrl.out_ep_ctrl[ep_idx].cb;
560 
561 	switch (status) {
562 	case USB_DW_GRXSTSR_PKT_STS_SETUP:
563 		/* Call the registered callback if any */
564 		if (ep_cb) {
565 			ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT),
566 			      USB_DC_EP_SETUP);
567 		}
568 
569 		break;
570 	case USB_DW_GRXSTSR_PKT_STS_OUT_DATA:
571 		if (ep_cb) {
572 			ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT),
573 			      USB_DC_EP_DATA_OUT);
574 		}
575 
576 		break;
577 	case USB_DW_GRXSTSR_PKT_STS_OUT_DATA_DONE:
578 	case USB_DW_GRXSTSR_PKT_STS_SETUP_DONE:
579 		break;
580 	default:
581 		break;
582 	}
583 }
584 
usb_dw_int_iep_handler(void)585 static inline void usb_dw_int_iep_handler(void)
586 {
587 	uint32_t ep_int_status;
588 	uint8_t ep_idx;
589 	usb_dc_ep_callback ep_cb;
590 
591 	for (ep_idx = 0U; ep_idx < USB_DW_IN_EP_NUM; ep_idx++) {
592 		if (USB_DW->daint & USB_DW_DAINT_IN_EP_INT(ep_idx)) {
593 			/* Read IN EP interrupt status */
594 			ep_int_status = USB_DW->in_ep_reg[ep_idx].diepint &
595 				USB_DW->diepmsk;
596 
597 			/* Clear IN EP interrupts */
598 			USB_DW->in_ep_reg[ep_idx].diepint = ep_int_status;
599 
600 			LOG_DBG("USB IN EP%u interrupt status: 0x%x",
601 				ep_idx, ep_int_status);
602 
603 			ep_cb = usb_dw_ctrl.in_ep_ctrl[ep_idx].cb;
604 			if (ep_cb &&
605 			    (ep_int_status & USB_DW_DIEPINT_XFER_COMPL)) {
606 
607 				/* Call the registered callback */
608 				ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_IN),
609 				      USB_DC_EP_DATA_IN);
610 			}
611 		}
612 	}
613 
614 	/* Clear interrupt. */
615 	USB_DW->gintsts = USB_DW_GINTSTS_IEP_INT;
616 }
617 
usb_dw_int_oep_handler(void)618 static inline void usb_dw_int_oep_handler(void)
619 {
620 	uint32_t ep_int_status;
621 	uint8_t ep_idx;
622 
623 	for (ep_idx = 0U; ep_idx < USB_DW_OUT_EP_NUM; ep_idx++) {
624 		if (USB_DW->daint & USB_DW_DAINT_OUT_EP_INT(ep_idx)) {
625 			/* Read OUT EP interrupt status */
626 			ep_int_status = USB_DW->out_ep_reg[ep_idx].doepint &
627 				USB_DW->doepmsk;
628 
629 			/* Clear OUT EP interrupts */
630 			USB_DW->out_ep_reg[ep_idx].doepint = ep_int_status;
631 
632 			LOG_DBG("USB OUT EP%u interrupt status: 0x%x\n",
633 				ep_idx, ep_int_status);
634 		}
635 	}
636 
637 	/* Clear interrupt. */
638 	USB_DW->gintsts = USB_DW_GINTSTS_OEP_INT;
639 }
640 
usb_dw_isr_handler(const void * unused)641 static void usb_dw_isr_handler(const void *unused)
642 {
643 	uint32_t int_status;
644 
645 	ARG_UNUSED(unused);
646 
647 	/*  Read interrupt status */
648 	while ((int_status = (USB_DW->gintsts & USB_DW->gintmsk))) {
649 
650 		LOG_DBG("USB GINTSTS 0x%x", int_status);
651 
652 		if (int_status & USB_DW_GINTSTS_USB_RST) {
653 			/* Clear interrupt. */
654 			USB_DW->gintsts = USB_DW_GINTSTS_USB_RST;
655 
656 			/* Reset detected */
657 			usb_dw_handle_reset();
658 		}
659 
660 		if (int_status & USB_DW_GINTSTS_ENUM_DONE) {
661 			/* Clear interrupt. */
662 			USB_DW->gintsts = USB_DW_GINTSTS_ENUM_DONE;
663 
664 			/* Enumeration done detected */
665 			usb_dw_handle_enum_done();
666 		}
667 
668 		if (int_status & USB_DW_GINTSTS_USB_SUSP) {
669 			/* Clear interrupt. */
670 			USB_DW->gintsts = USB_DW_GINTSTS_USB_SUSP;
671 
672 			if (usb_dw_ctrl.status_cb) {
673 				usb_dw_ctrl.status_cb(USB_DC_SUSPEND, NULL);
674 			}
675 		}
676 
677 		if (int_status & USB_DW_GINTSTS_WK_UP_INT) {
678 			/* Clear interrupt. */
679 			USB_DW->gintsts = USB_DW_GINTSTS_WK_UP_INT;
680 
681 			if (usb_dw_ctrl.status_cb) {
682 				usb_dw_ctrl.status_cb(USB_DC_RESUME, NULL);
683 			}
684 		}
685 
686 		if (int_status & USB_DW_GINTSTS_RX_FLVL) {
687 			/* Packet in RX FIFO */
688 			usb_dw_int_rx_flvl_handler();
689 		}
690 
691 		if (int_status & USB_DW_GINTSTS_IEP_INT) {
692 			/* IN EP interrupt */
693 			usb_dw_int_iep_handler();
694 		}
695 
696 		if (int_status & USB_DW_GINTSTS_OEP_INT) {
697 			/* No OUT interrupt expected in FIFO mode,
698 			 * just clear interruot
699 			 */
700 			usb_dw_int_oep_handler();
701 		}
702 	}
703 }
704 
usb_dc_attach(void)705 int usb_dc_attach(void)
706 {
707 	int ret;
708 
709 	if (usb_dw_ctrl.attached) {
710 		return 0;
711 	}
712 
713 	ret = usb_dw_init();
714 	if (ret) {
715 		return ret;
716 	}
717 
718 	/* Connect and enable USB interrupt */
719 	IRQ_CONNECT(DT_INST_IRQN(0),
720 		    DT_INST_IRQ(0, priority),
721 		    usb_dw_isr_handler, 0,
722 		    DT_INST_IRQ(0, sense));
723 	irq_enable(DT_INST_IRQN(0));
724 
725 	usb_dw_ctrl.attached = 1U;
726 
727 	return 0;
728 }
729 
usb_dc_detach(void)730 int usb_dc_detach(void)
731 {
732 	if (!usb_dw_ctrl.attached) {
733 		return 0;
734 	}
735 
736 	irq_disable(DT_INST_IRQN(0));
737 
738 	/* Enable soft disconnect */
739 	USB_DW->dctl |= USB_DW_DCTL_SFT_DISCON;
740 
741 	usb_dw_ctrl.attached = 0U;
742 
743 	return 0;
744 }
745 
usb_dc_reset(void)746 int usb_dc_reset(void)
747 {
748 	int ret;
749 
750 	ret = usb_dw_reset();
751 
752 	/* Clear private data */
753 	(void)memset(&usb_dw_ctrl, 0, sizeof(usb_dw_ctrl));
754 
755 	return ret;
756 }
757 
usb_dc_set_address(const uint8_t addr)758 int usb_dc_set_address(const uint8_t addr)
759 {
760 	if (addr > (USB_DW_DCFG_DEV_ADDR_MASK >> USB_DW_DCFG_DEV_ADDR_OFFSET)) {
761 		return -EINVAL;
762 	}
763 
764 	USB_DW->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK;
765 	USB_DW->dcfg |= addr << USB_DW_DCFG_DEV_ADDR_OFFSET;
766 
767 	return 0;
768 }
769 
usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)770 int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)
771 {
772 	uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
773 
774 	LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps,
775 		cfg->ep_type);
776 
777 	if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx) {
778 		LOG_ERR("invalid endpoint configuration");
779 		return -1;
780 	}
781 
782 	if (cfg->ep_mps > DW_USB_MAX_PACKET_SIZE) {
783 		LOG_WRN("unsupported packet size");
784 		return -1;
785 	}
786 
787 	if ((USB_EP_DIR_IS_OUT(cfg->ep_addr)) &&
788 	    (ep_idx >= DW_USB_OUT_EP_NUM)) {
789 		LOG_WRN("OUT endpoint address out of range");
790 		return -1;
791 	}
792 
793 	if ((USB_EP_DIR_IS_IN(cfg->ep_addr)) &&
794 	    (ep_idx >= DW_USB_IN_EP_NUM)) {
795 		LOG_WRN("IN endpoint address out of range");
796 		return -1;
797 	}
798 
799 	return 0;
800 }
801 
usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)802 int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)
803 {
804 	uint8_t ep;
805 
806 	if (!ep_cfg) {
807 		return -EINVAL;
808 	}
809 
810 	ep = ep_cfg->ep_addr;
811 
812 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
813 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
814 		return -EINVAL;
815 	}
816 
817 	usb_dw_ep_set(ep, ep_cfg->ep_mps, ep_cfg->ep_type);
818 
819 	return 0;
820 }
821 
usb_dc_ep_set_stall(const uint8_t ep)822 int usb_dc_ep_set_stall(const uint8_t ep)
823 {
824 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
825 
826 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
827 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
828 		return -EINVAL;
829 	}
830 
831 	if (USB_EP_DIR_IS_OUT(ep)) {
832 		USB_DW->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_STALL;
833 	} else {
834 		USB_DW->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_STALL;
835 	}
836 
837 	return 0;
838 }
839 
usb_dc_ep_clear_stall(const uint8_t ep)840 int usb_dc_ep_clear_stall(const uint8_t ep)
841 {
842 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
843 
844 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
845 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
846 		return -EINVAL;
847 	}
848 
849 	if (!ep_idx) {
850 		/* Not possible to clear stall for EP0 */
851 		return -EINVAL;
852 	}
853 
854 	if (USB_EP_DIR_IS_OUT(ep)) {
855 		USB_DW->out_ep_reg[ep_idx].doepctl &= ~USB_DW_DEPCTL_STALL;
856 	} else {
857 		USB_DW->in_ep_reg[ep_idx].diepctl &= ~USB_DW_DEPCTL_STALL;
858 	}
859 
860 	return 0;
861 }
862 
usb_dc_ep_halt(const uint8_t ep)863 int usb_dc_ep_halt(const uint8_t ep)
864 {
865 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
866 	volatile uint32_t *p_depctl;
867 
868 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
869 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
870 		return -EINVAL;
871 	}
872 
873 	if (!ep_idx) {
874 		/* Cannot disable EP0, just set stall */
875 		usb_dc_ep_set_stall(ep);
876 	} else {
877 		if (USB_EP_DIR_IS_OUT(ep)) {
878 			p_depctl = &USB_DW->out_ep_reg[ep_idx].doepctl;
879 		} else {
880 			p_depctl = &USB_DW->in_ep_reg[ep_idx].diepctl;
881 		}
882 
883 		/* Set STALL and disable endpoint if enabled */
884 		if (*p_depctl & USB_DW_DEPCTL_EP_ENA) {
885 			*p_depctl |= USB_DW_DEPCTL_EP_DIS | USB_DW_DEPCTL_STALL;
886 		} else {
887 			*p_depctl |= USB_DW_DEPCTL_STALL;
888 		}
889 	}
890 
891 	return 0;
892 }
893 
usb_dc_ep_is_stalled(const uint8_t ep,uint8_t * const stalled)894 int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled)
895 {
896 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
897 
898 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
899 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
900 		return -EINVAL;
901 	}
902 
903 	if (!stalled) {
904 		return -EINVAL;
905 	}
906 
907 	*stalled = 0U;
908 	if (USB_EP_DIR_IS_OUT(ep)) {
909 		if (USB_DW->out_ep_reg[ep_idx].doepctl & USB_DW_DEPCTL_STALL) {
910 			*stalled = 1U;
911 		}
912 	} else {
913 		if (USB_DW->in_ep_reg[ep_idx].diepctl & USB_DW_DEPCTL_STALL) {
914 			*stalled = 1U;
915 		}
916 	}
917 
918 	return 0;
919 }
920 
usb_dc_ep_enable(const uint8_t ep)921 int usb_dc_ep_enable(const uint8_t ep)
922 {
923 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
924 
925 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
926 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
927 		return -EINVAL;
928 	}
929 
930 	/* enable EP interrupts */
931 	if (USB_EP_DIR_IS_OUT(ep)) {
932 		USB_DW->daintmsk |= USB_DW_DAINT_OUT_EP_INT(ep_idx);
933 	} else {
934 		USB_DW->daintmsk |= USB_DW_DAINT_IN_EP_INT(ep_idx);
935 	}
936 
937 	/* Activate Ep */
938 	if (USB_EP_DIR_IS_OUT(ep)) {
939 		USB_DW->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_USB_ACT_EP;
940 		usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1U;
941 	} else {
942 		USB_DW->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_USB_ACT_EP;
943 		usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1U;
944 	}
945 
946 	if (USB_EP_DIR_IS_OUT(ep) &&
947 	    usb_dw_ctrl.out_ep_ctrl[ep_idx].cb != usb_transfer_ep_callback) {
948 		/* Start reading now, except for transfer managed eps */
949 		usb_dw_prep_rx(ep, 0);
950 	}
951 
952 	return 0;
953 }
954 
usb_dc_ep_disable(const uint8_t ep)955 int usb_dc_ep_disable(const uint8_t ep)
956 {
957 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
958 
959 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
960 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
961 		return -EINVAL;
962 	}
963 
964 	/* Disable EP interrupts */
965 	if (USB_EP_DIR_IS_OUT(ep)) {
966 		USB_DW->daintmsk &= ~USB_DW_DAINT_OUT_EP_INT(ep_idx);
967 		USB_DW->doepmsk &= ~USB_DW_DOEPINT_SET_UP;
968 	} else {
969 		USB_DW->daintmsk &= ~USB_DW_DAINT_IN_EP_INT(ep_idx);
970 		USB_DW->diepmsk &= ~USB_DW_DIEPINT_XFER_COMPL;
971 		USB_DW->gintmsk &= ~USB_DW_GINTSTS_RX_FLVL;
972 	}
973 
974 	/* De-activate, disable and set NAK for Ep */
975 	if (USB_EP_DIR_IS_OUT(ep)) {
976 		USB_DW->out_ep_reg[ep_idx].doepctl &=
977 		    ~(USB_DW_DEPCTL_USB_ACT_EP |
978 		    USB_DW_DEPCTL_EP_ENA |
979 		    USB_DW_DEPCTL_SNAK);
980 		usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 0U;
981 	} else {
982 		USB_DW->in_ep_reg[ep_idx].diepctl &=
983 		    ~(USB_DW_DEPCTL_USB_ACT_EP |
984 		    USB_DW_DEPCTL_EP_ENA |
985 		    USB_DW_DEPCTL_SNAK);
986 		usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 0U;
987 	}
988 
989 	return 0;
990 }
991 
usb_dc_ep_flush(const uint8_t ep)992 int usb_dc_ep_flush(const uint8_t ep)
993 {
994 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
995 	uint32_t cnt;
996 
997 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
998 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
999 		return -EINVAL;
1000 	}
1001 
1002 	if (USB_EP_DIR_IS_OUT(ep)) {
1003 		/* RX FIFO is global and cannot be flushed per EP */
1004 		return -EINVAL;
1005 	}
1006 
1007 	/* Each endpoint has dedicated Tx FIFO */
1008 	USB_DW->grstctl |= ep_idx << USB_DW_GRSTCTL_TX_FNUM_OFFSET;
1009 	USB_DW->grstctl |= USB_DW_GRSTCTL_TX_FFLSH;
1010 
1011 	cnt = 0U;
1012 
1013 	do {
1014 		if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
1015 			LOG_ERR("USB TX FIFO flush HANG!");
1016 			return -EIO;
1017 		}
1018 		usb_dw_udelay(1);
1019 	} while (USB_DW->grstctl & USB_DW_GRSTCTL_TX_FFLSH);
1020 
1021 	return 0;
1022 }
1023 
usb_dc_ep_write(const uint8_t ep,const uint8_t * const data,const uint32_t data_len,uint32_t * const ret_bytes)1024 int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data,
1025 		    const uint32_t data_len, uint32_t * const ret_bytes)
1026 {
1027 	int ret;
1028 
1029 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1030 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1031 		return -EINVAL;
1032 	}
1033 
1034 	/* Check if IN ep */
1035 	if (USB_EP_GET_DIR(ep) != USB_EP_DIR_IN) {
1036 		return -EINVAL;
1037 	}
1038 
1039 	/* Check if ep enabled */
1040 	if (!usb_dw_ep_is_enabled(ep)) {
1041 		return -EINVAL;
1042 	}
1043 
1044 	ret = usb_dw_tx(ep, data, data_len);
1045 	if (ret < 0) {
1046 		return ret;
1047 	}
1048 
1049 	if (ret_bytes) {
1050 		*ret_bytes = ret;
1051 	}
1052 
1053 	return 0;
1054 }
1055 
usb_dc_ep_read_wait(uint8_t ep,uint8_t * data,uint32_t max_data_len,uint32_t * read_bytes)1056 int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len,
1057 			uint32_t *read_bytes)
1058 {
1059 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
1060 	uint32_t i, j, data_len, bytes_to_copy;
1061 
1062 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1063 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1064 		return -EINVAL;
1065 	}
1066 
1067 	/* Check if OUT ep */
1068 	if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
1069 		LOG_ERR("Wrong endpoint direction");
1070 		return -EINVAL;
1071 	}
1072 
1073 	/* Allow to read 0 bytes */
1074 	if (!data && max_data_len) {
1075 		LOG_ERR("Wrong arguments");
1076 		return -EINVAL;
1077 	}
1078 
1079 	/* Check if ep enabled */
1080 	if (!usb_dw_ep_is_enabled(ep)) {
1081 		LOG_ERR("Not enabled endpoint");
1082 		return -EINVAL;
1083 	}
1084 
1085 	data_len = usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len;
1086 
1087 	if (!data && !max_data_len) {
1088 		/* When both buffer and max data to read are zero return
1089 		 * the available data in buffer
1090 		 */
1091 		if (read_bytes) {
1092 			*read_bytes = data_len;
1093 		}
1094 		return 0;
1095 	}
1096 
1097 
1098 	if (data_len > max_data_len) {
1099 		LOG_ERR("Not enough room to copy all the rcvd data!");
1100 		bytes_to_copy = max_data_len;
1101 	} else {
1102 		bytes_to_copy = data_len;
1103 	}
1104 
1105 	LOG_DBG("Read EP%d, req %d, read %d bytes", ep, max_data_len,
1106 		bytes_to_copy);
1107 
1108 	/* Data in the FIFOs is always stored per 32-bit words */
1109 	for (i = 0U; i < (bytes_to_copy & ~0x3); i += 4U) {
1110 		*(uint32_t *)(data + i) = USB_DW_EP_FIFO(ep_idx);
1111 	}
1112 	if (bytes_to_copy & 0x3) {
1113 		/* Not multiple of 4 */
1114 		uint32_t last_dw = USB_DW_EP_FIFO(ep_idx);
1115 
1116 		for (j = 0U; j < (bytes_to_copy & 0x3); j++) {
1117 			*(data + i + j) =
1118 				(sys_cpu_to_le32(last_dw) >> (j * 8U)) & 0xFF;
1119 			}
1120 	}
1121 
1122 	usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len -= bytes_to_copy;
1123 
1124 	if (read_bytes) {
1125 		*read_bytes = bytes_to_copy;
1126 	}
1127 
1128 	return 0;
1129 
1130 }
1131 
usb_dc_ep_read_continue(uint8_t ep)1132 int usb_dc_ep_read_continue(uint8_t ep)
1133 {
1134 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
1135 
1136 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1137 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1138 		return -EINVAL;
1139 	}
1140 
1141 	/* Check if OUT ep */
1142 	if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
1143 		LOG_ERR("Wrong endpoint direction");
1144 		return -EINVAL;
1145 	}
1146 
1147 	if (!usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len) {
1148 		usb_dw_prep_rx(ep_idx, 0);
1149 	}
1150 
1151 	return 0;
1152 }
1153 
usb_dc_ep_read(const uint8_t ep,uint8_t * const data,const uint32_t max_data_len,uint32_t * const read_bytes)1154 int usb_dc_ep_read(const uint8_t ep, uint8_t *const data,
1155 		const uint32_t max_data_len, uint32_t * const read_bytes)
1156 {
1157 	if (usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes) != 0) {
1158 		return -EINVAL;
1159 	}
1160 
1161 	if (!data && !max_data_len) {
1162 		/* When both buffer and max data to read are zero the above
1163 		 * call would fetch the data len and we simply return.
1164 		 */
1165 		return 0;
1166 	}
1167 
1168 	if (usb_dc_ep_read_continue(ep) != 0) {
1169 		return -EINVAL;
1170 	}
1171 
1172 	return 0;
1173 }
1174 
usb_dc_ep_set_callback(const uint8_t ep,const usb_dc_ep_callback cb)1175 int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
1176 {
1177 	uint8_t ep_idx = USB_EP_GET_IDX(ep);
1178 
1179 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1180 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1181 		return -EINVAL;
1182 	}
1183 
1184 	if (USB_EP_DIR_IS_IN(ep)) {
1185 		usb_dw_ctrl.in_ep_ctrl[ep_idx].cb = cb;
1186 	} else {
1187 		usb_dw_ctrl.out_ep_ctrl[ep_idx].cb = cb;
1188 	}
1189 
1190 	return 0;
1191 }
1192 
usb_dc_set_status_callback(const usb_dc_status_callback cb)1193 void usb_dc_set_status_callback(const usb_dc_status_callback cb)
1194 {
1195 	usb_dw_ctrl.status_cb = cb;
1196 }
1197 
usb_dc_ep_mps(const uint8_t ep)1198 int usb_dc_ep_mps(const uint8_t ep)
1199 {
1200 	enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep);
1201 
1202 	if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1203 		LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1204 		return -EINVAL;
1205 	}
1206 
1207 	if (USB_EP_DIR_IS_OUT(ep)) {
1208 		return usb_dw_ctrl.out_ep_ctrl[ep_idx].mps;
1209 	} else {
1210 		return usb_dw_ctrl.in_ep_ctrl[ep_idx].mps;
1211 	}
1212 }
1213