1 /*
2  * Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT melexis_mlx90394
7 
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/sensor.h>
12 #include <zephyr/drivers/sensor_data_types.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/drivers/sensor/mlx90394.h>
18 
19 #include "mlx90394.h"
20 #include "mlx90394_reg.h"
21 
22 LOG_MODULE_REGISTER(MLX90394, CONFIG_SENSOR_LOG_LEVEL);
23 
24 /*
25  * conversion time of one single axis for different filter orders if osr is enabled the value has
26  * to be doubled
27  */
28 static const int32_t MLX90394_CONVERSION_TIME_US_AXIS[] = {111, 170,  270,  490,
29 							   910, 1770, 3470, 6890};
30 
31 /* conversion time per axis dependent of filter order */
32 
33 /*
34  * DSP Time per measurement first index:temperature sensor count ( 0..1 ) second index:
35  * magnetic axis count (0..3) in us
36  */
37 static const int32_t MLX90394_DSP_TIME_US[2][4] = {{0, 27, 50, 73}, {20, 63, 86, 110}};
38 
mlx90394_update_measurement_Time_us(struct mlx90394_data * data)39 static void mlx90394_update_measurement_Time_us(struct mlx90394_data *data)
40 {
41 	int32_t en_x = FIELD_GET(MLX90394_CTRL1_X_EN, data->ctrl_reg_values.ctrl1);
42 	int32_t en_y = FIELD_GET(MLX90394_CTRL1_Y_EN, data->ctrl_reg_values.ctrl1);
43 	int32_t en_z = FIELD_GET(MLX90394_CTRL1_Z_EN, data->ctrl_reg_values.ctrl1);
44 	int32_t en_temp = FIELD_GET(MLX90394_CTRL4_T_EN, data->ctrl_reg_values.ctrl4);
45 	int32_t filter_hall_xy =
46 		FIELD_GET(MLX90394_CTRL3_DIG_FILT_HALL_XY, data->ctrl_reg_values.ctrl3);
47 	int32_t filter_hall_z =
48 		FIELD_GET(MLX90394_CTRL4_DIG_FILT_HALL_Z, data->ctrl_reg_values.ctrl4);
49 	int32_t filter_temp = FIELD_GET(MLX90394_CTRL3_DIG_FILT_TEMP, data->ctrl_reg_values.ctrl3);
50 	int32_t osr_temp = FIELD_GET(MLX90394_CTRL3_OSR_TEMP, data->ctrl_reg_values.ctrl3);
51 	int32_t osr_hall = FIELD_GET(MLX90394_CTRL3_OSR_HALL, data->ctrl_reg_values.ctrl3);
52 
53 	int32_t conversion_time_us =
54 		(osr_hall + 1) * ((en_x + en_y) * MLX90394_CONVERSION_TIME_US_AXIS[filter_hall_xy] +
55 				  en_z * MLX90394_CONVERSION_TIME_US_AXIS[filter_hall_z]) +
56 		(osr_temp + 1) * en_temp * MLX90394_CONVERSION_TIME_US_AXIS[filter_temp];
57 	int32_t dsp_time_us = MLX90394_DSP_TIME_US[en_temp][en_x + en_y + en_z];
58 
59 	/*
60 	 * adding 5% tolerance from datasheet
61 	 */
62 	data->measurement_time_us = (conversion_time_us + dsp_time_us) * 105 / 100;
63 }
64 
mlx90394_convert_magn(enum mlx90394_reg_config_val config,struct sensor_value * val,uint8_t sample_l,uint8_t sample_h)65 static void mlx90394_convert_magn(enum mlx90394_reg_config_val config, struct sensor_value *val,
66 				  uint8_t sample_l, uint8_t sample_h)
67 {
68 	int64_t scale, conv_val;
69 
70 	if (config == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
71 		scale = MLX90394_HIGH_SENSITIVITY_MICRO_GAUSS_PER_BIT;
72 	} else {
73 		scale = MLX90394_HIGH_RANGE_MICRO_GAUSS_PER_BIT;
74 	}
75 	conv_val = (int16_t)((uint16_t)sample_l | (uint16_t)(sample_h << 8)) * scale;
76 
77 	val->val1 = conv_val / 1000000;               /* G */
78 	val->val2 = conv_val - (val->val1 * 1000000); /* uG */
79 }
80 
mlx90394_convert_temp(struct sensor_value * val,uint8_t sample_l,uint8_t sample_h)81 static void mlx90394_convert_temp(struct sensor_value *val, uint8_t sample_l, uint8_t sample_h)
82 {
83 	int64_t conv_val = sample_l | (sample_h << 8) * MLX90394_MICRO_CELSIUS_PER_BIT;
84 
85 	val->val1 = conv_val / 1000000;                 /* C */
86 	val->val2 = (conv_val - (val->val1 * 1000000)); /* uC */
87 }
88 
89 /*
90  * The user has to take care about that the requested channel was fetched before. Else the data will
91  * be random. Magnetic Flux Density is in Gauss, Temperature in Celsius
92  */
mlx90394_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)93 static int mlx90394_channel_get(const struct device *dev, enum sensor_channel chan,
94 				struct sensor_value *val)
95 {
96 	struct mlx90394_data *data = dev->data;
97 
98 	switch (chan) {
99 	case SENSOR_CHAN_MAGN_X: {
100 		mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
101 	} break;
102 	case SENSOR_CHAN_MAGN_Y: {
103 		mlx90394_convert_magn(data->config_val, val, data->sample.y_l, data->sample.y_h);
104 	} break;
105 	case SENSOR_CHAN_MAGN_Z: {
106 		mlx90394_convert_magn(data->config_val, val, data->sample.z_l, data->sample.z_h);
107 	} break;
108 	case SENSOR_CHAN_AMBIENT_TEMP: {
109 		mlx90394_convert_temp(val, data->sample.temp_l, data->sample.temp_h);
110 	} break;
111 	case SENSOR_CHAN_MAGN_XYZ: {
112 		mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
113 		mlx90394_convert_magn(data->config_val, val + 1, data->sample.y_l,
114 				      data->sample.y_h);
115 		mlx90394_convert_magn(data->config_val, val + 2, data->sample.z_l,
116 				      data->sample.z_h);
117 	} break;
118 	case SENSOR_CHAN_ALL: {
119 		mlx90394_convert_magn(data->config_val, val, data->sample.x_l, data->sample.x_h);
120 		mlx90394_convert_magn(data->config_val, val + 1, data->sample.y_l,
121 				      data->sample.y_h);
122 		mlx90394_convert_magn(data->config_val, val + 2, data->sample.z_l,
123 				      data->sample.z_h);
124 		mlx90394_convert_temp(val + 3, data->sample.temp_l, data->sample.temp_h);
125 	} break;
126 	default: {
127 		LOG_DBG("Invalid channel %d", chan);
128 		return -ENOTSUP;
129 	}
130 	}
131 	return 0;
132 }
133 
134 /**
135  * update a register on the device and @param old_value as well
136  */
mlx90394_update_register(const struct device * dev,const uint8_t reg_addr,const uint8_t new_val,uint8_t * old_value)137 static inline int mlx90394_update_register(const struct device *dev, const uint8_t reg_addr,
138 					   const uint8_t new_val, uint8_t *old_value)
139 {
140 	const struct mlx90394_config *cfg = dev->config;
141 
142 	if (new_val != *old_value) {
143 		*old_value = new_val;
144 		return i2c_reg_write_byte_dt(&cfg->i2c, reg_addr, new_val);
145 	}
146 	return 0;
147 }
148 
mlx90394_sync_config_val(const struct device * dev)149 static inline int mlx90394_sync_config_val(const struct device *dev)
150 {
151 	struct mlx90394_data *data = dev->data;
152 	uint8_t updated_ctrl2;
153 
154 	updated_ctrl2 = MLX90394_FIELD_MOD(MLX90394_CTRL2_CONFIG, data->config_val,
155 					   data->ctrl_reg_values.ctrl2);
156 
157 	return mlx90394_update_register(dev, MLX90394_REG_CTRL2, updated_ctrl2,
158 					&data->ctrl_reg_values.ctrl2);
159 }
160 
mlx90394_fs_set(const struct device * dev,const struct sensor_value * val)161 static inline int mlx90394_fs_set(const struct device *dev, const struct sensor_value *val)
162 {
163 	struct mlx90394_data *data = dev->data;
164 
165 	/*
166 	 * in low current mode, only High Range is possible
167 	 */
168 	if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT) {
169 		LOG_ERR("different FS values only supported in low noise mode");
170 
171 		return -ENOTSUP;
172 	}
173 
174 	/* if the requested range is greater the driver switches from HIGH_SENSITIVITY to
175 	 * HIGH_RANGE
176 	 */
177 	if (val->val1 > MLX90394_ATTR_FS_LOW_G) {
178 		data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE;
179 	} else {
180 		data->config_val = MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE;
181 	}
182 
183 	return mlx90394_sync_config_val(dev);
184 }
185 
mlx90394_fs_get(const struct device * dev,struct sensor_value * val)186 static inline int mlx90394_fs_get(const struct device *dev, struct sensor_value *val)
187 {
188 	struct mlx90394_data *data = dev->data;
189 
190 	val->val2 = 0;
191 	if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE) {
192 		val->val1 = MLX90394_ATTR_FS_LOW_G;
193 	} else {
194 		val->val1 = MLX90394_ATTR_FS_HIGH_G;
195 	}
196 
197 	return 0;
198 }
199 
mlx90394_low_noise_set(const struct device * dev,struct sensor_value * val)200 static inline int mlx90394_low_noise_set(const struct device *dev, struct sensor_value *val)
201 {
202 	struct mlx90394_data *data = dev->data;
203 
204 	switch (data->config_val) {
205 	case MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT: {
206 		if (val->val1) {
207 			data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE;
208 
209 			return mlx90394_sync_config_val(dev);
210 		}
211 	} break;
212 	case MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_NOISE: {
213 		if (val->val1 == 0) {
214 			data->config_val = MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT;
215 
216 			return mlx90394_sync_config_val(dev);
217 		}
218 	} break;
219 	case MLX90394_CTRL2_CONFIG_HIGH_SENSITIVITY_LOW_NOISE: {
220 		if (val->val1 == 0) {
221 			LOG_ERR("High Sensitivity only supported in Low-Noise config, therefore "
222 				"changing now to Low-Current config is not possible");
223 
224 			return -ENOTSUP;
225 		}
226 	} break;
227 	}
228 
229 	return 0;
230 }
231 
mlx90394_low_noise_get(const struct device * dev,struct sensor_value * val)232 static inline int mlx90394_low_noise_get(const struct device *dev, struct sensor_value *val)
233 {
234 	struct mlx90394_data *data = dev->data;
235 
236 	val->val2 = 0;
237 	if (data->config_val == MLX90394_CTRL2_CONFIG_HIGH_RANGE_LOW_CURRENT) {
238 		val->val1 = 0;
239 	} else {
240 		val->val1 = 1;
241 	}
242 
243 	return 0;
244 }
245 
246 /*
247  * helper function to get/set attributes if set is 0 it will be a get, otherwise is interpreted
248  * as set
249  */
mlx90394_attr_helper(const struct device * dev,enum sensor_channel chan,unsigned int attr,struct sensor_value * val,uint8_t set)250 static int mlx90394_attr_helper(const struct device *dev, enum sensor_channel chan,
251 				unsigned int attr, struct sensor_value *val, uint8_t set)
252 {
253 	struct mlx90394_data *data = dev->data;
254 
255 	if (!data->initialized) {
256 		return -ENODEV;
257 	}
258 
259 	switch (attr) {
260 	case SENSOR_ATTR_FULL_SCALE: {
261 		if (chan != SENSOR_CHAN_MAGN_XYZ) {
262 			return -ENOTSUP;
263 		}
264 
265 		if (set) {
266 			return mlx90394_fs_set(dev, val);
267 		} else {
268 			return mlx90394_fs_get(dev, val);
269 		}
270 	} break;
271 
272 	case MLX90394_SENSOR_ATTR_MAGN_LOW_NOISE: {
273 		if (chan != SENSOR_CHAN_MAGN_XYZ) {
274 			return -ENOTSUP;
275 		}
276 
277 		if (set) {
278 			return mlx90394_low_noise_set(dev, val);
279 		} else {
280 			return mlx90394_low_noise_get(dev, val);
281 		}
282 	} break;
283 
284 	case MLX90394_SENSOR_ATTR_MAGN_FILTER_XY: {
285 		if (set) {
286 			if (val->val1 > 7 || val->val1 < 0) {
287 				return -EINVAL;
288 			}
289 
290 			return mlx90394_update_register(
291 				dev, MLX90394_REG_CTRL3,
292 				MLX90394_FIELD_MOD(MLX90394_CTRL3_DIG_FILT_HALL_XY, val->val1,
293 						   data->ctrl_reg_values.ctrl3),
294 				&data->ctrl_reg_values.ctrl3);
295 		} else {
296 			val->val1 = FIELD_GET(MLX90394_CTRL3_DIG_FILT_HALL_XY,
297 					      data->ctrl_reg_values.ctrl3);
298 			val->val2 = 0;
299 		}
300 	} break;
301 	case MLX90394_SENSOR_ATTR_MAGN_FILTER_Z: {
302 		if (set) {
303 			if (val->val1 > 7 || val->val1 < 0) {
304 
305 				return -EINVAL;
306 			}
307 
308 			return mlx90394_update_register(
309 				dev, MLX90394_REG_CTRL4,
310 				MLX90394_FIELD_MOD(MLX90394_CTRL4_DIG_FILT_HALL_Z, val->val1,
311 						   data->ctrl_reg_values.ctrl4),
312 				&data->ctrl_reg_values.ctrl4);
313 		} else {
314 			val->val1 = FIELD_GET(MLX90394_CTRL4_DIG_FILT_HALL_Z,
315 					      data->ctrl_reg_values.ctrl4);
316 			val->val2 = 0;
317 		}
318 	} break;
319 	case MLX90394_SENSOR_ATTR_MAGN_OSR: {
320 		if (set) {
321 			if (val->val1 > 1 || val->val1 < 0) {
322 
323 				return -EINVAL;
324 			}
325 
326 			return mlx90394_update_register(
327 				dev, MLX90394_REG_CTRL3,
328 				MLX90394_FIELD_MOD(MLX90394_CTRL3_OSR_HALL, val->val1,
329 						   data->ctrl_reg_values.ctrl3),
330 				&data->ctrl_reg_values.ctrl3);
331 		} else {
332 			val->val1 = FIELD_GET(MLX90394_CTRL3_OSR_HALL, data->ctrl_reg_values.ctrl3);
333 			val->val2 = 0;
334 		}
335 	} break;
336 	case MLX90394_SENSOR_ATTR_TEMP_FILTER: {
337 		if (set) {
338 			if (val->val1 > 7 || val->val1 < 0) {
339 				return -EINVAL;
340 			}
341 			return mlx90394_update_register(
342 				dev, MLX90394_REG_CTRL3,
343 				MLX90394_FIELD_MOD(MLX90394_CTRL3_DIG_FILT_TEMP, val->val1,
344 						   data->ctrl_reg_values.ctrl3),
345 				&data->ctrl_reg_values.ctrl3);
346 		} else {
347 			val->val1 = FIELD_GET(MLX90394_CTRL3_DIG_FILT_TEMP,
348 					      data->ctrl_reg_values.ctrl3);
349 			val->val2 = 0;
350 		}
351 	} break;
352 	case MLX90394_SENSOR_ATTR_TEMP_OSR: {
353 		if (set) {
354 			if (val->val1 > 1 || val->val1 < 0) {
355 				return -EINVAL;
356 			}
357 			return mlx90394_update_register(
358 				dev, MLX90394_REG_CTRL3,
359 				MLX90394_FIELD_MOD(MLX90394_CTRL3_OSR_TEMP, val->val1,
360 						   data->ctrl_reg_values.ctrl3),
361 				&data->ctrl_reg_values.ctrl3);
362 		} else {
363 			val->val1 = FIELD_GET(MLX90394_CTRL3_OSR_TEMP, data->ctrl_reg_values.ctrl3);
364 			val->val2 = 0;
365 		}
366 	} break;
367 	default: {
368 		return -ENOTSUP;
369 	}
370 	}
371 
372 	return 0;
373 }
mlx90394_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)374 static int mlx90394_attr_get(const struct device *dev, enum sensor_channel chan,
375 			     enum sensor_attribute attr, struct sensor_value *val)
376 {
377 	return mlx90394_attr_helper(dev, chan, (unsigned int)attr, val, 0);
378 }
379 
mlx90394_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)380 static int mlx90394_attr_set(const struct device *dev, enum sensor_channel chan,
381 			     enum sensor_attribute attr, const struct sensor_value *val)
382 {
383 	/*
384 	 * must be a copy because val is const
385 	 */
386 	struct sensor_value val_copy = *val;
387 	int rc;
388 
389 	rc = mlx90394_attr_helper(dev, chan, (unsigned int)attr, &val_copy, 1);
390 	if (rc == 0) {
391 		mlx90394_update_measurement_Time_us(dev->data);
392 	}
393 
394 	return rc;
395 }
396 
mlx90394_check_who_am_i(const struct i2c_dt_spec * i2c)397 static inline int mlx90394_check_who_am_i(const struct i2c_dt_spec *i2c)
398 {
399 	uint8_t buffer[2];
400 	int rc;
401 
402 	rc = i2c_burst_read_dt(i2c, MLX90394_REG_CID, buffer, ARRAY_SIZE(buffer));
403 	if (rc != 0) {
404 		LOG_ERR("Failed to read who-am-i register (rc=%d)", rc);
405 		return -EIO;
406 	}
407 
408 	if (buffer[0] != MLX90394_CID || buffer[1] != MLX90394_DID) {
409 		LOG_ERR("Wrong who-am-i value");
410 		return -EINVAL;
411 	}
412 
413 	return 0;
414 }
415 
mlx90394_write_read_dt(const struct i2c_dt_spec * i2c,uint8_t start_addr,uint8_t * buffer_write,uint8_t * buffer_read,size_t cnt)416 static int mlx90394_write_read_dt(const struct i2c_dt_spec *i2c, uint8_t start_addr,
417 				  uint8_t *buffer_write, uint8_t *buffer_read, size_t cnt)
418 {
419 	int rc;
420 
421 	rc = i2c_burst_write_dt(i2c, start_addr, buffer_write, cnt);
422 	if (rc != 0) {
423 		LOG_ERR("Failed to write %d bytes to register %d (rc=%d)", cnt, start_addr, rc);
424 		return -EIO;
425 	}
426 	rc = i2c_burst_read_dt(i2c, start_addr, buffer_read, cnt);
427 	if (rc != 0) {
428 		LOG_ERR("Failed to read %d bytes from register %d (rc=%d)", cnt, start_addr, rc);
429 		return -EIO;
430 	}
431 
432 	return 0;
433 }
434 
mlx90394_sample_fetch_internal(const struct device * dev,enum sensor_channel chan)435 int mlx90394_sample_fetch_internal(const struct device *dev, enum sensor_channel chan)
436 {
437 	const struct mlx90394_config *cfg = dev->config;
438 	struct mlx90394_data *data = dev->data;
439 	int rc;
440 
441 	if (!data->initialized) {
442 		return -ENODEV;
443 	}
444 
445 	rc = i2c_burst_read_dt(&cfg->i2c, MLX90394_REG_STAT1, (uint8_t *)&data->sample,
446 			       MLX90394_REG_TH + 1);
447 	if (rc != 0) {
448 		LOG_ERR("Failed to read bytes");
449 		return rc;
450 	}
451 
452 	if (FIELD_GET(MLX90394_STAT1_DRDY, data->sample.stat1) != 1) {
453 		LOG_ERR("Data was not ready during fetch. In continues mode consider to "
454 			"adjust "
455 			"sample frequency");
456 		return -EIO;
457 	}
458 	return 0;
459 }
460 
mlx90394_trigger_measurement_internal(const struct device * dev,enum sensor_channel chan)461 int mlx90394_trigger_measurement_internal(const struct device *dev, enum sensor_channel chan)
462 {
463 	const struct mlx90394_config *cfg = dev->config;
464 	struct mlx90394_data *data = dev->data;
465 	int rc;
466 
467 	if (!data->initialized) {
468 		return -ENODEV;
469 	}
470 
471 	/*
472 	 * set single measurement mode as default if not already done
473 	 */
474 	if (FIELD_GET(MLX90394_CTRL1_MODE, data->ctrl_reg_values.ctrl1) !=
475 	    MLX90394_CTRL1_MODE_SINGLE) {
476 		data->ctrl_reg_values.ctrl1 =
477 			MLX90394_FIELD_MOD(MLX90394_CTRL1_MODE, MLX90394_CTRL1_MODE_SINGLE,
478 					   data->ctrl_reg_values.ctrl1);
479 	}
480 
481 	/*
482 	 * change channel bits and update ctrl4 and the measurement time
483 	 * if the channel is different than during the last measurement
484 	 */
485 	if (chan != data->channel) {
486 		switch (chan) {
487 		case SENSOR_CHAN_MAGN_X: {
488 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
489 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
490 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
491 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
492 		} break;
493 		case SENSOR_CHAN_MAGN_Y: {
494 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
495 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
496 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
497 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
498 		} break;
499 		case SENSOR_CHAN_MAGN_Z: {
500 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
501 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
502 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
503 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
504 		} break;
505 		case SENSOR_CHAN_MAGN_XYZ: {
506 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
507 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
508 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
509 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 0);
510 		} break;
511 		case SENSOR_CHAN_AMBIENT_TEMP: {
512 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 0);
513 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 0);
514 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 0);
515 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 1);
516 		} break;
517 		case SENSOR_CHAN_ALL: {
518 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_X_EN_BIT, 1);
519 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Y_EN_BIT, 1);
520 			WRITE_BIT(data->ctrl_reg_values.ctrl1, MLX90394_CTRL1_Z_EN_BIT, 1);
521 			WRITE_BIT(data->ctrl_reg_values.ctrl4, MLX90394_CTRL4_T_EN_BIT, 1);
522 		} break;
523 		default: {
524 			return -ENOTSUP;
525 		}
526 		}
527 		rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_CTRL4,
528 					   data->ctrl_reg_values.ctrl4);
529 		if (rc != 0) {
530 			LOG_ERR("Failed to write ctrl4");
531 			return rc;
532 		}
533 
534 		data->channel = chan;
535 		mlx90394_update_measurement_Time_us(data);
536 	}
537 
538 	rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_CTRL1, data->ctrl_reg_values.ctrl1);
539 	if (rc != 0) {
540 		LOG_ERR("Failed to write ctrl1");
541 	}
542 
543 	return rc;
544 }
545 
mlx90394_sample_fetch(const struct device * dev,enum sensor_channel chan)546 static int mlx90394_sample_fetch(const struct device *dev, enum sensor_channel chan)
547 {
548 	int rc;
549 	struct mlx90394_data *data = dev->data;
550 
551 	rc = mlx90394_trigger_measurement_internal(dev, chan);
552 	if (rc != 0) {
553 		return rc;
554 	}
555 
556 	k_usleep(data->measurement_time_us);
557 	rc = mlx90394_sample_fetch_internal(dev, chan);
558 
559 	return rc;
560 }
561 
mlx90394_init(const struct device * dev)562 static int mlx90394_init(const struct device *dev)
563 {
564 	const struct mlx90394_config *cfg = dev->config;
565 	struct mlx90394_data *data = dev->data;
566 	int rc;
567 
568 	if (!i2c_is_ready_dt(&cfg->i2c)) {
569 		LOG_ERR("I2C bus device not ready");
570 		return -ENODEV;
571 	}
572 
573 	/*
574 	 * Soft reset the chip
575 	 */
576 	rc = i2c_reg_write_byte_dt(&cfg->i2c, MLX90394_REG_RST, MLX90394_RST);
577 	if (rc != 0) {
578 		LOG_ERR("Failed to soft reset");
579 		return -EIO;
580 	}
581 	k_usleep(MLX90394_STARTUP_TIME_US);
582 
583 	/*
584 	 * check chip ID
585 	 */
586 	rc = mlx90394_check_who_am_i(&cfg->i2c);
587 	if (rc != 0) {
588 		return rc;
589 	}
590 
591 	/*
592 	 * set all to default and read the settings back
593 	 */
594 	rc = mlx90394_write_read_dt(&cfg->i2c, MLX90394_REG_CTRL1,
595 				    (uint8_t *)&data->ctrl_reg_values.ctrl1,
596 				    (uint8_t *)&data->ctrl_reg_values.ctrl1, 2);
597 	if (rc != 0) {
598 		return rc;
599 	}
600 
601 	rc = mlx90394_write_read_dt(&cfg->i2c, MLX90394_REG_CTRL3,
602 				    (uint8_t *)&data->ctrl_reg_values.ctrl3,
603 				    (uint8_t *)&data->ctrl_reg_values.ctrl3, 2);
604 	if (rc != 0) {
605 		return rc;
606 	}
607 
608 	mlx90394_update_measurement_Time_us(data);
609 
610 #ifdef CONFIG_SENSOR_ASYNC_API
611 	data->dev = dev;
612 	/*
613 	 * init work for fetching after measurement has completed
614 	 */
615 	k_work_init_delayable(&data->async_fetch_work, mlx90394_async_fetch);
616 #endif
617 	data->initialized = true;
618 	return 0;
619 }
620 
621 static DEVICE_API(sensor, mlx90394_driver_api) = {
622 	.sample_fetch = mlx90394_sample_fetch,
623 	.channel_get = mlx90394_channel_get,
624 	.attr_get = mlx90394_attr_get,
625 	.attr_set = mlx90394_attr_set,
626 #ifdef CONFIG_SENSOR_ASYNC_API
627 	.submit = mlx90394_submit,
628 	.get_decoder = mlx90394_get_decoder,
629 #endif
630 };
631 
632 #define MLX90394_DEFINE(inst)                                                                      \
633 	static struct mlx90394_data mlx90394_data_##inst = {                                       \
634 		.sample = {.x_l = 0,                                                               \
635 			   .x_h = 0,                                                               \
636 			   .y_l = 0,                                                               \
637 			   .y_h = 0,                                                               \
638 			   .z_l = 0,                                                               \
639 			   .z_h = 0,                                                               \
640 			   .temp_l = 0,                                                            \
641 			   .temp_h = 0},                                                           \
642 		.channel = SENSOR_CHAN_MAGN_XYZ,                                                   \
643 		.config_val = FIELD_GET(MLX90394_CTRL2_CONFIG, MLX90394_CTRL2_DEFAULT),            \
644 		.measurement_time_us = 0,                                                          \
645 		.ctrl_reg_values = {.ctrl1 = MLX90394_CTRL1_DEFAULT,                               \
646 				    .ctrl2 = MLX90394_CTRL2_DEFAULT,                               \
647 				    .ctrl3 = MLX90394_CTRL3_DEFAULT,                               \
648 				    .ctrl4 = MLX90394_CTRL4_DEFAULT},                              \
649 		.initialized = false};                                                             \
650 	static const struct mlx90394_config mlx90394_config_##inst = {                             \
651 		.i2c = I2C_DT_SPEC_INST_GET(inst)};                                                \
652 	SENSOR_DEVICE_DT_INST_DEFINE(inst, mlx90394_init, NULL, &mlx90394_data_##inst,             \
653 				     &mlx90394_config_##inst, POST_KERNEL,                         \
654 				     CONFIG_SENSOR_INIT_PRIORITY, &mlx90394_driver_api);
655 
656 DT_INST_FOREACH_STATUS_OKAY(MLX90394_DEFINE)
657