mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
af37e4703d
Compared to the other supported parts, AD7091R are dependent of a CONVST signal that initiates the conversion. At this moment, only sampling in buffered mode is supported for AD7091R and the only option until now was to generate this signal externally using an IIO trigger. This patch adds the option of generating it internally, more compatible triggers being available in this case. Also, it is an intermediate step of adding support more devices. Signed-off-by: Dragos Bogdan <dragos.bogdan@analog.com> Signed-off-by: Beniamin Bia <beniamin.bia@analog.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
376 lines
8.8 KiB
C
376 lines
8.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Analog Devices AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
|
|
* TI ADC081S/ADC101S/ADC121S 8/10/12-bit SPI ADC driver
|
|
*
|
|
* Copyright 2010 Analog Devices Inc.
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/err.h>
|
|
#include <linux/module.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/sysfs.h>
|
|
#include <linux/iio/buffer.h>
|
|
#include <linux/iio/trigger_consumer.h>
|
|
#include <linux/iio/triggered_buffer.h>
|
|
|
|
struct ad7476_state;
|
|
|
|
struct ad7476_chip_info {
|
|
unsigned int int_vref_uv;
|
|
struct iio_chan_spec channel[2];
|
|
void (*reset)(struct ad7476_state *);
|
|
};
|
|
|
|
struct ad7476_state {
|
|
struct spi_device *spi;
|
|
const struct ad7476_chip_info *chip_info;
|
|
struct regulator *reg;
|
|
struct gpio_desc *convst_gpio;
|
|
struct spi_transfer xfer;
|
|
struct spi_message msg;
|
|
/*
|
|
* DMA (thus cache coherency maintenance) requires the
|
|
* transfer buffers to live in their own cache lines.
|
|
* Make the buffer large enough for one 16 bit sample and one 64 bit
|
|
* aligned 64 bit timestamp.
|
|
*/
|
|
unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)]
|
|
____cacheline_aligned;
|
|
};
|
|
|
|
enum ad7476_supported_device_ids {
|
|
ID_AD7091R,
|
|
ID_AD7276,
|
|
ID_AD7277,
|
|
ID_AD7278,
|
|
ID_AD7466,
|
|
ID_AD7467,
|
|
ID_AD7468,
|
|
ID_AD7495,
|
|
ID_AD7940,
|
|
ID_ADC081S,
|
|
ID_ADC101S,
|
|
ID_ADC121S,
|
|
ID_ADS7866,
|
|
ID_ADS7867,
|
|
ID_ADS7868,
|
|
};
|
|
|
|
static void ad7091_convst(struct ad7476_state *st)
|
|
{
|
|
if (!st->convst_gpio)
|
|
return;
|
|
|
|
gpiod_set_value(st->convst_gpio, 0);
|
|
udelay(1); /* CONVST pulse width: 10 ns min */
|
|
gpiod_set_value(st->convst_gpio, 1);
|
|
udelay(1); /* Conversion time: 650 ns max */
|
|
}
|
|
|
|
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
|
|
{
|
|
struct iio_poll_func *pf = p;
|
|
struct iio_dev *indio_dev = pf->indio_dev;
|
|
struct ad7476_state *st = iio_priv(indio_dev);
|
|
int b_sent;
|
|
|
|
ad7091_convst(st);
|
|
|
|
b_sent = spi_sync(st->spi, &st->msg);
|
|
if (b_sent < 0)
|
|
goto done;
|
|
|
|
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
|
iio_get_time_ns(indio_dev));
|
|
done:
|
|
iio_trigger_notify_done(indio_dev->trig);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static void ad7091_reset(struct ad7476_state *st)
|
|
{
|
|
/* Any transfers with 8 scl cycles will reset the device */
|
|
spi_read(st->spi, st->data, 1);
|
|
}
|
|
|
|
static int ad7476_scan_direct(struct ad7476_state *st)
|
|
{
|
|
int ret;
|
|
|
|
ret = spi_sync(st->spi, &st->msg);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return be16_to_cpup((__be16 *)st->data);
|
|
}
|
|
|
|
static int ad7476_read_raw(struct iio_dev *indio_dev,
|
|
struct iio_chan_spec const *chan,
|
|
int *val,
|
|
int *val2,
|
|
long m)
|
|
{
|
|
int ret;
|
|
struct ad7476_state *st = iio_priv(indio_dev);
|
|
int scale_uv;
|
|
|
|
switch (m) {
|
|
case IIO_CHAN_INFO_RAW:
|
|
ret = iio_device_claim_direct_mode(indio_dev);
|
|
if (ret)
|
|
return ret;
|
|
ret = ad7476_scan_direct(st);
|
|
iio_device_release_direct_mode(indio_dev);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
|
|
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
|
|
return IIO_VAL_INT;
|
|
case IIO_CHAN_INFO_SCALE:
|
|
if (!st->chip_info->int_vref_uv) {
|
|
scale_uv = regulator_get_voltage(st->reg);
|
|
if (scale_uv < 0)
|
|
return scale_uv;
|
|
} else {
|
|
scale_uv = st->chip_info->int_vref_uv;
|
|
}
|
|
*val = scale_uv / 1000;
|
|
*val2 = chan->scan_type.realbits;
|
|
return IIO_VAL_FRACTIONAL_LOG2;
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
#define _AD7476_CHAN(bits, _shift, _info_mask_sep) \
|
|
{ \
|
|
.type = IIO_VOLTAGE, \
|
|
.indexed = 1, \
|
|
.info_mask_separate = _info_mask_sep, \
|
|
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
|
.scan_type = { \
|
|
.sign = 'u', \
|
|
.realbits = (bits), \
|
|
.storagebits = 16, \
|
|
.shift = (_shift), \
|
|
.endianness = IIO_BE, \
|
|
}, \
|
|
}
|
|
|
|
#define ADC081S_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
|
|
BIT(IIO_CHAN_INFO_RAW))
|
|
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
|
|
BIT(IIO_CHAN_INFO_RAW))
|
|
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
|
|
BIT(IIO_CHAN_INFO_RAW))
|
|
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
|
|
#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
|
|
BIT(IIO_CHAN_INFO_RAW))
|
|
|
|
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
|
|
[ID_AD7091R] = {
|
|
.channel[0] = AD7091R_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
.reset = ad7091_reset,
|
|
},
|
|
[ID_AD7276] = {
|
|
.channel[0] = AD7940_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7277] = {
|
|
.channel[0] = AD7940_CHAN(10),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7278] = {
|
|
.channel[0] = AD7940_CHAN(8),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7466] = {
|
|
.channel[0] = AD7476_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7467] = {
|
|
.channel[0] = AD7476_CHAN(10),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7468] = {
|
|
.channel[0] = AD7476_CHAN(8),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_AD7495] = {
|
|
.channel[0] = AD7476_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
.int_vref_uv = 2500000,
|
|
},
|
|
[ID_AD7940] = {
|
|
.channel[0] = AD7940_CHAN(14),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADC081S] = {
|
|
.channel[0] = ADC081S_CHAN(8),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADC101S] = {
|
|
.channel[0] = ADC081S_CHAN(10),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADC121S] = {
|
|
.channel[0] = ADC081S_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADS7866] = {
|
|
.channel[0] = ADS786X_CHAN(12),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADS7867] = {
|
|
.channel[0] = ADS786X_CHAN(10),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
[ID_ADS7868] = {
|
|
.channel[0] = ADS786X_CHAN(8),
|
|
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
|
},
|
|
};
|
|
|
|
static const struct iio_info ad7476_info = {
|
|
.read_raw = &ad7476_read_raw,
|
|
};
|
|
|
|
static int ad7476_probe(struct spi_device *spi)
|
|
{
|
|
struct ad7476_state *st;
|
|
struct iio_dev *indio_dev;
|
|
int ret;
|
|
|
|
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
|
if (!indio_dev)
|
|
return -ENOMEM;
|
|
|
|
st = iio_priv(indio_dev);
|
|
st->chip_info =
|
|
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
|
|
|
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
|
if (IS_ERR(st->reg))
|
|
return PTR_ERR(st->reg);
|
|
|
|
ret = regulator_enable(st->reg);
|
|
if (ret)
|
|
return ret;
|
|
|
|
st->convst_gpio = devm_gpiod_get_optional(&spi->dev,
|
|
"adi,conversion-start",
|
|
GPIOD_OUT_LOW);
|
|
if (IS_ERR(st->convst_gpio))
|
|
return PTR_ERR(st->convst_gpio);
|
|
|
|
spi_set_drvdata(spi, indio_dev);
|
|
|
|
st->spi = spi;
|
|
|
|
/* Establish that the iio_dev is a child of the spi device */
|
|
indio_dev->dev.parent = &spi->dev;
|
|
indio_dev->dev.of_node = spi->dev.of_node;
|
|
indio_dev->name = spi_get_device_id(spi)->name;
|
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
|
indio_dev->channels = st->chip_info->channel;
|
|
indio_dev->num_channels = 2;
|
|
indio_dev->info = &ad7476_info;
|
|
/* Setup default message */
|
|
|
|
st->xfer.rx_buf = &st->data;
|
|
st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8;
|
|
|
|
spi_message_init(&st->msg);
|
|
spi_message_add_tail(&st->xfer, &st->msg);
|
|
|
|
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
|
&ad7476_trigger_handler, NULL);
|
|
if (ret)
|
|
goto error_disable_reg;
|
|
|
|
if (st->chip_info->reset)
|
|
st->chip_info->reset(st);
|
|
|
|
ret = iio_device_register(indio_dev);
|
|
if (ret)
|
|
goto error_ring_unregister;
|
|
return 0;
|
|
|
|
error_ring_unregister:
|
|
iio_triggered_buffer_cleanup(indio_dev);
|
|
error_disable_reg:
|
|
regulator_disable(st->reg);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int ad7476_remove(struct spi_device *spi)
|
|
{
|
|
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
|
struct ad7476_state *st = iio_priv(indio_dev);
|
|
|
|
iio_device_unregister(indio_dev);
|
|
iio_triggered_buffer_cleanup(indio_dev);
|
|
regulator_disable(st->reg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct spi_device_id ad7476_id[] = {
|
|
{"ad7091r", ID_AD7091R},
|
|
{"ad7273", ID_AD7277},
|
|
{"ad7274", ID_AD7276},
|
|
{"ad7276", ID_AD7276},
|
|
{"ad7277", ID_AD7277},
|
|
{"ad7278", ID_AD7278},
|
|
{"ad7466", ID_AD7466},
|
|
{"ad7467", ID_AD7467},
|
|
{"ad7468", ID_AD7468},
|
|
{"ad7475", ID_AD7466},
|
|
{"ad7476", ID_AD7466},
|
|
{"ad7476a", ID_AD7466},
|
|
{"ad7477", ID_AD7467},
|
|
{"ad7477a", ID_AD7467},
|
|
{"ad7478", ID_AD7468},
|
|
{"ad7478a", ID_AD7468},
|
|
{"ad7495", ID_AD7495},
|
|
{"ad7910", ID_AD7467},
|
|
{"ad7920", ID_AD7466},
|
|
{"ad7940", ID_AD7940},
|
|
{"adc081s", ID_ADC081S},
|
|
{"adc101s", ID_ADC101S},
|
|
{"adc121s", ID_ADC121S},
|
|
{"ads7866", ID_ADS7866},
|
|
{"ads7867", ID_ADS7867},
|
|
{"ads7868", ID_ADS7868},
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(spi, ad7476_id);
|
|
|
|
static struct spi_driver ad7476_driver = {
|
|
.driver = {
|
|
.name = "ad7476",
|
|
},
|
|
.probe = ad7476_probe,
|
|
.remove = ad7476_remove,
|
|
.id_table = ad7476_id,
|
|
};
|
|
module_spi_driver(ad7476_driver);
|
|
|
|
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
|
|
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
|
|
MODULE_LICENSE("GPL v2");
|