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