iio: adc: Add support for AD7091R-8
Add support for Analog Devices AD7091R-2, AD7091R-4, and AD7091R-8 low power 12-Bit SAR ADCs with SPI interface. Extend ad7091r-base driver so it can be used by the AD7091R-8 driver. Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com> Link: https://lore.kernel.org/r/09d1d1c4b39cecc528488efac6094233715f5659.1703013352.git.marcelo.schmitt1@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
6875b85729
commit
0b76ff46c4
@ -47,6 +47,18 @@ config AD7091R5
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7091R-5 ADC.
|
||||
|
||||
config AD7091R8
|
||||
tristate "Analog Devices AD7091R8 ADC Driver"
|
||||
depends on SPI
|
||||
select AD7091R
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7091R-2, AD7091R-4,
|
||||
and AD7091R-8 ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7091r8.
|
||||
|
||||
config AD7124
|
||||
tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
|
||||
depends on SPI_MASTER
|
||||
|
@ -9,6 +9,7 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
|
||||
obj-$(CONFIG_AD4130) += ad4130.o
|
||||
obj-$(CONFIG_AD7091R) += ad7091r-base.o
|
||||
obj-$(CONFIG_AD7091R5) += ad7091r5.o
|
||||
obj-$(CONFIG_AD7091R8) += ad7091r8.o
|
||||
obj-$(CONFIG_AD7124) += ad7124.o
|
||||
obj-$(CONFIG_AD7192) += ad7192.o
|
||||
obj-$(CONFIG_AD7266) += ad7266.o
|
||||
|
@ -322,6 +322,12 @@ int ad7091r_probe(struct device *dev, const struct ad7091r_init_info *init_info,
|
||||
iio_dev->info = &ad7091r_info;
|
||||
iio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
if (init_info->setup) {
|
||||
ret = init_info->setup(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (irq) {
|
||||
st->chip_info = init_info->info_irq;
|
||||
ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
|
||||
|
@ -49,6 +49,7 @@
|
||||
}
|
||||
|
||||
struct device;
|
||||
struct gpio_desc;
|
||||
|
||||
enum ad7091r_mode {
|
||||
AD7091R_MODE_SAMPLE,
|
||||
@ -59,10 +60,14 @@ enum ad7091r_mode {
|
||||
struct ad7091r_state {
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
struct gpio_desc *convst_gpio;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator *vref;
|
||||
const struct ad7091r_chip_info *chip_info;
|
||||
enum ad7091r_mode mode;
|
||||
struct mutex lock; /*lock to prevent concurent reads */
|
||||
__be16 tx_buf __aligned(IIO_DMA_MINALIGN);
|
||||
__be16 rx_buf;
|
||||
};
|
||||
|
||||
struct ad7091r_chip_info {
|
||||
@ -80,6 +85,7 @@ struct ad7091r_init_info {
|
||||
const struct regmap_config *regmap_config;
|
||||
void (*init_adc_regmap)(struct ad7091r_state *st,
|
||||
const struct regmap_config *regmap_conf);
|
||||
int (*setup)(struct ad7091r_state *st);
|
||||
};
|
||||
|
||||
extern const struct iio_event_spec ad7091r_events[3];
|
||||
|
272
drivers/iio/adc/ad7091r8.c
Normal file
272
drivers/iio/adc/ad7091r8.c
Normal file
@ -0,0 +1,272 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Analog Devices AD7091R8 12-bit SAR ADC driver
|
||||
*
|
||||
* Copyright 2023 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "ad7091r-base.h"
|
||||
|
||||
#define AD7091R8_REG_ADDR_MSK GENMASK(15, 11)
|
||||
#define AD7091R8_RD_WR_FLAG_MSK BIT(10)
|
||||
#define AD7091R8_REG_DATA_MSK GENMASK(9, 0)
|
||||
|
||||
#define AD7091R_SPI_REGMAP_CONFIG(n) { \
|
||||
.reg_bits = 8, \
|
||||
.val_bits = 16, \
|
||||
.volatile_reg = ad7091r_volatile_reg, \
|
||||
.writeable_reg = ad7091r_writeable_reg, \
|
||||
.max_register = AD7091R_REG_CH_HYSTERESIS(n), \
|
||||
}
|
||||
|
||||
static int ad7091r8_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
|
||||
{
|
||||
/* AD7091R-2/-4/-8 don't set sample/command/autocycle mode in conf reg */
|
||||
st->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ad7091r8_reg_result_chan_id(unsigned int val)
|
||||
{
|
||||
return AD7091R8_REG_RESULT_CH_ID(val);
|
||||
}
|
||||
|
||||
#define AD7091R_SPI_CHIP_INFO(_n, _name) { \
|
||||
.name = _name, \
|
||||
.channels = ad7091r##_n##_channels, \
|
||||
.num_channels = ARRAY_SIZE(ad7091r##_n##_channels), \
|
||||
.vref_mV = 2500, \
|
||||
.reg_result_chan_id = &ad7091r8_reg_result_chan_id, \
|
||||
.set_mode = &ad7091r8_set_mode, \
|
||||
}
|
||||
|
||||
#define AD7091R_SPI_CHIP_INFO_IRQ(_n, _name) { \
|
||||
.name = _name, \
|
||||
.channels = ad7091r##_n##_channels_irq, \
|
||||
.num_channels = ARRAY_SIZE(ad7091r##_n##_channels_irq), \
|
||||
.vref_mV = 2500, \
|
||||
.reg_result_chan_id = &ad7091r8_reg_result_chan_id, \
|
||||
.set_mode = &ad7091r8_set_mode, \
|
||||
}
|
||||
|
||||
enum ad7091r8_info_ids {
|
||||
AD7091R2_INFO,
|
||||
AD7091R4_INFO,
|
||||
AD7091R4_INFO_IRQ,
|
||||
AD7091R8_INFO,
|
||||
AD7091R8_INFO_IRQ,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7091r2_channels[] = {
|
||||
AD7091R_CHANNEL(0, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(1, 12, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7091r4_channels[] = {
|
||||
AD7091R_CHANNEL(0, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(1, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(2, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(3, 12, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7091r4_channels_irq[] = {
|
||||
AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7091r8_channels[] = {
|
||||
AD7091R_CHANNEL(0, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(1, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(2, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(3, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(4, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(5, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(6, 12, NULL, 0),
|
||||
AD7091R_CHANNEL(7, 12, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7091r8_channels_irq[] = {
|
||||
AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(4, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(5, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(6, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
AD7091R_CHANNEL(7, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
|
||||
};
|
||||
|
||||
static void ad7091r_pulse_convst(struct ad7091r_state *st)
|
||||
{
|
||||
gpiod_set_value_cansleep(st->convst_gpio, 1);
|
||||
gpiod_set_value_cansleep(st->convst_gpio, 0);
|
||||
}
|
||||
|
||||
static int ad7091r_regmap_bus_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
struct ad7091r_state *st = context;
|
||||
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
|
||||
int ret;
|
||||
|
||||
struct spi_transfer t[] = {
|
||||
{
|
||||
.tx_buf = &st->tx_buf,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
}, {
|
||||
.rx_buf = &st->rx_buf,
|
||||
.len = 2,
|
||||
}
|
||||
};
|
||||
|
||||
if (reg == AD7091R_REG_RESULT)
|
||||
ad7091r_pulse_convst(st);
|
||||
|
||||
st->tx_buf = cpu_to_be16(reg << 11);
|
||||
|
||||
ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = be16_to_cpu(st->rx_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7091r_regmap_bus_reg_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct ad7091r_state *st = context;
|
||||
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
|
||||
|
||||
/*
|
||||
* AD7091R-2/-4/-8 protocol (datasheet page 31) is to do a single SPI
|
||||
* transfer with reg address set in bits B15:B11 and value set in B9:B0.
|
||||
*/
|
||||
st->tx_buf = cpu_to_be16(FIELD_PREP(AD7091R8_REG_DATA_MSK, val) |
|
||||
FIELD_PREP(AD7091R8_RD_WR_FLAG_MSK, 1) |
|
||||
FIELD_PREP(AD7091R8_REG_ADDR_MSK, reg));
|
||||
|
||||
return spi_write(spi, &st->tx_buf, 2);
|
||||
}
|
||||
|
||||
static struct regmap_bus ad7091r8_regmap_bus = {
|
||||
.reg_read = ad7091r_regmap_bus_reg_read,
|
||||
.reg_write = ad7091r_regmap_bus_reg_write,
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
};
|
||||
|
||||
static const struct ad7091r_chip_info ad7091r8_infos[] = {
|
||||
[AD7091R2_INFO] = AD7091R_SPI_CHIP_INFO(2, "ad7091r-2"),
|
||||
[AD7091R4_INFO] = AD7091R_SPI_CHIP_INFO(4, "ad7091r-4"),
|
||||
[AD7091R4_INFO_IRQ] = AD7091R_SPI_CHIP_INFO_IRQ(4, "ad7091r-4"),
|
||||
[AD7091R8_INFO] = AD7091R_SPI_CHIP_INFO(8, "ad7091r-8"),
|
||||
[AD7091R8_INFO_IRQ] = AD7091R_SPI_CHIP_INFO_IRQ(8, "ad7091r-8")
|
||||
};
|
||||
|
||||
static const struct regmap_config ad7091r2_reg_conf = AD7091R_SPI_REGMAP_CONFIG(2);
|
||||
static const struct regmap_config ad7091r4_reg_conf = AD7091R_SPI_REGMAP_CONFIG(4);
|
||||
static const struct regmap_config ad7091r8_reg_conf = AD7091R_SPI_REGMAP_CONFIG(8);
|
||||
|
||||
static void ad7091r8_regmap_init(struct ad7091r_state *st,
|
||||
const struct regmap_config *regmap_conf)
|
||||
{
|
||||
st->map = devm_regmap_init(st->dev, &ad7091r8_regmap_bus, st,
|
||||
regmap_conf);
|
||||
}
|
||||
|
||||
static int ad7091r8_gpio_setup(struct ad7091r_state *st)
|
||||
{
|
||||
st->convst_gpio = devm_gpiod_get(st->dev, "convst", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->convst_gpio))
|
||||
return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio),
|
||||
"Error getting convst GPIO\n");
|
||||
|
||||
st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(st->reset_gpio))
|
||||
return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio),
|
||||
"Error on requesting reset GPIO\n");
|
||||
|
||||
if (st->reset_gpio) {
|
||||
fsleep(20);
|
||||
gpiod_set_value_cansleep(st->reset_gpio, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ad7091r_init_info ad7091r2_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R2_INFO],
|
||||
.regmap_config = &ad7091r2_reg_conf,
|
||||
.init_adc_regmap = &ad7091r8_regmap_init,
|
||||
.setup = &ad7091r8_gpio_setup
|
||||
};
|
||||
|
||||
static struct ad7091r_init_info ad7091r4_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R4_INFO],
|
||||
.info_irq = &ad7091r8_infos[AD7091R4_INFO_IRQ],
|
||||
.regmap_config = &ad7091r4_reg_conf,
|
||||
.init_adc_regmap = &ad7091r8_regmap_init,
|
||||
.setup = &ad7091r8_gpio_setup
|
||||
};
|
||||
|
||||
static struct ad7091r_init_info ad7091r8_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R8_INFO],
|
||||
.info_irq = &ad7091r8_infos[AD7091R8_INFO_IRQ],
|
||||
.regmap_config = &ad7091r8_reg_conf,
|
||||
.init_adc_regmap = &ad7091r8_regmap_init,
|
||||
.setup = &ad7091r8_gpio_setup
|
||||
};
|
||||
|
||||
static int ad7091r8_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7091r_init_info *init_info;
|
||||
|
||||
init_info = spi_get_device_match_data(spi);
|
||||
if (!init_info)
|
||||
return -EINVAL;
|
||||
|
||||
return ad7091r_probe(&spi->dev, init_info, spi->irq);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7091r8_of_match[] = {
|
||||
{ .compatible = "adi,ad7091r2", .data = &ad7091r2_init_info },
|
||||
{ .compatible = "adi,ad7091r4", .data = &ad7091r4_init_info },
|
||||
{ .compatible = "adi,ad7091r8", .data = &ad7091r8_init_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7091r8_of_match);
|
||||
|
||||
static const struct spi_device_id ad7091r8_spi_id[] = {
|
||||
{ "ad7091r2", (kernel_ulong_t)&ad7091r2_init_info },
|
||||
{ "ad7091r4", (kernel_ulong_t)&ad7091r4_init_info },
|
||||
{ "ad7091r8", (kernel_ulong_t)&ad7091r8_init_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad7091r8_spi_id);
|
||||
|
||||
static struct spi_driver ad7091r8_driver = {
|
||||
.driver = {
|
||||
.name = "ad7091r8",
|
||||
.of_match_table = ad7091r8_of_match,
|
||||
},
|
||||
.probe = ad7091r8_spi_probe,
|
||||
.id_table = ad7091r8_spi_id,
|
||||
};
|
||||
module_spi_driver(ad7091r8_driver);
|
||||
|
||||
MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7091R8 ADC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IIO_AD7091R);
|
Loading…
Reference in New Issue
Block a user