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