Lines Matching +full:interrupt +full:- +full:endpoint
5 * SPDX-License-Identifier: Apache-2.0
43 * There is no real advantage to change control endpoint size
50 * Buffer Descriptor (BD) entry provides endpoint buffer control
51 * information for USBFSOTG controller. Every endpoint direction requires
84 * per endpoint and 512 bytes of memory.
99 /* OUT transaction for specific endpoint is finished */
101 /* IN transaction for specific endpoint is finished */
107 /* Structure for driver's endpoint events */
132 /* Get buffer descriptor (BD) based on endpoint address */
137 const struct usbfsotg_config *config = dev->config; in usbfsotg_get_ebd()
140 bd_idx = USB_EP_GET_IDX(cfg->addr) * 4U + (cfg->stat.odd ^ opposite); in usbfsotg_get_ebd()
141 if (USB_EP_DIR_IS_IN(cfg->addr)) { in usbfsotg_get_ebd()
145 return &config->bdt[bd_idx]; in usbfsotg_get_ebd()
150 /* Do not use it for control OUT endpoint */ in usbfsotg_bd_is_busy()
151 return bd->get.own; in usbfsotg_bd_is_busy()
159 bd->set.bc = bc; in usbfsotg_bd_set_ctrl()
160 bd->buf_addr = POINTER_TO_UINT(data); in usbfsotg_bd_set_ctrl()
163 bd->set.bd_ctrl = USBFSOTG_BD_OWN | USBFSOTG_BD_DATA1 | in usbfsotg_bd_set_ctrl()
166 bd->set.bd_ctrl = USBFSOTG_BD_OWN | USBFSOTG_BD_DTS; in usbfsotg_bd_set_ctrl()
174 const struct usbfsotg_config *config = dev->config; in usbfsotg_resume_tx()
175 USB_Type *base = config->base; in usbfsotg_resume_tx()
177 base->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; in usbfsotg_resume_tx()
184 const struct usbfsotg_config *config = dev->config; in usbfsotg_xfer_continue()
185 USB_Type *base = config->base; in usbfsotg_xfer_continue()
192 LOG_ERR("ep 0x%02x buf busy", cfg->addr); in usbfsotg_xfer_continue()
194 return -EBUSY; in usbfsotg_xfer_continue()
197 if (USB_EP_DIR_IS_OUT(cfg->addr)) { in usbfsotg_xfer_continue()
201 len = MIN(buf->len, udc_mps_ep_size(cfg)); in usbfsotg_xfer_continue()
202 data_ptr = buf->data; in usbfsotg_xfer_continue()
205 usbfsotg_bd_set_ctrl(bd, len, data_ptr, cfg->stat.data1); in usbfsotg_xfer_continue()
207 if (USB_EP_GET_IDX(cfg->addr) == 0U) { in usbfsotg_xfer_continue()
212 buf, bd, base->ENDPOINT[USB_EP_GET_IDX(cfg->addr)].ENDPT, in usbfsotg_xfer_continue()
213 bd->bd_fields); in usbfsotg_xfer_continue()
218 /* Initiate a new transfer, must not be used for control endpoint OUT */
224 buf = udc_buf_peek(dev, cfg->addr); in usbfsotg_xfer_next()
226 return -ENODATA; in usbfsotg_xfer_next()
241 if (priv->busy[cfg->stat.odd]) { in usbfsotg_ctrl_feed_start()
242 return -EBUSY; in usbfsotg_ctrl_feed_start()
248 priv->out_buf[cfg->stat.odd] = buf; in usbfsotg_ctrl_feed_start()
249 priv->busy[cfg->stat.odd] = true; in usbfsotg_ctrl_feed_start()
250 usbfsotg_bd_set_ctrl(bd, length, net_buf_tail(buf), cfg->stat.data1); in usbfsotg_ctrl_feed_start()
251 LOG_DBG("ep0 %p|odd: %u|d: %u", buf, cfg->stat.odd, cfg->stat.data1); in usbfsotg_ctrl_feed_start()
265 if (priv->busy[!cfg->stat.odd]) { in usbfsotg_ctrl_feed_start_next()
266 return -EBUSY; in usbfsotg_ctrl_feed_start_next()
272 priv->out_buf[!cfg->stat.odd] = buf; in usbfsotg_ctrl_feed_start_next()
273 priv->busy[!cfg->stat.odd] = true; in usbfsotg_ctrl_feed_start_next()
274 usbfsotg_bd_set_ctrl(bd, length, net_buf_tail(buf), cfg->stat.data1); in usbfsotg_ctrl_feed_start_next()
275 LOG_DBG("ep0 %p|odd: %u|d: %u (n)", buf, cfg->stat.odd, cfg->stat.data1); in usbfsotg_ctrl_feed_start_next()
294 return -ENOMEM; in usbfsotg_ctrl_feed_dout()
322 return -ENODATA; in work_handler_setup()
330 LOG_DBG("s:%p|feed for -out-", buf); in work_handler_setup()
333 if (err == -ENOMEM) { in work_handler_setup()
342 LOG_DBG("s:%p|feed for -in-status >setup", buf); in work_handler_setup()
375 return -ENODATA; in work_handler_out()
380 /* s-in-status finished, next bd is already fed */ in work_handler_out()
413 return -ENODATA; in work_handler_in()
455 ev->dev = dev; in usbfsotg_event_submit()
456 ev->ep = ep; in usbfsotg_event_submit()
457 ev->event = event; in usbfsotg_event_submit()
458 k_fifo_put(&priv->fifo, ev); in usbfsotg_event_submit()
459 k_work_submit_to_queue(udc_get_work_q(), &priv->work); in usbfsotg_event_submit()
468 while ((ev = k_fifo_get(&priv->fifo, K_NO_WAIT)) != NULL) { in xfer_work_handler()
473 ev->dev, ev->ep, ev->event); in xfer_work_handler()
474 ep_cfg = udc_get_ep_cfg(ev->dev, ev->ep); in xfer_work_handler()
476 udc_submit_event(ev->dev, UDC_EVT_ERROR, -ENODATA); in xfer_work_handler()
480 switch (ev->event) { in xfer_work_handler()
482 err = work_handler_setup(ev->dev); in xfer_work_handler()
485 err = work_handler_out(ev->dev, ev->ep); in xfer_work_handler()
486 udc_ep_set_busy(ev->dev, ev->ep, false); in xfer_work_handler()
489 err = work_handler_in(ev->dev, ev->ep); in xfer_work_handler()
490 udc_ep_set_busy(ev->dev, ev->ep, false); in xfer_work_handler()
493 err = usbfsotg_ep_clear_halt(ev->dev, ep_cfg); in xfer_work_handler()
500 udc_submit_event(ev->dev, UDC_EVT_ERROR, err); in xfer_work_handler()
504 if (ev->ep != USB_CONTROL_EP_OUT && !udc_ep_is_busy(ev->dev, ev->ep)) { in xfer_work_handler()
505 if (usbfsotg_xfer_next(ev->dev, ep_cfg) == 0) { in xfer_work_handler()
506 udc_ep_set_busy(ev->dev, ev->ep, true); in xfer_work_handler()
532 ep_cfg->stat.data1 = true; in set_control_in_pid_data1()
552 token_pid = bd->get.tok_pid; in isr_handle_xfer_done()
553 len = bd->get.bc; in isr_handle_xfer_done()
554 data1 = bd->get.data1 ? true : false; in isr_handle_xfer_done()
561 ep_cfg->stat.odd = !odd; in isr_handle_xfer_done()
562 ep_cfg->stat.data1 = true; in isr_handle_xfer_done()
565 if (priv->out_buf[odd] != NULL) { in isr_handle_xfer_done()
566 net_buf_add(priv->out_buf[odd], len); in isr_handle_xfer_done()
567 udc_ep_buf_set_setup(priv->out_buf[odd]); in isr_handle_xfer_done()
568 udc_buf_put(ep_cfg, priv->out_buf[odd]); in isr_handle_xfer_done()
569 priv->busy[odd] = false; in isr_handle_xfer_done()
570 priv->out_buf[odd] = NULL; in isr_handle_xfer_done()
574 udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); in isr_handle_xfer_done()
579 ep_cfg->stat.odd = !odd; in isr_handle_xfer_done()
580 ep_cfg->stat.data1 = !data1; in isr_handle_xfer_done()
583 buf = priv->out_buf[odd]; in isr_handle_xfer_done()
584 priv->busy[odd] = false; in isr_handle_xfer_done()
585 priv->out_buf[odd] = NULL; in isr_handle_xfer_done()
587 buf = udc_buf_peek(dev, ep_cfg->addr); in isr_handle_xfer_done()
592 udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); in isr_handle_xfer_done()
614 ep_cfg->stat.odd = !odd; in isr_handle_xfer_done()
615 ep_cfg->stat.data1 = !data1; in isr_handle_xfer_done()
617 buf = udc_buf_peek(dev, ep_cfg->addr); in isr_handle_xfer_done()
620 udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); in isr_handle_xfer_done()
625 if (buf->len) { in isr_handle_xfer_done()
645 const struct usbfsotg_config *config = dev->config; in usbfsotg_isr_handler()
646 USB_Type *base = config->base; in usbfsotg_isr_handler()
647 const uint8_t istatus = base->ISTAT; in usbfsotg_isr_handler()
648 const uint8_t status = base->STAT; in usbfsotg_isr_handler()
651 base->ADDR = 0U; in usbfsotg_isr_handler()
660 LOG_DBG("ERROR IRQ 0x%02x", base->ERRSTAT); in usbfsotg_isr_handler()
661 udc_submit_event(dev, UDC_EVT_ERROR, base->ERRSTAT); in usbfsotg_isr_handler()
662 base->ERRSTAT = 0xFF; in usbfsotg_isr_handler()
671 if (ep_cfg->stat.halted) { in usbfsotg_isr_handler()
681 if (ep_cfg->stat.halted) { in usbfsotg_isr_handler()
693 /* Enable resume interrupt */ in usbfsotg_isr_handler()
694 base->INTEN |= USB_INTEN_RESUMEEN_MASK; in usbfsotg_isr_handler()
702 /* Disable resume interrupt */ in usbfsotg_isr_handler()
703 base->INTEN &= ~USB_INTEN_RESUMEEN_MASK; in usbfsotg_isr_handler()
709 /* Clear interrupt status bits */ in usbfsotg_isr_handler()
710 base->ISTAT = istatus; in usbfsotg_isr_handler()
719 if (cfg->stat.halted) { in usbfsotg_ep_enqueue()
720 LOG_DBG("ep 0x%02x halted", cfg->addr); in usbfsotg_ep_enqueue()
724 usbfsotg_event_submit(dev, cfg->addr, USBFSOTG_EVT_XFER); in usbfsotg_ep_enqueue()
739 bd->set.bd_ctrl = USBFSOTG_BD_DTS; in usbfsotg_ep_dequeue()
742 cfg->stat.halted = false; in usbfsotg_ep_dequeue()
743 buf = udc_buf_get_all(dev, cfg->addr); in usbfsotg_ep_dequeue()
745 udc_submit_ep_event(dev, buf, -ECONNABORTED); in usbfsotg_ep_dequeue()
748 udc_ep_set_busy(dev, cfg->addr, false); in usbfsotg_ep_dequeue()
762 if (priv->busy[!cfg->stat.odd]) { in ctrl_drop_out_successor()
764 buf = priv->out_buf[!cfg->stat.odd]; in ctrl_drop_out_successor()
766 bd->bd_fields = 0U; in ctrl_drop_out_successor()
767 priv->busy[!cfg->stat.odd] = false; in ctrl_drop_out_successor()
780 bd->set.bd_ctrl = USBFSOTG_BD_STALL | USBFSOTG_BD_DTS | USBFSOTG_BD_OWN; in usbfsotg_ep_set_halt()
781 cfg->stat.halted = true; in usbfsotg_ep_set_halt()
782 LOG_DBG("Halt ep 0x%02x bd %p", cfg->addr, bd); in usbfsotg_ep_set_halt()
784 if (cfg->addr == USB_CONTROL_EP_IN) { in usbfsotg_ep_set_halt()
785 /* Drop subsequent out transfer, current can be re-used */ in usbfsotg_ep_set_halt()
789 if (USB_EP_GET_IDX(cfg->addr) == 0U) { in usbfsotg_ep_set_halt()
799 const struct usbfsotg_config *config = dev->config; in usbfsotg_ep_clear_halt()
801 USB_Type *base = config->base; in usbfsotg_ep_clear_halt()
802 uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); in usbfsotg_ep_clear_halt()
805 LOG_DBG("Clear halt ep 0x%02x", cfg->addr); in usbfsotg_ep_clear_halt()
808 if (bd->set.bd_ctrl & USBFSOTG_BD_STALL) { in usbfsotg_ep_clear_halt()
809 LOG_DBG("bd %p: %x", bd, bd->set.bd_ctrl); in usbfsotg_ep_clear_halt()
810 bd->set.bd_ctrl = USBFSOTG_BD_DTS; in usbfsotg_ep_clear_halt()
815 cfg->stat.data1 = false; in usbfsotg_ep_clear_halt()
816 cfg->stat.halted = false; in usbfsotg_ep_clear_halt()
817 base->ENDPOINT[ep_idx].ENDPT &= ~USB_ENDPT_EPSTALL_MASK; in usbfsotg_ep_clear_halt()
819 if (cfg->addr == USB_CONTROL_EP_OUT) { in usbfsotg_ep_clear_halt()
820 if (priv->busy[cfg->stat.odd]) { in usbfsotg_ep_clear_halt()
822 bd->set.bd_ctrl = USBFSOTG_BD_DTS | USBFSOTG_BD_OWN; in usbfsotg_ep_clear_halt()
828 if (USB_EP_GET_IDX(cfg->addr) == 0U) { in usbfsotg_ep_clear_halt()
832 usbfsotg_event_submit(dev, cfg->addr, USBFSOTG_EVT_XFER); in usbfsotg_ep_clear_halt()
841 const struct usbfsotg_config *config = dev->config; in usbfsotg_ep_enable()
843 USB_Type *base = config->base; in usbfsotg_ep_enable()
844 const uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); in usbfsotg_ep_enable()
847 LOG_DBG("Enable ep 0x%02x", cfg->addr); in usbfsotg_ep_enable()
851 bd_even->bd_fields = 0U; in usbfsotg_ep_enable()
852 bd_even->buf_addr = 0U; in usbfsotg_ep_enable()
853 bd_odd->bd_fields = 0U; in usbfsotg_ep_enable()
854 bd_odd->buf_addr = 0U; in usbfsotg_ep_enable()
856 switch (cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) { in usbfsotg_ep_enable()
858 base->ENDPOINT[ep_idx].ENDPT = (USB_ENDPT_EPHSHK_MASK | in usbfsotg_ep_enable()
864 base->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPHSHK_MASK; in usbfsotg_ep_enable()
865 if (USB_EP_DIR_IS_OUT(cfg->addr)) { in usbfsotg_ep_enable()
866 base->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPRXEN_MASK; in usbfsotg_ep_enable()
868 base->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPTXEN_MASK; in usbfsotg_ep_enable()
872 if (USB_EP_DIR_IS_OUT(cfg->addr)) { in usbfsotg_ep_enable()
873 base->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPRXEN_MASK; in usbfsotg_ep_enable()
875 base->ENDPOINT[ep_idx].ENDPT |= USB_ENDPT_EPTXEN_MASK; in usbfsotg_ep_enable()
879 return -EINVAL; in usbfsotg_ep_enable()
882 if (cfg->addr == USB_CONTROL_EP_OUT) { in usbfsotg_ep_enable()
885 priv->busy[0] = false; in usbfsotg_ep_enable()
886 priv->busy[1] = false; in usbfsotg_ep_enable()
888 usbfsotg_bd_set_ctrl(bd_even, buf->size, buf->data, false); in usbfsotg_ep_enable()
889 priv->out_buf[0] = buf; in usbfsotg_ep_enable()
898 const struct usbfsotg_config *config = dev->config; in usbfsotg_ep_disable()
899 USB_Type *base = config->base; in usbfsotg_ep_disable()
900 uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); in usbfsotg_ep_disable()
906 if (USB_EP_DIR_IS_OUT(cfg->addr)) { in usbfsotg_ep_disable()
907 base->ENDPOINT[ep_idx].ENDPT &= ~USB_ENDPT_EPRXEN_MASK; in usbfsotg_ep_disable()
909 base->ENDPOINT[ep_idx].ENDPT &= ~USB_ENDPT_EPTXEN_MASK; in usbfsotg_ep_disable()
913 LOG_DBG("Endpoint buffer is busy"); in usbfsotg_ep_disable()
916 bd_even->bd_fields = 0U; in usbfsotg_ep_disable()
917 bd_even->buf_addr = 0U; in usbfsotg_ep_disable()
918 bd_odd->bd_fields = 0U; in usbfsotg_ep_disable()
919 bd_odd->buf_addr = 0U; in usbfsotg_ep_disable()
921 LOG_DBG("Disable ep 0x%02x", cfg->addr); in usbfsotg_ep_disable()
928 return -ENOTSUP; in usbfsotg_host_wakeup()
933 const struct usbfsotg_config *config = dev->config; in usbfsotg_set_address()
934 USB_Type *base = config->base; in usbfsotg_set_address()
936 base->ADDR = addr; in usbfsotg_set_address()
943 const struct usbfsotg_config *config = dev->config; in usbfsotg_enable()
944 USB_Type *base = config->base; in usbfsotg_enable()
946 /* non-OTG device mode, enable DP Pullup */ in usbfsotg_enable()
947 base->CONTROL = USB_CONTROL_DPPULLUPNONOTG_MASK; in usbfsotg_enable()
954 const struct usbfsotg_config *config = dev->config; in usbfsotg_disable()
955 USB_Type *base = config->base; in usbfsotg_disable()
958 base->CTL &= ~USB_CTL_USBENSOFEN_MASK; in usbfsotg_disable()
959 base->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK; in usbfsotg_disable()
966 const struct usbfsotg_config *config = dev->config; in usbfsotg_is_supported()
967 USB_Type *base = config->base; in usbfsotg_is_supported()
969 if ((base->PERID != USBFSOTG_PERID) || (base->REV != USBFSOTG_REV)) { in usbfsotg_is_supported()
978 const struct usbfsotg_config *config = dev->config; in usbfsotg_init()
979 USB_Type *base = config->base; in usbfsotg_init()
983 SIM->SOPT1 |= SIM_SOPT1_USBREGEN_MASK; in usbfsotg_init()
987 base->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; in usbfsotg_init()
991 base->CTL = USB_CTL_USBENSOFEN_MASK; in usbfsotg_init()
994 return -ENOTSUP; in usbfsotg_init()
998 base->ENDPOINT[i].ENDPT = 0; in usbfsotg_init()
1001 base->BDTPAGE1 = (uint8_t)(POINTER_TO_UINT(config->bdt) >> 8); in usbfsotg_init()
1002 base->BDTPAGE2 = (uint8_t)(POINTER_TO_UINT(config->bdt) >> 16); in usbfsotg_init()
1003 base->BDTPAGE3 = (uint8_t)(POINTER_TO_UINT(config->bdt) >> 24); in usbfsotg_init()
1006 base->USBCTRL = USB_USBCTRL_PDE_MASK; in usbfsotg_init()
1008 /* Clear interrupt flags */ in usbfsotg_init()
1009 base->ISTAT = 0xFF; in usbfsotg_init()
1011 base->ERRSTAT = 0xFF; in usbfsotg_init()
1013 /* Enable all error interrupt sources */ in usbfsotg_init()
1014 base->ERREN = 0xFF; in usbfsotg_init()
1015 /* Enable reset interrupt */ in usbfsotg_init()
1016 base->INTEN = (USB_INTEN_SLEEPEN_MASK | in usbfsotg_init()
1026 LOG_ERR("Failed to enable control endpoint"); in usbfsotg_init()
1027 return -EIO; in usbfsotg_init()
1033 LOG_ERR("Failed to enable control endpoint"); in usbfsotg_init()
1034 return -EIO; in usbfsotg_init()
1037 /* Connect and enable USB interrupt */ in usbfsotg_init()
1038 config->irq_enable_func(dev); in usbfsotg_init()
1047 const struct usbfsotg_config *config = dev->config; in usbfsotg_shutdown()
1049 config->irq_disable_func(dev); in usbfsotg_shutdown()
1052 LOG_ERR("Failed to disable control endpoint"); in usbfsotg_shutdown()
1053 return -EIO; in usbfsotg_shutdown()
1057 LOG_ERR("Failed to disable control endpoint"); in usbfsotg_shutdown()
1058 return -EIO; in usbfsotg_shutdown()
1062 config->base->CTL = 0; in usbfsotg_shutdown()
1066 SIM->SOPT1 &= ~SIM_SOPT1_USBREGEN_MASK; in usbfsotg_shutdown()
1084 const struct usbfsotg_config *config = dev->config; in usbfsotg_driver_preinit()
1085 struct udc_data *data = dev->data; in usbfsotg_driver_preinit()
1086 struct usbfsotg_data *priv = data->priv; in usbfsotg_driver_preinit()
1089 k_mutex_init(&data->mutex); in usbfsotg_driver_preinit()
1090 k_fifo_init(&priv->fifo); in usbfsotg_driver_preinit()
1091 k_work_init(&priv->work, xfer_work_handler); in usbfsotg_driver_preinit()
1093 for (int i = 0; i < config->num_of_eps; i++) { in usbfsotg_driver_preinit()
1094 config->ep_cfg_out[i].caps.out = 1; in usbfsotg_driver_preinit()
1096 config->ep_cfg_out[i].caps.control = 1; in usbfsotg_driver_preinit()
1097 config->ep_cfg_out[i].caps.mps = 64; in usbfsotg_driver_preinit()
1099 config->ep_cfg_out[i].caps.bulk = 1; in usbfsotg_driver_preinit()
1100 config->ep_cfg_out[i].caps.interrupt = 1; in usbfsotg_driver_preinit()
1101 config->ep_cfg_out[i].caps.iso = 1; in usbfsotg_driver_preinit()
1102 config->ep_cfg_out[i].caps.mps = 1023; in usbfsotg_driver_preinit()
1105 config->ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; in usbfsotg_driver_preinit()
1106 err = udc_register_ep(dev, &config->ep_cfg_out[i]); in usbfsotg_driver_preinit()
1108 LOG_ERR("Failed to register endpoint"); in usbfsotg_driver_preinit()
1113 for (int i = 0; i < config->num_of_eps; i++) { in usbfsotg_driver_preinit()
1114 config->ep_cfg_in[i].caps.in = 1; in usbfsotg_driver_preinit()
1116 config->ep_cfg_in[i].caps.control = 1; in usbfsotg_driver_preinit()
1117 config->ep_cfg_in[i].caps.mps = 64; in usbfsotg_driver_preinit()
1119 config->ep_cfg_in[i].caps.bulk = 1; in usbfsotg_driver_preinit()
1120 config->ep_cfg_in[i].caps.interrupt = 1; in usbfsotg_driver_preinit()
1121 config->ep_cfg_in[i].caps.iso = 1; in usbfsotg_driver_preinit()
1122 config->ep_cfg_in[i].caps.mps = 1023; in usbfsotg_driver_preinit()
1125 config->ep_cfg_in[i].addr = USB_EP_DIR_IN | i; in usbfsotg_driver_preinit()
1126 err = udc_register_ep(dev, &config->ep_cfg_in[i]); in usbfsotg_driver_preinit()
1128 LOG_ERR("Failed to register endpoint"); in usbfsotg_driver_preinit()
1133 data->caps.rwup = false; in usbfsotg_driver_preinit()
1134 data->caps.mps0 = USBFSOTG_MPS0; in usbfsotg_driver_preinit()