| /* |
| * Copyright (c) 2023 deveritec GmbH |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT ti_tmag5273 |
| |
| #include "tmag5273.h" |
| |
| #include <stdint.h> |
| #include <stdlib.h> |
| |
| #include <zephyr/drivers/sensor/tmag5273.h> |
| #include <zephyr/dt-bindings/sensor/tmag5273.h> |
| |
| #include <zephyr/device.h> |
| #include <zephyr/kernel.h> |
| |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/drivers/i2c.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/check.h> |
| #include <zephyr/sys/crc.h> |
| #include <zephyr/sys/util.h> |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(TMAG5273, CONFIG_SENSOR_LOG_LEVEL); |
| |
| #define CONV_FACTOR_MT_TO_GS 10 |
| |
| #define TMAG5273_CRC_DATA_BYTES 4 |
| #define TMAG5273_CRC_I2C_SIZE COND_CODE_1(CONFIG_CRC, (1), (0)) |
| |
| /** |
| * @brief size of the buffer to read out all result data from the sensor |
| * |
| * Since the register counting is zero-based, one byte needs to be added to get the correct size. |
| * Also takes into account if CRC is enabled, which adds an additional byte for the CRC always |
| * located after the last read result byte. |
| */ |
| #define TMAG5273_I2C_BUFFER_SIZE \ |
| (TMAG5273_REG_RESULT_END - TMAG5273_REG_RESULT_BEGIN + 1 + TMAG5273_CRC_I2C_SIZE) |
| |
| /** static configuration data */ |
| struct tmag5273_config { |
| struct i2c_dt_spec i2c; |
| |
| uint8_t mag_channel; |
| uint8_t axis; |
| bool temperature; |
| |
| uint8_t meas_range; |
| uint8_t temperature_coefficient; |
| uint8_t angle_magnitude_axis; |
| uint8_t ch_mag_gain_correction; |
| |
| uint8_t operation_mode; |
| uint8_t averaging; |
| |
| bool trigger_conv_via_int; |
| bool low_noise_mode; |
| bool ignore_diag_fail; |
| |
| struct gpio_dt_spec int_gpio; |
| |
| #if CONFIG_CRC |
| bool crc_enabled; |
| #endif |
| }; |
| |
| struct tmag5273_data { |
| uint8_t version; /** version as given by the sensor */ |
| uint16_t conversion_time_us; /** time for one conversion */ |
| |
| int16_t x_sample; /** measured B-field @x-axis */ |
| int16_t y_sample; /** measured B-field @y-axis */ |
| int16_t z_sample; /** measured B-field @z-axis */ |
| int16_t temperature_sample; /** measured temperature data */ |
| |
| uint16_t xyz_range; /** magnetic range for x/y/z-axis in mT */ |
| |
| int16_t angle_sample; /** measured angle in degree, if activated */ |
| uint8_t magnitude_sample; /** Positive vector magnitude (can be >7 bit). */ |
| }; |
| |
| /** |
| * @brief resets the DEVICE_STATUS register |
| * |
| * @param dev driver handle |
| * @retval see @ref i2c_reg_write_byte |
| */ |
| static int tmag5273_reset_device_status(const struct device *dev) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| |
| return i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_STATUS, |
| TMAG5273_RESET_DEVICE_STATUS); |
| } |
| |
| /** |
| * @brief checks for DIAG_FAIL errors and reads out the DEVICE_STATUS register if necessary |
| * |
| * Prints a human readable representation to the log, if \c CONFIG_LOG is activated. |
| * |
| * @param drv_cfg[in] driver instance configuration |
| * @param device_status[out] DEVICE_STATUS register if DIAG_FAIL is set |
| * |
| * @retval 0 on success |
| * @retval "!= 0" on error (see @ref i2c_reg_read_byte for error codes) |
| * |
| * @note |
| * If tmag5273_config.ignore_diag_fail is se |
| * - \a device_status will be always set to \c 0, |
| * - the function always returns \c 0. |
| */ |
| static int tmag5273_check_device_status(const struct tmag5273_config *drv_cfg, |
| uint8_t *device_status) |
| { |
| int retval; |
| |
| if (drv_cfg->ignore_diag_fail) { |
| *device_status = 0; |
| return 0; |
| } |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_CONV_STATUS, device_status); |
| if (retval < 0) { |
| LOG_ERR("error reading CONV_STATUS %d", retval); |
| return retval; |
| } |
| |
| if ((*device_status & TMAG5273_DIAG_STATUS_MSK) != TMAG5273_DIAG_FAIL) { |
| /* no error */ |
| *device_status = 0; |
| return 0; |
| } |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_STATUS, device_status); |
| if (retval < 0) { |
| LOG_ERR("error reading DEVICE_STATUS %d", retval); |
| return retval; |
| } |
| |
| if ((*device_status & TMAG5273_VCC_UV_ER_MSK) == TMAG5273_VCC_UV_ERR) { |
| LOG_WRN("VCC undervoltage detected"); |
| } |
| #if CONFIG_CRC |
| if (drv_cfg->crc_enabled && |
| ((*device_status & TMAG5273_OTP_CRC_ER_MSK) == TMAG5273_OTP_CRC_ERR)) { |
| LOG_WRN("OTP CRC error detected"); |
| } |
| #endif |
| if ((*device_status & TMAG5273_INT_ER_MSK) == TMAG5273_INT_ERR) { |
| LOG_WRN("INT pin error detected"); |
| } |
| |
| if ((*device_status & TMAG5273_OSC_ER_MSK) == TMAG5273_OSC_ERR) { |
| LOG_WRN("Oscillator error detected"); |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief performs a trigger through the INT-pin |
| * |
| * @param drv_cfg driver instance configuration |
| * |
| * @retval 0 on success |
| * @retval see @ref gpio_pin_set_dt |
| */ |
| static inline int tmag5273_dev_int_trigger(const struct tmag5273_config *drv_cfg) |
| { |
| int retval; |
| |
| retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_OUTPUT); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| retval = gpio_pin_set_dt(&drv_cfg->int_gpio, 1); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| retval = gpio_pin_set_dt(&drv_cfg->int_gpio, 0); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_INPUT); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| return 0; |
| } |
| |
| /** @brief returns the high measurement range based on the chip version */ |
| static inline uint16_t tmag5273_range_high(uint8_t version) |
| { |
| return (version == TMAG5273_VER_TMAG5273X1) ? TMAG5273_MEAS_RANGE_HIGH_MT_VER1 |
| : TMAG5273_MEAS_RANGE_HIGH_MT_VER2; |
| } |
| |
| /** @brief returns the low measurement range based on the chip version */ |
| static inline uint16_t tmag5273_range_low(uint8_t version) |
| { |
| return (version == TMAG5273_VER_TMAG5273X1) ? TMAG5273_MEAS_RANGE_LOW_MT_VER1 |
| : TMAG5273_MEAS_RANGE_LOW_MT_VER2; |
| } |
| |
| /** |
| * @brief update the measurement range of the X/Y/Z-axis |
| * |
| * @param dev handle to the sensor |
| * @param val value to be set |
| * |
| * @return see @ref i2c_reg_update_byte_dt |
| */ |
| static inline int tmag5273_attr_set_xyz_meas_range(const struct device *dev, |
| const struct sensor_value *val) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| |
| const uint16_t range_high = tmag5273_range_high(drv_data->version); |
| const uint16_t range_low = tmag5273_range_low(drv_data->version); |
| |
| int retval; |
| uint8_t regdata; |
| uint16_t range; |
| |
| if (val->val1 >= range_high) { |
| regdata = TMAG5273_XYZ_MEAS_RANGE_HIGH; |
| range = range_high; |
| } else { |
| regdata = TMAG5273_XYZ_MEAS_RANGE_LOW; |
| range = range_low; |
| } |
| |
| retval = i2c_reg_update_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, |
| TMAG5273_MEAS_RANGE_XYZ_MSK, regdata); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| drv_data->xyz_range = range; |
| |
| return 0; |
| } |
| |
| /** |
| * @brief returns the used measurement range of the X/Y/Z-axis |
| * |
| * @param dev handle to the sensor |
| * @param val return value |
| * |
| * @return \c 0 on success |
| * @return see @ref i2c_reg_read_byte_dt |
| */ |
| static inline int tmag5273_attr_get_xyz_meas_range(const struct device *dev, |
| struct sensor_value *val) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| |
| uint8_t regdata; |
| int retval; |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, ®data); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| if ((regdata & TMAG5273_MEAS_RANGE_XYZ_MSK) == TMAG5273_XYZ_MEAS_RANGE_HIGH) { |
| val->val1 = tmag5273_range_high(drv_data->version); |
| } else { |
| val->val1 = tmag5273_range_low(drv_data->version); |
| } |
| |
| val->val2 = 0; |
| |
| return 0; |
| } |
| |
| /** |
| * set the X/Y/Z angle & magnitude calculation mode |
| * |
| * @param dev handle to the sensor |
| * @param val value to be set |
| * |
| * @return \c -ENOTSUP if unknown value |
| * @return see @ref i2c_reg_update_byte_dt |
| */ |
| static inline int tmag5273_attr_set_xyz_calc(const struct device *dev, |
| const struct sensor_value *val) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| uint8_t regdata; |
| int retval; |
| |
| switch (val->val1) { |
| case TMAG5273_ANGLE_CALC_NONE: |
| regdata = TMAG5273_ANGLE_EN_NONE; |
| break; |
| case TMAG5273_ANGLE_CALC_XY: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X) || |
| !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y)) { |
| return -ENOTSUP; |
| } |
| regdata = TMAG5273_ANGLE_EN_XY; |
| break; |
| case TMAG5273_ANGLE_CALC_YZ: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y) || |
| !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) { |
| return -ENOTSUP; |
| } |
| regdata = TMAG5273_ANGLE_EN_YZ; |
| break; |
| case TMAG5273_ANGLE_CALC_XZ: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X) || |
| !(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) { |
| return -ENOTSUP; |
| } |
| regdata = TMAG5273_ANGLE_EN_XZ; |
| break; |
| default: |
| LOG_ERR("unknown attribute value %d", val->val1); |
| return -ENOTSUP; |
| } |
| |
| retval = i2c_reg_update_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, |
| TMAG5273_ANGLE_EN_MSK, regdata); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * returns the X/Y/Z angle & magnitude calculation mode |
| * |
| * @param dev handle to the sensor |
| * @param val return value |
| * |
| * @return \c 0 on success |
| * @return see @ref i2c_reg_read_byte_dt |
| */ |
| static inline int tmag5273_attr_get_xyz_calc(const struct device *dev, struct sensor_value *val) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| |
| uint8_t regdata; |
| int retval; |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, ®data); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| switch (regdata & TMAG5273_ANGLE_EN_MSK) { |
| case TMAG5273_ANGLE_EN_XY: |
| val->val1 = TMAG5273_ANGLE_CALC_XY; |
| break; |
| case TMAG5273_ANGLE_EN_YZ: |
| val->val1 = TMAG5273_ANGLE_CALC_YZ; |
| break; |
| case TMAG5273_ANGLE_EN_XZ: |
| val->val1 = TMAG5273_ANGLE_CALC_XZ; |
| break; |
| case TMAG5273_ANGLE_EN_NONE: |
| __fallthrough; |
| default: |
| val->val1 = TMAG5273_ANGLE_CALC_NONE; |
| } |
| |
| val->val2 = 0; |
| |
| return 0; |
| } |
| |
| /** @brief returns the number of bytes readable per block for i2c burst reads */ |
| static inline uint8_t tmag5273_get_fetch_block_size(const struct tmag5273_config *drv_cfg, |
| uint8_t remaining_bytes) |
| { |
| #if CONFIG_CRC |
| if (drv_cfg->crc_enabled && (remaining_bytes > TMAG5273_CRC_DATA_BYTES)) { |
| return TMAG5273_CRC_DATA_BYTES; |
| } |
| #endif |
| return remaining_bytes; |
| } |
| |
| /** @brief returns the size of the CRC field if active */ |
| static inline uint8_t tmag5273_get_crc_size(const struct tmag5273_config *drv_cfg) |
| { |
| if (drv_cfg->crc_enabled) { |
| return TMAG5273_CRC_I2C_SIZE; |
| } |
| |
| return 0; |
| } |
| |
| static int tmag5273_attr_set(const struct device *dev, enum sensor_channel chan, |
| enum sensor_attribute attr, const struct sensor_value *val) |
| { |
| CHECKIF(dev == NULL) { |
| LOG_ERR("dev: NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(val == NULL) { |
| LOG_ERR("val: NULL"); |
| return -EINVAL; |
| } |
| |
| if (chan != SENSOR_CHAN_MAGN_XYZ) { |
| return -ENOTSUP; |
| } |
| |
| const struct tmag5273_config *drv_cfg = dev->config; |
| |
| int retval; |
| |
| switch ((uint16_t)attr) { |
| case SENSOR_ATTR_FULL_SCALE: |
| if (drv_cfg->meas_range != TMAG5273_DT_AXIS_RANGE_RUNTIME) { |
| return -ENOTSUP; |
| } |
| |
| retval = tmag5273_attr_set_xyz_meas_range(dev, val); |
| if (retval < 0) { |
| return retval; |
| } |
| break; |
| case TMAG5273_ATTR_ANGLE_MAG_AXIS: |
| if (drv_cfg->angle_magnitude_axis != TMAG5273_DT_ANGLE_MAG_RUNTIME) { |
| return -ENOTSUP; |
| } |
| |
| retval = tmag5273_attr_set_xyz_calc(dev, val); |
| if (retval < 0) { |
| return retval; |
| } |
| break; |
| default: |
| LOG_ERR("unknown attribute %d", attr); |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static int tmag5273_attr_get(const struct device *dev, enum sensor_channel chan, |
| enum sensor_attribute attr, struct sensor_value *val) |
| { |
| CHECKIF(dev == NULL) { |
| LOG_ERR("dev: NULL"); |
| return -EINVAL; |
| } |
| |
| CHECKIF(val == NULL) { |
| LOG_ERR("val: NULL"); |
| return -EINVAL; |
| } |
| |
| if (chan != SENSOR_CHAN_MAGN_XYZ) { |
| return -ENOTSUP; |
| } |
| |
| const struct tmag5273_config *drv_cfg = dev->config; |
| |
| int retval; |
| |
| switch ((uint16_t)attr) { |
| case SENSOR_ATTR_FULL_SCALE: |
| if (drv_cfg->meas_range != TMAG5273_DT_AXIS_RANGE_RUNTIME) { |
| return -ENOTSUP; |
| } |
| |
| retval = tmag5273_attr_get_xyz_meas_range(dev, val); |
| if (retval < 0) { |
| return retval; |
| } |
| break; |
| case TMAG5273_ATTR_ANGLE_MAG_AXIS: |
| if (drv_cfg->angle_magnitude_axis != TMAG5273_DT_ANGLE_MAG_RUNTIME) { |
| return -ENOTSUP; |
| } |
| |
| retval = tmag5273_attr_get_xyz_calc(dev, val); |
| if (retval < 0) { |
| return retval; |
| } |
| break; |
| default: |
| LOG_ERR("unknown attribute %d", attr); |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static int tmag5273_sample_fetch(const struct device *dev, enum sensor_channel chan) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| |
| int retval; |
| |
| uint8_t i2c_buffer[TMAG5273_I2C_BUFFER_SIZE] = {0}; |
| |
| /* trigger a conversion and wait until done if in standby mode */ |
| if (drv_cfg->operation_mode == TMAG5273_DT_OPER_MODE_STANDBY) { |
| if (drv_cfg->trigger_conv_via_int) { |
| retval = tmag5273_dev_int_trigger(drv_cfg); |
| if (retval < 0) { |
| return retval; |
| } |
| } |
| |
| uint8_t conv_bit = TMAG5273_CONVERSION_START_BIT; |
| |
| while ((i2c_buffer[0] & TMAG5273_RESULT_STATUS_MSK) != |
| TMAG5273_CONVERSION_COMPLETE) { |
| retval = i2c_reg_read_byte_dt( |
| &drv_cfg->i2c, TMAG5273_REG_CONV_STATUS | conv_bit, &i2c_buffer[0]); |
| |
| if (retval < 0) { |
| LOG_ERR("error reading conversion state %d", retval); |
| return retval; |
| } |
| |
| conv_bit = 0; |
| |
| k_usleep(drv_data->conversion_time_us); |
| } |
| } |
| |
| /* read data */ |
| uint8_t start_address, end_address; |
| |
| switch ((int)chan) { |
| case SENSOR_CHAN_MAGN_X: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_X)) { |
| LOG_ERR("x-axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_X_MSB_RESULT; |
| end_address = TMAG5273_REG_X_LSB_RESULT; |
| break; |
| case SENSOR_CHAN_MAGN_Y: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Y)) { |
| LOG_ERR("y-axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_Y_MSB_RESULT; |
| end_address = TMAG5273_REG_Y_LSB_RESULT; |
| break; |
| case SENSOR_CHAN_MAGN_Z: |
| if (!(drv_cfg->axis & TMAG5273_MAG_CH_EN_Z)) { |
| LOG_ERR("x-axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_Z_MSB_RESULT; |
| end_address = TMAG5273_REG_Z_LSB_RESULT; |
| break; |
| case SENSOR_CHAN_MAGN_XYZ: |
| if (drv_cfg->axis == TMAG5273_MAG_CH_EN_NONE) { |
| LOG_ERR("xyz-axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_X_MSB_RESULT; |
| end_address = TMAG5273_REG_Z_LSB_RESULT; |
| break; |
| case SENSOR_CHAN_DIE_TEMP: |
| if (!drv_cfg->temperature) { |
| LOG_ERR("temperature measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_T_MSB_RESULT; |
| end_address = TMAG5273_REG_T_LSB_RESULT; |
| break; |
| case SENSOR_CHAN_ROTATION: |
| if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) { |
| LOG_ERR("axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_ANGLE_MSB_RESULT; |
| end_address = TMAG5273_REG_ANGLE_LSB_RESULT; |
| break; |
| case TMAG5273_CHAN_MAGNITUDE: |
| case TMAG5273_CHAN_MAGNITUDE_MSB: |
| if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) { |
| LOG_ERR("axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = end_address = TMAG5273_REG_MAGNITUDE_RESULT; |
| break; |
| case TMAG5273_CHAN_ANGLE_MAGNITUDE: |
| if (drv_cfg->angle_magnitude_axis == TMAG5273_ANGLE_CALC_NONE) { |
| LOG_ERR("axis measurement deactivated"); |
| return -ENOTSUP; |
| } |
| start_address = TMAG5273_REG_ANGLE_MSB_RESULT; |
| end_address = TMAG5273_REG_MAGNITUDE_RESULT; |
| break; |
| case SENSOR_CHAN_ALL: |
| start_address = TMAG5273_REG_RESULT_BEGIN; |
| end_address = TMAG5273_REG_RESULT_END; |
| break; |
| default: |
| LOG_ERR("unknown sensor channel %d", chan); |
| return -EINVAL; |
| } |
| |
| __ASSERT_NO_MSG(start_address >= TMAG5273_REG_RESULT_BEGIN); |
| __ASSERT_NO_MSG(end_address <= TMAG5273_REG_RESULT_END); |
| __ASSERT_NO_MSG(start_address <= end_address); |
| |
| uint32_t nb_bytes = end_address - start_address + 1; |
| |
| #if CONFIG_CRC |
| /* if CRC is enabled multiples of TMAG5273_CRC_DATA_BYTES need to be read */ |
| if (drv_cfg->crc_enabled && ((nb_bytes % TMAG5273_CRC_DATA_BYTES) != 0)) { |
| const uint8_t diff = TMAG5273_CRC_DATA_BYTES - (nb_bytes % TMAG5273_CRC_DATA_BYTES); |
| |
| if ((start_address - diff) >= TMAG5273_REG_RESULT_BEGIN) { |
| start_address -= diff; |
| } |
| |
| nb_bytes = (nb_bytes / TMAG5273_CRC_DATA_BYTES + 1) * TMAG5273_CRC_DATA_BYTES; |
| } |
| |
| __ASSERT_NO_MSG((start_address + nb_bytes) <= (TMAG5273_REG_RESULT_END + 1)); |
| #endif |
| |
| uint8_t offset = start_address - TMAG5273_REG_RESULT_BEGIN; |
| const uint8_t crc_size = tmag5273_get_crc_size(drv_cfg); |
| |
| while (nb_bytes) { |
| const uint8_t block_size = tmag5273_get_fetch_block_size(drv_cfg, nb_bytes); |
| |
| __ASSERT((offset + block_size + crc_size) <= TMAG5273_I2C_BUFFER_SIZE, |
| "block_size would exceed available i2c buffer capacity"); |
| __ASSERT(start_address <= end_address, |
| "start_address for reading after end address"); |
| |
| /* Note: crc_size needs to be read additionally, since it is appended on the end */ |
| retval = i2c_burst_read_dt(&drv_cfg->i2c, start_address, &i2c_buffer[offset], |
| block_size + crc_size); |
| |
| if (retval < 0) { |
| LOG_ERR("could not read result data %d", retval); |
| return -EIO; |
| } |
| |
| #if CONFIG_CRC |
| /* check data validity, if activated */ |
| if (drv_cfg->crc_enabled) { |
| const uint8_t crc = crc8_ccitt(0xFF, &i2c_buffer[offset], block_size); |
| |
| if (i2c_buffer[offset + block_size] != crc) { |
| LOG_ERR("invalid CRC value: 0x%X (expected: 0x%X)", |
| i2c_buffer[offset + block_size], crc); |
| return -EIO; |
| } |
| } |
| #endif |
| |
| __ASSERT(nb_bytes >= block_size, "overflow on nb_bytes"); |
| |
| nb_bytes -= block_size; |
| |
| offset += block_size; |
| start_address += block_size; |
| } |
| |
| retval = tmag5273_check_device_status( |
| drv_cfg, &i2c_buffer[TMAG5273_REG_CONV_STATUS - TMAG5273_REG_RESULT_BEGIN]); |
| if (retval < 0) { |
| return retval; |
| } |
| |
| if ((i2c_buffer[TMAG5273_REG_CONV_STATUS - TMAG5273_REG_RESULT_BEGIN] & |
| TMAG5273_DIAG_STATUS_MSK) == TMAG5273_DIAG_FAIL) { |
| return -EIO; |
| } |
| |
| bool all_channels = (chan == SENSOR_CHAN_ALL); |
| bool all_xyz = all_channels || (chan == SENSOR_CHAN_MAGN_XYZ); |
| bool all_angle_magnitude = all_channels || ((int)chan == TMAG5273_CHAN_ANGLE_MAGNITUDE); |
| |
| if (all_xyz || (chan == SENSOR_CHAN_MAGN_X)) { |
| drv_data->x_sample = sys_get_be16( |
| &i2c_buffer[TMAG5273_REG_X_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]); |
| } |
| |
| if (all_xyz || (chan == SENSOR_CHAN_MAGN_Y)) { |
| drv_data->y_sample = sys_get_be16( |
| &i2c_buffer[TMAG5273_REG_Y_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]); |
| } |
| |
| if (all_xyz || (chan == SENSOR_CHAN_MAGN_Z)) { |
| drv_data->z_sample = sys_get_be16( |
| &i2c_buffer[TMAG5273_REG_Z_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]); |
| } |
| |
| if (all_channels || (chan == SENSOR_CHAN_DIE_TEMP)) { |
| drv_data->temperature_sample = sys_get_be16( |
| &i2c_buffer[TMAG5273_REG_T_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]); |
| } |
| |
| if (all_angle_magnitude || (chan == SENSOR_CHAN_ROTATION)) { |
| drv_data->angle_sample = sys_get_be16( |
| &i2c_buffer[TMAG5273_REG_ANGLE_MSB_RESULT - TMAG5273_REG_RESULT_BEGIN]); |
| } |
| if (all_angle_magnitude || ((int)chan == TMAG5273_CHAN_MAGNITUDE) || |
| ((int)chan == TMAG5273_CHAN_MAGNITUDE_MSB)) { |
| drv_data->magnitude_sample = |
| i2c_buffer[TMAG5273_REG_MAGNITUDE_RESULT - TMAG5273_REG_RESULT_BEGIN]; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief calculates the b-field value in G based on the sensor value |
| * |
| * The calculation follows the formula |
| * @f[ B=\frac{-(D_{15} \cdot 2^{15}) + \sum_{i=0}^{14} D_i \cdot 2^i}{2^{16}} \cdot 2|B_R| @f] |
| * where |
| * - \em D denotes the bit of the input data, |
| * - \em Br represents the magnetic range in mT |
| * |
| * After the calculation, the value is scaled to Gauss (1 G == 0.1 mT). |
| * |
| * @param[in] raw_value data read from the device |
| * @param[in] range magnetic range of the selected axis (in mT) |
| * @param[out] b_field holds the result data after the operation |
| */ |
| static inline void tmag5273_channel_b_field_convert(int64_t raw_value, const uint16_t range, |
| struct sensor_value *b_field) |
| { |
| raw_value *= (range << 1) * CONV_FACTOR_MT_TO_GS; |
| |
| /* calc integer part in mT and scale to G */ |
| b_field->val1 = raw_value / (1 << 16); |
| |
| /* calc remaining part (first mT digit + fractal part) and scale according to Zephyr. |
| * Ensure that always positive. |
| */ |
| const int64_t raw_dec_part = b_field->val1 * (1 << 16); |
| |
| b_field->val2 = ((raw_value - raw_dec_part) * 1000000) / (1 << 16); |
| } |
| |
| /** |
| * @brief calculates the temperature value |
| * |
| * @param[in] raw_value data read from the device |
| * @param[out] temperature holds the result data after the operation |
| */ |
| static inline void tmag5273_temperature_convert(int64_t raw_value, struct sensor_value *temperature) |
| { |
| const int64_t value = |
| (TMAG5273_TEMPERATURE_T_SENS_T0 + |
| ((raw_value - TMAG5273_TEMPERATURE_T_ADC_T0) / TMAG5273_TEMPERATURE_T_ADC_RES)) * |
| 1000000; |
| |
| temperature->val1 = value / 1000000; |
| temperature->val2 = value % 1000000; |
| } |
| |
| /** |
| * @brief calculates the angle value between two axis |
| * |
| * @param[in] raw_value data read from the device |
| * @param[out] angle holds the result data after the operation |
| */ |
| static inline void tmag5273_angle_convert(int16_t raw_value, struct sensor_value *angle) |
| { |
| angle->val1 = (raw_value >> 4) & 0x1FF; |
| angle->val2 = ((raw_value & 0xF) * 1000000) >> 1; |
| } |
| |
| /** |
| * @brief calculates the magnitude value in G between two axis |
| * |
| * Note that \c MAGNITUDE_RESULT represents the MSB of the calculation, |
| * therefore it needs to be shifted. |
| * |
| * @param[in] raw_value data read from the device |
| * @param[out] magnitude holds the result data after the operation |
| */ |
| static inline void tmag5273_magnitude_convert(uint8_t raw_value, const uint16_t range, |
| struct sensor_value *magnitude) |
| { |
| tmag5273_channel_b_field_convert(raw_value << 8, range, magnitude); |
| } |
| |
| static int tmag5273_channel_get(const struct device *dev, enum sensor_channel chan, |
| struct sensor_value *val) |
| { |
| CHECKIF(val == NULL) { |
| LOG_ERR("val: NULL"); |
| return -EINVAL; |
| } |
| |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| |
| int8_t val_offset = 0; |
| |
| const bool all_mag_axis = (chan == SENSOR_CHAN_MAGN_XYZ) || (chan == SENSOR_CHAN_ALL); |
| |
| if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_X) && |
| (all_mag_axis || (chan == SENSOR_CHAN_MAGN_X))) { |
| tmag5273_channel_b_field_convert(drv_data->x_sample, drv_data->xyz_range, |
| val + val_offset); |
| val_offset++; |
| } |
| |
| if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_Y) && |
| (all_mag_axis || (chan == SENSOR_CHAN_MAGN_Y))) { |
| tmag5273_channel_b_field_convert(drv_data->y_sample, drv_data->xyz_range, |
| val + val_offset); |
| val_offset++; |
| } |
| |
| if ((drv_cfg->axis & TMAG5273_MAG_CH_EN_Z) && |
| (all_mag_axis || (chan == SENSOR_CHAN_MAGN_Z))) { |
| tmag5273_channel_b_field_convert(drv_data->z_sample, drv_data->xyz_range, |
| val + val_offset); |
| val_offset++; |
| } |
| |
| if (drv_cfg->temperature && (chan == SENSOR_CHAN_DIE_TEMP)) { |
| tmag5273_temperature_convert(drv_data->temperature_sample, val + val_offset); |
| val_offset++; |
| } |
| |
| if (drv_cfg->angle_magnitude_axis != TMAG5273_ANGLE_CALC_NONE) { |
| const bool all_calc_ch = (TMAG5273_CHAN_ANGLE_MAGNITUDE == (uint16_t)chan); |
| |
| if (all_calc_ch || ((uint16_t)chan == SENSOR_CHAN_ROTATION)) { |
| tmag5273_angle_convert(drv_data->angle_sample, val + val_offset); |
| val_offset++; |
| } |
| |
| if (all_calc_ch || ((uint16_t)chan == TMAG5273_CHAN_MAGNITUDE)) { |
| tmag5273_magnitude_convert(drv_data->magnitude_sample, drv_data->xyz_range, |
| val + val_offset); |
| val_offset++; |
| } |
| |
| if (all_calc_ch || (uint16_t)chan == TMAG5273_CHAN_MAGNITUDE_MSB) { |
| val[val_offset].val1 = drv_data->magnitude_sample; |
| val[val_offset].val2 = 0; |
| |
| val_offset++; |
| } |
| } |
| |
| if (val_offset == 0) { |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief sets the \c DEVICE_CONFIG_1 and \c DEVICE_CONFIG_2 registers |
| * |
| * @param dev handle to the current device instance |
| * |
| * @retval 0 if everything was okay |
| * @retval -EIO on communication errors |
| */ |
| static inline int tmag5273_init_device_config(const struct device *dev) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| int retval; |
| uint8_t regdata; |
| |
| /* REG_DEVICE_CONFIG_1 */ |
| regdata = 0; |
| |
| #if CONFIG_CRC |
| if (drv_cfg->crc_enabled) { |
| regdata |= TMAG5273_CRC_ENABLE; |
| } |
| #endif |
| |
| switch (drv_cfg->temperature_coefficient) { |
| case TMAG5273_DT_TEMP_COEFF_NDBFE: |
| regdata |= TMAG5273_MAGNET_TEMP_COEFF_NDBFE; |
| break; |
| case TMAG5273_DT_TEMP_COEFF_CERAMIC: |
| regdata |= TMAG5273_MAGNET_TEMP_COEFF_CERAMIC; |
| break; |
| case TMAG5273_DT_TEMP_COEFF_NONE: |
| __fallthrough; |
| default: |
| regdata |= TMAG5273_MAGNET_TEMP_COEFF_NONE; |
| break; |
| } |
| |
| switch (drv_cfg->averaging) { |
| case TMAG5273_DT_AVERAGING_2X: |
| regdata |= TMAG5273_CONV_AVG_2; |
| break; |
| case TMAG5273_DT_AVERAGING_4X: |
| regdata |= TMAG5273_CONV_AVG_4; |
| break; |
| case TMAG5273_DT_AVERAGING_8X: |
| regdata |= TMAG5273_CONV_AVG_8; |
| break; |
| case TMAG5273_DT_AVERAGING_16X: |
| regdata |= TMAG5273_CONV_AVG_16; |
| break; |
| case TMAG5273_DT_AVERAGING_32X: |
| regdata |= TMAG5273_CONV_AVG_32; |
| break; |
| case TMAG5273_DT_AVERAGING_NONE: |
| __fallthrough; |
| default: |
| regdata |= TMAG5273_CONV_AVG_1; |
| break; |
| } |
| |
| const int nb_captured_channels = |
| ((drv_cfg->mag_channel >= TMAG5273_DT_AXIS_XYZ) |
| ? 3 |
| : POPCOUNT((drv_cfg->mag_channel & TMAG5273_DT_AXIS_XYZ))) + |
| (int)drv_cfg->temperature; |
| |
| drv_data->conversion_time_us = TMAG5273_T_CONVERSION_US( |
| (FIELD_GET(regdata, TMAG5273_CONV_AVB_MSK)), (nb_captured_channels)); |
| |
| regdata |= TMAG5273_I2C_READ_MODE_STANDARD; |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_1, regdata); |
| if (retval < 0) { |
| LOG_ERR("error setting DEVICE_CONFIG_1 %d", retval); |
| return -EIO; |
| } |
| |
| /* REG_DEVICE_CONFIG_2 */ |
| regdata = 0; |
| |
| if (drv_cfg->low_noise_mode) { |
| regdata |= TMAG5273_LP_LOWNOISE; |
| } |
| |
| if (drv_cfg->trigger_conv_via_int) { |
| regdata |= TMAG5273_TRIGGER_MODE_INT; |
| } |
| |
| if (drv_cfg->operation_mode == TMAG5273_DT_OPER_MODE_CONTINUOUS) { |
| regdata |= TMAG5273_OPERATING_MODE_CONTINUOUS; |
| } |
| |
| /* Note: I2C glitch filter enabled by default */ |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_2, regdata); |
| if (retval < 0) { |
| LOG_ERR("error setting DEVICE_CONFIG_2 %d", retval); |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief sets the \c SENSOR_CONFIG_1 and \c SENSOR_CONFIG_2 registers |
| * |
| * @param drv_cfg configuration of the TMAG5273 instance |
| * |
| * @retval 0 if everything was okay |
| * @retval -EIO on communication errors |
| */ |
| static inline int tmag5273_init_sensor_settings(const struct tmag5273_config *drv_cfg) |
| { |
| int retval; |
| uint8_t regdata; |
| |
| /* REG_SENSOR_CONFIG_1 */ |
| regdata = drv_cfg->mag_channel << TMAG5273_MAG_CH_EN_POS; |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_1, regdata); |
| if (retval < 0) { |
| LOG_ERR("error setting SENSOR_CONFIG_1 %d", retval); |
| return -EIO; |
| } |
| |
| /* REG_SENSOR_CONFIG_2 */ |
| regdata = 0; |
| |
| if (drv_cfg->ch_mag_gain_correction == TMAG5273_DT_CORRECTION_CH_2) { |
| regdata |= TMAG5273_MAG_GAIN_CORRECTION_CH_2; |
| } |
| |
| switch (drv_cfg->angle_magnitude_axis) { |
| case TMAG5273_DT_ANGLE_MAG_XY: |
| regdata |= TMAG5273_ANGLE_EN_XY; |
| break; |
| case TMAG5273_DT_ANGLE_MAG_YZ: |
| regdata |= TMAG5273_ANGLE_EN_YZ; |
| break; |
| case TMAG5273_DT_ANGLE_MAG_XZ: |
| regdata |= TMAG5273_ANGLE_EN_XZ; |
| break; |
| case TMAG5273_DT_ANGLE_MAG_RUNTIME: |
| case TMAG5273_DT_ANGLE_MAG_NONE: |
| __fallthrough; |
| default: |
| regdata |= TMAG5273_ANGLE_EN_POS; |
| break; |
| } |
| |
| if (drv_cfg->meas_range == TMAG5273_DT_AXIS_RANGE_LOW) { |
| regdata |= TMAG5273_XYZ_MEAS_RANGE_LOW; |
| } else { |
| regdata |= TMAG5273_XYZ_MEAS_RANGE_HIGH; |
| } |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_SENSOR_CONFIG_2, regdata); |
| if (retval < 0) { |
| LOG_ERR("error setting SENSOR_CONFIG_2 %d", retval); |
| return -EIO; |
| } |
| |
| /* REG_T_CONFIG */ |
| regdata = 0; |
| |
| if (drv_cfg->temperature) { |
| regdata |= TMAG5273_T_CH_EN_ENABLED; |
| } |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_T_CONFIG, regdata); |
| if (retval < 0) { |
| LOG_ERR("error setting SENSOR_CONFIG_2 %d", retval); |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * @brief initialize a TMAG5273 sensor |
| * |
| * @param dev handle to the device |
| * |
| * @retval 0 on success |
| * @retval -EINVAL if bus label is invalid |
| * @retval -EIO on communication errors |
| */ |
| static int tmag5273_init(const struct device *dev) |
| { |
| const struct tmag5273_config *drv_cfg = dev->config; |
| struct tmag5273_data *drv_data = dev->data; |
| int retval; |
| uint8_t regdata; |
| |
| if (!i2c_is_ready_dt(&drv_cfg->i2c)) { |
| LOG_ERR("could not get pointer to TMAG5273 I2C device"); |
| return -ENODEV; |
| } |
| |
| if (drv_cfg->trigger_conv_via_int) { |
| if (!gpio_is_ready_dt(&drv_cfg->int_gpio)) { |
| LOG_ERR("invalid int-gpio configuration"); |
| return -ENODEV; |
| } |
| |
| retval = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_INPUT); |
| if (retval < 0) { |
| LOG_ERR("cannot configure GPIO %d", retval); |
| return -EINVAL; |
| } |
| } |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_CONFIG_2, ®data); |
| if (retval < 0) { |
| LOG_ERR("could not read device config 2 register %d", retval); |
| return -EIO; |
| } |
| |
| LOG_DBG("operation mode: %d", (int)FIELD_GET(TMAG5273_OPERATING_MODE_MSK, regdata)); |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_MANUFACTURER_ID_LSB, ®data); |
| if (retval < 0) { |
| return -EIO; |
| } |
| |
| if (regdata != TMAG5273_MANUFACTURER_ID_LSB) { |
| LOG_ERR("unexpected manufacturer id LSB 0x%X", regdata); |
| return -EINVAL; |
| } |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_MANUFACTURER_ID_MSB, ®data); |
| if (retval < 0) { |
| LOG_ERR("could not read MSB of manufacturer id %d", retval); |
| return -EIO; |
| } |
| |
| if (regdata != TMAG5273_MANUFACTURER_ID_MSB) { |
| LOG_ERR("unexpected manufacturer id MSB 0x%X", regdata); |
| return -EINVAL; |
| } |
| |
| tmag5273_check_device_status(drv_cfg, ®data); |
| |
| retval = tmag5273_reset_device_status(dev); |
| if (retval < 0) { |
| LOG_ERR("could not reset DEVICE_STATUS register %d", retval); |
| return -EIO; |
| } |
| |
| retval = i2c_reg_read_byte_dt(&drv_cfg->i2c, TMAG5273_REG_DEVICE_ID, ®data); |
| if (retval < 0) { |
| LOG_ERR("could not read DEVICE_ID register %d", retval); |
| return -EIO; |
| } |
| |
| drv_data->version = regdata & TMAG5273_VER_MSK; |
| |
| /* magnetic measurement range based on version, apply correct one */ |
| if (drv_cfg->meas_range == TMAG5273_DT_AXIS_RANGE_LOW) { |
| drv_data->xyz_range = tmag5273_range_low(drv_data->version); |
| } else { |
| drv_data->xyz_range = tmag5273_range_high(drv_data->version); |
| } |
| |
| regdata = TMAG5273_INT_MODE_NONE; |
| |
| if (!drv_cfg->trigger_conv_via_int) { |
| regdata |= TMAG5273_INT_MASK_INTB_PIN_MASKED; |
| } |
| |
| retval = i2c_reg_write_byte_dt(&drv_cfg->i2c, TMAG5273_REG_INT_CONFIG_1, regdata); |
| if (retval < 0) { |
| LOG_ERR("error deactivating interrupts %d", retval); |
| return -EIO; |
| } |
| |
| /* set settings */ |
| retval = tmag5273_init_sensor_settings(drv_cfg); |
| if (retval < 0) { |
| LOG_ERR("error setting sensor configuration %d", retval); |
| return retval; |
| } |
| |
| retval = tmag5273_init_device_config(dev); |
| if (retval < 0) { |
| LOG_ERR("error setting device configuration %d", retval); |
| return retval; |
| } |
| |
| return 0; |
| } |
| |
| static const struct sensor_driver_api tmag5273_driver_api = { |
| .attr_set = tmag5273_attr_set, |
| .attr_get = tmag5273_attr_get, |
| .sample_fetch = tmag5273_sample_fetch, |
| .channel_get = tmag5273_channel_get, |
| }; |
| |
| #define TMAG5273_DT_X_AXIS_BIT(axis_dts) \ |
| ((((axis_dts & TMAG5273_DT_AXIS_X) == TMAG5273_DT_AXIS_X) || \ |
| (axis_dts == TMAG5273_DT_AXIS_XYX) || (axis_dts == TMAG5273_DT_AXIS_YXY) || \ |
| (axis_dts == TMAG5273_DT_AXIS_XZX)) \ |
| ? TMAG5273_MAG_CH_EN_X \ |
| : 0) |
| |
| #define TMAG5273_DT_Y_AXIS_BIT(axis_dts) \ |
| ((((axis_dts & TMAG5273_DT_AXIS_Y) == TMAG5273_DT_AXIS_Y) || \ |
| (axis_dts == TMAG5273_DT_AXIS_XYX) || (axis_dts == TMAG5273_DT_AXIS_YXY) || \ |
| (axis_dts == TMAG5273_DT_AXIS_YZY)) \ |
| ? TMAG5273_MAG_CH_EN_Y \ |
| : 0) |
| |
| #define TMAG5273_DT_Z_AXIS_BIT(axis_dts) \ |
| ((((axis_dts & TMAG5273_DT_AXIS_Z) == TMAG5273_DT_AXIS_Z) || \ |
| (axis_dts == TMAG5273_DT_AXIS_YZY) || (axis_dts == TMAG5273_DT_AXIS_XZX)) \ |
| ? TMAG5273_MAG_CH_EN_Z \ |
| : 0) |
| |
| /** Instantiation macro */ |
| #define TMAG5273_DEFINE(inst) \ |
| BUILD_ASSERT(IS_ENABLED(CONFIG_CRC) || (DT_INST_PROP(inst, crc_enabled) == 0), \ |
| "CRC support necessary"); \ |
| BUILD_ASSERT(!DT_INST_PROP(inst, trigger_conversion_via_int) || \ |
| DT_INST_NODE_HAS_PROP(inst, int_gpios), \ |
| "trigger-conversion-via-int requires int-gpios to be defined"); \ |
| static const struct tmag5273_config tmag5273_driver_cfg##inst = { \ |
| .i2c = I2C_DT_SPEC_INST_GET(inst), \ |
| .mag_channel = DT_INST_PROP(inst, axis), \ |
| .axis = (TMAG5273_DT_X_AXIS_BIT(DT_INST_PROP(inst, axis)) | \ |
| TMAG5273_DT_Y_AXIS_BIT(DT_INST_PROP(inst, axis)) | \ |
| TMAG5273_DT_Z_AXIS_BIT(DT_INST_PROP(inst, axis))), \ |
| .temperature = DT_INST_PROP(inst, temperature), \ |
| .meas_range = DT_INST_PROP(inst, range), \ |
| .temperature_coefficient = DT_INST_PROP(inst, temperature_coefficient), \ |
| .angle_magnitude_axis = DT_INST_PROP(inst, angle_magnitude_axis), \ |
| .ch_mag_gain_correction = DT_INST_PROP(inst, ch_mag_gain_correction), \ |
| .operation_mode = DT_INST_PROP(inst, operation_mode), \ |
| .averaging = DT_INST_PROP(inst, average_mode), \ |
| .trigger_conv_via_int = DT_INST_PROP(inst, trigger_conversion_via_int), \ |
| .low_noise_mode = DT_INST_PROP(inst, low_noise), \ |
| .ignore_diag_fail = DT_INST_PROP(inst, ignore_diag_fail), \ |
| .int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ |
| IF_ENABLED(CONFIG_CRC, (.crc_enabled = DT_INST_PROP(inst, crc_enabled),))}; \ |
| static struct tmag5273_data tmag5273_driver_data##inst; \ |
| SENSOR_DEVICE_DT_INST_DEFINE(inst, tmag5273_init, NULL, &tmag5273_driver_data##inst, \ |
| &tmag5273_driver_cfg##inst, POST_KERNEL, \ |
| CONFIG_SENSOR_INIT_PRIORITY, &tmag5273_driver_api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(TMAG5273_DEFINE) |