1 /*
2  * Copyright (c) 2024 Analog Devices Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "adxl372.h"
8 
9 #ifdef CONFIG_ADXL372_STREAM
10 
11 /* (1.0 / 10 (sensor sensitivity)) * (2^31 / 2^11 (sensor shift) ) * SENSOR_G */
12 #define SENSOR_QSCALE_FACTOR UINT32_C(1027604)
13 
14 #define ADXL372_COMPLEMENT         0xf000
15 
16 static const uint32_t accel_period_ns[] = {
17 	[ADXL372_ODR_400HZ] = UINT32_C(1000000000) / 400,
18 	[ADXL372_ODR_800HZ] = UINT32_C(1000000000) / 800,
19 	[ADXL372_ODR_1600HZ] = UINT32_C(1000000000) / 1600,
20 	[ADXL372_ODR_3200HZ] = UINT32_C(1000000000) / 3200,
21 	[ADXL372_ODR_6400HZ] = UINT32_C(1000000000) / 6400,
22 };
23 
adxl372_accel_convert_q31(q31_t * out,const uint8_t * buff)24 static inline void adxl372_accel_convert_q31(q31_t *out, const uint8_t *buff)
25 {
26 	int16_t data_in = ((int16_t)*buff << 4) | (((int16_t)*(buff + 1) & 0xF0) >> 4);
27 
28 	if (data_in & BIT(11)) {
29 		data_in |= ADXL372_COMPLEMENT;
30 	}
31 
32 	*out = data_in * SENSOR_QSCALE_FACTOR;
33 }
34 
adxl372_decode_stream(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)35 static int adxl372_decode_stream(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
36 				 uint32_t *fit, uint16_t max_count, void *data_out)
37 {
38 	const struct adxl372_fifo_data *enc_data = (const struct adxl372_fifo_data *)buffer;
39 	const uint8_t *buffer_end =
40 		buffer + sizeof(struct adxl372_fifo_data) + enc_data->fifo_byte_count;
41 	int count = 0;
42 	uint8_t sample_num = 0;
43 
44 	if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) {
45 		return 0;
46 	}
47 
48 	struct sensor_three_axis_data *data = (struct sensor_three_axis_data *)data_out;
49 
50 	memset(data, 0, sizeof(struct sensor_three_axis_data));
51 	data->header.base_timestamp_ns = enc_data->timestamp;
52 	data->header.reading_count = 1;
53 	data->header.shift = 11; /* Sensor shift */
54 
55 	buffer += sizeof(struct adxl372_fifo_data);
56 
57 	uint8_t sample_set_size = enc_data->sample_set_size;
58 	uint64_t period_ns = accel_period_ns[enc_data->accel_odr];
59 
60 	/* Calculate which sample is decoded. */
61 	if ((uint8_t *)*fit >= buffer) {
62 		sample_num = ((uint8_t *)*fit - buffer) / sample_set_size;
63 	}
64 
65 	while (count < max_count && buffer < buffer_end) {
66 		const uint8_t *sample_end = buffer;
67 
68 		sample_end += sample_set_size;
69 
70 		if ((uintptr_t)buffer < *fit) {
71 			/* This frame was already decoded, move on to the next frame */
72 			buffer = sample_end;
73 			continue;
74 		}
75 
76 		switch (chan_spec.chan_type) {
77 		case SENSOR_CHAN_ACCEL_X:
78 			if (enc_data->has_x) {
79 				data->readings[count].timestamp_delta = sample_num * period_ns;
80 				adxl372_accel_convert_q31(&data->readings[count].x, buffer);
81 			}
82 			break;
83 		case SENSOR_CHAN_ACCEL_Y:
84 			if (enc_data->has_y) {
85 				uint8_t buff_offset = 0;
86 
87 				/* If packet has X channel, then Y channel has offset. */
88 				if (enc_data->has_x) {
89 					buff_offset = 2;
90 				}
91 				data->readings[count].timestamp_delta = sample_num * period_ns;
92 				adxl372_accel_convert_q31(&data->readings[count].y,
93 							  (buffer + buff_offset));
94 			}
95 			break;
96 		case SENSOR_CHAN_ACCEL_Z:
97 			if (enc_data->has_z) {
98 				uint8_t buff_offset = 0;
99 
100 				/* If packet has X channel and/or Y channel,
101 				 * then Z channel has offset.
102 				 */
103 				if (enc_data->has_x) {
104 					buff_offset = 2;
105 				}
106 
107 				if (enc_data->has_y) {
108 					buff_offset += 2;
109 				}
110 				data->readings[count].timestamp_delta = sample_num * period_ns;
111 				adxl372_accel_convert_q31(&data->readings[count].z,
112 							  (buffer + buff_offset));
113 			}
114 			break;
115 		case SENSOR_CHAN_ACCEL_XYZ:
116 			data->readings[count].timestamp_delta = sample_num * period_ns;
117 			uint8_t buff_offset = 0;
118 
119 			if (enc_data->has_x) {
120 				adxl372_accel_convert_q31(&data->readings[count].x, buffer);
121 				buff_offset = 2;
122 			}
123 
124 			if (enc_data->has_y) {
125 				adxl372_accel_convert_q31(&data->readings[count].y,
126 							  (buffer + buff_offset));
127 
128 				buff_offset += 2;
129 			}
130 
131 			if (enc_data->has_z) {
132 				adxl372_accel_convert_q31(&data->readings[count].z,
133 							  (buffer + buff_offset));
134 			}
135 			break;
136 		default:
137 			return -ENOTSUP;
138 		}
139 
140 		buffer = sample_end;
141 		*fit = (uintptr_t)sample_end;
142 		count++;
143 	}
144 	return count;
145 }
146 
147 #endif /* CONFIG_ADXL372_STREAM */
148 
adxl372_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint16_t * frame_count)149 static int adxl372_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
150 					   uint16_t *frame_count)
151 {
152 	int32_t ret = -ENOTSUP;
153 
154 	if (chan_spec.chan_idx != 0) {
155 		return ret;
156 	}
157 
158 #ifdef CONFIG_ADXL372_STREAM
159 	const struct adxl372_fifo_data *data = (const struct adxl372_fifo_data *)buffer;
160 
161 	if (!data->is_fifo) {
162 #endif /* CONFIG_ADXL372_STREAM */
163 		switch (chan_spec.chan_type) {
164 		case SENSOR_CHAN_ACCEL_X:
165 		case SENSOR_CHAN_ACCEL_Y:
166 		case SENSOR_CHAN_ACCEL_Z:
167 		case SENSOR_CHAN_ACCEL_XYZ:
168 			*frame_count = 1;
169 			ret = 0;
170 			break;
171 
172 		default:
173 			break;
174 		}
175 #ifdef CONFIG_ADXL372_STREAM
176 	} else {
177 		if (data->fifo_byte_count == 0) {
178 			*frame_count = 0;
179 			ret = 0;
180 		} else {
181 			switch (chan_spec.chan_type) {
182 			case SENSOR_CHAN_ACCEL_X:
183 				if (data->has_x) {
184 					*frame_count =
185 						data->fifo_byte_count / data->sample_set_size;
186 					ret = 0;
187 				}
188 				break;
189 			case SENSOR_CHAN_ACCEL_Y:
190 				if (data->has_y) {
191 					*frame_count =
192 						data->fifo_byte_count / data->sample_set_size;
193 					ret = 0;
194 				}
195 				break;
196 			case SENSOR_CHAN_ACCEL_Z:
197 				if (data->has_z) {
198 					*frame_count =
199 						data->fifo_byte_count / data->sample_set_size;
200 					ret = 0;
201 				}
202 				break;
203 			case SENSOR_CHAN_ACCEL_XYZ:
204 				if (data->has_x || data->has_y || data->has_z) {
205 					*frame_count =
206 						data->fifo_byte_count / data->sample_set_size;
207 					ret = 0;
208 				}
209 				break;
210 
211 			default:
212 				break;
213 			}
214 		}
215 	}
216 #endif /* CONFIG_ADXL372_STREAM */
217 
218 	return ret;
219 }
220 
adxl372_decode_sample(const struct adxl372_xyz_accel_data * data,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)221 static int adxl372_decode_sample(const struct adxl372_xyz_accel_data *data,
222 				 struct sensor_chan_spec chan_spec, uint32_t *fit,
223 				 uint16_t max_count, void *data_out)
224 {
225 	struct sensor_value *out = (struct sensor_value *)data_out;
226 
227 	if (*fit > 0) {
228 		return -ENOTSUP;
229 	}
230 
231 	switch (chan_spec.chan_type) {
232 	case SENSOR_CHAN_ACCEL_X:
233 		adxl372_accel_convert(out, data->x);
234 		break;
235 	case SENSOR_CHAN_ACCEL_Y:
236 		adxl372_accel_convert(out, data->y);
237 		break;
238 	case SENSOR_CHAN_ACCEL_Z:
239 		adxl372_accel_convert(out, data->z);
240 		break;
241 	case SENSOR_CHAN_ACCEL_XYZ:
242 		adxl372_accel_convert(out++, data->x);
243 		adxl372_accel_convert(out++, data->y);
244 		adxl372_accel_convert(out, data->z);
245 		break;
246 	default:
247 		return -ENOTSUP;
248 	}
249 
250 	*fit = 1;
251 
252 	return 0;
253 }
254 
adxl372_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec chan_spec,uint32_t * fit,uint16_t max_count,void * data_out)255 static int adxl372_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
256 				    uint32_t *fit, uint16_t max_count, void *data_out)
257 {
258 	const struct adxl372_xyz_accel_data *data = (const struct adxl372_xyz_accel_data *)buffer;
259 
260 #ifdef CONFIG_ADXL372_STREAM
261 	if (data->is_fifo) {
262 		return adxl372_decode_stream(buffer, chan_spec, fit, max_count, data_out);
263 	}
264 #endif /* CONFIG_ADXL372_STREAM */
265 
266 	return adxl372_decode_sample(data, chan_spec, fit, max_count, data_out);
267 }
268 
adxl372_decoder_has_trigger(const uint8_t * buffer,enum sensor_trigger_type trigger)269 static bool adxl372_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
270 {
271 	const struct adxl372_fifo_data *data = (const struct adxl372_fifo_data *)buffer;
272 
273 	if (!data->is_fifo) {
274 		return false;
275 	}
276 
277 	switch (trigger) {
278 	case SENSOR_TRIG_DATA_READY:
279 		return FIELD_GET(ADXL372_INT1_MAP_DATA_RDY_MSK, data->int_status);
280 	case SENSOR_TRIG_FIFO_WATERMARK:
281 	case SENSOR_TRIG_FIFO_FULL:
282 		return FIELD_GET(ADXL372_INT1_MAP_FIFO_FULL_MSK, data->int_status);
283 	default:
284 		return false;
285 	}
286 }
287 
288 SENSOR_DECODER_API_DT_DEFINE() = {
289 	.get_frame_count = adxl372_decoder_get_frame_count,
290 	.decode = adxl372_decoder_decode,
291 	.has_trigger = adxl372_decoder_has_trigger,
292 };
293 
adxl372_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)294 int adxl372_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
295 {
296 	ARG_UNUSED(dev);
297 	*decoder = &SENSOR_DECODER_NAME();
298 
299 	return 0;
300 }
301