Initial commit; kernel source import

This commit is contained in:
Nathan
2025-04-06 23:50:55 -05:00
commit 25c6d769f4
45093 changed files with 18199410 additions and 0 deletions

160
drivers/iio/adc/Kconfig Normal file
View File

@@ -0,0 +1,160 @@
#
# ADC drivers
#
menu "Analog to digital converters"
config AD_SIGMA_DELTA
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7266
tristate "Analog Devices AD7265/AD7266 ADC driver"
depends on SPI_MASTER
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7298
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7298.
config AD7923
tristate "Analog Devices AD7923 and similar ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
To compile this driver as a module, choose M here: the
module will be called ad7923.
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7787, AD7788, AD7789,
AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say
N (but it is safe to say "Y").
To compile this driver as a module, choose M here: the module will be
called ad7791.
config AD7793
tristate "Analog Devices AD7793 and similar ADCs driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7785, AD7792, AD7793,
AD7794 and AD7795 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called AD7793.
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7476.
config AD7887
tristate "Analog Devices AD7887 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7887 SPI analog to digital converter (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7887.
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select SYSFS
help
Say yes here to build support for Atmel AT91 ADC.
config EXYNOS_ADC
bool "Exynos ADC driver support"
depends on OF
help
Core support for the ADC block found in the Samsung EXYNOS series
of SoCs for drivers such as the touchscreen and hwmon to use to share
this resource.
config LP8788_ADC
bool "LP8788 ADC driver"
depends on MFD_LP8788
help
Say yes here to build support for TI LP8788 ADC.
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for many Maxim i2c analog to digital
converters (ADC). (max1361, max1362, max1363, max1364, max1036,
max1037, max1038, max1039, max1136, max1136, max1137, max1138,
max1139, max1236, max1237, max11238, max1239, max11600, max11601,
max11602, max11603, max11604, max11605, max11606, max11607,
max11608, max11609, max11610, max11611, max11612, max11613,
max11614, max11615, max11616, max11617, max11644, max11645,
max11646, max11647) Provides direct access via sysfs and buffered
data via the iio dev interface.
config TI_ADC081C
tristate "Texas Instruments ADC081C021/027"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADC081C021
and ADC081C027 ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-adc081c.
config TI_AM335X_ADC
tristate "TI's ADC driver"
depends on MFD_TI_AM335X_TSCADC
help
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
config VIPERBOARD_ADC
tristate "Viperboard ADC support"
depends on MFD_VIPERBOARD && USB
help
Say yes here to access the ADC part of the Nano River
Technologies Viperboard.
endmenu

19
drivers/iio/adc/Makefile Normal file
View File

@@ -0,0 +1,19 @@
#
# Makefile for IIO ADC drivers
#
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o

539
drivers/iio/adc/ad7266.c Normal file
View File

@@ -0,0 +1,539 @@
/*
* AD7266/65 SPI ADC driver
*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/platform_data/ad7266.h>
struct ad7266_state {
struct spi_device *spi;
struct regulator *reg;
unsigned long vref_uv;
struct spi_transfer single_xfer[3];
struct spi_message single_msg;
enum ad7266_range range;
enum ad7266_mode mode;
bool fixed_addr;
struct gpio gpios[3];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* The buffer needs to be large enough to hold two samples (4 bytes) and
* the naturally aligned timestamp (8 bytes).
*/
uint8_t data[ALIGN(4, sizeof(s64)) + sizeof(s64)] ____cacheline_aligned;
};
static int ad7266_wakeup(struct ad7266_state *st)
{
/* Any read with >= 2 bytes will wake the device */
return spi_read(st->spi, st->data, 2);
}
static int ad7266_powerdown(struct ad7266_state *st)
{
/* Any read with < 2 bytes will powerdown the device */
return spi_read(st->spi, st->data, 1);
}
static int ad7266_preenable(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
ret = ad7266_wakeup(st);
if (ret)
return ret;
ret = iio_sw_buffer_preenable(indio_dev);
if (ret)
ad7266_powerdown(st);
return ret;
}
static int ad7266_postdisable(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
return ad7266_powerdown(st);
}
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
.preenable = &ad7266_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad7266_postdisable,
};
static irqreturn_t ad7266_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
ret = spi_read(st->spi, st->data, 4);
if (ret == 0) {
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)st->data);
}
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static void ad7266_select_input(struct ad7266_state *st, unsigned int nr)
{
unsigned int i;
if (st->fixed_addr)
return;
switch (st->mode) {
case AD7266_MODE_SINGLE_ENDED:
nr >>= 1;
break;
case AD7266_MODE_PSEUDO_DIFF:
nr |= 1;
break;
case AD7266_MODE_DIFF:
nr &= ~1;
break;
}
for (i = 0; i < 3; ++i)
gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i)));
}
static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad7266_state *st = iio_priv(indio_dev);
unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength);
ad7266_select_input(st, nr);
return 0;
}
static int ad7266_read_single(struct ad7266_state *st, int *val,
unsigned int address)
{
int ret;
ad7266_select_input(st, address);
ret = spi_sync(st->spi, &st->single_msg);
*val = be16_to_cpu(st->data[address % 2]);
return ret;
}
static int ad7266_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long m)
{
struct ad7266_state *st = iio_priv(indio_dev);
unsigned long scale_uv;
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = ad7266_read_single(st, val, chan->address);
if (ret)
return ret;
*val = (*val >> 2) & 0xfff;
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = (st->vref_uv * 100);
if (st->mode == AD7266_MODE_DIFF)
scale_uv *= 2;
if (st->range == AD7266_RANGE_2VREF)
scale_uv *= 2;
scale_uv >>= chan->scan_type.realbits;
*val = scale_uv / 100000;
*val2 = (scale_uv % 100000) * 10;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OFFSET:
if (st->range == AD7266_RANGE_2VREF &&
st->mode != AD7266_MODE_DIFF)
*val = 2048;
else
*val = 0;
return IIO_VAL_INT;
}
return -EINVAL;
}
#define AD7266_CHAN(_chan, _sign) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = (_sign), \
.realbits = 12, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
}
#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS(_name, _sign) \
const struct iio_chan_spec ad7266_channels_##_name[] = { \
AD7266_CHAN(0, (_sign)), \
AD7266_CHAN(1, (_sign)), \
AD7266_CHAN(2, (_sign)), \
AD7266_CHAN(3, (_sign)), \
AD7266_CHAN(4, (_sign)), \
AD7266_CHAN(5, (_sign)), \
AD7266_CHAN(6, (_sign)), \
AD7266_CHAN(7, (_sign)), \
AD7266_CHAN(8, (_sign)), \
AD7266_CHAN(9, (_sign)), \
AD7266_CHAN(10, (_sign)), \
AD7266_CHAN(11, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(13), \
}
#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(_name, _sign) \
const struct iio_chan_spec ad7266_channels_##_name##_fixed[] = { \
AD7266_CHAN(0, (_sign)), \
AD7266_CHAN(1, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(u, 'u');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(s, 's');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(u, 'u');
static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's');
#define AD7266_CHAN_DIFF(_chan, _sign) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2, \
.channel2 = (_chan) * 2 + 1, \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = _sign, \
.realbits = 12, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
.differential = 1, \
}
#define AD7266_DECLARE_DIFF_CHANNELS(_name, _sign) \
const struct iio_chan_spec ad7266_channels_diff_##_name[] = { \
AD7266_CHAN_DIFF(0, (_sign)), \
AD7266_CHAN_DIFF(1, (_sign)), \
AD7266_CHAN_DIFF(2, (_sign)), \
AD7266_CHAN_DIFF(3, (_sign)), \
AD7266_CHAN_DIFF(4, (_sign)), \
AD7266_CHAN_DIFF(5, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(6), \
}
static AD7266_DECLARE_DIFF_CHANNELS(s, 's');
static AD7266_DECLARE_DIFF_CHANNELS(u, 'u');
#define AD7266_DECLARE_DIFF_CHANNELS_FIXED(_name, _sign) \
const struct iio_chan_spec ad7266_channels_diff_fixed_##_name[] = { \
AD7266_CHAN_DIFF(0, (_sign)), \
AD7266_CHAN_DIFF(1, (_sign)), \
IIO_CHAN_SOFT_TIMESTAMP(2), \
}
static AD7266_DECLARE_DIFF_CHANNELS_FIXED(s, 's');
static AD7266_DECLARE_DIFF_CHANNELS_FIXED(u, 'u');
static const struct iio_info ad7266_info = {
.read_raw = &ad7266_read_raw,
.update_scan_mode = &ad7266_update_scan_mode,
.driver_module = THIS_MODULE,
};
static unsigned long ad7266_available_scan_masks[] = {
0x003,
0x00c,
0x030,
0x0c0,
0x300,
0xc00,
0x000,
};
static unsigned long ad7266_available_scan_masks_diff[] = {
0x003,
0x00c,
0x030,
0x000,
};
static unsigned long ad7266_available_scan_masks_fixed[] = {
0x003,
0x000,
};
struct ad7266_chan_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned long *scan_masks;
};
#define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \
(((_differential) << 2) | ((_signed) << 1) | ((_fixed) << 0))
static const struct ad7266_chan_info ad7266_chan_infos[] = {
[AD7266_CHAN_INFO_INDEX(0, 0, 0)] = {
.channels = ad7266_channels_u,
.num_channels = ARRAY_SIZE(ad7266_channels_u),
.scan_masks = ad7266_available_scan_masks,
},
[AD7266_CHAN_INFO_INDEX(0, 0, 1)] = {
.channels = ad7266_channels_u_fixed,
.num_channels = ARRAY_SIZE(ad7266_channels_u_fixed),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(0, 1, 0)] = {
.channels = ad7266_channels_s,
.num_channels = ARRAY_SIZE(ad7266_channels_s),
.scan_masks = ad7266_available_scan_masks,
},
[AD7266_CHAN_INFO_INDEX(0, 1, 1)] = {
.channels = ad7266_channels_s_fixed,
.num_channels = ARRAY_SIZE(ad7266_channels_s_fixed),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(1, 0, 0)] = {
.channels = ad7266_channels_diff_u,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_u),
.scan_masks = ad7266_available_scan_masks_diff,
},
[AD7266_CHAN_INFO_INDEX(1, 0, 1)] = {
.channels = ad7266_channels_diff_fixed_u,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_u),
.scan_masks = ad7266_available_scan_masks_fixed,
},
[AD7266_CHAN_INFO_INDEX(1, 1, 0)] = {
.channels = ad7266_channels_diff_s,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_s),
.scan_masks = ad7266_available_scan_masks_diff,
},
[AD7266_CHAN_INFO_INDEX(1, 1, 1)] = {
.channels = ad7266_channels_diff_fixed_s,
.num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_s),
.scan_masks = ad7266_available_scan_masks_fixed,
},
};
static void ad7266_init_channels(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
bool is_differential, is_signed;
const struct ad7266_chan_info *chan_info;
int i;
is_differential = st->mode != AD7266_MODE_SINGLE_ENDED;
is_signed = (st->range == AD7266_RANGE_2VREF) |
(st->mode == AD7266_MODE_DIFF);
i = AD7266_CHAN_INFO_INDEX(is_differential, is_signed, st->fixed_addr);
chan_info = &ad7266_chan_infos[i];
indio_dev->channels = chan_info->channels;
indio_dev->num_channels = chan_info->num_channels;
indio_dev->available_scan_masks = chan_info->scan_masks;
indio_dev->masklength = chan_info->num_channels - 1;
}
static const char * const ad7266_gpio_labels[] = {
"AD0", "AD1", "AD2",
};
static int ad7266_probe(struct spi_device *spi)
{
struct ad7266_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad7266_state *st;
unsigned int i;
int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "vref");
if (!IS_ERR_OR_NULL(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
st->vref_uv = ret;
} else {
/* Use internal reference */
st->vref_uv = 2500000;
}
if (pdata) {
st->fixed_addr = pdata->fixed_addr;
st->mode = pdata->mode;
st->range = pdata->range;
if (!st->fixed_addr) {
for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) {
st->gpios[i].gpio = pdata->addr_gpios[i];
st->gpios[i].flags = GPIOF_OUT_INIT_LOW;
st->gpios[i].label = ad7266_gpio_labels[i];
}
ret = gpio_request_array(st->gpios,
ARRAY_SIZE(st->gpios));
if (ret)
goto error_disable_reg;
}
} else {
st->fixed_addr = true;
st->range = AD7266_RANGE_VREF;
st->mode = AD7266_MODE_DIFF;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7266_info;
ad7266_init_channels(indio_dev);
/* wakeup */
st->single_xfer[0].rx_buf = &st->data;
st->single_xfer[0].len = 2;
st->single_xfer[0].cs_change = 1;
/* conversion */
st->single_xfer[1].rx_buf = &st->data;
st->single_xfer[1].len = 4;
st->single_xfer[1].cs_change = 1;
/* powerdown */
st->single_xfer[2].tx_buf = &st->data;
st->single_xfer[2].len = 1;
spi_message_init(&st->single_msg);
spi_message_add_tail(&st->single_xfer[0], &st->single_msg);
spi_message_add_tail(&st->single_xfer[1], &st->single_msg);
spi_message_add_tail(&st->single_xfer[2], &st->single_msg);
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops);
if (ret)
goto error_free_gpios;
ret = iio_device_register(indio_dev);
if (ret)
goto error_buffer_cleanup;
return 0;
error_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
error_free_gpios:
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
if (!IS_ERR_OR_NULL(st->reg))
regulator_disable(st->reg);
error_put_reg:
if (!IS_ERR_OR_NULL(st->reg))
regulator_put(st->reg);
iio_device_free(indio_dev);
return ret;
}
static int ad7266_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7266_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
if (!IS_ERR_OR_NULL(st->reg)) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7266_id[] = {
{"ad7265", 0},
{"ad7266", 0},
{ }
};
MODULE_DEVICE_TABLE(spi, ad7266_id);
static struct spi_driver ad7266_driver = {
.driver = {
.name = "ad7266",
.owner = THIS_MODULE,
},
.probe = ad7266_probe,
.remove = ad7266_remove,
.id_table = ad7266_id,
};
module_spi_driver(ad7266_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD7266/65 ADC");
MODULE_LICENSE("GPL v2");

408
drivers/iio/adc/ad7298.c Normal file
View File

@@ -0,0 +1,408 @@
/*
* AD7298 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#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/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.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>
#include <linux/platform_data/ad7298.h>
#define AD7298_WRITE (1 << 15) /* write to the control register */
#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
#define AD7298_EXTREF (1 << 2) /* external reference enable */
#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
#define AD7298_PDD (1 << 0) /* partial power down enable */
#define AD7298_MAX_CHAN 8
#define AD7298_BITS 12
#define AD7298_STORAGE_BITS 16
#define AD7298_INTREF_mV 2500
#define AD7298_CH_TEMP 9
#define RES_MASK(bits) ((1 << (bits)) - 1)
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
struct spi_transfer scan_single_xfer[3];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 rx_buf[12] ____cacheline_aligned;
__be16 tx_buf[2];
};
#define AD7298_V_CHAN(index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec ad7298_channels[] = {
{
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.address = AD7298_CH_TEMP,
.scan_index = -1,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
},
},
AD7298_V_CHAN(0),
AD7298_V_CHAN(1),
AD7298_V_CHAN(2),
AD7298_V_CHAN(3),
AD7298_V_CHAN(4),
AD7298_V_CHAN(5),
AD7298_V_CHAN(6),
AD7298_V_CHAN(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
/**
* ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7298_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7298_state *st = iio_priv(indio_dev);
int i, m;
unsigned short command;
int scan_count;
/* Now compute overall size */
scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
if (test_bit(i, active_scan_mask))
command |= m;
st->tx_buf[0] = cpu_to_be16(command);
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = 2;
st->ring_xfer[0].cs_change = 1;
st->ring_xfer[1].tx_buf = &st->tx_buf[1];
st->ring_xfer[1].len = 2;
st->ring_xfer[1].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
for (i = 0; i < scan_count; i++) {
st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 2].len = 2;
st->ring_xfer[i + 2].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7298_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7298_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
s64 time_ns = 0;
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
{
int ret;
st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref |
(AD7298_CH(0) >> ch));
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
return be16_to_cpu(st->rx_buf[0]);
}
static int ad7298_scan_temp(struct ad7298_state *st, int *val)
{
int ret;
__be16 buf;
buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
AD7298_TAVG | st->ext_ref);
ret = spi_write(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
buf = cpu_to_be16(0);
ret = spi_write(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
usleep_range(101, 1000); /* sleep > 100us */
ret = spi_read(st->spi, (u8 *)&buf, 2);
if (ret)
return ret;
*val = sign_extend32(be16_to_cpu(buf), 11);
return 0;
}
static int ad7298_get_ref_voltage(struct ad7298_state *st)
{
int vref;
if (st->ext_ref) {
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
return vref / 1000;
} else {
return AD7298_INTREF_mV;
}
}
static int ad7298_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7298_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
} else {
if (chan->address == AD7298_CH_TEMP)
ret = ad7298_scan_temp(st, val);
else
ret = ad7298_scan_direct(st, chan->address);
}
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
if (chan->address != AD7298_CH_TEMP)
*val = ret & RES_MASK(AD7298_BITS);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
*val = ad7298_get_ref_voltage(st);
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
*val = ad7298_get_ref_voltage(st);
*val2 = 10;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 1093 - 2732500 / ad7298_get_ref_voltage(st);
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info ad7298_info = {
.read_raw = &ad7298_read_raw,
.update_scan_mode = ad7298_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int ad7298_probe(struct spi_device *spi)
{
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
int ret;
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (pdata && pdata->ext_ref)
st->ext_ref = AD7298_EXTREF;
if (st->ext_ref) {
st->reg = regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad7298_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7298_channels);
indio_dev->info = &ad7298_info;
/* Setup default message */
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].tx_buf = &st->tx_buf[1];
st->scan_single_xfer[1].len = 2;
st->scan_single_xfer[1].cs_change = 1;
st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[2].len = 2;
spi_message_init(&st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7298_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (st->ext_ref)
regulator_disable(st->reg);
error_put_reg:
if (st->ext_ref)
regulator_put(st->reg);
error_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7298_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7298_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (st->ext_ref) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7298_id[] = {
{"ad7298", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ad7298_id);
static struct spi_driver ad7298_driver = {
.driver = {
.name = "ad7298",
.owner = THIS_MODULE,
},
.probe = ad7298_probe,
.remove = ad7298_remove,
.id_table = ad7298_id,
};
module_spi_driver(ad7298_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
MODULE_LICENSE("GPL v2");

332
drivers/iio/adc/ad7476.c Normal file
View File

@@ -0,0 +1,332 @@
/*
* AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#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/err.h>
#include <linux/module.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>
#define RES_MASK(bits) ((1 << (bits)) - 1)
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 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,
};
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);
s64 time_ns;
int b_sent;
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
goto done;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
iio_push_to_buffers(indio_dev, st->data);
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:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7476_scan_direct(st);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
RES_MASK(st->chip_info->channel[0].scan_type.realbits);
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;
}
scale_uv >>= chan->scan_type.realbits;
*val = scale_uv / 1000;
*val2 = (scale_uv % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
}
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 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)
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),
},
};
static const struct iio_info ad7476_info = {
.driver_module = THIS_MODULE,
.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 = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
}
st = iio_priv(indio_dev);
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
st->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free_dev;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
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->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);
error_put_reg:
regulator_put(st->reg);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
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);
regulator_put(st->reg);
iio_device_free(indio_dev);
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},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
static struct spi_driver ad7476_driver = {
.driver = {
.name = "ad7476",
.owner = THIS_MODULE,
},
.probe = ad7476_probe,
.remove = ad7476_remove,
.id_table = ad7476_id,
};
module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2");

460
drivers/iio/adc/ad7791.c Normal file
View File

@@ -0,0 +1,460 @@
/*
* AD7787/AD7788/AD7789/AD7790/AD7791 SPI ADC driver
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#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/err.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <linux/platform_data/ad7791.h>
#define AD7791_REG_COMM 0x0 /* For writes */
#define AD7791_REG_STATUS 0x0 /* For reads */
#define AD7791_REG_MODE 0x1
#define AD7791_REG_FILTER 0x2
#define AD7791_REG_DATA 0x3
#define AD7791_MODE_CONTINUOUS 0x00
#define AD7791_MODE_SINGLE 0x02
#define AD7791_MODE_POWERDOWN 0x03
#define AD7791_CH_AIN1P_AIN1N 0x00
#define AD7791_CH_AIN2 0x01
#define AD7791_CH_AIN1N_AIN1N 0x02
#define AD7791_CH_AVDD_MONITOR 0x03
#define AD7791_FILTER_CLK_DIV_1 (0x0 << 4)
#define AD7791_FILTER_CLK_DIV_2 (0x1 << 4)
#define AD7791_FILTER_CLK_DIV_4 (0x2 << 4)
#define AD7791_FILTER_CLK_DIV_8 (0x3 << 4)
#define AD7791_FILTER_CLK_MASK (0x3 << 4)
#define AD7791_FILTER_RATE_120 0x0
#define AD7791_FILTER_RATE_100 0x1
#define AD7791_FILTER_RATE_33_3 0x2
#define AD7791_FILTER_RATE_20 0x3
#define AD7791_FILTER_RATE_16_6 0x4
#define AD7791_FILTER_RATE_16_7 0x5
#define AD7791_FILTER_RATE_13_3 0x6
#define AD7791_FILTER_RATE_9_5 0x7
#define AD7791_FILTER_RATE_MASK 0x7
#define AD7791_MODE_BUFFER BIT(1)
#define AD7791_MODE_UNIPOLAR BIT(2)
#define AD7791_MODE_BURNOUT BIT(3)
#define AD7791_MODE_SEL_MASK (0x3 << 6)
#define AD7791_MODE_SEL(x) ((x) << 6)
#define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \
const struct iio_chan_spec name[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \
AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR, \
(bits), (storagebits), 0), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \
const struct iio_chan_spec name[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \
(bits), (storagebits), 0), \
AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \
(bits), (storagebits), 0), \
IIO_CHAN_SOFT_TIMESTAMP(3), \
}
static DECLARE_AD7787_CHANNELS(ad7787_channels, 24, 32);
static DECLARE_AD7791_CHANNELS(ad7790_channels, 16, 16);
static DECLARE_AD7791_CHANNELS(ad7791_channels, 24, 32);
enum {
AD7787,
AD7788,
AD7789,
AD7790,
AD7791,
};
enum ad7791_chip_info_flags {
AD7791_FLAG_HAS_FILTER = (1 << 0),
AD7791_FLAG_HAS_BUFFER = (1 << 1),
AD7791_FLAG_HAS_UNIPOLAR = (1 << 2),
AD7791_FLAG_HAS_BURNOUT = (1 << 3),
};
struct ad7791_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
enum ad7791_chip_info_flags flags;
};
static const struct ad7791_chip_info ad7791_chip_infos[] = {
[AD7787] = {
.channels = ad7787_channels,
.num_channels = ARRAY_SIZE(ad7787_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
},
[AD7788] = {
.channels = ad7790_channels,
.num_channels = ARRAY_SIZE(ad7790_channels),
.flags = AD7791_FLAG_HAS_UNIPOLAR,
},
[AD7789] = {
.channels = ad7791_channels,
.num_channels = ARRAY_SIZE(ad7791_channels),
.flags = AD7791_FLAG_HAS_UNIPOLAR,
},
[AD7790] = {
.channels = ad7790_channels,
.num_channels = ARRAY_SIZE(ad7790_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_BURNOUT,
},
[AD7791] = {
.channels = ad7791_channels,
.num_channels = ARRAY_SIZE(ad7791_channels),
.flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER |
AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT,
},
};
struct ad7791_state {
struct ad_sigma_delta sd;
uint8_t mode;
uint8_t filter;
struct regulator *reg;
const struct ad7791_chip_info *info;
};
static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd)
{
return container_of(sd, struct ad7791_state, sd);
}
static int ad7791_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
{
ad_sd_set_comm(sd, channel);
return 0;
}
static int ad7791_set_mode(struct ad_sigma_delta *sd,
enum ad_sigma_delta_mode mode)
{
struct ad7791_state *st = ad_sigma_delta_to_ad7791(sd);
switch (mode) {
case AD_SD_MODE_CONTINUOUS:
mode = AD7791_MODE_CONTINUOUS;
break;
case AD_SD_MODE_SINGLE:
mode = AD7791_MODE_SINGLE;
break;
case AD_SD_MODE_IDLE:
case AD_SD_MODE_POWERDOWN:
mode = AD7791_MODE_POWERDOWN;
break;
}
st->mode &= ~AD7791_MODE_SEL_MASK;
st->mode |= AD7791_MODE_SEL(mode);
return ad_sd_write_reg(sd, AD7791_REG_MODE, sizeof(st->mode), st->mode);
}
static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
.set_channel = ad7791_set_channel,
.set_mode = ad7791_set_mode,
.has_registers = true,
.addr_shift = 4,
.read_mask = BIT(3),
};
static int ad7791_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct ad7791_state *st = iio_priv(indio_dev);
bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR);
unsigned long long scale_pv;
switch (info) {
case IIO_CHAN_INFO_RAW:
return ad_sigma_delta_single_conversion(indio_dev, chan, val);
case IIO_CHAN_INFO_OFFSET:
/**
* Unipolar: 0 to VREF
* Bipolar -VREF to VREF
**/
if (unipolar)
*val = 0;
else
*val = -(1 << (chan->scan_type.realbits - 1));
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* The monitor channel uses an internal reference. */
if (chan->address == AD7791_CH_AVDD_MONITOR) {
scale_pv = 5850000000000ULL;
} else {
int voltage_uv;
voltage_uv = regulator_get_voltage(st->reg);
if (voltage_uv < 0)
return voltage_uv;
scale_pv = (unsigned long long)voltage_uv * 1000000;
}
if (unipolar)
scale_pv >>= chan->scan_type.realbits;
else
scale_pv >>= chan->scan_type.realbits - 1;
*val2 = do_div(scale_pv, 1000000000);
*val = scale_pv;
return IIO_VAL_INT_PLUS_NANO;
}
return -EINVAL;
}
static const char * const ad7791_sample_freq_avail[] = {
[AD7791_FILTER_RATE_120] = "120",
[AD7791_FILTER_RATE_100] = "100",
[AD7791_FILTER_RATE_33_3] = "33.3",
[AD7791_FILTER_RATE_20] = "20",
[AD7791_FILTER_RATE_16_6] = "16.6",
[AD7791_FILTER_RATE_16_7] = "16.7",
[AD7791_FILTER_RATE_13_3] = "13.3",
[AD7791_FILTER_RATE_9_5] = "9.5",
};
static ssize_t ad7791_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7791_state *st = iio_priv(indio_dev);
unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK;
return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]);
}
static ssize_t ad7791_write_frequency(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7791_state *st = iio_priv(indio_dev);
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) {
mutex_lock(&indio_dev->mlock);
st->filter &= ~AD7791_FILTER_RATE_MASK;
st->filter |= i;
ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
sizeof(st->filter), st->filter);
mutex_unlock(&indio_dev->mlock);
ret = 0;
break;
}
}
return ret ? ret : len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad7791_read_frequency,
ad7791_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5");
static struct attribute *ad7791_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad7791_attribute_group = {
.attrs = ad7791_attributes,
};
static const struct iio_info ad7791_info = {
.read_raw = &ad7791_read_raw,
.attrs = &ad7791_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7791_no_filter_info = {
.read_raw = &ad7791_read_raw,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static int ad7791_setup(struct ad7791_state *st,
struct ad7791_platform_data *pdata)
{
/* Set to poweron-reset default values */
st->mode = AD7791_MODE_BUFFER;
st->filter = AD7791_FILTER_RATE_16_6;
if (!pdata)
return 0;
if ((st->info->flags & AD7791_FLAG_HAS_BUFFER) && !pdata->buffered)
st->mode &= ~AD7791_MODE_BUFFER;
if ((st->info->flags & AD7791_FLAG_HAS_BURNOUT) &&
pdata->burnout_current)
st->mode |= AD7791_MODE_BURNOUT;
if ((st->info->flags & AD7791_FLAG_HAS_UNIPOLAR) && pdata->unipolar)
st->mode |= AD7791_MODE_UNIPOLAR;
return ad_sd_write_reg(&st->sd, AD7791_REG_MODE, sizeof(st->mode),
st->mode);
}
static int ad7791_probe(struct spi_device *spi)
{
struct ad7791_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad7791_state *st;
int ret;
if (!spi->irq) {
dev_err(&spi->dev, "Missing IRQ.\n");
return -ENXIO;
}
indio_dev = iio_device_alloc(sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto err_iio_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
if (st->info->flags & AD7791_FLAG_HAS_FILTER)
indio_dev->info = &ad7791_info;
else
indio_dev->info = &ad7791_no_filter_info;
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
if (ret)
goto error_disable_reg;
ret = ad7791_setup(st, pdata);
if (ret)
goto error_remove_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
error_put_reg:
regulator_put(st->reg);
err_iio_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7791_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7791_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
regulator_disable(st->reg);
regulator_put(st->reg);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7791_spi_ids[] = {
{ "ad7787", AD7787 },
{ "ad7788", AD7788 },
{ "ad7789", AD7789 },
{ "ad7790", AD7790 },
{ "ad7791", AD7791 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7791_spi_ids);
static struct spi_driver ad7791_driver = {
.driver = {
.name = "ad7791",
.owner = THIS_MODULE,
},
.probe = ad7791_probe,
.remove = ad7791_remove,
.id_table = ad7791_spi_ids,
};
module_spi_driver(ad7791_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver");
MODULE_LICENSE("GPL v2");

876
drivers/iio/adc/ad7793.c Normal file
View File

@@ -0,0 +1,876 @@
/*
* AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver
*
* Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#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/err.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <linux/platform_data/ad7793.h>
/* Registers */
#define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */
#define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */
#define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */
#define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */
#define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */
#define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */
#define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */
#define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit
* (AD7792)/24-bit (AD7793)) */
#define AD7793_REG_FULLSALE 7 /* Full-Scale Register
* (RW, 16-bit (AD7792)/24-bit (AD7793)) */
/* Communications Register Bit Designations (AD7793_REG_COMM) */
#define AD7793_COMM_WEN (1 << 7) /* Write Enable */
#define AD7793_COMM_WRITE (0 << 6) /* Write Operation */
#define AD7793_COMM_READ (1 << 6) /* Read Operation */
#define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */
#define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */
/* Status Register Bit Designations (AD7793_REG_STAT) */
#define AD7793_STAT_RDY (1 << 7) /* Ready */
#define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */
#define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */
#define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */
#define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */
/* Mode Register Bit Designations (AD7793_REG_MODE) */
#define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */
#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */
#define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */
#define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */
#define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */
#define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */
#define AD7793_MODE_IDLE 2 /* Idle Mode */
#define AD7793_MODE_PWRDN 3 /* Power-Down Mode */
#define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */
#define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */
#define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */
#define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */
#define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not
* available at the CLK pin */
#define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available
* at the CLK pin */
#define AD7793_CLK_EXT 2 /* External 64 kHz Clock */
#define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */
/* Configuration Register Bit Designations (AD7793_REG_CONF) */
#define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage
* Generator Enable */
#define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */
#define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */
#define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */
#define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */
#define AD7793_CONF_REFSEL(x) ((x) << 6) /* INT/EXT Reference Select */
#define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */
#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */
#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */
#define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */
#define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */
#define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */
#define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */
#define AD7793_CH_TEMP 6 /* Temp Sensor */
#define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */
#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */
#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */
#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */
#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */
/* ID Register Bit Designations (AD7793_REG_ID) */
#define AD7785_ID 0xB
#define AD7792_ID 0xA
#define AD7793_ID 0xB
#define AD7794_ID 0xF
#define AD7795_ID 0xF
#define AD7796_ID 0xA
#define AD7797_ID 0xB
#define AD7798_ID 0x8
#define AD7799_ID 0x9
#define AD7793_ID_MASK 0xF
/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */
#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1,
* IEXC2 connect to IOUT2 */
#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2,
* IEXC2 connect to IOUT1 */
#define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources
* IEXC1,2 connect to IOUT1 */
#define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources
* IEXC1,2 connect to IOUT2 */
#define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */
#define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */
#define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */
/* NOTE:
* The AD7792/AD7793 features a dual use data out ready DOUT/RDY output.
* In order to avoid contentions on the SPI bus, it's therefore necessary
* to use spi bus locking.
*
* The DOUT/RDY output must also be wired to an interrupt capable GPIO.
*/
#define AD7793_FLAG_HAS_CLKSEL BIT(0)
#define AD7793_FLAG_HAS_REFSEL BIT(1)
#define AD7793_FLAG_HAS_VBIAS BIT(2)
#define AD7793_HAS_EXITATION_CURRENT BIT(3)
#define AD7793_FLAG_HAS_GAIN BIT(4)
#define AD7793_FLAG_HAS_BUFFER BIT(5)
struct ad7793_chip_info {
unsigned int id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int flags;
const struct iio_info *iio_info;
const u16 *sample_freq_avail;
};
struct ad7793_state {
const struct ad7793_chip_info *chip_info;
struct regulator *reg;
u16 int_vref_mv;
u16 mode;
u16 conf;
u32 scale_avail[8][2];
struct ad_sigma_delta sd;
};
enum ad7793_supported_device_ids {
ID_AD7785,
ID_AD7792,
ID_AD7793,
ID_AD7794,
ID_AD7795,
ID_AD7796,
ID_AD7797,
ID_AD7798,
ID_AD7799,
};
static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd)
{
return container_of(sd, struct ad7793_state, sd);
}
static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
{
struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
st->conf &= ~AD7793_CONF_CHAN_MASK;
st->conf |= AD7793_CONF_CHAN(channel);
return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf);
}
static int ad7793_set_mode(struct ad_sigma_delta *sd,
enum ad_sigma_delta_mode mode)
{
struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd);
st->mode &= ~AD7793_MODE_SEL_MASK;
st->mode |= AD7793_MODE_SEL(mode);
return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode);
}
static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
.set_channel = ad7793_set_channel,
.set_mode = ad7793_set_mode,
.has_registers = true,
.addr_shift = 3,
.read_mask = BIT(6),
};
static const struct ad_sd_calib_data ad7793_calib_arr[6] = {
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M},
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M},
{AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M},
{AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M}
};
static int ad7793_calibrate_all(struct ad7793_state *st)
{
return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr,
ARRAY_SIZE(ad7793_calib_arr));
}
static int ad7793_check_platform_data(struct ad7793_state *st,
const struct ad7793_platform_data *pdata)
{
if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 ||
pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) &&
((pdata->exitation_current != AD7793_IX_10uA) &&
(pdata->exitation_current != AD7793_IX_210uA)))
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL) &&
pdata->clock_src != AD7793_CLK_SRC_INT)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_REFSEL) &&
pdata->refsel != AD7793_REFSEL_REFIN1)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS) &&
pdata->bias_voltage != AD7793_BIAS_VOLTAGE_DISABLED)
return -EINVAL;
if (!(st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) &&
pdata->exitation_current != AD7793_IX_DISABLED)
return -EINVAL;
return 0;
}
static int ad7793_setup(struct iio_dev *indio_dev,
const struct ad7793_platform_data *pdata,
unsigned int vref_mv)
{
struct ad7793_state *st = iio_priv(indio_dev);
int i, ret = -1;
unsigned long long scale_uv;
u32 id;
ret = ad7793_check_platform_data(st, pdata);
if (ret)
return ret;
/* reset the serial interface */
ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret));
if (ret < 0)
goto out;
usleep_range(500, 2000); /* Wait for at least 500us */
/* write/read test for device presence */
ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id);
if (ret)
goto out;
id &= AD7793_ID_MASK;
if (id != st->chip_info->id) {
dev_err(&st->sd.spi->dev, "device ID query failed\n");
goto out;
}
st->mode = AD7793_MODE_RATE(1);
st->conf = 0;
if (st->chip_info->flags & AD7793_FLAG_HAS_CLKSEL)
st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src);
if (st->chip_info->flags & AD7793_FLAG_HAS_REFSEL)
st->conf |= AD7793_CONF_REFSEL(pdata->refsel);
if (st->chip_info->flags & AD7793_FLAG_HAS_VBIAS)
st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage);
if (pdata->buffered || !(st->chip_info->flags & AD7793_FLAG_HAS_BUFFER))
st->conf |= AD7793_CONF_BUF;
if (pdata->boost_enable &&
(st->chip_info->flags & AD7793_FLAG_HAS_VBIAS))
st->conf |= AD7793_CONF_BOOST;
if (pdata->burnout_current)
st->conf |= AD7793_CONF_BO_EN;
if (pdata->unipolar)
st->conf |= AD7793_CONF_UNIPOLAR;
if (!(st->chip_info->flags & AD7793_FLAG_HAS_GAIN))
st->conf |= AD7793_CONF_GAIN(7);
ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE);
if (ret)
goto out;
ret = ad7793_set_channel(&st->sd, 0);
if (ret)
goto out;
if (st->chip_info->flags & AD7793_HAS_EXITATION_CURRENT) {
ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1,
pdata->exitation_current |
(pdata->current_source_direction << 2));
if (ret)
goto out;
}
ret = ad7793_calibrate_all(st);
if (ret)
goto out;
/* Populate available ADC input ranges */
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
scale_uv = ((u64)vref_mv * 100000000)
>> (st->chip_info->channels[0].scan_type.realbits -
(!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1));
scale_uv >>= i;
st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10;
st->scale_avail[i][0] = scale_uv;
}
return 0;
out:
dev_err(&st->sd.spi->dev, "setup failed\n");
return ret;
}
static const u16 ad7793_sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39,
33, 19, 17, 16, 12, 10, 8, 6, 4};
static const u16 ad7797_sample_freq_avail[16] = {0, 0, 0, 123, 62, 50, 0,
33, 0, 17, 16, 12, 10, 8, 6, 4};
static ssize_t ad7793_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
st->chip_info->sample_freq_avail[AD7793_MODE_RATE(st->mode)]);
}
static ssize_t ad7793_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
long lval;
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = kstrtol(buf, 10, &lval);
if (ret)
return ret;
if (lval == 0)
return -EINVAL;
ret = -EINVAL;
for (i = 0; i < 16; i++)
if (lval == st->chip_info->sample_freq_avail[i]) {
mutex_lock(&indio_dev->mlock);
st->mode &= ~AD7793_MODE_RATE(-1);
st->mode |= AD7793_MODE_RATE(i);
ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
sizeof(st->mode), st->mode);
mutex_unlock(&indio_dev->mlock);
ret = 0;
}
return ret ? ret : len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad7793_read_frequency,
ad7793_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"470 242 123 62 50 39 33 19 17 16 12 10 8 6 4");
static IIO_CONST_ATTR_NAMED(sampling_frequency_available_ad7797,
sampling_frequency_available, "123 62 50 33 17 16 12 10 8 6 4");
static ssize_t ad7793_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0],
st->scale_avail[i][1]);
len += sprintf(buf + len, "\n");
return len;
}
static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available,
in_voltage-voltage_scale_available, S_IRUGO,
ad7793_show_scale_available, NULL, 0);
static struct attribute *ad7793_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_m_in_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad7793_attribute_group = {
.attrs = ad7793_attributes,
};
static struct attribute *ad7797_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available_ad7797.dev_attr.attr,
NULL
};
static const struct attribute_group ad7797_attribute_group = {
.attrs = ad7797_attributes,
};
static int ad7793_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad7793_state *st = iio_priv(indio_dev);
int ret;
unsigned long long scale_uv;
bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad_sigma_delta_single_conversion(indio_dev, chan, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
if (chan->differential) {
*val = st->
scale_avail[(st->conf >> 8) & 0x7][0];
*val2 = st->
scale_avail[(st->conf >> 8) & 0x7][1];
return IIO_VAL_INT_PLUS_NANO;
} else {
/* 1170mV / 2^23 * 6 */
scale_uv = (1170ULL * 1000000000ULL * 6ULL);
}
break;
case IIO_TEMP:
/* 1170mV / 0.81 mV/C / 2^23 */
scale_uv = 1444444444444444ULL;
break;
default:
return -EINVAL;
}
scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1));
*val = 0;
*val2 = scale_uv;
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_OFFSET:
if (!unipolar)
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
/* Kelvin to Celsius */
if (chan->type == IIO_TEMP) {
unsigned long long offset;
unsigned int shift;
shift = chan->scan_type.realbits - (unipolar ? 0 : 1);
offset = 273ULL << shift;
do_div(offset, 1444);
*val -= offset;
}
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad7793_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad7793_state *st = iio_priv(indio_dev);
int ret, i;
unsigned int tmp;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
tmp = st->conf;
st->conf &= ~AD7793_CONF_GAIN(-1);
st->conf |= AD7793_CONF_GAIN(i);
if (tmp == st->conf)
break;
ad_sd_write_reg(&st->sd, AD7793_REG_CONF,
sizeof(st->conf), st->conf);
ad7793_calibrate_all(st);
break;
}
break;
default:
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
return IIO_VAL_INT_PLUS_NANO;
}
static const struct iio_info ad7793_info = {
.read_raw = &ad7793_read_raw,
.write_raw = &ad7793_write_raw,
.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
.attrs = &ad7793_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7797_info = {
.read_raw = &ad7793_read_raw,
.write_raw = &ad7793_write_raw,
.write_raw_get_fmt = &ad7793_write_raw_get_fmt,
.attrs = &ad7793_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
.driver_module = THIS_MODULE,
};
#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \
AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \
AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \
AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \
IIO_CHAN_SOFT_TIMESTAMP(6), \
}
#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(9), \
}
#define DECLARE_AD7797_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7799_CHANNELS(_name, _b, _sb) \
const struct iio_chan_spec _name##_channels[] = { \
AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \
AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \
AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \
AD_SD_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \
IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4);
static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0);
static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0);
static DECLARE_AD7795_CHANNELS(ad7794, 16, 32);
static DECLARE_AD7795_CHANNELS(ad7795, 24, 32);
static DECLARE_AD7797_CHANNELS(ad7796, 16, 16);
static DECLARE_AD7797_CHANNELS(ad7797, 24, 32);
static DECLARE_AD7799_CHANNELS(ad7798, 16, 16);
static DECLARE_AD7799_CHANNELS(ad7799, 24, 32);
static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
[ID_AD7785] = {
.id = AD7785_ID,
.channels = ad7785_channels,
.num_channels = ARRAY_SIZE(ad7785_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7792] = {
.id = AD7792_ID,
.channels = ad7792_channels,
.num_channels = ARRAY_SIZE(ad7792_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7793] = {
.id = AD7793_ID,
.channels = ad7793_channels,
.num_channels = ARRAY_SIZE(ad7793_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7794] = {
.id = AD7794_ID,
.channels = ad7794_channels,
.num_channels = ARRAY_SIZE(ad7794_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7795] = {
.id = AD7795_ID,
.channels = ad7795_channels,
.num_channels = ARRAY_SIZE(ad7795_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL |
AD7793_FLAG_HAS_REFSEL |
AD7793_FLAG_HAS_VBIAS |
AD7793_HAS_EXITATION_CURRENT |
AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7796] = {
.id = AD7796_ID,
.channels = ad7796_channels,
.num_channels = ARRAY_SIZE(ad7796_channels),
.iio_info = &ad7797_info,
.sample_freq_avail = ad7797_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL,
},
[ID_AD7797] = {
.id = AD7797_ID,
.channels = ad7797_channels,
.num_channels = ARRAY_SIZE(ad7797_channels),
.iio_info = &ad7797_info,
.sample_freq_avail = ad7797_sample_freq_avail,
.flags = AD7793_FLAG_HAS_CLKSEL,
},
[ID_AD7798] = {
.id = AD7798_ID,
.channels = ad7798_channels,
.num_channels = ARRAY_SIZE(ad7798_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
[ID_AD7799] = {
.id = AD7799_ID,
.channels = ad7799_channels,
.num_channels = ARRAY_SIZE(ad7799_channels),
.iio_info = &ad7793_info,
.sample_freq_avail = ad7793_sample_freq_avail,
.flags = AD7793_FLAG_HAS_GAIN |
AD7793_FLAG_HAS_BUFFER,
},
};
static int ad7793_probe(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
struct ad7793_state *st;
struct iio_dev *indio_dev;
int ret, vref_mv = 0;
if (!pdata) {
dev_err(&spi->dev, "no platform data?\n");
return -ENODEV;
}
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
}
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
st->reg = regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_device_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
vref_mv = regulator_get_voltage(st->reg);
if (vref_mv < 0) {
ret = vref_mv;
goto error_disable_reg;
}
vref_mv /= 1000;
} else {
vref_mv = 1170; /* Build-in ref */
}
st->chip_info =
&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->iio_info;
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
if (ret)
goto error_disable_reg;
ret = ad7793_setup(indio_dev, pdata, vref_mv);
if (ret)
goto error_remove_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
return 0;
error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_reg:
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_disable(st->reg);
error_put_reg:
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
regulator_put(st->reg);
error_device_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7793_remove(struct spi_device *spi)
{
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7793_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7793_id[] = {
{"ad7785", ID_AD7785},
{"ad7792", ID_AD7792},
{"ad7793", ID_AD7793},
{"ad7794", ID_AD7794},
{"ad7795", ID_AD7795},
{"ad7796", ID_AD7796},
{"ad7797", ID_AD7797},
{"ad7798", ID_AD7798},
{"ad7799", ID_AD7799},
{}
};
MODULE_DEVICE_TABLE(spi, ad7793_id);
static struct spi_driver ad7793_driver = {
.driver = {
.name = "ad7793",
.owner = THIS_MODULE,
},
.probe = ad7793_probe,
.remove = ad7793_remove,
.id_table = ad7793_id,
};
module_spi_driver(ad7793_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs");
MODULE_LICENSE("GPL v2");

378
drivers/iio/adc/ad7887.c Normal file
View File

@@ -0,0 +1,378 @@
/*
* AD7887 SPI ADC driver
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#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/err.h>
#include <linux/module.h>
#include <linux/interrupt.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>
#include <linux/platform_data/ad7887.h>
#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */
#define AD7887_DUAL (1 << 4) /* dual-channel mode */
#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */
#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */
#define AD7887_PM_MODE1 (0) /* CS based shutdown */
#define AD7887_PM_MODE2 (1) /* full on */
#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */
#define AD7887_PM_MODE4 (3) /* standby mode */
enum ad7887_channels {
AD7887_CH0,
AD7887_CH0_CH1,
AD7887_CH1,
};
#define RES_MASK(bits) ((1 << (bits)) - 1)
/**
* struct ad7887_chip_info - chip specifc information
* @int_vref_mv: the internal reference voltage
* @channel: channel specification
*/
struct ad7887_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[3];
};
struct ad7887_state {
struct spi_device *spi;
const struct ad7887_chip_info *chip_info;
struct regulator *reg;
struct spi_transfer xfer[4];
struct spi_message msg[3];
struct spi_message *ring_msg;
unsigned char tx_cmd_buf[4];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* Buffer needs to be large enough to hold two 16 bit samples and a
* 64 bit aligned 64 bit timestamp.
*/
unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)]
____cacheline_aligned;
};
enum ad7887_supported_device_ids {
ID_AD7887
};
static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
int ret;
ret = iio_sw_buffer_preenable(indio_dev);
if (ret < 0)
return ret;
/* We know this is a single long so can 'cheat' */
switch (*indio_dev->active_scan_mask) {
case (1 << 0):
st->ring_msg = &st->msg[AD7887_CH0];
break;
case (1 << 1):
st->ring_msg = &st->msg[AD7887_CH1];
/* Dummy read: push CH1 setting down to hardware */
spi_sync(st->spi, st->ring_msg);
break;
case ((1 << 1) | (1 << 0)):
st->ring_msg = &st->msg[AD7887_CH0_CH1];
break;
}
return 0;
}
static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
/* dummy read: restore default CH0 settin */
return spi_sync(st->spi, &st->msg[AD7887_CH0]);
}
/**
* ad7887_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7887_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7887_state *st = iio_priv(indio_dev);
s64 time_ns;
int b_sent;
b_sent = spi_sync(st->spi, st->ring_msg);
if (b_sent)
goto done;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
memcpy(st->data + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
iio_push_to_buffers(indio_dev, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
.preenable = &ad7887_ring_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad7887_ring_postdisable,
};
static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch)
{
int ret = spi_sync(st->spi, &st->msg[ch]);
if (ret)
return ret;
return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1];
}
static int ad7887_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7887_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7887_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = ret >> chan->scan_type.shift;
*val &= RES_MASK(chan->scan_type.realbits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (st->reg) {
*val = regulator_get_voltage(st->reg);
if (*val < 0)
return *val;
*val /= 1000;
} else {
*val = st->chip_info->int_vref_mv;
}
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
/*
* More devices added in future
*/
[ID_AD7887] = {
.channel[0] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
},
.channel[1] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
},
.channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2),
.int_vref_mv = 2500,
},
};
static const struct iio_info ad7887_info = {
.read_raw = &ad7887_read_raw,
.driver_module = THIS_MODULE,
};
static int ad7887_probe(struct spi_device *spi)
{
struct ad7887_platform_data *pdata = spi->dev.platform_data;
struct ad7887_state *st;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
uint8_t mode;
int ret;
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (!pdata || !pdata->use_onchip_ref) {
st->reg = regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
}
st->chip_info =
&ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
/* Estabilish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad7887_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Setup default message */
mode = AD7887_PM_MODE4;
if (!pdata || !pdata->use_onchip_ref)
mode |= AD7887_REF_DIS;
if (pdata && pdata->en_dual)
mode |= AD7887_DUAL;
st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode;
st->xfer[0].rx_buf = &st->data[0];
st->xfer[0].tx_buf = &st->tx_cmd_buf[0];
st->xfer[0].len = 2;
spi_message_init(&st->msg[AD7887_CH0]);
spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]);
if (pdata && pdata->en_dual) {
st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode;
st->xfer[1].rx_buf = &st->data[0];
st->xfer[1].tx_buf = &st->tx_cmd_buf[2];
st->xfer[1].len = 2;
st->xfer[2].rx_buf = &st->data[2];
st->xfer[2].tx_buf = &st->tx_cmd_buf[0];
st->xfer[2].len = 2;
spi_message_init(&st->msg[AD7887_CH0_CH1]);
spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]);
spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]);
st->xfer[3].rx_buf = &st->data[2];
st->xfer[3].tx_buf = &st->tx_cmd_buf[2];
st->xfer[3].len = 2;
spi_message_init(&st->msg[AD7887_CH1]);
spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = 3;
} else {
indio_dev->channels = &st->chip_info->channel[1];
indio_dev->num_channels = 2;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7887_trigger_handler, &ad7887_ring_setup_ops);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unregister_ring;
return 0;
error_unregister_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (st->reg)
regulator_disable(st->reg);
error_put_reg:
if (st->reg)
regulator_put(st->reg);
error_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7887_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7887_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (st->reg) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7887_id[] = {
{"ad7887", ID_AD7887},
{}
};
MODULE_DEVICE_TABLE(spi, ad7887_id);
static struct spi_driver ad7887_driver = {
.driver = {
.name = "ad7887",
.owner = THIS_MODULE,
},
.probe = ad7887_probe,
.remove = ad7887_remove,
.id_table = ad7887_id,
};
module_spi_driver(ad7887_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
MODULE_LICENSE("GPL v2");

383
drivers/iio/adc/ad7923.c Normal file
View File

@@ -0,0 +1,383 @@
/*
* AD7904/AD7914/AD7923/AD7924 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
* Licensed under the GPL-2.
*/
#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/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.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>
#define AD7923_WRITE_CR (1 << 11) /* write control register */
#define AD7923_RANGE (1 << 1) /* range to REFin */
#define AD7923_CODING (1 << 0) /* coding is straight binary */
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
#define AD7923_CHANNEL_0 (0) /* analog input 0 */
#define AD7923_CHANNEL_1 (1) /* analog input 1 */
#define AD7923_CHANNEL_2 (2) /* analog input 2 */
#define AD7923_CHANNEL_3 (3) /* analog input 3 */
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
#define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */
#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \
+ ((sequence & 2) << 9))
/* write sequence fonction */
/* left shift for CR : bit 11 transmit in first */
#define AD7923_SHIFT_REGISTER 4
/* val = value, dec = left shift, bits = number of bits of the mask */
#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1))
struct ad7923_state {
struct spi_device *spi;
struct spi_transfer ring_xfer[5];
struct spi_transfer scan_single_xfer[2];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
struct regulator *reg;
unsigned int settings;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 rx_buf[4] ____cacheline_aligned;
__be16 tx_buf[4];
};
struct ad7923_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
enum ad7923_id {
AD7904,
AD7914,
AD7924,
};
#define AD7923_V_CHAN(index, bits) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define DECLARE_AD7923_CHANNELS(name, bits) \
const struct iio_chan_spec name ## _channels[] = { \
AD7923_V_CHAN(0, bits), \
AD7923_V_CHAN(1, bits), \
AD7923_V_CHAN(2, bits), \
AD7923_V_CHAN(3, bits), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
static DECLARE_AD7923_CHANNELS(ad7904, 8);
static DECLARE_AD7923_CHANNELS(ad7914, 10);
static DECLARE_AD7923_CHANNELS(ad7924, 12);
static const struct ad7923_chip_info ad7923_chip_info[] = {
[AD7904] = {
.channels = ad7904_channels,
.num_channels = ARRAY_SIZE(ad7904_channels),
},
[AD7914] = {
.channels = ad7914_channels,
.num_channels = ARRAY_SIZE(ad7914_channels),
},
[AD7924] = {
.channels = ad7924_channels,
.num_channels = ARRAY_SIZE(ad7924_channels),
},
};
/**
* ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7923_state *st = iio_priv(indio_dev);
int i, cmd, len;
len = 0;
for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[len++] = cpu_to_be16(cmd);
}
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = len;
st->ring_xfer[0].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
for (i = 0; i < len; i++) {
st->ring_xfer[i + 1].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 1].len = 2;
st->ring_xfer[i + 1].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 1], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7923_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7923_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7923_state *st = iio_priv(indio_dev);
s64 time_ns = 0;
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
{
int ret, cmd;
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(ch) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[0] = cpu_to_be16(cmd);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
return be16_to_cpu(st->rx_buf[0]);
}
static int ad7923_get_range(struct ad7923_state *st)
{
int vref;
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
vref /= 1000;
if (!(st->settings & AD7923_RANGE))
vref *= 2;
return vref;
}
static int ad7923_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7923_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7923_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
if (chan->address == EXTRACT(ret, 12, 4))
*val = EXTRACT(ret, 0, 12);
else
return -EIO;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = ad7923_get_range(st);
if (ret < 0)
return ret;
*val = ret;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info ad7923_info = {
.read_raw = &ad7923_read_raw,
.update_scan_mode = ad7923_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int ad7923_probe(struct spi_device *spi)
{
struct ad7923_state *st;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
const struct ad7923_chip_info *info;
int ret;
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->settings = AD7923_CODING | AD7923_RANGE |
AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS);
info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data];
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->channels;
indio_dev->num_channels = info->num_channels;
indio_dev->info = &ad7923_info;
/* Setup default message */
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[1].len = 2;
spi_message_init(&st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
st->reg = regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7923_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
error_put_reg:
regulator_put(st->reg);
error_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7923_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7923_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
regulator_put(st->reg);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7923_id[] = {
{"ad7904", AD7904},
{"ad7914", AD7914},
{"ad7923", AD7924},
{"ad7924", AD7924},
{}
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
static struct spi_driver ad7923_driver = {
.driver = {
.name = "ad7923",
.owner = THIS_MODULE,
},
.probe = ad7923_probe,
.remove = ad7923_remove,
.id_table = ad7923_id,
};
module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,558 @@
/*
* Support code for Analog Devices Sigma-Delta ADCs
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
#include <asm/unaligned.h>
#define AD_SD_COMM_CHAN_MASK 0x3
#define AD_SD_REG_COMM 0x00
#define AD_SD_REG_DATA 0x03
/**
* ad_sd_set_comm() - Set communications register
*
* @sigma_delta: The sigma delta device
* @comm: New value for the communications register
*/
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
{
/* Some variants use the lower two bits of the communications register
* to select the channel */
sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK;
}
EXPORT_SYMBOL_GPL(ad_sd_set_comm);
/**
* ad_sd_write_reg() - Write a register
*
* @sigma_delta: The sigma delta device
* @reg: Address of the register
* @size: Size of the register (0-3)
* @val: Value to write to the register
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
unsigned int size, unsigned int val)
{
uint8_t *data = sigma_delta->data;
struct spi_transfer t = {
.tx_buf = data,
.len = size + 1,
.cs_change = sigma_delta->bus_locked,
};
struct spi_message m;
int ret;
data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm;
switch (size) {
case 3:
data[1] = val >> 16;
data[2] = val >> 8;
data[3] = val;
break;
case 2:
put_unaligned_be16(val, &data[1]);
break;
case 1:
data[1] = val;
break;
case 0:
break;
default:
return -EINVAL;
}
spi_message_init(&m);
spi_message_add_tail(&t, &m);
if (sigma_delta->bus_locked)
ret = spi_sync_locked(sigma_delta->spi, &m);
else
ret = spi_sync(sigma_delta->spi, &m);
return ret;
}
EXPORT_SYMBOL_GPL(ad_sd_write_reg);
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
unsigned int reg, unsigned int size, uint8_t *val)
{
uint8_t *data = sigma_delta->data;
int ret;
struct spi_transfer t[] = {
{
.tx_buf = data,
.len = 1,
}, {
.rx_buf = val,
.len = size,
.cs_change = sigma_delta->bus_locked,
},
};
struct spi_message m;
spi_message_init(&m);
if (sigma_delta->info->has_registers) {
data[0] = reg << sigma_delta->info->addr_shift;
data[0] |= sigma_delta->info->read_mask;
spi_message_add_tail(&t[0], &m);
}
spi_message_add_tail(&t[1], &m);
if (sigma_delta->bus_locked)
ret = spi_sync_locked(sigma_delta->spi, &m);
else
ret = spi_sync(sigma_delta->spi, &m);
return ret;
}
/**
* ad_sd_read_reg() - Read a register
*
* @sigma_delta: The sigma delta device
* @reg: Address of the register
* @size: Size of the register (1-4)
* @val: Read value
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta,
unsigned int reg, unsigned int size, unsigned int *val)
{
int ret;
ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data);
if (ret < 0)
goto out;
switch (size) {
case 4:
*val = get_unaligned_be32(sigma_delta->data);
break;
case 3:
*val = (sigma_delta->data[0] << 16) |
(sigma_delta->data[1] << 8) |
sigma_delta->data[2];
break;
case 2:
*val = get_unaligned_be16(sigma_delta->data);
break;
case 1:
*val = sigma_delta->data[0];
break;
default:
ret = -EINVAL;
break;
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(ad_sd_read_reg);
static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
int ret;
ret = ad_sigma_delta_set_channel(sigma_delta, channel);
if (ret)
return ret;
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
INIT_COMPLETION(sigma_delta->completion);
ret = ad_sigma_delta_set_mode(sigma_delta, mode);
if (ret < 0)
goto out;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ);
if (ret == 0) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
ret = -EIO;
} else {
ret = 0;
}
out:
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
return ret;
}
/**
* ad_sd_calibrate_all() - Performs channel calibration
* @sigma_delta: The sigma delta device
* @cb: Array of channels and calibration type to perform
* @n: Number of items in cb
*
* Returns 0 on success, an error code otherwise.
**/
int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta,
const struct ad_sd_calib_data *cb, unsigned int n)
{
unsigned int i;
int ret;
for (i = 0; i < n; i++) {
ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_calibrate_all);
/**
* ad_sigma_delta_single_conversion() - Performs a single data conversion
* @indio_dev: The IIO device
* @chan: The conversion is done for this channel
* @val: Pointer to the location where to store the read value
*
* Returns: 0 on success, an error value otherwise.
*/
int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int sample, raw_sample;
int ret = 0;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
mutex_lock(&indio_dev->mlock);
ad_sigma_delta_set_channel(sigma_delta, chan->address);
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
INIT_COMPLETION(sigma_delta->completion);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
ret = wait_for_completion_interruptible_timeout(
&sigma_delta->completion, HZ);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
if (ret == 0)
ret = -EIO;
if (ret < 0)
goto out;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
&raw_sample);
out:
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->spi->irq);
sigma_delta->irq_dis = true;
}
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
sample = raw_sample >> chan->scan_type.shift;
sample &= (1 << chan->scan_type.realbits) - 1;
*val = sample;
ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample);
if (ret)
return ret;
return IIO_VAL_INT;
}
EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion);
static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int channel;
int ret;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret < 0)
return ret;
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
ret = ad_sigma_delta_set_channel(sigma_delta,
indio_dev->channels[channel].address);
if (ret)
goto err_predisable;
spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true;
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
if (ret)
goto err_unlock;
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
return 0;
err_unlock:
spi_bus_unlock(sigma_delta->spi->master);
err_predisable:
return ret;
}
static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
INIT_COMPLETION(sigma_delta->completion);
wait_for_completion_timeout(&sigma_delta->completion, HZ);
if (!sigma_delta->irq_dis) {
disable_irq_nosync(sigma_delta->spi->irq);
sigma_delta->irq_dis = true;
}
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
return spi_bus_unlock(sigma_delta->spi->master);
}
static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int reg_size;
uint8_t data[16];
int ret;
memset(data, 0x00, 16);
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
((s64 *)data)[1] = pf->timestamp;
reg_size = indio_dev->channels[0].scan_type.realbits +
indio_dev->channels[0].scan_type.shift;
reg_size = DIV_ROUND_UP(reg_size, 8);
switch (reg_size) {
case 4:
case 2:
case 1:
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[0]);
break;
case 3:
/* We store 24 bit samples in a 32 bit word. Keep the upper
* byte set to zero. */
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[1]);
break;
}
iio_push_to_buffers(indio_dev, (uint8_t *)data);
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
return IRQ_HANDLED;
}
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &ad_sd_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
.postdisable = &ad_sd_buffer_postdisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
{
struct ad_sigma_delta *sigma_delta = private;
complete(&sigma_delta->completion);
disable_irq_nosync(irq);
sigma_delta->irq_dis = true;
iio_trigger_poll(sigma_delta->trig, iio_get_time_ns());
return IRQ_HANDLED;
}
/**
* ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices
* @indio_dev: The IIO device
* @trig: The new trigger
*
* Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta
* device, -EINVAL otherwise.
*/
int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
if (sigma_delta->trig != trig)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
static const struct iio_trigger_ops ad_sd_trigger_ops = {
.owner = THIS_MODULE,
};
static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
int ret;
sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
indio_dev->id);
if (sigma_delta->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
sigma_delta->trig->ops = &ad_sd_trigger_ops;
init_completion(&sigma_delta->completion);
ret = request_irq(sigma_delta->spi->irq,
ad_sd_data_rdy_trig_poll,
IRQF_TRIGGER_LOW,
indio_dev->name,
sigma_delta);
if (ret)
goto error_free_trig;
if (!sigma_delta->irq_dis) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
}
sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
ret = iio_trigger_register(sigma_delta->trig);
if (ret)
goto error_free_irq;
/* select default trigger */
indio_dev->trig = sigma_delta->trig;
return 0;
error_free_irq:
free_irq(sigma_delta->spi->irq, sigma_delta);
error_free_trig:
iio_trigger_free(sigma_delta->trig);
error_ret:
return ret;
}
static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
iio_trigger_unregister(sigma_delta->trig);
free_irq(sigma_delta->spi->irq, sigma_delta);
iio_trigger_free(sigma_delta->trig);
}
/**
* ad_sd_setup_buffer_and_trigger() -
* @indio_dev: The IIO device
*/
int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
{
int ret;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
if (ret)
return ret;
ret = ad_sd_probe_trigger(indio_dev);
if (ret) {
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
/**
* ad_sd_cleanup_buffer_and_trigger() -
* @indio_dev: The IIO device
*/
void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
{
ad_sd_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
/**
* ad_sd_init() - Initializes a ad_sigma_delta struct
* @sigma_delta: The ad_sigma_delta device
* @indio_dev: The IIO device which the Sigma Delta device is used for
* @spi: The SPI device for the ad_sigma_delta device
* @info: Device specific callbacks and options
*
* This function needs to be called before any other operations are performed on
* the ad_sigma_delta struct.
*/
int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
struct spi_device *spi, const struct ad_sigma_delta_info *info)
{
sigma_delta->spi = spi;
sigma_delta->info = info;
iio_device_set_drvdata(indio_dev, sigma_delta);
return 0;
}
EXPORT_SYMBOL_GPL(ad_sd_init);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
MODULE_LICENSE("GPL v2");

796
drivers/iio/adc/at91_adc.c Normal file
View File

@@ -0,0 +1,796 @@
/*
* Driver for the ADC present in the Atmel AT91 evaluation boards.
*
* Copyright 2011 Free Electrons
*
* Licensed under the GPLv2 or later.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/platform_data/at91_adc.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <mach/at91_adc.h>
#define AT91_ADC_CHAN(st, ch) \
(st->registers->channel_base + (ch * 4))
#define at91_adc_readl(st, reg) \
(readl_relaxed(st->reg_base + reg))
#define at91_adc_writel(st, reg, val) \
(writel_relaxed(val, st->reg_base + reg))
struct at91_adc_state {
struct clk *adc_clk;
u16 *buffer;
unsigned long channels_mask;
struct clk *clk;
bool done;
int irq;
u16 last_value;
struct mutex lock;
u8 num_channels;
void __iomem *reg_base;
struct at91_adc_reg_desc *registers;
u8 startup_time;
u8 sample_hold_time;
bool sleep_mode;
struct iio_trigger **trig;
struct at91_adc_trigger *trigger_list;
u32 trigger_number;
bool use_external;
u32 vref_mv;
u32 res; /* resolution used for convertions */
bool low_res; /* the resolution corresponds to the lowest one */
wait_queue_head_t wq_data_avail;
};
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
if (!test_bit(i, idev->active_scan_mask))
continue;
st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
j++;
}
if (idev->scan_timestamp) {
s64 *timestamp = (s64 *)((u8 *)st->buffer +
ALIGN(j, sizeof(s64)));
*timestamp = pf->timestamp;
}
iio_push_to_buffers(idev, (u8 *)st->buffer);
iio_trigger_notify_done(idev->trig);
/* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_ADC_LCDR);
enable_irq(st->irq);
return IRQ_HANDLED;
}
static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
{
struct iio_dev *idev = private;
struct at91_adc_state *st = iio_priv(idev);
u32 status = at91_adc_readl(st, st->registers->status_register);
if (!(status & st->registers->drdy_mask))
return IRQ_HANDLED;
if (iio_buffer_enabled(idev)) {
disable_irq_nosync(irq);
iio_trigger_poll(idev->trig, iio_get_time_ns());
} else {
st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
st->done = true;
wake_up_interruptible(&st->wq_data_avail);
}
return IRQ_HANDLED;
}
static int at91_adc_channel_init(struct iio_dev *idev)
{
struct at91_adc_state *st = iio_priv(idev);
struct iio_chan_spec *chan_array, *timestamp;
int bit, idx = 0;
idev->num_channels = bitmap_weight(&st->channels_mask,
st->num_channels) + 1;
chan_array = devm_kzalloc(&idev->dev,
((idev->num_channels + 1) *
sizeof(struct iio_chan_spec)),
GFP_KERNEL);
if (!chan_array)
return -ENOMEM;
for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
struct iio_chan_spec *chan = chan_array + idx;
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = bit;
chan->scan_index = idx;
chan->scan_type.sign = 'u';
chan->scan_type.realbits = st->res;
chan->scan_type.storagebits = 16;
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
idx++;
}
timestamp = chan_array + idx;
timestamp->type = IIO_TIMESTAMP;
timestamp->channel = -1;
timestamp->scan_index = idx;
timestamp->scan_type.sign = 's';
timestamp->scan_type.realbits = 64;
timestamp->scan_type.storagebits = 64;
idev->channels = chan_array;
return idev->num_channels;
}
static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
struct at91_adc_trigger *triggers,
const char *trigger_name)
{
struct at91_adc_state *st = iio_priv(idev);
u8 value = 0;
int i;
for (i = 0; i < st->trigger_number; i++) {
char *name = kasprintf(GFP_KERNEL,
"%s-dev%d-%s",
idev->name,
idev->id,
triggers[i].name);
if (!name)
return -ENOMEM;
if (strcmp(trigger_name, name) == 0) {
value = triggers[i].value;
kfree(name);
break;
}
kfree(name);
}
return value;
}
static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{
struct iio_dev *idev = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(idev);
struct iio_buffer *buffer = idev->buffer;
struct at91_adc_reg_desc *reg = st->registers;
u32 status = at91_adc_readl(st, reg->trigger_register);
u8 value;
u8 bit;
value = at91_adc_get_trigger_value_by_name(idev,
st->trigger_list,
idev->trig->name);
if (value == 0)
return -EINVAL;
if (state) {
st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
if (st->buffer == NULL)
return -ENOMEM;
at91_adc_writel(st, reg->trigger_register,
status | value);
for_each_set_bit(bit, buffer->scan_mask,
st->num_channels) {
struct iio_chan_spec const *chan = idev->channels + bit;
at91_adc_writel(st, AT91_ADC_CHER,
AT91_ADC_CH(chan->channel));
}
at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
} else {
at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
at91_adc_writel(st, reg->trigger_register,
status & ~value);
for_each_set_bit(bit, buffer->scan_mask,
st->num_channels) {
struct iio_chan_spec const *chan = idev->channels + bit;
at91_adc_writel(st, AT91_ADC_CHDR,
AT91_ADC_CH(chan->channel));
}
kfree(st->buffer);
}
return 0;
}
static const struct iio_trigger_ops at91_adc_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &at91_adc_configure_trigger,
};
static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
struct at91_adc_trigger *trigger)
{
struct iio_trigger *trig;
int ret;
trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
idev->id, trigger->name);
if (trig == NULL)
return NULL;
trig->dev.parent = idev->dev.parent;
iio_trigger_set_drvdata(trig, idev);
trig->ops = &at91_adc_trigger_ops;
ret = iio_trigger_register(trig);
if (ret)
return NULL;
return trig;
}
static int at91_adc_trigger_init(struct iio_dev *idev)
{
struct at91_adc_state *st = iio_priv(idev);
int i, ret;
st->trig = devm_kzalloc(&idev->dev,
st->trigger_number * sizeof(st->trig),
GFP_KERNEL);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
for (i = 0; i < st->trigger_number; i++) {
if (st->trigger_list[i].is_external && !(st->use_external))
continue;
st->trig[i] = at91_adc_allocate_trigger(idev,
st->trigger_list + i);
if (st->trig[i] == NULL) {
dev_err(&idev->dev,
"Could not allocate trigger %d\n", i);
ret = -ENOMEM;
goto error_trigger;
}
}
return 0;
error_trigger:
for (i--; i >= 0; i--) {
iio_trigger_unregister(st->trig[i]);
iio_trigger_free(st->trig[i]);
}
error_ret:
return ret;
}
static void at91_adc_trigger_remove(struct iio_dev *idev)
{
struct at91_adc_state *st = iio_priv(idev);
int i;
for (i = 0; i < st->trigger_number; i++) {
iio_trigger_unregister(st->trig[i]);
iio_trigger_free(st->trig[i]);
}
}
static int at91_adc_buffer_init(struct iio_dev *idev)
{
return iio_triggered_buffer_setup(idev, &iio_pollfunc_store_time,
&at91_adc_trigger_handler, NULL);
}
static void at91_adc_buffer_remove(struct iio_dev *idev)
{
iio_triggered_buffer_cleanup(idev);
}
static int at91_adc_read_raw(struct iio_dev *idev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct at91_adc_state *st = iio_priv(idev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
at91_adc_writel(st, AT91_ADC_CHER,
AT91_ADC_CH(chan->channel));
at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
ret = wait_event_interruptible_timeout(st->wq_data_avail,
st->done,
msecs_to_jiffies(1000));
if (ret == 0)
ret = -ETIMEDOUT;
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
*val = st->last_value;
at91_adc_writel(st, AT91_ADC_CHDR,
AT91_ADC_CH(chan->channel));
at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
st->last_value = 0;
st->done = false;
mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
*val2 = 0;
return IIO_VAL_INT_PLUS_MICRO;
default:
break;
}
return -EINVAL;
}
static int at91_adc_of_get_resolution(struct at91_adc_state *st,
struct platform_device *pdev)
{
struct iio_dev *idev = iio_priv_to_dev(st);
struct device_node *np = pdev->dev.of_node;
int count, i, ret = 0;
char *res_name, *s;
u32 *resolutions;
count = of_property_count_strings(np, "atmel,adc-res-names");
if (count < 2) {
dev_err(&idev->dev, "You must specified at least two resolution names for "
"adc-res-names property in the DT\n");
return count;
}
resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
if (!resolutions)
return -ENOMEM;
if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) {
dev_err(&idev->dev, "Missing adc-res property in the DT.\n");
ret = -ENODEV;
goto ret;
}
if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name))
res_name = "highres";
for (i = 0; i < count; i++) {
if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s))
continue;
if (strcmp(res_name, s))
continue;
st->res = resolutions[i];
if (!strcmp(res_name, "lowres"))
st->low_res = true;
else
st->low_res = false;
dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
goto ret;
}
dev_err(&idev->dev, "There is no resolution for %s\n", res_name);
ret:
kfree(resolutions);
return ret;
}
static int at91_adc_probe_dt(struct at91_adc_state *st,
struct platform_device *pdev)
{
struct iio_dev *idev = iio_priv_to_dev(st);
struct device_node *node = pdev->dev.of_node;
struct device_node *trig_node;
int i = 0, ret;
u32 prop;
if (!node)
return -EINVAL;
st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->channels_mask = prop;
if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->num_channels = prop;
st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->startup_time = prop;
prop = 0;
of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop);
st->sample_hold_time = prop;
if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->vref_mv = prop;
ret = at91_adc_of_get_resolution(st, pdev);
if (ret)
goto error_ret;
st->registers = devm_kzalloc(&idev->dev,
sizeof(struct at91_adc_reg_desc),
GFP_KERNEL);
if (!st->registers) {
dev_err(&idev->dev, "Could not allocate register memory.\n");
ret = -ENOMEM;
goto error_ret;
}
if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->registers->channel_base = prop;
if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->registers->drdy_mask = prop;
if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->registers->status_register = prop;
if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
st->registers->trigger_register = prop;
st->trigger_number = of_get_child_count(node);
st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
sizeof(struct at91_adc_trigger),
GFP_KERNEL);
if (!st->trigger_list) {
dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
ret = -ENOMEM;
goto error_ret;
}
for_each_child_of_node(node, trig_node) {
struct at91_adc_trigger *trig = st->trigger_list + i;
const char *name;
if (of_property_read_string(trig_node, "trigger-name", &name)) {
dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
trig->name = name;
if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
trig->value = prop;
trig->is_external = of_property_read_bool(trig_node, "trigger-external");
i++;
}
return 0;
error_ret:
return ret;
}
static int at91_adc_probe_pdata(struct at91_adc_state *st,
struct platform_device *pdev)
{
struct at91_adc_data *pdata = pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
st->use_external = pdata->use_external_triggers;
st->vref_mv = pdata->vref;
st->channels_mask = pdata->channels_used;
st->num_channels = pdata->num_channels;
st->startup_time = pdata->startup_time;
st->trigger_number = pdata->trigger_number;
st->trigger_list = pdata->trigger_list;
st->registers = pdata->registers;
return 0;
}
static const struct iio_info at91_adc_info = {
.driver_module = THIS_MODULE,
.read_raw = &at91_adc_read_raw,
};
static int at91_adc_probe(struct platform_device *pdev)
{
unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
int ret;
struct iio_dev *idev;
struct at91_adc_state *st;
struct resource *res;
u32 reg;
idev = iio_device_alloc(sizeof(struct at91_adc_state));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
}
st = iio_priv(idev);
if (pdev->dev.of_node)
ret = at91_adc_probe_dt(st, pdev);
else
ret = at91_adc_probe_pdata(st, pdev);
if (ret) {
dev_err(&pdev->dev, "No platform data available.\n");
ret = -EINVAL;
goto error_free_device;
}
platform_set_drvdata(pdev, idev);
idev->dev.parent = &pdev->dev;
idev->name = dev_name(&pdev->dev);
idev->modes = INDIO_DIRECT_MODE;
idev->info = &at91_adc_info;
st->irq = platform_get_irq(pdev, 0);
if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQ ID is designated\n");
ret = -ENODEV;
goto error_free_device;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
st->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(st->reg_base)) {
ret = PTR_ERR(st->reg_base);
goto error_free_device;
}
/*
* Disable all IRQs before setting up the handler
*/
at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
ret = request_irq(st->irq,
at91_adc_eoc_trigger,
0,
pdev->dev.driver->name,
idev);
if (ret) {
dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
goto error_free_device;
}
st->clk = devm_clk_get(&pdev->dev, "adc_clk");
if (IS_ERR(st->clk)) {
dev_err(&pdev->dev, "Failed to get the clock.\n");
ret = PTR_ERR(st->clk);
goto error_free_irq;
}
ret = clk_prepare_enable(st->clk);
if (ret) {
dev_err(&pdev->dev,
"Could not prepare or enable the clock.\n");
goto error_free_irq;
}
st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
if (IS_ERR(st->adc_clk)) {
dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
ret = PTR_ERR(st->adc_clk);
goto error_disable_clk;
}
ret = clk_prepare_enable(st->adc_clk);
if (ret) {
dev_err(&pdev->dev,
"Could not prepare or enable the ADC clock.\n");
goto error_disable_clk;
}
/*
* Prescaler rate computation using the formula from the Atmel's
* datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
* specified by the electrical characteristics of the board.
*/
mstrclk = clk_get_rate(st->clk);
adc_clk = clk_get_rate(st->adc_clk);
prsc = (mstrclk / (2 * adc_clk)) - 1;
if (!st->startup_time) {
dev_err(&pdev->dev, "No startup time available.\n");
ret = -EINVAL;
goto error_disable_adc_clk;
}
/*
* Number of ticks needed to cover the startup time of the ADC as
* defined in the electrical characteristics of the board, divided by 8.
* The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
*/
ticks = round_up((st->startup_time * adc_clk /
1000000) - 1, 8) / 8;
/*
* a minimal Sample and Hold Time is necessary for the ADC to guarantee
* the best converted final value between two channels selection
* The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
*/
shtim = round_up((st->sample_hold_time * adc_clk /
1000000) - 1, 1);
reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
if (st->low_res)
reg |= AT91_ADC_LOWRES;
if (st->sleep_mode)
reg |= AT91_ADC_SLEEP;
reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM;
at91_adc_writel(st, AT91_ADC_MR, reg);
/* Setup the ADC channels available on the board */
ret = at91_adc_channel_init(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
goto error_disable_adc_clk;
}
init_waitqueue_head(&st->wq_data_avail);
mutex_init(&st->lock);
ret = at91_adc_buffer_init(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
goto error_disable_adc_clk;
}
ret = at91_adc_trigger_init(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
goto error_unregister_buffer;
}
ret = iio_device_register(idev);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto error_remove_triggers;
}
return 0;
error_remove_triggers:
at91_adc_trigger_remove(idev);
error_unregister_buffer:
at91_adc_buffer_remove(idev);
error_disable_adc_clk:
clk_disable_unprepare(st->adc_clk);
error_disable_clk:
clk_disable_unprepare(st->clk);
error_free_irq:
free_irq(st->irq, idev);
error_free_device:
iio_device_free(idev);
error_ret:
return ret;
}
static int at91_adc_remove(struct platform_device *pdev)
{
struct iio_dev *idev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(idev);
iio_device_unregister(idev);
at91_adc_trigger_remove(idev);
at91_adc_buffer_remove(idev);
clk_disable_unprepare(st->adc_clk);
clk_disable_unprepare(st->clk);
free_irq(st->irq, idev);
iio_device_free(idev);
return 0;
}
static const struct of_device_id at91_adc_dt_ids[] = {
{ .compatible = "atmel,at91sam9260-adc" },
{},
};
MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
static struct platform_driver at91_adc_driver = {
.probe = at91_adc_probe,
.remove = at91_adc_remove,
.driver = {
.name = "at91_adc",
.of_match_table = of_match_ptr(at91_adc_dt_ids),
},
};
module_platform_driver(at91_adc_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");

View File

@@ -0,0 +1,452 @@
/*
* exynos_adc.c - Support for ADC in EXYNOS SoCs
*
* 8 ~ 10 channel, 10/12-bit ADC
*
* Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
enum adc_version {
ADC_V1,
ADC_V2
};
/* EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00)
#define ADC_V1_DLY(x) ((x) + 0x08)
#define ADC_V1_DATX(x) ((x) + 0x0C)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
#define ADC_V2_CON2(x) ((x) + 0x04)
#define ADC_V2_STAT(x) ((x) + 0x08)
#define ADC_V2_INT_EN(x) ((x) + 0x10)
#define ADC_V2_INT_ST(x) ((x) + 0x14)
#define ADC_V2_VER(x) ((x) + 0x20)
/* Bit definitions for ADC_V1 */
#define ADC_V1_CON_RES (1u << 16)
#define ADC_V1_CON_PRSCEN (1u << 14)
#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY (1u << 2)
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
#define ADC_V2_CON2_OSEL (1u << 10)
#define ADC_V2_CON2_ESEL (1u << 9)
#define ADC_V2_CON2_HIGHF (1u << 8)
#define ADC_V2_CON2_C_TIME(x) (((x) & 7) << 4)
#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
#define ADC_V2_CON2_ACH_MASK 0xF
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
#define ADC_DATX_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(1000))
struct exynos_adc {
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
unsigned int irq;
struct regulator *vdd;
struct completion completion;
u32 value;
unsigned int version;
};
static const struct of_device_id exynos_adc_match[] = {
{ .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 },
{ .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 },
{},
};
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos_adc_match, pdev->dev.of_node);
return (unsigned int)match->data;
}
static int exynos_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
u32 con1, con2;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
/* Select the channel to be used and Trigger conversion */
if (info->version == ADC_V2) {
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_ACH_MASK;
con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
writel(con2, ADC_V2_CON2(info->regs));
con1 = readl(ADC_V2_CON1(info->regs));
writel(con1 | ADC_CON_EN_START,
ADC_V2_CON1(info->regs));
} else {
writel(chan->address, ADC_V1_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START,
ADC_V1_CON(info->regs));
}
timeout = wait_for_completion_interruptible_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT);
*val = info->value;
mutex_unlock(&indio_dev->mlock);
if (timeout == 0)
return -ETIMEDOUT;
return IIO_VAL_INT;
}
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
/* Read value */
info->value = readl(ADC_V1_DATX(info->regs)) &
ADC_DATX_MASK;
/* clear irq */
if (info->version == ADC_V2)
writel(1, ADC_V2_INT_ST(info->regs));
else
writel(1, ADC_V1_INTCLR(info->regs));
complete(&info->completion);
return IRQ_HANDLED;
}
static int exynos_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct exynos_adc *info = iio_priv(indio_dev);
if (readval == NULL)
return -EINVAL;
*readval = readl(info->regs + reg);
return 0;
}
static const struct iio_info exynos_adc_iio_info = {
.read_raw = &exynos_read_raw,
.debugfs_reg_access = &exynos_adc_reg_access,
.driver_module = THIS_MODULE,
};
#define ADC_CHANNEL(_index, _id) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.address = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.datasheet_name = _id, \
}
static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
ADC_CHANNEL(3, "adc3"),
ADC_CHANNEL(4, "adc4"),
ADC_CHANNEL(5, "adc5"),
ADC_CHANNEL(6, "adc6"),
ADC_CHANNEL(7, "adc7"),
ADC_CHANNEL(8, "adc8"),
ADC_CHANNEL(9, "adc9"),
};
static int exynos_adc_remove_devices(struct device *dev, void *c)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
static void exynos_adc_hw_init(struct exynos_adc *info)
{
u32 con1, con2;
if (info->version == ADC_V2) {
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
} else {
/* set default prescaler values and Enable prescaler */
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
/* Enable 12-bit ADC resolution */
con1 |= ADC_V1_CON_RES;
writel(con1, ADC_V1_CON(info->regs));
}
}
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
int ret = -ENODEV;
int irq;
if (!np)
return ret;
indio_dev = iio_device_alloc(sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_request_and_ioremap(&pdev->dev, mem);
if (!info->regs) {
ret = -ENOMEM;
goto err_iio;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_request_and_ioremap(&pdev->dev, mem);
if (!info->enable_reg) {
ret = -ENOMEM;
goto err_iio;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
ret = irq;
goto err_iio;
}
info->irq = irq;
init_completion(&info->completion);
ret = request_irq(info->irq, exynos_adc_isr,
0, dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
info->irq);
goto err_iio;
}
writel(1, info->enable_reg);
info->clk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
ret = PTR_ERR(info->clk);
goto err_irq;
}
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) {
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
PTR_ERR(info->vdd));
ret = PTR_ERR(info->vdd);
goto err_irq;
}
info->version = exynos_adc_get_version(pdev);
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &exynos_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = exynos_adc_iio_channels;
if (info->version == ADC_V1)
indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
else
indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
ret = iio_device_register(indio_dev);
if (ret)
goto err_irq;
ret = regulator_enable(info->vdd);
if (ret)
goto err_iio_dev;
clk_prepare_enable(info->clk);
exynos_adc_hw_init(info);
ret = of_platform_populate(np, exynos_adc_match, NULL, &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
goto err_of_populate;
}
return 0;
err_of_populate:
device_for_each_child(&pdev->dev, NULL,
exynos_adc_remove_devices);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
err_iio_dev:
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
err_iio:
iio_device_free(indio_dev);
return ret;
}
static int exynos_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
device_for_each_child(&pdev->dev, NULL,
exynos_adc_remove_devices);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
iio_device_unregister(indio_dev);
free_irq(info->irq, info);
iio_device_free(indio_dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int exynos_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev);
u32 con;
if (info->version == ADC_V2) {
con = readl(ADC_V2_CON1(info->regs));
con &= ~ADC_CON_EN_START;
writel(con, ADC_V2_CON1(info->regs));
} else {
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
writel(con, ADC_V1_CON(info->regs));
}
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
regulator_disable(info->vdd);
return 0;
}
static int exynos_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vdd);
if (ret)
return ret;
writel(1, info->enable_reg);
clk_prepare_enable(info->clk);
exynos_adc_hw_init(info);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops,
exynos_adc_suspend,
exynos_adc_resume);
static struct platform_driver exynos_adc_driver = {
.probe = exynos_adc_probe,
.remove = exynos_adc_remove,
.driver = {
.name = "exynos-adc",
.owner = THIS_MODULE,
.of_match_table = exynos_adc_match,
.pm = &exynos_adc_pm_ops,
},
};
module_platform_driver(exynos_adc_driver);
MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>");
MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,258 @@
/*
* TI LP8788 MFD - ADC driver
*
* Copyright 2012 Texas Instruments
*
* Author: Milo(Woogyom) Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/mfd/lp8788.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* register address */
#define LP8788_ADC_CONF 0x60
#define LP8788_ADC_RAW 0x61
#define LP8788_ADC_DONE 0x63
#define ADC_CONV_START 1
struct lp8788_adc {
struct lp8788 *lp;
struct iio_map *map;
struct mutex lock;
};
static const int lp8788_scale[LPADC_MAX] = {
[LPADC_VBATT_5P5] = 1343101,
[LPADC_VIN_CHG] = 3052503,
[LPADC_IBATT] = 610500,
[LPADC_IC_TEMP] = 61050,
[LPADC_VBATT_6P0] = 1465201,
[LPADC_VBATT_5P0] = 1221001,
[LPADC_ADC1] = 610500,
[LPADC_ADC2] = 610500,
[LPADC_VDD] = 1025641,
[LPADC_VCOIN] = 757020,
[LPADC_ADC3] = 610500,
[LPADC_ADC4] = 610500,
};
static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id,
int *val)
{
unsigned int msb;
unsigned int lsb;
unsigned int result;
u8 data;
u8 rawdata[2];
int size = ARRAY_SIZE(rawdata);
int retry = 5;
int ret;
data = (id << 1) | ADC_CONV_START;
ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data);
if (ret)
goto err_io;
/* retry until adc conversion is done */
data = 0;
while (retry--) {
usleep_range(100, 200);
ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data);
if (ret)
goto err_io;
/* conversion done */
if (data)
break;
}
ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size);
if (ret)
goto err_io;
msb = (rawdata[0] << 4) & 0x00000ff0;
lsb = (rawdata[1] >> 4) & 0x0000000f;
result = msb | lsb;
*val = result;
return 0;
err_io:
return ret;
}
static int lp8788_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct lp8788_adc *adc = iio_priv(indio_dev);
enum lp8788_adc_id id = chan->channel;
int ret;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = lp8788_scale[id] / 1000000;
*val2 = lp8788_scale[id] % 1000000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&adc->lock);
return ret;
}
static const struct iio_info lp8788_adc_info = {
.read_raw = &lp8788_adc_read_raw,
.driver_module = THIS_MODULE,
};
#define LP8788_CHAN(_id, _type) { \
.type = _type, \
.indexed = 1, \
.channel = LPADC_##_id, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = #_id, \
}
static const struct iio_chan_spec lp8788_adc_channels[] = {
[LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE),
[LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE),
[LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT),
[LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP),
[LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE),
[LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE),
[LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE),
[LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE),
[LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE),
[LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE),
[LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE),
[LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE),
};
/* default maps used by iio consumer (lp8788-charger driver) */
static struct iio_map lp8788_default_iio_maps[] = {
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_vbatt_5p0",
.adc_channel_label = "VBATT_5P0",
},
{
.consumer_dev_name = "lp8788-charger",
.consumer_channel = "lp8788_adc1",
.adc_channel_label = "ADC1",
},
{ }
};
static int lp8788_iio_map_register(struct iio_dev *indio_dev,
struct lp8788_platform_data *pdata,
struct lp8788_adc *adc)
{
struct iio_map *map;
int ret;
map = (!pdata || !pdata->adc_pdata) ?
lp8788_default_iio_maps : pdata->adc_pdata;
ret = iio_map_array_register(indio_dev, map);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
return ret;
}
adc->map = map;
return 0;
}
static int lp8788_adc_probe(struct platform_device *pdev)
{
struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
struct iio_dev *indio_dev;
struct lp8788_adc *adc;
int ret;
indio_dev = iio_device_alloc(sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->lp = lp;
platform_set_drvdata(pdev, indio_dev);
indio_dev->dev.of_node = pdev->dev.of_node;
ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
if (ret)
goto err_iio_map;
mutex_init(&adc->lock);
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &lp8788_adc_info;
indio_dev->channels = lp8788_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "iio dev register err: %d\n", ret);
goto err_iio_device;
}
return 0;
err_iio_device:
iio_map_array_unregister(indio_dev);
err_iio_map:
iio_device_free(indio_dev);
return ret;
}
static int lp8788_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
}
static struct platform_driver lp8788_adc_driver = {
.probe = lp8788_adc_probe,
.remove = lp8788_adc_remove,
.driver = {
.name = LP8788_DEV_ADC,
.owner = THIS_MODULE,
},
};
module_platform_driver(lp8788_adc_driver);
MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver");
MODULE_AUTHOR("Milo Kim");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:lp8788-adc");

1667
drivers/iio/adc/max1363.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2012 Avionic Design GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
struct adc081c {
struct i2c_client *i2c;
struct regulator *ref;
};
#define REG_CONV_RES 0x00
static int adc081c_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *value,
int *shift, long mask)
{
struct adc081c *adc = iio_priv(iio);
int err;
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = i2c_smbus_read_word_swapped(adc->i2c, REG_CONV_RES);
if (err < 0)
return err;
*value = (err >> 4) & 0xff;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
err = regulator_get_voltage(adc->ref);
if (err < 0)
return err;
*value = err / 1000;
*shift = 8;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static const struct iio_chan_spec adc081c_channel = {
.type = IIO_VOLTAGE,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
};
static const struct iio_info adc081c_info = {
.read_raw = adc081c_read_raw,
.driver_module = THIS_MODULE,
};
static int adc081c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *iio;
struct adc081c *adc;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
iio = iio_device_alloc(sizeof(*adc));
if (!iio)
return -ENOMEM;
adc = iio_priv(iio);
adc->i2c = client;
adc->ref = regulator_get(&client->dev, "vref");
if (IS_ERR(adc->ref)) {
err = PTR_ERR(adc->ref);
goto iio_free;
}
err = regulator_enable(adc->ref);
if (err < 0)
goto regulator_put;
iio->dev.parent = &client->dev;
iio->name = dev_name(&client->dev);
iio->modes = INDIO_DIRECT_MODE;
iio->info = &adc081c_info;
iio->channels = &adc081c_channel;
iio->num_channels = 1;
err = iio_device_register(iio);
if (err < 0)
goto regulator_disable;
i2c_set_clientdata(client, iio);
return 0;
regulator_disable:
regulator_disable(adc->ref);
regulator_put:
regulator_put(adc->ref);
iio_free:
iio_device_free(iio);
return err;
}
static int adc081c_remove(struct i2c_client *client)
{
struct iio_dev *iio = i2c_get_clientdata(client);
struct adc081c *adc = iio_priv(iio);
iio_device_unregister(iio);
regulator_disable(adc->ref);
regulator_put(adc->ref);
iio_device_free(iio);
return 0;
}
static const struct i2c_device_id adc081c_id[] = {
{ "adc081c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
#ifdef CONFIG_OF
static const struct of_device_id adc081c_of_match[] = {
{ .compatible = "ti,adc081c" },
{ }
};
MODULE_DEVICE_TABLE(of, adc081c_of_match);
#endif
static struct i2c_driver adc081c_driver = {
.driver = {
.name = "adc081c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(adc081c_of_match),
},
.probe = adc081c_probe,
.remove = adc081c_remove,
.id_table = adc081c_id,
};
module_i2c_driver(adc081c_driver);
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,260 @@
/*
* TI ADC MFD driver
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/mfd/ti_am335x_tscadc.h>
#include <linux/platform_data/ti_am335x_adc.h>
struct tiadc_device {
struct ti_tscadc_dev *mfd_tscadc;
int channels;
};
static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
{
return readl(adc->mfd_tscadc->tscadc_base + reg);
}
static void tiadc_writel(struct tiadc_device *adc, unsigned int reg,
unsigned int val)
{
writel(val, adc->mfd_tscadc->tscadc_base + reg);
}
static void tiadc_step_config(struct tiadc_device *adc_dev)
{
unsigned int stepconfig;
int i, channels = 0, steps;
/*
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC.
*
* Steps backwards i.e. from 16 towards 0 are used by ADC
* depending on number of input lines needed.
* Channel would represent which analog input
* needs to be given to ADC to digitalize data.
*/
steps = TOTAL_STEPS - adc_dev->channels;
channels = TOTAL_CHANNELS - adc_dev->channels;
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
for (i = (steps + 1); i <= TOTAL_STEPS; i++) {
tiadc_writel(adc_dev, REG_STEPCONFIG(i),
stepconfig | STEPCONFIG_INP(channels));
tiadc_writel(adc_dev, REG_STEPDELAY(i),
STEPCONFIG_OPENDLY);
channels++;
}
tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
}
static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
{
struct iio_chan_spec *chan_array;
int i;
indio_dev->num_channels = channels;
chan_array = kcalloc(indio_dev->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (chan_array == NULL)
return -ENOMEM;
for (i = 0; i < (indio_dev->num_channels); i++) {
struct iio_chan_spec *chan = chan_array + i;
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = i;
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
}
indio_dev->channels = chan_array;
return indio_dev->num_channels;
}
static void tiadc_channels_remove(struct iio_dev *indio_dev)
{
kfree(indio_dev->channels);
}
static int tiadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i;
unsigned int fifo1count, readx1;
/*
* When the sub-system is first enabled,
* the sequencer will always start with the
* lowest step (1) and continue until step (16).
* For ex: If we have enabled 4 ADC channels and
* currently use only 1 out of them, the
* sequencer still configures all the 4 steps,
* leading to 3 unwanted data.
* Hence we need to flush out this data.
*/
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++) {
readx1 = tiadc_readl(adc_dev, REG_FIFO1);
if (i == chan->channel)
*val = readx1 & 0xfff;
}
tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
return IIO_VAL_INT;
}
static const struct iio_info tiadc_info = {
.read_raw = &tiadc_read_raw,
};
static int tiadc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct tiadc_device *adc_dev;
struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
struct mfd_tscadc_board *pdata;
int err;
pdata = tscadc_dev->dev->platform_data;
if (!pdata || !pdata->adc_init) {
dev_err(&pdev->dev, "Could not find platform data\n");
return -EINVAL;
}
indio_dev = iio_device_alloc(sizeof(struct tiadc_device));
if (indio_dev == NULL) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
err = -ENOMEM;
goto err_ret;
}
adc_dev = iio_priv(indio_dev);
adc_dev->mfd_tscadc = tscadc_dev;
adc_dev->channels = pdata->adc_init->adc_channels;
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tiadc_info;
tiadc_step_config(adc_dev);
err = tiadc_channel_init(indio_dev, adc_dev->channels);
if (err < 0)
goto err_free_device;
err = iio_device_register(indio_dev);
if (err)
goto err_free_channels;
platform_set_drvdata(pdev, indio_dev);
return 0;
err_free_channels:
tiadc_channels_remove(indio_dev);
err_free_device:
iio_device_free(indio_dev);
err_ret:
return err;
}
static int tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
tiadc_channels_remove(indio_dev);
iio_device_free(indio_dev);
return 0;
}
#ifdef CONFIG_PM
static int tiadc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
unsigned int idle;
if (!device_may_wakeup(tscadc_dev->dev)) {
idle = tiadc_readl(adc_dev, REG_CTRL);
idle &= ~(CNTRLREG_TSCSSENB);
tiadc_writel(adc_dev, REG_CTRL, (idle |
CNTRLREG_POWERDOWN));
}
return 0;
}
static int tiadc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int restore;
/* Make sure ADC is powered up */
restore = tiadc_readl(adc_dev, REG_CTRL);
restore &= ~(CNTRLREG_POWERDOWN);
tiadc_writel(adc_dev, REG_CTRL, restore);
tiadc_step_config(adc_dev);
return 0;
}
static const struct dev_pm_ops tiadc_pm_ops = {
.suspend = tiadc_suspend,
.resume = tiadc_resume,
};
#define TIADC_PM_OPS (&tiadc_pm_ops)
#else
#define TIADC_PM_OPS NULL
#endif
static struct platform_driver tiadc_driver = {
.driver = {
.name = "tiadc",
.owner = THIS_MODULE,
.pm = TIADC_PM_OPS,
},
.probe = tiadc_probe,
.remove = tiadc_remove,
};
module_platform_driver(tiadc_driver);
MODULE_DESCRIPTION("TI ADC controller driver");
MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,181 @@
/*
* Nano River Technologies viperboard IIO ADC driver
*
* (C) 2012 by Lemonage GmbH
* Author: Lars Poeschel <poeschel@lemonage.de>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/iio/iio.h>
#include <linux/mfd/viperboard.h>
#define VPRBRD_ADC_CMD_GET 0x00
struct vprbrd_adc_msg {
u8 cmd;
u8 chan;
u8 val;
} __packed;
struct vprbrd_adc {
struct vprbrd *vb;
};
#define VPRBRD_ADC_CHANNEL(_index) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \
.scan_type = { \
.sign = 'u', \
.realbits = 8, \
.storagebits = 8, \
}, \
}
static struct iio_chan_spec const vprbrd_adc_iio_channels[] = {
VPRBRD_ADC_CHANNEL(0),
VPRBRD_ADC_CHANNEL(1),
VPRBRD_ADC_CHANNEL(2),
VPRBRD_ADC_CHANNEL(3),
};
static int vprbrd_iio_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
int ret, error = 0;
struct vprbrd_adc *adc = iio_priv(iio_dev);
struct vprbrd *vb = adc->vb;
struct vprbrd_adc_msg *admsg = (struct vprbrd_adc_msg *)vb->buf;
switch (info) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&vb->lock);
admsg->cmd = VPRBRD_ADC_CMD_GET;
admsg->chan = chan->scan_index;
admsg->val = 0x00;
ret = usb_control_msg(vb->usb_dev,
usb_sndctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
if (ret != sizeof(struct vprbrd_adc_msg)) {
dev_err(&iio_dev->dev, "usb send error on adc read\n");
error = -EREMOTEIO;
}
ret = usb_control_msg(vb->usb_dev,
usb_rcvctrlpipe(vb->usb_dev, 0), VPRBRD_USB_REQUEST_ADC,
VPRBRD_USB_TYPE_IN, 0x0000, 0x0000, admsg,
sizeof(struct vprbrd_adc_msg), VPRBRD_USB_TIMEOUT_MS);
*val = admsg->val;
mutex_unlock(&vb->lock);
if (ret != sizeof(struct vprbrd_adc_msg)) {
dev_err(&iio_dev->dev, "usb recv error on adc read\n");
error = -EREMOTEIO;
}
if (error)
goto error;
return IIO_VAL_INT;
default:
error = -EINVAL;
break;
}
error:
return error;
}
static const struct iio_info vprbrd_adc_iio_info = {
.read_raw = &vprbrd_iio_read_raw,
.driver_module = THIS_MODULE,
};
static int vprbrd_adc_probe(struct platform_device *pdev)
{
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
struct vprbrd_adc *adc;
struct iio_dev *indio_dev;
int ret;
/* registering iio */
indio_dev = iio_device_alloc(sizeof(*adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
adc = iio_priv(indio_dev);
adc->vb = vb;
indio_dev->name = "viperboard adc";
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &vprbrd_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vprbrd_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vprbrd_adc_iio_channels);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio (adc)");
goto error;
}
platform_set_drvdata(pdev, indio_dev);
return 0;
error:
iio_device_free(indio_dev);
return ret;
}
static int vprbrd_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_device_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
}
static struct platform_driver vprbrd_adc_driver = {
.driver = {
.name = "viperboard-adc",
.owner = THIS_MODULE,
},
.probe = vprbrd_adc_probe,
.remove = vprbrd_adc_remove,
};
module_platform_driver(vprbrd_adc_driver);
MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
MODULE_DESCRIPTION("IIO ADC driver for Nano River Techs Viperboard");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:viperboard-adc");