fsl_kpp.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright 2017, 2019 NXP
  3. * All rights reserved.
  4. *
  5. * SPDX-License-Identifier: BSD-3-Clause
  6. */
  7. #include "fsl_kpp.h"
  8. /*******************************************************************************
  9. * Definitions
  10. ******************************************************************************/
  11. /* Component ID definition, used by tools. */
  12. #ifndef FSL_COMPONENT_ID
  13. #define FSL_COMPONENT_ID "platform.drivers.kpp"
  14. #endif
  15. #define KPP_KEYPAD_SCAN_TIMES (3U)
  16. /*******************************************************************************
  17. * Prototypes
  18. ******************************************************************************/
  19. /*******************************************************************************
  20. * Variables
  21. ******************************************************************************/
  22. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  23. /*! @brief Pointers to SEMC clocks for each instance. */
  24. static const clock_ip_name_t s_kppClock[FSL_FEATURE_SOC_KPP_COUNT] = KPP_CLOCKS;
  25. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  26. /*! @brief Pointers to SEMC bases for each instance. */
  27. static KPP_Type *const s_kppBases[] = KPP_BASE_PTRS;
  28. /*! @brief Pointers to KPP IRQ number for each instance. */
  29. static const IRQn_Type s_kppIrqs[] = KPP_IRQS;
  30. /*******************************************************************************
  31. * Code
  32. ******************************************************************************/
  33. static uint32_t KPP_GetInstance(KPP_Type *base)
  34. {
  35. uint32_t instance;
  36. /* Find the instance index from base address mappings. */
  37. for (instance = 0; instance < ARRAY_SIZE(s_kppBases); instance++)
  38. {
  39. if (s_kppBases[instance] == base)
  40. {
  41. break;
  42. }
  43. }
  44. assert(instance < ARRAY_SIZE(s_kppBases));
  45. return instance;
  46. }
  47. static void KPP_Mdelay(uint64_t tickets)
  48. {
  49. while ((tickets--) != 0UL)
  50. {
  51. __NOP();
  52. }
  53. }
  54. /*!
  55. * brief KPP initialize.
  56. * This function ungates the KPP clock and initializes KPP.
  57. * This function must be called before calling any other KPP driver functions.
  58. *
  59. * param base KPP peripheral base address.
  60. * param configure The KPP configuration structure pointer.
  61. */
  62. void KPP_Init(KPP_Type *base, kpp_config_t *configure)
  63. {
  64. assert(configure);
  65. uint32_t instance = KPP_GetInstance(base);
  66. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  67. /* Un-gate sdram controller clock. */
  68. CLOCK_EnableClock(s_kppClock[KPP_GetInstance(base)]);
  69. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  70. /* Clear all. */
  71. base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
  72. /* Enable the keypad row and set the column strobe output to open drain. */
  73. base->KPCR = KPP_KPCR_KRE(configure->activeRow);
  74. base->KPDR = KPP_KPDR_KCD((uint8_t) ~(configure->activeColumn));
  75. base->KPCR |= KPP_KPCR_KCO(configure->activeColumn);
  76. /* Set the input direction for row and output direction for column. */
  77. base->KDDR = KPP_KDDR_KCDD(configure->activeColumn) | KPP_KDDR_KRDD((uint8_t) ~(configure->activeRow));
  78. /* Clear the status flag and enable the interrupt. */
  79. base->KPSR = KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK | KPP_KPSR_KDSC_MASK | configure->interrupt;
  80. if ((configure->interrupt) != 0U)
  81. {
  82. /* Enable at the Interrupt */
  83. (void)EnableIRQ(s_kppIrqs[instance]);
  84. }
  85. }
  86. /*!
  87. * brief Deinitializes the KPP module and gates the clock.
  88. * This function gates the KPP clock. As a result, the KPP
  89. * module doesn't work after calling this function.
  90. *
  91. * param base KPP peripheral base address.
  92. */
  93. void KPP_Deinit(KPP_Type *base)
  94. {
  95. /* Disable interrupts and disable all rows. */
  96. base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
  97. base->KPCR = 0;
  98. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  99. /* Disable KPP clock. */
  100. CLOCK_DisableClock(s_kppClock[KPP_GetInstance(base)]);
  101. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  102. }
  103. /*!
  104. * brief Keypad press scanning.
  105. *
  106. * This function will scanning all columns and rows. so
  107. * all scanning data will be stored in the data pointer.
  108. *
  109. * param base KPP peripheral base address.
  110. * param data KPP key press scanning data. The data buffer should be prepared with
  111. * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX.
  112. * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX].
  113. * for example the data[2] = 4, that means in column 1 row 2 has a key press event.
  114. * param clockSrc_Hz Source clock.
  115. */
  116. void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz)
  117. {
  118. assert(data);
  119. uint16_t kppKCO = base->KPCR & KPP_KPCR_KCO_MASK;
  120. uint8_t columIndex = 0;
  121. uint8_t activeColumn = (uint8_t)((base->KPCR & KPP_KPCR_KCO_MASK) >> KPP_KPCR_KCO_SHIFT);
  122. uint8_t times;
  123. uint8_t rowData[KPP_KEYPAD_SCAN_TIMES][KPP_KEYPAD_COLUMNNUM_MAX];
  124. bool press = false;
  125. uint8_t column;
  126. /* Initialize row data to zero. */
  127. (void)memset(&rowData[0][0], 0, sizeof(rowData));
  128. /* Scanning. */
  129. /* Configure the column data to 1 according to column numbers. */
  130. base->KPDR = KPP_KPDR_KCD_MASK;
  131. /* Configure column to totem pole for quick discharge of keypad capacitance. */
  132. base->KPCR &= (uint16_t)(((uint16_t)~kppKCO) | KPP_KPCR_KRE_MASK);
  133. /* Recover. */
  134. base->KPCR |= kppKCO;
  135. /* Three times scanning. */
  136. for (times = 0; times < KPP_KEYPAD_SCAN_TIMES; times++)
  137. {
  138. for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
  139. {
  140. column = activeColumn & (1U << columIndex);
  141. if (column != 0U)
  142. {
  143. /* Set the single column line to 0. */
  144. base->KPDR = KPP_KPDR_KCD(~(uint16_t)column);
  145. /* Take 100us delays. */
  146. KPP_Mdelay(((uint64_t)clockSrc_Hz / 10000000UL));
  147. /* Read row data. */
  148. rowData[times][columIndex] = (uint8_t)(~(base->KPDR & KPP_KPDR_KRD_MASK));
  149. }
  150. else
  151. {
  152. /* Read row data. */
  153. rowData[times][columIndex] = 0;
  154. }
  155. }
  156. }
  157. /* Return all columns to 0 in preparation for standby mode. */
  158. base->KPDR &= (uint16_t)(~KPP_KPDR_KCD_MASK);
  159. /* Check if three time scan data is the same. */
  160. for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
  161. {
  162. if (((uint8_t)(rowData[0][columIndex] & rowData[1][columIndex]) & rowData[2][columIndex]) != 0U)
  163. {
  164. press = true;
  165. }
  166. }
  167. if (press)
  168. {
  169. (void)memcpy(data, &rowData[0][0], sizeof(rowData[0]));
  170. }
  171. else
  172. {
  173. (void)memset(data, 0, sizeof(rowData[0]));
  174. }
  175. }