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