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