Added sensor driver for ADXL362
The ADXL362 is a 3-axis MEMS accelerometer. See http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL362.pdf Jira: ZEP-1695 Change-Id: I29d870b59e62412452494cf0bc06eac632bebba5 Signed-off-by: Dario Pennisi <dario@iptronix.com> Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
4679a5f413
commit
8e27ad430e
6 changed files with 897 additions and 0 deletions
|
@ -40,6 +40,8 @@ config SENSOR_INIT_PRIORITY
|
|||
help
|
||||
Sensor initialization priority.
|
||||
|
||||
source "drivers/sensor/adxl362/Kconfig"
|
||||
|
||||
source "drivers/sensor/ak8975/Kconfig"
|
||||
|
||||
source "drivers/sensor/bma280/Kconfig"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
ccflags-y +=-I$(srctree)/drivers
|
||||
|
||||
obj-$(CONFIG_ADXL362) += adxl362/
|
||||
obj-$(CONFIG_AK8975) += ak8975/
|
||||
obj-$(CONFIG_BMA280) += bma280/
|
||||
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn/
|
||||
|
|
81
drivers/sensor/adxl362/Kconfig
Normal file
81
drivers/sensor/adxl362/Kconfig
Normal file
|
@ -0,0 +1,81 @@
|
|||
# Kconfig.adxl362 - ADXL362 Three-Axis Digital Accelerometers
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 IpTronix S.r.l.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
menuconfig ADXL362
|
||||
bool "ADXL362 sensor"
|
||||
depends on SENSOR && SPI
|
||||
default n
|
||||
help
|
||||
Enable driver for ADXL362 Three-Axis Digital Accelerometers.
|
||||
|
||||
config ADXL362_DEV_NAME
|
||||
string "ADXL362 device name"
|
||||
depends on ADXL362
|
||||
default "ADXL362"
|
||||
|
||||
config ADXL362_SPI_DEV_NAME
|
||||
string "SPI device where ADXL362 is connected"
|
||||
depends on ADXL362
|
||||
default "SPI_0"
|
||||
help
|
||||
Specify the device name of the SPI device to which ADXL362 is
|
||||
connected.
|
||||
|
||||
config ADXL362_SPI_DEV_SLAVE
|
||||
int "SPI Slave Select where ADXL362 is connected"
|
||||
depends on ADXL362
|
||||
default 2
|
||||
help
|
||||
Specify the slave select pin of the SPI to which ADXL362 is
|
||||
connected.
|
||||
|
||||
choice
|
||||
prompt "Accelerometer range setting"
|
||||
depends on ADXL362
|
||||
default BMI160_ACCEL_RANGE_RUNTIME
|
||||
|
||||
config ADXL362_ACCEL_RANGE_RUNTIME
|
||||
bool "Set at runtime."
|
||||
|
||||
config ADXL362_ACCEL_RANGE_2G
|
||||
bool "2G"
|
||||
|
||||
config ADXL362_ACCEL_RANGE_4G
|
||||
bool "4G"
|
||||
|
||||
config ADXL362_ACCEL_RANGE_8G
|
||||
bool "8G"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Accelerometer sampling frequency."
|
||||
depends on ADXL362
|
||||
default ADXL362_ACCEL_ODR_RUNTIME
|
||||
|
||||
config ADXL362_ACCEL_ODR_RUNTIME
|
||||
bool "Set at runtime."
|
||||
|
||||
config ADXL362_ACCEL_ODR_12_5
|
||||
bool "12.5 Hz"
|
||||
|
||||
config ADXL362_ACCEL_ODR_25
|
||||
bool "25 Hz"
|
||||
|
||||
config ADXL362_ACCEL_ODR_50
|
||||
bool "50 Hz"
|
||||
|
||||
config ADXL362_ACCEL_ODR_100
|
||||
bool "100 Hz"
|
||||
|
||||
config ADXL362_ACCEL_ODR_200
|
||||
bool "200 Hz"
|
||||
|
||||
config ADXL362_ACCEL_ODR_400
|
||||
bool "400 Hz"
|
||||
|
||||
endchoice
|
1
drivers/sensor/adxl362/Makefile
Normal file
1
drivers/sensor/adxl362/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_ADXL362) += adxl362.o
|
618
drivers/sensor/adxl362/adxl362.c
Normal file
618
drivers/sensor/adxl362/adxl362.c
Normal file
|
@ -0,0 +1,618 @@
|
|||
/* adxl362.c - ADXL362 Three-Axis Digital Accelerometers */
|
||||
/*
|
||||
* Copyright (c) 2017 IpTronix S.r.l.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <sensor.h>
|
||||
#include <init.h>
|
||||
#include <gpio.h>
|
||||
#include <misc/printk.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <spi.h>
|
||||
|
||||
#include "adxl362.h"
|
||||
|
||||
|
||||
static struct adxl362_data adxl362_data;
|
||||
|
||||
static int adxl362_set_reg(struct device *dev, uint16_t register_value,
|
||||
uint8_t register_address, uint8_t count)
|
||||
{
|
||||
struct adxl362_data *adxl362_data = dev->driver_data;
|
||||
uint8_t buffer[4];
|
||||
int ret;
|
||||
|
||||
buffer[0] = ADXL362_WRITE_REG;
|
||||
buffer[1] = register_address;
|
||||
buffer[2] = (register_value & 0x00FF);
|
||||
buffer[3] = (register_value >> 8);
|
||||
|
||||
ret = spi_slave_select(adxl362_data->spi,
|
||||
adxl362_data->spi_slave);
|
||||
if (ret) {
|
||||
SYS_LOG_DBG("spi_slave_select FAIL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spi_transceive(adxl362_data->spi, buffer, count + 2,
|
||||
buffer, count + 2);
|
||||
if (ret) {
|
||||
SYS_LOG_DBG("spi_transceive FAIL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_get_reg(struct device *dev, uint8_t *read_buf,
|
||||
uint8_t register_address, uint8_t count)
|
||||
{
|
||||
struct adxl362_data *adxl362_data = dev->driver_data;
|
||||
uint8_t buffer[4];
|
||||
uint8_t index;
|
||||
int ret;
|
||||
|
||||
buffer[0] = ADXL362_READ_REG;
|
||||
buffer[1] = register_address;
|
||||
for (index = 0; index < count; index++) {
|
||||
buffer[index + 2] = read_buf[index];
|
||||
}
|
||||
|
||||
ret = spi_slave_select(adxl362_data->spi,
|
||||
adxl362_data->spi_slave);
|
||||
if (ret) {
|
||||
SYS_LOG_DBG("spi_slave_select FAIL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spi_transceive(adxl362_data->spi, buffer, count + 2,
|
||||
buffer, count + 2);
|
||||
if (ret) {
|
||||
SYS_LOG_DBG("spi_transceive FAIL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (index = 0; index < count; index++) {
|
||||
read_buf[index] = buffer[index + 2];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_software_reset(struct device *dev)
|
||||
{
|
||||
return adxl362_set_reg(dev, ADXL362_RESET_KEY,
|
||||
ADXL362_REG_SOFT_RESET, 1);
|
||||
}
|
||||
|
||||
static int adxl362_set_power_mode(struct device *dev, uint8_t mode)
|
||||
{
|
||||
uint8_t old_power_ctl;
|
||||
uint8_t new_power_ctl;
|
||||
int ret;
|
||||
|
||||
ret = adxl362_get_reg(dev, &old_power_ctl, ADXL362_REG_POWER_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_power_ctl = old_power_ctl & ~ADXL362_POWER_CTL_MEASURE(0x3);
|
||||
new_power_ctl = new_power_ctl |
|
||||
(mode *
|
||||
ADXL362_POWER_CTL_MEASURE(ADXL362_MEASURE_ON));
|
||||
return adxl362_set_reg(dev, new_power_ctl, ADXL362_REG_POWER_CTL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Output data rate map with allowed frequencies:
|
||||
* freq = freq_int + freq_milli / 1000
|
||||
*
|
||||
* Since we don't need a finer frequency resolution than milliHz, use uint16_t
|
||||
* to save some flash.
|
||||
*/
|
||||
static const struct {
|
||||
uint16_t freq_int;
|
||||
uint16_t freq_milli; /* User should convert to uHz before setting the
|
||||
* SENSOR_ATTR_SAMPLING_FREQUENCY attribute.
|
||||
*/
|
||||
} adxl362_odr_map[] = {
|
||||
{ 12, 500 },
|
||||
{ 25, 0 },
|
||||
{ 50, 0 },
|
||||
{ 100, 0 },
|
||||
{ 200, 0 },
|
||||
{ 400, 0 },
|
||||
};
|
||||
|
||||
static int adxl362_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* An ODR of 0 Hz is not allowed */
|
||||
if (freq_int == 0 && freq_milli == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adxl362_odr_map); i++) {
|
||||
if (freq_int < adxl362_odr_map[i].freq_int ||
|
||||
(freq_int == adxl362_odr_map[i].freq_int &&
|
||||
freq_milli <= adxl362_odr_map[i].freq_milli)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct adxl362_range {
|
||||
uint16_t range;
|
||||
uint8_t reg_val;
|
||||
} adxl362_acc_range_map[] = {
|
||||
{2, ADXL362_RANGE_2G},
|
||||
{4, ADXL362_RANGE_4G},
|
||||
{8, ADXL362_RANGE_8G},
|
||||
};
|
||||
|
||||
static int32_t adxl362_range_to_reg_val(uint16_t range)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adxl362_acc_range_map); i++) {
|
||||
if (range <= adxl362_acc_range_map[i].range) {
|
||||
return adxl362_acc_range_map[i].reg_val;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl362_set_range(struct device *dev, uint8_t range)
|
||||
{
|
||||
struct adxl362_data *adxl362_data = dev->driver_data;
|
||||
uint8_t old_filter_ctl;
|
||||
uint8_t new_filter_ctl;
|
||||
int ret;
|
||||
|
||||
ret = adxl362_get_reg(dev, &old_filter_ctl, ADXL362_REG_FILTER_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_filter_ctl = old_filter_ctl & ~ADXL362_FILTER_CTL_RANGE(0x3);
|
||||
new_filter_ctl = new_filter_ctl | ADXL362_FILTER_CTL_RANGE(range);
|
||||
ret = adxl362_set_reg(dev, new_filter_ctl, ADXL362_REG_FILTER_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
adxl362_data->selected_range = (1 << range) * 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_set_output_rate(struct device *dev, uint8_t out_rate)
|
||||
{
|
||||
uint8_t old_filter_ctl;
|
||||
uint8_t new_filter_ctl;
|
||||
|
||||
adxl362_get_reg(dev, &old_filter_ctl, ADXL362_REG_FILTER_CTL, 1);
|
||||
new_filter_ctl = old_filter_ctl & ~ADXL362_FILTER_CTL_ODR(0x7);
|
||||
new_filter_ctl = new_filter_ctl | ADXL362_FILTER_CTL_ODR(out_rate);
|
||||
adxl362_set_reg(dev, new_filter_ctl, ADXL362_REG_FILTER_CTL, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int axl362_acc_config(struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
switch (attr) {
|
||||
#if defined(CONFIG_ADXL362_ACCEL_RANGE_RUNTIME)
|
||||
case SENSOR_ATTR_FULL_SCALE:
|
||||
{
|
||||
int range_reg;
|
||||
|
||||
range_reg = adxl362_range_to_reg_val(sensor_ms2_to_g(val));
|
||||
if (range_reg < 0) {
|
||||
SYS_LOG_DBG("invalid range requested.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return adxl362_set_range(dev, range_reg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_ADXL362_ACCEL_ODR_RUNTIME)
|
||||
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||
{
|
||||
int out_rate;
|
||||
|
||||
out_rate = adxl362_freq_to_odr_val(val->val1,
|
||||
val->val2 / 1000);
|
||||
if (out_rate < 0) {
|
||||
SYS_LOG_DBG("invalid output rate.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return adxl362_set_output_rate(dev, out_rate);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
SYS_LOG_DBG("Accel attribute not supported.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_attr_set(struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr, const struct sensor_value *val)
|
||||
{
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
case SENSOR_CHAN_ACCEL_XYZ:
|
||||
return axl362_acc_config(dev, chan, attr, val);
|
||||
|
||||
default:
|
||||
SYS_LOG_DBG("attr_set() not supported on this channel.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int adxl362_read_temperature(struct device *dev, int32_t *temp_celsius)
|
||||
{
|
||||
uint8_t raw_temp_data[2];
|
||||
int ret;
|
||||
|
||||
/* Reads the temperature of the device. */
|
||||
ret = adxl362_get_reg(dev, raw_temp_data, ADXL362_REG_TEMP_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*temp_celsius = (int32_t)(raw_temp_data[1] << 8) + raw_temp_data[0];
|
||||
*temp_celsius *= 65;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adxl362_fifo_setup(struct device *dev, uint8_t mode,
|
||||
uint16_t water_mark_lvl, uint8_t en_temp_read)
|
||||
{
|
||||
uint8_t write_val;
|
||||
int ret;
|
||||
|
||||
write_val = ADXL362_FIFO_CTL_FIFO_MODE(mode) |
|
||||
(en_temp_read * ADXL362_FIFO_CTL_FIFO_TEMP) |
|
||||
ADXL362_FIFO_CTL_AH;
|
||||
ret = adxl362_set_reg(dev, write_val, ADXL362_REG_FIFO_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adxl362_set_reg(dev, water_mark_lvl, ADXL362_REG_FIFO_SAMPLES, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_setup_activity_detection(struct device *dev,
|
||||
uint8_t ref_or_abs,
|
||||
uint16_t threshold,
|
||||
uint8_t time)
|
||||
{
|
||||
uint8_t old_act_inact_reg;
|
||||
uint8_t new_act_inact_reg;
|
||||
int ret;
|
||||
|
||||
/**
|
||||
* mode
|
||||
* must be one of the following:
|
||||
* ADXL362_FIFO_DISABLE - FIFO is disabled.
|
||||
* ADXL362_FIFO_OLDEST_SAVED - Oldest saved mode.
|
||||
* ADXL362_FIFO_STREAM - Stream mode.
|
||||
* ADXL362_FIFO_TRIGGERED - Triggered mode.
|
||||
* water_mark_lvl
|
||||
* Specifies the number of samples to store in the FIFO.
|
||||
* en_temp_read
|
||||
* Store Temperature Data to FIFO.
|
||||
* 1 - temperature data is stored in the FIFO
|
||||
* together with x-, y- and x-axis data.
|
||||
* 0 - temperature data is skipped.
|
||||
*/
|
||||
|
||||
/* Configure motion threshold and activity timer. */
|
||||
ret = adxl362_set_reg(dev, (threshold & 0x7FF),
|
||||
ADXL362_REG_THRESH_ACT_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adxl362_set_reg(dev, time, ADXL362_REG_TIME_ACT, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable activity interrupt and select a referenced or absolute
|
||||
* configuration.
|
||||
*/
|
||||
ret = adxl362_get_reg(dev, &old_act_inact_reg,
|
||||
ADXL362_REG_ACT_INACT_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_act_inact_reg = old_act_inact_reg & ~ADXL362_ACT_INACT_CTL_ACT_REF;
|
||||
new_act_inact_reg |= ADXL362_ACT_INACT_CTL_ACT_EN |
|
||||
(ref_or_abs * ADXL362_ACT_INACT_CTL_ACT_REF);
|
||||
ret = adxl362_set_reg(dev, new_act_inact_reg,
|
||||
ADXL362_REG_ACT_INACT_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_setup_inactivity_detection(struct device *dev,
|
||||
uint8_t ref_or_abs,
|
||||
uint16_t threshold,
|
||||
uint16_t time)
|
||||
{
|
||||
uint8_t old_act_inact_reg;
|
||||
uint8_t new_act_inact_reg;
|
||||
int ret;
|
||||
|
||||
/* Configure motion threshold and inactivity timer. */
|
||||
ret = adxl362_set_reg(dev, (threshold & 0x7FF),
|
||||
ADXL362_REG_THRESH_INACT_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = adxl362_set_reg(dev, time, ADXL362_REG_TIME_INACT_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable inactivity interrupt and select a referenced or
|
||||
* absolute configuration.
|
||||
*/
|
||||
ret = adxl362_get_reg(dev, &old_act_inact_reg,
|
||||
ADXL362_REG_ACT_INACT_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_act_inact_reg = old_act_inact_reg &
|
||||
~ADXL362_ACT_INACT_CTL_INACT_REF;
|
||||
new_act_inact_reg |= ADXL362_ACT_INACT_CTL_INACT_EN |
|
||||
(ref_or_abs * ADXL362_ACT_INACT_CTL_INACT_REF);
|
||||
ret = adxl362_set_reg(dev, new_act_inact_reg,
|
||||
ADXL362_REG_ACT_INACT_CTL, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct adxl362_data *data = dev->driver_data;
|
||||
uint8_t buf[2];
|
||||
int16_t x, y, z;
|
||||
int ret;
|
||||
|
||||
ret = adxl362_get_reg(dev, buf, ADXL362_REG_XDATA_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
x = (buf[1] << 8) + buf[0];
|
||||
ret = adxl362_get_reg(dev, buf, ADXL362_REG_YDATA_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
y = (buf[1] << 8) + buf[0];
|
||||
ret = adxl362_get_reg(dev, buf, ADXL362_REG_ZDATA_L, 2);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
z = (buf[1] << 8) + buf[0];
|
||||
|
||||
data->acc_x = (int32_t)x * (adxl362_data.selected_range / 2);
|
||||
data->acc_y = (int32_t)y * (adxl362_data.selected_range / 2);
|
||||
data->acc_z = (int32_t)z * (adxl362_data.selected_range / 2);
|
||||
|
||||
ret = adxl362_read_temperature(dev, &data->temp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl362_channel_get(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct adxl362_data *data = dev->driver_data;
|
||||
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X: /* Acceleration on the X axis, in m/s^2. */
|
||||
val->val1 = data->acc_x / 1000;
|
||||
val->val2 = (data->acc_x % 1000) * 1000;
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Y: /* Acceleration on the Y axis, in m/s^2. */
|
||||
val->val1 = data->acc_y / 1000;
|
||||
val->val2 = (data->acc_y % 1000) * 1000;
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Z: /* Acceleration on the Z axis, in m/s^2. */
|
||||
val->val1 = data->acc_z / 1000;
|
||||
val->val2 = (data->acc_z % 1000) * 1000;
|
||||
break;
|
||||
case SENSOR_CHAN_TEMP: /* Temperature in degrees Celsius. */
|
||||
val->val1 = data->temp / 1000;
|
||||
val->val2 = (data->temp % 1000) * 1000;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api adxl362_api_funcs = {
|
||||
.attr_set = adxl362_attr_set,
|
||||
.sample_fetch = adxl362_sample_fetch,
|
||||
.channel_get = adxl362_channel_get,
|
||||
};
|
||||
|
||||
static int adxl362_chip_init(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Configures activity detection.
|
||||
* Referenced/Absolute Activity or Inactivity Select.
|
||||
* 0 - absolute mode.
|
||||
* 1 - referenced mode.
|
||||
* threshold
|
||||
* 11-bit unsigned value that the adxl362 samples are
|
||||
* compared to.
|
||||
* time
|
||||
* 8-bit value written to the activity timer register.
|
||||
* The amount of time (in seconds) is:
|
||||
* time / ODR,
|
||||
* where ODR - is the output data rate.
|
||||
*/
|
||||
ret = adxl362_setup_activity_detection(dev, 0, 250, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configures inactivity detection.
|
||||
* Referenced/Absolute Activity or Inactivity Select.
|
||||
* 0 - absolute mode.
|
||||
* 1 - referenced mode.
|
||||
* threshold
|
||||
* 11-bit unsigned value that the adxl362 samples are
|
||||
* compared to.
|
||||
* time
|
||||
* 16-bit value written to the activity timer register.
|
||||
* The amount of time (in seconds) is:
|
||||
* time / ODR,
|
||||
* where ODR - is the output data rate.
|
||||
*/
|
||||
ret = adxl362_setup_inactivity_detection(dev, 0, 100, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configures the FIFO feature. */
|
||||
ret = adxl362_fifo_setup(dev, ADXL362_FIFO_DISABLE, 0, 0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Selects the measurement range.
|
||||
* options are:
|
||||
* ADXL362_RANGE_2G - +-2 g
|
||||
* ADXL362_RANGE_4G - +-4 g
|
||||
* ADXL362_RANGE_8G - +-8 g
|
||||
*/
|
||||
ret = adxl362_set_range(dev, ADXL362_DEFAULT_RANGE_ACC);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Selects the Output Data Rate of the device.
|
||||
* Options are:
|
||||
* ADXL362_ODR_12_5_HZ - 12.5Hz
|
||||
* ADXL362_ODR_25_HZ - 25Hz
|
||||
* ADXL362_ODR_50_HZ - 50Hz
|
||||
* ADXL362_ODR_100_HZ - 100Hz
|
||||
* ADXL362_ODR_200_HZ - 200Hz
|
||||
* ADXL362_ODR_400_HZ - 400Hz
|
||||
*/
|
||||
ret = adxl362_set_output_rate(dev, ADXL362_DEFAULT_ODR_ACC);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Places the device into measure mode. */
|
||||
ret = adxl362_set_power_mode(dev, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes communication with the device and checks if the part is
|
||||
* present by reading the device id.
|
||||
*
|
||||
* @return 0 - the initialization was successful and the device is present;
|
||||
* -1 - an error occurred.
|
||||
*
|
||||
*/
|
||||
static int adxl362_init(struct device *dev)
|
||||
{
|
||||
struct adxl362_data *data = dev->driver_data;
|
||||
struct spi_config spi_config;
|
||||
uint8_t value;
|
||||
int ret;
|
||||
|
||||
data->spi = device_get_binding(CONFIG_ADXL362_SPI_DEV_NAME);
|
||||
if (!data->spi) {
|
||||
SYS_LOG_DBG("spi device not found: %s",
|
||||
CONFIG_ADXL362_SPI_DEV_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spi_config.config = SPI_WORD(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL |
|
||||
SPI_MODE_CPHA;
|
||||
spi_config.max_sys_freq = 4;
|
||||
ret = spi_configure(data->spi, &spi_config);
|
||||
if (ret) {
|
||||
SYS_LOG_DBG("SPI configuration error %s %d\n",
|
||||
CONFIG_ADXL362_SPI_DEV_NAME, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->spi_slave = CONFIG_ADXL362_SPI_DEV_SLAVE;
|
||||
|
||||
adxl362_software_reset(dev);
|
||||
|
||||
adxl362_get_reg(dev, &value, ADXL362_REG_PARTID, 1);
|
||||
if (value != ADXL362_PART_ID) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (adxl362_chip_init(dev) < 0) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(adxl362, CONFIG_ADXL362_DEV_NAME, adxl362_init,
|
||||
&adxl362_data, NULL, POST_KERNEL,
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &adxl362_api_funcs);
|
194
drivers/sensor/adxl362/adxl362.h
Normal file
194
drivers/sensor/adxl362/adxl362.h
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2017 IpTronix S.r.l.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SENSOR_ADXL362_H__
|
||||
#define __SENSOR_ADXL362_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <device.h>
|
||||
|
||||
#define ADXL362_SLAVE_ID 1
|
||||
|
||||
/* ADXL362 communication commands */
|
||||
#define ADXL362_WRITE_REG 0x0A
|
||||
#define ADXL362_READ_REG 0x0B
|
||||
#define ADXL362_WRITE_FIFO 0x0D
|
||||
|
||||
/* Registers */
|
||||
#define ADXL362_REG_DEVID_AD 0x00
|
||||
#define ADXL362_REG_DEVID_MST 0x01
|
||||
#define ADXL362_REG_PARTID 0x02
|
||||
#define ADXL362_REG_REVID 0x03
|
||||
#define ADXL362_REG_XDATA 0x08
|
||||
#define ADXL362_REG_YDATA 0x09
|
||||
#define ADXL362_REG_ZDATA 0x0A
|
||||
#define ADXL362_REG_STATUS 0x0B
|
||||
#define ADXL362_REG_FIFO_L 0x0C
|
||||
#define ADXL362_REG_FIFO_H 0x0D
|
||||
#define ADXL362_REG_XDATA_L 0x0E
|
||||
#define ADXL362_REG_XDATA_H 0x0F
|
||||
#define ADXL362_REG_YDATA_L 0x10
|
||||
#define ADXL362_REG_YDATA_H 0x11
|
||||
#define ADXL362_REG_ZDATA_L 0x12
|
||||
#define ADXL362_REG_ZDATA_H 0x13
|
||||
#define ADXL362_REG_TEMP_L 0x14
|
||||
#define ADXL362_REG_TEMP_H 0x15
|
||||
#define ADXL362_REG_SOFT_RESET 0x1F
|
||||
#define ADXL362_REG_THRESH_ACT_L 0x20
|
||||
#define ADXL362_REG_THRESH_ACT_H 0x21
|
||||
#define ADXL362_REG_TIME_ACT 0x22
|
||||
#define ADXL362_REG_THRESH_INACT_L 0x23
|
||||
#define ADXL362_REG_THRESH_INACT_H 0x24
|
||||
#define ADXL362_REG_TIME_INACT_L 0x25
|
||||
#define ADXL362_REG_TIME_INACT_H 0x26
|
||||
#define ADXL362_REG_ACT_INACT_CTL 0x27
|
||||
#define ADXL362_REG_FIFO_CTL 0x28
|
||||
#define ADXL362_REG_FIFO_SAMPLES 0x29
|
||||
#define ADXL362_REG_INTMAP1 0x2A
|
||||
#define ADXL362_REG_INTMAP2 0x2B
|
||||
#define ADXL362_REG_FILTER_CTL 0x2C
|
||||
#define ADXL362_REG_POWER_CTL 0x2D
|
||||
#define ADXL362_REG_SELF_TEST 0x2E
|
||||
|
||||
/* ADXL362_REG_STATUS definitions */
|
||||
#define ADXL362_STATUS_ERR_USER_REGS (1 << 7)
|
||||
#define ADXL362_STATUS_AWAKE (1 << 6)
|
||||
#define ADXL362_STATUS_INACT (1 << 5)
|
||||
#define ADXL362_STATUS_ACT (1 << 4)
|
||||
#define ADXL362_STATUS_FIFO_OVERRUN (1 << 3)
|
||||
#define ADXL362_STATUS_FIFO_WATERMARK (1 << 2)
|
||||
#define ADXL362_STATUS_FIFO_RDY (1 << 1)
|
||||
#define ADXL362_STATUS_DATA_RDY (1 << 0)
|
||||
|
||||
/* ADXL362_REG_ACT_INACT_CTL definitions */
|
||||
#define ADXL362_ACT_INACT_CTL_LINKLOOP(x) (((x) & 0x3) << 4)
|
||||
#define ADXL362_ACT_INACT_CTL_INACT_REF (1 << 3)
|
||||
#define ADXL362_ACT_INACT_CTL_INACT_EN (1 << 2)
|
||||
#define ADXL362_ACT_INACT_CTL_ACT_REF (1 << 1)
|
||||
#define ADXL362_ACT_INACT_CTL_ACT_EN (1 << 0)
|
||||
|
||||
/* ADXL362_ACT_INACT_CTL_LINKLOOP(x) options */
|
||||
#define ADXL362_MODE_DEFAULT 0
|
||||
#define ADXL362_MODE_LINK 1
|
||||
#define ADXL362_MODE_LOOP 3
|
||||
|
||||
/* ADXL362_REG_FIFO_CTL */
|
||||
#define ADXL362_FIFO_CTL_AH (1 << 3)
|
||||
#define ADXL362_FIFO_CTL_FIFO_TEMP (1 << 2)
|
||||
#define ADXL362_FIFO_CTL_FIFO_MODE(x) (((x) & 0x3) << 0)
|
||||
|
||||
/* ADXL362_FIFO_CTL_FIFO_MODE(x) options */
|
||||
#define ADXL362_FIFO_DISABLE 0
|
||||
#define ADXL362_FIFO_OLDEST_SAVED 1
|
||||
#define ADXL362_FIFO_STREAM 2
|
||||
#define ADXL362_FIFO_TRIGGERED 3
|
||||
|
||||
/* ADXL362_REG_INTMAP1 */
|
||||
#define ADXL362_INTMAP1_INT_LOW (1 << 7)
|
||||
#define ADXL362_INTMAP1_AWAKE (1 << 6)
|
||||
#define ADXL362_INTMAP1_INACT (1 << 5)
|
||||
#define ADXL362_INTMAP1_ACT (1 << 4)
|
||||
#define ADXL362_INTMAP1_FIFO_OVERRUN (1 << 3)
|
||||
#define ADXL362_INTMAP1_FIFO_WATERMARK (1 << 2)
|
||||
#define ADXL362_INTMAP1_FIFO_READY (1 << 1)
|
||||
#define ADXL362_INTMAP1_DATA_READY (1 << 0)
|
||||
|
||||
/* ADXL362_REG_INTMAP2 definitions */
|
||||
#define ADXL362_INTMAP2_INT_LOW (1 << 7)
|
||||
#define ADXL362_INTMAP2_AWAKE (1 << 6)
|
||||
#define ADXL362_INTMAP2_INACT (1 << 5)
|
||||
#define ADXL362_INTMAP2_ACT (1 << 4)
|
||||
#define ADXL362_INTMAP2_FIFO_OVERRUN (1 << 3)
|
||||
#define ADXL362_INTMAP2_FIFO_WATERMARK (1 << 2)
|
||||
#define ADXL362_INTMAP2_FIFO_READY (1 << 1)
|
||||
#define ADXL362_INTMAP2_DATA_READY (1 << 0)
|
||||
|
||||
/* ADXL362_REG_FILTER_CTL definitions */
|
||||
#define ADXL362_FILTER_CTL_RANGE(x) (((x) & 0x3) << 6)
|
||||
#define ADXL362_FILTER_CTL_RES (1 << 5)
|
||||
#define ADXL362_FILTER_CTL_HALF_BW (1 << 4)
|
||||
#define ADXL362_FILTER_CTL_EXT_SAMPLE (1 << 3)
|
||||
#define ADXL362_FILTER_CTL_ODR(x) (((x) & 0x7) << 0)
|
||||
|
||||
/* ADXL362_FILTER_CTL_RANGE(x) options */
|
||||
#define ADXL362_RANGE_2G 0 /* +/-2 g */
|
||||
#define ADXL362_RANGE_4G 1 /* +/-4 g */
|
||||
#define ADXL362_RANGE_8G 2 /* +/-8 g */
|
||||
|
||||
/* ADXL362_FILTER_CTL_ODR(x) options */
|
||||
#define ADXL362_ODR_12_5_HZ 0 /* 12.5 Hz */
|
||||
#define ADXL362_ODR_25_HZ 1 /* 25 Hz */
|
||||
#define ADXL362_ODR_50_HZ 2 /* 50 Hz */
|
||||
#define ADXL362_ODR_100_HZ 3 /* 100 Hz */
|
||||
#define ADXL362_ODR_200_HZ 4 /* 200 Hz */
|
||||
#define ADXL362_ODR_400_HZ 5 /* 400 Hz */
|
||||
|
||||
/* ADXL362_REG_POWER_CTL definitions */
|
||||
#define ADXL362_POWER_CTL_RES (1 << 7)
|
||||
#define ADXL362_POWER_CTL_EXT_CLK (1 << 6)
|
||||
#define ADXL362_POWER_CTL_LOW_NOISE(x) (((x) & 0x3) << 4)
|
||||
#define ADXL362_POWER_CTL_WAKEUP (1 << 3)
|
||||
#define ADXL362_POWER_CTL_AUTOSLEEP (1 << 2)
|
||||
#define ADXL362_POWER_CTL_MEASURE(x) (((x) & 0x3) << 0)
|
||||
|
||||
/* ADXL362_POWER_CTL_LOW_NOISE(x) options */
|
||||
#define ADXL362_NOISE_MODE_NORMAL 0
|
||||
#define ADXL362_NOISE_MODE_LOW 1
|
||||
#define ADXL362_NOISE_MODE_ULTRALOW 2
|
||||
|
||||
/* ADXL362_POWER_CTL_MEASURE(x) options */
|
||||
#define ADXL362_MEASURE_STANDBY 0
|
||||
#define ADXL362_MEASURE_ON 2
|
||||
|
||||
/* ADXL362_REG_SELF_TEST */
|
||||
#define ADXL362_SELF_TEST_ST (1 << 0)
|
||||
|
||||
/* ADXL362 device information */
|
||||
#define ADXL362_DEVICE_AD 0xAD
|
||||
#define ADXL362_DEVICE_MST 0x1D
|
||||
#define ADXL362_PART_ID 0xF2
|
||||
|
||||
/* ADXL362 Reset settings */
|
||||
#define ADXL362_RESET_KEY 0x52
|
||||
|
||||
struct adxl362_data {
|
||||
struct device *spi;
|
||||
int32_t acc_x;
|
||||
int32_t acc_y;
|
||||
int32_t acc_z;
|
||||
int32_t temp;
|
||||
uint8_t spi_slave;
|
||||
uint8_t selected_range;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ADXL362_ACCEL_RANGE_RUNTIME) ||\
|
||||
defined(CONFIG_ADXL362_ACCEL_RANGE_2G)
|
||||
# define ADXL362_DEFAULT_RANGE_ACC ADXL362_RANGE_2G
|
||||
#elif defined(CONFIG_ADXL362_ACCEL_RANGE_4G)
|
||||
# define ADXL362_DEFAULT_RANGE_ACC ADXL362_RANGE_4G
|
||||
#else
|
||||
# define ADXL362_DEFAULT_RANGE_ACC ADXL362_RANGE_8G
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ADXL362_ACCEL_ODR_RUNTIME) ||\
|
||||
defined(CONFIG_ADXL362_ACCEL_ODR_12_5)
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_12_5_HZ
|
||||
#elif defined(CONFIG_ADXL362_ACCEL_ODR_25)
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_25_HZ
|
||||
#elif defined(CONFIG_ADXL362_ACCEL_ODR_50)
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_50_HZ
|
||||
#elif defined(CONFIG_ADXL362_ACCEL_ODR_100)
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_100_HZ
|
||||
#elif defined(CONFIG_ADXL362_ACCEL_ODR_200)
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_200_HZ
|
||||
#else
|
||||
# define ADXL362_DEFAULT_ODR_ACC ADXL362_ODR_400_HZ
|
||||
#endif
|
||||
|
||||
#define SYS_LOG_DOMAIN "ADXL362"
|
||||
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
|
||||
#include <logging/sys_log.h>
|
||||
#endif /* __SENSOR_ADXL362_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue