drivers: sensor: Add suport for TMAG5170 3D Hall sensor
Introduce support for Texas Instruments TMAG5170 high-precision linear 3D Hall-effect SPI sensor. This driver allows to configure measurements on magnetic and temperature channels. It is also possible to read rotation of the magnet. Signed-off-by: Michal Morsisko <morsisko@gmail.com>
This commit is contained in:
parent
39aa2ad719
commit
8e32b5ee0a
13 changed files with 1104 additions and 1 deletions
|
@ -135,6 +135,7 @@ add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5)
|
||||||
add_subdirectory_ifdef(CONFIG_TH02 th02)
|
add_subdirectory_ifdef(CONFIG_TH02 th02)
|
||||||
add_subdirectory_ifdef(CONFIG_TI_HDC ti_hdc)
|
add_subdirectory_ifdef(CONFIG_TI_HDC ti_hdc)
|
||||||
add_subdirectory_ifdef(CONFIG_TI_HDC20XX ti_hdc20xx)
|
add_subdirectory_ifdef(CONFIG_TI_HDC20XX ti_hdc20xx)
|
||||||
|
add_subdirectory_ifdef(CONFIG_TMAG5170 tmag5170)
|
||||||
add_subdirectory_ifdef(CONFIG_TMD2620 tmd2620)
|
add_subdirectory_ifdef(CONFIG_TMD2620 tmd2620)
|
||||||
add_subdirectory_ifdef(CONFIG_TMP007 tmp007)
|
add_subdirectory_ifdef(CONFIG_TMP007 tmp007)
|
||||||
add_subdirectory_ifdef(CONFIG_TMP108 tmp108)
|
add_subdirectory_ifdef(CONFIG_TMP108 tmp108)
|
||||||
|
|
|
@ -191,6 +191,7 @@ source "drivers/sensor/tcs3400/Kconfig"
|
||||||
source "drivers/sensor/th02/Kconfig"
|
source "drivers/sensor/th02/Kconfig"
|
||||||
source "drivers/sensor/ti_hdc/Kconfig"
|
source "drivers/sensor/ti_hdc/Kconfig"
|
||||||
source "drivers/sensor/ti_hdc20xx/Kconfig"
|
source "drivers/sensor/ti_hdc20xx/Kconfig"
|
||||||
|
source "drivers/sensor/tmag5170/Kconfig"
|
||||||
source "drivers/sensor/tmd2620/Kconfig"
|
source "drivers/sensor/tmd2620/Kconfig"
|
||||||
source "drivers/sensor/tmp007/Kconfig"
|
source "drivers/sensor/tmp007/Kconfig"
|
||||||
source "drivers/sensor/tmp108/Kconfig"
|
source "drivers/sensor/tmp108/Kconfig"
|
||||||
|
|
6
drivers/sensor/tmag5170/CMakeLists.txt
Normal file
6
drivers/sensor/tmag5170/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources(tmag5170.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_TMAG5170_TRIGGER tmag5170_trigger.c)
|
69
drivers/sensor/tmag5170/Kconfig
Normal file
69
drivers/sensor/tmag5170/Kconfig
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
# Texas Instruments TMAG5170 high-precision, linear 3D Hall-effect sensor with SPI bus interface
|
||||||
|
|
||||||
|
# Copyright (c) 2023 Michal Morsisko
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
menuconfig TMAG5170
|
||||||
|
bool "TMAG5170 SPI Hall-effect sensor driver"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_TI_TMAG5170_ENABLED
|
||||||
|
select SPI
|
||||||
|
help
|
||||||
|
Enable driver for TMAG5170 Hall-effect sensor driver
|
||||||
|
|
||||||
|
if TMAG5170
|
||||||
|
|
||||||
|
choice TMAG5170_TRIGGER_MODE
|
||||||
|
prompt "Trigger mode"
|
||||||
|
help
|
||||||
|
Specify the type of triggering to be used by the driver.
|
||||||
|
|
||||||
|
config TMAG5170_TRIGGER_NONE
|
||||||
|
bool "No trigger"
|
||||||
|
|
||||||
|
config TMAG5170_TRIGGER_GLOBAL_THREAD
|
||||||
|
bool "Use global thread"
|
||||||
|
depends on GPIO
|
||||||
|
select TMAG5170_TRIGGER
|
||||||
|
|
||||||
|
config TMAG5170_TRIGGER_OWN_THREAD
|
||||||
|
bool "Use own thread"
|
||||||
|
depends on GPIO
|
||||||
|
select TMAG5170_TRIGGER
|
||||||
|
|
||||||
|
config TMAG5170_TRIGGER_DIRECT
|
||||||
|
bool "Process trigger within interrupt context"
|
||||||
|
depends on GPIO
|
||||||
|
select TMAG5170_TRIGGER
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config TMAG5170_CRC
|
||||||
|
bool "Use CRC error detection"
|
||||||
|
default y
|
||||||
|
select CRC
|
||||||
|
help
|
||||||
|
Verify CRC of RX data and append CRC to TX data
|
||||||
|
|
||||||
|
config TMAG5170_TRIGGER
|
||||||
|
bool
|
||||||
|
|
||||||
|
if TMAG5170_TRIGGER
|
||||||
|
|
||||||
|
config TMAG5170_THREAD_PRIORITY
|
||||||
|
int "Thread priority"
|
||||||
|
depends on TMAG5170_TRIGGER_OWN_THREAD
|
||||||
|
default 10
|
||||||
|
help
|
||||||
|
Priority of thread used by the driver to handle interrupts.
|
||||||
|
|
||||||
|
config TMAG5170_THREAD_STACK_SIZE
|
||||||
|
int "Thread stack size"
|
||||||
|
depends on TMAG5170_TRIGGER_OWN_THREAD
|
||||||
|
default 1024
|
||||||
|
help
|
||||||
|
Stack size of thread used by the driver to handle interrupts.
|
||||||
|
|
||||||
|
endif # TMAG5170_TRIGGER
|
||||||
|
|
||||||
|
endif # TMAG5170
|
586
drivers/sensor/tmag5170/tmag5170.c
Normal file
586
drivers/sensor/tmag5170/tmag5170.c
Normal file
|
@ -0,0 +1,586 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Michal Morsisko
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT ti_tmag5170
|
||||||
|
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/devicetree.h>
|
||||||
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/sys/__assert.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_CRC)
|
||||||
|
#include <zephyr/sys/crc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tmag5170.h"
|
||||||
|
|
||||||
|
#define TMAG5170_REG_DEVICE_CONFIG 0x0U
|
||||||
|
#define TMAG5170_REG_SENSOR_CONFIG 0x1U
|
||||||
|
#define TMAG5170_REG_SYSTEM_CONFIG 0x2U
|
||||||
|
#define TMAG5170_REG_ALERT_CONFIG 0x3U
|
||||||
|
#define TMAG5170_REG_X_THRX_CONFIG 0x4U
|
||||||
|
#define TMAG5170_REG_Y_THRX_CONFIG 0x5U
|
||||||
|
#define TMAG5170_REG_Z_THRX_CONFIG 0x6U
|
||||||
|
#define TMAG5170_REG_T_THRX_CONFIG 0x7U
|
||||||
|
#define TMAG5170_REG_CONV_STATUS 0x8U
|
||||||
|
#define TMAG5170_REG_X_CH_RESULT 0x9U
|
||||||
|
#define TMAG5170_REG_Y_CH_RESULT 0xAU
|
||||||
|
#define TMAG5170_REG_Z_CH_RESULT 0xBU
|
||||||
|
#define TMAG5170_REG_TEMP_RESULT 0xCU
|
||||||
|
#define TMAG5170_REG_AFE_STATUS 0xDU
|
||||||
|
#define TMAG5170_REG_SYS_STATUS 0xEU
|
||||||
|
#define TMAG5170_REG_TEST_CONFIG 0xFU
|
||||||
|
#define TMAG5170_REG_OSC_MONITOR 0x10U
|
||||||
|
#define TMAG5170_REG_MAG_GAIN_CONFIG 0x11U
|
||||||
|
#define TMAG5170_REG_MAG_OFFSET_CONFIG 0x12U
|
||||||
|
#define TMAG5170_REG_ANGLE_RESULT 0x13U
|
||||||
|
#define TMAG5170_REG_MAGNITUDE_RESULT 0x14U
|
||||||
|
|
||||||
|
#define TMAG5170_CONV_AVG_POS 12U
|
||||||
|
#define TMAG5170_CONV_AVG_MASK (BIT_MASK(3U) << TMAG5170_CONV_AVG_POS)
|
||||||
|
#define TMAG5170_CONV_AVG_SET(value) (((value) << TMAG5170_CONV_AVG_POS) &\
|
||||||
|
TMAG5170_CONV_AVG_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_MAG_TEMPCO_POS 8U
|
||||||
|
#define TMAG5170_MAG_TEMPCO_MASK (BIT_MASK(2U) << TMAG5170_MAG_TEMPCO_POS)
|
||||||
|
#define TMAG5170_MAG_TEMPCO_SET(value) (((value) << TMAG5170_MAG_TEMPCO_POS) &\
|
||||||
|
TMAG5170_MAG_TEMPCO_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_OPERATING_MODE_POS 4U
|
||||||
|
#define TMAG5170_OPERATING_MODE_MASK (BIT_MASK(3U) << TMAG5170_OPERATING_MODE_POS)
|
||||||
|
#define TMAG5170_OPERATING_MODE_SET(value) (((value) << TMAG5170_OPERATING_MODE_POS) &\
|
||||||
|
TMAG5170_OPERATING_MODE_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_T_CH_EN_POS 3U
|
||||||
|
#define TMAG5170_T_CH_EN_MASK (BIT_MASK(1U) << TMAG5170_T_CH_EN_POS)
|
||||||
|
#define TMAG5170_T_CH_EN_SET(value) (((value) << TMAG5170_T_CH_EN_POS) &\
|
||||||
|
TMAG5170_T_CH_EN_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_T_RATE_POS 2U
|
||||||
|
#define TMAG5170_T_RATE_MASK (BIT_MASK(1U) << TMAG5170_T_RATE_POS)
|
||||||
|
#define TMAG5170_T_RATE_SET(value) (((value) << TMAG5170_T_RATE_POS) &\
|
||||||
|
TMAG5170_T_RATE_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_ANGLE_EN_POS 14U
|
||||||
|
#define TMAG5170_ANGLE_EN_MASK (BIT_MASK(2U) << TMAG5170_ANGLE_EN_POS)
|
||||||
|
#define TMAG5170_ANGLE_EN_SET(value) (((value) << TMAG5170_ANGLE_EN_POS) &\
|
||||||
|
TMAG5170_ANGLE_EN_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_SLEEPTIME_POS 10U
|
||||||
|
#define TMAG5170_SLEEPTIME_MASK (BIT_MASK(4U) << TMAG5170_SLEEPTIME_POS)
|
||||||
|
#define TMAG5170_SLEEPTIME_SET(value) (((value) << TMAG5170_SLEEPTIME_POS) &\
|
||||||
|
TMAG5170_SLEEPTIME_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_MAG_CH_EN_POS 6U
|
||||||
|
#define TMAG5170_MAG_CH_EN_MASK (BIT_MASK(4U) << TMAG5170_MAG_CH_EN_POS)
|
||||||
|
#define TMAG5170_MAG_CH_EN_SET(value) (((value) << TMAG5170_MAG_CH_EN_POS) &\
|
||||||
|
TMAG5170_MAG_CH_EN_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_Z_RANGE_POS 4U
|
||||||
|
#define TMAG5170_Z_RANGE_MASK (BIT_MASK(2U) << TMAG5170_Z_RANGE_POS)
|
||||||
|
#define TMAG5170_Z_RANGE_SET(value) (((value) << TMAG5170_Z_RANGE_POS) &\
|
||||||
|
TMAG5170_Z_RANGE_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_Y_RANGE_POS 2U
|
||||||
|
#define TMAG5170_Y_RANGE_MASK (BIT_MASK(2U) << TMAG5170_Y_RANGE_POS)
|
||||||
|
#define TMAG5170_Y_RANGE_SET(value) (((value) << TMAG5170_Y_RANGE_POS) &\
|
||||||
|
TMAG5170_Y_RANGE_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_X_RANGE_POS 0U
|
||||||
|
#define TMAG5170_X_RANGE_MASK (BIT_MASK(2U) << TMAG5170_X_RANGE_POS)
|
||||||
|
#define TMAG5170_X_RANGE_SET(value) (((value) << TMAG5170_X_RANGE_POS) &\
|
||||||
|
TMAG5170_X_RANGE_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_RSLT_ALRT_POS 8U
|
||||||
|
#define TMAG5170_RSLT_ALRT_MASK (BIT_MASK(1U) << TMAG5170_RSLT_ALRT_POS)
|
||||||
|
#define TMAG5170_RSLT_ALRT_SET(value) (((value) << TMAG5170_RSLT_ALRT_POS) &\
|
||||||
|
TMAG5170_RSLT_ALRT_MASK)
|
||||||
|
|
||||||
|
#define TMAG5170_VER_POS 4U
|
||||||
|
#define TMAG5170_VER_MASK (BIT_MASK(2U) << TMAG5170_VER_POS)
|
||||||
|
#define TMAG5170_VER_GET(value) (((value) & TMAG5170_VER_MASK) >> TMAG5170_VER_POS)
|
||||||
|
|
||||||
|
#define TMAG5170_A1_REV 0x0U
|
||||||
|
#define TMAG5170_A2_REV 0x1U
|
||||||
|
|
||||||
|
#define TMAG5170_MAX_RANGE_50MT_IDX 0x0U
|
||||||
|
#define TMAG5170_MAX_RANGE_25MT_IDX 0x1U
|
||||||
|
#define TMAG5170_MAX_RANGE_100MT_IDX 0x2U
|
||||||
|
#define TMAG5170_MAX_RANGE_EXTEND_FACTOR 0x3U
|
||||||
|
|
||||||
|
#define TMAG5170_CONFIGURATION_MODE 0x0U
|
||||||
|
#define TMAG5170_STAND_BY_MODE 0x1U
|
||||||
|
#define TMAG5170_ACTIVE_TRIGGER_MODE 0x3U
|
||||||
|
#define TMAG5170_SLEEP_MODE 0x5U
|
||||||
|
#define TMAG5170_DEEP_SLEEP_MODE 0x6U
|
||||||
|
|
||||||
|
#define TMAG5170_MT_TO_GAUSS_RATIO 10U
|
||||||
|
#define TMAG5170_T_SENS_T0 25U
|
||||||
|
#define TMAG5170_T_ADC_T0 17522U
|
||||||
|
#define TMAG5170_T_ADC_RES 60U
|
||||||
|
|
||||||
|
#define TMAG5170_CMD_TRIGGER_CONVERSION BIT(0U)
|
||||||
|
|
||||||
|
#define TMAG5170_CRC_SEED 0xFU
|
||||||
|
#define TMAG5170_CRC_POLY 0x3U
|
||||||
|
#define TMAG5170_SPI_BUFFER_LEN 4U
|
||||||
|
#define TMAG5170_SET_CRC(buf, crc) ((uint8_t *)(buf))[3] |= (crc & 0x0F)
|
||||||
|
#define TMAG5170_ZERO_CRC(buf) ((uint8_t *)(buf))[3] &= 0xF0
|
||||||
|
#define TMAG5170_GET_CRC(buf) ((uint8_t *)(buf))[3] & 0x0F
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(TMAG5170, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static int tmag5170_transmit_raw(const struct tmag5170_dev_config *config,
|
||||||
|
uint8_t *buffer_tx,
|
||||||
|
uint8_t *buffer_rx)
|
||||||
|
{
|
||||||
|
const struct spi_buf tx_buf = {
|
||||||
|
.buf = buffer_tx,
|
||||||
|
.len = TMAG5170_SPI_BUFFER_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct spi_buf_set tx = {
|
||||||
|
.buffers = &tx_buf,
|
||||||
|
.count = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct spi_buf rx_buf = {
|
||||||
|
.buf = buffer_rx,
|
||||||
|
.len = TMAG5170_SPI_BUFFER_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct spi_buf_set rx = {
|
||||||
|
.buffers = &rx_buf,
|
||||||
|
.count = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = spi_transceive_dt(&config->bus, &tx, &rx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_transmit(const struct device *dev, uint8_t *buffer_tx, uint8_t *buffer_rx)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_TMAG5170_CRC)
|
||||||
|
TMAG5170_ZERO_CRC(buffer_tx);
|
||||||
|
uint8_t crc = crc4_ti(TMAG5170_CRC_SEED, buffer_tx, TMAG5170_SPI_BUFFER_LEN);
|
||||||
|
|
||||||
|
TMAG5170_SET_CRC(buffer_tx, crc);
|
||||||
|
#endif
|
||||||
|
int ret = tmag5170_transmit_raw(dev->config, buffer_tx, buffer_rx);
|
||||||
|
#if defined(CONFIG_TMAG5170_CRC)
|
||||||
|
if (buffer_rx != NULL && ret == 0) {
|
||||||
|
uint8_t read_crc = TMAG5170_GET_CRC(buffer_rx);
|
||||||
|
|
||||||
|
TMAG5170_ZERO_CRC(buffer_rx);
|
||||||
|
crc = crc4_ti(TMAG5170_CRC_SEED, buffer_rx, TMAG5170_SPI_BUFFER_LEN);
|
||||||
|
if (read_crc != crc) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_write_register(const struct device *dev, uint32_t reg, uint16_t data)
|
||||||
|
{
|
||||||
|
uint8_t buffer_tx[4] = { reg, (data >> 8) & 0xFF, data & 0xFF, 0x00U };
|
||||||
|
|
||||||
|
return tmag5170_transmit(dev, buffer_tx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_read_register(const struct device *dev,
|
||||||
|
uint32_t reg,
|
||||||
|
uint16_t *output,
|
||||||
|
uint8_t cmd)
|
||||||
|
{
|
||||||
|
uint8_t buffer_tx[4] = { BIT(7) | reg, 0x00U, 0x00U, (cmd & BIT_MASK(4U)) << 4U };
|
||||||
|
uint8_t buffer_rx[4] = { 0x00U };
|
||||||
|
|
||||||
|
int ret = tmag5170_transmit(dev, buffer_tx, buffer_rx);
|
||||||
|
|
||||||
|
*output = (buffer_rx[1] << 8) | buffer_rx[2];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_convert_magn_reading_to_gauss(struct sensor_value *output,
|
||||||
|
uint16_t chan_reading,
|
||||||
|
uint8_t chan_range,
|
||||||
|
uint8_t chip_revision)
|
||||||
|
{
|
||||||
|
uint16_t max_range_mt = 0U;
|
||||||
|
|
||||||
|
if (chan_range == TMAG5170_MAX_RANGE_50MT_IDX) {
|
||||||
|
max_range_mt = 50U;
|
||||||
|
} else if (chan_range == TMAG5170_MAX_RANGE_25MT_IDX) {
|
||||||
|
max_range_mt = 25U;
|
||||||
|
} else if (chan_range == TMAG5170_MAX_RANGE_100MT_IDX) {
|
||||||
|
max_range_mt = 100U;
|
||||||
|
} else {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip_revision == TMAG5170_A2_REV) {
|
||||||
|
max_range_mt *= TMAG5170_MAX_RANGE_EXTEND_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_range_mt *= 2U;
|
||||||
|
|
||||||
|
/* The sensor returns data in mT, we need to convert it to Gauss */
|
||||||
|
uint32_t max_range_gauss = max_range_mt * TMAG5170_MT_TO_GAUSS_RATIO;
|
||||||
|
|
||||||
|
/* Convert from 2's complementary system */
|
||||||
|
int64_t result = chan_reading - ((chan_reading & 0x8000) << 1);
|
||||||
|
|
||||||
|
result *= max_range_gauss;
|
||||||
|
|
||||||
|
/* Scale to increase accuracy */
|
||||||
|
result *= 100000;
|
||||||
|
|
||||||
|
/* Divide as it is shown in datasheet */
|
||||||
|
result /= 65536;
|
||||||
|
|
||||||
|
/* Remove scale from the final result */
|
||||||
|
output->val1 = result / 100000;
|
||||||
|
output->val2 = result % 100000;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmag5170_convert_temp_reading_to_celsius(struct sensor_value *output,
|
||||||
|
uint16_t chan_reading)
|
||||||
|
{
|
||||||
|
int32_t result = chan_reading - TMAG5170_T_ADC_T0;
|
||||||
|
|
||||||
|
result = (TMAG5170_T_SENS_T0 * 100000) + (100000 * result / (int32_t)TMAG5170_T_ADC_RES);
|
||||||
|
|
||||||
|
output->val1 = result / 100000;
|
||||||
|
output->val2 = (result % 100000) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmag5170_covert_angle_reading_to_degrees(struct sensor_value *output,
|
||||||
|
uint16_t chan_reading)
|
||||||
|
{
|
||||||
|
/* 12 MSBs store the integer part of the result,
|
||||||
|
* 4 LSBs store the fractional part of the result
|
||||||
|
*/
|
||||||
|
output->val1 = chan_reading >> 4;
|
||||||
|
output->val2 = ((chan_reading & 0xF) * 1000000) / 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_sample_fetch(const struct device *dev,
|
||||||
|
enum sensor_channel chan)
|
||||||
|
{
|
||||||
|
const struct tmag5170_dev_config *cfg = dev->config;
|
||||||
|
struct tmag5170_data *drv_data = dev->data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (cfg->operating_mode == TMAG5170_STAND_BY_MODE ||
|
||||||
|
cfg->operating_mode == TMAG5170_ACTIVE_TRIGGER_MODE) {
|
||||||
|
uint16_t read_status;
|
||||||
|
|
||||||
|
tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_SYS_STATUS,
|
||||||
|
&read_status,
|
||||||
|
TMAG5170_CMD_TRIGGER_CONVERSION);
|
||||||
|
|
||||||
|
/* Wait for the measurement to be ready.
|
||||||
|
* The waiting time will vary depending on the configuration
|
||||||
|
*/
|
||||||
|
k_sleep(K_MSEC(5U));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_MAGN_X:
|
||||||
|
ret = tmag5170_read_register(dev, TMAG5170_REG_X_CH_RESULT, &drv_data->x, 0U);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_Y:
|
||||||
|
ret = tmag5170_read_register(dev, TMAG5170_REG_Y_CH_RESULT, &drv_data->y, 0U);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_Z:
|
||||||
|
ret = tmag5170_read_register(dev, TMAG5170_REG_Z_CH_RESULT, &drv_data->z, 0U);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_XYZ:
|
||||||
|
ret = tmag5170_read_register(dev, TMAG5170_REG_X_CH_RESULT, &drv_data->x, 0U);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_Y_CH_RESULT,
|
||||||
|
&drv_data->y,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_Z_CH_RESULT,
|
||||||
|
&drv_data->z,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ROTATION:
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_ANGLE_RESULT,
|
||||||
|
&drv_data->angle,
|
||||||
|
0U);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_TEMP_RESULT,
|
||||||
|
&drv_data->temperature,
|
||||||
|
0U);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ALL:
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_TEMP_RESULT,
|
||||||
|
&drv_data->temperature,
|
||||||
|
0U);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_ANGLE_RESULT,
|
||||||
|
&drv_data->angle,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_X_CH_RESULT,
|
||||||
|
&drv_data->x,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_Y_CH_RESULT,
|
||||||
|
&drv_data->y,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev,
|
||||||
|
TMAG5170_REG_Z_CH_RESULT,
|
||||||
|
&drv_data->z,
|
||||||
|
0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_channel_get(const struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
const struct tmag5170_dev_config *cfg = dev->config;
|
||||||
|
struct tmag5170_data *drv_data = dev->data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_MAGN_XYZ:
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val,
|
||||||
|
drv_data->x,
|
||||||
|
cfg->x_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val + 1,
|
||||||
|
drv_data->y,
|
||||||
|
cfg->y_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val + 2,
|
||||||
|
drv_data->z,
|
||||||
|
cfg->z_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_X:
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val,
|
||||||
|
drv_data->x,
|
||||||
|
cfg->x_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_Y:
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val,
|
||||||
|
drv_data->y,
|
||||||
|
cfg->y_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_MAGN_Z:
|
||||||
|
ret = tmag5170_convert_magn_reading_to_gauss(val,
|
||||||
|
drv_data->z,
|
||||||
|
cfg->z_range,
|
||||||
|
drv_data->chip_revision);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ROTATION:
|
||||||
|
tmag5170_covert_angle_reading_to_degrees(val, drv_data->angle);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||||
|
tmag5170_convert_temp_reading_to_celsius(val, drv_data->temperature);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmag5170_init_registers(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct tmag5170_dev_config *cfg = dev->config;
|
||||||
|
struct tmag5170_data *drv_data = dev->data;
|
||||||
|
uint16_t test_cfg_reg = 0U;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
#if !defined(CONFIG_TMAG5170_CRC)
|
||||||
|
const uint8_t disable_crc_packet[4] = { 0x0FU, 0x0U, 0x04U, 0x07U };
|
||||||
|
|
||||||
|
ret = tmag5170_transmit_raw(cfg, disable_crc_packet, NULL);
|
||||||
|
#endif
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_read_register(dev, TMAG5170_REG_TEST_CONFIG, &test_cfg_reg, 0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
drv_data->chip_revision = TMAG5170_VER_GET(test_cfg_reg);
|
||||||
|
|
||||||
|
ret = tmag5170_write_register(dev,
|
||||||
|
TMAG5170_REG_SENSOR_CONFIG,
|
||||||
|
TMAG5170_ANGLE_EN_SET(cfg->angle_measurement) |
|
||||||
|
TMAG5170_SLEEPTIME_SET(cfg->sleep_time) |
|
||||||
|
TMAG5170_MAG_CH_EN_SET(cfg->magnetic_channels) |
|
||||||
|
TMAG5170_Z_RANGE_SET(cfg->z_range) |
|
||||||
|
TMAG5170_Y_RANGE_SET(cfg->y_range) |
|
||||||
|
TMAG5170_X_RANGE_SET(cfg->x_range));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_write_register(dev,
|
||||||
|
TMAG5170_REG_ALERT_CONFIG,
|
||||||
|
TMAG5170_RSLT_ALRT_SET(1U));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = tmag5170_write_register(dev,
|
||||||
|
TMAG5170_REG_DEVICE_CONFIG,
|
||||||
|
TMAG5170_OPERATING_MODE_SET(cfg->operating_mode) |
|
||||||
|
TMAG5170_CONV_AVG_SET(cfg->oversampling) |
|
||||||
|
TMAG5170_MAG_TEMPCO_SET(cfg->magnet_type) |
|
||||||
|
TMAG5170_T_CH_EN_SET(cfg->tempeature_measurement) |
|
||||||
|
TMAG5170_T_RATE_SET(cfg->disable_temperature_oversampling));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_DEVICE
|
||||||
|
static int tmag5170_pm_action(const struct device *dev,
|
||||||
|
enum pm_device_action action)
|
||||||
|
{
|
||||||
|
int ret_val = 0;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case PM_DEVICE_ACTION_RESUME:
|
||||||
|
tmag5170_write_register(dev,
|
||||||
|
TMAG5170_REG_DEVICE_CONFIG,
|
||||||
|
TMAG5170_OPERATING_MODE_SET(TMAG5170_CONFIGURATION_MODE));
|
||||||
|
/* As per datasheet, waking up from deep-sleep can take up to 500us */
|
||||||
|
k_sleep(K_USEC(500));
|
||||||
|
ret_val = tmag5170_init_registers(dev);
|
||||||
|
break;
|
||||||
|
case PM_DEVICE_ACTION_SUSPEND:
|
||||||
|
ret_val = tmag5170_write_register(dev,
|
||||||
|
TMAG5170_REG_DEVICE_CONFIG,
|
||||||
|
TMAG5170_OPERATING_MODE_SET(TMAG5170_DEEP_SLEEP_MODE));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM_DEVICE */
|
||||||
|
|
||||||
|
static const struct sensor_driver_api tmag5170_driver_api = {
|
||||||
|
.sample_fetch = tmag5170_sample_fetch,
|
||||||
|
.channel_get = tmag5170_channel_get,
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
.trigger_set = tmag5170_trigger_set
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tmag5170_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct tmag5170_dev_config *cfg = dev->config;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!spi_is_ready_dt(&cfg->bus)) {
|
||||||
|
LOG_ERR("SPI dev %s not ready", cfg->bus.bus->name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tmag5170_init_registers(dev);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
if (cfg->int_gpio.port) {
|
||||||
|
ret = tmag5170_trigger_init(dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_TMAG5170(_num) \
|
||||||
|
static struct tmag5170_data tmag5170_data_##_num; \
|
||||||
|
static const struct tmag5170_dev_config tmag5170_config_##_num = { \
|
||||||
|
.bus = SPI_DT_SPEC_INST_GET(_num, \
|
||||||
|
SPI_OP_MODE_MASTER | \
|
||||||
|
SPI_TRANSFER_MSB | \
|
||||||
|
SPI_WORD_SET(32), \
|
||||||
|
0), \
|
||||||
|
.magnetic_channels = DT_INST_ENUM_IDX(_num, magnetic_channels), \
|
||||||
|
.x_range = DT_INST_ENUM_IDX(_num, x_range), \
|
||||||
|
.y_range = DT_INST_ENUM_IDX(_num, y_range), \
|
||||||
|
.z_range = DT_INST_ENUM_IDX(_num, z_range), \
|
||||||
|
.operating_mode = DT_INST_PROP(_num, operating_mode), \
|
||||||
|
.oversampling = DT_INST_ENUM_IDX(_num, oversampling), \
|
||||||
|
.tempeature_measurement = DT_INST_PROP(_num, enable_temperature_channel), \
|
||||||
|
.magnet_type = DT_INST_ENUM_IDX(_num, magnet_type), \
|
||||||
|
.angle_measurement = DT_INST_ENUM_IDX(_num, angle_measurement), \
|
||||||
|
.disable_temperature_oversampling = DT_INST_PROP(_num, \
|
||||||
|
disable_temperature_oversampling), \
|
||||||
|
.sleep_time = DT_INST_ENUM_IDX(_num, sleep_time), \
|
||||||
|
IF_ENABLED(CONFIG_TMAG5170_TRIGGER, \
|
||||||
|
(.int_gpio = GPIO_DT_SPEC_INST_GET_OR(_num, int_gpios, { 0 }),)) \
|
||||||
|
}; \
|
||||||
|
PM_DEVICE_DT_INST_DEFINE(_num, tmag5170_pm_action); \
|
||||||
|
\
|
||||||
|
SENSOR_DEVICE_DT_INST_DEFINE(_num, \
|
||||||
|
tmag5170_init, \
|
||||||
|
PM_DEVICE_DT_INST_GET(_num), \
|
||||||
|
&tmag5170_data_##_num, \
|
||||||
|
&tmag5170_config_##_num, \
|
||||||
|
POST_KERNEL, \
|
||||||
|
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||||
|
&tmag5170_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(DEFINE_TMAG5170)
|
66
drivers/sensor/tmag5170/tmag5170.h
Normal file
66
drivers/sensor/tmag5170/tmag5170.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Michal Morsisko
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_TMAG5170_TMAG5170_H_
|
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_TMAG5170_TMAG5170_H_
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/spi.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
|
struct tmag5170_dev_config {
|
||||||
|
struct spi_dt_spec bus;
|
||||||
|
uint8_t magnetic_channels;
|
||||||
|
uint8_t x_range;
|
||||||
|
uint8_t y_range;
|
||||||
|
uint8_t z_range;
|
||||||
|
uint8_t oversampling;
|
||||||
|
bool tempeature_measurement;
|
||||||
|
uint8_t magnet_type;
|
||||||
|
uint8_t angle_measurement;
|
||||||
|
bool disable_temperature_oversampling;
|
||||||
|
uint8_t sleep_time;
|
||||||
|
uint8_t operating_mode;
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
struct gpio_dt_spec int_gpio;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tmag5170_data {
|
||||||
|
uint8_t chip_revision;
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
uint16_t z;
|
||||||
|
uint16_t temperature;
|
||||||
|
uint16_t angle;
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
sensor_trigger_handler_t handler_drdy;
|
||||||
|
const struct sensor_trigger *trigger_drdy;
|
||||||
|
const struct device *dev;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
|
||||||
|
struct k_sem sem;
|
||||||
|
struct k_thread thread;
|
||||||
|
|
||||||
|
K_THREAD_STACK_MEMBER(thread_stack,
|
||||||
|
CONFIG_TMAG5170_THREAD_STACK_SIZE);
|
||||||
|
#elif defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
|
||||||
|
struct k_work work;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER)
|
||||||
|
int tmag5170_trigger_set(const struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler);
|
||||||
|
|
||||||
|
int tmag5170_trigger_init(const struct device *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_DRIVERS_SENSOR_TMAG5170_TMAG5170_H_ */
|
149
drivers/sensor/tmag5170/tmag5170_trigger.c
Normal file
149
drivers/sensor/tmag5170/tmag5170_trigger.c
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Michal Morsisko
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT ti_tmag5170
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "tmag5170.h"
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(TMAG5170, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static void tmag5170_handle_interrupts(const void *arg)
|
||||||
|
{
|
||||||
|
const struct device *dev = (const struct device *)arg;
|
||||||
|
struct tmag5170_data *data = dev->data;
|
||||||
|
|
||||||
|
if (data->handler_drdy) {
|
||||||
|
data->handler_drdy(dev, data->trigger_drdy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
|
||||||
|
static void tmag5170_thread_main(void *arg1, void *unused1, void *unused2)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(unused1);
|
||||||
|
ARG_UNUSED(unused2);
|
||||||
|
const struct device *dev = (const struct device *)arg1;
|
||||||
|
struct tmag5170_data *data = dev->data;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
tmag5170_handle_interrupts(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
|
||||||
|
static void tmag5170_work_handler(struct k_work *work)
|
||||||
|
{
|
||||||
|
struct tmag5170_data *data = CONTAINER_OF(work,
|
||||||
|
struct tmag5170_data,
|
||||||
|
work);
|
||||||
|
|
||||||
|
tmag5170_handle_interrupts(data->dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void tmag5170_gpio_callback(const struct device *port,
|
||||||
|
struct gpio_callback *cb,
|
||||||
|
uint32_t pin)
|
||||||
|
{
|
||||||
|
struct tmag5170_data *data = CONTAINER_OF(cb,
|
||||||
|
struct tmag5170_data,
|
||||||
|
gpio_cb);
|
||||||
|
|
||||||
|
ARG_UNUSED(port);
|
||||||
|
ARG_UNUSED(pin);
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
#elif defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
|
||||||
|
k_work_submit(&data->work);
|
||||||
|
#elif defined(CONFIG_TMAG5170_TRIGGER_DIRECT)
|
||||||
|
tmag5170_handle_interrupts(data->dev);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmag5170_trigger_set(
|
||||||
|
const struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler)
|
||||||
|
{
|
||||||
|
struct tmag5170_data *data = dev->data;
|
||||||
|
|
||||||
|
#if defined(CONFIG_PM_DEVICE)
|
||||||
|
enum pm_device_state state;
|
||||||
|
|
||||||
|
(void)pm_device_state_get(dev, &state);
|
||||||
|
if (state != PM_DEVICE_STATE_ACTIVE) {
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (trig->type != SENSOR_TRIG_DATA_READY) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->trigger_drdy = trig;
|
||||||
|
data->handler_drdy = handler;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmag5170_trigger_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct tmag5170_data *data = dev->data;
|
||||||
|
const struct tmag5170_dev_config *cfg = dev->config;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!device_is_ready(cfg->int_gpio.port)) {
|
||||||
|
LOG_ERR("%s: device %s is not ready", dev->name, cfg->int_gpio.port->name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->dev = dev;
|
||||||
|
|
||||||
|
#if defined(CONFIG_TMAG5170_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_init(&data->sem, 0, 1);
|
||||||
|
k_thread_create(
|
||||||
|
&data->thread,
|
||||||
|
data->thread_stack,
|
||||||
|
CONFIG_TMAG5170_THREAD_STACK_SIZE,
|
||||||
|
tmag5170_thread_main,
|
||||||
|
(void *)dev,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
K_PRIO_COOP(CONFIG_TMAG5170_THREAD_PRIORITY),
|
||||||
|
0,
|
||||||
|
K_NO_WAIT);
|
||||||
|
#elif defined(CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD)
|
||||||
|
data->work.handler = tmag5170_work_handler;
|
||||||
|
#endif
|
||||||
|
ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_init_callback(&data->gpio_cb, tmag5170_gpio_callback, BIT(cfg->int_gpio.pin));
|
||||||
|
|
||||||
|
ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_FALLING);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
213
dts/bindings/sensor/ti,tmag5170.yaml
Normal file
213
dts/bindings/sensor/ti,tmag5170.yaml
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
# Copyright (c) 2023 Michal Morsisko
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Texas Instruments TMAG5170 high-precision, linear 3D Hall-effect sensor.
|
||||||
|
|
||||||
|
compatible: "ti,tmag5170"
|
||||||
|
|
||||||
|
include: [sensor-device.yaml, spi-device.yaml]
|
||||||
|
|
||||||
|
properties:
|
||||||
|
int-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
description: |
|
||||||
|
This property specifies the connection to ALERT sensor pin.
|
||||||
|
It will be used by the driver to notify the application about
|
||||||
|
data ready event. For this property to take effect, the
|
||||||
|
TMAG5170_TRIGGER must be set in project configuration
|
||||||
|
operating-mode:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
Operating mode of the device.
|
||||||
|
1 - stand-by mode - in this mode the device waits for application to trigger
|
||||||
|
the measurement.
|
||||||
|
2 - active measure mode - continuous sampling on all enabled channels
|
||||||
|
as fast as possible. Recommended for devices that haven't got
|
||||||
|
strict power requirements and need frequent sampling.
|
||||||
|
3 - active trigger mode - in this mode, similar to stand-by mode, the device
|
||||||
|
wait for application to trigger the measurement, but the time needed to finish
|
||||||
|
the conversion is shorter than in stand-by mode, on the cost of increased power
|
||||||
|
consumption.
|
||||||
|
4 - duty-cycled - after each sample the device goes to sleep and then
|
||||||
|
automatically wakes up to take another sample. The sleep time is determined
|
||||||
|
by `sleep-time` property. Recommended for low-power devices that don't need
|
||||||
|
high frequency sampling.
|
||||||
|
enum:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
magnetic-channels:
|
||||||
|
type: string
|
||||||
|
default: "XYZ"
|
||||||
|
description: |
|
||||||
|
Enables data acquisition of the magnetic axis channel(s)
|
||||||
|
If axis is enabled more than once, sensor will do pseudo-simultaneous
|
||||||
|
sampling. Refer to datasheet for more information, By default all axes
|
||||||
|
are enabled (XYZ) to allow the user to check if the sensor work as expected.
|
||||||
|
Following options are allowed:
|
||||||
|
None (chip reset value)
|
||||||
|
X
|
||||||
|
Y
|
||||||
|
XY
|
||||||
|
Z
|
||||||
|
ZX
|
||||||
|
YZ
|
||||||
|
XYZ (default)
|
||||||
|
XYX
|
||||||
|
YXY
|
||||||
|
YZY
|
||||||
|
ZYZ
|
||||||
|
ZXZ
|
||||||
|
XZX
|
||||||
|
XYZYX
|
||||||
|
XYZZYX
|
||||||
|
enum:
|
||||||
|
- "None"
|
||||||
|
- "X"
|
||||||
|
- "Y"
|
||||||
|
- "XY"
|
||||||
|
- "Z"
|
||||||
|
- "ZX"
|
||||||
|
- "YZ"
|
||||||
|
- "XYZ"
|
||||||
|
- "XYX"
|
||||||
|
- "YXY"
|
||||||
|
- "YZY"
|
||||||
|
- "ZYZ"
|
||||||
|
- "ZXZ"
|
||||||
|
- "XZX"
|
||||||
|
- "XYZYX"
|
||||||
|
- "XYZZYX"
|
||||||
|
x-range:
|
||||||
|
type: int
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
The maximum and minimum values that can be measured on X axis.
|
||||||
|
The wider the range, the worse the resolution.
|
||||||
|
0 = ±50mT (TMAG5170A1)/ ±150mT(TMAG5170A2) - (default; chip reset value)
|
||||||
|
1 = ±25mT (TMAG5170A1)/ ±75mT(TMAG5170A2)
|
||||||
|
2 = ±100mT (TMAG5170A1)/ ±300mT(TMAG5170A2)
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
y-range:
|
||||||
|
type: int
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
The maximum and minimum values that can be measured on Y axis.
|
||||||
|
The wider the range, the worse the resolution.
|
||||||
|
0 = ±50mT (TMAG5170A1)/ ±150mT(TMAG5170A2) - (default; chip reset value)
|
||||||
|
1 = ±25mT (TMAG5170A1)/ ±75mT(TMAG5170A2)
|
||||||
|
2 = ±100mT (TMAG5170A1)/ ±300mT(TMAG5170A2)
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
z-range:
|
||||||
|
type: int
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
The maximum and minimum values that can be measured on Z axis.
|
||||||
|
The wider the range, the worse the resolution.
|
||||||
|
0 = ±50mT (TMAG5170A1)/ ±150mT(TMAG5170A2) - (default; chip reset value)
|
||||||
|
1 = ±25mT (TMAG5170A1)/ ±75mT(TMAG5170A2)
|
||||||
|
2 = ±100mT (TMAG5170A1)/ ±300mT(TMAG5170A2)
|
||||||
|
enum:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
oversampling:
|
||||||
|
type: int
|
||||||
|
default: 1
|
||||||
|
description: |
|
||||||
|
Enables additional sampling of the sensor data to reduce the noise
|
||||||
|
effect. If temperature channel is enabled, temperature will be oversampled
|
||||||
|
too, unless `disable-temperature-oversampling` property is present.
|
||||||
|
Following options are allowed:
|
||||||
|
1 (default; chip reset value)
|
||||||
|
2
|
||||||
|
4
|
||||||
|
8
|
||||||
|
16
|
||||||
|
32
|
||||||
|
enum:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 4
|
||||||
|
- 8
|
||||||
|
- 16
|
||||||
|
- 32
|
||||||
|
enable-temperature-channel:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
Enables temperature measurement
|
||||||
|
magnet-type:
|
||||||
|
type: string
|
||||||
|
default: "None"
|
||||||
|
description: |
|
||||||
|
Enables temperature compensation basing on the type of magnet.
|
||||||
|
Following options are allowed:
|
||||||
|
None (default; chip reset value)
|
||||||
|
NdBFe = 0.12%/deg C
|
||||||
|
SmCo = 0.03%/deg C
|
||||||
|
Ceramic = 0.2%/deg C
|
||||||
|
enum:
|
||||||
|
- "None"
|
||||||
|
- "NdBFe"
|
||||||
|
- "SmCo"
|
||||||
|
- "Ceramic"
|
||||||
|
angle-measurement:
|
||||||
|
type: string
|
||||||
|
default: "None"
|
||||||
|
description: |
|
||||||
|
Enable angle calculation using two axis data:
|
||||||
|
None (default; chip reset value)
|
||||||
|
XY
|
||||||
|
YZ
|
||||||
|
XZ
|
||||||
|
enum:
|
||||||
|
- "None"
|
||||||
|
- "XY"
|
||||||
|
- "YZ"
|
||||||
|
- "XZ"
|
||||||
|
disable-temperature-oversampling:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
If true, temperature is always sampled once per conversion set
|
||||||
|
If false, temperature is oversampled according to `oversampling`
|
||||||
|
property.
|
||||||
|
sleep-time:
|
||||||
|
type: int
|
||||||
|
default: 1
|
||||||
|
description: |
|
||||||
|
The time in miliseconds the sensor will be in sleep during conversions.
|
||||||
|
For this property to take effect sensor must be in `duty-cycled` mode.
|
||||||
|
Note that to calculate total time between conversions, the conversion time
|
||||||
|
itself must be taken into account. The conversion time is dependent
|
||||||
|
on the values of `oversampling`, `magnetic-channels`, `temperature-channel-enabled`
|
||||||
|
and `disable-temperature-oversampling` properties.
|
||||||
|
Following value are allowed:
|
||||||
|
1 (default; chip reset value)
|
||||||
|
5
|
||||||
|
10
|
||||||
|
15
|
||||||
|
20
|
||||||
|
30
|
||||||
|
50
|
||||||
|
100
|
||||||
|
500
|
||||||
|
1000
|
||||||
|
enum:
|
||||||
|
- 1
|
||||||
|
- 5
|
||||||
|
- 10
|
||||||
|
- 15
|
||||||
|
- 20
|
||||||
|
- 30
|
||||||
|
- 50
|
||||||
|
- 100
|
||||||
|
- 500
|
||||||
|
- 1000
|
|
@ -119,7 +119,8 @@
|
||||||
<&test_gpio 0 0>,
|
<&test_gpio 0 0>,
|
||||||
<&test_gpio 0 0>,
|
<&test_gpio 0 0>,
|
||||||
<&test_gpio 0 0>,
|
<&test_gpio 0 0>,
|
||||||
<&test_gpio 0 0>; /* 0x24 */
|
<&test_gpio 0 0>,
|
||||||
|
<&test_gpio 0 0>; /* 0x25 */
|
||||||
|
|
||||||
#include "spi.dtsi"
|
#include "spi.dtsi"
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,7 @@ CONFIG_SM351LT_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_STTS751_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_STTS751_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_SX9500_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_SX9500_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD=y
|
||||||
|
CONFIG_TMAG5170_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_TMD2620_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_TMD2620_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_TMP007_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_TMP007_TRIGGER_GLOBAL_THREAD=y
|
||||||
CONFIG_TSL2540_TRIGGER_GLOBAL_THREAD=y
|
CONFIG_TSL2540_TRIGGER_GLOBAL_THREAD=y
|
||||||
|
|
|
@ -48,6 +48,7 @@ CONFIG_SM351LT_TRIGGER_NONE=y
|
||||||
CONFIG_STTS751_TRIGGER_NONE=y
|
CONFIG_STTS751_TRIGGER_NONE=y
|
||||||
CONFIG_SX9500_TRIGGER_NONE=y
|
CONFIG_SX9500_TRIGGER_NONE=y
|
||||||
CONFIG_TCN75A_TRIGGER_NONE=y
|
CONFIG_TCN75A_TRIGGER_NONE=y
|
||||||
|
CONFIG_TMAG5170_TRIGGER_NONE=y
|
||||||
CONFIG_TMD2620_TRIGGER_NONE=y
|
CONFIG_TMD2620_TRIGGER_NONE=y
|
||||||
CONFIG_TMP007_TRIGGER_NONE=y
|
CONFIG_TMP007_TRIGGER_NONE=y
|
||||||
CONFIG_TSL2540_TRIGGER_NONE=y
|
CONFIG_TSL2540_TRIGGER_NONE=y
|
||||||
|
|
|
@ -46,6 +46,7 @@ CONFIG_SM351LT_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_STTS751_TRIGGER_OWN_THREAD=y
|
CONFIG_STTS751_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_SX9500_TRIGGER_OWN_THREAD=y
|
CONFIG_SX9500_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_TCN75A_TRIGGER_OWN_THREAD=y
|
CONFIG_TCN75A_TRIGGER_OWN_THREAD=y
|
||||||
|
CONFIG_TMAG5170_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
CONFIG_TMP007_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_TSL2540_TRIGGER_OWN_THREAD=y
|
CONFIG_TSL2540_TRIGGER_OWN_THREAD=y
|
||||||
CONFIG_VCNL4040_TRIGGER_OWN_THREAD=y
|
CONFIG_VCNL4040_TRIGGER_OWN_THREAD=y
|
||||||
|
|
|
@ -287,3 +287,11 @@ test_spi_bmi08x_gyro: bmi08x@24 {
|
||||||
gyro-hz = "1000_116";
|
gyro-hz = "1000_116";
|
||||||
gyro-fs = <1000>;
|
gyro-fs = <1000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test_spi_tmag5170: tmag5170@25 {
|
||||||
|
compatible = "ti,tmag5170";
|
||||||
|
reg = <0x25>;
|
||||||
|
spi-max-frequency = <0>;
|
||||||
|
int-gpios = <&test_gpio 0 0>;
|
||||||
|
operating-mode = <1>;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue