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