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