1 /***************************************************************************//**
2 * \file cy_usbfs_dev_drv.c
3 * \version 2.30
4 *
5 * Provides general API implementation of the USBFS driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2023 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24
25 #include "cy_device.h"
26
27 #if defined (CY_IP_MXUSBFS) && defined (CY_IP_MXPERI)
28
29 #include "cy_usbfs_dev_drv.h"
30 #include "cy_usbfs_dev_drv_pvt.h"
31
32 #if defined(__cplusplus)
33 extern "C" {
34 #endif
35
36 /*******************************************************************************
37 * Internal Constants
38 *******************************************************************************/
39
40 /* After suspend, disable wait 2 us */
41 #define WAIT_SUSPEND_DISABLE (2U)
42
43 /* The bus reset counter is driven by the 100 kHz clock and detects a bus reset
44 * condition after 100 us.
45 */
46 #define BUS_RESET_PERIOD (10UL)
47
48
49 /*******************************************************************************
50 * Internal Functions Prototypes
51 *******************************************************************************/
52
53 static void LpmIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
54 static void SofIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
55 static void Ep0IntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
56 static void BusResetIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
57 static void ArbiterIntrHandler (USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
58 static void SieEnpointIntrHandler(USBFS_Type *base, uint32_t endpoint, cy_stc_usbfs_dev_drv_context_t *context);
59
60 static uint32_t WriteEp0Buffer(USBFS_Type *base, uint8_t const *buffer, uint32_t size);
61 static uint32_t ReadEp0Buffer (USBFS_Type const *base, uint8_t *buffer, uint32_t size);
62
63 static void RestoreDeviceConfiguration(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context);
64
65 static void EndpointTransferComplete(USBFS_Type *base, uint32_t endpoint,
66 cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData,
67 cy_stc_usbfs_dev_drv_context_t *context);
68
69 /*******************************************************************************
70 * Function Name: Cy_USBFS_Dev_Drv_Init
71 ****************************************************************************//**
72 *
73 * Initializes the USBFS in device mode. If DMAs are used, initialize the DMAs.
74 *
75 * \param base
76 * The pointer to the USBFS instance.
77 *
78 * \param config
79 * The pointer to the configuration structure \ref cy_stc_usbfs_dev_drv_config_t.
80 *
81 * \param context
82 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
83 * allocated by the user. The structure is used during the USBFS Device
84 * operation for internal configuration and data retention. The user must not
85 * modify anything in this structure.
86 *
87 * \return
88 * The status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
89 *
90 *******************************************************************************/
Cy_USBFS_Dev_Drv_Init(USBFS_Type * base,cy_stc_usbfs_dev_drv_config_t const * config,cy_stc_usbfs_dev_drv_context_t * context)91 cy_en_usbfs_dev_drv_status_t Cy_USBFS_Dev_Drv_Init(USBFS_Type *base,
92 cy_stc_usbfs_dev_drv_config_t const *config,
93 cy_stc_usbfs_dev_drv_context_t *context)
94 {
95 cy_en_usbfs_dev_drv_status_t retStatus = CY_USBFS_DEV_DRV_BAD_PARAM;
96
97 /* Input parameters verification */
98 if ((NULL == base) || (NULL == config) || (NULL == context))
99 {
100 return CY_USBFS_DEV_DRV_BAD_PARAM;
101 }
102
103 CY_ASSERT_L3(CY_USBFS_DEV_DRV_IS_MODE_VALID(config->mode));
104
105 /* Enables clock to mxusb IP */
106 USBFS_DEV_USB_CLK_EN(base) = CY_USBFS_DEV_DRV_WRITE_ODD(USBFS_USBDEV_USB_CLK_EN_CSR_CLK_EN_Msk);
107
108 /* Clears register (except reserved): the IOMODE = 0 means usb IP controls the usb pins */
109 USBFS_DEV_USBIO_CR1(base) = (USBFS_DEV_USBIO_CR1(base) & USBFS_USBDEV_USBIO_CR1_RESERVED_2_Msk);
110
111 /* Sets the number of clocks (divided version of Clk_Peri) to detect bus reset */
112 USBFS_DEV_BUS_RST_CNT(base) = BUS_RESET_PERIOD;
113
114 /* Enable PHY detector and single-ended and differential receivers */
115 USBFS_DEV_LPM_POWER_CTL(base) = (USBFS_USBLPM_POWER_CTL_SUSPEND_Msk |
116 USBFS_USBLPM_POWER_CTL_ENABLE_DPO_Msk |
117 USBFS_USBLPM_POWER_CTL_ENABLE_DMO_Msk);
118 (void) USBFS_DEV_LPM_POWER_CTL(base);
119
120 /* Suspends a clear sequence */
121 Cy_SysLib_DelayUs(WAIT_SUSPEND_DISABLE);
122 USBFS_DEV_LPM_POWER_CTL(base) &= ~USBFS_USBLPM_POWER_CTL_SUSPEND_Msk;
123 (void) USBFS_DEV_LPM_POWER_CTL(base);
124
125 /* Clears the register (except reserved) and enable IMO lock */
126 USBFS_DEV_CR1(base) = USBFS_USBDEV_CR1_ENABLE_LOCK_Msk |
127 (USBFS_DEV_CR1(base) & USBFS_USBDEV_CR1_RESERVED_3_Msk);
128
129 /* Configures the level selection (HI, MED, LO) for each interrupt source */
130 USBFS_DEV_LPM_INTR_LVL_SEL(base) = config->intrLevelSel;
131
132 /* Enables the interrupt sources: Bus Reset and EP0 */
133 USBFS_DEV_LPM_INTR_SIE_MASK(base) = (USBFS_USBLPM_INTR_SIE_BUS_RESET_INTR_Msk |
134 USBFS_USBLPM_INTR_SIE_EP0_INTR_Msk);
135
136 /* Clears the LPM register (disable LPM response) */
137 USBFS_DEV_LPM_LPM_CTL(base) = 0UL;
138
139 if (config->enableLpm)
140 {
141 /* Enables the device to ACK LPM requests */
142 USBFS_DEV_LPM_LPM_CTL(base) = (USBFS_USBLPM_LPM_CTL_LPM_EN_Msk |
143 USBFS_USBLPM_LPM_CTL_LPM_ACK_RESP_Msk);
144 }
145
146 /* Copies the configuration in the context */
147 context->mode = config->mode;
148 context->useReg16 = (config->epAccess == CY_USBFS_DEV_DRV_USE_16_BITS_DR);
149 context->epSharedBuf = config->epBuffer;
150 context->epSharedBufSize = config->epBufferSize;
151
152 /* Initializes the pointers to functions that work with data endpoint */
153 switch(config->mode)
154 {
155 case CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU:
156 {
157 context->addEndpoint = &AddEndpointHwBuffer;
158 context->loadInEndpoint = &LoadInEndpointCpu;
159 context->readOutEndpoint = &ReadOutEndpointCpu;
160
161 USBFS_DEV_ARB_CFG(base) = _VAL2FLD(USBFS_USBDEV_ARB_CFG_DMA_CFG,
162 CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU);
163
164 retStatus = CY_USBFS_DEV_DRV_SUCCESS;
165 }
166 break;
167
168 case CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA:
169 {
170 context->addEndpoint = &AddEndpointHwBuffer;
171 context->loadInEndpoint = &LoadInEndpointDma;
172 context->readOutEndpoint = &ReadOutEndpointDma;
173
174 USBFS_DEV_ARB_CFG(base) = _VAL2FLD(USBFS_USBDEV_ARB_CFG_DMA_CFG,
175 CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA);
176 }
177 break;
178
179 case CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO:
180 {
181 context->addEndpoint = &AddEndpointRamBuffer;
182 context->loadInEndpoint = &LoadInEndpointDmaAuto;
183 context->readOutEndpoint = &ReadOutEndpointDmaAuto;
184
185 USBFS_DEV_ARB_CFG(base) = (_VAL2FLD(USBFS_USBDEV_ARB_CFG_DMA_CFG,
186 CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO) |
187 USBFS_USBDEV_ARB_CFG_AUTO_MEM_Msk);
188 }
189 break;
190
191 default:
192 /* Unknown mode */
193 break;
194 }
195
196 /* Configure DMA and store info about DMA channels */
197 if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU != context->mode)
198 {
199 retStatus = DmaInit(config, context);
200 }
201
202 return retStatus;
203 }
204
205
206 /*******************************************************************************
207 * Function Name: Cy_USBFS_Dev_Drv_DeInit
208 ****************************************************************************//**
209 *
210 * De-initializes the USBFS Device hardware (returns the register values to
211 * default) and removes all registered callbacks.
212 *
213 * \param base
214 * The pointer to the USBFS instance.
215 *
216 * \param context
217 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
218 * allocated by the user. The structure is used during the USBFS Device
219 * operation for internal configuration and data retention. The user must not
220 * modify anything in this structure.
221 *
222 *******************************************************************************/
Cy_USBFS_Dev_Drv_DeInit(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)223 void Cy_USBFS_Dev_Drv_DeInit(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
224 {
225 uint32_t regVal;
226 uint32_t endpoint;
227
228 /* Set USBLPM registers into the default state */
229 USBFS_DEV_LPM_POWER_CTL(base) = 0UL;
230 USBFS_DEV_LPM_USBIO_CTL(base) = 0UL;
231 USBFS_DEV_LPM_FLOW_CTL(base) = 0UL;
232 USBFS_DEV_LPM_LPM_CTL(base) = 0UL;
233 USBFS_DEV_LPM_INTR_SIE(base) = 0UL;
234 USBFS_DEV_LPM_INTR_SIE_SET(base) = 0UL;
235 USBFS_DEV_LPM_INTR_SIE_MASK(base) = 0UL;
236 USBFS_DEV_LPM_INTR_LVL_SEL(base) = 0UL;
237
238 /* Set USBDEV registers into the default state */
239 USBFS_DEV_CR0(base) = 0UL;
240 USBFS_DEV_CR1(base) = (USBFS_DEV_CR1(base) & USBFS_USBDEV_CR1_RESERVED_3_Msk);
241 USBFS_DEV_USBIO_CR0(base) = 0UL;
242 USBFS_DEV_USBIO_CR1(base) = ((USBFS_DEV_USBIO_CR1(base) & USBFS_USBDEV_USBIO_CR1_RESERVED_2_Msk) |
243 USBFS_USBDEV_USBIO_CR1_IOMODE_Msk);
244 regVal = CY_USBFS_DEV_READ_ODD(USBFS_DEV_USBIO_CR2(base));
245 USBFS_DEV_USBIO_CR2(base) = (CY_USBFS_DEV_DRV_WRITE_ODD(regVal) & USBFS_USBDEV_USBIO_CR2_RESERVED_7_Msk);
246
247 USBFS_DEV_BUS_RST_CNT(base) = BUS_RESET_PERIOD;
248 USBFS_DEV_USB_CLK_EN(base) = CY_USBFS_DEV_DRV_WRITE_ODD(0UL);
249
250 USBFS_DEV_EP0_CR(base) = 0UL;
251 USBFS_DEV_EP0_CNT(base) = CY_USBFS_DEV_DRV_WRITE_ODD(0UL);
252
253 USBFS_DEV_ARB_CFG(base) = 0UL;
254 USBFS_DEV_ARB_INT_EN(base) = 0UL;
255
256 USBFS_DEV_DYN_RECONFIG(base) = 0UL;
257 USBFS_DEV_BUF_SIZE(base) = 0UL;
258 USBFS_DEV_DMA_THRES16(base) = 0UL;
259 USBFS_DEV_EP_ACTIVE(base) = 0UL;
260 USBFS_DEV_EP_TYPE(base) = CY_USBFS_DEV_DRV_WRITE_ODD(0UL);
261 USBFS_DEV_CWA16(base) = 0UL;
262
263 USBFS_DEV_SIE_EP_INT_EN(base) = 0UL;
264 USBFS_DEV_SIE_EP_INT_SR(base) = 0UL;
265
266 for (endpoint = 0UL; endpoint < CY_USBFS_DEV_DRV_NUM_EPS_MAX; ++endpoint)
267 {
268 /* Sets the SIE endpoint register into the default state */
269 USBFS_DEV_SIE_EP_CR0(base, endpoint) = 0UL;
270 USBFS_DEV_SIE_EP_CNT0(base, endpoint) = 0UL;
271 USBFS_DEV_SIE_EP_CNT1(base, endpoint) = 0UL;
272
273 /* Sets the ARBITER endpoint register into the default state */
274 USBFS_DEV_ARB_EP_CFG(base, endpoint) = 0UL;
275 USBFS_DEV_ARB_EP_INT_EN(base, endpoint) = 0UL;
276 USBFS_DEV_ARB_RW_WA16(base, endpoint) = 0UL;
277 USBFS_DEV_ARB_RW_RA16(base, endpoint) = 0UL;
278 }
279
280 /* Cleans the context callbacks */
281 context->cbSof = NULL;
282 context->cbLpm = NULL;
283
284 for (endpoint = 0UL; endpoint < CY_USBFS_DEV_DRV_NUM_EPS_MAX; ++endpoint)
285 {
286 context->epPool[endpoint].address = 0U;
287 context->epPool[endpoint].copyData = NULL;
288 context->epPool[endpoint].epComplete = NULL;
289 context->epPool[endpoint].buffer = NULL;
290 }
291 }
292
293
294 /*******************************************************************************
295 * Function Name: Cy_USBFS_Dev_Drv_Enable
296 ****************************************************************************//**
297 *
298 * Enables the USBFS Device operation.
299 *
300 * \param base
301 * The pointer to the USBFS instance.
302 *
303 * \param context
304 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
305 * allocated by the user. The structure is used during the USBFS Device
306 * operation for internal configuration and data retention. The user must not
307 * modify anything in this structure.
308 *
309 *******************************************************************************/
Cy_USBFS_Dev_Drv_Enable(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t const * context)310 void Cy_USBFS_Dev_Drv_Enable(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t const *context)
311 {
312 /* Suppresses a compiler warning about unused variables */
313 (void) context;
314
315 /* Clears the EP0 count register */
316 USBFS_DEV_EP0_CNT(base) = CY_USBFS_DEV_DRV_WRITE_ODD(0UL);
317
318 /* Sets EP0.CR: ACK Setup, NAK IN/OUT */
319 USBFS_DEV_EP0_CR(base) = CY_USBFS_DEV_DRV_EP_CR_NAK_INOUT;
320
321 /* Enables D+ pull-up, the device appears on the bus */
322 USBFS_DEV_LPM_POWER_CTL(base) |= USBFS_USBLPM_POWER_CTL_DP_UP_EN_Msk;
323 (void) USBFS_DEV_LPM_POWER_CTL(base);
324 }
325
326
327 /*******************************************************************************
328 * Function Name: Cy_USBFS_Dev_Drv_Disable
329 ****************************************************************************//**
330 *
331 * Disables the USBFS Device operation. If DMAs are used, disables the DMAs.
332 *
333 * \param base
334 * The pointer to the USBFS instance.
335 *
336 * \param context
337 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
338 * allocated by the user. The structure is used during the USBFS Device
339 * operation for internal configuration and data retention. The user must not
340 * modify anything in this structure.
341 *
342 *******************************************************************************/
Cy_USBFS_Dev_Drv_Disable(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)343 void Cy_USBFS_Dev_Drv_Disable(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
344 {
345 /* Suppresses a compiler warning about unused variables */
346 (void) context;
347
348 /* Disables D+ pull-up */
349 USBFS_DEV_LPM_POWER_CTL(base) &= ~USBFS_USBLPM_POWER_CTL_DP_UP_EN_Msk;
350 (void) USBFS_DEV_LPM_POWER_CTL(base);
351
352 /* Disables the device to respond to usb traffic */
353 USBFS_DEV_CR0(base) &= ~USBFS_USBDEV_CR0_USB_ENABLE_Msk;
354
355 /* Disables the DMA channels */
356 if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU != context->mode)
357 {
358 DmaDisable(context);
359 }
360 }
361
362
363 /*******************************************************************************
364 * Function Name: LpmIntrHandler
365 ****************************************************************************//**
366 *
367 * LPM (Link Power Manager) interrupt handler.
368 *
369 * \param base
370 * The pointer to the USBFS instance.
371 *
372 * \param context
373 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
374 * allocated by the user. The structure is used during the USBFS Device
375 * operation for internal configuration and data retention. The user must not
376 * modify anything in this structure.
377 *
378 *******************************************************************************/
LpmIntrHandler(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)379 static void LpmIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
380 {
381 if (context->cbLpm != NULL)
382 {
383 context->cbLpm(base, context);
384 }
385 }
386
387
388 /*******************************************************************************
389 * Function Name: SofIntrHandler
390 ****************************************************************************//**
391 *
392 * SOF (Start Of Frame) interrupt handler.
393 *
394 * \param base
395 * The pointer to the USBFS instance.
396 *
397 * \param context
398 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
399 * allocated by the user. The structure is used during the USBFS Device
400 * operation for internal configuration and data retention. The user must not
401 * modify anything in this structure.
402 *
403 *******************************************************************************/
SofIntrHandler(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)404 static void SofIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
405 {
406 if (context->cbSof != NULL)
407 {
408 context->cbSof(base, context);
409 }
410 }
411
412
413 /*******************************************************************************
414 * Function Name: Ep0IntrHandler
415 ****************************************************************************//**
416 *
417 * Endpoint 0 (Control Endpoint) interrupt handler.
418 *
419 * \param base
420 * The pointer to the USBFS instance.
421 *
422 * \param context
423 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
424 * allocated by the user. The structure is used during the USBFS Device
425 * operation for internal configuration and data retention. The user must not
426 * modify anything in this structure.
427 *
428 *******************************************************************************/
Ep0IntrHandler(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)429 static void Ep0IntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
430 {
431 /* Reads the CR register */
432 uint32_t ep0Cr = Cy_USBFS_Dev_Drv_ReadEp0Mode(base);
433
434 /* Checks whether the packet was ACKed */
435 if (0U != (ep0Cr & USBFS_USBDEV_EP0_CR_ACKED_TXN_Msk))
436 {
437 /* Checks the packet direction */
438 if (_FLD2BOOL(USBFS_USBDEV_EP0_CR_SETUP_RCVD, ep0Cr))
439 {
440 /* A setup packet received */
441 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_SETUP;
442
443 /* Handles SETUP */
444 if (_FLD2VAL(USBFS_USBDEV_EP0_CR_MODE, ep0Cr) == CY_USBFS_DEV_DRV_EP_CR_NAK_INOUT)
445 {
446 /* Tries to unlock the CR0 register: read and then write.
447 * The success write clears 8-4 bits in the register.
448 */
449 Cy_USBFS_Dev_Drv_WriteEp0Mode(base, ep0Cr);
450
451 /* Checks whether the CR0 register unlocked (bits cleared) */
452 ep0Cr = Cy_USBFS_Dev_Drv_ReadEp0Mode(base);
453 if (false == _FLD2BOOL(USBFS_USBDEV_EP0_CR_SETUP_RCVD, ep0Cr))
454 {
455 /* Resets the EP0 data toggle */
456 context->ep0DataToggle = 0U;
457
458 /* Calls Device layer to service a request */
459 context->ep0Setup(base, context);
460 }
461 else
462 {
463 /* CR0 is still locked, sets an interrupt pending to retry */
464 Cy_USBFS_Dev_Drv_SetSieInterrupt(base, USBFS_USBLPM_INTR_CAUSE_EP0_INTR_Msk);
465 }
466 }
467 }
468 /* Handles IN */
469 else if (_FLD2BOOL(USBFS_USBDEV_EP0_CR_IN_RCVD, ep0Cr))
470 {
471 if (CY_USBFS_DEV_DRV_EP0_CTRL_STATE_DATA == context->ep0CtrlState)
472 {
473 /* Data stage: invokes a callback to proceed the control transfer */
474 context->ep0In(base, context);
475 }
476 else if (CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_IN == context->ep0CtrlState)
477 {
478 /* Sets an address after the Status stage completion */
479 if (context->setAddress)
480 {
481 Cy_USBFS_Dev_Drv_SetDeviceAddress(base, context->address);
482 context->setAddress = false;
483 }
484
485 /* Completes the control transfer */
486 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_IDLE;
487 }
488 else if (CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_OUT == context->ep0CtrlState)
489 {
490 /* Updates the CNT and CR registers to continue the IN/OUT transfer */
491 Cy_USBFS_Dev_Drv_SetEp0Count (base, 0U, USBFS_USBDEV_EP0_CNT_DATA_TOGGLE_Msk);
492 Cy_USBFS_Dev_Drv_WriteEp0Mode(base, CY_USBFS_DEV_DRV_EP_CR_STATUS_OUT_ONLY);
493
494 /* The transfer is completed */
495 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_IDLE;
496 }
497 else
498 {
499 /* Nothing to handle in this state */
500 }
501 }
502 /* Handles OUT */
503 else if (_FLD2BOOL(USBFS_USBDEV_EP0_CR_OUT_RCVD, ep0Cr))
504 {
505 if (CY_USBFS_DEV_DRV_EP0_CTRL_STATE_DATA == context->ep0CtrlState)
506 {
507 /* Data stage: invokes a callback to proceed the control transfer */
508 context->ep0Out(base, context);
509 }
510 }
511 else
512 {
513 /* Does nothing - an unknown source */
514 }
515 }
516 }
517
518
519 /*******************************************************************************
520 * Function Name: BusResetIntrHandler
521 ****************************************************************************//**
522 *
523 * Bus Reset interrupt handler.
524 *
525 * \param base
526 * The pointer to the USBFS instance.
527 *
528 * \param context
529 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
530 * allocated by the user. The structure is used during the USBFS Device
531 * operation for internal configuration and data retention. The user must not
532 * modify anything in this structure.
533 *
534 *******************************************************************************/
BusResetIntrHandler(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)535 static void BusResetIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
536 {
537 /* Resets the driver variables if any */
538
539 /* Cypress ID# 293217: write CR0 when pull-up is enabled */
540 if (_FLD2BOOL(USBFS_USBLPM_POWER_CTL_DP_UP_EN, USBFS_DEV_LPM_POWER_CTL(base)))
541 {
542 /* Passes an event to the Device layer */
543 context->busReset(base, context);
544
545 /* Clears the EP0 count register */
546 USBFS_DEV_EP0_CNT(base) = CY_USBFS_DEV_DRV_WRITE_ODD(0UL);
547
548 /* Sets EP0.CR: ACK Setup, NAK IN/OUT */
549 USBFS_DEV_EP0_CR(base) = CY_USBFS_DEV_DRV_EP_CR_NAK_INOUT;
550
551 /* Resets the driver context variables into the default state */
552 context->setAddress = false;
553 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_IDLE;
554 context->curBufAddr = 0U;
555 context->activeEpMask = 0U;
556 context->epAbortMask = 0U;
557
558 /* Enable device to responds to USB traffic with address 0 */
559 USBFS_DEV_CR0(base) = USBFS_USBDEV_CR0_USB_ENABLE_Msk;
560 (void) USBFS_DEV_CR0(base);
561 }
562 }
563
564
565 /*******************************************************************************
566 * Function Name: EndpointTransferComplete
567 ****************************************************************************//**
568 *
569 * Handles the endpoint transfer complete: updates the endpoint state,
570 * calls a transfer completion callback, handles the abort.
571 *
572 * \param base
573 * The pointer to the USBFS instance.
574 *
575 * \param endpoint
576 * The data endpoint index.
577 *
578 * \param endpointData
579 * The pointer to the endpoint data structure.
580 *
581 * \param context
582 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
583 * allocated by the user. The structure is used during the USBFS Device
584 * operation for internal configuration and data retention. The user must not
585 * modify anything in this structure.
586 *
587 *******************************************************************************/
EndpointTransferComplete(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_endpoint_data_t * endpointData,cy_stc_usbfs_dev_drv_context_t * context)588 static void EndpointTransferComplete(USBFS_Type *base, uint32_t endpoint,
589 cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData,
590 cy_stc_usbfs_dev_drv_context_t *context)
591 {
592 /* Updates the toggle (exclude ISOC endpoints) */
593 if (false == IS_EP_ISOC(endpointData->sieMode))
594 {
595 endpointData->toggle ^= (uint8_t) USBFS_USBDEV_SIE_EP_DATA_TOGGLE_Msk;
596 }
597
598 if (0U != (context->epAbortMask & EP2MASK(endpoint)))
599 {
600 /* Clears the endpoint abort: Do not invoke callback, the state was set to idle */
601 context->epAbortMask &= (uint8_t) ~EP2MASK(endpoint);
602 }
603 else
604 {
605 /* Data has been transferred to the bus set-endpoint complete state */
606 endpointData->state = CY_USB_DEV_EP_COMPLETED;
607
608 /* Involves a callback if it is registered */
609 if (NULL != endpointData->epComplete)
610 {
611 uint32_t errorType = 0UL;
612
613 /* Checks transfer errors (detect by hardware) */
614 if (0U != Cy_USBFS_Dev_Drv_GetSieEpError(base, endpoint))
615 {
616 errorType = CY_USBFS_DEV_ENDPOINT_TRANSFER_ERROR;
617 }
618
619 /* Checks the data toggle bit of current transfer (exclude ISOC endpoints) */
620 if (false == IS_EP_ISOC(endpointData->sieMode))
621 {
622 /* This may fail only for OUT endpoints */
623 if (endpointData->toggle == Cy_USBFS_Dev_Drv_GetSieEpToggle(base, endpoint))
624 {
625 errorType |= CY_USBFS_DEV_ENDPOINT_SAME_DATA_TOGGLE;
626
627 /* Restores the data toggle to recover it in the next OUT transfer */
628 endpointData->toggle ^= (uint8_t) USBFS_USBDEV_SIE_EP_DATA_TOGGLE_Msk;
629 }
630 }
631
632 /* Calls the endpoint complete callback */
633 endpointData->epComplete(base, (uint32_t) endpointData->address, errorType, context);
634 }
635 }
636 }
637
638
639 /*******************************************************************************
640 * Function Name: ArbiterIntrHandler
641 ****************************************************************************//**
642 *
643 * Arbiter interrupt handler (enabled for operation with DMAs).
644 *
645 * \param base
646 * The pointer to the USBFS instance.
647 *
648 * \param context
649 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
650 * allocated by the user. The structure is used during the USBFS Device
651 * operation for internal configuration and data retention. The user must not
652 * modify anything in this structure.
653 *
654 *******************************************************************************/
ArbiterIntrHandler(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)655 static void ArbiterIntrHandler(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
656 {
657 uint32_t endpoint = 0UL;
658 uint32_t intrMask = Cy_USBFS_Dev_Drv_GetArbAllEpsInterruptStatus(base);
659
660 /* Handle active interrupt sources */
661 while (0U != intrMask)
662 {
663 if (0U != (intrMask & 0x01U))
664 {
665 /* Get the endpoint enable interrupt sources */
666 uint32_t sourceMask = Cy_USBFS_Dev_Drv_GetArbEpInterruptStatusMasked(base, endpoint);
667
668 /* Gets the pointer to the endpoint data */
669 cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData = &context->epPool[endpoint];
670
671 Cy_USBFS_Dev_Drv_ClearArbEpInterrupt(base, endpoint, sourceMask);
672
673 /* Mode 2/3: Handle IN endpoint buffer full event: trigger after
674 * endpoint buffer has been loaded
675 */
676 if (0U != (sourceMask & USBFS_USBDEV_ARB_EP_IN_BUF_FULL_Msk))
677 {
678 Cy_USBFS_Dev_Drv_ClearArbCfgEpInReady(base, endpoint);
679
680 /* Mode 2: Notifies the LoadInEndpointDma function that data has been copied into the endpoint buffer.
681 * Mode 3: No impact, the endpoint pending state is set in LoadInEndpointDmaAuto before.
682 */
683 endpointData->state = CY_USB_DEV_EP_PENDING;
684
685 /* Arm IN endpoint */
686 Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, (uint32_t) endpointData->sieMode);
687 }
688
689 /* Mode 2: Handle DMA completion event for OUT endpoints */
690 if (0U != (sourceMask & USBFS_USBDEV_ARB_EP_DMA_GNT_Msk))
691 {
692 /* Notifies the ReadOutEndpointDma function that the data has been copied from endpoint buffer
693 * into the user buffer.
694 */
695 endpointData->state = CY_USB_DEV_EP_COMPLETED;
696 }
697
698 /* Mode 3: Handles a DMA completion event for OUT endpoints */
699 if (0U != (sourceMask & USBFS_USBDEV_ARB_EP_DMA_TERMIN_Msk))
700 {
701 /* Sets a DMA channel to start a new transfer */
702 DmaOutEndpointRestore(endpointData);
703
704 /* Completes an endpoint transfer */
705 EndpointTransferComplete(base, endpoint, endpointData, context);
706 }
707
708 /* This error condition indicates system failure */
709 if (0U != (sourceMask & USBFS_USBDEV_ARB_EP_BUF_OVER_Msk))
710 {
711 /* The DMA cannot move the data from the mxusbfs IP
712 * hardware buffer fast enough and so caused an overflow. Give a DMA
713 * channel for this endpoint greater priority or increase the clock
714 * at which it operates.
715 */
716 CY_ASSERT_L1(false);
717 }
718
719 /* This error condition indicates system failure */
720 if (0U != (sourceMask & USBFS_USBDEV_ARB_EP_BUF_UNDER_Msk))
721 {
722 /* The DMA cannot move the data into the mxusbfs IP
723 * hardware buffer fast enough and so caused an underflow. Give a DMA
724 * channel for this endpoint greater priority or increase the clock
725 * at which it operates.
726 */
727 CY_ASSERT_L1(false);
728 }
729 }
730
731 /* Moves to a next endpoint */
732 intrMask >>= 1UL;
733 ++endpoint;
734 }
735 }
736
737
738 /*******************************************************************************
739 * Function Name: SieEnpointIntrHandler
740 ****************************************************************************//**
741 *
742 * SIE (Serial Interface Engine) endpoint interrupt handler.
743 * It triggers when communication was completed with data endpoint.
744 *
745 * \param base
746 * The pointer to the USBFS instance.
747 *
748 * \param endpoint
749 * The data endpoint number.
750 *
751 * \param context
752 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
753 * allocated by the user. The structure is used during the USBFS Device
754 * operation for internal configuration and data retention. The user must not
755 * modify anything in this structure.
756 *
757 *******************************************************************************/
SieEnpointIntrHandler(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)758 static void SieEnpointIntrHandler(USBFS_Type *base, uint32_t endpoint,
759 cy_stc_usbfs_dev_drv_context_t *context)
760 {
761 bool modeDmaAuto;
762 bool inEndpoint;
763 bool zeroLengthPacket;
764
765 /* Gets the pointer to endpoint data */
766 cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData = &context->epPool[endpoint];
767
768 Cy_USBFS_Dev_Drv_ClearSieEpInterrupt(base, endpoint);
769
770 /*
771 * DMA Auto requires special processing:
772 * IN endpoints: Updates the endpoint state here to complete the transfer (includes a zero-length packet).
773 * OUT endpoints: Updates the endpoint state in ArbiterIntrHandler when DMA is done to complete the transfer
774 * (interrupt source DMA_TERMIN).
775 * In the case of a zero-length packet, updates the endpoint state here to complete the transfer.
776 * Other modes (CPU mode and DMA mode): Updates the endpoint state here to complete the transfer for the IN and OUT endpoints.
777 */
778 modeDmaAuto = (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO == context->mode);
779 inEndpoint = CY_USBFS_DEV_DRV_IS_EP_DIR_IN(endpointData->address);
780 zeroLengthPacket = (0U == Cy_USBFS_Dev_Drv_GetSieEpCount(base, endpoint));
781
782 CY_MISRA_FP_LINE('MISRA C-2012 Rule 14.3', 'Checked manually. No issues.');
783 if ( (!modeDmaAuto) ||
784 (modeDmaAuto && (inEndpoint || zeroLengthPacket)) )
785 {
786 EndpointTransferComplete(base, endpoint, endpointData, context);
787 }
788 }
789
790
791 /*******************************************************************************
792 * Function Name: Cy_USBFS_Dev_Drv_Interrupt
793 ****************************************************************************//**
794 *
795 * Processes interrupt events generated by the USBFS Device.
796 * The interrupts are mandatory for USBFS Device operation and this function
797 * must be called inside the user-defined interrupt service routine.
798 *
799 * \param base
800 * The pointer to the USBFS instance.
801 *
802 * \param intrCause
803 * The interrupt cause register value. Call appropriate function to get
804 * interrupt cause (Low, Medium or High):
805 * * \ref Cy_USBFS_Dev_Drv_GetInterruptCauseLo
806 * * \ref Cy_USBFS_Dev_Drv_GetInterruptCauseMed
807 * * \ref Cy_USBFS_Dev_Drv_GetInterruptCauseHi
808 *
809 * \param context
810 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
811 * allocated by the user. The structure is used during the USBFS Device
812 * operation for internal configuration and data retention. The user must not
813 * modify anything in this structure.
814 *
815 *******************************************************************************/
Cy_USBFS_Dev_Drv_Interrupt(USBFS_Type * base,uint32_t intrCause,cy_stc_usbfs_dev_drv_context_t * context)816 void Cy_USBFS_Dev_Drv_Interrupt(USBFS_Type *base, uint32_t intrCause,
817 cy_stc_usbfs_dev_drv_context_t *context)
818 {
819 uint32_t endpoint = 0U;
820 uint32_t intrCauseEp;
821
822 /* Clears the SIE interrupts while the below are served */
823 Cy_USBFS_Dev_Drv_ClearSieInterrupt(base, intrCause);
824
825 /* LPM */
826 if (0U != (intrCause & USBFS_USBLPM_INTR_CAUSE_LPM_INTR_Msk))
827 {
828 LpmIntrHandler(base, context);
829 }
830
831 /* Arbiter: Data endpoints */
832 if (0U != (intrCause & USBFS_USBLPM_INTR_CAUSE_ARB_EP_INTR_Msk))
833 {
834 /* This interrupt is cleared inside the handler */
835 ArbiterIntrHandler(base, context);
836 }
837
838 /* SIE: Data endpoints */
839 intrCauseEp = (intrCause >> USBFS_USBLPM_INTR_CAUSE_EP1_INTR_Pos);
840 while (0U != intrCauseEp)
841 {
842 if (0u != (intrCauseEp & 0x1U))
843 {
844 /* These interrupts are cleared inside the handler */
845 SieEnpointIntrHandler(base, endpoint, context);
846 }
847
848 intrCauseEp >>= 1U;
849 ++endpoint;
850 }
851
852 /* SOF */
853 if (0U != (intrCause & USBFS_USBLPM_INTR_CAUSE_SOF_INTR_Msk))
854 {
855 SofIntrHandler(base, context);
856 }
857
858 /* Controls EP0 */
859 if (0U != (intrCause & USBFS_USBLPM_INTR_CAUSE_EP0_INTR_Msk))
860 {
861 Ep0IntrHandler(base, context);
862 }
863
864 /* Bus Reset */
865 if (0U != (intrCause & USBFS_USBLPM_INTR_CAUSE_BUS_RESET_INTR_Msk))
866 {
867 BusResetIntrHandler(base, context);
868 }
869 }
870
871
872 /*******************************************************************************
873 * Function Name: WriteEp0Buffer
874 ****************************************************************************//**
875 *
876 * Writes data into the Endpoint 0 hardware buffer and returns how many bytes
877 * were written.
878 *
879 * \param base
880 * The pointer to the USBFS instance.
881 *
882 * \param buffer
883 * The pointer to the data to write in the Endpoint 0.
884 *
885 * \param size
886 * The number of bytes to write into the Endpoint 0.
887 *
888 * \return
889 * The number of bytes that were written.
890 *
891 *******************************************************************************/
WriteEp0Buffer(USBFS_Type * base,uint8_t const * buffer,uint32_t size)892 static uint32_t WriteEp0Buffer(USBFS_Type *base, uint8_t const *buffer, uint32_t size)
893 {
894 uint32_t idx;
895
896 /* Cuts the message size if too many bytes are requested to write */
897 if (size > CY_USBFS_DEV_DRV_EP0_BUFFER_SIZE)
898 {
899 size = CY_USBFS_DEV_DRV_EP0_BUFFER_SIZE;
900 }
901
902 /* Writes data into the hardware buffer */
903 for (idx = 0UL; idx < size; ++idx)
904 {
905 Cy_USBFS_Dev_Drv_WriteEp0Data(base, idx, (uint32_t) buffer[idx]);
906 }
907
908 return idx;
909 }
910
911
912 /*******************************************************************************
913 * Function Name: ReadEp0Buffer
914 ****************************************************************************//**
915 *
916 * Reads data from Endpoint 0 hardware and returns how many bytes were read.
917 *
918 * \param base
919 * The pointer to the USBFS instance.
920 *
921 * \param buffer
922 * The pointer to the buffer for data read from the Endpoint 0.
923 *
924 * \param size
925 * The number of bytes to read from the Endpoint 0.
926 *
927 * \return
928 * The number of bytes that were read.
929 *
930 *******************************************************************************/
ReadEp0Buffer(USBFS_Type const * base,uint8_t * buffer,uint32_t size)931 static uint32_t ReadEp0Buffer(USBFS_Type const *base, uint8_t *buffer, uint32_t size)
932 {
933 uint32_t idx;
934
935 /* Gets the number of received bytes */
936 uint32_t numToCopy = Cy_USBFS_Dev_Drv_GetEp0Count(base);
937
938 /* Reads received bytes only */
939 if (size > numToCopy)
940 {
941 size = numToCopy;
942 }
943
944 /* Gets the data from the buffer */
945 for (idx = 0UL; idx < size; ++idx)
946 {
947 buffer[idx] = (uint8_t) Cy_USBFS_Dev_Drv_ReadEp0Data(base, idx);
948 }
949
950 return idx;
951 }
952
953
954 /*******************************************************************************
955 * Function Name: Cy_USBFS_Dev_Drv_Ep0GetSetup
956 ****************************************************************************//**
957 *
958 * Reads the setup packed from the Endpoint 0 hardware buffer.
959 *
960 * \param base
961 * The pointer to the USBFS instance.
962 *
963 * \param buffer
964 * The pointer to the buffer for data read from the Endpoint 0.
965 *
966 * \param context
967 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
968 * allocated by the user. The structure is used during the USBFS Device
969 * operation for internal configuration and data retention. The user must not
970 * modify anything in this structure.
971 *
972 *******************************************************************************/
Cy_USBFS_Dev_Drv_Ep0GetSetup(USBFS_Type const * base,uint8_t * buffer,cy_stc_usbfs_dev_drv_context_t const * context)973 void Cy_USBFS_Dev_Drv_Ep0GetSetup(USBFS_Type const *base, uint8_t *buffer,
974 cy_stc_usbfs_dev_drv_context_t const *context)
975 {
976 /* Suppresses a compiler warning about unused variables */
977 (void) context;
978
979 (void) ReadEp0Buffer(base, buffer, CY_USBFS_DEV_DRV_EP0_BUFFER_SIZE);
980 }
981
982
983 /*******************************************************************************
984 * Function Name: Cy_USBFS_Dev_Drv_Ep0Write
985 ****************************************************************************//**
986 *
987 * Writes data into Endpoint 0 hardware buffer and returns how many bytes were
988 * written.
989 *
990 * \param base
991 * The pointer to the USBFS instance.
992 *
993 * \param buffer
994 * The pointer to the buffer containing data bytes to write.
995 * To switch a transfer from the data stage to status, pass NULL as a pointer.
996 *
997 * \param size
998 * The number of bytes to write.
999 * Setting the size to zero sends to the bus zero-length data packet.
1000 *
1001 * \param context
1002 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1003 * allocated by the user. The structure is used during the USBFS Device
1004 * operation for internal configuration and data retention. The user must not
1005 * modify anything in this structure.
1006 *
1007 * \return
1008 * The number of bytes that were written.
1009 *
1010 *******************************************************************************/
Cy_USBFS_Dev_Drv_Ep0Write(USBFS_Type * base,uint8_t const * buffer,uint32_t size,cy_stc_usbfs_dev_drv_context_t * context)1011 uint32_t Cy_USBFS_Dev_Drv_Ep0Write(USBFS_Type *base, uint8_t const *buffer, uint32_t size,
1012 cy_stc_usbfs_dev_drv_context_t *context)
1013 {
1014 uint32_t numBytes = 0UL;
1015
1016 if (NULL != buffer)
1017 {
1018 /* Data stage (IN): Loads data to be sent */
1019
1020 /* Puts the data into the buffer */
1021 if (size > 0U)
1022 {
1023 numBytes = WriteEp0Buffer(base, buffer, size);
1024 }
1025
1026 /* Updates the data toggle and counter */
1027 context->ep0DataToggle ^= (uint8_t) USBFS_USBDEV_EP0_CNT_DATA_TOGGLE_Msk;
1028
1029 /* Updates the CNT and CR registers to continue the IN transfer */
1030 Cy_USBFS_Dev_Drv_SetEp0Count (base, numBytes, (uint32_t) context->ep0DataToggle);
1031 Cy_USBFS_Dev_Drv_WriteEp0Mode(base, CY_USBFS_DEV_DRV_EP_CR_ACK_IN_STATUS_OUT);
1032
1033 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_DATA;
1034 }
1035 else
1036 {
1037 /* Status stage (IN): Completes the status stage, sends an ACK handshake */
1038
1039 /* Updates the CNT and CR registers to continue the IN transfer */
1040 Cy_USBFS_Dev_Drv_SetEp0Count (base, numBytes, USBFS_USBDEV_EP0_CNT_DATA_TOGGLE_Msk);
1041 Cy_USBFS_Dev_Drv_WriteEp0Mode(base, CY_USBFS_DEV_DRV_EP_CR_STATUS_IN_ONLY);
1042
1043 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_IN;
1044 }
1045
1046 return numBytes;
1047 }
1048
1049
1050 /*******************************************************************************
1051 * Function Name: Cy_USBFS_Dev_Drv_Ep0Read
1052 ****************************************************************************//**
1053 *
1054 * Start receiving a packet into the Endpoint 0 hardware buffer.
1055 *
1056 * \param base
1057 * The pointer to the USBFS instance.
1058 *
1059 * \param buffer
1060 * The pointer to buffer that stores data that was read.
1061 *
1062 * \param size
1063 * The number of bytes to read.
1064 * Reading zero bytes switch control transfer to status stage.
1065 *
1066 * \param context
1067 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1068 * allocated by the user. The structure is used during the USBFS Device
1069 * operation for internal configuration and data retention. The user must not
1070 * modify anything in this structure.
1071 *
1072 *******************************************************************************/
Cy_USBFS_Dev_Drv_Ep0Read(USBFS_Type * base,uint8_t * buffer,uint32_t size,cy_stc_usbfs_dev_drv_context_t * context)1073 void Cy_USBFS_Dev_Drv_Ep0Read(USBFS_Type *base, uint8_t *buffer, uint32_t size,
1074 cy_stc_usbfs_dev_drv_context_t *context)
1075 {
1076 if (0U != size)
1077 {
1078 /* Data stage (OUT): Prepares to receive data */
1079
1080 /* Stores the Endpoint 0 buffer to put read operation results */
1081 context->ep0Buffer = buffer;
1082 context->ep0BufferSize = (uint8_t) size; /* The Endpoint 0 max packet is 8 bytes */
1083
1084 /* Updates the CNT and CR registers to continue the OUT transfer */
1085 Cy_USBFS_Dev_Drv_SetEp0Count (base, 0U, 0U);
1086 Cy_USBFS_Dev_Drv_WriteEp0Mode(base, CY_USBFS_DEV_DRV_EP_CR_ACK_OUT_STATUS_IN);
1087
1088 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_DATA;
1089 }
1090 else
1091 {
1092 /* Status stage (OUT): prepare to complete status stage after IN transfer is finished */
1093 context->ep0CtrlState = CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_OUT;
1094 }
1095 }
1096
1097
1098 /*******************************************************************************
1099 * Function Name: Cy_USBFS_Dev_Drv_Ep0ReadResult
1100 ****************************************************************************//**
1101 *
1102 * Reads data from the Endpoint 0 hardware and returns the number of read bytes.
1103 *
1104 * \param base
1105 * The pointer to the USBFS instance.
1106 *
1107 * \param context
1108 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1109 * allocated by the user. The structure is used during the USBFS Device
1110 * operation for internal configuration and data retention. The user must not
1111 * modify anything in this structure.
1112 *
1113 * \return
1114 * The number of read bytes.
1115 *
1116 *******************************************************************************/
Cy_USBFS_Dev_Drv_Ep0ReadResult(USBFS_Type const * base,cy_stc_usbfs_dev_drv_context_t * context)1117 uint32_t Cy_USBFS_Dev_Drv_Ep0ReadResult(USBFS_Type const *base, cy_stc_usbfs_dev_drv_context_t *context)
1118 {
1119 /* Stores received data to the buffer */
1120 return ReadEp0Buffer(base, context->ep0Buffer, (uint32_t) context->ep0BufferSize);
1121 }
1122
1123
1124 /*******************************************************************************
1125 * Function Name: Cy_USBFS_Dev_Drv_RegisterServiceCallback
1126 ****************************************************************************//**
1127 *
1128 * Registers a callback function to notify about service events (Bus Reset or
1129 * Endpoint 0 communication) in \ref Cy_USBFS_Dev_Drv_Interrupt.
1130 * To remove callback function, pass NULL as function pointer.
1131 *
1132 * \param base
1133 * The pointer to the USBFS instance.
1134 *
1135 * \param source
1136 * The event that involves the callback.
1137 *
1138 * \param callback
1139 * The pointer to a callback function.
1140 *
1141 * \param context
1142 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1143 * allocated by the user. The structure is used during the USBFS Device
1144 * operation for internal configuration and data retention. The user must not
1145 * modify anything in this structure.
1146 *
1147 * \return
1148 * The status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
1149 *
1150 *******************************************************************************/
Cy_USBFS_Dev_Drv_RegisterServiceCallback(USBFS_Type const * base,cy_en_usb_dev_service_cb_t source,cy_cb_usbfs_dev_drv_callback_t callback,cy_stc_usbfs_dev_drv_context_t * context)1151 void Cy_USBFS_Dev_Drv_RegisterServiceCallback(USBFS_Type const *base,
1152 cy_en_usb_dev_service_cb_t source,
1153 cy_cb_usbfs_dev_drv_callback_t callback,
1154 cy_stc_usbfs_dev_drv_context_t *context)
1155 {
1156 /* Suppresses a compiler warning about unused variables */
1157 (void) base;
1158
1159 switch(source)
1160 {
1161 case CY_USB_DEV_BUS_RESET:
1162 context->busReset = callback;
1163 break;
1164
1165 case CY_USB_DEV_EP0_SETUP:
1166 context->ep0Setup = callback;
1167 break;
1168
1169 case CY_USB_DEV_EP0_IN:
1170 context->ep0In = callback;
1171 break;
1172
1173 case CY_USB_DEV_EP0_OUT:
1174 context->ep0Out = callback;
1175 break;
1176
1177 default:
1178 /* Unknown callback */
1179 break;
1180 }
1181 }
1182
1183 /*******************************************************************************
1184 * Function Name: RestoreDeviceConfiguration
1185 ****************************************************************************//**
1186 *
1187 * Restores device configuration and data endpoints for the active mode
1188 * operation.
1189 *
1190 * \param base
1191 * The pointer to the USBFS instance.
1192 *
1193 * \param context
1194 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1195 * allocated by the user. The structure is used during the USBFS Device
1196 * operation for internal configuration and data retention. The user must not
1197 * modify anything in this structure.
1198 *
1199 *******************************************************************************/
RestoreDeviceConfiguration(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)1200 static void RestoreDeviceConfiguration(USBFS_Type *base,
1201 cy_stc_usbfs_dev_drv_context_t *context)
1202 {
1203 uint32_t endpoint;
1204
1205 /* Due to Deep Sleep, non-retention registers are set to the default state */
1206
1207 for (endpoint = 0U; endpoint < CY_USBFS_DEV_DRV_NUM_EPS_MAX; ++endpoint)
1208 {
1209 if (0U != context->epPool[endpoint].address)
1210 {
1211 /* Restores the endpoint configuration */
1212 if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO == context->mode)
1213 {
1214 RestoreEndpointRamBuffer(base, &context->epPool[endpoint]);
1215 }
1216 else
1217 {
1218 RestoreEndpointHwBuffer(base, context->mode, &context->epPool[endpoint]);
1219 }
1220 }
1221 }
1222
1223 /* Completes the device configuration */
1224 Cy_USBFS_Dev_Drv_ConfigDevice(base, context);
1225 }
1226
1227
1228 /*******************************************************************************
1229 * Function Name: Cy_USBFS_Dev_Drv_Suspend
1230 ****************************************************************************//**
1231 *
1232 * Prepares the USBFS component to enter Deep Sleep mode.
1233 *
1234 * \param base
1235 * The pointer to the USBFS instance.
1236 *
1237 * \param context
1238 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1239 * allocated by the user. The structure is used during the USBFS Device
1240 * operation for internal configuration and data retention. The user must not
1241 * modify anything in this structure.
1242 *
1243 * \note
1244 * After entering low-power mode, the data that is left in the IN or OUT
1245 * endpoint buffers is not restored after a wakeup, and is lost. Therefore, it should
1246 * be stored in the SRAM for OUT endpoint or read by the host for the IN endpoint
1247 * before entering low-power mode.
1248 *
1249 *******************************************************************************/
Cy_USBFS_Dev_Drv_Suspend(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)1250 void Cy_USBFS_Dev_Drv_Suspend(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
1251 {
1252 /* Puts PHY to suspend mode */
1253 USBFS_DEV_LPM_POWER_CTL(base) |= USBFS_USBLPM_POWER_CTL_SUSPEND_Msk;
1254 (void) USBFS_DEV_LPM_POWER_CTL(base);
1255
1256 /* Disables all DMA channels: DMA registers are retention */
1257 if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU != context->mode)
1258 {
1259 DmaDisable(context);
1260 }
1261 }
1262
1263
1264 /*******************************************************************************
1265 * Function Name: Cy_USBFS_Dev_Drv_Resume
1266 ****************************************************************************//**
1267 *
1268 * Prepares the USBFS component for operation after exiting Deep Sleep mode.
1269 *
1270 * \param base
1271 * The pointer to the USBFS instance.
1272 *
1273 * \param context
1274 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
1275 * allocated by the user. The structure is used during the USBFS Device
1276 * operation for internal configuration and data retention. The user must not
1277 * modify anything in this structure.
1278 *
1279 *******************************************************************************/
Cy_USBFS_Dev_Drv_Resume(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)1280 void Cy_USBFS_Dev_Drv_Resume(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
1281 {
1282 uint32_t lpmCtl;
1283
1284 /* Enables the clock to mxusbfs IP */
1285 USBFS_DEV_USB_CLK_EN(base) = CY_USBFS_DEV_DRV_WRITE_ODD(USBFS_USBDEV_USB_CLK_EN_CSR_CLK_EN_Msk);
1286
1287 /* Sets the number of clocks (divided version of Clk_Peri) to detect bus reset */
1288 USBFS_DEV_BUS_RST_CNT(base) = BUS_RESET_PERIOD;
1289
1290 /* Sets EP0.CR: ACK Setup, NAK IN/OUT */
1291 USBFS_DEV_EP0_CR(base) = CY_USBFS_DEV_DRV_EP_CR_NAK_INOUT;
1292
1293 /* Restores the data endpoints configuration */
1294 RestoreDeviceConfiguration(base, context);
1295
1296 /* Cypress ID# 337915: Restore response to LPM packets */
1297 lpmCtl = USBFS_DEV_LPM_LPM_CTL(base);
1298 USBFS_DEV_LPM_LPM_CTL(base) = lpmCtl;
1299
1300 /* Releases PHY from suspend mode */
1301 USBFS_DEV_LPM_POWER_CTL(base) &= ~USBFS_USBLPM_POWER_CTL_SUSPEND_Msk;
1302 (void) USBFS_DEV_LPM_POWER_CTL(base);
1303 }
1304
1305 #if defined(__cplusplus)
1306 }
1307 #endif
1308
1309 #endif /* CY_IP_MXUSBFS */
1310
1311
1312 /* [] END OF FILE */
1313