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, ¤t_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