1 /*******************************************************************************
2 * File Name: cyhal_usb_dev.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon USB Device.
6 * This interface abstracts out the chip specific details.
7 * If any chip specific functionality is necessary, or performance is critical
8 * the low level functions can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2019-2021 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 *     http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29 
30 #include <string.h>
31 #include "cyhal_usb_dev.h"
32 #include "cyhal_gpio.h"
33 #include "cyhal_hwmgr.h"
34 #include "cyhal_syspm.h"
35 #include "cyhal_clock.h"
36 #include "cyhal_utils.h"
37 #include "cyhal_irq_impl.h"
38 
39 #if (CYHAL_DRIVER_AVAILABLE_USB_DEV)
40 
41 #if defined(__cplusplus)
42 extern "C"
43 {
44 #endif
45 
46 /******************************************************************************
47  ********************* Internal Support Macros/Functions **********************
48  *****************************************************************************/
49 
50 /* Interrupt configuration and access */
51 #define _CYHAL_USB_DEV_DEFAULT_IRQ_PRIORITY    (3U)
52 
53 /* Assign all interrupt sources to Low interrupt */
54 #define _CYHAL_USB_DEV_IRQ_LVL                 (CY_USBFS_DEV_DRV_LVL_LOW)
55 #define _CYHAL_USB_DEV_IRQ_LVL_DEFAULT         (CY_USBFS_DEV_DRV_SET_SOF_LVL(_CYHAL_USB_DEV_IRQ_LVL)      | \
56                                                 CY_USBFS_DEV_DRV_SET_BUS_RESET_LVL(_CYHAL_USB_DEV_IRQ_LVL) | \
57                                                 CY_USBFS_DEV_DRV_SET_EP0_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
58                                                 CY_USBFS_DEV_DRV_SET_LPM_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
59                                                 CY_USBFS_DEV_DRV_SET_ARB_EP_LVL(_CYHAL_USB_DEV_IRQ_LVL)    | \
60                                                 CY_USBFS_DEV_DRV_SET_EP1_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
61                                                 CY_USBFS_DEV_DRV_SET_EP2_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
62                                                 CY_USBFS_DEV_DRV_SET_EP3_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
63                                                 CY_USBFS_DEV_DRV_SET_EP4_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
64                                                 CY_USBFS_DEV_DRV_SET_EP5_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
65                                                 CY_USBFS_DEV_DRV_SET_EP6_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
66                                                 CY_USBFS_DEV_DRV_SET_EP7_LVL(_CYHAL_USB_DEV_IRQ_LVL)       | \
67                                                 CY_USBFS_DEV_DRV_SET_EP8_LVL(_CYHAL_USB_DEV_IRQ_LVL))
68 
69 #define _CYHAL_USB_DEV_IS_EVENT_VALID(event)    ( ((event) == CYHAL_USB_DEV_EVENT_BUS_RESET) || \
70                                                   ((event) == CYHAL_USB_DEV_EVENT_EP0_SETUP) || \
71                                                   ((event) == CYHAL_USB_DEV_EVENT_EP0_IN)    || \
72                                                   ((event) == CYHAL_USB_DEV_EVENT_EP0_OUT) )
73 
74 #define _CYHAL_USB_DEV_IS_EP_NUM_VALID(endpoint)     CY_USBFS_DEV_DRV_IS_EP_VALID(endpoint)
75 #define _CYHAL_USB_DEV_IS_EP0_SIZE_VALID(ep0_size)   (ep0_size >= CY_USBFS_DEV_DRV_EP0_BUFFER_SIZE)
76 
77 #define _CYHAL_USB_DEV_EVENT_NUM          (4)
78 #define _CYHAL_USB_DEV_EP_EVENT_NUM       (CY_USBFS_DEV_DRV_NUM_EPS_MAX)
79 
80 /* Clock configuration constants */
81 #define _CYHAL_USB_DEV_USB_CLK_HF                (3U)        /* USBFS block dedicated path clock: CLK_HF3 */
82 #define _CYHAL_USB_DEV_USB_CLK_HF_FREQ           (48000000U) /* CLK_HF3 required frequency, Hz */
83 #define _CYHAL_USB_DEV_BUS_RESET_CLOCK_HZ        (100000U)   /* Bus Reset require frequency, Hz */
84 
85 typedef enum
86 {
87     CYHAL_USB_DEV_EP1_IDX = 0,     /* Callback number for Endpoint 1 completion interrupt */
88     CYHAL_USB_DEV_EP2_IDX = 1,     /* Callback number for Endpoint 2 completion interrupt */
89     CYHAL_USB_DEV_EP3_IDX = 2,     /* Callback number for Endpoint 3 completion interrupt */
90     CYHAL_USB_DEV_EP4_IDX = 3,     /* Callback number for Endpoint 4 completion interrupt */
91     CYHAL_USB_DEV_EP5_IDX = 4,     /* Callback number for Endpoint 5 completion interrupt */
92     CYHAL_USB_DEV_EP6_IDX = 5,     /* Callback number for Endpoint 6 completion interrupt */
93     CYHAL_USB_DEV_EP7_IDX = 6,     /* Callback number for Endpoint 7 completion interrupt */
94     CYHAL_USB_DEV_EP8_IDX = 7,     /* Callback number for Endpoint 8 completion interrupt */
95 } _cyhal_usb_dev_ep_cb_num_t;
96 
97 static USBFS_Type* const _CYHAL_USB_DEV_BASE_ADDRESSES[CY_IP_MXUSBFS_INSTANCES] =
98 {
99 #ifdef USBFS0
100     USBFS0,
101 #endif
102 };
103 
104 static const _cyhal_system_irq_t _CYHAL_USB_DEV_IRQ_N[CY_IP_MXUSBFS_INSTANCES] =
105 {
106 #ifdef USBFS0
107     usb_interrupt_lo_IRQn,
108 #endif
109 };
110 
111 
112 static bool      _cyhal_usb_dev_set_hf_divider(uint32_t clock, uint32_t input_freq, uint32_t target_freq);
113 static cy_rslt_t _cyhal_usb_dev_reserve_pll(cyhal_resource_inst_t *rsc);
114 static cy_rslt_t _cyhal_usb_dev_init_pll(uint32_t clock, uint32_t pll, uint32_t target_freq);
115 static uint32_t _cyhal_usb_dev_get_pll_freq(uint32_t path);
116 static cy_rslt_t _cyhal_usb_dev_hf_clock_setup(cyhal_usb_dev_t *obj);
117 static cy_rslt_t _cyhal_usb_dev_peri_clock_setup(cyhal_usb_dev_t *obj, const cyhal_clock_t *clk);
118 
119 static cy_rslt_t _cyhal_usb_dev_pin_setup(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm);
120 static void _cyhal_usb_dev_free_resources(cyhal_usb_dev_t *obj);
121 
122 static void _cyhal_usb_0_dev_bus_reset_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext);
123 static void _cyhal_usb_0_dev_ep0_setup_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext);
124 static void _cyhal_usb_0_dev_ep0_in_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext);
125 static void _cyhal_usb_0_dev_ep0_out_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext);
126 static cyhal_usb_dev_event_callback_t _cyhal_usb_dev_event_callback_table[CY_IP_MXUSBFS_INSTANCES][_CYHAL_USB_DEV_EVENT_NUM];
127 static const cy_cb_usbfs_dev_drv_callback_t _cyhal_usb_dev_drv_event_cb_table[CY_IP_MXUSBFS_INSTANCES][_CYHAL_USB_DEV_EVENT_NUM] =
128 {
129     /* USBFS0 */
130     {
131         &_cyhal_usb_0_dev_bus_reset_callback,    /* CY_USB_DEV_BUS_RESET = 0U */
132         &_cyhal_usb_0_dev_ep0_setup_callback,    /* CY_USB_DEV_EP0_SETUP = 1U */
133         &_cyhal_usb_0_dev_ep0_in_callback,       /* CY_USB_DEV_EP0_IN    = 2U */
134         &_cyhal_usb_0_dev_ep0_out_callback       /* CY_USB_DEV_EP0_OUT   = 3U */
135     },
136 };
137 
138 static void _cyhal_usb_0_dev_sof_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext);
139 static cyhal_usb_dev_sof_callback_t _cyhal_usb_dev_sof_user_callback[CY_IP_MXUSBFS_INSTANCES];
140 static const cy_cb_usbfs_dev_drv_callback_t _cyhal_usb_dev_drv_sof_cb_table[CY_IP_MXUSBFS_INSTANCES]=
141 {
142     /* USBFS0 */
143     &_cyhal_usb_0_dev_sof_callback,
144 };
145 
146 static void _cyhal_usb_0_dev_ep_callback(USBFS_Type *base, uint32_t ep_addr, uint32_t errorType, cy_stc_usbfs_dev_drv_context_t *drvContext);
147 static cyhal_usb_dev_endpoint_callback_t _cyhal_usb_dev_ep_handler_table[CY_IP_MXUSBFS_INSTANCES][_CYHAL_USB_DEV_EP_EVENT_NUM];
148 static const cy_cb_usbfs_dev_drv_ep_callback_t _cyhal_usb_dev_drv_ep_cb_table[CY_IP_MXUSBFS_INSTANCES] =
149 {
150     /* USBFS0 */
151     &_cyhal_usb_0_dev_ep_callback,
152 };
153 
_cyhal_usb_0_dev_bus_reset_callback(USBFS_Type * base,struct cy_stc_usbfs_dev_drv_context * drvContext)154 static void _cyhal_usb_0_dev_bus_reset_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext)
155 {
156     CY_UNUSED_PARAMETER(base);
157     CY_UNUSED_PARAMETER(drvContext);
158     _cyhal_usb_dev_event_callback_table[0][CYHAL_USB_DEV_EVENT_BUS_RESET]();
159 }
160 
_cyhal_usb_0_dev_ep0_setup_callback(USBFS_Type * base,struct cy_stc_usbfs_dev_drv_context * drvContext)161 static void _cyhal_usb_0_dev_ep0_setup_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext)
162 {
163     CY_UNUSED_PARAMETER(base);
164     CY_UNUSED_PARAMETER(drvContext);
165     _cyhal_usb_dev_event_callback_table[0][CYHAL_USB_DEV_EVENT_EP0_SETUP]();
166 }
167 
_cyhal_usb_0_dev_ep0_in_callback(USBFS_Type * base,struct cy_stc_usbfs_dev_drv_context * drvContext)168 static void _cyhal_usb_0_dev_ep0_in_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext)
169 {
170     CY_UNUSED_PARAMETER(base);
171     CY_UNUSED_PARAMETER(drvContext);
172     _cyhal_usb_dev_event_callback_table[0][CYHAL_USB_DEV_EVENT_EP0_IN]();
173 }
174 
_cyhal_usb_0_dev_ep0_out_callback(USBFS_Type * base,struct cy_stc_usbfs_dev_drv_context * drvContext)175 static void _cyhal_usb_0_dev_ep0_out_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext)
176 {
177     CY_UNUSED_PARAMETER(base);
178     CY_UNUSED_PARAMETER(drvContext);
179     _cyhal_usb_dev_event_callback_table[0][CYHAL_USB_DEV_EVENT_EP0_OUT]();
180 }
181 
_cyhal_usb_0_dev_sof_callback(USBFS_Type * base,struct cy_stc_usbfs_dev_drv_context * drvContext)182 static void _cyhal_usb_0_dev_sof_callback(USBFS_Type *base, struct cy_stc_usbfs_dev_drv_context *drvContext)
183 {
184     CY_UNUSED_PARAMETER(drvContext);
185     if (NULL != _cyhal_usb_dev_sof_user_callback[0])
186         _cyhal_usb_dev_sof_user_callback[0](Cy_USBFS_Dev_Drv_GetSofNubmer(base));
187 }
188 
_cyhal_usb_0_dev_ep_callback(USBFS_Type * base,uint32_t ep_addr,uint32_t errorType,cy_stc_usbfs_dev_drv_context_t * drvContext)189 static void _cyhal_usb_0_dev_ep_callback(USBFS_Type *base, uint32_t ep_addr, uint32_t errorType, cy_stc_usbfs_dev_drv_context_t *drvContext)
190 {
191     CY_UNUSED_PARAMETER(base);
192     CY_UNUSED_PARAMETER(errorType);
193     CY_UNUSED_PARAMETER(drvContext);
194     cyhal_usb_dev_endpoint_callback_t ep_handler = _cyhal_usb_dev_ep_handler_table[0U][CYHAL_USB_DEV_GET_EP_IDX(ep_addr)];
195 
196     if (NULL != ep_handler)
197         ep_handler((cyhal_usb_dev_ep_t)ep_addr);
198 }
199 
_cyhal_usb_dev_set_hf_divider(uint32_t clock,uint32_t input_freq,uint32_t target_freq)200 static bool _cyhal_usb_dev_set_hf_divider(uint32_t clock, uint32_t input_freq, uint32_t target_freq)
201 {
202     bool divider_found;
203 
204     for (cy_en_clkhf_dividers_t divider = CY_SYSCLK_CLKHF_NO_DIVIDE; divider <= CY_SYSCLK_CLKHF_DIVIDE_BY_8; divider++)
205     {
206         divider_found = ((target_freq << divider) == input_freq) ? true : false;
207         if (divider_found)
208         {
209             Cy_SysClk_ClkHfSetDivider(clock, divider);
210             break;
211         }
212     }
213 
214     return divider_found;
215 }
216 
_cyhal_usb_dev_reserve_pll(cyhal_resource_inst_t * rsc)217 static cy_rslt_t _cyhal_usb_dev_reserve_pll(cyhal_resource_inst_t *rsc)
218 {
219     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR_CLK_CFG;
220 
221     rsc->type = CYHAL_RSC_CLKPATH;
222     rsc->channel_num = 0u;
223 
224     for (uint8_t path = 1u; path <= SRSS_NUM_PLL; ++path)
225     {
226         /* Set block number to path number that belongs to PLL */
227         rsc->block_num = path;
228         result = cyhal_hwmgr_reserve(rsc);
229         if (CY_RSLT_SUCCESS == result)
230             break;
231     }
232 
233     /* Reservation failed mark type invalid */
234     if (CY_RSLT_SUCCESS != result)
235         rsc->type = CYHAL_RSC_INVALID;
236 
237     return result;
238 }
239 
_cyhal_usb_dev_init_pll(uint32_t clock,uint32_t pll,uint32_t target_freq)240 static cy_rslt_t _cyhal_usb_dev_init_pll(uint32_t clock, uint32_t pll, uint32_t target_freq)
241 {
242     cy_stc_pll_config_t cfg;
243 
244     Cy_SysClk_PllDisable(pll);
245     Cy_SysClk_ClkHfSetSource(clock, (cy_en_clkhf_in_sources_t)(pll));
246 
247     cfg.inputFreq  = CY_SYSCLK_IMO_FREQ;
248     cfg.outputFreq = target_freq;
249     cfg.lfMode     = false;
250     cfg.outputMode = CY_SYSCLK_FLLPLL_OUTPUT_AUTO;
251 
252     Cy_SysClk_ClkPathSetSource(pll, CY_SYSCLK_CLKPATH_IN_IMO);
253     cy_rslt_t result = Cy_SysClk_PllConfigure(pll, &cfg);
254 
255     /* Wait up to 1 seconds for PLL to lock */
256     if (result == CY_RSLT_SUCCESS)
257         result = Cy_SysClk_PllEnable(pll, 1000000);
258 
259     if (result == CY_RSLT_SUCCESS)
260         Cy_SysClk_ClkHfSetDivider(clock, CY_SYSCLK_CLKHF_NO_DIVIDE);
261 
262     return result;
263 }
264 
_cyhal_usb_dev_get_pll_freq(uint32_t path)265 static uint32_t _cyhal_usb_dev_get_pll_freq(uint32_t path)
266 {
267     /* PLL sourced from the IMO */
268     uint32_t freq = CY_SYSCLK_IMO_FREQ;
269 
270     cy_stc_pll_manual_config_t pll_config;
271     Cy_SysClk_PllGetConfiguration(path, &pll_config);
272 
273     if (pll_config.outputMode != CY_SYSCLK_FLLPLL_OUTPUT_INPUT)
274     {
275         freq = (uint32_t)CY_SYSLIB_DIV_ROUND(((uint64_t)freq * (uint64_t)pll_config.feedbackDiv),
276                                              ((uint64_t)pll_config.referenceDiv * (uint64_t)pll_config.outputDiv));
277     }
278 
279     return freq;
280 }
281 
_cyhal_usb_dev_hf_clock_setup(cyhal_usb_dev_t * obj)282 static cy_rslt_t _cyhal_usb_dev_hf_clock_setup(cyhal_usb_dev_t *obj)
283 {
284     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR_CLK_CFG;
285     uint32_t  clock  = _CYHAL_USB_DEV_USB_CLK_HF;
286 
287     /* Start CLK_HF3 configuration */
288     Cy_SysClk_ClkHfDisable(clock);
289 
290     /* Loop through all enabled PLLs and find one that matches requirements:
291     * sourced from IMO and frequency in multiple of 48MHz.
292     */
293     for (uint32_t path = 1U; path <= SRSS_NUM_PLL; ++path)
294     {
295         if ( Cy_SysClk_PllIsEnabled(path) && (CY_SYSCLK_CLKPATH_IN_IMO == Cy_SysClk_ClkPathGetSource(path)) )
296         {
297             /* Get PLL frequency */
298             uint32_t clk_pll_freq = _cyhal_usb_dev_get_pll_freq(path);
299 
300             /* Try to adjust CLK_HF3 divider to meet frequency requirements (48 MHz) */
301             if (_cyhal_usb_dev_set_hf_divider(clock, clk_pll_freq, _CYHAL_USB_DEV_USB_CLK_HF_FREQ))
302             {
303                 /* Change path if it does not match after successful divider update */
304                 if (Cy_SysClk_ClkHfGetSource(clock) != path)
305                 {
306                     Cy_SysClk_ClkHfSetSource(clock, (cy_en_clkhf_in_sources_t) path);
307                 }
308 
309                 /* The existing PLL is used, mark to not try clear it */
310                 result = CY_RSLT_SUCCESS;
311                 break;
312             }
313         }
314     }
315 
316     /* None of existing PLLs do meet USB requirements, try to allocate free */
317     if (CY_RSLT_SUCCESS != result)
318     {
319         result = _cyhal_usb_dev_reserve_pll(&(obj->pll_resource));
320 
321         if (CY_RSLT_SUCCESS == result)
322         {
323             /* Sets PLL source IMO and clear CLK_HF3 divider */
324             result = _cyhal_usb_dev_init_pll(clock, obj->pll_resource.block_num, _CYHAL_USB_DEV_USB_CLK_HF_FREQ);
325         }
326     }
327 
328     /* End CLK_HF3 configuration */
329     Cy_SysClk_ClkHfEnable(clock);
330 
331     if (result == CY_RSLT_SUCCESS)
332     {
333         SystemCoreClockUpdate();
334     }
335 
336     return result;
337 }
338 
_cyhal_usb_dev_peri_clock_setup(cyhal_usb_dev_t * obj,const cyhal_clock_t * clk)339 static cy_rslt_t _cyhal_usb_dev_peri_clock_setup(cyhal_usb_dev_t *obj, const cyhal_clock_t *clk)
340 {
341     cy_rslt_t result;
342     cy_rslt_t status = CY_SYSCLK_BAD_PARAM;
343 
344     if (NULL == clk)
345     {
346         obj->shared_clock = false;
347 
348         /* USB bus reset clock must be 100KHz. Usual peri clock frequency is > 26 MHz, which requires 16-bit divider */
349         result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
350 
351         if (CY_RSLT_SUCCESS == result)
352         {
353             /* Get divider to provide 100kHz clock or less */
354             uint32_t div_value = (_cyhal_utils_get_peripheral_clock_frequency(&(obj->resource)) / _CYHAL_USB_DEV_BUS_RESET_CLOCK_HZ) - 1U;
355 
356             (void) _cyhal_utils_peri_pclk_disable_divider(PCLK_USB_CLOCK_DEV_BRS, &(obj->clock));
357             status = _cyhal_utils_peri_pclk_set_divider(PCLK_USB_CLOCK_DEV_BRS, &(obj->clock), div_value);
358             (void) _cyhal_utils_peri_pclk_enable_divider(PCLK_USB_CLOCK_DEV_BRS, &(obj->clock));
359         }
360     }
361     else
362     {
363         obj->clock = *clk;
364         obj->shared_clock = true;
365         status = CY_RSLT_SUCCESS;
366     }
367 
368     if (CY_RSLT_SUCCESS == status)
369     {
370         status = _cyhal_utils_peri_pclk_assign_divider(PCLK_USB_CLOCK_DEV_BRS, &(obj->clock));
371     }
372 
373     result = (CY_RSLT_SUCCESS == status) ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR_CLK_CFG;
374 
375     return result;
376 }
377 
_cyhal_usb_dev_pin_setup(cyhal_usb_dev_t * obj,cyhal_gpio_t dp,cyhal_gpio_t dm)378 static cy_rslt_t _cyhal_usb_dev_pin_setup(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm)
379 {
380     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR;
381 
382     const cyhal_resource_pin_mapping_t *dp_map = _CYHAL_UTILS_GET_RESOURCE(dp, cyhal_pin_map_usb_usb_dp_pad);
383     const cyhal_resource_pin_mapping_t *dm_map = _CYHAL_UTILS_GET_RESOURCE(dm, cyhal_pin_map_usb_usb_dm_pad);
384 
385     if ((NULL != dp_map) && (NULL != dm_map) && _cyhal_utils_map_resources_equal(dp_map, dm_map))
386     {
387         _CYHAL_UTILS_ASSIGN_RESOURCE(obj->resource, CYHAL_RSC_USB, dp_map);
388 
389         /* reserve DM and DP pins */
390         result = _cyhal_utils_reserve_and_connect(dp_map, CYHAL_PIN_MAP_DRIVE_MODE_USB_USB_DP_PAD);
391         if (CY_RSLT_SUCCESS == result)
392         {
393             obj->pin_dp = dp;
394 
395             result = _cyhal_utils_reserve_and_connect(dm_map, CYHAL_PIN_MAP_DRIVE_MODE_USB_USB_DM_PAD);
396             if (CY_RSLT_SUCCESS == result)
397             {
398                 obj->pin_dm = dm;
399             }
400         }
401     }
402 
403     return result;
404 }
405 
_cyhal_usb_dev_free_resources(cyhal_usb_dev_t * obj)406 static void _cyhal_usb_dev_free_resources(cyhal_usb_dev_t *obj)
407 {
408     /* The object set into the default state in the cyhal_usb_dev_init() */
409     if (CYHAL_RSC_INVALID != obj->resource.type)
410         cyhal_hwmgr_free(&(obj->resource));
411     if (CYHAL_RSC_INVALID != obj->pll_resource.type)
412         cyhal_hwmgr_free(&(obj->pll_resource));
413     if (!obj->shared_clock)
414         cyhal_clock_free(&(obj->clock));
415 
416     _cyhal_utils_release_if_used(&(obj->pin_dp));
417     _cyhal_utils_release_if_used(&(obj->pin_dm));
418 }
419 
_cyhal_usb_dev_pm_callback(cyhal_syspm_callback_state_t state,cyhal_syspm_callback_mode_t mode,void * callback_arg)420 static bool _cyhal_usb_dev_pm_callback(cyhal_syspm_callback_state_t state, cyhal_syspm_callback_mode_t mode, void* callback_arg)
421 {
422     CY_UNUSED_PARAMETER(state);
423     CY_UNUSED_PARAMETER(mode);
424     cyhal_usb_dev_t *obj = (cyhal_usb_dev_t *)callback_arg;
425     return USBFS_DEV_LPM_POWER_CTL(obj->base) & USBFS_USBLPM_POWER_CTL_SUSPEND_Msk;
426 }
427 
428 
429 /******************************************************************************
430  ***************************** Public Functions *******************************
431  *****************************************************************************/
432 
cyhal_usb_dev_init(cyhal_usb_dev_t * obj,cyhal_gpio_t dp,cyhal_gpio_t dm,const cyhal_clock_t * clk)433 cy_rslt_t cyhal_usb_dev_init(cyhal_usb_dev_t *obj, cyhal_gpio_t dp, cyhal_gpio_t dm, const cyhal_clock_t *clk)
434 {
435     cy_rslt_t result;
436 
437     CY_ASSERT(NULL != obj);
438     memset(obj, 0, sizeof(cyhal_usb_dev_t));
439 
440     /* Reset object into the default state to handle resource free */
441     obj->base = NULL;
442     obj->resource.type     = CYHAL_RSC_INVALID;
443     obj->pll_resource.type = CYHAL_RSC_INVALID;
444     obj->shared_clock     = true;
445     obj->pin_dp = CYHAL_NC_PIN_VALUE;
446     obj->pin_dm = CYHAL_NC_PIN_VALUE;
447 
448     result = _cyhal_usb_dev_pin_setup(obj, dp, dm);
449 
450     if (CY_RSLT_SUCCESS == result)
451     {
452         /* Configure CLK_HF3 frequency and proper path */
453         result = _cyhal_usb_dev_hf_clock_setup(obj);
454         if (CY_RSLT_SUCCESS == result)
455         {
456             /* Configure CLK_PERI divider */
457             result = _cyhal_usb_dev_peri_clock_setup(obj, clk);
458         }
459     }
460 
461     if (CY_RSLT_SUCCESS == result)
462     {
463         result = cyhal_hwmgr_reserve(&(obj->resource));
464         obj->base = _CYHAL_USB_DEV_BASE_ADDRESSES[obj->resource.block_num];
465     }
466 
467     if (CY_RSLT_SUCCESS == result)
468     {
469         /* Configure driver */
470         static cy_stc_usbfs_dev_drv_config_t default_cfg =
471         {
472             .mode         = CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU,
473             .dmaConfig    = { 0 },
474             .epBuffer     = NULL,
475             .epBufferSize = 0U,
476             .intrLevelSel = _CYHAL_USB_DEV_IRQ_LVL_DEFAULT,
477             .enableLpm    = false,
478             .epAccess     = CY_USBFS_DEV_DRV_USE_8_BITS_DR
479         };
480 
481         if (CY_USBFS_DEV_DRV_SUCCESS != Cy_USBFS_Dev_Drv_Init(obj->base, &default_cfg, &(obj->context)))
482         {
483             result = CYHAL_USB_DEV_RSLT_ERR;
484         }
485     }
486 
487     if (CY_RSLT_SUCCESS == result)
488     {
489         uint32_t instance = obj->resource.block_num;
490 
491         /* Register service callbacks */
492         Cy_USBFS_Dev_Drv_RegisterServiceCallback(obj->base, CY_USB_DEV_BUS_RESET,
493                                                  _cyhal_usb_dev_drv_event_cb_table[instance][CY_USB_DEV_BUS_RESET],
494                                                  &(obj->context));
495         Cy_USBFS_Dev_Drv_RegisterServiceCallback(obj->base, CY_USB_DEV_EP0_SETUP,
496                                                  _cyhal_usb_dev_drv_event_cb_table[instance][CY_USB_DEV_EP0_SETUP],
497                                                  &(obj->context));
498         Cy_USBFS_Dev_Drv_RegisterServiceCallback(obj->base, CY_USB_DEV_EP0_IN,
499                                                  _cyhal_usb_dev_drv_event_cb_table[instance][CY_USB_DEV_EP0_IN],
500                                                  &(obj->context));
501         Cy_USBFS_Dev_Drv_RegisterServiceCallback(obj->base, CY_USB_DEV_EP0_OUT,
502                                                  _cyhal_usb_dev_drv_event_cb_table[instance][CY_USB_DEV_EP0_OUT],
503                                                  &(obj->context));
504 
505         /* Register sof callback (it enables sof interrupt, so disable it after registration) */
506         Cy_USBFS_Dev_Drv_RegisterSofCallback(obj->base, _cyhal_usb_dev_drv_sof_cb_table[instance],
507                                              &(obj->context));
508         cyhal_usb_dev_sof_enable(obj, false);
509 
510         obj->pm_callback.states = (cyhal_syspm_callback_state_t)(CYHAL_SYSPM_CB_CPU_DEEPSLEEP | CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM | CYHAL_SYSPM_CB_SYSTEM_HIBERNATE);
511         obj->pm_callback.callback = &_cyhal_usb_dev_pm_callback;
512         obj->pm_callback.args = (void *)obj;
513         obj->pm_callback.next = NULL;
514         obj->pm_callback.ignore_modes = (cyhal_syspm_callback_mode_t)(CYHAL_SYSPM_CHECK_FAIL | CYHAL_SYSPM_BEFORE_TRANSITION | CYHAL_SYSPM_AFTER_TRANSITION | CYHAL_SYSPM_AFTER_DS_WFI_TRANSITION);
515         _cyhal_syspm_register_peripheral_callback(&(obj->pm_callback));
516 
517         /* Register data endpoint handlers */
518         for (uint32_t cb_num = 0; cb_num < _CYHAL_USB_DEV_EP_EVENT_NUM; cb_num++)
519         {
520             Cy_USBFS_Dev_Drv_RegisterEndpointCallback(obj->base,
521                                                       (cb_num + 1U),
522                                                       _cyhal_usb_dev_drv_ep_cb_table[instance],
523                                                       &(obj->context));
524         }
525     }
526 
527     if (CY_RSLT_SUCCESS != result)
528     {
529         _cyhal_usb_dev_free_resources(obj);
530     }
531 
532     return result;
533 }
534 
cyhal_usb_dev_free(cyhal_usb_dev_t * obj)535 void cyhal_usb_dev_free(cyhal_usb_dev_t *obj)
536 {
537     _cyhal_syspm_unregister_peripheral_callback(&(obj->pm_callback));
538     cyhal_usb_dev_irq_enable(obj, false);
539     cyhal_usb_dev_disconnect(obj);
540     _cyhal_usb_dev_free_resources(obj);
541 }
542 
cyhal_usb_dev_connect(cyhal_usb_dev_t * obj)543 void cyhal_usb_dev_connect(cyhal_usb_dev_t *obj)
544 {
545     Cy_USBFS_Dev_Drv_Enable(obj->base, &(obj->context));
546 }
547 
cyhal_usb_dev_disconnect(cyhal_usb_dev_t * obj)548 void cyhal_usb_dev_disconnect(cyhal_usb_dev_t *obj)
549 {
550     Cy_USBFS_Dev_Drv_Disable(obj->base, &(obj->context));
551 }
552 
cyhal_usb_dev_suspend(cyhal_usb_dev_t * obj)553 void cyhal_usb_dev_suspend(cyhal_usb_dev_t *obj)
554 {
555     Cy_USBFS_Dev_Drv_Suspend(obj->base, &(obj->context));
556 }
557 
cyhal_usb_dev_resume(cyhal_usb_dev_t * obj)558 void cyhal_usb_dev_resume(cyhal_usb_dev_t *obj)
559 {
560     Cy_USBFS_Dev_Drv_Resume(obj->base, &(obj->context));
561 }
562 
cyhal_usb_dev_set_configured(cyhal_usb_dev_t * obj)563 void cyhal_usb_dev_set_configured(cyhal_usb_dev_t *obj)
564 {
565     Cy_USBFS_Dev_Drv_ConfigDevice(obj->base, &(obj->context));
566 }
567 
cyhal_usb_dev_set_unconfigured(cyhal_usb_dev_t * obj)568 void cyhal_usb_dev_set_unconfigured(cyhal_usb_dev_t *obj)
569 {
570     Cy_USBFS_Dev_Drv_UnConfigureDevice(obj->base, &(obj->context));
571 }
572 
cyhal_usb_dev_sof_enable(cyhal_usb_dev_t * obj,bool enable)573 void cyhal_usb_dev_sof_enable(cyhal_usb_dev_t *obj, bool enable)
574 {
575     uint32_t mask = Cy_USBFS_Dev_Drv_GetSieInterruptMask(obj->base);
576 
577     if (enable)
578     {
579         mask |= CY_USBFS_DEV_DRV_INTR_SIE_SOF;
580         Cy_USBFS_Dev_Drv_ClearSieInterrupt(obj->base, CY_USBFS_DEV_DRV_INTR_SIE_SOF);
581     }
582     else
583     {
584         mask &= ~CY_USBFS_DEV_DRV_INTR_SIE_SOF;
585     }
586 
587     Cy_USBFS_Dev_Drv_SetSieInterruptMask(obj->base, mask);
588 }
589 
cyhal_usb_dev_set_address(cyhal_usb_dev_t * obj,uint8_t address)590 void cyhal_usb_dev_set_address(cyhal_usb_dev_t *obj, uint8_t address)
591 {
592     Cy_USBFS_Dev_Drv_SetAddress(obj->base, address, &(obj->context));
593 }
594 
cyhal_usb_dev_ep0_get_max_packet(cyhal_usb_dev_t * obj)595 uint32_t cyhal_usb_dev_ep0_get_max_packet(cyhal_usb_dev_t *obj)
596 {
597     return Cy_USBFS_Dev_Drv_GetEp0MaxPacket(obj->base);
598 }
599 
cyhal_usb_dev_ep0_setup_read_result(cyhal_usb_dev_t * obj,uint8_t * buffer,uint32_t size)600 void cyhal_usb_dev_ep0_setup_read_result(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size)
601 {
602     CY_UNUSED_PARAMETER(size);
603     CY_ASSERT(_CYHAL_USB_DEV_IS_EP0_SIZE_VALID(size));
604 
605     Cy_USBFS_Dev_Drv_Ep0GetSetup(obj->base, buffer, &(obj->context));
606 }
607 
cyhal_usb_dev_ep0_read(cyhal_usb_dev_t * obj,uint8_t * buffer,uint32_t size)608 void cyhal_usb_dev_ep0_read(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size)
609 {
610     Cy_USBFS_Dev_Drv_Ep0Read(obj->base, buffer, size, &(obj->context));
611 }
612 
cyhal_usb_dev_ep0_read_result(cyhal_usb_dev_t * obj)613 uint32_t cyhal_usb_dev_ep0_read_result(cyhal_usb_dev_t *obj)
614 {
615     return Cy_USBFS_Dev_Drv_Ep0ReadResult(obj->base, &(obj->context));
616 }
617 
cyhal_usb_dev_ep0_write(cyhal_usb_dev_t * obj,uint8_t * buffer,uint32_t size)618 uint32_t cyhal_usb_dev_ep0_write(cyhal_usb_dev_t *obj, uint8_t *buffer, uint32_t size)
619 {
620     return Cy_USBFS_Dev_Drv_Ep0Write(obj->base, buffer, size, &(obj->context));
621 }
622 
cyhal_usb_dev_ep0_stall(cyhal_usb_dev_t * obj)623 void cyhal_usb_dev_ep0_stall(cyhal_usb_dev_t *obj)
624 {
625     Cy_USBFS_Dev_Drv_Ep0Stall(obj->base);
626 }
627 
cyhal_usb_dev_endpoint_add(cyhal_usb_dev_t * obj,bool alloc,bool enable,cyhal_usb_dev_ep_t endpoint,uint32_t max_packet,cyhal_usb_dev_ep_type_t type)628 cy_rslt_t cyhal_usb_dev_endpoint_add(cyhal_usb_dev_t *obj, bool alloc, bool enable,
629                                      cyhal_usb_dev_ep_t endpoint, uint32_t max_packet, cyhal_usb_dev_ep_type_t type)
630 {
631     cy_stc_usb_dev_ep_config_t ep_config;
632 
633     /* Set parameters to allocate endpoint buffer */
634     ep_config.allocBuffer    = alloc;
635     ep_config.bufferSize     = (uint16_t) max_packet;
636 
637     /* Set parameters to enable endpoint operation */
638     ep_config.enableEndpoint = enable;
639     ep_config.endpointAddr   = (uint8_t) endpoint;
640     ep_config.attributes     = (uint8_t) type;
641     ep_config.maxPacketSize  = (uint16_t) max_packet;
642 
643     return (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_AddEndpoint(obj->base, &ep_config, &(obj->context)))
644                 ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
645 }
646 
cyhal_usb_dev_endpoint_remove(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint)647 cy_rslt_t cyhal_usb_dev_endpoint_remove(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint)
648 {
649     return (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_RemoveEndpoint(obj->base, endpoint, &(obj->context)))
650                 ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
651 }
652 
cyhal_usb_dev_endpoint_stall(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint)653 cy_rslt_t cyhal_usb_dev_endpoint_stall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint)
654 {
655     return (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_StallEndpoint(obj->base, CYHAL_USB_DEV_GET_EP_NUM(endpoint), &(obj->context)))
656                 ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
657 }
658 
cyhal_usb_dev_endpoint_unstall(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint)659 cy_rslt_t cyhal_usb_dev_endpoint_unstall(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint)
660 {
661     return (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_UnStallEndpoint(obj->base, CYHAL_USB_DEV_GET_EP_NUM(endpoint), &(obj->context)))
662                 ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
663 }
664 
cyhal_usb_dev_endpoint_is_stalled(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint)665 bool cyhal_usb_dev_endpoint_is_stalled(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint)
666 {
667     return (CY_USB_DEV_EP_STALLED == Cy_USBFS_Dev_Drv_GetEndpointState(obj->base, CYHAL_USB_DEV_GET_EP_NUM(endpoint), &(obj->context)));
668 }
669 
cyhal_usb_dev_endpoint_read(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint,uint8_t * data,uint32_t size)670 cy_rslt_t cyhal_usb_dev_endpoint_read(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t *data, uint32_t size)
671 {
672     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR;
673     uint32_t  ep_num = CYHAL_USB_DEV_GET_EP_NUM(endpoint);
674 
675     /* Check if endpoint is read for a read operation */
676     cy_en_usb_dev_ep_state_t ep_state;
677     ep_state = Cy_USBFS_Dev_Drv_GetEndpointState(obj->base, ep_num, &(obj->context));
678     if ((CY_USB_DEV_EP_IDLE == ep_state) || (CY_USB_DEV_EP_COMPLETED == ep_state))
679     {
680         /* Save pointer and size to use in cyhal_usb_dev_endpoint_read_result */
681         obj->rd_data[CYHAL_USB_DEV_GET_EP_IDX(endpoint)] = data;
682         obj->rd_size[CYHAL_USB_DEV_GET_EP_IDX(endpoint)] = size;
683 
684         Cy_USBFS_Dev_Drv_EnableOutEndpoint(obj->base, ep_num, &obj->context);
685 
686         result = CY_RSLT_SUCCESS;
687     }
688 
689     return result;
690 }
691 
cyhal_usb_dev_endpoint_read_result(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint,uint32_t * act_size)692 cy_rslt_t cyhal_usb_dev_endpoint_read_result(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint32_t *act_size)
693 {
694     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR;
695     uint32_t  ep_num = CYHAL_USB_DEV_GET_EP_NUM(endpoint);
696 
697     /* Check if endpoint is read for a read result operation */
698     if (CY_USB_DEV_EP_COMPLETED == Cy_USBFS_Dev_Drv_GetEndpointState(obj->base, ep_num, &(obj->context)))
699     {
700         result = (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_ReadOutEndpoint(obj->base,
701                                                      ep_num,
702                                                      obj->rd_data[CYHAL_USB_DEV_GET_EP_IDX(endpoint)],
703                                                      obj->rd_size[CYHAL_USB_DEV_GET_EP_IDX(endpoint)],
704                                                      act_size,
705                                                      &(obj->context))) ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
706     }
707 
708     return result;
709 }
710 
cyhal_usb_dev_endpoint_write(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint,uint8_t const * data,uint32_t size)711 cy_rslt_t cyhal_usb_dev_endpoint_write(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, uint8_t const *data, uint32_t size)
712 {
713     cy_rslt_t result = CYHAL_USB_DEV_RSLT_ERR;
714     uint32_t  ep_num = CYHAL_USB_DEV_GET_EP_NUM(endpoint);
715 
716     /* Check if endpoint is read for a write operation */
717     cy_en_usb_dev_ep_state_t ep_state = Cy_USBFS_Dev_Drv_GetEndpointState(obj->base, ep_num, &(obj->context));
718     if ((CY_USB_DEV_EP_IDLE == ep_state) || (CY_USB_DEV_EP_COMPLETED == ep_state))
719     {
720         result = (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_LoadInEndpoint(obj->base,
721                                                     ep_num,
722                                                     data,
723                                                     size,
724                                                     &(obj->context))) ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
725     }
726 
727     return result;
728 }
729 
cyhal_usb_dev_endpoint_abort(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint)730 cy_rslt_t cyhal_usb_dev_endpoint_abort(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint)
731 {
732     return (CY_USBFS_DEV_DRV_SUCCESS == Cy_USBFS_Dev_Drv_Abort(obj->base, CYHAL_USB_DEV_GET_EP_NUM(endpoint), &(obj->context)))
733             ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
734 }
735 
cyhal_usb_dev_irq_enable(cyhal_usb_dev_t * obj,bool enable)736 void cyhal_usb_dev_irq_enable(cyhal_usb_dev_t *obj, bool enable)
737 {
738     uint32_t instance = (uint32_t)obj->resource.block_num;
739     _cyhal_system_irq_t system_irq = _CYHAL_USB_DEV_IRQ_N[instance];
740     if (enable)
741     {
742         _cyhal_irq_clear_pending(system_irq);
743         _cyhal_irq_enable(system_irq);
744     }
745     else
746     {
747         _cyhal_irq_disable(system_irq);
748     }
749 }
750 
cyhal_usb_dev_process_irq(cyhal_usb_dev_t * obj)751 void cyhal_usb_dev_process_irq(cyhal_usb_dev_t *obj)
752 {
753     Cy_USBFS_Dev_Drv_Interrupt(obj->base, Cy_USBFS_Dev_Drv_GetInterruptCauseLo(obj->base), &(obj->context));
754 }
755 
cyhal_usb_dev_register_irq_callback(cyhal_usb_dev_t * obj,cyhal_usb_dev_irq_callback_t callback)756 cy_rslt_t cyhal_usb_dev_register_irq_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_irq_callback_t callback)
757 {
758     uint32_t instance = (uint32_t)obj->resource.block_num;
759 
760     /* Setup interrupt in NVIC to trigger the callback */
761     return (CY_RSLT_SUCCESS == _cyhal_irq_register(_CYHAL_USB_DEV_IRQ_N[instance], _CYHAL_USB_DEV_DEFAULT_IRQ_PRIORITY, (cy_israddress)callback))
762                 ? CY_RSLT_SUCCESS : CYHAL_USB_DEV_RSLT_ERR;
763 }
764 
cyhal_usb_dev_register_event_callback(cyhal_usb_dev_t * obj,cyhal_usb_dev_event_t event,cyhal_usb_dev_event_callback_t callback)765 void cyhal_usb_dev_register_event_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_event_t event, cyhal_usb_dev_event_callback_t callback)
766 {
767     CY_ASSERT(_CYHAL_USB_DEV_IS_EVENT_VALID(event));
768     uint32_t instance = (uint32_t)obj->resource.block_num;
769 
770     _cyhal_usb_dev_event_callback_table[instance][event] = callback;
771 }
772 
cyhal_usb_dev_register_sof_callback(cyhal_usb_dev_t * obj,cyhal_usb_dev_sof_callback_t callback)773 void cyhal_usb_dev_register_sof_callback( cyhal_usb_dev_t *obj, cyhal_usb_dev_sof_callback_t callback)
774 {
775     uint32_t instance = (uint32_t)obj->resource.block_num;
776     _cyhal_usb_dev_sof_user_callback[instance] = callback;
777 }
778 
cyhal_usb_dev_register_endpoint_callback(cyhal_usb_dev_t * obj,cyhal_usb_dev_ep_t endpoint,cyhal_usb_dev_endpoint_callback_t callback)779 void cyhal_usb_dev_register_endpoint_callback(cyhal_usb_dev_t *obj, cyhal_usb_dev_ep_t endpoint, cyhal_usb_dev_endpoint_callback_t callback)
780 {
781     uint32_t endpoint_num = CYHAL_USB_DEV_GET_EP_NUM(endpoint);
782     uint32_t instance = (uint32_t)obj->resource.block_num;
783 
784     CY_ASSERT(_CYHAL_USB_DEV_IS_EP_NUM_VALID(endpoint_num));
785 
786     _cyhal_usb_dev_ep_handler_table[instance][CYHAL_USB_DEV_GET_EP_IDX(endpoint_num)]= callback;
787 }
788 
789 #if defined(__cplusplus)
790 }
791 #endif
792 
793 #endif /* CYHAL_DRIVER_AVAILABLE_USB_DEV */
794