iio: accel: add ADXL367 driver

The ADXL367 is an ultralow power, 3-axis MEMS accelerometer.

The ADXL367 does not alias input signals to achieve ultralow power
consumption, it samples the full bandwidth of the sensor at all
data rates. Measurement ranges of +-2g, +-4g, and +-8g are available,
with a resolution of 0.25mg/LSB on the +-2 g range.

In addition to its ultralow power consumption, the ADXL367
has many features to enable true system level power reduction.
It includes a deep multimode output FIFO, a built-in micropower
temperature sensor, and an internal ADC for synchronous conversion
of an additional analog input.

Signed-off-by: Cosmin Tanislav <cosmin.tanislav@analog.com>
Link: https://lore.kernel.org/r/20220214073810.781016-6-cosmin.tanislav@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Cosmin Tanislav 2022-02-14 09:38:10 +02:00 committed by Jonathan Cameron
parent 27ae7f9d92
commit cbab791c5e
7 changed files with 1903 additions and 0 deletions

View File

@ -606,6 +606,14 @@ F: drivers/iio/accel/adxl355_core.c
F: drivers/iio/accel/adxl355_i2c.c
F: drivers/iio/accel/adxl355_spi.c
ADXL367 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
M: Cosmin Tanislav <cosmin.tanislav@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: http://ez.analog.com/community/linux-device-drivers
F: Documentation/devicetree/bindings/iio/accel/adi,adxl367.yaml
F: drivers/iio/accel/adxl367*
ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported

View File

@ -123,6 +123,33 @@ config ADXL355_SPI
will be called adxl355_spi and you will also get adxl355_core
for the core module.
config ADXL367
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config ADXL367_SPI
tristate "Analog Devices ADXL367 3-Axis Accelerometer SPI Driver"
depends on SPI
select ADXL367
select REGMAP_SPI
help
Say yes here to add support for the Analog Devices ADXL367 triaxial
acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl367_spi.
config ADXL367_I2C
tristate "Analog Devices ADXL367 3-Axis Accelerometer I2C Driver"
depends on I2C
select ADXL367
select REGMAP_I2C
help
Say yes here to add support for the Analog Devices ADXL367 triaxial
acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl367_i2c.
config ADXL372
tristate
select IIO_BUFFER

View File

@ -15,6 +15,9 @@ obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
obj-$(CONFIG_ADXL355) += adxl355_core.o
obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o
obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o
obj-$(CONFIG_ADXL367) += adxl367.o
obj-$(CONFIG_ADXL367_I2C) += adxl367_i2c.o
obj-$(CONFIG_ADXL367_SPI) += adxl367_spi.o
obj-$(CONFIG_ADXL372) += adxl372.o
obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o

1588
drivers/iio/accel/adxl367.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2021 Analog Devices, Inc.
* Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
*/
#ifndef _ADXL367_H_
#define _ADXL367_H_
#include <linux/types.h>
struct device;
struct regmap;
struct adxl367_ops {
int (*read_fifo)(void *context, __be16 *fifo_buf,
unsigned int fifo_entries);
};
int adxl367_probe(struct device *dev, const struct adxl367_ops *ops,
void *context, struct regmap *regmap, int irq);
#endif /* _ADXL367_H_ */

View File

@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Analog Devices, Inc.
* Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
*/
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "adxl367.h"
#define ADXL367_I2C_FIFO_DATA 0x42
struct adxl367_i2c_state {
struct regmap *regmap;
};
static bool adxl367_readable_noinc_reg(struct device *dev, unsigned int reg)
{
return reg == ADXL367_I2C_FIFO_DATA;
}
static int adxl367_i2c_read_fifo(void *context, __be16 *fifo_buf,
unsigned int fifo_entries)
{
struct adxl367_i2c_state *st = context;
return regmap_noinc_read(st->regmap, ADXL367_I2C_FIFO_DATA, fifo_buf,
fifo_entries * sizeof(*fifo_buf));
}
static const struct regmap_config adxl367_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.readable_noinc_reg = adxl367_readable_noinc_reg,
};
static const struct adxl367_ops adxl367_i2c_ops = {
.read_fifo = adxl367_i2c_read_fifo,
};
static int adxl367_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adxl367_i2c_state *st;
struct regmap *regmap;
st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
regmap = devm_regmap_init_i2c(client, &adxl367_i2c_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
st->regmap = regmap;
return adxl367_probe(&client->dev, &adxl367_i2c_ops, st, regmap,
client->irq);
}
static const struct i2c_device_id adxl367_i2c_id[] = {
{ "adxl367", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
static const struct of_device_id adxl367_of_match[] = {
{ .compatible = "adi,adxl367" },
{ },
};
MODULE_DEVICE_TABLE(of, adxl367_of_match);
static struct i2c_driver adxl367_i2c_driver = {
.driver = {
.name = "adxl367_i2c",
.of_match_table = adxl367_of_match,
},
.probe = adxl367_i2c_probe,
.id_table = adxl367_i2c_id,
};
module_i2c_driver(adxl367_i2c_driver);
MODULE_IMPORT_NS(IIO_ADXL367);
MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Analog Devices, Inc.
* Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
*/
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "adxl367.h"
#define ADXL367_SPI_WRITE_COMMAND 0x0A
#define ADXL367_SPI_READ_COMMAND 0x0B
#define ADXL367_SPI_FIFO_COMMAND 0x0D
struct adxl367_spi_state {
struct spi_device *spi;
struct spi_message reg_write_msg;
struct spi_transfer reg_write_xfer[2];
struct spi_message reg_read_msg;
struct spi_transfer reg_read_xfer[2];
struct spi_message fifo_msg;
struct spi_transfer fifo_xfer[2];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
u8 reg_write_tx_buf[1] ____cacheline_aligned;
u8 reg_read_tx_buf[2];
u8 fifo_tx_buf[1];
};
static int adxl367_read_fifo(void *context, __be16 *fifo_buf,
unsigned int fifo_entries)
{
struct adxl367_spi_state *st = context;
st->fifo_xfer[1].rx_buf = fifo_buf;
st->fifo_xfer[1].len = fifo_entries * sizeof(*fifo_buf);
return spi_sync(st->spi, &st->fifo_msg);
}
static int adxl367_read(void *context, const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_size)
{
struct adxl367_spi_state *st = context;
u8 reg = ((const u8 *)reg_buf)[0];
st->reg_read_tx_buf[1] = reg;
st->reg_read_xfer[1].rx_buf = val_buf;
st->reg_read_xfer[1].len = val_size;
return spi_sync(st->spi, &st->reg_read_msg);
}
static int adxl367_write(void *context, const void *val_buf, size_t val_size)
{
struct adxl367_spi_state *st = context;
st->reg_write_xfer[1].tx_buf = val_buf;
st->reg_write_xfer[1].len = val_size;
return spi_sync(st->spi, &st->reg_write_msg);
}
static struct regmap_bus adxl367_spi_regmap_bus = {
.read = adxl367_read,
.write = adxl367_write,
};
static const struct regmap_config adxl367_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static const struct adxl367_ops adxl367_spi_ops = {
.read_fifo = adxl367_read_fifo,
};
static int adxl367_spi_probe(struct spi_device *spi)
{
struct adxl367_spi_state *st;
struct regmap *regmap;
st = devm_kzalloc(&spi->dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
st->spi = spi;
/*
* Xfer: [XFR1] [ XFR2 ]
* Master: 0x0A ADDR DATA0 DATA1 ... DATAN
* Slave: .... ..........................
*/
st->reg_write_tx_buf[0] = ADXL367_SPI_WRITE_COMMAND;
st->reg_write_xfer[0].tx_buf = st->reg_write_tx_buf;
st->reg_write_xfer[0].len = sizeof(st->reg_write_tx_buf);
spi_message_init_with_transfers(&st->reg_write_msg,
st->reg_write_xfer, 2);
/*
* Xfer: [ XFR1 ] [ XFR2 ]
* Master: 0x0B ADDR .....................
* Slave: ......... DATA0 DATA1 ... DATAN
*/
st->reg_read_tx_buf[0] = ADXL367_SPI_READ_COMMAND;
st->reg_read_xfer[0].tx_buf = st->reg_read_tx_buf;
st->reg_read_xfer[0].len = sizeof(st->reg_read_tx_buf);
spi_message_init_with_transfers(&st->reg_read_msg,
st->reg_read_xfer, 2);
/*
* Xfer: [XFR1] [ XFR2 ]
* Master: 0x0D .....................
* Slave: .... DATA0 DATA1 ... DATAN
*/
st->fifo_tx_buf[0] = ADXL367_SPI_FIFO_COMMAND;
st->fifo_xfer[0].tx_buf = st->fifo_tx_buf;
st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf);
spi_message_init_with_transfers(&st->fifo_msg, st->fifo_xfer, 2);
regmap = devm_regmap_init(&spi->dev, &adxl367_spi_regmap_bus, st,
&adxl367_spi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return adxl367_probe(&spi->dev, &adxl367_spi_ops, st, regmap, spi->irq);
}
static const struct spi_device_id adxl367_spi_id[] = {
{ "adxl367", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, adxl367_spi_id);
static const struct of_device_id adxl367_of_match[] = {
{ .compatible = "adi,adxl367" },
{ },
};
MODULE_DEVICE_TABLE(of, adxl367_of_match);
static struct spi_driver adxl367_spi_driver = {
.driver = {
.name = "adxl367_spi",
.of_match_table = adxl367_of_match,
},
.probe = adxl367_spi_probe,
.id_table = adxl367_spi_id,
};
module_spi_driver(adxl367_spi_driver);
MODULE_IMPORT_NS(IIO_ADXL367);
MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver");
MODULE_LICENSE("GPL");