1 /***************************************************************************//**
2 * \file cy_keyscan.c
3 * \version 1.0
4 *
5 * \brief
6 * Provides an API declaration of the KEYSCAN driver
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2020-2021, Cypress Semiconductor Corporation. All rights reserved.
11 * You may use this file only in accordance with the license, terms, conditions,
12 * disclaimers, and limitations in the end user license agreement accompanying
13 * the software package with which this file was provided.
14 *******************************************************************************/
15 #include "cy_device.h"
16 #if defined (CY_IP_MXKEYSCAN)
17 /*****************************************************************************/
18 /* Include files                                                             */
19 /*****************************************************************************/
20 #include "cy_keyscan.h"
21 #include <string.h>
22 
23 /*****************************************************************************/
24 /* Local pre-processor symbols/macros ('#define')                            */
25 /*****************************************************************************/
26 
27 
28 /*****************************************************************************/
29 /* Global variable definitions (declared in header file with 'extern')       */
30 /*****************************************************************************/
31 
32 /*****************************************************************************/
33 /* Local type definitions ('typedef')                                        */
34 /*****************************************************************************/
35 
36 
37 /*****************************************************************************/
38 /* Local variable definitions ('static')                                     */
39 /*****************************************************************************/
40 
41 
42 /*****************************************************************************/
43 /* Local function prototypes ('static')                                      */
44 /*****************************************************************************/
45 static cy_en_ks_status_t Cy_Keyscan_GetEventsFromHWFifo(MXKEYSCAN_Type *base, cy_stc_keyscan_context_t *context);
46 static cy_en_ks_status_t Cy_Keyscan_Fq_Flush(cy_stc_keyscan_context_t* context);
47 static cy_en_ks_status_t Cy_Keyscan_Fq_GetCurNumElements(cy_stc_keyscan_context_t* context, uint8_t *numElements);
48 static cy_en_ks_status_t Cy_Keyscan_Fq_PutIncludeOverflowSlot(cy_stc_keyscan_context_t* context, cy_stc_key_event *element);
49 static cy_en_ks_status_t Cy_Keyscan_Fq_GetCurElmPtr(cy_stc_keyscan_context_t* context, cy_stc_key_event **current_element);
50 static cy_en_ks_status_t Cy_Keyscan_Fq_RemoveCurElement(cy_stc_keyscan_context_t* context);
51 static cy_en_ks_status_t Cy_Keyscan_Fq_Put(cy_stc_keyscan_context_t* context, cy_stc_key_event *element);
52 static cy_en_ks_status_t Cy_Keyscan_Fq_MarkCurrentEventForRollBack (cy_stc_keyscan_context_t* context);
53 static cy_en_ks_status_t Cy_Keyscan_Fq_RollbackUptoMarkedEvents(cy_stc_keyscan_context_t* context);
54 static cy_en_ks_status_t Cy_Keyscan_PutEvent(cy_stc_keyscan_context_t* context, cy_stc_key_event *event);
55 static cy_en_ks_status_t Cy_Keyscan_GetEvent(cy_stc_keyscan_context_t* context, cy_stc_key_event *event);
56 static cy_en_ks_status_t Cy_Keyscan_Mia_FreezeClk(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context);
57 static cy_en_ks_status_t Cy_Keyscan_Mia_UnfreezeClk(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context);
58 static cy_en_ks_status_t Cy_Keyscan_HwResetOnce(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context);
59 static cy_en_ks_status_t Cy_Keyscan_Init_Context( cy_stc_keyscan_context_t* context);
60 
61 /*****************************************************************************/
62 /* Function implementation - global ('extern') and local ('static')          */
63 /*****************************************************************************/
64 
65 /**
66  *****************************************************************************
67  ** Discards elements from Keyscan FW circular FIFO.
68  ** This Function Discards all elements from the FIFO, including any elements in the overflow slot.
69  **
70  ** [in]  context     Pointer to the context.
71  **
72  **
73  **
74  *****************************************************************************/
Cy_Keyscan_Fq_Flush(cy_stc_keyscan_context_t * context)75 static cy_en_ks_status_t Cy_Keyscan_Fq_Flush(cy_stc_keyscan_context_t* context)
76 {
77     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
78     /* Check if pointers are valid */
79     if (NULL == context)
80     {
81         status = CY_KEYSCAN_BAD_PARAM;
82     }
83     else
84     {
85         context->readIndex = context->writeIndex = context->curNumElements = 0U;
86     }
87     return status;
88 }
89 
90 /**
91  *****************************************************************************
92  ** Returns no of elements in the keyscan FW circular FIFO.
93  ** This function discards all elements from the FIFO, including any elements in the overflow slot.
94  **
95  ** [in]  context      Pointer to the context.
96  **
97  ** [out] numElements  Pointer to the number of elements.
98  **
99  **
100  **
101  *****************************************************************************/
Cy_Keyscan_Fq_GetCurNumElements(cy_stc_keyscan_context_t * context,uint8_t * numElements)102 static cy_en_ks_status_t Cy_Keyscan_Fq_GetCurNumElements(cy_stc_keyscan_context_t* context, uint8_t *numElements)
103 {
104     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
105     /* Check if pointers are valid */
106     if ((NULL == context) || (NULL == numElements))
107     {
108         status = CY_KEYSCAN_BAD_PARAM;
109     }
110     else
111     {
112         *numElements = context->curNumElements;
113     }
114     return status;
115 }
116 /**
117  *****************************************************************************
118  ** Puts an element into the FIFO as long as there is room for 1 element or more, i.e.
119  **         this method will fill in the overflow slot if that is the
120  **         last slot left. Should be used if (a) overflow slots are not needed (b)
121  **         for queuing an overflow event.
122  **
123  ** [in]  context      Pointer to the context.
124  **
125  ** [in]  element      pointer to the element to be placed in the FIFO
126  **
127  ** [in]  length       length number of bytes in element. This number of bytes is copied into the
128  **                           internal storage of the FIFO. This must be <= the maximum element size
129  **                           specified when the FIFO was constructed, otherwise the results are undefined.
130  **
131  **
132  **
133  *****************************************************************************/
Cy_Keyscan_Fq_PutIncludeOverflowSlot(cy_stc_keyscan_context_t * context,cy_stc_key_event * element)134 static cy_en_ks_status_t Cy_Keyscan_Fq_PutIncludeOverflowSlot(cy_stc_keyscan_context_t* context, cy_stc_key_event *element)
135 {
136     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
137     /* Check if pointers are valid */
138     if ( (NULL == element) || (NULL == context))
139     {
140         status = CY_KEYSCAN_BAD_PARAM;
141     }
142     else
143     {
144         // Check if we have room including the overflow slot
145         if (context->curNumElements < context->maxNumElements)
146         {
147             // We can put it in. Use the local put function to add the element in
148             status = Cy_Keyscan_Fq_Put(context, element);
149         }
150         else
151         {
152             // We have an overflow condition. Inform the caller
153             status = CY_KEYSCAN_QUEUE_OVERFLOW;
154         }
155     }
156     return status;
157 }
158 
159 /**
160  *****************************************************************************
161  ** Returns pointer to the first element in the FIFO. If the FIFO is empty returns NULL.
162  **
163  ** [in]  context      Pointer to the context.
164  **
165  ** [out]  element     pointer to the next element in the FIFO if the FIFO is not empty
166  **                           NULL if the FIFO is empty.
167  **
168  **
169  **
170  *****************************************************************************/
Cy_Keyscan_Fq_GetCurElmPtr(cy_stc_keyscan_context_t * context,cy_stc_key_event ** current_element)171 static cy_en_ks_status_t Cy_Keyscan_Fq_GetCurElmPtr(cy_stc_keyscan_context_t* context, cy_stc_key_event **current_element)
172 {
173     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
174     /* Check if pointers are valid */
175     if ( (NULL == current_element) || (NULL == context))
176     {
177         status = CY_KEYSCAN_BAD_PARAM;
178     }
179     else
180     {
181         // Check if the FIFO has an element
182         if (context->curNumElements != 0U)
183         {
184             // Return pointer to the element
185             *current_element = &(context->bufStart[context->readIndex]);
186         }
187         else
188         {
189             // If we get here, the FIFO doesn't have any elements. Return NULL
190             current_element = NULL;
191             status = CY_KEYSCAN_EVENT_NONE;
192         }
193 
194     }
195     return status;
196 }
197 /**
198  *****************************************************************************
199  ** Removes the current element from the FIFO. Does nothing if the FIFO is empty.
200  **
201  ** [in]  context     Pointer to the context.
202  **
203  **
204  **
205  *****************************************************************************/
Cy_Keyscan_Fq_RemoveCurElement(cy_stc_keyscan_context_t * context)206 static cy_en_ks_status_t Cy_Keyscan_Fq_RemoveCurElement(cy_stc_keyscan_context_t* context)
207 {
208     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
209     /* Check if pointers are valid */
210     if (NULL == context)
211     {
212         status = CY_KEYSCAN_BAD_PARAM;
213     }
214     else
215     {
216         // Check if the FIFO has any elements
217         if ((context->curNumElements) != 0U)
218         {
219             // Reduce the number of elements by 1
220             (context->curNumElements)--;
221 
222             // Advance the read index and read pointer
223             (context->readIndex)++;
224 
225             // Check for wraparound
226             if (context->readIndex >= context->maxNumElements)
227             {
228                 // We have wraparound. Move the read index to the top of the buffer
229                 context->readIndex = 0;
230             }
231         }
232     }
233     return status;
234 }
235 /**
236  *****************************************************************************
237  ** Puts an element into the FIFO.
238  ** This function puts an element into the FIFO. Does not perform any bound checking.
239  **
240  ** [in]  context      Pointer to the context.
241  **
242  ** [in]  element      Pointer to the element to be placed in the FIFO
243  **
244  ** [in]  length       Number of bytes in element. This number of bytes is copied into the
245  **                    internal storage of the FIFO. This must be <= the maximum element size
246  **                    specified when the FIFO was constructed, otherwise the results are undefined.
247  *****************************************************************************/
Cy_Keyscan_Fq_Put(cy_stc_keyscan_context_t * context,cy_stc_key_event * element)248 static cy_en_ks_status_t Cy_Keyscan_Fq_Put(cy_stc_keyscan_context_t* context, cy_stc_key_event *element)
249 {
250     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
251     /* Check if pointers are valid */
252     if ( (NULL == element) || (NULL == context))
253     {
254         status = CY_KEYSCAN_BAD_PARAM;
255     }
256     else
257     {
258         // Copy the element at the current write location
259         (void)memcpy( &context->bufStart[context->writeIndex], element, sizeof(cy_stc_key_event)); /* Suppress a compiler warning about unused return value */
260 
261         // Update the number of elements in the FIFO
262         (context->curNumElements)++;
263 
264         // Next increment the write index
265         (context->writeIndex)++;
266 
267         // Now check for wraparound
268         if (context->writeIndex >= context->maxNumElements)
269         {
270             // We need to wraparound. Set the write index to zero
271             context->writeIndex = 0;
272         }
273     }
274     return status;
275 }
276 
277 /**
278  *****************************************************************************
279  ** Save the current FW FIFO write index. This is useful for rolling
280  **         back what we added in case we encounter a ghost/overflow condition.
281  **
282  ** [in]  context     Pointer to the context.
283  **
284  *****************************************************************************/
Cy_Keyscan_Fq_MarkCurrentEventForRollBack(cy_stc_keyscan_context_t * context)285 static cy_en_ks_status_t Cy_Keyscan_Fq_MarkCurrentEventForRollBack (cy_stc_keyscan_context_t* context)
286 {
287     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
288     /* Check if pointers are valid */
289     if ( (NULL == context))
290     {
291         status = CY_KEYSCAN_BAD_PARAM;
292     }
293     else
294     {
295         /// Save the current FW FIFO write index. This is useful for rolling
296         /// back what we added in case we encounter a ghost/overflow condition
297         context->savedWriteIndexForRollBack = context->writeIndex;
298         context->savedNumElements = context->curNumElements;
299 
300     }
301     return status;
302 }
303 
304 /**
305  *****************************************************************************
306  ** Rollback upto the marked events.
307  **
308  ** [in]  context     Pointer to the context.
309  **
310  **
311  **
312  *****************************************************************************/
Cy_Keyscan_Fq_RollbackUptoMarkedEvents(cy_stc_keyscan_context_t * context)313 static cy_en_ks_status_t Cy_Keyscan_Fq_RollbackUptoMarkedEvents(cy_stc_keyscan_context_t* context)
314 {
315     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
316     /* Check if pointers are valid */
317     if (NULL == context)
318     {
319         status = CY_KEYSCAN_BAD_PARAM;
320     }
321     else
322     {
323         context->curNumElements = context->savedNumElements;
324         // rollback upto the marked event
325         context->writeIndex = context->savedWriteIndexForRollBack;
326     }
327     return status;
328 }
329 
330 /**
331  *****************************************************************************
332  ** Put an event into the Keyscan data FIFO.
333  **
334  ** [in]  context   Pointer to the context.
335  **
336  ** [in]  event     Pointer to the event.
337  **
338  *****************************************************************************/
Cy_Keyscan_PutEvent(cy_stc_keyscan_context_t * context,cy_stc_key_event * event)339 static cy_en_ks_status_t Cy_Keyscan_PutEvent(cy_stc_keyscan_context_t* context, cy_stc_key_event *event)
340 {
341     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
342     uint8_t numElements;
343     /* Check if pointers are valid */
344     if ((NULL == event) || (NULL == context))
345     {
346         status = CY_KEYSCAN_BAD_PARAM;
347     }
348     else
349     {
350         status = Cy_Keyscan_Fq_GetCurNumElements( context, &numElements);
351         if(status == CY_KEYSCAN_SUCCESS)
352         {
353             // Check if the FIFO has room
354             if(numElements == ((uint8_t)(KEYSCAN_FW_FIFO_SIZE - 1U)))
355             {
356                 // Overflow! FIFO a rollover event; discard whatever was given to us
357                 event->keyCode = ((uint8_t)KEYSCAN_KEYCODE_ROLLOVER);
358             }
359             // if not overflow the event is put into FIFO
360             status = Cy_Keyscan_Fq_PutIncludeOverflowSlot(context, event);
361         }
362     }
363     return status;
364 }
365 
366 /**
367  *****************************************************************************
368  ** Get the next element in the FIFO
369  **
370  ** [in]  context    Pointer to the context.
371  **
372  ** [out]  event     Pointer to the event.
373  *****************************************************************************/
Cy_Keyscan_GetEvent(cy_stc_keyscan_context_t * context,cy_stc_key_event * event)374 static cy_en_ks_status_t  Cy_Keyscan_GetEvent(cy_stc_keyscan_context_t* context, cy_stc_key_event *event)
375 {
376     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
377     cy_stc_key_event *current_event;
378     uint8_t numElements;
379     /* Check if pointers are valid */
380     if ((NULL == event) || (NULL == context))
381     {
382         status = CY_KEYSCAN_BAD_PARAM;
383     }
384     else
385     {
386         status = Cy_Keyscan_Fq_GetCurNumElements( context, &numElements);
387         if(status == CY_KEYSCAN_SUCCESS)
388         {
389             // Check if FIFO is empty
390             if (numElements == 0U)
391             {
392                  event->keyCode = (uint8_t)KEYSCAN_KEYCODE_NONE;
393                  status = CY_KEYSCAN_EVENT_NONE;
394             }
395             else
396             {
397                 status = Cy_Keyscan_Fq_GetCurElmPtr(context, &current_event);
398                 if(status == CY_KEYSCAN_SUCCESS)
399                 {
400                 event->keyCode = current_event->keyCode;
401                 event->upDownFlag = current_event->upDownFlag;
402                 event->scanCycleFlag = current_event->scanCycleFlag;
403 
404                 (void)Cy_Keyscan_Fq_RemoveCurElement(context); /* Suppress a compiler warning about unused return value */
405                 }
406 
407             }
408 
409         }
410     }
411     return status;
412 }
413 
414 /**
415  *****************************************************************************
416  ** Freeze the MIA clock. Wait until the HW accepts the command, then
417  ** generate an event indicating that the MIA clock is unfrozen for anyone
418  ** who desires to catch it.
419  **
420  ** [in]  context    Pointer to the context.
421  ** [in]  base       Pointer to KeyScan instance register area
422  **
423  **
424  *****************************************************************************/
Cy_Keyscan_Mia_FreezeClk(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)425 static cy_en_ks_status_t  Cy_Keyscan_Mia_FreezeClk(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
426 {
427     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
428     /* Check if pointers are valid */
429     if ((NULL == base) || (NULL == context))
430     {
431         status = CY_KEYSCAN_BAD_PARAM;
432     }
433     else
434     {
435         // Issue the freeze command to the HW
436         KEYSCAN_MIA_CTL(base) |= _VAL2FLD(MXKEYSCAN_MIA_CTL_FREEZE_MIA, 1U);
437         Cy_SysLib_DelayUs(100U);
438         // Wait till mia_clk_freezed bit in MIA_STATUS register to go high
439         while (_FLD2VAL(MXKEYSCAN_MIA_STATUS_MIA_CLOCK_FREEZED_STATUS, KEYSCAN_MIA_STATUS(base)) != 1U)
440         {
441         }
442 
443         // Notify application that clock is frozen. This allows workarounds for clock freeze related MIA
444         // bugs, specifically key event loss when clock is frozen/unfrozen without reading the key event FIFO
445         // Poll the event FIFO only if the freeze didn't come from us
446         if (!context->keyscan_pollingKeyscanHw)
447         {
448             // Retrieve any pending events from the HW FIFO
449             status = Cy_Keyscan_GetEventsFromHWFifo(base, context);
450         }
451     }
452     return status;
453 }
454 /**
455  *****************************************************************************
456  ** Unfreeze the MIA clock. Wait until the HW accepts the command, then
457  ** generate an event indicating that the MIA clock is unfrozen for anyone
458  ** who desires to catch it.
459  **
460  ** [in]  context    Pointer to the context.
461  ** [in]  base       Pointer to KeyScan instance register area
462  **
463  *****************************************************************************/
Cy_Keyscan_Mia_UnfreezeClk(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)464 static cy_en_ks_status_t Cy_Keyscan_Mia_UnfreezeClk(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
465 {
466     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
467     /* Check if pointers are valid */
468     if ((NULL == base) || (NULL == context))
469     {
470         status = CY_KEYSCAN_BAD_PARAM;
471     }
472     else
473     {
474         // Unfreeze the clock
475         KEYSCAN_MIA_CTL(base) &= ~MXKEYSCAN_MIA_CTL_FREEZE_MIA_Msk;
476 
477         // Wait until it is unfrozen
478         while (_FLD2VAL(MXKEYSCAN_MIA_STATUS_MIA_CLOCK_FREEZED_STATUS, KEYSCAN_MIA_STATUS(base)) != 0U)
479         {
480         }
481         KEYSCAN_CTL(base) &= ~MXKEYSCAN_KEYSCAN_CTL_KYS_RST_EN_Msk;
482     }
483     return status;
484 }
485 
486 /**
487  *****************************************************************************
488  ** Reset the Keyscan HW once.
489  **
490  ** [in]  context    Pointer to the context.
491  ** [in]  base       Pointer to KeyScan instance register area
492  **
493  *****************************************************************************/
Cy_Keyscan_HwResetOnce(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)494 static cy_en_ks_status_t Cy_Keyscan_HwResetOnce(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
495 {
496     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
497     /* Check if pointers are valid */
498     if ((NULL == base) || (NULL == context))
499     {
500         status = CY_KEYSCAN_BAD_PARAM;
501     }
502     else
503     {
504         // Freeze the MIA clock
505         status = Cy_Keyscan_Mia_FreezeClk(base, context);
506 
507         if(status == CY_KEYSCAN_SUCCESS)
508         {
509             // Set the "clear reported keys" bit. This is necessary or the HW reset will not be accepted
510             KEYSCAN_MIA_CTL(base)  |= MXKEYSCAN_MIA_CTL_REPORTED_CLEAR_KYS_Msk;
511 
512             // Set the reset bit
513             KEYSCAN_CTL(base) |= MXKEYSCAN_KEYSCAN_CTL_KYS_RST_EN_Msk;
514 
515             // Unfreeze the MIA clock. This will clear the reset bit
516             status = Cy_Keyscan_Mia_UnfreezeClk(base, context);
517 
518             // Delay to ensure that the reset takes effect
519             // SOme more information on why 2550 delay to be gathered.
520             Cy_SysLib_DelayUs(2550U);
521         }
522 
523     }
524     return status;
525 }
526 
527 
528 /**
529  *****************************************************************************
530  ** Flush Events
531  **
532  ** [in]  context    Pointer to the context.
533  ** [in]  base       Pointer to KeyScan instance register area
534  **
535  *****************************************************************************/
Cy_Keyscan_FlushEvents(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)536 cy_en_ks_status_t Cy_Keyscan_FlushEvents(MXKEYSCAN_Type *base, cy_stc_keyscan_context_t *context)
537 {
538     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
539     /* Check if pointers are valid */
540     if ((NULL == base) || (NULL == context))
541     {
542         status = CY_KEYSCAN_BAD_PARAM;
543     }
544     else
545     {
546         // Freeze the MIA clock
547         status = Cy_Keyscan_Mia_FreezeClk(base, context);
548 
549         if(status == CY_KEYSCAN_SUCCESS)
550         {
551             // Unfreeze the MIA clock.
552             status = Cy_Keyscan_Mia_UnfreezeClk(base, context);
553             // Flush the FW FIFO
554             (void)Cy_Keyscan_Fq_Flush(context); /* Suppress a compiler warning about unused return value */
555 
556             // no keys currently pressed
557             context->keysPressedCount = 0U;
558         }
559 
560     }
561     return status;
562 }
563 
564 /**
565  *****************************************************************************
566  ** Initialization of the keyscan FW circular FIFO.
567  ** This function initializes circular FIFO to maintain the key codes for each key event generated.
568  **
569  ** [in]  context     Pointer to the context.
570  **
571  *****************************************************************************/
Cy_Keyscan_Init_Context(cy_stc_keyscan_context_t * context)572 static cy_en_ks_status_t Cy_Keyscan_Init_Context( cy_stc_keyscan_context_t* context)
573 {
574     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
575     /* Check if pointers are valid */
576     if (NULL == context)
577     {
578         status = CY_KEYSCAN_BAD_PARAM;
579     }
580     else
581     {
582         /* Save max elements, and buffer */
583         context->maxNumElements = KEYSCAN_FW_FIFO_SIZE;
584         context->readIndex = context->writeIndex = context->curNumElements = 0;
585     }
586     return status;
587 }
588 
589 /**
590  *****************************************************************************
591  ** Registers for callback
592  **
593  ** [in]  cbEvents    Pointer to the callback function.
594  **
595  ** [in]  context     Pointer to the context.
596  *****************************************************************************/
Cy_Keyscan_Register_Callback(cy_cb_keyscan_handle_events_t cbEvents,cy_stc_keyscan_context_t * context)597 cy_en_ks_status_t Cy_Keyscan_Register_Callback(cy_cb_keyscan_handle_events_t cbEvents, cy_stc_keyscan_context_t* context)
598 {
599     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
600     /* Check if pointers are valid */
601     if ((NULL == context) || (NULL == cbEvents))
602     {
603         status = CY_KEYSCAN_BAD_PARAM;
604     }
605     else
606     {
607         /* Save callback function in context */
608         context->cbEvents = cbEvents;
609     }
610     return status;
611 }
612 
613 
614 /**
615  *****************************************************************************
616  ** Register Context with the driver
617  ** This Function registers for the event callback and FW FIFO buffer.
618  **
619  ** The Application must configure corresponding keyscan pins
620  **      according to requirements and settings of keyscan instance.
621  **
622  ** [in] base       Pointer to KeyScan instance register area
623  ** [in] config     KeyScan module configuration. See #cy_stc_ks_config_t.
624  ** [out] context    Pointer to the context.
625  *****************************************************************************/
Cy_Keyscan_Init(MXKEYSCAN_Type * base,const cy_stc_ks_config_t * config,cy_stc_keyscan_context_t * context)626 cy_en_ks_status_t  Cy_Keyscan_Init(MXKEYSCAN_Type* base, const cy_stc_ks_config_t* config, cy_stc_keyscan_context_t *context )
627 {
628     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
629     /* Check if pointers are valid */
630     if ( (NULL == base) || (NULL == context) || (NULL == config))
631     {
632         status = CY_KEYSCAN_BAD_PARAM;
633     }
634     else
635     {
636         (void)Cy_Keyscan_Init_Context(context);
637         // Reset the keyscan HW to ensure we start from a known state
638         status = Cy_Keyscan_DeInit(base, context);
639 
640         if(status == CY_KEYSCAN_SUCCESS)
641         {
642             CY_ASSERT_L3(CY_KEYSCAN_IS_ROW_COUNT_VALID(config->noofRows));
643             CY_ASSERT_L3(CY_KEYSCAN_IS_COLUMN_COUNT_VALID(config->noofColumns));
644             CY_ASSERT_L3(CY_KEYSCAN_IS_MD_DEBOUNCE_VALID(config->macroDownDebCnt));
645             CY_ASSERT_L3(CY_KEYSCAN_IS_MU_DEBOUNCE_VALID(config->macroUpDebCnt));
646             CY_ASSERT_L3(CY_KEYSCAN_IS_U_DEBOUNCE_VALID(config->microDebCnt));
647 
648             context->keyscan_pollingKeyscanHw  = false;
649             context->keysPressedCount = 0U;
650 
651             KEYSCAN_DEBOUNCE(base) =  (_VAL2FLD(MXKEYSCAN_DEBOUNCE_MD_DEBOUNCE, config->macroDownDebCnt) | \
652                                        _VAL2FLD(MXKEYSCAN_DEBOUNCE_MU_DEBOUNCE, config->macroUpDebCnt)   | \
653                                        _VAL2FLD(MXKEYSCAN_DEBOUNCE_U_DEBOUNCE,  config->microDebCnt));
654 
655             // Configure the control register except for the enable bit
656             KEYSCAN_CTL(base) =       (_VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_GHOST_EN,     config->ghostEnable)                       | \
657                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KS_INT_EN,    config->cpuWakeupEnable)                   | \
658                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KYS_RST_EN,   MXKEYSCAN_KEYSCAN_CTL_KYS_RST_EN_DEFAULT)  | \
659                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_RC_EXT,       MXKEYSCAN_KEYSCAN_CTL_RC_EXT_DEFAULT)      | \
660                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_RCTC_ROW,     ((uint32_t)(config->noofRows)-1U))                      | \
661                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_RCTC_COLUMN,  ((uint32_t)(config->noofColumns)-1U))                   | \
662                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_PULL_HIGH,    MXKEYSCAN_KEYSCAN_CTL_PULL_HIGH_DEFAULT)   | \
663                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KSI_DRV_HIGH, MXKEYSCAN_KEYSCAN_CTL_KSI_DRV_HIGH_DEFAULT)| \
664                                        _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KYSCLK_STAYON,config->clkStayOn));
665 
666             // Configure the control register and enable the KS HW
667             KEYSCAN_CTL(base)  |= _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KS_EN, MXKEYSCAN_KEYSCAN_CTL_KS_EN_Msk);
668         }
669 
670     }
671     return status;
672 }
673 
674 /**
675  *****************************************************************************
676  **  DeInit Keyscan.
677  **
678  **  base     [in]        Pointer to KEYSCAN instance register area.
679  *****************************************************************************/
Cy_Keyscan_DeInit(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)680 cy_en_ks_status_t Cy_Keyscan_DeInit(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
681 {
682     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
683     /* Check if pointers are valid */
684     if ( (NULL == base) || (NULL == context))
685     {
686         status = CY_KEYSCAN_BAD_PARAM;
687     }
688     else
689     {
690         uint32_t savedKeyscanCtrl;
691 
692         // Save the current value of the control register
693         savedKeyscanCtrl = KEYSCAN_CTL(base);
694 
695         // Flag that we are polling the keyscan HW.
696         // Avoids potentially infinite recursion
697         context->keyscan_pollingKeyscanHw = true;
698         /* Reset the Hardware if keyscan is in enabled state.*/
699         if(_FLD2VAL(MXKEYSCAN_KEYSCAN_CTL_KS_EN, KEYSCAN_CTL(base)) != 0UL)
700         {
701             // Reset the HW multiple times to ensure that any partial counts are cleared
702             status = Cy_Keyscan_HwResetOnce(base, context);
703             status = Cy_Keyscan_HwResetOnce(base, context);
704         }
705 
706         if(status == CY_KEYSCAN_SUCCESS)
707         {
708             // Disable keyscan HW
709             KEYSCAN_CTL(base) &= ~MXKEYSCAN_KEYSCAN_CTL_KS_EN_Msk;
710 
711             // Delay to ensure that the HW is actually disabled
712             Cy_SysLib_DelayUs(100U);
713             // Clear FW event FIFO after a HW reset. Doesn't seem to be any reason
714             // to keep events around in the FW FIFO
715             status = Cy_Keyscan_Fq_Flush(context);
716 
717             // no keys currently pressed
718             context->keysPressedCount = 0U;
719 
720             // Clear the polling flag
721             context->keyscan_pollingKeyscanHw = false;
722         }
723 
724         // Restore the control register and enable scans if they were enabled before this function was called
725         KEYSCAN_CTL(base) = savedKeyscanCtrl;
726     }
727     return status;
728 }
729 
730 /**
731  *****************************************************************************
732  **  Enable Keyscan.
733  **
734  **  base    [in]  Pointer to KeyScan instance register area.
735  **  context [in]  Pointer to the context.
736  *****************************************************************************/
Cy_Keyscan_Enable(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)737 cy_en_ks_status_t Cy_Keyscan_Enable(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
738 {
739     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
740     /* Check if pointers are valid */
741     if ( (NULL == base) || (NULL == context))
742     {
743         status = CY_KEYSCAN_BAD_PARAM;
744     }
745     else
746     {
747         KEYSCAN_CTL(base)  |= _VAL2FLD(MXKEYSCAN_KEYSCAN_CTL_KS_EN, MXKEYSCAN_KEYSCAN_CTL_KS_EN_Msk);
748     }
749     return status;
750 }
751 
752 /**
753  *****************************************************************************
754  **  Disable keyscan
755  **
756  **  base    [in]  Pointer to KeyScan instance register area.
757  **  context [in]  Pointer to the context.
758  *****************************************************************************/
Cy_Keyscan_Disable(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)759 cy_en_ks_status_t Cy_Keyscan_Disable(MXKEYSCAN_Type* base, cy_stc_keyscan_context_t *context)
760 {
761     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
762     /* Check if pointers are valid */
763     if ( (NULL == base) || (NULL == context))
764     {
765         status = CY_KEYSCAN_BAD_PARAM;
766     }
767     else
768     {
769         // Disable keyscan HW
770         KEYSCAN_CTL(base) &= ~MXKEYSCAN_KEYSCAN_CTL_KS_EN_Msk;
771     }
772     return status;
773 }
774 
775 /**
776  *****************************************************************************
777  **  Events pending
778  **
779  **  base          [in]  Pointer to KeyScan instance register area.
780  **  context       [in]  Pointer to the context.
781  **  eventsPending [out]  Pointer to the eventsPending.
782  *****************************************************************************/
Cy_Keyscan_EventsPending(MXKEYSCAN_Type * base,bool * eventsPending,cy_stc_keyscan_context_t * context)783 cy_en_ks_status_t Cy_Keyscan_EventsPending(MXKEYSCAN_Type* base, bool *eventsPending, cy_stc_keyscan_context_t *context)
784 {
785     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
786     uint8_t numElements = 0U;
787     /* Check if pointers are valid */
788     if ((NULL == base) || (NULL == context) || (NULL == eventsPending))
789     {
790         status = CY_KEYSCAN_BAD_PARAM;
791     }
792     else
793     {
794         // Return whether any events are in the FW FIFO or not
795         status = Cy_Keyscan_Fq_GetCurNumElements( context, &numElements);
796         if(numElements == 0U)
797         {
798             *eventsPending = false;
799         }
800         else
801         {
802             *eventsPending = true;
803         }
804     }
805     return status;
806 }
807 
808 /**
809  *****************************************************************************
810  **  Get Next event from FW FIFO
811  **
812  **  base          [in]  Pointer to KeyScan instance register area.
813  **  context       [in]  Pointer to the context.
814  **  event         [out] Pointer to the next event.
815  *****************************************************************************/
Cy_Keyscan_GetNextEvent(MXKEYSCAN_Type * base,cy_stc_key_event * event,cy_stc_keyscan_context_t * context)816 cy_en_ks_status_t Cy_Keyscan_GetNextEvent(MXKEYSCAN_Type* base, cy_stc_key_event *event, cy_stc_keyscan_context_t *context)
817 {
818     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
819     /* Check if pointers are valid */
820     if ((NULL == base) || (NULL == context) || (NULL == event))
821     {
822         status = CY_KEYSCAN_BAD_PARAM;
823     }
824     else
825     {
826         // Get the next event from the FW FIFO and return it.
827         // The get function returns CY_KEYSCAN_EVENT_NONE if the FW FIFO is empty
828         status = Cy_Keyscan_GetEvent(context, event);
829     }
830     return status;
831 }
832 
833 /**
834  *****************************************************************************
835  **  Setup interrupt source to be accepted.
836  **
837  **  base    [in]  Pointer to KeyScan instance register area.
838  **  mask    [in]  The mask with the OR of the interrupt source to be accepted.
839  **                       See \ group_keyscan_intr_mask_macro for the set of constants.
840  *****************************************************************************/
Cy_Keyscan_SetInterruptMask(MXKEYSCAN_Type * base,uint32_t mask)841 cy_en_ks_status_t Cy_Keyscan_SetInterruptMask(MXKEYSCAN_Type* base, uint32_t mask)
842 {
843     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
844     /* Check if pointers are valid */
845     if (NULL == base)
846     {
847         status = CY_KEYSCAN_BAD_PARAM;
848     }
849     else
850     {
851         KEYSCAN_INTR_MASK(base)  = mask;
852     }
853     return status;
854 }
855 
856 /**
857  *****************************************************************************
858  **  Return interrupt mask setting.
859  **
860  **  base [in]  Pointer to KeyScan instance register area.
861  **  mask  [out] The mask with the OR of the interrupt source which is masked.
862  **                       See \ group_keyscan_intr_mask_macro for the set of constants.
863  *****************************************************************************/
Cy_Keyscan_GetInterruptMask(MXKEYSCAN_Type * base,uint32_t * mask)864 cy_en_ks_status_t Cy_Keyscan_GetInterruptMask(MXKEYSCAN_Type* base, uint32_t *mask)
865 {
866     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
867     /* Check if pointers are valid */
868     if ( (NULL == base) || (NULL == mask))
869     {
870         status = CY_KEYSCAN_BAD_PARAM;
871     }
872     else
873     {
874         *mask = KEYSCAN_INTR_MASK(base);
875     }
876     return status;
877 }
878 
879 /**
880  *****************************************************************************
881  **  Return interrupt masked status.
882  **
883  **  base    [in]  Pointer to KeyScan instance register area.
884  **  status  [out] The mask with the OR of the interrupt source which occurs.
885  **                       See \ group_keyscan_intr_mask_macro for the set of constants.
886  *****************************************************************************/
Cy_Keyscan_GetInterruptMaskedStatus(MXKEYSCAN_Type * base,uint32_t * status)887 cy_en_ks_status_t Cy_Keyscan_GetInterruptMaskedStatus(MXKEYSCAN_Type* base, uint32_t *status)
888 {
889     cy_en_ks_status_t return_status = CY_KEYSCAN_SUCCESS;
890     /* Check if pointers are valid */
891     if ( (NULL == base) || (NULL == status))
892     {
893         return_status = CY_KEYSCAN_BAD_PARAM;
894     }
895     else
896     {
897         *status = KEYSCAN_INTR_MASKED(base);
898     }
899     return return_status;
900 }
901 
902 /**
903  *****************************************************************************
904  **  Return interrupt raw status.
905  **
906  **  base    [in]  Pointer to Keyscan instance register area.
907  **  status  [out] The mask with the OR of the interrupt source which occurs.
908  **                       See \ group_keyscan_intr_mask_macro for the set of constants.
909  *****************************************************************************/
Cy_Keyscan_GetInterruptStatus(MXKEYSCAN_Type * base,uint32_t * status)910 cy_en_ks_status_t Cy_Keyscan_GetInterruptStatus(MXKEYSCAN_Type* base, uint32_t *status)
911 {
912     cy_en_ks_status_t return_status = CY_KEYSCAN_SUCCESS;
913     /* Check if pointers are valid */
914     if ( (NULL == base) || (NULL == status))
915     {
916         return_status = CY_KEYSCAN_BAD_PARAM;
917     }
918     else
919     {
920         *status = KEYSCAN_INTR(base) ;
921     }
922     return return_status;
923 }
924 
925 /**
926  *****************************************************************************
927  **  Clear interrupt status.
928  **
929  **  base    [in]  Pointer to Keyscan instance register area.
930  **  mask    [in]  The mask with the OR of the interrupt source to be cleared.
931  **                       See \ group_keyscan_intr_mask_macro for the set of constants.
932  *****************************************************************************/
Cy_Keyscan_ClearInterrupt(MXKEYSCAN_Type * base,uint32_t mask)933 cy_en_ks_status_t Cy_Keyscan_ClearInterrupt(MXKEYSCAN_Type* base, uint32_t mask)
934 {
935     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
936     /* Check if pointers are valid */
937     if (NULL == base)
938     {
939         status = CY_KEYSCAN_BAD_PARAM;
940     }
941     else
942     {
943         KEYSCAN_INTR(base) = mask;
944     }
945     return status;
946 }
947 
948 /**
949  *****************************************************************************
950  **  Handler for keyscan interrupts.
951  ** Applications have to call this function from keyscan interrupt handler.
952  **
953  **  base    [in]  Pointer to Keyscan instance register area.
954  **  context [in]  Pointer to the context.
955  *****************************************************************************/
Cy_Keyscan_Interrupt_Handler(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)956 cy_en_ks_status_t Cy_Keyscan_Interrupt_Handler(MXKEYSCAN_Type *base, cy_stc_keyscan_context_t *context)
957 {
958     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
959     /* Check if pointers are valid */
960     if ( (NULL == base) || (NULL == context))
961     {
962         status = CY_KEYSCAN_BAD_PARAM;
963     }
964     else
965     {
966         while(_FLD2VAL(MXKEYSCAN_MIA_STATUS_KEYCODE_SET_STATUS, KEYSCAN_MIA_STATUS(base)) != 0UL)
967         {
968             /* internally calls Cy_Keyscan_getEventsFromHWFifo to read from the FIFO. */
969             (void)Cy_Keyscan_Mia_FreezeClk(base, context); /* Suppress a compiler warning about unused return value */
970 
971             /* Unfreeze the clock once read from FIFO is complete */
972             (void)Cy_Keyscan_Mia_UnfreezeClk(base, context); /* Suppress a compiler warning about unused return value */
973 
974             /* notify application to read from the FW FIFO.
975                Application has to call Cy_Keyscan_getNextEvent() in a loop till the
976                the return value is CY_KEYSCAN_EVENT_NONE */
977 
978             context->cbEvents();
979         }
980 
981        /* Clear all the interrupts */
982         status = Cy_Keyscan_ClearInterrupt(MXKEYSCAN, MXKEYSCAN_INTR_ALL);
983     }
984     return status;
985 }
986 
987 /**
988  *****************************************************************************
989  ** Reads from Hardware FIFO.
990  ** Called when Applications call keyscan interrupt handler.
991  **
992  **  base    [in]  Pointer to Keyscan instance register area.
993  **  context [in]  Pointer to the context.
994  **
995  *****************************************************************************/
Cy_Keyscan_GetEventsFromHWFifo(MXKEYSCAN_Type * base,cy_stc_keyscan_context_t * context)996 static cy_en_ks_status_t Cy_Keyscan_GetEventsFromHWFifo(MXKEYSCAN_Type *base, cy_stc_keyscan_context_t *context)
997 {
998     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
999     /* Check if pointers are valid */
1000     if ( (NULL == base) || (NULL == context))
1001     {
1002         status = CY_KEYSCAN_BAD_PARAM;
1003     }
1004     else
1005     {
1006         bool ghostDetected;
1007         uint8_t keyCode;
1008         uint8_t numEvents;
1009         uint32_t scanCycleOfLastEvent = 0;
1010         bool firstEvent;
1011         cy_stc_key_event event = {.keyCode = 0, .upDownFlag = 0, .scanCycleFlag = 0};
1012 
1013         // No ghost events detected to begin with
1014         ghostDetected = false;
1015 
1016         // Processing for first event is slightly different from subsequent
1017         // events. Set the first event flag on
1018         firstEvent = true;
1019 
1020         (void)Cy_Keyscan_Fq_MarkCurrentEventForRollBack(context); /* Suppress a compiler warning about unused return value */
1021 
1022         // Get the number of events present in the event FIFO
1023         numEvents = (uint8_t)(_FLD2VAL(MXKEYSCAN_KEYFIFO_CNT_KEYFIFO_CNT, KEYSCAN_KEYFIFO_CNT(base)));
1024 
1025         // Now read and copy the events into the FW FIFO.
1026         while (numEvents > 0U)
1027         {
1028             // Read another event from the HW FIFO
1029             uint32_t fifo_val = KEYSCAN_KEYFIFO(base);
1030             keyCode = (uint8_t)(_FLD2VAL(MXKEYSCAN_KEYFIFO_KEYFIFO, fifo_val));
1031 
1032             // HW can spit out 0xff events that don't mean anything. This happens
1033             // after a reset when the FW and HW get out of sync. The simplest way to deal
1034             // with them is to treat them like a ghost since we have no idea what the actual HW state
1035             // is. The caller should then generate a reset.
1036 
1037             // Did we see a ghost?
1038             if ((keyCode  == ((uint8_t)KEYSCAN_KEYCODE_GHOST)) || (keyCode  == 0xFFU))
1039             {
1040                 // Yes. Set the ghost detected flag
1041                 ghostDetected = true;
1042             }
1043 
1044             // If we detect a ghost we discard all events, even those belonging
1045             // to subsequent scan cycles.
1046             if (!ghostDetected)
1047             {
1048                 // So we don't have a ghost
1049 
1050                 // Check if this event belongs to a different scan cycle than the previous event
1051                 if (!firstEvent &&
1052                     ((_FLD2VAL(MXKEYSCAN_KEYFIFO_TRACK_SCAN_CYCLE, fifo_val) ^ scanCycleOfLastEvent) != 0UL))
1053                 {
1054                     // It does. Add an end of scan cycle event to the FW FIFO
1055                     event.keyCode = (uint8_t)KEYSCAN_KEYCODE_END_OF_SCAN_CYCLE;
1056                     (void)Cy_Keyscan_PutEvent(context, &event); /* Suppress a compiler warning about unused return value */
1057 
1058                     // Save the current FIFO index for rollback to the last scan cycle
1059                     (void)Cy_Keyscan_Fq_MarkCurrentEventForRollBack(context); /* Suppress a compiler warning about unused return value */
1060                 }
1061 
1062                 // Subsequent events are not first events
1063                 firstEvent = false;
1064 
1065                 // Save the scan cycle of the new event for later use
1066                 scanCycleOfLastEvent = (_FLD2VAL(MXKEYSCAN_KEYFIFO_TRACK_SCAN_CYCLE, fifo_val));
1067 
1068                 // Add new event to the FW FIFO
1069                 event.keyCode       = keyCode;
1070                 event.upDownFlag    = (uint8_t)(_FLD2VAL(MXKEYSCAN_KEYFIFO_KEY_UP_DOWN, fifo_val));
1071                 event.scanCycleFlag = (uint8_t)(_FLD2VAL(MXKEYSCAN_KEYFIFO_TRACK_SCAN_CYCLE, fifo_val));
1072 
1073                 // keep track of the number of unmatched key down events by
1074                 // incrementing every time get key down event, and decrementing
1075                 // every time get a key up event
1076                 if (event.upDownFlag != 0U)
1077                 {
1078                     // since should never get a key up event without a key
1079                     // down  event, don't decrement if already 0
1080                     if (context->keysPressedCount > 0U)
1081                     {
1082                         context->keysPressedCount--; // detected key up event
1083                     }
1084                 }
1085                 else
1086                 {
1087                     context->keysPressedCount++; // detected key down event
1088                 }
1089 
1090                 (void)Cy_Keyscan_PutEvent(context, &event); /* Suppress a compiler warning about unused return value */
1091             }
1092             numEvents -= 1U;
1093         }
1094 
1095         // Note that we are ignoring the case where the FW scans the HW just
1096         // as its in the middle of detecting an overflow condition. If
1097         // an overflow is detected, we really don't know what is the current
1098         // state of the matrix. It probably doesn't matter that we don't catch
1099         // all the keys. Current plan is to reset the HW in case of an overflow
1100         // to allow it to accurately capture the current state of the keyboard
1101         // This seems adequate at this time.
1102 
1103         // Check if an overflow or ghost condition has been detected
1104         if ( ghostDetected || ((_FLD2VAL(MXKEYSCAN_MIA_STATUS_OVERFLOW_STATUS, KEYSCAN_MIA_STATUS(base))) != 0UL) )
1105         {
1106             // Rollback the FW FIFO to the last save point
1107             (void)Cy_Keyscan_Fq_RollbackUptoMarkedEvents(context); /* Suppress a compiler warning about unused return value */
1108 
1109             // Now place a rollover event into the FW fifo
1110             event.keyCode = ((uint8_t)KEYSCAN_KEYCODE_ROLLOVER);
1111             (void)Cy_Keyscan_PutEvent(context, &event); /* Suppress a compiler warning about unused return value */
1112 
1113             if ((_FLD2VAL(MXKEYSCAN_KEYSCAN_CTL_GHOST_EN, KEYSCAN_CTL(base))) != 0UL)
1114             {
1115                 // Enable the HW reset bit. After the reset the HW will capture
1116                 // the current state of the system
1117                 KEYSCAN_CTL(base) |= MXKEYSCAN_KEYSCAN_CTL_KYS_RST_EN_Msk;
1118             }
1119             // clear the pressed key count.
1120             context->keysPressedCount = 0;
1121         }
1122         else
1123         {
1124             // If we queued any events, add an end of scan cycle marker to the end
1125             // We can use the first event flag; it will be cleared if we
1126             // added any events
1127             if (!firstEvent)
1128             {
1129                 // Now place a rollover event into the FW FIFO
1130                 event.keyCode = (uint8_t)KEYSCAN_KEYCODE_END_OF_SCAN_CYCLE;
1131                 (void)Cy_Keyscan_PutEvent(context, &event); /* Suppress a compiler warning about unused return value */
1132             }
1133         }
1134 
1135         // Set the "clear reported keys" bit. This will clear the HW when the MIA clock is unfrozen
1136             KEYSCAN_MIA_CTL(base)  |= MXKEYSCAN_MIA_CTL_REPORTED_CLEAR_KYS_Msk;
1137     }
1138     return status;
1139 }
1140 
1141 /**
1142  *****************************************************************************
1143  **  Enables Ghost detection
1144  **
1145  **  base    [in]  Pointer to Keyscan instance register area.
1146  *****************************************************************************/
Cy_Keyscan_EnableGhostDetection(MXKEYSCAN_Type * base)1147 cy_en_ks_status_t Cy_Keyscan_EnableGhostDetection(MXKEYSCAN_Type *base)
1148 {
1149     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
1150     /* Check if pointers are valid */
1151     if (NULL == base)
1152     {
1153         status = CY_KEYSCAN_BAD_PARAM;
1154     }
1155     else
1156     {
1157         /* enable ghost detection */
1158         KEYSCAN_CTL(base)  |=  MXKEYSCAN_KEYSCAN_CTL_GHOST_EN_Msk;
1159     }
1160     return status;
1161 }
1162 
1163 /**
1164  *****************************************************************************
1165  **  Disables Ghost detection
1166  **
1167  **  base    [in]  Pointer to Keyscan instance register area.
1168  *****************************************************************************/
Cy_Keyscan_DisableGhostDetection(MXKEYSCAN_Type * base)1169 cy_en_ks_status_t Cy_Keyscan_DisableGhostDetection(MXKEYSCAN_Type *base)
1170 {
1171     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
1172     /* Check if pointers are valid */
1173     if (NULL == base)
1174     {
1175         status = CY_KEYSCAN_BAD_PARAM;
1176     }
1177     else
1178     {
1179         /* disable ghost detection */
1180         KEYSCAN_CTL(base) &= ~MXKEYSCAN_KEYSCAN_CTL_GHOST_EN_Msk;
1181     }
1182     return status;
1183 }
1184 
1185 /**
1186  *****************************************************************************
1187  ** Enables Clock Stay On
1188  ** Clock to the IP is always enabled.
1189  **
1190  ** base    [in]  Pointer to Keyscan instance register area.
1191  *****************************************************************************/
Cy_Keyscan_EnableClockStayOn(MXKEYSCAN_Type * base)1192 cy_en_ks_status_t Cy_Keyscan_EnableClockStayOn(MXKEYSCAN_Type *base)
1193 {
1194     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
1195     /* Check if pointers are valid */
1196     if (NULL == base)
1197     {
1198         status = CY_KEYSCAN_BAD_PARAM;
1199     }
1200     else
1201     {
1202         /* enable clock stay on */
1203         KEYSCAN_CTL(base)  |= MXKEYSCAN_KEYSCAN_CTL_KYSCLK_STAYON_Msk;
1204     }
1205     return status;
1206 }
1207 
1208 /**
1209  *****************************************************************************
1210  **  Disables Clock Stay On
1211  **  When there is no activity detected, the clock to the Keyscan is gated off.
1212  **
1213  **  base    [in]  Pointer to Keyscan instance register area.
1214  *****************************************************************************/
Cy_Keyscan_DisableClockStayOn(MXKEYSCAN_Type * base)1215 cy_en_ks_status_t Cy_Keyscan_DisableClockStayOn(MXKEYSCAN_Type *base)
1216 {
1217     cy_en_ks_status_t status = CY_KEYSCAN_SUCCESS;
1218     /* Check if pointers are valid */
1219     if (NULL == base)
1220     {
1221         status = CY_KEYSCAN_BAD_PARAM;
1222     }
1223     else
1224     {
1225         /* disable clock stay on */
1226         KEYSCAN_CTL(base) &= ~MXKEYSCAN_KEYSCAN_CTL_KYSCLK_STAYON_Msk;
1227     }
1228     return status;
1229 }
1230 
1231 #endif /* CY_IP_MXKEYSCAN */
1232 /*****************************************************************************/
1233 /* EOF (not truncated)                                                       */
1234 /*****************************************************************************/
1235