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