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