1 /*
2  * Copyright (c) 2024 Chen Xingyu <hi@xingrz.me>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT adc_keys
7 
8 #include <stdlib.h>
9 #include <stdbool.h>
10 
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/adc.h>
13 #include <zephyr/input/input.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/sys/util.h>
17 
18 LOG_MODULE_REGISTER(adc_keys, CONFIG_INPUT_LOG_LEVEL);
19 
20 struct adc_keys_code_config {
21 	int32_t press_mv;
22 	uint8_t key_index;
23 };
24 
25 struct adc_keys_key_state {
26 	bool orig_state;
27 	bool last_state;
28 	bool curr_state;
29 };
30 
31 struct adc_keys_config {
32 	struct adc_dt_spec channel;
33 	uint32_t sample_period_ms;
34 	int32_t keyup_mv;
35 	const struct adc_keys_code_config *code_cfg;
36 	const uint16_t *key_code;
37 	struct adc_keys_key_state *key_state;
38 	uint8_t code_cnt;
39 	uint8_t key_cnt;
40 };
41 
42 struct adc_keys_data {
43 	const struct device *self;
44 	struct k_work_delayable dwork;
45 	struct adc_sequence seq;
46 };
47 
adc_keys_read(const struct device * dev)48 static inline int32_t adc_keys_read(const struct device *dev)
49 {
50 	const struct adc_keys_config *cfg = dev->config;
51 	struct adc_keys_data *data = dev->data;
52 	uint16_t sample_raw;
53 	int32_t sample_mv;
54 	int ret;
55 
56 	data->seq.buffer = &sample_raw;
57 	data->seq.buffer_size = sizeof(sample_raw);
58 
59 	ret = adc_read(cfg->channel.dev, &data->seq);
60 	if (ret) {
61 		LOG_ERR("ADC read failed %d", ret);
62 		return cfg->keyup_mv;
63 	}
64 
65 	sample_mv = (int32_t)sample_raw;
66 	adc_raw_to_millivolts_dt(&cfg->channel, &sample_mv);
67 
68 	return sample_mv;
69 }
70 
adc_keys_process(const struct device * dev)71 static inline void adc_keys_process(const struct device *dev)
72 {
73 	const struct adc_keys_config *cfg = dev->config;
74 	int32_t sample_mv, closest_mv = 0;
75 	uint32_t diff, closest_diff = UINT32_MAX;
76 	const struct adc_keys_code_config *code_cfg;
77 	struct adc_keys_key_state *key_state;
78 	uint16_t key_code;
79 
80 	sample_mv = adc_keys_read(dev);
81 
82 	/*
83 	 * Find the closest key press threshold to the sample value.
84 	 */
85 
86 	for (uint8_t i = 0; i < cfg->code_cnt; i++) {
87 		diff = abs(sample_mv - cfg->code_cfg[i].press_mv);
88 		if (diff < closest_diff) {
89 			closest_diff = diff;
90 			closest_mv = cfg->code_cfg[i].press_mv;
91 		}
92 	}
93 
94 	diff = abs(sample_mv - cfg->keyup_mv);
95 	if (diff < closest_diff) {
96 		closest_diff = diff;
97 		closest_mv = cfg->keyup_mv;
98 	}
99 
100 	LOG_DBG("sample=%d mV, closest=%d mV, diff=%d mV", sample_mv, closest_mv, closest_diff);
101 
102 	/*
103 	 * Update cached key states and init current states with false
104 	 */
105 
106 	for (uint8_t i = 0; i < cfg->key_cnt; i++) {
107 		key_state = &cfg->key_state[i];
108 
109 		key_state->last_state = key_state->curr_state;
110 		key_state->curr_state = false;
111 	}
112 
113 	/*
114 	 * Update current key states according to the closest key press threshold.
115 	 *
116 	 * Note that multiple keys may have the same press threshold, which is
117 	 * the mixed voltage that these keys are simultaneously pressed.
118 	 */
119 
120 	for (uint8_t i = 0; i < cfg->code_cnt; i++) {
121 		code_cfg = &cfg->code_cfg[i];
122 		key_state = &cfg->key_state[code_cfg->key_index];
123 
124 		/*
125 		 * Only update curr_state if the key is pressed to prevent
126 		 * being overwritten by another threshold configuration.
127 		 */
128 		if (closest_mv == code_cfg->press_mv) {
129 			key_state->curr_state = true;
130 		}
131 	}
132 
133 	/*
134 	 * Report the key event if the key state changed for at least two continuous cycles.
135 	 */
136 
137 	for (uint8_t i = 0; i < cfg->key_cnt; i++) {
138 		key_state = &cfg->key_state[i];
139 		key_code = cfg->key_code[i];
140 
141 		if (key_state->orig_state != key_state->curr_state &&
142 		    key_state->last_state == key_state->curr_state) {
143 			LOG_DBG("Report event %s %d, code=%d", dev->name, key_state->curr_state,
144 				key_code);
145 			input_report_key(dev, key_code, key_state->curr_state, true, K_FOREVER);
146 			key_state->orig_state = key_state->curr_state;
147 		}
148 	}
149 }
150 
adc_keys_work_handler(struct k_work * work)151 static void adc_keys_work_handler(struct k_work *work)
152 {
153 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
154 	struct adc_keys_data *data = CONTAINER_OF(dwork, struct adc_keys_data, dwork);
155 	const struct device *dev = data->self;
156 	const struct adc_keys_config *cfg = dev->config;
157 
158 	adc_keys_process(dev);
159 
160 	k_work_schedule(&data->dwork, K_MSEC(cfg->sample_period_ms));
161 }
162 
adc_keys_init(const struct device * dev)163 static int adc_keys_init(const struct device *dev)
164 {
165 	const struct adc_keys_config *cfg = dev->config;
166 	struct adc_keys_data *data = dev->data;
167 	int ret;
168 
169 	if (!adc_is_ready_dt(&cfg->channel)) {
170 		LOG_ERR("ADC controller device %s not ready", cfg->channel.dev->name);
171 		return -ENODEV;
172 	}
173 
174 	ret = adc_channel_setup_dt(&cfg->channel);
175 	if (ret) {
176 		LOG_ERR("ADC channel setup failed %d", ret);
177 		return ret;
178 	}
179 
180 	ret = adc_sequence_init_dt(&cfg->channel, &data->seq);
181 	if (ret) {
182 		LOG_ERR("ADC sequence init failed %d", ret);
183 		return ret;
184 	}
185 
186 	data->self = dev;
187 	k_work_init_delayable(&data->dwork, adc_keys_work_handler);
188 
189 	if (IS_ENABLED(CONFIG_INPUT_LOG_LEVEL_DBG)) {
190 		for (uint8_t i = 0; i < cfg->code_cnt; i++) {
191 			LOG_DBG("* code %d: key_index=%d threshold=%d mV code=%d", i,
192 				cfg->code_cfg[i].key_index, cfg->code_cfg[i].press_mv,
193 				cfg->key_code[cfg->code_cfg[i].key_index]);
194 		}
195 	}
196 
197 	k_work_schedule(&data->dwork, K_MSEC(cfg->sample_period_ms));
198 
199 	return 0;
200 }
201 
202 #define ADC_KEYS_CODE_CFG_ITEM(node_id, prop, idx)                                                 \
203 	{                                                                                          \
204 		.key_index = DT_NODE_CHILD_IDX(node_id) /* include disabled nodes */,              \
205 		.press_mv = DT_PROP_BY_IDX(node_id, prop, idx),                                    \
206 	}
207 
208 #define ADC_KEYS_CODE_CFG(node_id)                                                                 \
209 	DT_FOREACH_PROP_ELEM_SEP(node_id, press_thresholds_mv, ADC_KEYS_CODE_CFG_ITEM, (,))
210 
211 #define ADC_KEYS_KEY_CODE(node_id) DT_PROP(node_id, zephyr_code)
212 
213 #define ADC_KEYS_INST(n)                                                                           \
214 	static struct adc_keys_data adc_keys_data_##n;                                             \
215                                                                                                    \
216 	static const struct adc_keys_code_config adc_keys_code_cfg_##n[] = {                       \
217 		DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(n, ADC_KEYS_CODE_CFG, (,))};                 \
218                                                                                                    \
219 	static const uint16_t adc_keys_key_code_##n[] = {                                          \
220 		DT_INST_FOREACH_CHILD_SEP(n, ADC_KEYS_KEY_CODE, (,))};                             \
221                                                                                                    \
222 	static struct adc_keys_key_state                                                           \
223 		adc_keys_key_state_##n[ARRAY_SIZE(adc_keys_key_code_##n)];                         \
224                                                                                                    \
225 	static const struct adc_keys_config adc_keys_cfg_##n = {                                   \
226 		.channel = ADC_DT_SPEC_INST_GET(n),                                                \
227 		.sample_period_ms = DT_INST_PROP(n, sample_period_ms),                             \
228 		.keyup_mv = DT_INST_PROP(n, keyup_threshold_mv),                                   \
229 		.code_cfg = adc_keys_code_cfg_##n,                                                 \
230 		.key_code = adc_keys_key_code_##n,                                                 \
231 		.key_state = adc_keys_key_state_##n,                                               \
232 		.code_cnt = ARRAY_SIZE(adc_keys_code_cfg_##n),                                     \
233 		.key_cnt = ARRAY_SIZE(adc_keys_key_code_##n),                                      \
234 	};                                                                                         \
235                                                                                                    \
236 	DEVICE_DT_INST_DEFINE(n, adc_keys_init, NULL, &adc_keys_data_##n, &adc_keys_cfg_##n,       \
237 			      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
238 
239 DT_INST_FOREACH_STATUS_OKAY(ADC_KEYS_INST)
240