1 /*
2  * Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include "mlx90394.h"
7 #include <zephyr/drivers/sensor.h>
8 
9 #define DT_DRV_COMPAT melexis_mlx90394
10 
mlx90394_decoder_get_frame_count(const uint8_t * buffer,struct sensor_chan_spec channel,uint16_t * frame_count)11 static int mlx90394_decoder_get_frame_count(const uint8_t *buffer, struct sensor_chan_spec channel,
12 					    uint16_t *frame_count)
13 {
14 	ARG_UNUSED(buffer);
15 	ARG_UNUSED(channel);
16 
17 	/* This sensor lacks a FIFO; there will always only be one frame at a time. */
18 	*frame_count = 1;
19 	return 0;
20 }
21 
mlx90394_decoder_get_size_info(struct sensor_chan_spec channel,size_t * base_size,size_t * frame_size)22 static int mlx90394_decoder_get_size_info(struct sensor_chan_spec channel, size_t *base_size,
23 					  size_t *frame_size)
24 {
25 	switch (channel.chan_type) {
26 	case SENSOR_CHAN_MAGN_X:
27 	case SENSOR_CHAN_MAGN_Y:
28 	case SENSOR_CHAN_MAGN_Z:
29 	case SENSOR_CHAN_MAGN_XYZ: {
30 		*base_size = sizeof(struct sensor_three_axis_data);
31 		*frame_size = sizeof(struct sensor_three_axis_sample_data);
32 	} break;
33 	case SENSOR_CHAN_AMBIENT_TEMP: {
34 		*base_size = sizeof(struct sensor_q31_data);
35 		*frame_size = sizeof(struct sensor_q31_sample_data);
36 	} break;
37 	default:
38 		return -ENOTSUP;
39 	}
40 	return 0;
41 }
42 
mlx90394_convert_raw_magn_to_q31(int16_t reading,q31_t * out,const enum mlx90394_reg_config_val config_val)43 static int mlx90394_convert_raw_magn_to_q31(int16_t reading, q31_t *out,
44 					    const enum mlx90394_reg_config_val config_val)
45 {
46 	int64_t intermediate;
47 
48 	if (config_val == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
49 		intermediate = ((int64_t)reading * MLX90394_HIGH_SENSITIVITY_MICRO_GAUSS_PER_BIT) *
50 			       ((int64_t)INT32_MAX + 1) /
51 			       ((1 << MLX90394_SHIFT_MAGN_HIGH_SENSITIVITY) * INT64_C(1000000));
52 	} else {
53 		intermediate = ((int64_t)reading * MLX90394_HIGH_RANGE_MICRO_GAUSS_PER_BIT) *
54 			       ((int64_t)INT32_MAX + 1) /
55 			       ((1 << MLX90394_SHIFT_MAGN_HIGH_RANGE) * INT64_C(1000000));
56 	}
57 
58 	*out = CLAMP(intermediate, INT32_MIN, INT32_MAX);
59 	return 0;
60 }
mlx90394_convert_raw_temp_to_q31(int16_t reading,q31_t * out)61 static int mlx90394_convert_raw_temp_to_q31(int16_t reading, q31_t *out)
62 {
63 
64 	int64_t intermediate = ((int64_t)reading * MLX90394_MICRO_CELSIUS_PER_BIT) *
65 			       ((int64_t)INT32_MAX + 1) /
66 			       ((1 << MLX90394_SHIFT_TEMP) * INT64_C(1000000));
67 
68 	*out = CLAMP(intermediate, INT32_MIN, INT32_MAX);
69 	return 0;
70 }
71 
mlx90394_decoder_decode(const uint8_t * buffer,struct sensor_chan_spec channel,uint32_t * fit,uint16_t max_count,void * data_out)72 static int mlx90394_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec channel,
73 				   uint32_t *fit, uint16_t max_count, void *data_out)
74 {
75 	const struct mlx90394_encoded_data *edata = (const struct mlx90394_encoded_data *)buffer;
76 
77 	if (*fit != 0) {
78 		return 0;
79 	}
80 
81 	switch (channel.chan_type) {
82 	case SENSOR_CHAN_MAGN_X:
83 	case SENSOR_CHAN_MAGN_Y:
84 	case SENSOR_CHAN_MAGN_Z:
85 	case SENSOR_CHAN_MAGN_XYZ: {
86 		struct sensor_three_axis_data *out = data_out;
87 
88 		out->header.base_timestamp_ns = edata->header.timestamp;
89 		out->header.reading_count = 1;
90 		if (edata->header.config_val == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
91 			out->shift = MLX90394_SHIFT_MAGN_HIGH_SENSITIVITY;
92 		} else {
93 			out->shift = MLX90394_SHIFT_MAGN_HIGH_RANGE;
94 		}
95 
96 		mlx90394_convert_raw_magn_to_q31(edata->readings[0], &out->readings[0].x,
97 						 edata->header.config_val);
98 		mlx90394_convert_raw_magn_to_q31(edata->readings[1], &out->readings[0].y,
99 						 edata->header.config_val);
100 		mlx90394_convert_raw_magn_to_q31(edata->readings[2], &out->readings[0].z,
101 						 edata->header.config_val);
102 		*fit = 1;
103 	} break;
104 	case SENSOR_CHAN_AMBIENT_TEMP: {
105 		struct sensor_q31_data *out = data_out;
106 
107 		out->header.base_timestamp_ns = edata->header.timestamp;
108 		out->header.reading_count = 1;
109 		out->shift = MLX90394_SHIFT_TEMP;
110 		mlx90394_convert_raw_temp_to_q31(edata->readings[3], &out->readings[0].temperature);
111 		*fit = 1;
112 	} break;
113 	default:
114 		return -ENOTSUP;
115 	}
116 	return 1;
117 }
118 
119 SENSOR_DECODER_API_DT_DEFINE() = {
120 	.get_frame_count = mlx90394_decoder_get_frame_count,
121 	.get_size_info = mlx90394_decoder_get_size_info,
122 	.decode = mlx90394_decoder_decode,
123 };
124 
mlx90394_get_decoder(const struct device * dev,const struct sensor_decoder_api ** decoder)125 int mlx90394_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
126 {
127 	ARG_UNUSED(dev);
128 	*decoder = &SENSOR_DECODER_NAME();
129 
130 	return 0;
131 }
132