Line data Source code
1 1 : /*
2 : * Copyright 2023 Google LLC
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : * @ingroup input_kbd_matrix
10 : * @brief Main header file for keyboard matrix input devices.
11 : */
12 :
13 : #ifndef ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_
14 : #define ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_
15 :
16 : /**
17 : * @defgroup input_kbd_matrix Keyboard Matrix
18 : * @ingroup input_interface
19 : * @{
20 : */
21 :
22 : #include <zephyr/device.h>
23 : #include <zephyr/kernel.h>
24 : #include <zephyr/pm/device.h>
25 : #include <zephyr/sys/atomic.h>
26 : #include <zephyr/sys/util.h>
27 : #include <zephyr/sys_clock.h>
28 : #include <zephyr/toolchain.h>
29 :
30 : /** Special drive_column argument for not driving any column */
31 1 : #define INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE -1
32 :
33 : /** Special drive_column argument for driving all the columns */
34 1 : #define INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL -2
35 :
36 : /** Number of tracked scan cycles */
37 1 : #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U
38 :
39 : /** Row entry data type */
40 : #if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW
41 : typedef uint16_t kbd_row_t;
42 : #define PRIkbdrow "04" PRIx16
43 : #else
44 1 : typedef uint8_t kbd_row_t;
45 0 : #define PRIkbdrow "02" PRIx8
46 : #endif
47 :
48 : #if defined(CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC) || defined(__DOXYGEN__)
49 0 : #define INPUT_KBD_ACTUAL_KEY_MASK_CONST
50 : /**
51 : * @brief Enables or disables a specific row, column combination in the actual
52 : * key mask.
53 : *
54 : * This allows enabling or disabling specific row, column combination in the
55 : * actual key mask in runtime. It can be useful if some of the keys are not
56 : * present in some configuration, and the specific configuration is determined
57 : * in runtime. Requires @kconfig{CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC} to
58 : * be enabled.
59 : *
60 : * @param dev Pointer to the keyboard matrix device.
61 : * @param row The matrix row to enable or disable.
62 : * @param col The matrix column to enable or disable.
63 : * @param enabled Whether the specified row, col has to be enabled or disabled.
64 : *
65 : * @retval 0 If the change is successful.
66 : * @retval -errno Negative errno if row or col are out of range for the device.
67 : */
68 1 : int input_kbd_matrix_actual_key_mask_set(const struct device *dev,
69 : uint8_t row, uint8_t col, bool enabled);
70 : #else
71 : #define INPUT_KBD_ACTUAL_KEY_MASK_CONST const
72 : #endif
73 :
74 : /** Maximum number of rows */
75 1 : #define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t)
76 :
77 : /**
78 : * @brief Keyboard matrix internal APIs.
79 : */
80 1 : struct input_kbd_matrix_api {
81 : /**
82 : * @brief Request to drive a specific column.
83 : *
84 : * Request to drive a specific matrix column, or none, or all.
85 : *
86 : * @param dev Pointer to the keyboard matrix device.
87 : * @param col The column to drive, or
88 : * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or
89 : * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL.
90 : */
91 1 : void (*drive_column)(const struct device *dev, int col);
92 : /**
93 : * @brief Read the matrix row.
94 : *
95 : * @param dev Pointer to the keyboard matrix device.
96 : */
97 1 : kbd_row_t (*read_row)(const struct device *dev);
98 : /**
99 : * @brief Request to put the matrix in detection mode.
100 : *
101 : * Request to put the driver in detection mode, this is called after a
102 : * request to drive all the column and typically involves reenabling
103 : * interrupts row pin changes.
104 : *
105 : * @param dev Pointer to the keyboard matrix device.
106 : * @param enable Whether detection mode has to be enabled or disabled.
107 : */
108 1 : void (*set_detect_mode)(const struct device *dev, bool enabled);
109 : };
110 :
111 : /**
112 : * @brief Common keyboard matrix config.
113 : *
114 : * This structure **must** be placed first in the driver's config structure.
115 : */
116 1 : struct input_kbd_matrix_common_config {
117 0 : const struct input_kbd_matrix_api *api;
118 0 : uint8_t row_size;
119 0 : uint8_t col_size;
120 0 : uint32_t poll_period_us;
121 0 : uint32_t stable_poll_period_us;
122 0 : uint32_t poll_timeout_ms;
123 0 : uint32_t debounce_down_us;
124 0 : uint32_t debounce_up_us;
125 0 : uint32_t settle_time_us;
126 0 : bool ghostkey_check;
127 0 : INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t *actual_key_mask;
128 :
129 : /* extra data pointers */
130 0 : kbd_row_t *matrix_stable_state;
131 0 : kbd_row_t *matrix_unstable_state;
132 0 : kbd_row_t *matrix_previous_state;
133 0 : kbd_row_t *matrix_new_state;
134 0 : uint8_t *scan_cycle_idx;
135 : };
136 :
137 0 : #define INPUT_KBD_MATRIX_DATA_NAME(node_id, name) \
138 : _CONCAT(__input_kbd_matrix_, \
139 : _CONCAT(name, DEVICE_DT_NAME_GET(node_id)))
140 :
141 : /**
142 : * @brief Defines the common keyboard matrix support data from devicetree,
143 : * specify row and col count.
144 : */
145 1 : #define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \
146 : BUILD_ASSERT(IN_RANGE(_row_size, 1, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \
147 : BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \
148 : IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \
149 : BUILD_ASSERT(DT_PROP_LEN(node_id, actual_key_mask) == _col_size, \
150 : "actual-key-mask size does not match the number of columns"); \
151 : static INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t \
152 : INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask)[_col_size] = \
153 : DT_PROP(node_id, actual_key_mask); \
154 : )) \
155 : static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \
156 : static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \
157 : static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \
158 : static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \
159 : static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx)[_row_size * _col_size];
160 :
161 : /**
162 : * @brief Defines the common keyboard matrix support data from devicetree.
163 : */
164 1 : #define INPUT_KBD_MATRIX_DT_DEFINE(node_id) \
165 : INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL( \
166 : node_id, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size))
167 :
168 : /**
169 : * @brief Defines the common keyboard matrix support data from devicetree
170 : * instance, specify row and col count.
171 : *
172 : * @param inst Instance.
173 : * @param row_size The matrix row count.
174 : * @param col_size The matrix column count.
175 : */
176 1 : #define INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL(inst, row_size, col_size) \
177 : INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(DT_DRV_INST(inst), row_size, col_size)
178 :
179 : /**
180 : * @brief Defines the common keyboard matrix support data from devicetree instance.
181 : *
182 : * @param inst Instance.
183 : */
184 1 : #define INPUT_KBD_MATRIX_DT_INST_DEFINE(inst) \
185 : INPUT_KBD_MATRIX_DT_DEFINE(DT_DRV_INST(inst))
186 :
187 : /**
188 : * @brief Initialize common keyboard matrix config from devicetree, specify row and col count.
189 : *
190 : * @param node_id The devicetree node identifier.
191 : * @param _api Pointer to a @ref input_kbd_matrix_api structure.
192 : * @param _row_size The matrix row count.
193 : * @param _col_size The matrix column count.
194 : */
195 1 : #define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(node_id, _api, _row_size, _col_size) \
196 : { \
197 : .api = _api, \
198 : .row_size = _row_size, \
199 : .col_size = _col_size, \
200 : .poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \
201 : .stable_poll_period_us = DT_PROP_OR(node_id, stable_poll_period_ms, \
202 : DT_PROP(node_id, poll_period_ms)) * \
203 : USEC_PER_MSEC, \
204 : .poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \
205 : .debounce_down_us = DT_PROP(node_id, debounce_down_ms) * USEC_PER_MSEC, \
206 : .debounce_up_us = DT_PROP(node_id, debounce_up_ms) * USEC_PER_MSEC, \
207 : .settle_time_us = DT_PROP(node_id, settle_time_us), \
208 : .ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \
209 : IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \
210 : .actual_key_mask = INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask), \
211 : )) \
212 : \
213 : .matrix_stable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state), \
214 : .matrix_unstable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state), \
215 : .matrix_previous_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state), \
216 : .matrix_new_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state), \
217 : .scan_cycle_idx = INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx), \
218 : }
219 :
220 : /**
221 : * @brief Initialize common keyboard matrix config from devicetree.
222 : *
223 : * @param node_id The devicetree node identifier.
224 : * @param api Pointer to a @ref input_kbd_matrix_api structure.
225 : */
226 1 : #define INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(node_id, api) \
227 : INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL( \
228 : node_id, api, DT_PROP(node_id, row_size), DT_PROP(node_id, col_size))
229 :
230 : /**
231 : * @brief Initialize common keyboard matrix config from devicetree instance,
232 : * specify row and col count.
233 : *
234 : * @param inst Instance.
235 : * @param api Pointer to a @ref input_kbd_matrix_api structure.
236 : * @param row_size The matrix row count.
237 : * @param col_size The matrix column count.
238 : */
239 1 : #define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL(inst, api, row_size, col_size) \
240 : INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT_ROW_COL(DT_DRV_INST(inst), api, row_size, col_size)
241 :
242 : /**
243 : * @brief Initialize common keyboard matrix config from devicetree instance.
244 : *
245 : * @param inst Instance.
246 : * @param api Pointer to a @ref input_kbd_matrix_api structure.
247 : */
248 1 : #define INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(inst, api) \
249 : INPUT_KBD_MATRIX_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst), api)
250 :
251 : /**
252 : * @brief Common keyboard matrix data.
253 : *
254 : * This structure **must** be placed first in the driver's data structure.
255 : */
256 1 : struct input_kbd_matrix_common_data {
257 : /* Track previous cycles, used for debouncing. */
258 0 : uint32_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES];
259 0 : uint8_t scan_cycles_idx;
260 :
261 0 : struct k_sem poll_lock;
262 : #ifdef CONFIG_PM_DEVICE
263 : atomic_t suspended;
264 : #endif
265 :
266 0 : struct k_thread thread;
267 :
268 0 : K_KERNEL_STACK_MEMBER(thread_stack,
269 : CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE);
270 : };
271 :
272 : /**
273 : * @brief Validate the offset of the common data structures.
274 : *
275 : * @param config Name of the config structure.
276 : * @param data Name of the data structure.
277 : */
278 1 : #define INPUT_KBD_STRUCT_CHECK(config, data) \
279 : BUILD_ASSERT(offsetof(config, common) == 0, \
280 : "struct input_kbd_matrix_common_config must be placed first"); \
281 : BUILD_ASSERT(offsetof(data, common) == 0, \
282 : "struct input_kbd_matrix_common_data must be placed first")
283 :
284 : /**
285 : * @brief Start scanning the keyboard matrix
286 : *
287 : * Starts the keyboard matrix scanning cycle, this should be called in reaction
288 : * of a press event, after the device has been put in detect mode.
289 : *
290 : * @param dev Keyboard matrix device instance.
291 : */
292 1 : void input_kbd_matrix_poll_start(const struct device *dev);
293 :
294 : #if defined(CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK) || defined(__DOXYGEN__)
295 : /**
296 : * @brief Drive column hook
297 : *
298 : * This can be implemented by the application to handle column selection
299 : * quirks. Called after the driver specific drive_column function. Requires
300 : * @kconfig{CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK} to be enabled.
301 : *
302 : * @param dev Keyboard matrix device instance.
303 : * @param col The column to drive, or
304 : * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or
305 : * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL.
306 : */
307 1 : void input_kbd_matrix_drive_column_hook(const struct device *dev, int col);
308 : #endif
309 :
310 : /**
311 : * @brief Common function to initialize a keyboard matrix device at init time.
312 : *
313 : * This function must be called at the end of the device init function.
314 : *
315 : * @param dev Keyboard matrix device instance.
316 : *
317 : * @retval 0 If initialized successfully.
318 : * @retval -errno Negative errno in case of failure.
319 : */
320 1 : int input_kbd_matrix_common_init(const struct device *dev);
321 :
322 : #ifdef CONFIG_PM_DEVICE
323 : /**
324 : * @brief Common power management action handler.
325 : *
326 : * This handles PM actions for a keyboard matrix device, meant to be used as
327 : * argument of @ref PM_DEVICE_DT_INST_DEFINE.
328 : *
329 : * @param dev Keyboard matrix device instance.
330 : * @param action The power management action to handle.
331 : */
332 : int input_kbd_matrix_pm_action(const struct device *dev,
333 : enum pm_device_action action);
334 : #endif
335 :
336 : /** @} */
337 :
338 : #endif /* ZEPHYR_INCLUDE_INPUT_KBD_MATRIX_H_ */
|