1 /*
2  * Copyright 2023 Google LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT analog_axis
8 
9 #include <stdlib.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/adc.h>
12 #include <zephyr/input/input.h>
13 #include <zephyr/input/input_analog_axis.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/sys/util.h>
17 
18 LOG_MODULE_REGISTER(analog_axis, CONFIG_INPUT_LOG_LEVEL);
19 
20 struct analog_axis_channel_config {
21 	struct adc_dt_spec adc;
22 	int16_t out_min;
23 	int16_t out_max;
24 	uint16_t axis;
25 	bool invert;
26 };
27 
28 struct analog_axis_channel_data {
29 	int last_out;
30 };
31 
32 struct analog_axis_config {
33 	uint32_t poll_period_ms;
34 	const struct analog_axis_channel_config *channel_cfg;
35 	struct analog_axis_channel_data *channel_data;
36 	struct analog_axis_calibration *calibration;
37 	const uint8_t num_channels;
38 };
39 
40 struct analog_axis_data {
41 	struct k_mutex cal_lock;
42 	analog_axis_raw_data_t raw_data_cb;
43 	struct k_timer timer;
44 	struct k_thread thread;
45 
46 	K_KERNEL_STACK_MEMBER(thread_stack,
47 			      CONFIG_INPUT_ANALOG_AXIS_THREAD_STACK_SIZE);
48 };
49 
analog_axis_num_axes(const struct device * dev)50 int analog_axis_num_axes(const struct device *dev)
51 {
52 	const struct analog_axis_config *cfg = dev->config;
53 
54 	return cfg->num_channels;
55 }
56 
analog_axis_calibration_get(const struct device * dev,int channel,struct analog_axis_calibration * out_cal)57 int analog_axis_calibration_get(const struct device *dev,
58 				int channel,
59 				struct analog_axis_calibration *out_cal)
60 {
61 	const struct analog_axis_config *cfg = dev->config;
62 	struct analog_axis_data *data = dev->data;
63 	struct analog_axis_calibration *cal = &cfg->calibration[channel];
64 
65 	if (channel >= cfg->num_channels) {
66 		return -EINVAL;
67 	}
68 
69 	k_mutex_lock(&data->cal_lock, K_FOREVER);
70 	memcpy(out_cal, cal, sizeof(struct analog_axis_calibration));
71 	k_mutex_unlock(&data->cal_lock);
72 
73 	return 0;
74 }
75 
analog_axis_set_raw_data_cb(const struct device * dev,analog_axis_raw_data_t cb)76 void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_t cb)
77 {
78 	struct analog_axis_data *data = dev->data;
79 
80 	k_mutex_lock(&data->cal_lock, K_FOREVER);
81 	data->raw_data_cb = cb;
82 	k_mutex_unlock(&data->cal_lock);
83 }
84 
analog_axis_calibration_set(const struct device * dev,int channel,struct analog_axis_calibration * new_cal)85 int analog_axis_calibration_set(const struct device *dev,
86 				int channel,
87 				struct analog_axis_calibration *new_cal)
88 {
89 	const struct analog_axis_config *cfg = dev->config;
90 	struct analog_axis_data *data = dev->data;
91 	struct analog_axis_calibration *cal = &cfg->calibration[channel];
92 
93 	if (channel >= cfg->num_channels) {
94 		return -EINVAL;
95 	}
96 
97 	k_mutex_lock(&data->cal_lock, K_FOREVER);
98 	memcpy(cal, new_cal, sizeof(struct analog_axis_calibration));
99 	k_mutex_unlock(&data->cal_lock);
100 
101 	return 0;
102 }
103 
analog_axis_loop(const struct device * dev)104 static void analog_axis_loop(const struct device *dev)
105 {
106 	const struct analog_axis_config *cfg = dev->config;
107 	struct analog_axis_data *data = dev->data;
108 	int16_t bufs[cfg->num_channels];
109 	int32_t out;
110 	struct adc_sequence sequence = {
111 		.buffer = bufs,
112 		.buffer_size = sizeof(bufs),
113 	};
114 	const struct analog_axis_channel_config *axis_cfg_0 = &cfg->channel_cfg[0];
115 	int err;
116 	int i;
117 
118 	adc_sequence_init_dt(&axis_cfg_0->adc, &sequence);
119 
120 	for (i = 0; i < cfg->num_channels; i++) {
121 		const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i];
122 
123 		sequence.channels |= BIT(axis_cfg->adc.channel_id);
124 	}
125 
126 	err = adc_read(axis_cfg_0->adc.dev, &sequence);
127 	if (err < 0) {
128 		LOG_ERR("Could not read (%d)", err);
129 		return;
130 	}
131 
132 	k_mutex_lock(&data->cal_lock, K_FOREVER);
133 
134 	for (i = 0; i < cfg->num_channels; i++) {
135 		const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i];
136 		struct analog_axis_channel_data *axis_data = &cfg->channel_data[i];
137 		struct analog_axis_calibration *cal = &cfg->calibration[i];
138 		int16_t in_range = cal->in_max - cal->in_min;
139 		int16_t out_range = axis_cfg->out_max - axis_cfg->out_min;
140 		int32_t raw_val = bufs[i];
141 
142 		if (axis_cfg->invert) {
143 			raw_val *= -1;
144 		}
145 
146 		if (data->raw_data_cb != NULL) {
147 			data->raw_data_cb(dev, i, raw_val);
148 		}
149 
150 		LOG_DBG("%s: ch %d: raw_val: %d", dev->name, i, raw_val);
151 
152 		out = CLAMP((raw_val - cal->in_min) * out_range / in_range + axis_cfg->out_min,
153 			    axis_cfg->out_min, axis_cfg->out_max);
154 
155 		if (cal->out_deadzone > 0) {
156 			int16_t center = DIV_ROUND_CLOSEST(
157 					axis_cfg->out_max  + axis_cfg->out_min, 2);
158 			if (abs(out - center) < cal->out_deadzone) {
159 				out = center;
160 			}
161 		}
162 
163 		if (axis_data->last_out != out) {
164 			input_report_abs(dev, axis_cfg->axis, out, true, K_FOREVER);
165 		}
166 		axis_data->last_out = out;
167 	}
168 
169 	k_mutex_unlock(&data->cal_lock);
170 }
171 
analog_axis_thread(void * arg1,void * arg2,void * arg3)172 static void analog_axis_thread(void *arg1, void *arg2, void *arg3)
173 {
174 	const struct device *dev = arg1;
175 	const struct analog_axis_config *cfg = dev->config;
176 	struct analog_axis_data *data = dev->data;
177 	int err;
178 	int i;
179 
180 	for (i = 0; i < cfg->num_channels; i++) {
181 		const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i];
182 
183 		if (!adc_is_ready_dt(&axis_cfg->adc)) {
184 			LOG_ERR("ADC controller device not ready");
185 			return;
186 		}
187 
188 		err = adc_channel_setup_dt(&axis_cfg->adc);
189 		if (err < 0) {
190 			LOG_ERR("Could not setup channel #%d (%d)", i, err);
191 			return;
192 		}
193 	}
194 
195 	k_timer_init(&data->timer, NULL, NULL);
196 	k_timer_start(&data->timer,
197 		      K_MSEC(cfg->poll_period_ms), K_MSEC(cfg->poll_period_ms));
198 
199 	while (true) {
200 		analog_axis_loop(dev);
201 		k_timer_status_sync(&data->timer);
202 	}
203 }
204 
analog_axis_init(const struct device * dev)205 static int analog_axis_init(const struct device *dev)
206 {
207 	struct analog_axis_data *data = dev->data;
208 	k_tid_t tid;
209 
210 	k_mutex_init(&data->cal_lock);
211 
212 	tid = k_thread_create(&data->thread, data->thread_stack,
213 			      K_KERNEL_STACK_SIZEOF(data->thread_stack),
214 			      analog_axis_thread, (void *)dev, NULL, NULL,
215 			      CONFIG_INPUT_ANALOG_AXIS_THREAD_PRIORITY,
216 			      0, K_NO_WAIT);
217 	if (!tid) {
218 		LOG_ERR("thread creation failed");
219 		return -ENODEV;
220 	}
221 
222 	k_thread_name_set(&data->thread, dev->name);
223 
224 	return 0;
225 }
226 
227 #define ANALOG_AXIS_CHANNEL_CFG_DEF(node_id) \
228 	{ \
229 		.adc = ADC_DT_SPEC_GET(node_id), \
230 		.out_min = (int16_t)DT_PROP(node_id, out_min), \
231 		.out_max = (int16_t)DT_PROP(node_id, out_max), \
232 		.axis = DT_PROP(node_id, zephyr_axis), \
233 		.invert = DT_PROP(node_id, invert), \
234 	}
235 
236 #define ANALOG_AXIS_CHANNEL_CAL_DEF(node_id) \
237 	{ \
238 		.in_min = (int16_t)DT_PROP(node_id, in_min), \
239 		.in_max = (int16_t)DT_PROP(node_id, in_max), \
240 		.out_deadzone = DT_PROP(node_id, out_deadzone), \
241 	}
242 
243 #define ANALOG_AXIS_INIT(inst)									\
244 	static const struct analog_axis_channel_config analog_axis_channel_cfg_##inst[] = {	\
245 		DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, ANALOG_AXIS_CHANNEL_CFG_DEF, (,))	\
246 	};											\
247 												\
248 	static struct analog_axis_channel_data							\
249 		analog_axis_channel_data_##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)];	\
250 												\
251 	static struct analog_axis_calibration							\
252 		analog_axis_calibration##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)] = {	\
253 			DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(					\
254 				inst, ANALOG_AXIS_CHANNEL_CAL_DEF, (,))				\
255 		};										\
256 												\
257 	static const struct analog_axis_config analog_axis_cfg_##inst = {			\
258 		.poll_period_ms = DT_INST_PROP(inst, poll_period_ms),				\
259 		.channel_cfg = analog_axis_channel_cfg_##inst,					\
260 		.channel_data = analog_axis_channel_data_##inst,				\
261 		.calibration = analog_axis_calibration##inst,					\
262 		.num_channels = ARRAY_SIZE(analog_axis_channel_cfg_##inst),			\
263 	};											\
264 												\
265 	static struct analog_axis_data analog_axis_data_##inst;					\
266 												\
267 	DEVICE_DT_INST_DEFINE(inst, analog_axis_init, NULL,					\
268 			      &analog_axis_data_##inst, &analog_axis_cfg_##inst,		\
269 			      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
270 
271 DT_INST_FOREACH_STATUS_OKAY(ANALOG_AXIS_INIT)
272