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:
Родитель
27ae7f9d92
Коммит
cbab791c5e
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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_ */
|
|
@ -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");
|
|
@ -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");
|
Загрузка…
Ссылка в новой задаче