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