1 /*
2  * Copyright (c) 2023 deveritec GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_tmag5273
8 
9 #include "tmag5273.h"
10 
11 #include <stdint.h>
12 #include <stdlib.h>
13 
14 #include <zephyr/drivers/sensor/tmag5273.h>
15 #include <zephyr/dt-bindings/sensor/tmag5273.h>
16 
17 #include <zephyr/device.h>
18 #include <zephyr/kernel.h>
19 
20 #include <zephyr/drivers/gpio.h>
21 #include <zephyr/drivers/i2c.h>
22 #include <zephyr/drivers/sensor.h>
23 #include <zephyr/sys/byteorder.h>
24 #include <zephyr/sys/check.h>
25 #include <zephyr/sys/crc.h>
26 #include <zephyr/sys/util.h>
27 
28 #include <zephyr/logging/log.h>
29 LOG_MODULE_REGISTER(TMAG5273, CONFIG_SENSOR_LOG_LEVEL);
30 
31 #define CONV_FACTOR_MT_TO_GS 10
32 
33 #define TMAG5273_CRC_DATA_BYTES 4
34 #define TMAG5273_CRC_I2C_SIZE   COND_CODE_1(CONFIG_CRC, (1), (0))
35 
36 /**
37  * @brief size of the buffer to read out all result data from the sensor
38  *
39  * Since the register counting is zero-based, one byte needs to be added to get the correct size.
40  * Also takes into account if CRC is enabled, which adds an additional byte for the CRC always
41  * located after the last read result byte.
42  */
43 #define TMAG5273_I2C_BUFFER_SIZE                                                                   \
44 	(TMAG5273_REG_RESULT_END - TMAG5273_REG_RESULT_BEGIN + 1 + TMAG5273_CRC_I2C_SIZE)
45 
46 /** static configuration data */
47 struct tmag5273_config {
48 	struct i2c_dt_spec i2c;
49 
50 	uint8_t mag_channel;
51 	uint8_t axis;
52 	bool temperature;
53 
54 	uint8_t meas_range;
55 	uint8_t temperature_coefficient;
56 	uint8_t angle_magnitude_axis;
57 	uint8_t ch_mag_gain_correction;
58 
59 	uint8_t operation_mode;
60 	uint8_t averaging;
61 
62 	bool trigger_conv_via_int;
63 	bool low_noise_mode;
64 	bool ignore_diag_fail;
65 
66 	struct gpio_dt_spec int_gpio;
67 
68 #ifdef CONFIG_CRC
69 	bool crc_enabled;
70 #endif
71 };
72 
73 struct tmag5273_data {
74 	uint8_t version;             /** version as given by the sensor */
75 	uint16_t conversion_time_us; /** time for one conversion */
76 
77 	int16_t x_sample;           /** measured B-field @x-axis */
78 	int16_t y_sample;           /** measured B-field @y-axis */
79 	int16_t z_sample;           /** measured B-field @z-axis */
80 	int16_t temperature_sample; /** measured temperature data */
81 
82 	uint16_t xyz_range; /** magnetic range for x/y/z-axis in mT */
83 
84 	int16_t angle_sample;     /** measured angle in degree, if activated */
85 	uint8_t magnitude_sample; /** Positive vector magnitude (can be >7 bit). */
86 };
87 
88 /**
89  * @brief resets the DEVICE_STATUS register
90  *
91  * @param dev driver handle
92  * @retval see @ref i2c_reg_write_byte
93  */
tmag5273_reset_device_status(const struct device * dev)94 static int tmag5273_reset_device_status(const struct device *dev)
95 {
96 	const struct tmag5273_config *drv_cfg = dev->config;
97 
98 	return i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_STATUS,
99 				     TMAG5273_RESET_DEVICE_STATUS);
100 }
101 
102 /**
103  * @brief checks for DIAG_FAIL errors and reads out the DEVICE_STATUS register if necessary
104  *
105  * @param[in] drv_cfg driver instance configuration
106  * @param[out] device_status DEVICE_STATUS register if DIAG_FAIL is set
107  *
108  * @retval 0 on success
109  * @retval "!= 0" on error
110  *                  - \c -EIO on any set error device status bit
111  *                  - see @ref i2c_reg_read_byte for error codes
112  *
113  * @note
114  * If tmag5273_config.ignore_diag_fail is set
115  *   - \a device_status will be always set to \c 0,
116  *   - the function always returns \c 0.
117  */
tmag5273_check_device_status(const struct tmag5273_config * drv_cfg,uint8_t * device_status)118 static int tmag5273_check_device_status(const struct tmag5273_config *drv_cfg,
119 					uint8_t *device_status)
120 {
121 	int retval;
122 
123 	if (drv_cfg->ignore_diag_fail) {
124 		*device_status = 0;
125 		return 0;
126 	}
127 
128 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_CONV_STATUS, device_status);
129 	if (retval < 0) {
130 		LOG_ERR("error reading CONV_STATUS %d", retval);
131 		return retval;
132 	}
133 
134 	if ((*device_status & TMAG5273_DIAG_STATUS_MSK) != TMAG5273_DIAG_FAIL) {
135 		/* no error */
136 		*device_status = 0;
137 		return 0;
138 	}
139 
140 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_STATUS, device_status);
141 	if (retval < 0) {
142 		LOG_ERR("error reading DEVICE_STATUS %d", retval);
143 		return retval;
144 	}
145 
146 	if ((*device_status & TMAG5273_VCC_UV_ER_MSK) == TMAG5273_VCC_UV_ERR) {
147 		LOG_ERR("VCC under voltage detected");
148 	}
149 #ifdef CONFIG_CRC
150 	if (drv_cfg->crc_enabled &&
151 	    ((*device_status & TMAG5273_OTP_CRC_ER_MSK) == TMAG5273_OTP_CRC_ERR)) {
152 		LOG_ERR("OTP CRC error detected");
153 	}
154 #endif
155 	if ((*device_status & TMAG5273_INT_ER_MSK) == TMAG5273_INT_ERR) {
156 		LOG_ERR("INT pin error detected");
157 	}
158 
159 	if ((*device_status & TMAG5273_OSC_ER_MSK) == TMAG5273_OSC_ERR) {
160 		LOG_ERR("Oscillator error detected");
161 	}
162 
163 	return -EIO;
164 }
165 
166 /**
167  * @brief performs a trigger through the INT-pin
168  *
169  * @param drv_cfg driver instance configuration
170  *
171  * @retval 0 on success
172  * @retval see @ref gpio_pin_set_dt
173  */
tmag5273_dev_int_trigger(const struct tmag5273_config * drv_cfg)174 static inline int tmag5273_dev_int_trigger(const struct tmag5273_config *drv_cfg)
175 {
176 	int retval;
177 
178 	retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_OUTPUT);
179 	if (retval < 0) {
180 		return retval;
181 	}
182 
183 	retval = gpio_pin_set_dt(&drv_cfg->int_gpio, 1);
184 	if (retval < 0) {
185 		return retval;
186 	}
187 
188 	retval = gpio_pin_set_dt(&drv_cfg->int_gpio, 0);
189 	if (retval < 0) {
190 		return retval;
191 	}
192 
193 	retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_INPUT);
194 	if (retval < 0) {
195 		return retval;
196 	}
197 
198 	return 0;
199 }
200 
201 /** @brief returns the high measurement range based on the chip version */
tmag5273_range_high(uint8_t version)202 static inline uint16_t tmag5273_range_high(uint8_t version)
203 {
204 	switch (version) {
205 	case TMAG5273_VER_TMAG5273X1:
206 		return TMAG5273_MEAS_RANGE_HIGH_MT_VER1;
207 	case TMAG5273_VER_TMAG5273X2:
208 		return TMAG5273_MEAS_RANGE_HIGH_MT_VER2;
209 	case TMAG5273_VER_TMAG3001X1:
210 		return TMAG3001_MEAS_RANGE_HIGH_MT_VER1;
211 	case TMAG5273_VER_TMAG3001X2:
212 		return TMAG3001_MEAS_RANGE_HIGH_MT_VER2;
213 	default:
214 		return -ENODEV;
215 	}
216 }
217 
218 /** @brief returns the low measurement range based on the chip version */
tmag5273_range_low(uint8_t version)219 static inline uint16_t tmag5273_range_low(uint8_t version)
220 {
221 	switch (version) {
222 	case TMAG5273_VER_TMAG5273X1:
223 		return TMAG5273_MEAS_RANGE_LOW_MT_VER1;
224 	case TMAG5273_VER_TMAG5273X2:
225 		return TMAG5273_MEAS_RANGE_LOW_MT_VER2;
226 	case TMAG5273_VER_TMAG3001X1:
227 		return TMAG3001_MEAS_RANGE_LOW_MT_VER1;
228 	case TMAG5273_VER_TMAG3001X2:
229 		return TMAG3001_MEAS_RANGE_LOW_MT_VER2;
230 	default:
231 		return -ENODEV;
232 	}
233 }
234 
235 /**
236  * @brief update the measurement range of the X/Y/Z-axis
237  *
238  * @param dev handle to the sensor
239  * @param val value to be set
240  *
241  * @return see @ref i2c_reg_update_byte_dt
242  */
tmag5273_attr_set_xyz_meas_range(const struct device * dev,const struct sensor_value * val)243 static inline int tmag5273_attr_set_xyz_meas_range(const struct device *dev,
244 						   const struct sensor_value *val)
245 {
246 	const struct tmag5273_config *drv_cfg = dev->config;
247 	struct tmag5273_data *drv_data = dev->data;
248 
249 	const uint16_t range_high = tmag5273_range_high(drv_data->version);
250 	const uint16_t range_low = tmag5273_range_low(drv_data->version);
251 
252 	int retval;
253 	uint8_t regdata;
254 	uint16_t range;
255 
256 	if (val->val1 >= range_high) {
257 		regdata = TMAG5273_XYZ_MEAS_RANGE_HIGH;
258 		range = range_high;
259 	} else {
260 		regdata = TMAG5273_XYZ_MEAS_RANGE_LOW;
261 		range = range_low;
262 	}
263 
264 	retval = i2c_reg_update_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2,
265 					TMAG5273_MEAS_RANGE_XYZ_MSK, regdata);
266 	if (retval < 0) {
267 		return retval;
268 	}
269 
270 	drv_data->xyz_range = range;
271 
272 	return 0;
273 }
274 
275 /**
276  * @brief returns the used measurement range of the X/Y/Z-axis
277  *
278  * @param dev handle to the sensor
279  * @param val return value
280  *
281  * @return \c 0 on success
282  * @return see @ref i2c_reg_read_byte_dt
283  */
tmag5273_attr_get_xyz_meas_range(const struct device * dev,struct sensor_value * val)284 static inline int tmag5273_attr_get_xyz_meas_range(const struct device *dev,
285 						   struct sensor_value *val)
286 {
287 	const struct tmag5273_config *drv_cfg = dev->config;
288 	struct tmag5273_data *drv_data = dev->data;
289 
290 	uint8_t regdata;
291 	int retval;
292 
293 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, &regdata);
294 	if (retval < 0) {
295 		return retval;
296 	}
297 
298 	if ((regdata & TMAG5273_MEAS_RANGE_XYZ_MSK) == TMAG5273_XYZ_MEAS_RANGE_HIGH) {
299 		val->val1 = tmag5273_range_high(drv_data->version);
300 	} else {
301 		val->val1 = tmag5273_range_low(drv_data->version);
302 	}
303 
304 	val->val2 = 0;
305 
306 	return 0;
307 }
308 
309 /**
310  * set the X/Y/Z angle & magnitude calculation mode
311  *
312  * @param dev handle to the sensor
313  * @param val value to be set
314  *
315  * @return \c -ENOTSUP if unknown value
316  * @return see @ref i2c_reg_update_byte_dt
317  */
tmag5273_attr_set_xyz_calc(const struct device * dev,const struct sensor_value * val)318 static inline int tmag5273_attr_set_xyz_calc(const struct device *dev,
319 					     const struct sensor_value *val)
320 {
321 	const struct tmag5273_config *drv_cfg = dev->config;
322 	uint8_t regdata;
323 	int retval;
324 
325 	switch (val->val1) {
326 	case TMAG5273_ANGLE_CALC_NONE:
327 		regdata = TMAG5273_ANGLE_EN_NONE;
328 		break;
329 	case TMAG5273_ANGLE_CALC_XY:
330 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X) ||
331 		    !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y)) {
332 			return -ENOTSUP;
333 		}
334 		regdata = TMAG5273_ANGLE_EN_XY;
335 		break;
336 	case TMAG5273_ANGLE_CALC_YZ:
337 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y) ||
338 		    !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) {
339 			return -ENOTSUP;
340 		}
341 		regdata = TMAG5273_ANGLE_EN_YZ;
342 		break;
343 	case TMAG5273_ANGLE_CALC_XZ:
344 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X) ||
345 		    !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) {
346 			return -ENOTSUP;
347 		}
348 		regdata = TMAG5273_ANGLE_EN_XZ;
349 		break;
350 	default:
351 		LOG_ERR("unknown attribute value %d", val->val1);
352 		return -ENOTSUP;
353 	}
354 
355 	retval = i2c_reg_update_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2,
356 					TMAG5273_ANGLE_EN_MSK, regdata);
357 	if (retval < 0) {
358 		return retval;
359 	}
360 
361 	return 0;
362 }
363 
364 /**
365  * returns the X/Y/Z angle & magnitude calculation mode
366  *
367  * @param dev handle to the sensor
368  * @param val return value
369  *
370  * @return \c 0 on success
371  * @return see @ref i2c_reg_read_byte_dt
372  */
tmag5273_attr_get_xyz_calc(const struct device * dev,struct sensor_value * val)373 static inline int tmag5273_attr_get_xyz_calc(const struct device *dev, struct sensor_value *val)
374 {
375 	const struct tmag5273_config *drv_cfg = dev->config;
376 
377 	uint8_t regdata;
378 	int retval;
379 
380 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, &regdata);
381 	if (retval < 0) {
382 		return retval;
383 	}
384 
385 	switch (regdata & TMAG5273_ANGLE_EN_MSK) {
386 	case TMAG5273_ANGLE_EN_XY:
387 		val->val1 = TMAG5273_ANGLE_CALC_XY;
388 		break;
389 	case TMAG5273_ANGLE_EN_YZ:
390 		val->val1 = TMAG5273_ANGLE_CALC_YZ;
391 		break;
392 	case TMAG5273_ANGLE_EN_XZ:
393 		val->val1 = TMAG5273_ANGLE_CALC_XZ;
394 		break;
395 	case TMAG5273_ANGLE_EN_NONE:
396 		__fallthrough;
397 	default:
398 		val->val1 = TMAG5273_ANGLE_CALC_NONE;
399 	}
400 
401 	val->val2 = 0;
402 
403 	return 0;
404 }
405 
406 /** @brief returns the number of bytes readable per block for i2c burst reads */
tmag5273_get_fetch_block_size(const struct tmag5273_config * drv_cfg,uint8_t remaining_bytes)407 static inline uint8_t tmag5273_get_fetch_block_size(const struct tmag5273_config *drv_cfg,
408 						    uint8_t remaining_bytes)
409 {
410 #ifdef CONFIG_CRC
411 	if (drv_cfg->crc_enabled && (remaining_bytes > TMAG5273_CRC_DATA_BYTES)) {
412 		return TMAG5273_CRC_DATA_BYTES;
413 	}
414 #endif
415 	return remaining_bytes;
416 }
417 
418 /** @brief returns the size of the CRC field if active */
tmag5273_get_crc_size(const struct tmag5273_config * drv_cfg)419 static inline uint8_t tmag5273_get_crc_size(const struct tmag5273_config *drv_cfg)
420 {
421 #ifdef CONFIG_CRC
422 	if (drv_cfg->crc_enabled) {
423 		return TMAG5273_CRC_I2C_SIZE;
424 	}
425 #else
426 	ARG_UNUSED(drv_cfg);
427 #endif
428 	return 0;
429 }
430 
tmag5273_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)431 static int tmag5273_attr_set(const struct device *dev, enum sensor_channel chan,
432 			     enum sensor_attribute attr, const struct sensor_value *val)
433 {
434 	CHECKIF(dev == NULL) {
435 		LOG_ERR("dev: NULL");
436 		return -EINVAL;
437 	}
438 
439 	CHECKIF(val == NULL) {
440 		LOG_ERR("val: NULL");
441 		return -EINVAL;
442 	}
443 
444 	if (chan != SENSOR_CHAN_MAGN_XYZ) {
445 		return -ENOTSUP;
446 	}
447 
448 	const struct tmag5273_config *drv_cfg = dev->config;
449 
450 	int retval;
451 
452 	switch ((uint16_t)attr) {
453 	case SENSOR_ATTR_FULL_SCALE:
454 		if (drv_cfg->meas_range != TMAG5273_DT_AXIS_RANGE_RUNTIME) {
455 			return -ENOTSUP;
456 		}
457 
458 		retval = tmag5273_attr_set_xyz_meas_range(dev, val);
459 		if (retval < 0) {
460 			return retval;
461 		}
462 		break;
463 	case TMAG5273_ATTR_ANGLE_MAG_AXIS:
464 		if (drv_cfg->angle_magnitude_axis != TMAG5273_DT_ANGLE_MAG_RUNTIME) {
465 			return -ENOTSUP;
466 		}
467 
468 		retval = tmag5273_attr_set_xyz_calc(dev, val);
469 		if (retval < 0) {
470 			return retval;
471 		}
472 		break;
473 	default:
474 		LOG_ERR("unknown attribute %d", attr);
475 		return -ENOTSUP;
476 	}
477 
478 	return 0;
479 }
480 
tmag5273_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)481 static int tmag5273_attr_get(const struct device *dev, enum sensor_channel chan,
482 			     enum sensor_attribute attr, struct sensor_value *val)
483 {
484 	CHECKIF(dev == NULL) {
485 		LOG_ERR("dev: NULL");
486 		return -EINVAL;
487 	}
488 
489 	CHECKIF(val == NULL) {
490 		LOG_ERR("val: NULL");
491 		return -EINVAL;
492 	}
493 
494 	if (chan != SENSOR_CHAN_MAGN_XYZ) {
495 		return -ENOTSUP;
496 	}
497 
498 	const struct tmag5273_config *drv_cfg = dev->config;
499 
500 	int retval;
501 
502 	switch ((uint16_t)attr) {
503 	case SENSOR_ATTR_FULL_SCALE:
504 		if (drv_cfg->meas_range != TMAG5273_DT_AXIS_RANGE_RUNTIME) {
505 			return -ENOTSUP;
506 		}
507 
508 		retval = tmag5273_attr_get_xyz_meas_range(dev, val);
509 		if (retval < 0) {
510 			return retval;
511 		}
512 		break;
513 	case TMAG5273_ATTR_ANGLE_MAG_AXIS:
514 		if (drv_cfg->angle_magnitude_axis != TMAG5273_DT_ANGLE_MAG_RUNTIME) {
515 			return -ENOTSUP;
516 		}
517 
518 		retval = tmag5273_attr_get_xyz_calc(dev, val);
519 		if (retval < 0) {
520 			return retval;
521 		}
522 		break;
523 	default:
524 		LOG_ERR("unknown attribute %d", attr);
525 		return -ENOTSUP;
526 	}
527 
528 	return 0;
529 }
530 
tmag5273_sample_fetch(const struct device * dev,enum sensor_channel chan)531 static int tmag5273_sample_fetch(const struct device *dev, enum sensor_channel chan)
532 {
533 	const struct tmag5273_config *drv_cfg = dev->config;
534 	struct tmag5273_data *drv_data = dev->data;
535 
536 	int retval;
537 
538 	uint8_t i2c_buffer[TMAG5273_I2C_BUFFER_SIZE] = {0};
539 
540 	/* trigger a conversion and wait until done if in standby mode */
541 	if (drv_cfg->operation_mode == TMAG5273_DT_OPER_MODE_STANDBY) {
542 		if (drv_cfg->trigger_conv_via_int) {
543 			retval = tmag5273_dev_int_trigger(drv_cfg);
544 			if (retval < 0) {
545 				return retval;
546 			}
547 		}
548 
549 		uint8_t conv_bit = TMAG5273_CONVERSION_START_BIT;
550 
551 		while ((i2c_buffer[0] & TMAG5273_RESULT_STATUS_MSK) !=
552 		       TMAG5273_CONVERSION_COMPLETE) {
553 			retval = i2c_reg_read_byte_dt(
554 				&drv_cfg->i2c, TMAG5273_REG_CONV_STATUS | conv_bit, &i2c_buffer[0]);
555 
556 			if (retval < 0) {
557 				LOG_ERR("error reading conversion state %d", retval);
558 				return retval;
559 			}
560 
561 			conv_bit = 0;
562 
563 			k_usleep(drv_data->conversion_time_us);
564 		}
565 	}
566 
567 	/* read data */
568 	uint8_t start_address, end_address;
569 
570 	switch ((int)chan) {
571 	case SENSOR_CHAN_MAGN_X:
572 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X)) {
573 			LOG_ERR("x-axis measurement deactivated");
574 			return -ENOTSUP;
575 		}
576 		start_address = TMAG5273_REG_X_MSB_RESULT;
577 		end_address = TMAG5273_REG_X_LSB_RESULT;
578 		break;
579 	case SENSOR_CHAN_MAGN_Y:
580 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y)) {
581 			LOG_ERR("y-axis measurement deactivated");
582 			return -ENOTSUP;
583 		}
584 		start_address = TMAG5273_REG_Y_MSB_RESULT;
585 		end_address = TMAG5273_REG_Y_LSB_RESULT;
586 		break;
587 	case SENSOR_CHAN_MAGN_Z:
588 		if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) {
589 			LOG_ERR("x-axis measurement deactivated");
590 			return -ENOTSUP;
591 		}
592 		start_address = TMAG5273_REG_Z_MSB_RESULT;
593 		end_address = TMAG5273_REG_Z_LSB_RESULT;
594 		break;
595 	case SENSOR_CHAN_MAGN_XYZ:
596 		if (drv_cfg->axis == TMAG5273_MAG_CH_EN_NONE) {
597 			LOG_ERR("xyz-axis measurement deactivated");
598 			return -ENOTSUP;
599 		}
600 		start_address = TMAG5273_REG_X_MSB_RESULT;
601 		end_address = TMAG5273_REG_Z_LSB_RESULT;
602 		break;
603 	case SENSOR_CHAN_DIE_TEMP:
604 		if (!drv_cfg->temperature) {
605 			LOG_ERR("temperature measurement deactivated");
606 			return -ENOTSUP;
607 		}
608 		start_address = TMAG5273_REG_T_MSB_RESULT;
609 		end_address = TMAG5273_REG_T_LSB_RESULT;
610 		break;
611 	case SENSOR_CHAN_ROTATION:
612 		if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) {
613 			LOG_ERR("axis measurement deactivated");
614 			return -ENOTSUP;
615 		}
616 		start_address = TMAG5273_REG_ANGLE_MSB_RESULT;
617 		end_address = TMAG5273_REG_ANGLE_LSB_RESULT;
618 		break;
619 	case TMAG5273_CHAN_MAGNITUDE:
620 	case TMAG5273_CHAN_MAGNITUDE_MSB:
621 		if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) {
622 			LOG_ERR("axis measurement deactivated");
623 			return -ENOTSUP;
624 		}
625 		start_address = end_address = TMAG5273_REG_MAGNITUDE_RESULT;
626 		break;
627 	case TMAG5273_CHAN_ANGLE_MAGNITUDE:
628 		if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) {
629 			LOG_ERR("axis measurement deactivated");
630 			return -ENOTSUP;
631 		}
632 		start_address = TMAG5273_REG_ANGLE_MSB_RESULT;
633 		end_address = TMAG5273_REG_MAGNITUDE_RESULT;
634 		break;
635 	case SENSOR_CHAN_ALL:
636 		start_address = TMAG5273_REG_RESULT_BEGIN;
637 		end_address = TMAG5273_REG_RESULT_END;
638 		break;
639 	default:
640 		LOG_ERR("unknown sensor channel %d", chan);
641 		return -EINVAL;
642 	}
643 
644 	__ASSERT_NO_MSG(start_address >= TMAG5273_REG_RESULT_BEGIN);
645 	__ASSERT_NO_MSG(end_address <= TMAG5273_REG_RESULT_END);
646 	__ASSERT_NO_MSG(start_address <= end_address);
647 
648 	uint32_t nb_bytes = end_address - start_address + 1;
649 
650 #ifdef CONFIG_CRC
651 	/* if CRC is enabled multiples of TMAG5273_CRC_DATA_BYTES need to be read */
652 	if (drv_cfg->crc_enabled && ((nb_bytes % TMAG5273_CRC_DATA_BYTES) != 0)) {
653 		const uint8_t diff = TMAG5273_CRC_DATA_BYTES - (nb_bytes % TMAG5273_CRC_DATA_BYTES);
654 
655 		if ((start_address - diff) >= TMAG5273_REG_RESULT_BEGIN) {
656 			start_address -= diff;
657 		}
658 
659 		nb_bytes = (nb_bytes / TMAG5273_CRC_DATA_BYTES + 1) * TMAG5273_CRC_DATA_BYTES;
660 	}
661 
662 	__ASSERT_NO_MSG((start_address + nb_bytes) <= (TMAG5273_REG_RESULT_END + 1));
663 #endif
664 
665 	uint8_t offset = start_address - TMAG5273_REG_RESULT_BEGIN;
666 	const uint8_t crc_size = tmag5273_get_crc_size(drv_cfg);
667 
668 	while (nb_bytes) {
669 		const uint8_t block_size = tmag5273_get_fetch_block_size(drv_cfg, nb_bytes);
670 
671 		__ASSERT((offset + block_size + crc_size) <= TMAG5273_I2C_BUFFER_SIZE,
672 			 "block_size would exceed available i2c buffer capacity");
673 		__ASSERT(start_address <= end_address,
674 			 "start_address for reading after end address");
675 
676 		/* Note: crc_size needs to be read additionally, since it is appended on the end */
677 		retval = i2c_burst_read_dt(&drv_cfg->i2c, start_address, &i2c_buffer[offset],
678 					   block_size + crc_size);
679 
680 		if (retval < 0) {
681 			LOG_ERR("could not read result data %d", retval);
682 			return -EIO;
683 		}
684 
685 #ifdef CONFIG_CRC
686 		/* check data validity, if activated */
687 		if (drv_cfg->crc_enabled) {
688 			const uint8_t crc = crc8_ccitt(0xFF, &i2c_buffer[offset], block_size);
689 
690 			if (i2c_buffer[offset + block_size] != crc) {
691 				LOG_ERR("invalid CRC value: 0x%X (expected: 0x%X)",
692 					i2c_buffer[offset + block_size], crc);
693 				return -EIO;
694 			}
695 		}
696 #endif
697 
698 		__ASSERT(nb_bytes >= block_size, "overflow on nb_bytes");
699 
700 		nb_bytes -= block_size;
701 
702 		offset += block_size;
703 		start_address += block_size;
704 	}
705 
706 	retval = tmag5273_check_device_status(
707 		drv_cfg, &i2c_buffer[TMAG5273_REG_CONV_STATUS - TMAG5273_REG_RESULT_BEGIN]);
708 	if (retval < 0) {
709 		return retval;
710 	}
711 
712 	bool all_channels = (chan == SENSOR_CHAN_ALL);
713 	bool all_xyz = all_channels || (chan == SENSOR_CHAN_MAGN_XYZ);
714 	bool all_angle_magnitude = all_channels || ((int)chan == TMAG5273_CHAN_ANGLE_MAGNITUDE);
715 
716 	if (all_xyz || (chan == SENSOR_CHAN_MAGN_X)) {
717 		drv_data->x_sample = sys_get_be16(
718 			&i2c_buffer[TMAG5273_REG_X_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]);
719 	}
720 
721 	if (all_xyz || (chan == SENSOR_CHAN_MAGN_Y)) {
722 		drv_data->y_sample = sys_get_be16(
723 			&i2c_buffer[TMAG5273_REG_Y_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]);
724 	}
725 
726 	if (all_xyz || (chan == SENSOR_CHAN_MAGN_Z)) {
727 		drv_data->z_sample = sys_get_be16(
728 			&i2c_buffer[TMAG5273_REG_Z_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]);
729 	}
730 
731 	if (all_channels || (chan == SENSOR_CHAN_DIE_TEMP)) {
732 		drv_data->temperature_sample = sys_get_be16(
733 			&i2c_buffer[TMAG5273_REG_T_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]);
734 	}
735 
736 	if (all_angle_magnitude || (chan == SENSOR_CHAN_ROTATION)) {
737 		drv_data->angle_sample = sys_get_be16(
738 			&i2c_buffer[TMAG5273_REG_ANGLE_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]);
739 	}
740 	if (all_angle_magnitude || ((int)chan == TMAG5273_CHAN_MAGNITUDE) ||
741 	    ((int)chan == TMAG5273_CHAN_MAGNITUDE_MSB)) {
742 		drv_data->magnitude_sample =
743 			i2c_buffer[TMAG5273_REG_MAGNITUDE_RESULT - TMAG5273_REG_RESULT_BEGIN];
744 	}
745 
746 	return 0;
747 }
748 
749 /**
750  * @brief calculates the b-field value in G based on the sensor value
751  *
752  * The calculation follows the formula
753  * @f[ B=\frac{-(D_{15} \cdot 2^{15}) + \sum_{i=0}^{14} D_i \cdot 2^i}{2^{16}} \cdot 2|B_R| @f]
754  * where
755  *	- \em D denotes the bit of the input data,
756  *	- \em Br represents the magnetic range in mT
757  *
758  * After the calculation, the value is scaled to Gauss (1 G == 0.1 mT).
759  *
760  * @param[in] raw_value data read from the device
761  * @param[in] range magnetic range of the selected axis (in mT)
762  * @param[out] b_field holds the result data after the operation
763  */
tmag5273_channel_b_field_convert(int64_t raw_value,const uint16_t range,struct sensor_value * b_field)764 static inline void tmag5273_channel_b_field_convert(int64_t raw_value, const uint16_t range,
765 						    struct sensor_value *b_field)
766 {
767 	raw_value *= (range << 1) * CONV_FACTOR_MT_TO_GS;
768 
769 	/* calc integer part in mT and scale to G */
770 	b_field->val1 = raw_value / (1 << 16);
771 
772 	/* calc remaining part (first mT digit + fractal part) and scale according to Zephyr.
773 	 * Ensure that always positive.
774 	 */
775 	const int64_t raw_dec_part = (int64_t)b_field->val1 * (1 << 16);
776 
777 	b_field->val2 = ((raw_value - raw_dec_part) * 1000000) / (1 << 16);
778 }
779 
780 /**
781  * @brief calculates the temperature value
782  *
783  * @param[in] raw_value data read from the device
784  * @param[out] temperature holds the result data after the operation
785  */
tmag5273_temperature_convert(int64_t raw_value,struct sensor_value * temperature)786 static inline void tmag5273_temperature_convert(int64_t raw_value, struct sensor_value *temperature)
787 {
788 	const int64_t value =
789 		(TMAG5273_TEMPERATURE_T_SENS_T0 +
790 		 ((raw_value - TMAG5273_TEMPERATURE_T_ADC_T0) / TMAG5273_TEMPERATURE_T_ADC_RES)) *
791 		1000000;
792 
793 	temperature->val1 = value / 1000000;
794 	temperature->val2 = value % 1000000;
795 }
796 
797 /**
798  * @brief calculates the angle value between two axis
799  *
800  * @param[in] raw_value data read from the device
801  * @param[out] angle holds the result data after the operation
802  */
tmag5273_angle_convert(int16_t raw_value,struct sensor_value * angle)803 static inline void tmag5273_angle_convert(int16_t raw_value, struct sensor_value *angle)
804 {
805 	angle->val1 = (raw_value >> 4) & 0x1FF;
806 	angle->val2 = ((raw_value & 0xF) * 1000000) >> 1;
807 }
808 
809 /**
810  * @brief calculates the magnitude value in G between two axis
811  *
812  * Note that \c MAGNITUDE_RESULT represents the MSB of the calculation,
813  * therefore it needs to be shifted.
814  *
815  * @param[in] raw_value data read from the device
816  * @param[out] magnitude holds the result data after the operation
817  */
tmag5273_magnitude_convert(uint8_t raw_value,const uint16_t range,struct sensor_value * magnitude)818 static inline void tmag5273_magnitude_convert(uint8_t raw_value, const uint16_t range,
819 					      struct sensor_value *magnitude)
820 {
821 	tmag5273_channel_b_field_convert(raw_value << 8, range, magnitude);
822 }
823 
tmag5273_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)824 static int tmag5273_channel_get(const struct device *dev, enum sensor_channel chan,
825 				struct sensor_value *val)
826 {
827 	CHECKIF(val == NULL) {
828 		LOG_ERR("val: NULL");
829 		return -EINVAL;
830 	}
831 
832 	const struct tmag5273_config *drv_cfg = dev->config;
833 	struct tmag5273_data *drv_data = dev->data;
834 
835 	int8_t val_offset = 0;
836 
837 	const bool all_mag_axis = (chan == SENSOR_CHAN_MAGN_XYZ) || (chan == SENSOR_CHAN_ALL);
838 
839 	if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_X) &&
840 	    (all_mag_axis || (chan == SENSOR_CHAN_MAGN_X))) {
841 		tmag5273_channel_b_field_convert(drv_data->x_sample, drv_data->xyz_range,
842 						 val + val_offset);
843 		val_offset++;
844 	}
845 
846 	if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_Y) &&
847 	    (all_mag_axis || (chan == SENSOR_CHAN_MAGN_Y))) {
848 		tmag5273_channel_b_field_convert(drv_data->y_sample, drv_data->xyz_range,
849 						 val + val_offset);
850 		val_offset++;
851 	}
852 
853 	if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_Z) &&
854 	    (all_mag_axis || (chan == SENSOR_CHAN_MAGN_Z))) {
855 		tmag5273_channel_b_field_convert(drv_data->z_sample, drv_data->xyz_range,
856 						 val + val_offset);
857 		val_offset++;
858 	}
859 
860 	if (drv_cfg->temperature && (chan == SENSOR_CHAN_DIE_TEMP)) {
861 		tmag5273_temperature_convert(drv_data->temperature_sample, val + val_offset);
862 		val_offset++;
863 	}
864 
865 	if (drv_cfg->angle_magnitude_axis != TMAG5273_ANGLE_CALC_NONE) {
866 		const bool all_calc_ch = (TMAG5273_CHAN_ANGLE_MAGNITUDE == (uint16_t)chan);
867 
868 		if (all_calc_ch || ((uint16_t)chan == SENSOR_CHAN_ROTATION)) {
869 			tmag5273_angle_convert(drv_data->angle_sample, val + val_offset);
870 			val_offset++;
871 		}
872 
873 		if (all_calc_ch || ((uint16_t)chan == TMAG5273_CHAN_MAGNITUDE)) {
874 			tmag5273_magnitude_convert(drv_data->magnitude_sample, drv_data->xyz_range,
875 						   val + val_offset);
876 			val_offset++;
877 		}
878 
879 		if (all_calc_ch || (uint16_t)chan == TMAG5273_CHAN_MAGNITUDE_MSB) {
880 			val[val_offset].val1 = drv_data->magnitude_sample;
881 			val[val_offset].val2 = 0;
882 
883 			val_offset++;
884 		}
885 	}
886 
887 	if (val_offset == 0) {
888 		return -ENOTSUP;
889 	}
890 
891 	return 0;
892 }
893 
894 /**
895  * @brief sets the \c DEVICE_CONFIG_1 and \c DEVICE_CONFIG_2 registers
896  *
897  * @param dev handle to the current device instance
898  *
899  * @retval 0 if everything was okay
900  * @retval -EIO on communication errors
901  */
tmag5273_init_device_config(const struct device * dev)902 static inline int tmag5273_init_device_config(const struct device *dev)
903 {
904 	const struct tmag5273_config *drv_cfg = dev->config;
905 	struct tmag5273_data *drv_data = dev->data;
906 	int retval;
907 	uint8_t regdata;
908 
909 	/* REG_DEVICE_CONFIG_1 */
910 	regdata = 0;
911 
912 #ifdef CONFIG_CRC
913 	if (drv_cfg->crc_enabled) {
914 		regdata |= TMAG5273_CRC_ENABLE;
915 	}
916 #endif
917 
918 	switch (drv_cfg->temperature_coefficient) {
919 	case TMAG5273_DT_TEMP_COEFF_NDBFE:
920 		regdata |= TMAG5273_MAGNET_TEMP_COEFF_NDBFE;
921 		break;
922 	case TMAG5273_DT_TEMP_COEFF_CERAMIC:
923 		regdata |= TMAG5273_MAGNET_TEMP_COEFF_CERAMIC;
924 		break;
925 	case TMAG5273_DT_TEMP_COEFF_NONE:
926 		__fallthrough;
927 	default:
928 		regdata |= TMAG5273_MAGNET_TEMP_COEFF_NONE;
929 		break;
930 	}
931 
932 	switch (drv_cfg->averaging) {
933 	case TMAG5273_DT_AVERAGING_2X:
934 		regdata |= TMAG5273_CONV_AVG_2;
935 		break;
936 	case TMAG5273_DT_AVERAGING_4X:
937 		regdata |= TMAG5273_CONV_AVG_4;
938 		break;
939 	case TMAG5273_DT_AVERAGING_8X:
940 		regdata |= TMAG5273_CONV_AVG_8;
941 		break;
942 	case TMAG5273_DT_AVERAGING_16X:
943 		regdata |= TMAG5273_CONV_AVG_16;
944 		break;
945 	case TMAG5273_DT_AVERAGING_32X:
946 		regdata |= TMAG5273_CONV_AVG_32;
947 		break;
948 	case TMAG5273_DT_AVERAGING_NONE:
949 		__fallthrough;
950 	default:
951 		regdata |= TMAG5273_CONV_AVG_1;
952 		break;
953 	}
954 
955 	const int nb_captured_channels =
956 		((drv_cfg->mag_channel >= TMAG5273_DT_AXIS_XYZ)
957 			 ? 3
958 			 : POPCOUNT((drv_cfg->mag_channel & TMAG5273_DT_AXIS_XYZ))) +
959 		(int)drv_cfg->temperature;
960 
961 	drv_data->conversion_time_us = TMAG5273_T_CONVERSION_US(
962 		(FIELD_GET(TMAG5273_CONV_AVB_MSK, regdata)), (nb_captured_channels));
963 
964 	regdata |= TMAG5273_I2C_READ_MODE_STANDARD;
965 
966 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_1, regdata);
967 	if (retval < 0) {
968 		LOG_ERR("error setting DEVICE_CONFIG_1 %d", retval);
969 		return -EIO;
970 	}
971 
972 	/* REG_DEVICE_CONFIG_2 */
973 	regdata = 0;
974 
975 	if (drv_cfg->low_noise_mode) {
976 		regdata |= TMAG5273_LP_LOWNOISE;
977 	}
978 
979 	if (drv_cfg->trigger_conv_via_int) {
980 		regdata |= TMAG5273_TRIGGER_MODE_INT;
981 	}
982 
983 	if (drv_cfg->operation_mode == TMAG5273_DT_OPER_MODE_CONTINUOUS) {
984 		regdata |= TMAG5273_OPERATING_MODE_CONTINUOUS;
985 	}
986 
987 	/* Note: I2C glitch filter enabled by default */
988 
989 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_2, regdata);
990 	if (retval < 0) {
991 		LOG_ERR("error setting DEVICE_CONFIG_2 %d", retval);
992 		return -EIO;
993 	}
994 
995 	return 0;
996 }
997 
998 /**
999  * @brief sets the \c SENSOR_CONFIG_1 and \c SENSOR_CONFIG_2 registers
1000  *
1001  * @param drv_cfg configuration of the TMAG5273 instance
1002  *
1003  * @retval 0 if everything was okay
1004  * @retval -EIO on communication errors
1005  */
tmag5273_init_sensor_settings(const struct tmag5273_config * drv_cfg,uint8_t version)1006 static inline int tmag5273_init_sensor_settings(const struct tmag5273_config *drv_cfg,
1007 						uint8_t version)
1008 {
1009 	int retval;
1010 	uint8_t regdata;
1011 
1012 	/* REG_SENSOR_CONFIG_1 */
1013 	regdata = drv_cfg->mag_channel << TMAG5273_MAG_CH_EN_POS;
1014 
1015 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_1, regdata);
1016 	if (retval < 0) {
1017 		LOG_ERR("error setting SENSOR_CONFIG_1 %d", retval);
1018 		return -EIO;
1019 	}
1020 
1021 	/* REG_SENSOR_CONFIG_2 */
1022 	regdata = 0;
1023 
1024 	if (drv_cfg->ch_mag_gain_correction == TMAG5273_DT_CORRECTION_CH_2) {
1025 		regdata |= TMAG5273_MAG_GAIN_CORRECTION_CH_2;
1026 	}
1027 
1028 	switch (drv_cfg->angle_magnitude_axis) {
1029 	case TMAG5273_DT_ANGLE_MAG_XY:
1030 		regdata |= TMAG5273_ANGLE_EN_XY;
1031 		break;
1032 	case TMAG5273_DT_ANGLE_MAG_YZ:
1033 		regdata |= TMAG5273_ANGLE_EN_YZ;
1034 		break;
1035 	case TMAG5273_DT_ANGLE_MAG_XZ:
1036 		regdata |= TMAG5273_ANGLE_EN_XZ;
1037 		break;
1038 	case TMAG5273_DT_ANGLE_MAG_RUNTIME:
1039 	case TMAG5273_DT_ANGLE_MAG_NONE:
1040 		__fallthrough;
1041 	default:
1042 		regdata |= TMAG5273_ANGLE_EN_POS;
1043 		break;
1044 	}
1045 
1046 	if (drv_cfg->meas_range == TMAG5273_DT_AXIS_RANGE_LOW) {
1047 		regdata |= TMAG5273_XYZ_MEAS_RANGE_LOW;
1048 	} else {
1049 		regdata |= TMAG5273_XYZ_MEAS_RANGE_HIGH;
1050 	}
1051 
1052 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, regdata);
1053 	if (retval < 0) {
1054 		LOG_ERR("error setting SENSOR_CONFIG_2 %d", retval);
1055 		return -EIO;
1056 	}
1057 
1058 	/* the 3001 Variant has REG_CONFIG_3 instead of REG_T_CONFIG. No need for temp enable. */
1059 	if (version == TMAG5273_VER_TMAG3001X1 || version == TMAG5273_VER_TMAG3001X2) {
1060 		return 0;
1061 	}
1062 	/* REG_T_CONFIG */
1063 	regdata = 0;
1064 
1065 	if (drv_cfg->temperature) {
1066 		regdata |= TMAG5273_T_CH_EN_ENABLED;
1067 	}
1068 
1069 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_T_CONFIG, regdata);
1070 	if (retval < 0) {
1071 		LOG_ERR("error setting SENSOR_CONFIG_2 %d", retval);
1072 		return -EIO;
1073 	}
1074 
1075 	return 0;
1076 }
1077 
1078 /**
1079  * @brief initialize a TMAG5273 sensor
1080  *
1081  * @param dev handle to the device
1082  *
1083  * @retval 0 on success
1084  * @retval -EINVAL if bus label is invalid
1085  * @retval -EIO on communication errors
1086  */
tmag5273_init(const struct device * dev)1087 static int tmag5273_init(const struct device *dev)
1088 {
1089 	const struct tmag5273_config *drv_cfg = dev->config;
1090 	struct tmag5273_data *drv_data = dev->data;
1091 	int retval;
1092 	uint8_t regdata;
1093 
1094 	if (!i2c_is_ready_dt(&drv_cfg->i2c)) {
1095 		LOG_ERR("could not get pointer to TMAG5273 I2C device");
1096 		return -ENODEV;
1097 	}
1098 
1099 	if (drv_cfg->trigger_conv_via_int) {
1100 		if (!gpio_is_ready_dt(&drv_cfg->int_gpio)) {
1101 			LOG_ERR("invalid int-gpio configuration");
1102 			return -ENODEV;
1103 		}
1104 
1105 		retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_INPUT);
1106 		if (retval < 0) {
1107 			LOG_ERR("cannot configure GPIO %d", retval);
1108 			return -EINVAL;
1109 		}
1110 	}
1111 
1112 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_2, &regdata);
1113 	if (retval < 0) {
1114 		LOG_ERR("could not read device config 2 register %d", retval);
1115 		return -EIO;
1116 	}
1117 
1118 	LOG_DBG("operation mode: %d", (int)FIELD_GET(TMAG5273_OPERATING_MODE_MSK, regdata));
1119 
1120 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_MANUFACTURER_ID_LSB, &regdata);
1121 	if (retval < 0) {
1122 		return -EIO;
1123 	}
1124 
1125 	if (regdata != TMAG5273_MANUFACTURER_ID_LSB) {
1126 		LOG_ERR("unexpected manufacturer id LSB 0x%X", regdata);
1127 		return -EINVAL;
1128 	}
1129 
1130 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_MANUFACTURER_ID_MSB, &regdata);
1131 	if (retval < 0) {
1132 		LOG_ERR("could not read MSB of manufacturer id %d", retval);
1133 		return -EIO;
1134 	}
1135 
1136 	if (regdata != TMAG5273_MANUFACTURER_ID_MSB) {
1137 		LOG_ERR("unexpected manufacturer id MSB 0x%X", regdata);
1138 		return -EINVAL;
1139 	}
1140 
1141 	(void)tmag5273_check_device_status(drv_cfg, &regdata);
1142 
1143 	retval = tmag5273_reset_device_status(dev);
1144 	if (retval < 0) {
1145 		LOG_ERR("could not reset DEVICE_STATUS register %d", retval);
1146 		return -EIO;
1147 	}
1148 
1149 	retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_ID, &regdata);
1150 	if (retval < 0) {
1151 		LOG_ERR("could not read DEVICE_ID register %d", retval);
1152 		return -EIO;
1153 	}
1154 
1155 	drv_data->version = regdata & TMAG5273_VER_MSK;
1156 
1157 	/* magnetic measurement range based on version, apply correct one */
1158 	if (drv_cfg->meas_range == TMAG5273_DT_AXIS_RANGE_LOW) {
1159 		drv_data->xyz_range = tmag5273_range_low(drv_data->version);
1160 	} else {
1161 		drv_data->xyz_range = tmag5273_range_high(drv_data->version);
1162 	}
1163 
1164 	regdata = TMAG5273_INT_MODE_NONE;
1165 
1166 	if (!drv_cfg->trigger_conv_via_int) {
1167 		regdata |= TMAG5273_INT_MASK_INTB_PIN_MASKED;
1168 	}
1169 
1170 	retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_INT_CONFIG_1, regdata);
1171 	if (retval < 0) {
1172 		LOG_ERR("error deactivating interrupts %d", retval);
1173 		return -EIO;
1174 	}
1175 
1176 	/* set settings */
1177 	retval = tmag5273_init_sensor_settings(drv_cfg, drv_data->version);
1178 	if (retval < 0) {
1179 		LOG_ERR("error setting sensor configuration %d", retval);
1180 		return retval;
1181 	}
1182 
1183 	retval = tmag5273_init_device_config(dev);
1184 	if (retval < 0) {
1185 		LOG_ERR("error setting device configuration %d", retval);
1186 		return retval;
1187 	}
1188 
1189 	return 0;
1190 }
1191 
1192 static DEVICE_API(sensor, tmag5273_driver_api) = {
1193 	.attr_set = tmag5273_attr_set,
1194 	.attr_get = tmag5273_attr_get,
1195 	.sample_fetch = tmag5273_sample_fetch,
1196 	.channel_get = tmag5273_channel_get,
1197 };
1198 
1199 #define TMAG5273_DT_X_AXIS_BIT(axis_dts)                                                           \
1200 	((((axis_dts & TMAG5273_DT_AXIS_X) == TMAG5273_DT_AXIS_X) ||                               \
1201 	  (axis_dts == TMAG5273_DT_AXIS_XYX) || (axis_dts == TMAG5273_DT_AXIS_YXY) ||              \
1202 	  (axis_dts == TMAG5273_DT_AXIS_XZX))                                                      \
1203 		 ? TMAG5273_MAG_CH_EN_X                                                            \
1204 		 : 0)
1205 
1206 #define TMAG5273_DT_Y_AXIS_BIT(axis_dts)                                                           \
1207 	((((axis_dts & TMAG5273_DT_AXIS_Y) == TMAG5273_DT_AXIS_Y) ||                               \
1208 	  (axis_dts == TMAG5273_DT_AXIS_XYX) || (axis_dts == TMAG5273_DT_AXIS_YXY) ||              \
1209 	  (axis_dts == TMAG5273_DT_AXIS_YZY))                                                      \
1210 		 ? TMAG5273_MAG_CH_EN_Y                                                            \
1211 		 : 0)
1212 
1213 #define TMAG5273_DT_Z_AXIS_BIT(axis_dts)                                                           \
1214 	((((axis_dts & TMAG5273_DT_AXIS_Z) == TMAG5273_DT_AXIS_Z) ||                               \
1215 	  (axis_dts == TMAG5273_DT_AXIS_YZY) || (axis_dts == TMAG5273_DT_AXIS_XZX))                \
1216 		 ? TMAG5273_MAG_CH_EN_Z                                                            \
1217 		 : 0)
1218 
1219 /** Instantiation macro */
1220 #define TMAG5273_DEFINE(inst)                                                                      \
1221 	BUILD_ASSERT(IS_ENABLED(CONFIG_CRC) || (DT_INST_PROP(inst, crc_enabled) == 0),             \
1222 		     "CRC support necessary");                                                     \
1223 	BUILD_ASSERT(!DT_INST_PROP(inst, trigger_conversion_via_int) ||                            \
1224 			     DT_INST_NODE_HAS_PROP(inst, int_gpios),                               \
1225 		     "trigger-conversion-via-int requires int-gpios to be defined");               \
1226 	static const struct tmag5273_config tmag5273_driver_cfg##inst = {                          \
1227 		.i2c = I2C_DT_SPEC_INST_GET(inst),                                                 \
1228 		.mag_channel = DT_INST_PROP(inst, axis),                                           \
1229 		.axis = (TMAG5273_DT_X_AXIS_BIT(DT_INST_PROP(inst, axis)) |                        \
1230 			 TMAG5273_DT_Y_AXIS_BIT(DT_INST_PROP(inst, axis)) |                        \
1231 			 TMAG5273_DT_Z_AXIS_BIT(DT_INST_PROP(inst, axis))),                        \
1232 		.temperature = DT_INST_PROP(inst, temperature),                                    \
1233 		.meas_range = DT_INST_PROP(inst, range),                                           \
1234 		.temperature_coefficient = DT_INST_PROP(inst, temperature_coefficient),            \
1235 		.angle_magnitude_axis = DT_INST_PROP(inst, angle_magnitude_axis),                  \
1236 		.ch_mag_gain_correction = DT_INST_PROP(inst, ch_mag_gain_correction),              \
1237 		.operation_mode = DT_INST_PROP(inst, operation_mode),                              \
1238 		.averaging = DT_INST_PROP(inst, average_mode),                                     \
1239 		.trigger_conv_via_int = DT_INST_PROP(inst, trigger_conversion_via_int),            \
1240 		.low_noise_mode = DT_INST_PROP(inst, low_noise),                                   \
1241 		.ignore_diag_fail = DT_INST_PROP(inst, ignore_diag_fail),                          \
1242 		.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}),                        \
1243 		IF_ENABLED(CONFIG_CRC, (.crc_enabled = DT_INST_PROP(inst, crc_enabled),))};        \
1244 	static struct tmag5273_data tmag5273_driver_data##inst;                                    \
1245 	SENSOR_DEVICE_DT_INST_DEFINE(inst, tmag5273_init, NULL, &tmag5273_driver_data##inst,       \
1246 				     &tmag5273_driver_cfg##inst, POST_KERNEL,                      \
1247 				     CONFIG_SENSOR_INIT_PRIORITY, &tmag5273_driver_api);
1248 
1249 DT_INST_FOREACH_STATUS_OKAY(TMAG5273_DEFINE)
1250