1 /*
2  * Copyright 2019 Intel Corporation
3  * Copyright 2022 Nuvoton Technology Corporation.
4  * Copyright 2023 Google LLC
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/device.h>
10 #include <zephyr/input/input.h>
11 #include <zephyr/input/input_kbd_matrix.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/sys/util.h>
16 
17 LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL);
18 
input_kbd_matrix_poll_start(const struct device * dev)19 void input_kbd_matrix_poll_start(const struct device *dev)
20 {
21 	struct input_kbd_matrix_common_data *data = dev->data;
22 
23 	k_sem_give(&data->poll_lock);
24 }
25 
input_kbd_matrix_ghosting(const struct device * dev)26 static bool input_kbd_matrix_ghosting(const struct device *dev)
27 {
28 	const struct input_kbd_matrix_common_config *cfg = dev->config;
29 	const kbd_row_t *state = cfg->matrix_new_state;
30 
31 	/*
32 	 * Matrix keyboard designs are suceptible to ghosting.
33 	 * An extra key appears to be pressed when 3 keys belonging to the same
34 	 * block are pressed. For example, in the following block:
35 	 *
36 	 * . . w . q .
37 	 * . . . . . .
38 	 * . . . . . .
39 	 * . . m . a .
40 	 *
41 	 * the key m would look as pressed if the user pressed keys w, q and a
42 	 * simultaneously. A block can also be formed, with not adjacent
43 	 * columns.
44 	 */
45 	for (int c = 0; c < cfg->col_size; c++) {
46 		if (!state[c]) {
47 			continue;
48 		}
49 
50 		for (int c_next = c + 1; c_next < cfg->col_size; c_next++) {
51 			/*
52 			 * We AND the columns to detect a "block". This is an
53 			 * indication of ghosting, due to current flowing from
54 			 * a key which was never pressed. In our case, current
55 			 * flowing is a bit set to 1 as we flipped the bits
56 			 * when the matrix was scanned. Now we OR the colums
57 			 * using z&(z-1) which is non-zero only if z has more
58 			 * than one bit set.
59 			 */
60 			kbd_row_t common_row_bits = state[c] & state[c_next];
61 
62 			if (common_row_bits & (common_row_bits - 1)) {
63 				return true;
64 			}
65 		}
66 	}
67 
68 	return false;
69 }
70 
input_kbd_matrix_drive_column(const struct device * dev,int col)71 static void input_kbd_matrix_drive_column(const struct device *dev, int col)
72 {
73 	const struct input_kbd_matrix_common_config *cfg = dev->config;
74 	const struct input_kbd_matrix_api *api = cfg->api;
75 
76 	api->drive_column(dev, col);
77 
78 #ifdef CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK
79 	input_kbd_matrix_drive_column_hook(dev, col);
80 #endif
81 }
82 
input_kbd_matrix_scan(const struct device * dev)83 static bool input_kbd_matrix_scan(const struct device *dev)
84 {
85 	const struct input_kbd_matrix_common_config *cfg = dev->config;
86 	const struct input_kbd_matrix_api *api = cfg->api;
87 	kbd_row_t row;
88 	kbd_row_t key_event = 0U;
89 
90 	for (int col = 0; col < cfg->col_size; col++) {
91 		input_kbd_matrix_drive_column(dev, col);
92 
93 		/* Allow the matrix to stabilize before reading it */
94 		k_busy_wait(cfg->settle_time_us);
95 
96 		row = api->read_row(dev);
97 
98 		if (cfg->actual_key_mask != NULL) {
99 			row &= cfg->actual_key_mask[col];
100 		}
101 
102 		cfg->matrix_new_state[col] = row;
103 		key_event |= row;
104 	}
105 
106 	input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE);
107 
108 	return key_event != 0U;
109 }
110 
input_kbd_matrix_update_state(const struct device * dev)111 static void input_kbd_matrix_update_state(const struct device *dev)
112 {
113 	const struct input_kbd_matrix_common_config *cfg = dev->config;
114 	struct input_kbd_matrix_common_data *data = dev->data;
115 	kbd_row_t *matrix_new_state = cfg->matrix_new_state;
116 	uint32_t cycles_now;
117 	kbd_row_t row_changed;
118 	kbd_row_t deb_col;
119 
120 	cycles_now = k_cycle_get_32();
121 
122 	data->scan_clk_cycle[data->scan_cycles_idx] = cycles_now;
123 
124 	/*
125 	 * The intent of this loop is to gather information related to key
126 	 * changes.
127 	 */
128 	for (int c = 0; c < cfg->col_size; c++) {
129 		/* Check if there was an update from the previous scan */
130 		row_changed = matrix_new_state[c] ^ cfg->matrix_previous_state[c];
131 
132 		if (!row_changed) {
133 			continue;
134 		}
135 
136 		for (int r = 0; r < cfg->row_size; r++) {
137 			uint8_t cyc_idx = c * cfg->row_size + r;
138 
139 			/*
140 			 * Index all they keys that changed for each row in
141 			 * order to debounce each key in terms of it
142 			 */
143 			if (row_changed & BIT(r)) {
144 				cfg->scan_cycle_idx[cyc_idx] = data->scan_cycles_idx;
145 			}
146 		}
147 
148 		cfg->matrix_unstable_state[c] |= row_changed;
149 		cfg->matrix_previous_state[c] = matrix_new_state[c];
150 	}
151 
152 	for (int c = 0; c < cfg->col_size; c++) {
153 		deb_col = cfg->matrix_unstable_state[c];
154 
155 		if (!deb_col) {
156 			continue;
157 		}
158 
159 		/* Debouncing for each row key occurs here */
160 		for (int r = 0; r < cfg->row_size; r++) {
161 			kbd_row_t mask = BIT(r);
162 			kbd_row_t row_bit = matrix_new_state[c] & mask;
163 
164 			/* Continue if we already debounce a key */
165 			if (!(deb_col & mask)) {
166 				continue;
167 			}
168 
169 			uint8_t cyc_idx = c * cfg->row_size + r;
170 			uint8_t scan_cyc_idx = cfg->scan_cycle_idx[cyc_idx];
171 			uint32_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx];
172 
173 			/* Convert the clock cycle differences to usec */
174 			uint32_t deb_t_us = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle);
175 
176 			/* Does the key requires more time to be debounced? */
177 			if (deb_t_us < (row_bit ? cfg->debounce_down_us : cfg->debounce_up_us)) {
178 				/* Need more time to debounce */
179 				continue;
180 			}
181 
182 			cfg->matrix_unstable_state[c] &= ~mask;
183 
184 			/* Check if there was a change in the stable state */
185 			if ((cfg->matrix_stable_state[c] & mask) == row_bit) {
186 				/* Key state did not change */
187 				continue;
188 			}
189 
190 			/*
191 			 * The current row has been debounced, therefore update
192 			 * the stable state. Then, proceed to notify the
193 			 * application about the keys pressed.
194 			 */
195 			cfg->matrix_stable_state[c] ^= mask;
196 
197 			input_report_abs(dev, INPUT_ABS_X, c, false, K_FOREVER);
198 			input_report_abs(dev, INPUT_ABS_Y, r, false, K_FOREVER);
199 			input_report_key(dev, INPUT_BTN_TOUCH, row_bit, true, K_FOREVER);
200 		}
201 	}
202 
203 	data->scan_cycles_idx = (data->scan_cycles_idx + 1) % INPUT_KBD_MATRIX_SCAN_OCURRENCES;
204 }
205 
input_kbd_matrix_check_key_events(const struct device * dev)206 static bool input_kbd_matrix_check_key_events(const struct device *dev)
207 {
208 	const struct input_kbd_matrix_common_config *cfg = dev->config;
209 	bool key_pressed;
210 
211 	/* Scan the matrix */
212 	key_pressed = input_kbd_matrix_scan(dev);
213 
214 	for (int c = 0; c < cfg->col_size; c++) {
215 		LOG_DBG("c=%2d u=" PRIkbdrow " p=" PRIkbdrow " n=" PRIkbdrow,
216 			c,
217 			cfg->matrix_unstable_state[c],
218 			cfg->matrix_previous_state[c],
219 			cfg->matrix_new_state[c]);
220 	}
221 
222 	/* Abort if ghosting is detected */
223 	if (cfg->ghostkey_check && input_kbd_matrix_ghosting(dev)) {
224 		return key_pressed;
225 	}
226 
227 	input_kbd_matrix_update_state(dev);
228 
229 	return key_pressed;
230 }
231 
input_kbd_matrix_poll_timeout(const struct device * dev)232 static k_timepoint_t input_kbd_matrix_poll_timeout(const struct device *dev)
233 {
234 	const struct input_kbd_matrix_common_config *cfg = dev->config;
235 
236 	if (cfg->poll_timeout_ms == 0) {
237 		return sys_timepoint_calc(K_FOREVER);
238 	}
239 
240 	return sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms));
241 }
242 
input_kbd_matrix_poll(const struct device * dev)243 static void input_kbd_matrix_poll(const struct device *dev)
244 {
245 	const struct input_kbd_matrix_common_config *cfg = dev->config;
246 	k_timepoint_t poll_time_end;
247 	uint32_t current_cycles;
248 	uint32_t cycles_diff;
249 	uint32_t wait_period_us;
250 
251 	poll_time_end = input_kbd_matrix_poll_timeout(dev);
252 
253 	while (true) {
254 		uint32_t start_period_cycles = k_cycle_get_32();
255 
256 		if (input_kbd_matrix_check_key_events(dev)) {
257 			poll_time_end = input_kbd_matrix_poll_timeout(dev);
258 		} else if (sys_timepoint_expired(poll_time_end)) {
259 			break;
260 		}
261 
262 		/*
263 		 * Subtract the time invested from the sleep period in order to
264 		 * compensate for the time invested in debouncing a key
265 		 */
266 		current_cycles = k_cycle_get_32();
267 		cycles_diff = current_cycles - start_period_cycles;
268 		wait_period_us = cfg->poll_period_us - k_cyc_to_us_floor32(cycles_diff);
269 
270 		wait_period_us = CLAMP(wait_period_us,
271 				       USEC_PER_MSEC, cfg->poll_period_us);
272 
273 		LOG_DBG("wait_period_us: %d", wait_period_us);
274 
275 		/* Allow other threads to run while we sleep */
276 		k_usleep(wait_period_us);
277 	}
278 }
279 
input_kbd_matrix_polling_thread(void * arg1,void * unused2,void * unused3)280 static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unused3)
281 {
282 	const struct device *dev = arg1;
283 	const struct input_kbd_matrix_common_config *cfg = dev->config;
284 	const struct input_kbd_matrix_api *api = cfg->api;
285 	struct input_kbd_matrix_common_data *data = dev->data;
286 
287 	ARG_UNUSED(unused2);
288 	ARG_UNUSED(unused3);
289 
290 	while (true) {
291 		input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL);
292 		api->set_detect_mode(dev, true);
293 
294 		/* Check the rows again after enabling the interrupt to catch
295 		 * any potential press since the last read.
296 		 */
297 		if (api->read_row(dev) != 0) {
298 			input_kbd_matrix_poll_start(dev);
299 		}
300 
301 		k_sem_take(&data->poll_lock, K_FOREVER);
302 		LOG_DBG("scan start");
303 
304 		/* Disable interrupt of KSI pins and start polling */
305 		api->set_detect_mode(dev, false);
306 
307 		input_kbd_matrix_poll(dev);
308 	}
309 }
310 
input_kbd_matrix_common_init(const struct device * dev)311 int input_kbd_matrix_common_init(const struct device *dev)
312 {
313 	struct input_kbd_matrix_common_data *data = dev->data;
314 
315 	k_sem_init(&data->poll_lock, 0, 1);
316 
317 	k_thread_create(&data->thread, data->thread_stack,
318 			K_KERNEL_STACK_SIZEOF(data->thread_stack),
319 			input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL,
320 			CONFIG_INPUT_KBD_MATRIX_THREAD_PRIORITY, 0, K_NO_WAIT);
321 
322 	k_thread_name_set(&data->thread, dev->name);
323 
324 	return 0;
325 }
326 
327 #if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC
input_kbd_matrix_actual_key_mask_set(const struct device * dev,uint8_t row,uint8_t col,bool enabled)328 int input_kbd_matrix_actual_key_mask_set(const struct device *dev,
329 					  uint8_t row, uint8_t col, bool enabled)
330 {
331 	const struct input_kbd_matrix_common_config *cfg = dev->config;
332 
333 	if (row >= cfg->row_size || col >= cfg->col_size) {
334 		return -EINVAL;
335 	}
336 
337 	if (cfg->actual_key_mask == NULL) {
338 		LOG_WRN("actual-key-mask not defined for %s", dev->name);
339 		return -EINVAL;
340 	}
341 
342 	WRITE_BIT(cfg->actual_key_mask[col], row, enabled);
343 
344 	return 0;
345 }
346 #endif
347