drivers: sensor: fxls8974: Added driver for this accelerometer
Added driver for the fxls8974 accelerometer which is present on the mimxrt1040_evk board. Signed-off-by: Krystof Sadlik <krystof.sadlik@nxp.com>
This commit is contained in:
parent
087680a49c
commit
928d025201
7 changed files with 1093 additions and 0 deletions
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
# zephyr-keep-sorted-start
|
# zephyr-keep-sorted-start
|
||||||
add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002)
|
add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002)
|
||||||
|
add_subdirectory_ifdef(CONFIG_FXLS8974 fxls8974)
|
||||||
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
|
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
|
||||||
add_subdirectory_ifdef(CONFIG_MCUX_ACMP mcux_acmp)
|
add_subdirectory_ifdef(CONFIG_MCUX_ACMP mcux_acmp)
|
||||||
add_subdirectory_ifdef(CONFIG_MCUX_LPCMP mcux_lpcmp)
|
add_subdirectory_ifdef(CONFIG_MCUX_LPCMP mcux_lpcmp)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
# zephyr-keep-sorted-start
|
# zephyr-keep-sorted-start
|
||||||
source "drivers/sensor/nxp/fxas21002/Kconfig"
|
source "drivers/sensor/nxp/fxas21002/Kconfig"
|
||||||
|
source "drivers/sensor/nxp/fxls8974/Kconfig"
|
||||||
source "drivers/sensor/nxp/fxos8700/Kconfig"
|
source "drivers/sensor/nxp/fxos8700/Kconfig"
|
||||||
source "drivers/sensor/nxp/mcux_acmp/Kconfig"
|
source "drivers/sensor/nxp/mcux_acmp/Kconfig"
|
||||||
source "drivers/sensor/nxp/mcux_lpcmp/Kconfig"
|
source "drivers/sensor/nxp/mcux_lpcmp/Kconfig"
|
||||||
|
|
10
drivers/sensor/nxp/fxls8974/CMakeLists.txt
Normal file
10
drivers/sensor/nxp/fxls8974/CMakeLists.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Makefile - FXLS8974 3-axis accelerometer
|
||||||
|
#
|
||||||
|
# Copyright 2024 NXP
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources(fxls8974.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_FXLS8974_TRIGGER fxls8974_trigger.c)
|
58
drivers/sensor/nxp/fxls8974/Kconfig
Normal file
58
drivers/sensor/nxp/fxls8974/Kconfig
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# FXLS8974 3-axis accelerometer
|
||||||
|
|
||||||
|
# Copyright 2024 NXP
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
menuconfig FXLS8974
|
||||||
|
bool "FXLS8974 accelerometer driver"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_NXP_FXLS8974_ENABLED
|
||||||
|
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_NXP_FXLS8974),i2c)
|
||||||
|
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_NXP_FXLS8974),spi)
|
||||||
|
help
|
||||||
|
Enable driver for the FXLS8974 accelerometer
|
||||||
|
|
||||||
|
if FXLS8974
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Trigger mode"
|
||||||
|
default FXLS8974_TRIGGER_NONE
|
||||||
|
|
||||||
|
config FXLS8974_TRIGGER_NONE
|
||||||
|
bool "No trigger"
|
||||||
|
|
||||||
|
config FXLS8974_TRIGGER_GLOBAL_THREAD
|
||||||
|
bool "Use global thread"
|
||||||
|
select FXLS8974_TRIGGER
|
||||||
|
|
||||||
|
config FXLS8974_TRIGGER_OWN_THREAD
|
||||||
|
bool "Use own thread"
|
||||||
|
select FXLS8974_TRIGGER
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config FXLS8974_TRIGGER
|
||||||
|
bool
|
||||||
|
|
||||||
|
config FXLS8974_DRDY_INT1
|
||||||
|
bool "Data ready interrupt to INT1 pin"
|
||||||
|
depends on FXLS8974_TRIGGER
|
||||||
|
help
|
||||||
|
Say Y to route data ready interrupt to INT1 pin. Say N to route to
|
||||||
|
INT2 pin.
|
||||||
|
|
||||||
|
if FXLS8974_TRIGGER
|
||||||
|
|
||||||
|
config FXLS8974_THREAD_PRIORITY
|
||||||
|
int "Own thread priority"
|
||||||
|
depends on FXLS8974_TRIGGER_OWN_THREAD
|
||||||
|
default 10
|
||||||
|
|
||||||
|
config FXLS8974_THREAD_STACK_SIZE
|
||||||
|
int "Own thread stack size"
|
||||||
|
depends on FXLS8974_TRIGGER_OWN_THREAD
|
||||||
|
default 1024
|
||||||
|
|
||||||
|
endif # FXLS8974_TRIGGER
|
||||||
|
|
||||||
|
endif # FXLS8974
|
640
drivers/sensor/nxp/fxls8974/fxls8974.c
Normal file
640
drivers/sensor/nxp/fxls8974/fxls8974.c
Normal file
|
@ -0,0 +1,640 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 NXP
|
||||||
|
* Copyright (c) 2018 Phytec Messtechnik GmbH
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT nxp_fxls8974
|
||||||
|
|
||||||
|
#include "fxls8974.h"
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/sys/__assert.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(FXLS8974, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||||
|
#define DIR_READ(a) ((a) & 0x7f)
|
||||||
|
#define DIR_WRITE(a) ((a) | BIT(7))
|
||||||
|
#define ADDR_7(a) ((a) & BIT(7))
|
||||||
|
|
||||||
|
int fxls8974_transceive(const struct device *dev,
|
||||||
|
void *data, size_t length)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
const struct spi_buf buf = { .buf = data, .len = length };
|
||||||
|
const struct spi_buf_set s = { .bufs = &buf, .count = 1 };
|
||||||
|
|
||||||
|
return spi_transceive_dt(&cfg->bus_cfg.spi, &s, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_read_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
void *data,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
/* Reads must clock out a dummy byte after sending the address. */
|
||||||
|
uint8_t reg_buf[3] = { DIR_READ(reg), ADDR_7(reg), 0 };
|
||||||
|
const struct spi_buf buf[2] = {
|
||||||
|
{ .buf = reg_buf, .len = 3 },
|
||||||
|
{ .buf = data, .len = length }
|
||||||
|
};
|
||||||
|
const struct spi_buf_set tx = { .bufs = buf, .count = 1 };
|
||||||
|
const struct spi_buf_set rx = { .bufs = buf, .count = 2 };
|
||||||
|
|
||||||
|
return spi_transceive_dt(&cfg->bus_cfg.spi, &tx, &rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_byte_read_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t *byte)
|
||||||
|
{
|
||||||
|
/* Reads must clock out a dummy byte after sending the address. */
|
||||||
|
uint8_t data[] = { DIR_READ(reg), ADDR_7(reg), 0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fxls8974_transceive(dev, data, sizeof(data));
|
||||||
|
|
||||||
|
*byte = data[2];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_byte_write_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t byte)
|
||||||
|
{
|
||||||
|
uint8_t data[] = { DIR_WRITE(reg), ADDR_7(reg), byte };
|
||||||
|
|
||||||
|
return fxls8974_transceive(dev, data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_reg_field_update_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t mask,
|
||||||
|
uint8_t val)
|
||||||
|
{
|
||||||
|
uint8_t old_val;
|
||||||
|
|
||||||
|
if (fxls8974_byte_read_spi(dev, reg, &old_val) < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fxls8974_byte_write_spi(dev, reg, (old_val & ~mask) | (val & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fxls8974_io_ops fxls8974_spi_ops = {
|
||||||
|
.read = fxls8974_read_spi,
|
||||||
|
.byte_read = fxls8974_byte_read_spi,
|
||||||
|
.byte_write = fxls8974_byte_write_spi,
|
||||||
|
.reg_field_update = fxls8974_reg_field_update_spi,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||||
|
int fxls8974_read_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
void *data,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
return i2c_burst_read_dt(&cfg->bus_cfg.i2c, reg, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_byte_read_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t *byte)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
return i2c_reg_read_byte_dt(&cfg->bus_cfg.i2c, reg, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_byte_write_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t byte)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
return i2c_reg_write_byte_dt(&cfg->bus_cfg.i2c, reg, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_reg_field_update_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t mask,
|
||||||
|
uint8_t val)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
return i2c_reg_update_byte_dt(&cfg->bus_cfg.i2c, reg, mask, val);
|
||||||
|
}
|
||||||
|
static const struct fxls8974_io_ops fxls8974_i2c_ops = {
|
||||||
|
.read = fxls8974_read_i2c,
|
||||||
|
.byte_read = fxls8974_byte_read_i2c,
|
||||||
|
.byte_write = fxls8974_byte_write_i2c,
|
||||||
|
.reg_field_update = fxls8974_reg_field_update_i2c,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int fxls8974_set_odr(const struct device *dev,
|
||||||
|
const struct sensor_value *val, enum fxls8974_wake mode)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
uint8_t odr;
|
||||||
|
/* val int32 */
|
||||||
|
switch (val->val1) {
|
||||||
|
case 3200:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_3200;
|
||||||
|
break;
|
||||||
|
case 800:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_800;
|
||||||
|
break;
|
||||||
|
case 400:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_400;
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_200;
|
||||||
|
break;
|
||||||
|
case 100:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_100;
|
||||||
|
break;
|
||||||
|
case 50:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_50;
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_25;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
if (val->val2 == 500000) {
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_12_5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
case 6:
|
||||||
|
if (val->val2 == 250000) {
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_6_25;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
case 3:
|
||||||
|
if (val->val2 == 125000) {
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_3_125;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
case 1:
|
||||||
|
if (val->val2 == 563000) {
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_1_563;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
case 0:
|
||||||
|
if (val->val2 == 781000) {
|
||||||
|
odr = FXLS8974_CTRLREG3_ODR_RATE_0_781;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Set %s ODR to 0x%02x", (mode == FXLS8974_WAKE) ? "wake" : "sleep", odr);
|
||||||
|
|
||||||
|
/* Change the attribute and restore active mode. */
|
||||||
|
if (mode == FXLS8974_WAKE) {
|
||||||
|
return cfg->ops->reg_field_update(dev, FXLS8974_REG_CTRLREG3,
|
||||||
|
FXLS8974_CTRLREG3_WAKE_ODR_MASK,
|
||||||
|
odr<<4);
|
||||||
|
} else {
|
||||||
|
return cfg->ops->reg_field_update(dev, FXLS8974_REG_CTRLREG3,
|
||||||
|
FXLS8974_CTRLREG3_SLEEP_ODR_MASK,
|
||||||
|
odr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_attr_set(const struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
enum sensor_attribute attr,
|
||||||
|
const struct sensor_value *val)
|
||||||
|
{
|
||||||
|
if (chan != SENSOR_CHAN_ALL) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr) {
|
||||||
|
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||||
|
return fxls8974_set_odr(dev, val, FXLS8974_WAKE);
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_sample_fetch(const struct device *dev, enum sensor_channel ch)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
uint8_t buf[FXLS8974_MAX_NUM_BYTES];
|
||||||
|
int16_t *raw;
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
|
||||||
|
/* Read all the accel channels in one I2C/SPI transaction. */
|
||||||
|
if (cfg->ops->read(dev, FXLS8974_REG_OUTXLSB, buf, FXLS8974_MAX_ACCEL_BYTES)) {
|
||||||
|
LOG_ERR("Could not fetch accelerometer data");
|
||||||
|
ret = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_OUTTEMP, buf+FXLS8974_DATA_TEMP_OFFSET)) {
|
||||||
|
LOG_ERR("Could not fetch temperature");
|
||||||
|
ret = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse the buf into raw channel data (16-bit integers). To save
|
||||||
|
* RAM, store the data in raw format and wait to convert to the
|
||||||
|
* normalized sensor_value type until later.
|
||||||
|
*/
|
||||||
|
__ASSERT(FXLS8974_MAX_NUM_CHANNELS <= ARRAY_SIZE(data->raw),
|
||||||
|
"Too many channels");
|
||||||
|
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_ACCEL_X];
|
||||||
|
|
||||||
|
for (i = 0; i < FXLS8974_MAX_ACCEL_BYTES; i += 2) {
|
||||||
|
*raw++ = (buf[i+1] << 8) | (buf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*raw = *(buf+FXLS8974_MAX_ACCEL_BYTES);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fxls8974_accel_convert(struct sensor_value *val, int16_t raw,
|
||||||
|
uint8_t fsr)
|
||||||
|
{
|
||||||
|
int64_t micro_ms2;
|
||||||
|
|
||||||
|
/* Convert units to micro m/s^2. */
|
||||||
|
micro_ms2 = (raw * SENSOR_G) >> fsr;
|
||||||
|
|
||||||
|
/* The maximum possible value is 16g, which in units of micro m/s^2
|
||||||
|
* always fits into 32-bits. Cast down to int32_t so we can use a
|
||||||
|
* faster divide.
|
||||||
|
*/
|
||||||
|
val->val1 = (int32_t) micro_ms2 / 1000000;
|
||||||
|
val->val2 = (int32_t) micro_ms2 % 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_get_accel_data(const struct device *dev,
|
||||||
|
struct sensor_value *val, enum sensor_channel ch)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
int16_t *raw;
|
||||||
|
uint8_t fsr;
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_CTRLREG1, &fsr)) {
|
||||||
|
LOG_ERR("Could not read scale settings");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsr = (fsr & FXLS8974_CTRLREG1_FSR_MASK) >> 1;
|
||||||
|
switch (fsr) {
|
||||||
|
case 0b00:
|
||||||
|
fsr = 10U;
|
||||||
|
break;
|
||||||
|
case 0b01:
|
||||||
|
fsr = 9U;
|
||||||
|
break;
|
||||||
|
case 0b10:
|
||||||
|
fsr = 8U;
|
||||||
|
break;
|
||||||
|
case 0b11:
|
||||||
|
fsr = 7U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == SENSOR_CHAN_ACCEL_XYZ) {
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_ACCEL_X];
|
||||||
|
for (int i = 0; i < FXLS8974_MAX_ACCEL_CHANNELS; i++) {
|
||||||
|
fxls8974_accel_convert(val++, *raw++, fsr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (ch) {
|
||||||
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_ACCEL_X];
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_ACCEL_Y];
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ACCEL_Z:
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_ACCEL_Z];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
fxls8974_accel_convert(val, *raw, fsr);
|
||||||
|
}
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_get_temp_data(const struct device *dev, struct sensor_value *val)
|
||||||
|
{
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
int16_t *raw;
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
raw = &data->raw[FXLS8974_CHANNEL_TEMP];
|
||||||
|
val->val1 = *raw+FXLS8974_ZERO_TEMP;
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_channel_get(const struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_ALL:
|
||||||
|
if (fxls8974_get_accel_data(dev, val, SENSOR_CHAN_ACCEL_XYZ)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
val += FXLS8974_MAX_ACCEL_CHANNELS;
|
||||||
|
|
||||||
|
if (fxls8974_get_temp_data(dev, val)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_ACCEL_XYZ:
|
||||||
|
return fxls8974_get_accel_data(dev, val, SENSOR_CHAN_ACCEL_XYZ);
|
||||||
|
case SENSOR_CHAN_ACCEL_X:
|
||||||
|
__fallthrough;
|
||||||
|
case SENSOR_CHAN_ACCEL_Y:
|
||||||
|
__fallthrough;
|
||||||
|
case SENSOR_CHAN_ACCEL_Z:
|
||||||
|
return fxls8974_get_accel_data(dev, val, chan);
|
||||||
|
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||||
|
return fxls8974_get_temp_data(dev, val);
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unsupported channel");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_get_active(const struct device *dev, enum fxls8974_active *active)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_CTRLREG1, &val)) {
|
||||||
|
LOG_ERR("Could not get active setting");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
val &= FXLS8974_CTRLREG1_ACTIVE_MASK;
|
||||||
|
|
||||||
|
*active = val;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fxls8974_set_active(const struct device *dev, enum fxls8974_active active)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
|
||||||
|
return cfg->ops->reg_field_update(dev, FXLS8974_REG_CTRLREG1,
|
||||||
|
FXLS8974_CTRLREG1_ACTIVE_MASK, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fxls8974_print_config(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
uint8_t regVal[5];
|
||||||
|
|
||||||
|
if (cfg->ops->read(dev, FXLS8974_REG_CTRLREG1, regVal, 5)) {
|
||||||
|
LOG_ERR("Failed to read config registers");
|
||||||
|
}
|
||||||
|
LOG_DBG("Current config:\n\r"
|
||||||
|
"CFG: 0x%02x CFG2: 0x%02x CFG3: 0x%02x CFG4: 0x%02x CFG5: 0x%02x",
|
||||||
|
regVal[0], regVal[1], regVal[2], regVal[3], regVal[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *cfg = dev->config;
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
struct sensor_value odr = {.val1 = 6, .val2 = 250000};
|
||||||
|
uint8_t regVal;
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||||
|
const struct i2c_dt_spec i2c_spec = cfg->bus_cfg.i2c;
|
||||||
|
|
||||||
|
if (cfg->inst_on_bus == FXLS8974_BUS_I2C) {
|
||||||
|
if (!i2c_is_ready_dt(&i2c_spec)) {
|
||||||
|
LOG_ERR("I2C bus device not ready");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||||
|
const struct spi_dt_spec spi_spec = cfg->bus_cfg.spi;
|
||||||
|
|
||||||
|
if (cfg->inst_on_bus == FXLS8974_BUS_SPI) {
|
||||||
|
if (!spi_is_ready_dt(&spi_spec)) {
|
||||||
|
LOG_ERR("SPI bus device not ready");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Software reset the sensor. Upon issuing a software
|
||||||
|
* reset command over the I2C interface, the sensor
|
||||||
|
* immediately resets and does not send any
|
||||||
|
* acknowledgment (ACK) of the written byte to the
|
||||||
|
* master. Therefore, do not check the return code of
|
||||||
|
* the I2C transaction.
|
||||||
|
*/
|
||||||
|
cfg->ops->byte_write(dev, FXLS8974_REG_CTRLREG1,
|
||||||
|
FXLS8974_CTRLREG1_RST_MASK);
|
||||||
|
|
||||||
|
/* The sensor requires us to wait 1 ms after a reset before
|
||||||
|
* attempting further communications.
|
||||||
|
*/
|
||||||
|
k_busy_wait(USEC_PER_MSEC);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the WHOAMI register to make sure we are talking to FXLS8974 or
|
||||||
|
* compatible device and not some other type of device that happens to
|
||||||
|
* have the same I2C address.
|
||||||
|
*/
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_WHOAMI,
|
||||||
|
&data->whoami)) {
|
||||||
|
LOG_ERR("Could not get WHOAMI value");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->whoami == WHOAMI_ID_FXLS8974) {
|
||||||
|
LOG_DBG("Device ID 0x%x, FXLS8974", data->whoami);
|
||||||
|
} else {
|
||||||
|
LOG_ERR("Unknown Device ID 0x%x", data->whoami);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fxls8974_get_active(dev, (enum fxls8974_active *)®Val)) {
|
||||||
|
LOG_ERR("Failed to set standby mode");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regVal != FXLS8974_ACTIVE_OFF) {
|
||||||
|
LOG_ERR("Not in standby mode");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->ops->byte_write(dev, FXLS8974_REG_CTRLREG4,
|
||||||
|
FXLS8974_CTRLREG4_INT_POL_HIGH)) {
|
||||||
|
LOG_ERR("Could not set up register 4");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_CTRLREG4, ®Val)) {
|
||||||
|
LOG_ERR("Could not get CTRL_REG4 value");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regVal != FXLS8974_CTRLREG4_INT_POL_HIGH) {
|
||||||
|
LOG_ERR("CTRLREG4 is not set up properly");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fxls8974_set_odr(dev, &odr, FXLS8974_WAKE)) {
|
||||||
|
LOG_ERR("Could not set default data rate");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the +-2G mode */
|
||||||
|
if (cfg->ops->byte_write(dev, FXLS8974_REG_CTRLREG1,
|
||||||
|
FXLS8974_CTRLREG1_FSR_2G)) {
|
||||||
|
LOG_ERR("Could not set range");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->ops->byte_read(dev, FXLS8974_REG_CTRLREG1,
|
||||||
|
®Val)) {
|
||||||
|
LOG_ERR("Could not ret CTRL_REG1 value");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((regVal & FXLS8974_CTRLREG1_FSR_MASK) != FXLS8974_CTRLREG1_FSR_2G) {
|
||||||
|
LOG_ERR("Wrong range selected!");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
|
||||||
|
|
||||||
|
#if CONFIG_FXLS8974_TRIGGER
|
||||||
|
if (fxls8974_trigger_init(dev)) {
|
||||||
|
LOG_ERR("Could not initialize interrupts");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fxls8974_set_active(dev, FXLS8974_ACTIVE_ON)) {
|
||||||
|
LOG_ERR("Could not set active mode");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fxls8974_get_active(dev, (enum fxls8974_active *)®Val)) {
|
||||||
|
LOG_ERR("Failed to get active mode");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regVal != FXLS8974_ACTIVE_ON) {
|
||||||
|
LOG_ERR("Not in active mode");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
fxls8974_print_config(dev);
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
LOG_DBG("Init complete");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sensor_driver_api fxls8974_driver_api = {
|
||||||
|
.sample_fetch = fxls8974_sample_fetch,
|
||||||
|
.channel_get = fxls8974_channel_get,
|
||||||
|
.attr_set = fxls8974_attr_set,
|
||||||
|
#if CONFIG_FXLS8974_TRIGGER
|
||||||
|
.trigger_set = fxls8974_trigger_set,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FXLS8974_CONFIG_I2C(n) \
|
||||||
|
.bus_cfg = { .i2c = I2C_DT_SPEC_INST_GET(n) }, \
|
||||||
|
.ops = &fxls8974_i2c_ops, \
|
||||||
|
.range = DT_INST_PROP(n, range), \
|
||||||
|
.inst_on_bus = FXLS8974_BUS_I2C,
|
||||||
|
|
||||||
|
#define FXLS8974_CONFIG_SPI(n) \
|
||||||
|
.bus_cfg = { .spi = SPI_DT_SPEC_INST_GET(n, \
|
||||||
|
SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0) }, \
|
||||||
|
.ops = &fxls8974_spi_ops, \
|
||||||
|
.range = DT_INST_PROP(n, range), \
|
||||||
|
.inst_on_bus = FXLS8974_BUS_SPI, \
|
||||||
|
|
||||||
|
#define FXLS8974_SPI_OPERATION (SPI_WORD_SET(8) | \
|
||||||
|
SPI_OP_MODE_MASTER) \
|
||||||
|
|
||||||
|
#define FXLS8974_INTM_PROPS(n, m) \
|
||||||
|
.int_gpio = GPIO_DT_SPEC_INST_GET(n, int##m##_gpios),
|
||||||
|
|
||||||
|
#define FXLS8974_INT_PROPS(n) \
|
||||||
|
COND_CODE_1(CONFIG_FXLS8974_DRDY_INT1, \
|
||||||
|
(FXLS8974_INTM_PROPS(n, 1)), \
|
||||||
|
(FXLS8974_INTM_PROPS(n, 2)))
|
||||||
|
|
||||||
|
#define FXLS8974_INT(n) \
|
||||||
|
COND_CODE_1(CONFIG_FXLS8974_TRIGGER, \
|
||||||
|
(FXLS8974_INT_PROPS(n)), \
|
||||||
|
())
|
||||||
|
|
||||||
|
#define FXLS8974_INIT(n) \
|
||||||
|
static const struct fxls8974_config fxls8974_config_##n = { \
|
||||||
|
COND_CODE_1(DT_INST_ON_BUS(n, spi), \
|
||||||
|
(FXLS8974_CONFIG_SPI(n)), \
|
||||||
|
(FXLS8974_CONFIG_I2C(n))) \
|
||||||
|
FXLS8974_INT(n) \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static struct fxls8974_data fxls8974_data_##n; \
|
||||||
|
\
|
||||||
|
SENSOR_DEVICE_DT_INST_DEFINE(n, \
|
||||||
|
fxls8974_init, \
|
||||||
|
NULL, \
|
||||||
|
&fxls8974_data_##n, \
|
||||||
|
&fxls8974_config_##n, \
|
||||||
|
POST_KERNEL, \
|
||||||
|
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||||
|
&fxls8974_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(FXLS8974_INIT)
|
204
drivers/sensor/nxp/fxls8974/fxls8974.h
Normal file
204
drivers/sensor/nxp/fxls8974/fxls8974.h
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 NXP
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||||
|
#include <zephyr/drivers/spi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||||
|
#include <zephyr/drivers/i2c.h>
|
||||||
|
#endif
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#define FXLS8974_BUS_I2C (1<<0)
|
||||||
|
#define FXLS8974_BUS_SPI (1<<1)
|
||||||
|
#define FXLS8974_REG_OUTXLSB 0x04
|
||||||
|
#define FXLS8974_REG_OUTTEMP 0x01
|
||||||
|
#define FXLS8974_REG_WHOAMI 0x13
|
||||||
|
#define FXLS8974_REG_CTRLREG1 0x15
|
||||||
|
#define FXLS8974_REG_CTRLREG2 0x16
|
||||||
|
#define FXLS8974_REG_CTRLREG3 0x17
|
||||||
|
#define FXLS8974_REG_CTRLREG4 0x18
|
||||||
|
#define FXLS8974_REG_CTRLREG5 0x19
|
||||||
|
|
||||||
|
#define WHOAMI_ID_FXLS8974 0x86
|
||||||
|
|
||||||
|
#define FXLS8974_CTRLREG1_ACTIVE_MASK 0x01
|
||||||
|
#define FXLS8974_CTRLREG1_RST_MASK 0x80
|
||||||
|
#define FXLS8974_CTRLREG1_FSR_MASK 0x06
|
||||||
|
#define FXLS8974_CTRLREG1_FSR_2G 0x00
|
||||||
|
#define FXLS8974_CTRLREG1_FSR_4G 0x02
|
||||||
|
#define FXLS8974_CTRLREG1_FSR_8G 0x04
|
||||||
|
#define FXLS8974_CTRLREG1_FSR_16G 0x06
|
||||||
|
|
||||||
|
#define FXLS8974_CTRLREG2_WAKE_PM_MASK 0xC0
|
||||||
|
#define FXLS8974_CTRLREG2_SLEEP_PM_MASK 0x30
|
||||||
|
|
||||||
|
#define FXLS8974_CTRLREG3_WAKE_ODR_MASK 0xF0
|
||||||
|
#define FXLS8974_CTRLREG3_SLEEP_ODR_MASK 0x0F
|
||||||
|
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_3200 0x00
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_1600 0x01
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_800 0x02
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_400 0x03
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_200 0x04
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_100 0x05
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_50 0x06
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_25 0x07
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_12_5 0x08
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_6_25 0x09
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_3_125 0x0A
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_1_563 0x0B
|
||||||
|
#define FXLS8974_CTRLREG3_ODR_RATE_0_781 0x0C
|
||||||
|
|
||||||
|
#define FXLS8974_CTRLREG4_INT_POL_HIGH 0x01
|
||||||
|
|
||||||
|
#define FXLS8974_INTREG_EN 0x20
|
||||||
|
#define FXLS8974_INT_PIN_SEL_REG 0x21
|
||||||
|
|
||||||
|
#define FXLS8974_DATA_ACCEL_X_OFFSET 0
|
||||||
|
#define FXLS8974_DATA_ACCEL_Y_OFFSET FXLS8974_BYTES_PER_CHANNEL_NORMAL
|
||||||
|
#define FXLS8974_DATA_ACCEL_Z_OFFSET 2*FXLS8974_BYTES_PER_CHANNEL_NORMAL
|
||||||
|
#define FXLS8974_DATA_TEMP_OFFSET 3*FXLS8974_BYTES_PER_CHANNEL_NORMAL
|
||||||
|
#define FXLS8974_ZERO_TEMP 25
|
||||||
|
|
||||||
|
#define FXLS8974_MAX_NUM_CHANNELS 4
|
||||||
|
#define FXLS8974_MAX_ACCEL_CHANNELS 3
|
||||||
|
#define FXLS8974_MAX_TEMP_CHANNELS 1
|
||||||
|
|
||||||
|
#define FXLS8974_BYTES_PER_CHANNEL_NORMAL 2
|
||||||
|
#define FXLS8974_BYTES_PER_CHANNEL_FAST 1
|
||||||
|
|
||||||
|
#define FXLS8974_MAX_ACCEL_BYTES (FXLS8974_MAX_ACCEL_CHANNELS*2)
|
||||||
|
#define FXLS8974_MAX_NUM_BYTES (FXLS8974_MAX_ACCEL_BYTES + FXLS8974_MAX_TEMP_CHANNELS)
|
||||||
|
|
||||||
|
#define FXLS8974_DRDY_MASK 0x80
|
||||||
|
|
||||||
|
enum fxls8974_active {
|
||||||
|
FXLS8974_ACTIVE_OFF = 0,
|
||||||
|
FXLS8974_ACTIVE_ON,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fxls8974_wake {
|
||||||
|
FXLS8974_WAKE = 0,
|
||||||
|
FXLS8974_SLEEP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fxls8974_channel {
|
||||||
|
FXLS8974_CHANNEL_ACCEL_X = 0,
|
||||||
|
FXLS8974_CHANNEL_ACCEL_Y,
|
||||||
|
FXLS8974_CHANNEL_ACCEL_Z,
|
||||||
|
FXLS8974_CHANNEL_TEMP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fxls8974_io_ops {
|
||||||
|
int (*read)(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
void *data,
|
||||||
|
size_t length);
|
||||||
|
int (*byte_read)(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t *byte);
|
||||||
|
int (*byte_write)(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t byte);
|
||||||
|
int (*reg_field_update)(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t mask,
|
||||||
|
uint8_t val);
|
||||||
|
};
|
||||||
|
|
||||||
|
union fxls8974_bus_cfg {
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||||
|
struct spi_dt_spec spi;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||||
|
struct i2c_dt_spec i2c;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fxls8974_config {
|
||||||
|
const union fxls8974_bus_cfg bus_cfg;
|
||||||
|
const struct fxls8974_io_ops *ops;
|
||||||
|
struct gpio_dt_spec reset_gpio;
|
||||||
|
uint8_t range;
|
||||||
|
uint8_t inst_on_bus;
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER
|
||||||
|
struct gpio_dt_spec int_gpio;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fxls8974_data {
|
||||||
|
struct k_sem sem;
|
||||||
|
int16_t raw[FXLS8974_MAX_NUM_CHANNELS];
|
||||||
|
uint8_t whoami;
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER
|
||||||
|
const struct device *dev;
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
sensor_trigger_handler_t drdy_handler;
|
||||||
|
const struct sensor_trigger *drdy_trig;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER_OWN_THREAD
|
||||||
|
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_FXLS8974_THREAD_STACK_SIZE);
|
||||||
|
struct k_thread thread;
|
||||||
|
struct k_sem trig_sem;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER_GLOBAL_THREAD
|
||||||
|
struct k_work work;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
int fxls8974_get_active(const struct device *dev, enum fxls8974_active *active);
|
||||||
|
int fxls8974_set_active(const struct device *dev, enum fxls8974_active active);
|
||||||
|
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
|
||||||
|
int fxls8974_byte_write_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t byte);
|
||||||
|
|
||||||
|
int fxls8974_byte_read_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t *byte);
|
||||||
|
|
||||||
|
int fxls8974_reg_field_update_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t mask,
|
||||||
|
uint8_t val);
|
||||||
|
|
||||||
|
int fxls8974_read_spi(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
void *data,
|
||||||
|
size_t length);
|
||||||
|
#endif
|
||||||
|
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
|
||||||
|
int fxls8974_byte_write_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t byte);
|
||||||
|
|
||||||
|
int fxls8974_byte_read_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t *byte);
|
||||||
|
|
||||||
|
int fxls8974_reg_field_update_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
uint8_t mask,
|
||||||
|
uint8_t val);
|
||||||
|
|
||||||
|
int fxls8974_read_i2c(const struct device *dev,
|
||||||
|
uint8_t reg,
|
||||||
|
void *data,
|
||||||
|
size_t length);
|
||||||
|
#endif
|
||||||
|
#if CONFIG_FXLS8974_TRIGGER
|
||||||
|
int fxls8974_trigger_init(const struct device *dev);
|
||||||
|
int fxls8974_trigger_set(const struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler);
|
||||||
|
#endif
|
179
drivers/sensor/nxp/fxls8974/fxls8974_trigger.c
Normal file
179
drivers/sensor/nxp/fxls8974/fxls8974_trigger.c
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 NXP
|
||||||
|
* Copyright (c) 2018 Phytec Messtechnik GmbH
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT nxp_fxls8974
|
||||||
|
|
||||||
|
#include "fxls8974.h"
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(FXLS8974, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
static void fxls8974_gpio_callback(const struct device *dev,
|
||||||
|
struct gpio_callback *cb,
|
||||||
|
uint32_t pin_mask)
|
||||||
|
{
|
||||||
|
struct fxls8974_data *data =
|
||||||
|
CONTAINER_OF(cb, struct fxls8974_data, gpio_cb);
|
||||||
|
const struct fxls8974_config *config = data->dev->config;
|
||||||
|
|
||||||
|
if ((pin_mask & BIT(config->int_gpio.pin)) == 0U) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE);
|
||||||
|
|
||||||
|
#if defined(CONFIG_FXLS8974_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_give(&data->trig_sem);
|
||||||
|
#elif defined(CONFIG_FXLS8974_TRIGGER_GLOBAL_THREAD)
|
||||||
|
k_work_submit(&data->work);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fxls8974_handle_drdy_int(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
|
||||||
|
if (data->drdy_handler) {
|
||||||
|
data->drdy_handler(dev, data->drdy_trig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fxls8974_handle_int(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *config = dev->config;
|
||||||
|
|
||||||
|
fxls8974_handle_drdy_int(dev);
|
||||||
|
|
||||||
|
gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_LEVEL_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER_OWN_THREAD
|
||||||
|
static void fxls8974_thread_main(void *p1, void *p2, void *p3)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(p2);
|
||||||
|
ARG_UNUSED(p3);
|
||||||
|
|
||||||
|
struct fxls8974_data *data = p1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
k_sem_take(&data->trig_sem, K_FOREVER);
|
||||||
|
fxls8974_handle_int(data->dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_FXLS8974_TRIGGER_GLOBAL_THREAD
|
||||||
|
static void fxls8974_work_handler(struct k_work *work)
|
||||||
|
{
|
||||||
|
struct fxls8974_data *data =
|
||||||
|
CONTAINER_OF(work, struct fxls8974_data, work);
|
||||||
|
|
||||||
|
fxls8974_handle_int(data->dev);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int fxls8974_trigger_set(const struct device *dev,
|
||||||
|
const struct sensor_trigger *trig,
|
||||||
|
sensor_trigger_handler_t handler)
|
||||||
|
{
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
k_sem_take(&data->sem, K_FOREVER);
|
||||||
|
|
||||||
|
/* Put the sensor in standby mode */
|
||||||
|
if (fxls8974_set_active(dev, FXLS8974_ACTIVE_OFF)) {
|
||||||
|
LOG_ERR("Could not set standby mode");
|
||||||
|
ret = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trig->type == SENSOR_TRIG_DATA_READY) {
|
||||||
|
data->drdy_handler = handler;
|
||||||
|
data->drdy_trig = trig;
|
||||||
|
} else {
|
||||||
|
LOG_ERR("Unsupported sensor trigger");
|
||||||
|
ret = -ENOTSUP;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Restore the previous active mode */
|
||||||
|
if (fxls8974_set_active(dev, FXLS8974_ACTIVE_ON)) {
|
||||||
|
LOG_ERR("Could not restore active mode");
|
||||||
|
ret = -EIO;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fxls8974_trigger_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct fxls8974_config *config = dev->config;
|
||||||
|
struct fxls8974_data *data = dev->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data->dev = dev;
|
||||||
|
|
||||||
|
#if defined(CONFIG_FXLS8974_TRIGGER_OWN_THREAD)
|
||||||
|
k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT);
|
||||||
|
k_thread_create(&data->thread, data->thread_stack,
|
||||||
|
CONFIG_FXLS8974_THREAD_STACK_SIZE,
|
||||||
|
fxls8974_thread_main,
|
||||||
|
data, NULL, NULL,
|
||||||
|
K_PRIO_COOP(CONFIG_FXLS8974_THREAD_PRIORITY),
|
||||||
|
0, K_NO_WAIT);
|
||||||
|
#elif defined(CONFIG_FXLS8974_TRIGGER_GLOBAL_THREAD)
|
||||||
|
data->work.handler = fxls8974_work_handler;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (config->ops->byte_write(dev, FXLS8974_INTREG_EN,
|
||||||
|
FXLS8974_DRDY_MASK)) {
|
||||||
|
LOG_ERR("Could not enable interrupt");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(CONFIG_FXLS8974_DRDY_INT1)
|
||||||
|
if (config->ops->byte_write(dev, FXLS8974_INT_PIN_SEL_REG,
|
||||||
|
FXLS8974_DRDY_MASK)) {
|
||||||
|
LOG_ERR("Could not configure interrupt pin routing");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!gpio_is_ready_dt(&config->int_gpio)) {
|
||||||
|
LOG_ERR("GPIO device not ready");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_init_callback(&data->gpio_cb, fxls8974_gpio_callback,
|
||||||
|
BIT(config->int_gpio.pin));
|
||||||
|
|
||||||
|
ret = gpio_add_callback(config->int_gpio.port, &data->gpio_cb);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue