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