drivers: sensors: adxl372: Add driver for ADXL372 high-g accelerometer

This patch adds support for the Analog Devices ADXL372 ultra-low power,
3-axis, +/-200 g MEMS accelerometer. The ADXL372 can be either connected
via a SPI or I2C interface.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
This commit is contained in:
Michael Hennerich 2018-08-01 10:45:59 +02:00 committed by Maureen Helm
commit a3e7cea1df
7 changed files with 1899 additions and 0 deletions

View file

@ -1,5 +1,6 @@
add_subdirectory_ifdef(CONFIG_ADT7420 adt7420)
add_subdirectory_ifdef(CONFIG_ADXL362 adxl362)
add_subdirectory_ifdef(CONFIG_ADXL372 adxl372)
add_subdirectory_ifdef(CONFIG_AK8975 ak8975)
add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx)
add_subdirectory_ifdef(CONFIG_APDS9960 apds9960)

View file

@ -39,6 +39,8 @@ source "drivers/sensor/adt7420/Kconfig"
source "drivers/sensor/adxl362/Kconfig"
source "drivers/sensor/adxl372/Kconfig"
source "drivers/sensor/ak8975/Kconfig"
source "drivers/sensor/amg88xx/Kconfig"

View file

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

View file

@ -0,0 +1,330 @@
# Kconfig - 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"
depends on SENSOR && (I2C || SPI)
help
Enable driver for ADXL372 Three-Axis Digital Accelerometers.
if ADXL372
choice ADXL372_BUS_TYPE
prompt "Interface type"
help
Select interface the digital interface type for the ADXL372
config ADXL372_I2C
depends on I2C
bool "I2C Interface"
config ADXL372_SPI
depends on SPI
bool "SPI Interface"
endchoice
if !HAS_DTS_I2C_DEVICE
config ADXL372_DEV_NAME
string "ADXL372 device name"
depends on ADXL372_I2C
default "ADXL372"
config ADXL372_I2C_ADDR
hex "I2C address for ADXL372"
depends on ADXL372_I2C
default 0x1D
help
I2C address of the ADXL372 sensor.
0x1D: if MISO is pulled low
0x53: if MISO is pulled high
config ADXL372_I2C_MASTER_DEV_NAME
string "I2C master where ADXL372 is connected"
depends on ADXL372_I2C
default "I2C_0"
help
Specify the device name of the I2C master device to which the
ADXL372 chip is connected.
endif # !HAS_DTS_I2C_DEVICE
if !HAS_DTS_SPI_DEVICE
config ADXL372_DEV_NAME
string "ADXL372 device name"
depends on ADXL372_SPI
default "ADXL372"
config ADXL372_SPI_DEV_NAME
string "SPI device where ADXL372 is connected"
depends on ADXL372_SPI
default "SPI_0"
help
Specify the device name of the SPI device to which ADXL372 is
connected.
config ADXL372_SPI_DEV_SLAVE
int "SPI Slave Select where ADXL372 is connected"
depends on ADXL372_SPI
default 2
help
Specify the slave select pin of the SPI to which ADXL372 is
connected.
config ADXL372_SPI_GPIO_CS
bool "ADXL372 SPI CS through a GPIO pin"
depends on ADXL372_SPI
help
This option is useful if one needs to manage SPI CS through a GPIO
pin to by-pass the SPI controller's CS logic.
config ADXL372_SPI_BUS_FREQ
int "ADXL372 SPI bus speed in Hz"
range 10000 10000000
default 8000000
help
This is the maximum supported SPI bus frequency. The chip supports a
frequency up to 10MHz.
endif # !HAS_DTS_SPI_DEVICE
if !HAS_DTS_SPI_PINS
config ADXL372_SPI_GPIO_CS_DRV_NAME
string "GPIO driver's name to use to drive SPI CS through"
default "GPIO_0"
depends on ADXL372_SPI_GPIO_CS
help
This option is mandatory to set which GPIO controller to use in order
to actually emulate the SPI CS.
config ADXL372_SPI_GPIO_CS_PIN
int "GPIO PIN to use to drive SPI CS through"
default 0
depends on ADXL372_SPI_GPIO_CS
help
This option is mandatory to set which GPIO pin to use in order
to actually emulate the SPI CS.
endif # !HAS_DTS_SPI_PINS
choice
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
choice
prompt "Accelerometer sampling frequency (ODR)"
default ADXL372_ODR_6400HZ if ADXL372_PEAK_DETECT_MODE
default ADXL372_ODR_400HZ if ADXL372_MEASUREMENT_MODE
config ADXL372_ODR_400HZ
bool "400 Hz"
config ADXL372_ODR_800HZ
bool "800 Hz"
config ADXL372_ODR_1600HZ
bool "1600 Hz"
config ADXL372_ODR_3200HZ
bool "3200 Hz"
config ADXL372_ODR_6400HZ
bool "6400 Hz"
endchoice
choice
prompt "Low-Pass (Antialiasing) Filter corner frequency"
default ADXL372_BW_200HZ if ADXL372_ODR_400HZ
default ADXL372_BW_400HZ if ADXL372_ODR_800HZ
default ADXL372_BW_800HZ if ADXL372_ODR_1600HZ
default ADXL372_BW_1600HZ if ADXL372_ODR_3200HZ
default ADXL372_BW_3200HZ if ADXL372_ODR_6400HZ
help
High g events often include acceleration content over a wide range
of frequencies. The ADC of the ADXL372 samples the input acceleration
at the user selected ODR.
In the absence of antialiasing filters, input signals whose frequency
is more than half the ODR alias or fold into the measurement bandwidth
can lead to inaccurate measurements.
config ADXL372_LPF_DISABLE
bool "Disabled"
config ADXL372_BW_200HZ
bool "200 Hz"
config ADXL372_BW_400HZ
bool "400 Hz"
config ADXL372_BW_800HZ
bool "800 Hz"
config ADXL372_BW_1600HZ
bool "1600 Hz"
config ADXL372_BW_3200HZ
bool "3200 Hz"
endchoice
choice
prompt "High-Pass Filter corner frequency"
default ADXL372_HPF_CORNER0
help
The ADXL372 offers a one-pole, high-pass filter with a user
selectable 3 dB frequency. Applications that do not require dc
acceleration measurements can use the high-pass filter to minimize
constant or slow varying offset errors including initial bias,
bias drift due to temperature, and bias drift due to supply voltage
config ADXL372_HPF_DISABLE
bool "Disabled"
config ADXL372_HPF_CORNER0
bool "ODR/210"
config ADXL372_HPF_CORNER1
bool "ODR/411"
config ADXL372_HPF_CORNER2
bool "ODR/812"
config ADXL372_HPF_CORNER3
bool "ODR/1616"
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
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
if !HAS_DTS_GPIO_DEVICE
config ADXL372_GPIO_DEV_NAME
string "GPIO device"
default "GPIO_0"
depends on ADXL372_TRIGGER
help
The GPIO device's name where the ADXL372 interrupt 1 or 2 pin is
connected.
config ADXL372_GPIO_PIN_NUM
int "Interrupt GPIO pin number"
default 0
depends on ADXL372_TRIGGER
help
The GPIO pin number receiving the interrupt signal from the
ADXL372 sensor.
endif # !HAS_DTS_GPIO_DEVICE
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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,374 @@
/*
* Copyright (c) 2018 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SENSOR_ADXL372_H__
#define __SENSOR_ADXL372_H__
#include <zephyr/types.h>
#include <device.h>
#include <gpio.h>
#include <spi.h>
#include <i2c.h>
#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (31 - (h))))
/*
* 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;
u16_t fifo_samples;
};
struct adxl372_activity_threshold {
u16_t thresh;
bool referenced;
bool enable;
};
struct adxl372_xyz_accel_data {
s16_t x;
s16_t y;
s16_t z;
};
struct adxl372_data {
struct device *bus;
#ifdef CONFIG_ADXL372_SPI
struct spi_config spi_cfg;
#endif
#if defined(CONFIG_ADXL372_SPI_GPIO_CS)
struct spi_cs_control adxl372_cs_ctrl;
#endif
struct adxl372_xyz_accel_data sample;
struct adxl372_fifo_config fifo_config;
#ifdef CONFIG_ADXL372_TRIGGER
struct device *gpio;
struct gpio_callback gpio_cb;
sensor_trigger_handler_t th_handler;
struct sensor_trigger th_trigger;
sensor_trigger_handler_t drdy_handler;
struct sensor_trigger drdy_trigger;
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
K_THREAD_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;
struct device *dev;
#endif
#endif /* CONFIG_ADXL372_TRIGGER */
};
struct adxl372_dev_config {
#ifdef CONFIG_ADXL372_I2C
const char *i2c_port;
u16_t i2c_addr;
#endif
#ifdef CONFIG_ADXL372_SPI
const char *spi_port;
u16_t spi_slave;
u32_t spi_max_frequency;
#ifdef CONFIG_ADXL372_SPI_GPIO_CS
const char *gpio_cs_port;
u8_t cs_gpio;
#endif
#endif /* CONFIG_ADXL372_SPI */
#ifdef CONFIG_ADXL372_TRIGGER
const char *gpio_port;
u8_t int_gpio;
#endif
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_bandwidth bw;
enum adxl372_hpf_corner hpf;
enum adxl372_odr odr;
enum adxl372_wakeup_rate wur;
enum adxl372_act_proc_mode act_proc_mode;
enum adxl372_instant_on_th_mode th_mode;
enum adxl372_filter_settle filter_settle;
enum adxl372_op_mode op_mode;
u16_t inactivity_time;
u8_t activity_time;
u8_t int1_config;
u8_t int2_config;
};
#ifdef CONFIG_ADXL372_TRIGGER
int adxl372_get_status(struct device *dev,
u8_t *status1, u8_t *status2, u16_t *fifo_entries);
int adxl372_reg_write_mask(struct device *dev,
u8_t reg_addr, u32_t mask, u8_t data);
int adxl372_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int adxl372_init_interrupt(struct device *dev);
#endif /* CONFIG_ADT7420_TRIGGER */
#define SYS_LOG_DOMAIN "ADXL372"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
#include <logging/sys_log.h>
#endif /* __SENSOR_ADXL372_H__ */

View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2018 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <gpio.h>
#include <misc/util.h>
#include <kernel.h>
#include <sensor.h>
#include "adxl372.h"
static void adxl372_thread_cb(void *arg)
{
struct device *dev = arg;
struct adxl372_data *drv_data = dev->driver_data;
const struct adxl372_dev_config *cfg = dev->config->config_info;
u8_t status1, status2;
/* 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);
}
gpio_pin_enable_callback(drv_data->gpio, cfg->int_gpio);
}
static void adxl372_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct adxl372_data *drv_data =
CONTAINER_OF(cb, struct adxl372_data, gpio_cb);
const struct adxl372_dev_config *cfg = dev->config->config_info;
gpio_pin_disable_callback(dev, cfg->int_gpio);
#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(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct adxl372_data *drv_data = dev->driver_data;
ARG_UNUSED(unused);
while (true) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
adxl372_thread_cb(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(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct adxl372_data *drv_data = dev->driver_data;
const struct adxl372_dev_config *cfg = dev->config->config_info;
u8_t int_mask, int_en, status1, status2;
int ret;
gpio_pin_disable_callback(drv_data->gpio, cfg->int_gpio);
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:
SYS_LOG_ERR("Unsupported sensor trigger");
ret = -ENOTSUP;
goto out;
}
if (handler) {
int_en = int_mask;
} else {
int_en = 0;
};
ret = adxl372_reg_write_mask(dev, ADXL372_INT1_MAP, int_mask, int_en);
adxl372_get_status(dev, &status1, &status2, NULL); /* Clear status */
out:
gpio_pin_enable_callback(drv_data->gpio, cfg->int_gpio);
return ret;
}
int adxl372_init_interrupt(struct device *dev)
{
struct adxl372_data *drv_data = dev->driver_data;
const struct adxl372_dev_config *cfg = dev->config->config_info;
drv_data->gpio = device_get_binding(cfg->gpio_port);
if (drv_data->gpio == NULL) {
SYS_LOG_ERR("Failed to get pointer to %s device!",
cfg->gpio_port);
return -EINVAL;
}
gpio_pin_configure(drv_data->gpio, cfg->int_gpio,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
gpio_init_callback(&drv_data->gpio_cb,
adxl372_gpio_callback,
BIT(cfg->int_gpio));
if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
SYS_LOG_ERR("Failed to set gpio callback!");
return -EIO;
}
#if defined(CONFIG_ADXL372_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
CONFIG_ADXL372_THREAD_STACK_SIZE,
(k_thread_entry_t)adxl372_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_ADXL372_THREAD_PRIORITY),
0, 0);
#elif defined(CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD)
drv_data->work.handler = adxl372_work_cb;
drv_data->dev = dev;
#endif
return 0;
}