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, ®data);
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, ®data);
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, ®data);
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, ®data);
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, ®data);
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, ®data);
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, ®data);
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