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