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