drivers: sensor: adi: Move to vendor subdirectory

Organizes sensor drivers by vendor to distribute maintainership
responsibilities.

Signed-off-by: Maureen Helm <maureen.helm@analog.com>
This commit is contained in:
Maureen Helm 2024-03-26 14:57:31 -05:00 committed by Anas Nashif
commit 8714f53188
45 changed files with 33 additions and 16 deletions

View file

@ -0,0 +1,11 @@
#
# Copyright (c) 2018 Analog Devices Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources(adxl372.c)
zephyr_library_sources(adxl372_spi.c)
zephyr_library_sources(adxl372_i2c.c)
zephyr_library_sources_ifdef(CONFIG_ADXL372_TRIGGER adxl372_trigger.c)

View file

@ -0,0 +1,124 @@
# Micropower, 3-Axis, +/-200g Digital Accelerometer
# Copyright (c) 2018 Analog Devices Inc.
# SPDX-License-Identifier: Apache-2.0
menuconfig ADXL372
bool "ADXL372 Three Axis High-g I2C/SPI accelerometer"
default y
depends on DT_HAS_ADI_ADXL372_ENABLED
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ADI_ADXL372),i2c)
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ADI_ADXL372),spi)
help
Enable driver for ADXL372 Three-Axis Digital Accelerometers.
if ADXL372
choice ADXL372_OP_MODE
prompt "Operating mode"
default ADXL372_PEAK_DETECT_MODE
config ADXL372_PEAK_DETECT_MODE
bool "Max Peak detect mode"
help
In most high-g applications, a single (3-axis) acceleration sample at
the peak of an impact event contains sufficient information
about the event, and the full acceleration history is not required.
In this mode the device returns only the over threshold
Peak Acceleration between two consecutive sample fetches.
config ADXL372_MEASUREMENT_MODE
bool "Measurement Mode"
help
In this mode, acceleration data is provided continuously at the
output data rate (ODR).
endchoice
config ADXL372_ACTIVITY_THRESHOLD
int "Activity threshold in mg"
range 0 200000
default 500
help
Threshold for activity detection.
config ADXL372_INACTIVITY_THRESHOLD
int "In-activity threshold in mg"
range 0 200000
default 400
help
Threshold for in-activity detection.
config ADXL372_ACTIVITY_TIME
int "Activity time"
range 0 255
default 1
help
The activity timer implements a robust activity detection that
minimizes false positive motion triggers. When the timer is used,
only sustained motion can trigger activity detection.
Number of multiples of 3.3 ms activity timer for which above threshold
acceleration is required to detect activity. It is 3.3 ms per code
for 6400 Hz ODR, and it is 6.6 ms per code for 3200 Hz ODR and below.
config ADXL372_INACTIVITY_TIME
int "In-activity time"
range 0 255
default 2
help
The time that all enabled axes must be lower than the inactivity
threshold for an inactivity event to be detected. Number of multiples
of 26 ms inactivity timer for which below threshold acceleration is
required to detect inactivity. It is 26 ms per code for 3200 Hz ODR
and below, and it is 13 ms per code for 6400 Hz ODR.
config ADXL372_REFERENCED_ACTIVITY_DETECTION_MODE
bool "Use referenced activity/in-activity detection"
default y
help
Activity detection can be configured as referenced or absolute.
When using absolute activity detection, acceleration samples are
compared directly to a user set threshold to determine whether
motion is present. In many applications, it is advantageous for
activity detection to be based not on an absolute threshold,
but on a deviation from a reference point or orientation.
choice ADXL372_TRIGGER_MODE
prompt "Trigger mode"
default ADXL372_TRIGGER_NONE
help
Specify the type of triggering used by the driver.
config ADXL372_TRIGGER_NONE
bool "No trigger"
config ADXL372_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select ADXL372_TRIGGER
config ADXL372_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select ADXL372_TRIGGER
endchoice
config ADXL372_TRIGGER
bool
config ADXL372_THREAD_PRIORITY
int "Thread priority"
depends on ADXL372_TRIGGER_OWN_THREAD && ADXL372_TRIGGER
default 10
help
Priority of thread used by the driver to handle interrupts.
config ADXL372_THREAD_STACK_SIZE
int "Thread stack size"
depends on ADXL372_TRIGGER_OWN_THREAD && ADXL372_TRIGGER
default 1024
help
Stack size of thread used by the driver to handle interrupts.
endif # ADXL372

View file

@ -0,0 +1,892 @@
/*
* Copyright (c) 2018 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_adxl372
#include <zephyr/drivers/sensor.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <string.h>
#include <zephyr/init.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/__assert.h>
#include <stdlib.h>
#include <zephyr/logging/log.h>
#include "adxl372.h"
LOG_MODULE_REGISTER(ADXL372, CONFIG_SENSOR_LOG_LEVEL);
/**
* Set the threshold for activity detection for a single axis
* @param dev - The device structure.
* @param axis_reg_h - The high part of the activity register.
* @param act - The activity config structure.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_activity_threshold(const struct device *dev,
uint8_t axis_reg_h,
const struct adxl372_activity_threshold *act)
{
int ret;
uint8_t val;
struct adxl372_data *data = dev->data;
ret = data->hw_tf->write_reg(dev, axis_reg_h++, act->thresh >> 3);
if (ret) {
return ret;
}
switch (axis_reg_h) {
case ADXL372_X_THRESH_ACT_L:
case ADXL372_X_THRESH_INACT_L:
case ADXL372_X_THRESH_ACT2_L:
val = (act->thresh << 5) | (act->referenced << 1) | act->enable;
break;
default:
val = (act->thresh << 5) | act->enable;
}
return data->hw_tf->write_reg(dev, axis_reg_h, val);
}
/**
* Set the threshold for activity detection for all 3-axis
* @param dev - The device structure.
* @param axis_reg_h - The high part of the activity register.
* @param act - The activity config structure.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_activity_threshold_xyz(const struct device *dev,
uint8_t axis_reg_h,
const struct adxl372_activity_threshold *act)
{
int i, ret;
for (i = 0; i < 3; i++) {
ret = adxl372_set_activity_threshold(dev, axis_reg_h, act);
if (ret) {
return ret;
}
axis_reg_h += 2U;
}
return 0;
}
/**
* Set the mode of operation.
* @param dev - The device structure.
* @param op_mode - Mode of operation.
* Accepted values: ADXL372_STANDBY
* ADXL372_WAKE_UP
* ADXL372_INSTANT_ON
* ADXL372_FULL_BW_MEASUREMENT
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_op_mode(const struct device *dev,
enum adxl372_op_mode op_mode)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_MODE_MSK,
ADXL372_POWER_CTL_MODE(op_mode));
}
/**
* Autosleep. When set to 1, autosleep is enabled, and the device enters
* wake-up mode automatically upon detection of inactivity.
* @param dev - The device structure.
* @param enable - Accepted values: true
* false
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_autosleep(const struct device *dev, bool enable)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
ADXL372_MEASURE_AUTOSLEEP_MSK,
ADXL372_MEASURE_AUTOSLEEP_MODE(enable));
}
/**
* Select the desired output signal bandwidth.
* @param dev - The device structure.
* @param bw - bandwidth.
* Accepted values: ADXL372_BW_200HZ
* ADXL372_BW_400HZ
* ADXL372_BW_800HZ
* ADXL372_BW_1600HZ
* ADXL372_BW_3200HZ
* ADXL372_BW_LPF_DISABLED
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_bandwidth(const struct device *dev,
enum adxl372_bandwidth bw)
{
int ret;
uint8_t mask;
struct adxl372_data *data = dev->data;
if (bw == ADXL372_BW_LPF_DISABLED) {
mask = ADXL372_POWER_CTL_LPF_DIS_MSK;
} else {
mask = 0U;
}
ret = data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_LPF_DIS_MSK, mask);
if (ret) {
return ret;
}
return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
ADXL372_MEASURE_BANDWIDTH_MSK,
ADXL372_MEASURE_BANDWIDTH_MODE(bw));
}
/**
* Select the desired high-pass filter corner.
* @param dev - The device structure.
* @param c - bandwidth.
* Accepted values: ADXL372_HPF_CORNER_0
* ADXL372_HPF_CORNER_1
* ADXL372_HPF_CORNER_2
* ADXL372_HPF_CORNER_3
* ADXL372_HPF_DISABLED
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_hpf_corner(const struct device *dev,
enum adxl372_hpf_corner c)
{
int ret;
uint8_t mask;
struct adxl372_data *data = dev->data;
if (c == ADXL372_HPF_DISABLED) {
mask = ADXL372_POWER_CTL_HPF_DIS_MSK;
} else {
mask = 0U;
}
ret = data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_HPF_DIS_MSK, mask);
if (ret) {
return ret;
}
return data->hw_tf->write_reg(dev, ADXL372_HPF, ADXL372_HPF_CORNER(c));
}
/**
* Link/Loop Activity Processing.
* @param dev - The device structure.
* @param mode - Mode of operation.
* Accepted values: ADXL372_DEFAULT
* ADXL372_LINKED
* ADXL372_LOOPED
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_act_proc_mode(const struct device *dev,
enum adxl372_act_proc_mode mode)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_MEASURE,
ADXL372_MEASURE_LINKLOOP_MSK,
ADXL372_MEASURE_LINKLOOP_MODE(mode));
}
/**
* Set Output data rate.
* @param dev - The device structure.
* @param odr - Output data rate.
* Accepted values: ADXL372_ODR_400HZ
* ADXL372_ODR_800HZ
* ADXL372_ODR_1600HZ
* ADXL372_ODR_3200HZ
* ADXL372_ODR_6400HZ
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_odr(const struct device *dev, enum adxl372_odr odr)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_TIMING,
ADXL372_TIMING_ODR_MSK,
ADXL372_TIMING_ODR_MODE(odr));
}
/**
* Select instant on threshold
* @param dev - The device structure.
* @param mode - 0 = low threshold, 1 = high threshold.
* Accepted values: ADXL372_INSTANT_ON_LOW_TH
* ADXL372_INSTANT_ON_HIGH_TH
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_instant_on_th(const struct device *dev,
enum adxl372_instant_on_th_mode mode)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_INSTANT_ON_TH_MSK,
ADXL372_POWER_CTL_INSTANT_ON_TH_MODE(mode));
}
/**
* Set the Timer Rate for Wake-Up Mode.
* @param dev - The device structure.
* @param wur - wake up mode rate
* Accepted values: ADXL372_WUR_52ms
* ADXL372_WUR_104ms
* ADXL372_WUR_208ms
* ADXL372_WUR_512ms
* ADXL372_WUR_2048ms
* ADXL372_WUR_4096ms
* ADXL372_WUR_8192ms
* ADXL372_WUR_24576ms
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_wakeup_rate(const struct device *dev,
enum adxl372_wakeup_rate wur)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_TIMING,
ADXL372_TIMING_WAKE_UP_RATE_MSK,
ADXL372_TIMING_WAKE_UP_RATE_MODE(wur));
}
/**
* Set the activity timer
* @param dev - The device structure.
* @param time - The value set in this register.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_activity_time(const struct device *dev, uint8_t time)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg(dev, ADXL372_TIME_ACT, time);
}
/**
* Set the inactivity timer
* @param dev - The device structure.
* @param time - is the 16-bit value set by the TIME_INACT_L register
* (eight LSBs) and the TIME_INACT_H register (eight MSBs).
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_inactivity_time(const struct device *dev,
uint16_t time)
{
int ret;
struct adxl372_data *data = dev->data;
ret = data->hw_tf->write_reg(dev, ADXL372_TIME_INACT_H, time >> 8);
if (ret) {
return ret;
}
return data->hw_tf->write_reg(dev, ADXL372_TIME_INACT_L, time & 0xFF);
}
/**
* Set the filter settling period.
* @param dev - The device structure.
* @param mode - settle period
* Accepted values: ADXL372_FILTER_SETTLE_370
* ADXL372_FILTER_SETTLE_16
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_set_filter_settle(const struct device *dev,
enum adxl372_filter_settle mode)
{
struct adxl372_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_FIL_SETTLE_MSK,
ADXL372_POWER_CTL_FIL_SETTLE_MODE(mode));
}
/**
* Configure the INT1 and INT2 interrupt pins.
* @param dev - The device structure.
* @param int1 - INT1 interrupt pins.
* @param int2 - INT2 interrupt pins.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_interrupt_config(const struct device *dev,
uint8_t int1,
uint8_t int2)
{
int ret;
struct adxl372_data *data = dev->data;
ret = data->hw_tf->write_reg(dev, ADXL372_INT1_MAP, int1);
if (ret) {
return ret;
}
return data->hw_tf->write_reg(dev, ADXL372_INT2_MAP, int2);
}
/**
* Get the STATUS, STATUS2, FIFO_ENTRIES and FIFO_ENTRIES2 registers data
* @param dev - The device structure.
* @param status1 - Data stored in the STATUS1 register
* @param status2 - Data stored in the STATUS2 register
* @param fifo_entries - Number of valid data samples present in the
* FIFO buffer (0 to 512)
* @return 0 in case of success, negative error code otherwise.
*/
int adxl372_get_status(const struct device *dev,
uint8_t *status1,
uint8_t *status2,
uint16_t *fifo_entries)
{
struct adxl372_data *data = dev->data;
uint8_t buf[4], length = 1U;
int ret;
if (status2) {
length++;
}
if (fifo_entries) {
length += 2U;
}
ret = data->hw_tf->read_reg_multiple(dev, ADXL372_STATUS_1, buf, length);
*status1 = buf[0];
if (status2) {
*status2 = buf[1];
}
if (fifo_entries) {
*fifo_entries = ((buf[2] & 0x3) << 8) | buf[3];
}
return ret;
}
/**
* Software reset.
* @param dev - The device structure.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_reset(const struct device *dev)
{
int ret;
struct adxl372_data *data = dev->data;
ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
if (ret) {
return ret;
}
/* Writing code 0x52 resets the device */
ret = data->hw_tf->write_reg(dev, ADXL372_RESET, ADXL372_RESET_CODE);
k_sleep(K_MSEC(1));
return ret;
}
/**
* Configure the operating parameters for the FIFO.
* @param dev - The device structure.
* @param mode - FIFO Mode. Specifies FIFO operating mode.
* Accepted values: ADXL372_FIFO_BYPASSED
* ADXL372_FIFO_STREAMED
* ADXL372_FIFO_TRIGGERED
* ADXL372_FIFO_OLD_SAVED
* @param format - FIFO Format. Specifies the data is stored in the FIFO buffer.
* Accepted values: ADXL372_XYZ_FIFO
* ADXL372_X_FIFO
* ADXL372_Y_FIFO
* ADXL372_XY_FIFO
* ADXL372_Z_FIFO
* ADXL372_XZ_FIFO
* ADXL372_YZ_FIFO
* ADXL372_XYZ_PEAK_FIFO
* @param fifo_samples - FIFO Samples. Watermark number of FIFO samples that
* triggers a FIFO_FULL condition when reached.
* Values range from 0 to 512.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_configure_fifo(const struct device *dev,
enum adxl372_fifo_mode mode,
enum adxl372_fifo_format format,
uint16_t fifo_samples)
{
struct adxl372_data *data = dev->data;
uint8_t fifo_config;
int ret;
if (fifo_samples > 512) {
return -EINVAL;
}
/*
* All FIFO modes must be configured while in standby mode.
*/
ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
if (ret) {
return ret;
}
fifo_config = (ADXL372_FIFO_CTL_FORMAT_MODE(format) |
ADXL372_FIFO_CTL_MODE_MODE(mode) |
ADXL372_FIFO_CTL_SAMPLES_MODE(fifo_samples));
ret = data->hw_tf->write_reg(dev, ADXL372_FIFO_CTL, fifo_config);
if (ret) {
return ret;
}
ret = data->hw_tf->write_reg(dev, ADXL372_FIFO_SAMPLES, fifo_samples & 0xFF);
if (ret) {
return ret;
}
data->fifo_config.fifo_format = format;
data->fifo_config.fifo_mode = mode;
data->fifo_config.fifo_samples = fifo_samples;
return 0;
}
/**
* Retrieve 3-axis acceleration data
* @param dev - The device structure.
* @param maxpeak - Retrieve the highest magnitude (x, y, z) sample recorded
* since the last read of the MAXPEAK registers
* @param accel_data - pointer to a variable of type adxl372_xyz_accel_data
* where (x, y, z) acceleration data will be stored.
* @return 0 in case of success, negative error code otherwise.
*/
static int adxl372_get_accel_data(const struct device *dev, bool maxpeak,
struct adxl372_xyz_accel_data *accel_data)
{
struct adxl372_data *data = dev->data;
uint8_t buf[6];
uint8_t status1;
int ret;
if (!IS_ENABLED(CONFIG_ADXL372_TRIGGER)) {
do {
adxl372_get_status(dev, &status1, NULL, NULL);
} while (!(ADXL372_STATUS_1_DATA_RDY(status1)));
}
ret = data->hw_tf->read_reg_multiple(dev, maxpeak ? ADXL372_X_MAXPEAK_H :
ADXL372_X_DATA_H, buf, 6);
accel_data->x = (buf[0] << 8) | (buf[1] & 0xF0);
accel_data->y = (buf[2] << 8) | (buf[3] & 0xF0);
accel_data->z = (buf[4] << 8) | (buf[5] & 0xF0);
return ret;
}
static int adxl372_attr_set_odr(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
enum adxl372_odr odr;
switch (val->val1) {
case 400:
odr = ADXL372_ODR_400HZ;
break;
case 800:
odr = ADXL372_ODR_800HZ;
break;
case 1600:
odr = ADXL372_ODR_1600HZ;
break;
case 3200:
odr = ADXL372_ODR_3200HZ;
break;
case 6400:
odr = ADXL372_ODR_6400HZ;
break;
default:
return -EINVAL;
}
return adxl372_set_odr(dev, odr);
}
static int adxl372_attr_set_thresh(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_activity_threshold threshold;
int64_t llvalue;
int32_t value;
int64_t micro_ms2 = val->val1 * 1000000LL + val->val2;
uint8_t reg;
llvalue = llabs((micro_ms2 * 10) / SENSOR_G);
if (llvalue > 2047) {
return -EINVAL;
}
value = (int32_t) llvalue;
threshold.thresh = value;
threshold.enable = cfg->activity_th.enable;
threshold.referenced = cfg->activity_th.referenced;
if (attr == SENSOR_ATTR_UPPER_THRESH) {
reg = ADXL372_X_THRESH_ACT_H;
} else {
reg = ADXL372_X_THRESH_INACT_H;
}
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
return adxl372_set_activity_threshold(dev, reg, &threshold);
case SENSOR_CHAN_ACCEL_Y:
return adxl372_set_activity_threshold(dev, reg + 2, &threshold);
case SENSOR_CHAN_ACCEL_Z:
return adxl372_set_activity_threshold(dev, reg + 4, &threshold);
case SENSOR_CHAN_ACCEL_XYZ:
return adxl372_set_activity_threshold_xyz(dev, reg, &threshold);
default:
LOG_ERR("attr_set() not supported on this channel");
return -ENOTSUP;
}
}
static int adxl372_attr_set(const struct device *dev,
enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return adxl372_attr_set_odr(dev, chan, attr, val);
case SENSOR_ATTR_UPPER_THRESH:
case SENSOR_ATTR_LOWER_THRESH:
return adxl372_attr_set_thresh(dev, chan, attr, val);
default:
return -ENOTSUP;
}
}
static int adxl372_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_data *data = dev->data;
return adxl372_get_accel_data(dev, cfg->max_peak_detect_mode,
&data->sample);
}
static void adxl372_accel_convert(struct sensor_value *val, int16_t value)
{
/*
* Sensor resolution is 100mg/LSB, 12-bit value needs to be right
* shifted by 4 or divided by 16. Overall this results in a scale of 160
*/
int32_t micro_ms2 = value * (SENSOR_G / (16 * 1000 / 100));
val->val1 = micro_ms2 / 1000000;
val->val2 = micro_ms2 % 1000000;
}
static int adxl372_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct adxl372_data *data = dev->data;
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
adxl372_accel_convert(val, data->sample.x);
break;
case SENSOR_CHAN_ACCEL_Y:
adxl372_accel_convert(val, data->sample.y);
break;
case SENSOR_CHAN_ACCEL_Z:
adxl372_accel_convert(val, data->sample.z);
break;
case SENSOR_CHAN_ACCEL_XYZ:
adxl372_accel_convert(val++, data->sample.x);
adxl372_accel_convert(val++, data->sample.y);
adxl372_accel_convert(val, data->sample.z);
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct sensor_driver_api adxl372_api_funcs = {
.attr_set = adxl372_attr_set,
.sample_fetch = adxl372_sample_fetch,
.channel_get = adxl372_channel_get,
#ifdef CONFIG_ADXL372_TRIGGER
.trigger_set = adxl372_trigger_set,
#endif
};
static int adxl372_probe(const struct device *dev)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_data *data = dev->data;
uint8_t dev_id, part_id;
int ret;
ret = data->hw_tf->read_reg(dev, ADXL372_DEVID, &dev_id);
if (ret) {
return ret;
}
ret = data->hw_tf->read_reg(dev, ADXL372_PARTID, &part_id);
if (ret) {
return ret;
}
if (dev_id != ADXL372_DEVID_VAL || part_id != ADXL372_PARTID_VAL) {
LOG_ERR("failed to read id (0x%X:0x%X)", dev_id, part_id);
return -ENODEV;
}
#ifdef CONFIG_ADXL372_TRIGGER
data->act_proc_mode = ADXL372_LINKED,
#else
data->act_proc_mode = ADXL372_LOOPED,
#endif
/* Device settings */
ret = adxl372_set_op_mode(dev, ADXL372_STANDBY);
if (ret) {
return ret;
}
ret = adxl372_reset(dev);
if (ret) {
return ret;
}
ret = adxl372_set_hpf_corner(dev, cfg->hpf);
if (ret) {
return ret;
}
ret = adxl372_set_bandwidth(dev, cfg->bw);
if (ret) {
return ret;
}
ret = adxl372_set_odr(dev, cfg->odr);
if (ret) {
return ret;
}
ret = adxl372_set_wakeup_rate(dev, cfg->wur);
if (ret) {
return ret;
}
ret = adxl372_set_autosleep(dev, cfg->autosleep);
if (ret) {
return ret;
}
ret = adxl372_set_instant_on_th(dev, cfg->th_mode);
if (ret) {
return ret;
}
ret = adxl372_set_activity_threshold_xyz(dev, ADXL372_X_THRESH_ACT_H,
&cfg->activity_th);
if (ret) {
return ret;
}
ret = adxl372_set_activity_threshold_xyz(dev, ADXL372_X_THRESH_INACT_H,
&cfg->inactivity_th);
if (ret) {
return ret;
}
ret = adxl372_set_activity_time(dev, cfg->activity_time);
if (ret) {
return ret;
}
ret = adxl372_set_inactivity_time(dev, cfg->inactivity_time);
if (ret) {
return ret;
}
ret = adxl372_set_filter_settle(dev, cfg->filter_settle);
if (ret) {
return ret;
}
ret = adxl372_configure_fifo(dev, cfg->fifo_config.fifo_mode,
cfg->fifo_config.fifo_format,
cfg->fifo_config.fifo_samples);
if (ret) {
return ret;
}
#ifdef CONFIG_ADXL372_TRIGGER
if (adxl372_init_interrupt(dev) < 0) {
LOG_ERR("Failed to initialize interrupt!");
return -EIO;
}
#endif
ret = adxl372_interrupt_config(dev, cfg->int1_config, cfg->int2_config);
if (ret) {
return ret;
}
ret = adxl372_set_op_mode(dev, cfg->op_mode);
if (ret) {
return ret;
}
return adxl372_set_act_proc_mode(dev, data->act_proc_mode);
}
static int adxl372_init(const struct device *dev)
{
int ret;
const struct adxl372_dev_config *cfg = dev->config;
ret = cfg->bus_init(dev);
if (ret < 0) {
LOG_ERR("Failed to initialize sensor bus");
return ret;
}
if (adxl372_probe(dev) < 0) {
return -ENODEV;
}
return 0;
}
#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "ADXL372 driver enabled without any devices"
#endif
/*
* Device creation macro, shared by ADXL372_DEFINE_SPI() and
* ADXL372_DEFINE_I2C().
*/
#define ADXL372_DEVICE_INIT(inst) \
SENSOR_DEVICE_DT_INST_DEFINE(inst, \
adxl372_init, \
NULL, \
&adxl372_data_##inst, \
&adxl372_config_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&adxl372_api_funcs);
/*
* Instantiation macros used when a device is on a SPI bus.
*/
#ifdef CONFIG_ADXL372_TRIGGER
#define ADXL372_CFG_IRQ(inst) \
.interrupt = GPIO_DT_SPEC_INST_GET(inst, int1_gpios),
#else
#define ADXL372_CFG_IRQ(inst)
#endif /* CONFIG_ADXL372_TRIGGER */
#define ADXL372_CONFIG(inst) \
.bw = DT_INST_PROP(inst, bw), \
.hpf = DT_INST_PROP(inst, hpf), \
.odr = DT_INST_PROP(inst, odr), \
.max_peak_detect_mode = IS_ENABLED(CONFIG_ADXL372_PEAK_DETECT_MODE), \
.th_mode = ADXL372_INSTANT_ON_LOW_TH, \
.autosleep = false, \
.wur = ADXL372_WUR_52ms, \
.activity_th.thresh = CONFIG_ADXL372_ACTIVITY_THRESHOLD / 100, \
.activity_th.referenced = \
IS_ENABLED(CONFIG_ADXL372_REFERENCED_ACTIVITY_DETECTION_MODE), \
.activity_th.enable = 1, \
.activity_time = CONFIG_ADXL372_ACTIVITY_TIME, \
.inactivity_th.thresh = CONFIG_ADXL372_INACTIVITY_THRESHOLD / 100, \
.inactivity_th.referenced = \
IS_ENABLED(CONFIG_ADXL372_REFERENCED_ACTIVITY_DETECTION_MODE), \
.inactivity_th.enable = 1, \
.inactivity_time = CONFIG_ADXL372_INACTIVITY_TIME, \
.filter_settle = ADXL372_FILTER_SETTLE_370, \
.fifo_config.fifo_mode = ADXL372_FIFO_STREAMED, \
.fifo_config.fifo_format = ADXL372_XYZ_PEAK_FIFO, \
.fifo_config.fifo_samples = 128, \
.op_mode = ADXL372_FULL_BW_MEASUREMENT, \
#define ADXL372_CONFIG_SPI(inst) \
{ \
.bus_init = adxl372_spi_init, \
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \
SPI_TRANSFER_MSB, 0), \
ADXL372_CONFIG(inst) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \
(ADXL372_CFG_IRQ(inst)), ()) \
}
#define ADXL372_DEFINE_SPI(inst) \
static struct adxl372_data adxl372_data_##inst; \
static const struct adxl372_dev_config adxl372_config_##inst = \
ADXL372_CONFIG_SPI(inst); \
ADXL372_DEVICE_INIT(inst)
/*
* Instantiation macros used when a device is on an I2C bus.
*/
#define ADXL372_CONFIG_I2C(inst) \
{ \
.bus_init = adxl372_i2c_init, \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
ADXL372_CONFIG(inst) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \
(ADXL372_CFG_IRQ(inst)), ()) \
}
#define ADXL372_DEFINE_I2C(inst) \
static struct adxl372_data adxl372_data_##inst; \
static const struct adxl372_dev_config adxl372_config_##inst = \
ADXL372_CONFIG_I2C(inst); \
ADXL372_DEVICE_INIT(inst)
/*
* Main instantiation macro. Use of COND_CODE_1() selects the right
* bus-specific macro at preprocessor time.
*/
#define ADXL372_DEFINE(inst) \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(ADXL372_DEFINE_SPI(inst)), \
(ADXL372_DEFINE_I2C(inst)))
DT_INST_FOREACH_STATUS_OKAY(ADXL372_DEFINE)

View file

@ -0,0 +1,375 @@
/*
* Copyright (c) 2018 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_ADXL372_ADXL372_H_
#define ZEPHYR_DRIVERS_SENSOR_ADXL372_ADXL372_H_
#include <zephyr/drivers/sensor.h>
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <zephyr/drivers/spi.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
#include <zephyr/drivers/i2c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
/*
* ADXL372 registers definition
*/
#define ADXL372_DEVID 0x00u /* Analog Devices accelerometer ID */
#define ADXL372_DEVID_MST 0x01u /* Analog Devices MEMS device ID */
#define ADXL372_PARTID 0x02u /* Device ID */
#define ADXL372_REVID 0x03u /* product revision ID*/
#define ADXL372_STATUS_1 0x04u /* Status register 1 */
#define ADXL372_STATUS_2 0x05u /* Status register 2 */
#define ADXL372_FIFO_ENTRIES_2 0x06u /* Valid data samples in the FIFO */
#define ADXL372_FIFO_ENTRIES_1 0x07u /* Valid data samples in the FIFO */
#define ADXL372_X_DATA_H 0x08u /* X-axis acceleration data [11:4] */
#define ADXL372_X_DATA_L 0x09u /* X-axis acceleration data [3:0] */
#define ADXL372_Y_DATA_H 0x0Au /* Y-axis acceleration data [11:4] */
#define ADXL372_Y_DATA_L 0x0Bu /* Y-axis acceleration data [3:0] */
#define ADXL372_Z_DATA_H 0x0Cu /* Z-axis acceleration data [11:4] */
#define ADXL372_Z_DATA_L 0x0Du /* Z-axis acceleration data [3:0] */
#define ADXL372_X_MAXPEAK_H 0x15u /* X-axis MaxPeak acceleration data */
#define ADXL372_X_MAXPEAK_L 0x16u /* X-axis MaxPeak acceleration data */
#define ADXL372_Y_MAXPEAK_H 0x17u /* Y-axis MaxPeak acceleration data */
#define ADXL372_Y_MAXPEAK_L 0x18u /* Y-axis MaxPeak acceleration data */
#define ADXL372_Z_MAXPEAK_H 0x19u /* Z-axis MaxPeak acceleration data */
#define ADXL372_Z_MAXPEAK_L 0x1Au /* Z-axis MaxPeak acceleration data */
#define ADXL372_OFFSET_X 0x20u /* X axis offset */
#define ADXL372_OFFSET_Y 0x21u /* Y axis offset */
#define ADXL372_OFFSET_Z 0x22u /* Z axis offset */
#define ADXL372_X_THRESH_ACT_H 0x23u /* X axis Activity Threshold [15:8] */
#define ADXL372_X_THRESH_ACT_L 0x24u /* X axis Activity Threshold [7:0] */
#define ADXL372_Y_THRESH_ACT_H 0x25u /* Y axis Activity Threshold [15:8] */
#define ADXL372_Y_THRESH_ACT_L 0x26u /* Y axis Activity Threshold [7:0] */
#define ADXL372_Z_THRESH_ACT_H 0x27u /* Z axis Activity Threshold [15:8] */
#define ADXL372_Z_THRESH_ACT_L 0x28u /* Z axis Activity Threshold [7:0] */
#define ADXL372_TIME_ACT 0x29u /* Activity Time */
#define ADXL372_X_THRESH_INACT_H 0x2Au /* X axis Inactivity Threshold */
#define ADXL372_X_THRESH_INACT_L 0x2Bu /* X axis Inactivity Threshold */
#define ADXL372_Y_THRESH_INACT_H 0x2Cu /* Y axis Inactivity Threshold */
#define ADXL372_Y_THRESH_INACT_L 0x2Du /* Y axis Inactivity Threshold */
#define ADXL372_Z_THRESH_INACT_H 0x2Eu /* Z axis Inactivity Threshold */
#define ADXL372_Z_THRESH_INACT_L 0x2Fu /* Z axis Inactivity Threshold */
#define ADXL372_TIME_INACT_H 0x30u /* Inactivity Time [15:8] */
#define ADXL372_TIME_INACT_L 0x31u /* Inactivity Time [7:0] */
#define ADXL372_X_THRESH_ACT2_H 0x32u /* X axis Activity2 Threshold [15:8] */
#define ADXL372_X_THRESH_ACT2_L 0x33u /* X axis Activity2 Threshold [7:0] */
#define ADXL372_Y_THRESH_ACT2_H 0x34u /* Y axis Activity2 Threshold [15:8] */
#define ADXL372_Y_THRESH_ACT2_L 0x35u /* Y axis Activity2 Threshold [7:0] */
#define ADXL372_Z_THRESH_ACT2_H 0x36u /* Z axis Activity2 Threshold [15:8] */
#define ADXL372_Z_THRESH_ACT2_L 0x37u /* Z axis Activity2 Threshold [7:0] */
#define ADXL372_HPF 0x38u /* High Pass Filter */
#define ADXL372_FIFO_SAMPLES 0x39u /* FIFO Samples */
#define ADXL372_FIFO_CTL 0x3Au /* FIFO Control */
#define ADXL372_INT1_MAP 0x3Bu /* Interrupt 1 mapping control */
#define ADXL372_INT2_MAP 0x3Cu /* Interrupt 2 mapping control */
#define ADXL372_TIMING 0x3Du /* Timing */
#define ADXL372_MEASURE 0x3Eu /* Measure */
#define ADXL372_POWER_CTL 0x3Fu /* Power control */
#define ADXL372_SELF_TEST 0x40u /* Self Test */
#define ADXL372_RESET 0x41u /* Reset */
#define ADXL372_FIFO_DATA 0x42u /* FIFO Data */
#define ADXL372_DEVID_VAL 0xADu /* Analog Devices accelerometer ID */
#define ADXL372_MST_DEVID_VAL 0x1Du /* Analog Devices MEMS device ID */
#define ADXL372_PARTID_VAL 0xFAu /* Device ID */
#define ADXL372_REVID_VAL 0x02u /* product revision ID*/
#define ADXL372_RESET_CODE 0x52u /* Writing code 0x52 resets the device */
#define ADXL372_READ 0x01u
#define ADXL372_REG_READ(x) (((x & 0xFF) << 1) | ADXL372_READ)
#define ADXL372_REG_WRITE(x) ((x & 0xFF) << 1)
#define ADXL372_TO_I2C_REG(x) ((x) >> 1)
/* ADXL372_POWER_CTL */
#define ADXL372_POWER_CTL_INSTANT_ON_TH_MSK BIT(5)
#define ADXL372_POWER_CTL_INSTANT_ON_TH_MODE(x) (((x) & 0x1) << 5)
#define ADXL372_POWER_CTL_FIL_SETTLE_MSK BIT(4)
#define ADXL372_POWER_CTL_FIL_SETTLE_MODE(x) (((x) & 0x1) << 4)
#define ADXL372_POWER_CTL_LPF_DIS_MSK BIT(3)
#define ADXL372_POWER_CTL_LPF_DIS_MODE(x) (((x) & 0x1) << 3)
#define ADXL372_POWER_CTL_HPF_DIS_MSK BIT(2)
#define ADXL372_POWER_CTL_HPF_DIS_MODE(x) (((x) & 0x1) << 2)
#define ADXL372_POWER_CTL_MODE_MSK GENMASK(1, 0)
#define ADXL372_POWER_CTL_MODE(x) (((x) & 0x3) << 0)
/* ADXL372_MEASURE */
#define ADXL372_MEASURE_AUTOSLEEP_MSK BIT(6)
#define ADXL372_MEASURE_AUTOSLEEP_MODE(x) (((x) & 0x1) << 6)
#define ADXL372_MEASURE_LINKLOOP_MSK GENMASK(5, 4)
#define ADXL372_MEASURE_LINKLOOP_MODE(x) (((x) & 0x3) << 4)
#define ADXL372_MEASURE_LOW_NOISE_MSK BIT(3)
#define ADXL372_MEASURE_LOW_NOISE_MODE(x) (((x) & 0x1) << 3)
#define ADXL372_MEASURE_BANDWIDTH_MSK GENMASK(2, 0)
#define ADXL372_MEASURE_BANDWIDTH_MODE(x) (((x) & 0x7) << 0)
/* ADXL372_TIMING */
#define ADXL372_TIMING_ODR_MSK GENMASK(7, 5)
#define ADXL372_TIMING_ODR_MODE(x) (((x) & 0x7) << 5)
#define ADXL372_TIMING_WAKE_UP_RATE_MSK GENMASK(4, 2)
#define ADXL372_TIMING_WAKE_UP_RATE_MODE(x) (((x) & 0x7) << 2)
#define ADXL372_TIMING_EXT_CLK_MSK BIT(1)
#define ADXL372_TIMING_EXT_CLK_MODE(x) (((x) & 0x1) << 1)
#define ADXL372_TIMING_EXT_SYNC_MSK BIT(0)
#define ADXL372_TIMING_EXT_SYNC_MODE(x) (((x) & 0x1) << 0)
/* ADXL372_FIFO_CTL */
#define ADXL372_FIFO_CTL_FORMAT_MSK GENMASK(5, 3)
#define ADXL372_FIFO_CTL_FORMAT_MODE(x) (((x) & 0x7) << 3)
#define ADXL372_FIFO_CTL_MODE_MSK GENMASK(2, 1)
#define ADXL372_FIFO_CTL_MODE_MODE(x) (((x) & 0x3) << 1)
#define ADXL372_FIFO_CTL_SAMPLES_MSK BIT(0)
#define ADXL372_FIFO_CTL_SAMPLES_MODE(x) (((x) > 0xFF) ? 1 : 0)
/* ADXL372_STATUS_1 */
#define ADXL372_STATUS_1_DATA_RDY(x) (((x) >> 0) & 0x1)
#define ADXL372_STATUS_1_FIFO_RDY(x) (((x) >> 1) & 0x1)
#define ADXL372_STATUS_1_FIFO_FULL(x) (((x) >> 2) & 0x1)
#define ADXL372_STATUS_1_FIFO_OVR(x) (((x) >> 3) & 0x1)
#define ADXL372_STATUS_1_USR_NVM_BUSY(x) (((x) >> 5) & 0x1)
#define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1)
#define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1)
/* ADXL372_STATUS_2 */
#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1)
#define ADXL372_STATUS_2_ACTIVITY(x) (((x) >> 5) & 0x1)
#define ADXL372_STATUS_2_ACTIVITY2(x) (((x) >> 6) & 0x1)
/* ADXL372_INT1_MAP */
#define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0)
#define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
#define ADXL372_INT1_MAP_FIFO_RDY_MSK BIT(1)
#define ADXL372_INT1_MAP_FIFO_RDY_MODE(x) (((x) & 0x1) << 1)
#define ADXL372_INT1_MAP_FIFO_FULL_MSK BIT(2)
#define ADXL372_INT1_MAP_FIFO_FULL_MODE(x) (((x) & 0x1) << 2)
#define ADXL372_INT1_MAP_FIFO_OVR_MSK BIT(3)
#define ADXL372_INT1_MAP_FIFO_OVR_MODE(x) (((x) & 0x1) << 3)
#define ADXL372_INT1_MAP_INACT_MSK BIT(4)
#define ADXL372_INT1_MAP_INACT_MODE(x) (((x) & 0x1) << 4)
#define ADXL372_INT1_MAP_ACT_MSK BIT(5)
#define ADXL372_INT1_MAP_ACT_MODE(x) (((x) & 0x1) << 5)
#define ADXL372_INT1_MAP_AWAKE_MSK BIT(6)
#define ADXL372_INT1_MAP_AWAKE_MODE(x) (((x) & 0x1) << 6)
#define ADXL372_INT1_MAP_LOW_MSK BIT(7)
#define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
/* ADXL372_INT2_MAP */
#define ADXL372_INT2_MAP_DATA_RDY_MSK BIT(0)
#define ADXL372_INT2_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
#define ADXL372_INT2_MAP_FIFO_RDY_MSK BIT(1)
#define ADXL372_INT2_MAP_FIFO_RDY_MODE(x) (((x) & 0x1) << 1)
#define ADXL372_INT2_MAP_FIFO_FULL_MSK BIT(2)
#define ADXL372_INT2_MAP_FIFO_FULL_MODE(x) (((x) & 0x1) << 2)
#define ADXL372_INT2_MAP_FIFO_OVR_MSK BIT(3)
#define ADXL372_INT2_MAP_FIFO_OVR_MODE(x) (((x) & 0x1) << 3)
#define ADXL372_INT2_MAP_INACT_MSK BIT(4)
#define ADXL372_INT2_MAP_INACT_MODE(x) (((x) & 0x1) << 4)
#define ADXL372_INT2_MAP_ACT_MSK BIT(5)
#define ADXL372_INT2_MAP_ACT_MODE(x) (((x) & 0x1) << 5)
#define ADXL372_INT2_MAP_AWAKE_MSK BIT(6)
#define ADXL372_INT2_MAP_AWAKE_MODE(x) (((x) & 0x1) << 6)
#define ADXL372_INT2_MAP_LOW_MSK BIT(7)
#define ADXL372_INT2_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
/* ADXL372_HPF */
#define ADXL372_HPF_CORNER(x) (((x) & 0x3) << 0)
enum adxl372_axis {
ADXL372_X_AXIS,
ADXL372_Y_AXIS,
ADXL372_Z_AXIS
};
enum adxl372_op_mode {
ADXL372_STANDBY,
ADXL372_WAKE_UP,
ADXL372_INSTANT_ON,
ADXL372_FULL_BW_MEASUREMENT
};
enum adxl372_bandwidth {
ADXL372_BW_200HZ,
ADXL372_BW_400HZ,
ADXL372_BW_800HZ,
ADXL372_BW_1600HZ,
ADXL372_BW_3200HZ,
ADXL372_BW_LPF_DISABLED = 0xC,
};
enum adxl372_hpf_corner {
ADXL372_HPF_CORNER_0,
ADXL372_HPF_CORNER_1,
ADXL372_HPF_CORNER_2,
ADXL372_HPF_CORNER_3,
ADXL372_HPF_DISABLED,
};
enum adxl372_act_proc_mode {
ADXL372_DEFAULT,
ADXL372_LINKED,
ADXL372_LOOPED
};
enum adxl372_odr {
ADXL372_ODR_400HZ,
ADXL372_ODR_800HZ,
ADXL372_ODR_1600HZ,
ADXL372_ODR_3200HZ,
ADXL372_ODR_6400HZ
};
enum adxl372_instant_on_th_mode {
ADXL372_INSTANT_ON_LOW_TH,
ADXL372_INSTANT_ON_HIGH_TH
};
enum adxl372_wakeup_rate {
ADXL372_WUR_52ms,
ADXL372_WUR_104ms,
ADXL372_WUR_208ms,
ADXL372_WUR_512ms,
ADXL372_WUR_2048ms,
ADXL372_WUR_4096ms,
ADXL372_WUR_8192ms,
ADXL372_WUR_24576ms
};
enum adxl372_filter_settle {
ADXL372_FILTER_SETTLE_370,
ADXL372_FILTER_SETTLE_16
};
enum adxl372_fifo_format {
ADXL372_XYZ_FIFO,
ADXL372_X_FIFO,
ADXL372_Y_FIFO,
ADXL372_XY_FIFO,
ADXL372_Z_FIFO,
ADXL372_XZ_FIFO,
ADXL372_YZ_FIFO,
ADXL372_XYZ_PEAK_FIFO,
};
enum adxl372_fifo_mode {
ADXL372_FIFO_BYPASSED,
ADXL372_FIFO_STREAMED,
ADXL372_FIFO_TRIGGERED,
ADXL372_FIFO_OLD_SAVED
};
struct adxl372_fifo_config {
enum adxl372_fifo_mode fifo_mode;
enum adxl372_fifo_format fifo_format;
uint16_t fifo_samples;
};
struct adxl372_activity_threshold {
uint16_t thresh;
bool referenced;
bool enable;
};
struct adxl372_xyz_accel_data {
int16_t x;
int16_t y;
int16_t z;
};
struct adxl372_transfer_function {
int (*read_reg_multiple)(const struct device *dev, uint8_t reg_addr,
uint8_t *value, uint16_t len);
int (*write_reg)(const struct device *dev, uint8_t reg_addr,
uint8_t value);
int (*read_reg)(const struct device *dev, uint8_t reg_addr,
uint8_t *value);
int (*write_reg_mask)(const struct device *dev, uint8_t reg_addr,
uint32_t mask, uint8_t value);
};
struct adxl372_data {
struct adxl372_xyz_accel_data sample;
const struct adxl372_transfer_function *hw_tf;
struct adxl372_fifo_config fifo_config;
enum adxl372_act_proc_mode act_proc_mode;
#ifdef CONFIG_ADXL372_TRIGGER
struct gpio_callback gpio_cb;
sensor_trigger_handler_t th_handler;
const struct sensor_trigger *th_trigger;
sensor_trigger_handler_t drdy_handler;
const struct sensor_trigger *drdy_trigger;
const struct device *dev;
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ADXL372_THREAD_STACK_SIZE);
struct k_sem gpio_sem;
struct k_thread thread;
#elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_ADXL372_TRIGGER */
};
struct adxl372_dev_config {
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
struct i2c_dt_spec i2c;
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
struct spi_dt_spec spi;
#endif
int (*bus_init)(const struct device *dev);
#ifdef CONFIG_ADXL372_TRIGGER
struct gpio_dt_spec interrupt;
#endif
enum adxl372_bandwidth bw;
enum adxl372_hpf_corner hpf;
enum adxl372_odr odr;
bool max_peak_detect_mode;
/* Device Settings */
bool autosleep;
struct adxl372_activity_threshold activity_th;
struct adxl372_activity_threshold activity2_th;
struct adxl372_activity_threshold inactivity_th;
struct adxl372_fifo_config fifo_config;
enum adxl372_wakeup_rate wur;
enum adxl372_instant_on_th_mode th_mode;
enum adxl372_filter_settle filter_settle;
enum adxl372_op_mode op_mode;
uint16_t inactivity_time;
uint8_t activity_time;
uint8_t int1_config;
uint8_t int2_config;
};
int adxl372_spi_init(const struct device *dev);
int adxl372_i2c_init(const struct device *dev);
#ifdef CONFIG_ADXL372_TRIGGER
int adxl372_get_status(const struct device *dev,
uint8_t *status1, uint8_t *status2, uint16_t *fifo_entries);
int adxl372_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int adxl372_init_interrupt(const struct device *dev);
#endif /* CONFIG_ADXL372_TRIGGER */
#endif /* ZEPHYR_DRIVERS_SENSOR_ADXL372_ADXL372_H_ */

View file

@ -0,0 +1,104 @@
/* adxl372_i2c.c - I2C routines for ADXL372 driver
*/
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_adxl372
#include <string.h>
#include <zephyr/logging/log.h>
#include "adxl372.h"
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
LOG_MODULE_DECLARE(ADXL372, CONFIG_SENSOR_LOG_LEVEL);
static int adxl372_bus_access(const struct device *dev, uint8_t reg,
void *data, size_t length)
{
const struct adxl372_dev_config *config = dev->config;
if (reg & ADXL372_READ) {
return i2c_burst_read_dt(&config->i2c,
ADXL372_TO_I2C_REG(reg),
(uint8_t *) data, length);
} else {
if (length != 1) {
return -EINVAL;
}
return i2c_reg_write_byte_dt(&config->i2c,
ADXL372_TO_I2C_REG(reg),
*(uint8_t *)data);
}
}
static int adxl372_i2c_reg_read(const struct device *dev, uint8_t reg_addr,
uint8_t *reg_data)
{
return adxl372_bus_access(dev, ADXL372_REG_READ(reg_addr), reg_data, 1);
}
static int adxl372_i2c_reg_read_multiple(const struct device *dev,
uint8_t reg_addr,
uint8_t *reg_data,
uint16_t count)
{
return adxl372_bus_access(dev, ADXL372_REG_READ(reg_addr),
reg_data, count);
}
static int adxl372_i2c_reg_write(const struct device *dev,
uint8_t reg_addr,
uint8_t reg_data)
{
return adxl372_bus_access(dev, ADXL372_REG_WRITE(reg_addr),
&reg_data, 1);
}
int adxl372_i2c_reg_write_mask(const struct device *dev,
uint8_t reg_addr,
uint32_t mask,
uint8_t data)
{
int ret;
uint8_t tmp;
ret = adxl372_i2c_reg_read(dev, reg_addr, &tmp);
if (ret) {
return ret;
}
tmp &= ~mask;
tmp |= data;
return adxl372_i2c_reg_write(dev, reg_addr, tmp);
}
static const struct adxl372_transfer_function adxl372_i2c_transfer_fn = {
.read_reg_multiple = adxl372_i2c_reg_read_multiple,
.write_reg = adxl372_i2c_reg_write,
.read_reg = adxl372_i2c_reg_read,
.write_reg_mask = adxl372_i2c_reg_write_mask,
};
int adxl372_i2c_init(const struct device *dev)
{
struct adxl372_data *data = dev->data;
const struct adxl372_dev_config *config = dev->config;
data->hw_tf = &adxl372_i2c_transfer_fn;
if (!device_is_ready(config->i2c.bus)) {
return -ENODEV;
}
return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

View file

@ -0,0 +1,119 @@
/* adxl372_spi.c - SPI routines for ADXL372 driver
*/
/*
* Copyright (c) 2022 Analog Devices
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_adxl372
#include <string.h>
#include <zephyr/logging/log.h>
#include "adxl372.h"
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
LOG_MODULE_DECLARE(ADXL372, CONFIG_SENSOR_LOG_LEVEL);
static int adxl372_bus_access(const struct device *dev, uint8_t reg,
void *data, size_t length)
{
const struct adxl372_dev_config *config = dev->config;
const struct spi_buf buf[2] = {
{
.buf = &reg,
.len = 1
}, {
.buf = data,
.len = length
}
};
struct spi_buf_set tx = {
.buffers = buf,
};
if (reg & ADXL372_READ) {
const struct spi_buf_set rx = {
.buffers = buf,
.count = 2
};
tx.count = 1;
return spi_transceive_dt(&config->spi, &tx, &rx);
}
tx.count = 2;
return spi_write_dt(&config->spi, &tx);
}
static int adxl372_spi_reg_read(const struct device *dev, uint8_t reg_addr,
uint8_t *reg_data)
{
return adxl372_bus_access(dev, ADXL372_REG_READ(reg_addr), reg_data, 1);
}
static int adxl372_spi_reg_read_multiple(const struct device *dev,
uint8_t reg_addr,
uint8_t *reg_data,
uint16_t count)
{
return adxl372_bus_access(dev, ADXL372_REG_READ(reg_addr),
reg_data, count);
}
static int adxl372_spi_reg_write(const struct device *dev,
uint8_t reg_addr,
uint8_t reg_data)
{
return adxl372_bus_access(dev, ADXL372_REG_WRITE(reg_addr),
&reg_data, 1);
}
int adxl372_spi_reg_write_mask(const struct device *dev,
uint8_t reg_addr,
uint32_t mask,
uint8_t data)
{
int ret;
uint8_t tmp;
ret = adxl372_spi_reg_read(dev, reg_addr, &tmp);
if (ret) {
return ret;
}
tmp &= ~mask;
tmp |= data;
return adxl372_spi_reg_write(dev, reg_addr, tmp);
}
static const struct adxl372_transfer_function adxl372_spi_transfer_fn = {
.read_reg_multiple = adxl372_spi_reg_read_multiple,
.write_reg = adxl372_spi_reg_write,
.read_reg = adxl372_spi_reg_read,
.write_reg_mask = adxl372_spi_reg_write_mask,
};
int adxl372_spi_init(const struct device *dev)
{
struct adxl372_data *data = dev->data;
const struct adxl372_dev_config *config = dev->config;
data->hw_tf = &adxl372_spi_transfer_fn;
if (!spi_is_ready_dt(&config->spi)) {
return -ENODEV;
}
return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2018 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT adi_adxl372
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include "adxl372.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(ADXL372, CONFIG_SENSOR_LOG_LEVEL);
static void adxl372_thread_cb(const struct device *dev)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_data *drv_data = dev->data;
uint8_t status1, status2;
int ret;
/* Clear the status */
if (adxl372_get_status(dev, &status1, &status2, NULL) < 0) {
return;
}
if (drv_data->th_handler != NULL) {
/* In max peak mode we wait until we settle below the inactivity
* threshold and then call the trigger handler.
*/
if (cfg->max_peak_detect_mode &&
ADXL372_STATUS_2_INACT(status2)) {
drv_data->th_handler(dev, drv_data->th_trigger);
} else if (!cfg->max_peak_detect_mode &&
(ADXL372_STATUS_2_INACT(status2) ||
ADXL372_STATUS_2_ACTIVITY(status2))) {
drv_data->th_handler(dev, drv_data->th_trigger);
}
}
if ((drv_data->drdy_handler != NULL) &&
ADXL372_STATUS_1_DATA_RDY(status1)) {
drv_data->drdy_handler(dev, drv_data->drdy_trigger);
}
ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
GPIO_INT_EDGE_TO_ACTIVE);
__ASSERT(ret == 0, "Interrupt configuration failed");
}
static void adxl372_gpio_callback(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
struct adxl372_data *drv_data =
CONTAINER_OF(cb, struct adxl372_data, gpio_cb);
const struct adxl372_dev_config *cfg = drv_data->dev->config;
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE);
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
#endif
}
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
static void adxl372_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p2);
ARG_UNUSED(p3);
struct adxl372_data *drv_data = p1;
while (true) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
adxl372_thread_cb(drv_data->dev);
}
}
#elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD)
static void adxl372_work_cb(struct k_work *work)
{
struct adxl372_data *drv_data =
CONTAINER_OF(work, struct adxl372_data, work);
adxl372_thread_cb(drv_data->dev);
}
#endif
int adxl372_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_data *drv_data = dev->data;
uint8_t int_mask, int_en, status1, status2;
int ret;
ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
GPIO_INT_DISABLE);
if (ret < 0) {
return ret;
}
switch (trig->type) {
case SENSOR_TRIG_THRESHOLD:
drv_data->th_handler = handler;
drv_data->th_trigger = trig;
int_mask = ADXL372_INT1_MAP_ACT_MSK |
ADXL372_INT1_MAP_INACT_MSK;
break;
case SENSOR_TRIG_DATA_READY:
drv_data->drdy_handler = handler;
drv_data->drdy_trigger = trig;
int_mask = ADXL372_INT1_MAP_DATA_RDY_MSK;
break;
default:
LOG_ERR("Unsupported sensor trigger");
return -ENOTSUP;
}
if (handler) {
int_en = int_mask;
} else {
int_en = 0U;
}
ret = drv_data->hw_tf->write_reg_mask(dev, ADXL372_INT1_MAP, int_mask, int_en);
if (ret < 0) {
return ret;
}
ret = adxl372_get_status(dev, &status1, &status2, NULL); /* Clear status */
if (ret < 0) {
return ret;
}
ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret < 0) {
return ret;
}
return 0;
}
int adxl372_init_interrupt(const struct device *dev)
{
const struct adxl372_dev_config *cfg = dev->config;
struct adxl372_data *drv_data = dev->data;
int ret;
if (!gpio_is_ready_dt(&cfg->interrupt)) {
LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name);
return -EINVAL;
}
ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
if (ret < 0) {
return ret;
}
gpio_init_callback(&drv_data->gpio_cb,
adxl372_gpio_callback,
BIT(cfg->interrupt.pin));
ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb);
if (ret < 0) {
LOG_ERR("Failed to set gpio callback!");
return ret;
}
drv_data->dev = dev;
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
CONFIG_ADXL372_THREAD_STACK_SIZE,
adxl372_thread, drv_data,
NULL, NULL, K_PRIO_COOP(CONFIG_ADXL372_THREAD_PRIORITY),
0, K_NO_WAIT);
#elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD)
drv_data->work.handler = adxl372_work_cb;
#endif
return 0;
}