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