Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

302
drivers/iio/adc/Kconfig Normal file
View file

@ -0,0 +1,302 @@
#
# ADC drivers
#
# When adding new entries keep the list in alphabetical order
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 AD7291
tristate "Analog Devices AD7291 ADC driver"
depends on I2C
help
Say yes here to build support for Analog Devices AD7291
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7291.
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 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 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 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 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 AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices:
ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998
i2c analog to digital converters (ADC). Provides direct access
via sysfs.
config AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91
depends on INPUT
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select SYSFS
help
Say yes here to build support for Atmel AT91 ADC.
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
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
tristate "LP8788 ADC driver"
depends on MFD_LP8788
help
Say yes here to build support for TI LP8788 ADC.
config MAX1027
tristate "Maxim max1027 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Maxim SPI ADC models
max1027, max1029 and max1031.
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 MCP320X
tristate "Microchip Technology MCP3204/08"
depends on SPI
help
Say yes here to build support for Microchip Technology's MCP3204 or
MCP3208 analog to digital converter.
This driver can also be built as a module. If so, the module will be
called mcp320x.
config MCP3422
tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
depends on I2C
help
Say yes here to build support for Microchip Technology's
MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428
analog to digital converters.
This driver can also be built as a module. If so, the module will be
called mcp3422.
config MEN_Z188_ADC
tristate "MEN 16z188 ADC IP Core support"
depends on MCB
help
Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB
carrier.
This driver can also be built as a module. If so, the module will be
called men_z188_adc.
config NAU7802
tristate "Nuvoton NAU7802 ADC driver"
depends on I2C
help
Say yes here to build support for Nuvoton NAU7802 ADC.
To compile this driver as a module, choose M here: the
module will be called nau7802.
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
help
Say yes here to build support for the SARADC found in SoCs from
Rockchip.
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
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_ADC128S052
tristate "Texas Instruments ADC128S052"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC128S052
chip.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC
select IIO_BUFFER
select IIO_KFIFO_BUF
help
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
help
This driver provides support for Triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can also be built as a module. If so, the module will be
called twl4030-madc.
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
default n
help
Say yes here if you want support for the TWL6030/TWL6032 General
Purpose A/D Converter. This will add support for battery type
detection, battery voltage and temperature measurement, die
temperature measurement, system supply voltage, audio accessory,
USB ID detection.
This driver can also be built as a module. If so, the module will be
called twl6030-gpadc.
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on OF
help
Say yes here to support for Vybrid board analog-to-digital converter.
Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
This driver can also be built as a module. If so, the module will be
called vf610_adc.
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.
config XILINX_XADC
tristate "Xilinx XADC driver"
depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST
depends on HAS_IOMEM
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to have support for the Xilinx XADC. The driver does support
both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
The driver can also be build as a module. If so, the module will be called
xilinx-xadc.
endmenu

34
drivers/iio/adc/Makefile Normal file
View file

@ -0,0 +1,34 @@
#
# Makefile for IIO ADC drivers
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.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_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o
obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o

522
drivers/iio/adc/ad7266.c Normal file
View file

@ -0,0 +1,522 @@
/*
* 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_mv;
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).
*/
struct {
__be16 sample[2];
s64 timestamp;
} data ____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.sample[0], 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.sample[0], 1);
}
static int ad7266_preenable(struct iio_dev *indio_dev)
{
struct ad7266_state *st = iio_priv(indio_dev);
return ad7266_wakeup(st);
}
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.sample, 4);
if (ret == 0) {
iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
pf->timestamp);
}
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.sample[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_mv;
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_mv = st->vref_mv;
if (st->mode == AD7266_MODE_DIFF)
scale_mv *= 2;
if (st->range == AD7266_RANGE_2VREF)
scale_mv *= 2;
*val = scale_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
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 const unsigned long ad7266_available_scan_masks[] = {
0x003,
0x00c,
0x030,
0x0c0,
0x300,
0xc00,
0x000,
};
static const unsigned long ad7266_available_scan_masks_diff[] = {
0x003,
0x00c,
0x030,
0x000,
};
static const unsigned long ad7266_available_scan_masks_fixed[] = {
0x003,
0x000,
};
struct ad7266_chan_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
const 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 = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vref");
if (!IS_ERR_OR_NULL(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = regulator_get_voltage(st->reg);
if (ret < 0)
goto error_disable_reg;
st->vref_mv = ret / 1000;
} else {
/* Use internal reference */
st->vref_mv = 2500;
}
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.sample[0];
st->single_xfer[0].len = 2;
st->single_xfer[0].cs_change = 1;
/* conversion */
st->single_xfer[1].rx_buf = st->data.sample;
st->single_xfer[1].len = 4;
st->single_xfer[1].cs_change = 1;
/* powerdown */
st->single_xfer[2].tx_buf = &st->data.sample[0];
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);
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);
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");

585
drivers/iio/adc/ad7291.c Normal file
View file

@ -0,0 +1,585 @@
/*
* AD7291 8-Channel, I2C, 12-Bit SAR ADC with Temperature Sensor
*
* Copyright 2010-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/platform_data/ad7291.h>
/*
* Simplified handling
*
* If no events enabled - single polled channel read
* If event enabled direct reads disable unless channel
* is in the read mask.
*
* The noise-delayed bit as per datasheet suggestion is always enabled.
*/
/*
* AD7291 registers definition
*/
#define AD7291_COMMAND 0x00
#define AD7291_VOLTAGE 0x01
#define AD7291_T_SENSE 0x02
#define AD7291_T_AVERAGE 0x03
#define AD7291_DATA_HIGH(x) ((x) * 3 + 0x4)
#define AD7291_DATA_LOW(x) ((x) * 3 + 0x5)
#define AD7291_HYST(x) ((x) * 3 + 0x6)
#define AD7291_VOLTAGE_ALERT_STATUS 0x1F
#define AD7291_T_ALERT_STATUS 0x20
#define AD7291_BITS 12
#define AD7291_VOLTAGE_LIMIT_COUNT 8
/*
* AD7291 command
*/
#define AD7291_AUTOCYCLE BIT(0)
#define AD7291_RESET BIT(1)
#define AD7291_ALERT_CLEAR BIT(2)
#define AD7291_ALERT_POLARITY BIT(3)
#define AD7291_EXT_REF BIT(4)
#define AD7291_NOISE_DELAY BIT(5)
#define AD7291_T_SENSE_MASK BIT(7)
#define AD7291_VOLTAGE_MASK GENMASK(15, 8)
#define AD7291_VOLTAGE_OFFSET 8
/*
* AD7291 value masks
*/
#define AD7291_VALUE_MASK GENMASK(11, 0)
/*
* AD7291 alert register bits
*/
#define AD7291_T_LOW BIT(0)
#define AD7291_T_HIGH BIT(1)
#define AD7291_T_AVG_LOW BIT(2)
#define AD7291_T_AVG_HIGH BIT(3)
#define AD7291_V_LOW(x) BIT((x) * 2)
#define AD7291_V_HIGH(x) BIT((x) * 2 + 1)
struct ad7291_chip_info {
struct i2c_client *client;
struct regulator *reg;
u16 command;
u16 c_mask; /* Active voltage channels for events */
struct mutex state_lock;
};
static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data)
{
struct i2c_client *client = chip->client;
int ret = 0;
ret = i2c_smbus_read_word_swapped(client, reg);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
*data = ret;
return 0;
}
static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data)
{
return i2c_smbus_write_word_swapped(chip->client, reg, data);
}
static irqreturn_t ad7291_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad7291_chip_info *chip = iio_priv(private);
u16 t_status, v_status;
u16 command;
int i;
s64 timestamp = iio_get_time_ns();
if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
return IRQ_HANDLED;
if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status))
return IRQ_HANDLED;
if (!(t_status || v_status))
return IRQ_HANDLED;
command = chip->command | AD7291_ALERT_CLEAR;
ad7291_i2c_write(chip, AD7291_COMMAND, command);
command = chip->command & ~AD7291_ALERT_CLEAR;
ad7291_i2c_write(chip, AD7291_COMMAND, command);
/* For now treat t_sense and t_sense_average the same */
if ((t_status & AD7291_T_LOW) || (t_status & AD7291_T_AVG_LOW))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
timestamp);
if ((t_status & AD7291_T_HIGH) || (t_status & AD7291_T_AVG_HIGH))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
if (v_status & AD7291_V_LOW(i))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
timestamp);
if (v_status & AD7291_V_HIGH(i))
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
timestamp);
}
return IRQ_HANDLED;
}
static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
enum iio_event_direction dir,
enum iio_event_info info)
{
unsigned int offset;
switch (chan->type) {
case IIO_VOLTAGE:
offset = chan->channel;
break;
case IIO_TEMP:
offset = AD7291_VOLTAGE_OFFSET;
break;
default:
return 0;
}
switch (info) {
case IIO_EV_INFO_VALUE:
if (dir == IIO_EV_DIR_FALLING)
return AD7291_DATA_HIGH(offset);
else
return AD7291_DATA_LOW(offset);
case IIO_EV_INFO_HYSTERESIS:
return AD7291_HYST(offset);
default:
break;
}
return 0;
}
static int ad7291_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
int ret;
u16 uval;
ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info),
&uval);
if (ret < 0)
return ret;
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE)
*val = uval & AD7291_VALUE_MASK;
else
*val = sign_extend32(uval, 11);
return IIO_VAL_INT;
}
static int ad7291_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) {
if (val > AD7291_VALUE_MASK || val < 0)
return -EINVAL;
} else {
if (val > 2047 || val < -2048)
return -EINVAL;
}
return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info),
val);
}
static int ad7291_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad7291_chip_info *chip = iio_priv(indio_dev);
/*
* To be enabled the channel must simply be on. If any are enabled
* we are in continuous sampling mode
*/
switch (chan->type) {
case IIO_VOLTAGE:
return !!(chip->c_mask & BIT(15 - chan->channel));
case IIO_TEMP:
/* always on */
return 1;
default:
return -EINVAL;
}
}
static int ad7291_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
int ret = 0;
struct ad7291_chip_info *chip = iio_priv(indio_dev);
unsigned int mask;
u16 regval;
mutex_lock(&chip->state_lock);
regval = chip->command;
/*
* To be enabled the channel must simply be on. If any are enabled
* use continuous sampling mode.
* Possible to disable temp as well but that makes single read tricky.
*/
mask = BIT(15 - chan->channel);
switch (chan->type) {
case IIO_VOLTAGE:
if ((!state) && (chip->c_mask & mask))
chip->c_mask &= ~mask;
else if (state && (!(chip->c_mask & mask)))
chip->c_mask |= mask;
else
break;
regval &= ~AD7291_AUTOCYCLE;
regval |= chip->c_mask;
if (chip->c_mask) /* Enable autocycle? */
regval |= AD7291_AUTOCYCLE;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval);
if (ret < 0)
goto error_ret;
chip->command = regval;
break;
default:
ret = -EINVAL;
}
error_ret:
mutex_unlock(&chip->state_lock);
return ret;
}
static int ad7291_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
int ret;
struct ad7291_chip_info *chip = iio_priv(indio_dev);
u16 regval;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&chip->state_lock);
/* If in autocycle mode drop through */
if (chip->command & AD7291_AUTOCYCLE) {
mutex_unlock(&chip->state_lock);
return -EBUSY;
}
/* Enable this channel alone */
regval = chip->command & (~AD7291_VOLTAGE_MASK);
regval |= BIT(15 - chan->channel);
ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
/* Read voltage */
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_VOLTAGE);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
*val = ret & AD7291_VALUE_MASK;
mutex_unlock(&chip->state_lock);
return IIO_VAL_INT;
case IIO_TEMP:
/* Assumes tsense bit of command register always set */
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_T_SENSE);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 11);
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_AVERAGE_RAW:
ret = i2c_smbus_read_word_swapped(chip->client,
AD7291_T_AVERAGE);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
if (chip->reg) {
int vref;
vref = regulator_get_voltage(chip->reg);
if (vref < 0)
return vref;
*val = vref / 1000;
} else {
*val = 2500;
}
*val2 = AD7291_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
/*
* One LSB of the ADC corresponds to 0.25 deg C.
* The temperature reading is in 12-bit twos
* complement format
*/
*val = 250;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_event_spec ad7291_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define AD7291_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = _chan, \
.event_spec = ad7291_events, \
.num_event_specs = ARRAY_SIZE(ad7291_events), \
}
static const struct iio_chan_spec ad7291_channels[] = {
AD7291_VOLTAGE_CHAN(0),
AD7291_VOLTAGE_CHAN(1),
AD7291_VOLTAGE_CHAN(2),
AD7291_VOLTAGE_CHAN(3),
AD7291_VOLTAGE_CHAN(4),
AD7291_VOLTAGE_CHAN(5),
AD7291_VOLTAGE_CHAN(6),
AD7291_VOLTAGE_CHAN(7),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = 0,
.event_spec = ad7291_events,
.num_event_specs = ARRAY_SIZE(ad7291_events),
}
};
static const struct iio_info ad7291_info = {
.read_raw = &ad7291_read_raw,
.read_event_config = &ad7291_read_event_config,
.write_event_config = &ad7291_write_event_config,
.read_event_value = &ad7291_read_event_value,
.write_event_value = &ad7291_write_event_value,
.driver_module = THIS_MODULE,
};
static int ad7291_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ad7291_platform_data *pdata = client->dev.platform_data;
struct ad7291_chip_info *chip;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
chip = iio_priv(indio_dev);
if (pdata && pdata->use_external_ref) {
chip->reg = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(chip->reg))
return PTR_ERR(chip->reg);
ret = regulator_enable(chip->reg);
if (ret)
return ret;
}
mutex_init(&chip->state_lock);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
chip->client = client;
chip->command = AD7291_NOISE_DELAY |
AD7291_T_SENSE_MASK | /* Tsense always enabled */
AD7291_ALERT_POLARITY; /* set irq polarity low level */
if (pdata && pdata->use_external_ref)
chip->command |= AD7291_EXT_REF;
indio_dev->name = id->name;
indio_dev->channels = ad7291_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7291_channels);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ad7291_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = ad7291_i2c_write(chip, AD7291_COMMAND, AD7291_RESET);
if (ret) {
ret = -EIO;
goto error_disable_reg;
}
ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command);
if (ret) {
ret = -EIO;
goto error_disable_reg;
}
if (client->irq > 0) {
ret = request_threaded_irq(client->irq,
NULL,
&ad7291_event_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
id->name,
indio_dev);
if (ret)
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_irq;
return 0;
error_unreg_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
error_disable_reg:
if (chip->reg)
regulator_disable(chip->reg);
return ret;
}
static int ad7291_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (client->irq)
free_irq(client->irq, indio_dev);
if (chip->reg)
regulator_disable(chip->reg);
return 0;
}
static const struct i2c_device_id ad7291_id[] = {
{ "ad7291", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ad7291_id);
static struct i2c_driver ad7291_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = ad7291_probe,
.remove = ad7291_remove,
.id_table = ad7291_id,
};
module_i2c_driver(ad7291_driver);
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7291 ADC driver");
MODULE_LICENSE("GPL v2");

391
drivers/iio/adc/ad7298.c Normal file
View file

@ -0,0 +1,391 @@
/*
* 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/bitops.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 BIT(15) /* write to the control register */
#define AD7298_REPEAT BIT(14) /* repeated conversion enable */
#define AD7298_CH(x) BIT(13 - (x)) /* channel select */
#define AD7298_TSENSE BIT(5) /* temperature conversion enable */
#define AD7298_EXTREF BIT(2) /* external reference enable */
#define AD7298_TAVG BIT(1) /* temperature sensor averaging enable */
#define AD7298_PDD BIT(0) /* partial power down enable */
#define AD7298_MAX_CHAN 8
#define AD7298_INTREF_mV 2500
#define AD7298_CH_TEMP 9
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);
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
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 & GENMASK(chan->scan_type.realbits - 1, 0);
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;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
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 = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
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);
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);
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");

315
drivers/iio/adc/ad7476.c Normal file
View file

@ -0,0 +1,315 @@
/*
* 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/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
struct ad7476_state;
struct ad7476_chip_info {
unsigned int int_vref_uv;
struct iio_chan_spec channel[2];
void (*reset)(struct ad7476_state *);
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
struct 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);
int b_sent;
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
iio_get_time_ns());
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) &
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (!st->chip_info->int_vref_uv) {
scale_uv = regulator_get_voltage(st->reg);
if (scale_uv < 0)
return scale_uv;
} else {
scale_uv = st->chip_info->int_vref_uv;
}
*val = scale_uv / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
#define _AD7476_CHAN(bits, _shift, _info_mask_sep) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.info_mask_separate = _info_mask_sep, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = (_shift), \
.endianness = IIO_BE, \
}, \
}
#define 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 = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
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);
return ret;
}
static int ad7476_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7476_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad7476_id[] = {
{"ad7091r", ID_AD7091R},
{"ad7273", ID_AD7277},
{"ad7274", ID_AD7276},
{"ad7276", ID_AD7276},
{"ad7277", ID_AD7277},
{"ad7278", ID_AD7278},
{"ad7466", ID_AD7466},
{"ad7467", ID_AD7467},
{"ad7468", ID_AD7468},
{"ad7475", ID_AD7466},
{"ad7476", ID_AD7466},
{"ad7476a", ID_AD7466},
{"ad7477", ID_AD7467},
{"ad7477a", ID_AD7467},
{"ad7478", ID_AD7468},
{"ad7478a", ID_AD7468},
{"ad7495", ID_AD7495},
{"ad7910", ID_AD7467},
{"ad7920", ID_AD7466},
{"ad7940", ID_AD7940},
{}
};
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");

453
drivers/iio/adc/ad7791.c Normal file
View file

@ -0,0 +1,453 @@
/*
* 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);
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) {
/*
* The signal is attenuated by a factor of 5 and
* compared against a 1.17V internal reference.
*/
*val = 1170 * 5;
} else {
int voltage_uv;
voltage_uv = regulator_get_voltage(st->reg);
if (voltage_uv < 0)
return voltage_uv;
*val = voltage_uv / 1000;
}
if (unipolar)
*val2 = chan->scan_type.realbits;
else
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
}
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 = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
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);
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);
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");

865
drivers/iio/adc/ad7793.c Normal file
View file

@ -0,0 +1,865 @@
/*
* 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 = devm_iio_device_alloc(&spi->dev, 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 = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
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);
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);
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");

369
drivers/iio/adc/ad7887.c Normal file
View file

@ -0,0 +1,369 @@
/*
* 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/bitops.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 BIT(5) /* on-chip reference disable */
#define AD7887_DUAL BIT(4) /* dual-channel mode */
#define AD7887_CH_AIN1 BIT(3) /* convert on channel 1, DUAL=1 */
#define AD7887_CH_AIN0 0 /* 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,
};
/**
* 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);
/* 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);
int b_sent;
b_sent = spi_sync(st->spi, st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
iio_get_time_ns());
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 &= GENMASK(chan->scan_type.realbits - 1, 0);
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 = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.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 = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.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;
uint8_t mode;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
if (!pdata || !pdata->use_onchip_ref) {
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
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);
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);
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");

371
drivers/iio/adc/ad7923.c Normal file
View file

@ -0,0 +1,371 @@
/*
* 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);
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
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;
const struct ad7923_chip_info *info;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
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 = devm_regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
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);
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);
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");

905
drivers/iio/adc/ad799x.c Normal file
View file

@ -0,0 +1,905 @@
/*
* iio/adc/ad799x.c
* Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc.
*
* based on iio/adc/max1363
* Copyright (C) 2008-2010 Jonathan Cameron
*
* based on linux/drivers/i2c/chips/max123x
* Copyright (C) 2002-2004 Stefan Eletzhofer
*
* based on linux/drivers/acron/char/pcf8583.c
* Copyright (C) 2000 Russell King
*
* 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.
*
* ad799x.c
*
* Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997,
* ad7998 and similar chips.
*
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define AD799X_CHANNEL_SHIFT 4
/*
* AD7991, AD7995 and AD7999 defines
*/
#define AD7991_REF_SEL 0x08
#define AD7991_FLTR 0x04
#define AD7991_BIT_TRIAL_DELAY 0x02
#define AD7991_SAMPLE_DELAY 0x01
/*
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
*/
#define AD7998_FLTR BIT(3)
#define AD7998_ALERT_EN BIT(2)
#define AD7998_BUSY_ALERT BIT(1)
#define AD7998_BUSY_ALERT_POL BIT(0)
#define AD7998_CONV_RES_REG 0x0
#define AD7998_ALERT_STAT_REG 0x1
#define AD7998_CONF_REG 0x2
#define AD7998_CYCLE_TMR_REG 0x3
#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4)
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
#define AD7998_CYC_MASK GENMASK(2, 0)
#define AD7998_CYC_DIS 0x0
#define AD7998_CYC_TCONF_32 0x1
#define AD7998_CYC_TCONF_64 0x2
#define AD7998_CYC_TCONF_128 0x3
#define AD7998_CYC_TCONF_256 0x4
#define AD7998_CYC_TCONF_512 0x5
#define AD7998_CYC_TCONF_1024 0x6
#define AD7998_CYC_TCONF_2048 0x7
#define AD7998_ALERT_STAT_CLEAR 0xFF
/*
* AD7997 and AD7997 defines
*/
#define AD7997_8_READ_SINGLE BIT(7)
#define AD7997_8_READ_SEQUENCE (BIT(6) | BIT(5) | BIT(4))
enum {
ad7991,
ad7995,
ad7999,
ad7992,
ad7993,
ad7994,
ad7997,
ad7998
};
/**
* struct ad799x_chip_config - chip specific information
* @channel: channel specification
* @default_config: device default configuration
* @info: pointer to iio_info struct
*/
struct ad799x_chip_config {
const struct iio_chan_spec channel[9];
u16 default_config;
const struct iio_info *info;
};
/**
* struct ad799x_chip_info - chip specific information
* @num_channels: number of channels
* @noirq_config: device configuration w/o IRQ
* @irq_config: device configuration w/IRQ
*/
struct ad799x_chip_info {
int num_channels;
const struct ad799x_chip_config noirq_config;
const struct ad799x_chip_config irq_config;
};
struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_config *chip_config;
struct regulator *reg;
struct regulator *vref;
unsigned id;
u16 config;
u8 *rx_buf;
unsigned int transfer_size;
};
static int ad799x_write_config(struct ad799x_state *st, u16 val)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
val);
case ad7992:
case ad7993:
case ad7994:
return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
val);
default:
/* Will be written when doing a conversion */
st->config = val;
return 0;
}
}
static int ad799x_read_config(struct ad799x_state *st)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
case ad7992:
case ad7993:
case ad7994:
return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
default:
/* No readback support */
return st->config;
}
}
/**
* ad799x_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 ad799x_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad799x_state *st = iio_priv(indio_dev);
int b_sent;
u8 cmd;
switch (st->id) {
case ad7991:
case ad7995:
case ad7999:
cmd = st->config |
(*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT);
break;
case ad7992:
case ad7993:
case ad7994:
cmd = (*indio_dev->active_scan_mask << AD799X_CHANNEL_SHIFT) |
AD7998_CONV_RES_REG;
break;
case ad7997:
case ad7998:
cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG;
break;
default:
cmd = 0;
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
cmd, st->transfer_size, st->rx_buf);
if (b_sent < 0)
goto out;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns());
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct ad799x_state *st = iio_priv(indio_dev);
kfree(st->rx_buf);
st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (!st->rx_buf)
return -ENOMEM;
st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
switch (st->id) {
case ad7992:
case ad7993:
case ad7994:
case ad7997:
case ad7998:
st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT);
st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT);
return ad799x_write_config(st, st->config);
default:
return 0;
}
}
static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
{
u8 cmd;
switch (st->id) {
case ad7991:
case ad7995:
case ad7999:
cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT);
break;
case ad7992:
case ad7993:
case ad7994:
cmd = BIT(ch) << AD799X_CHANNEL_SHIFT;
break;
case ad7997:
case ad7998:
cmd = (ch << AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE;
break;
default:
return -EINVAL;
}
return i2c_smbus_read_word_swapped(st->client, cmd);
}
static int ad799x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad799x_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 = ad799x_scan_direct(st, chan->scan_index);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(st->vref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const unsigned int ad7998_frequencies[] = {
[AD7998_CYC_DIS] = 0,
[AD7998_CYC_TCONF_32] = 15625,
[AD7998_CYC_TCONF_64] = 7812,
[AD7998_CYC_TCONF_128] = 3906,
[AD7998_CYC_TCONF_512] = 976,
[AD7998_CYC_TCONF_1024] = 488,
[AD7998_CYC_TCONF_2048] = 244,
};
static ssize_t ad799x_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]);
}
static ssize_t ad799x_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 ad799x_state *st = iio_priv(indio_dev);
long val;
int ret, i;
ret = kstrtol(buf, 10, &val);
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret < 0)
goto error_ret_mutex;
/* Wipe the bits clean */
ret &= ~AD7998_CYC_MASK;
for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++)
if (val == ad7998_frequencies[i])
break;
if (i == ARRAY_SIZE(ad7998_frequencies)) {
ret = -EINVAL;
goto error_ret_mutex;
}
ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
ret | i);
if (ret < 0)
goto error_ret_mutex;
ret = len;
error_ret_mutex:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad799x_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct ad799x_state *st = iio_priv(indio_dev);
if (!(st->config & AD7998_ALERT_EN))
return 0;
if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index))
return 1;
return 0;
}
static int ad799x_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto done;
}
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
else
st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT);
if (st->config >> AD799X_CHANNEL_SHIFT)
st->config |= AD7998_ALERT_EN;
else
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
done:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
enum iio_event_direction dir,
enum iio_event_info info)
{
switch (info) {
case IIO_EV_INFO_VALUE:
if (dir == IIO_EV_DIR_FALLING)
return AD7998_DATALOW_REG(chan->channel);
else
return AD7998_DATAHIGH_REG(chan->channel);
case IIO_EV_INFO_HYSTERESIS:
return AD7998_HYST_REG(chan->channel);
default:
return -EINVAL;
}
return 0;
}
static int ad799x_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_write_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info),
val << chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad799x_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
int ret;
struct ad799x_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
ret = i2c_smbus_read_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info));
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1 , 0);
return IIO_VAL_INT;
}
static irqreturn_t ad799x_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad799x_state *st = iio_priv(private);
int i, ret;
ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG);
if (ret <= 0)
goto done;
if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
AD7998_ALERT_STAT_CLEAR) < 0)
goto done;
for (i = 0; i < 8; i++) {
if (ret & BIT(i))
iio_push_event(indio_dev,
i & 0x1 ?
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) :
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
(i >> 1),
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns());
}
done:
return IRQ_HANDLED;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
ad799x_read_frequency,
ad799x_write_frequency);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0");
static struct attribute *ad799x_event_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes,
.name = "events",
};
static const struct iio_info ad7991_info = {
.read_raw = &ad799x_read_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7993_4_7_8_noirq_info = {
.read_raw = &ad799x_read_raw,
.driver_module = THIS_MODULE,
.update_scan_mode = ad799x_update_scan_mode,
};
static const struct iio_info ad7993_4_7_8_irq_info = {
.read_raw = &ad799x_read_raw,
.event_attrs = &ad799x_event_attrs_group,
.read_event_config = &ad799x_read_event_config,
.write_event_config = &ad799x_write_event_config,
.read_event_value = &ad799x_read_event_value,
.write_event_value = &ad799x_write_event_value,
.driver_module = THIS_MODULE,
.update_scan_mode = ad799x_update_scan_mode,
};
static const struct iio_event_spec ad799x_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \
.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), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = (_realbits), \
.storagebits = 16, \
.shift = 12 - (_realbits), \
.endianness = IIO_BE, \
}, \
.event_spec = _ev_spec, \
.num_event_specs = _num_ev_spec, \
}
#define AD799X_CHANNEL(_index, _realbits) \
_AD799X_CHANNEL(_index, _realbits, NULL, 0)
#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \
_AD799X_CHANNEL(_index, _realbits, ad799x_events, \
ARRAY_SIZE(ad799x_events))
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
[ad7991] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7995] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7999] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 8),
AD799X_CHANNEL(1, 8),
AD799X_CHANNEL(2, 8),
AD799X_CHANNEL(3, 8),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7991_info,
},
},
[ad7992] = {
.num_channels = 3,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7993] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10),
AD799X_CHANNEL_WITH_EVENTS(2, 10),
AD799X_CHANNEL_WITH_EVENTS(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7994] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
AD799X_CHANNEL_WITH_EVENTS(2, 12),
AD799X_CHANNEL_WITH_EVENTS(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7997] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
AD799X_CHANNEL(4, 10),
AD799X_CHANNEL(5, 10),
AD799X_CHANNEL(6, 10),
AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10),
AD799X_CHANNEL_WITH_EVENTS(2, 10),
AD799X_CHANNEL_WITH_EVENTS(3, 10),
AD799X_CHANNEL(4, 10),
AD799X_CHANNEL(5, 10),
AD799X_CHANNEL(6, 10),
AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
[ad7998] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
AD799X_CHANNEL(4, 12),
AD799X_CHANNEL(5, 12),
AD799X_CHANNEL(6, 12),
AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12),
AD799X_CHANNEL_WITH_EVENTS(2, 12),
AD799X_CHANNEL_WITH_EVENTS(3, 12),
AD799X_CHANNEL(4, 12),
AD799X_CHANNEL(5, 12),
AD799X_CHANNEL(6, 12),
AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.info = &ad7993_4_7_8_irq_info,
},
},
};
static int ad799x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct ad799x_state *st;
struct iio_dev *indio_dev;
const struct ad799x_chip_info *chip_info =
&ad799x_chip_info_tbl[id->driver_data];
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
st->id = id->driver_data;
if (client->irq > 0 && chip_info->irq_config.info)
st->chip_config = &chip_info->irq_config;
else
st->chip_config = &chip_info->noirq_config;
/* TODO: Add pdata options for filtering and bit delay */
st->reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
st->vref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(st->vref)) {
ret = PTR_ERR(st->vref);
goto error_disable_reg;
}
ret = regulator_enable(st->vref);
if (ret)
goto error_disable_reg;
st->client = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->info = st->chip_config->info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = chip_info->num_channels;
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
goto error_disable_reg;
ret = ad799x_read_config(st);
if (ret < 0)
goto error_disable_reg;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad799x_trigger_handler, NULL);
if (ret)
goto error_disable_vref;
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
ad799x_event_handler,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
client->name,
indio_dev);
if (ret)
goto error_cleanup_ring;
}
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_vref:
regulator_disable(st->vref);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int ad799x_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ad799x_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->vref);
regulator_disable(st->reg);
kfree(st->rx_buf);
return 0;
}
static const struct i2c_device_id ad799x_id[] = {
{ "ad7991", ad7991 },
{ "ad7995", ad7995 },
{ "ad7999", ad7999 },
{ "ad7992", ad7992 },
{ "ad7993", ad7993 },
{ "ad7994", ad7994 },
{ "ad7997", ad7997 },
{ "ad7998", ad7998 },
{}
};
MODULE_DEVICE_TABLE(i2c, ad799x_id);
static struct i2c_driver ad799x_driver = {
.driver = {
.name = "ad799x",
},
.probe = ad799x_probe,
.remove = ad799x_remove,
.id_table = ad799x_id,
};
module_i2c_driver(ad799x_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD799x ADC");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,553 @@
/*
* 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;
reinit_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;
reinit_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);
reinit_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);
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_with_timestamp(indio_dev, data, pf->timestamp);
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 = {
.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);
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 = iio_trigger_get(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");

1439
drivers/iio/adc/at91_adc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,889 @@
/*
* 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/errno.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/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <soc/samsung/exynos-powermode.h>
/* S3C/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)
/* S3C2410 ADC registers definitions */
#define ADC_S3C2410_MUX(x) ((x) + 0x18)
/* 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)
/* Sharing ADC_V3 registers definitions */
#define ADC_V3_DAT(x) ((x) + 0x08)
#define ADC_V3_DAT_SUM(x) ((x) + 0x0C)
#define ADC_V3_DBG_DATA(x) ((x) + 0x1C)
/* 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 S3C2410 ADC */
#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3)
#define ADC_S3C2410_DATX_MASK 0x3FF
#define ADC_S3C2416_CON_RES_SEL (1u << 3)
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
#define ADC_V2_CON1_SOFT_NON_RESET (1u << 1)
#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
/* Bit definitions for ADC_V3 */
#define ADC_V3_DAT_FLAG (1u << 31)
#define MAX_ADC_V3_CHANNELS 8
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
/* Bit definitions common for ADC_V1, ADC_V2, ADC_V3 */
#define ADC_CON_EN_START (1u << 0)
#define ADC_DATX_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
struct clk *sclk;
unsigned int irq;
struct regulator *vdd;
bool needs_adc_phy;
struct completion completion;
u32 value;
unsigned int version;
int idle_ip_index;
};
struct exynos_adc_data {
int num_channels;
bool needs_sclk;
u32 mask;
void (*init_hw)(struct exynos_adc *info);
void (*exit_hw)(struct exynos_adc *info);
void (*clear_irq)(struct exynos_adc *info);
void (*start_conv)(struct exynos_adc *info, unsigned long addr);
irqreturn_t (*adc_isr)(int irq, void *dev_id);
};
static void exynos_adc_unprepare_clk(struct exynos_adc *info)
{
if (info->data->needs_sclk)
clk_unprepare(info->sclk);
clk_unprepare(info->clk);
}
static int exynos_adc_prepare_clk(struct exynos_adc *info)
{
int ret;
ret = clk_prepare(info->clk);
if (ret) {
dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_prepare(info->sclk);
if (ret) {
clk_unprepare(info->clk);
dev_err(info->dev,
"failed preparing sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
}
static void exynos_adc_disable_clk(struct exynos_adc *info)
{
if (info->data->needs_sclk)
clk_disable(info->sclk);
clk_disable(info->clk);
}
static int exynos_adc_enable_clk(struct exynos_adc *info)
{
int ret;
ret = clk_enable(info->clk);
if (ret) {
dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_enable(info->sclk);
if (ret) {
clk_disable(info->clk);
dev_err(info->dev,
"failed enabling sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
}
static int exynos_adc_enable_access(struct exynos_adc *info)
{
int ret;
exynos_update_ip_idle_status(info->idle_ip_index, 0);
if (info->needs_adc_phy)
writel(1, info->enable_reg);
if (info->vdd) {
ret = regulator_enable(info->vdd);
if (ret)
goto err;
}
ret = exynos_adc_prepare_clk(info);
if (ret)
goto err;
ret = exynos_adc_enable_clk(info);
if (ret)
goto err;
return 0;
err:
exynos_update_ip_idle_status(info->idle_ip_index, 1);
return ret;
}
static void exynos_adc_disable_access(struct exynos_adc *info)
{
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
if (info->vdd)
regulator_disable(info->vdd);
if (info->needs_adc_phy)
writel(0, info->enable_reg);
exynos_update_ip_idle_status(info->idle_ip_index, 1);
}
static void exynos_adc_v1_init_hw(struct exynos_adc *info)
{
u32 con1;
/* 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 void exynos_adc_v1_exit_hw(struct exynos_adc *info)
{
u32 con;
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
writel(con, ADC_V1_CON(info->regs));
}
static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V1_INTCLR(info->regs));
}
static void exynos_adc_v1_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
writel(addr, ADC_V1_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static irqreturn_t exynos_adc_v1_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
u32 mask = info->data->mask;
/* Read value */
info->value = readl(ADC_V1_DATX(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
info->data->clear_irq(info);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
/* Enable 12 bit ADC resolution */
con1 = readl(ADC_V1_CON(info->regs));
con1 |= ADC_S3C2416_CON_RES_SEL;
writel(con1, ADC_V1_CON(info->regs));
/* Select channel for S3C2416 */
writel(addr, ADC_S3C2410_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c2416_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c2416_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
/* Select channel for S3C2433 */
writel(addr, ADC_S3C2410_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c2443_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c2443_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
con1 = readl(ADC_V1_CON(info->regs));
con1 &= ~ADC_S3C2410_CON_SELMUX(0x7);
con1 |= ADC_S3C2410_CON_SELMUX(addr);
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static struct exynos_adc_data const exynos_adc_s3c24xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.start_conv = exynos_adc_s3c64xx_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_s3c64xx_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_v2_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
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(6);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
{
u32 con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~(ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(7));
writel(con2, ADC_V2_CON2(info->regs));
/* Disable interrupts */
writel(0, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V2_INT_ST(info->regs));
}
static void exynos_adc_v2_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1, con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_ACH_MASK;
con2 |= ADC_V2_CON2_ACH_SEL(addr);
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));
}
static const struct exynos_adc_data exynos_adc_v2_data = {
.num_channels = MAX_ADC_V2_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static const struct exynos_adc_data exynos3250_adc_data = {
.num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_sclk = true,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v1_isr,
};
static void exynos_adc_v3_init_hw(struct exynos_adc *info)
{
u32 con1, con2;
con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con1 = ADC_V2_CON1_SOFT_NON_RESET;
writel(con1, ADC_V2_CON1(info->regs));
con2 = ADC_V2_CON2_C_TIME(6);
writel(con2, ADC_V2_CON2(info->regs));
/* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs));
}
static void exynos_adc_v3_exit_hw(struct exynos_adc *info)
{
u32 con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_C_TIME(7);
writel(con2, ADC_V2_CON2(info->regs));
/* Disable interrupts */
writel(0, ADC_V2_INT_EN(info->regs));
}
static irqreturn_t exynos_adc_v3_isr(int irq, void *dev_id)
{
struct exynos_adc *info = (struct exynos_adc *)dev_id;
u32 mask = info->data->mask;
/* Read value */
info->value = readl(ADC_V3_DAT(info->regs)) & mask;
/* clear irq */
if (info->data->clear_irq)
info->data->clear_irq(info);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct exynos_adc_data exynos_adc_v3_data = {
.num_channels = MAX_ADC_V3_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.init_hw = exynos_adc_v3_init_hw,
.exit_hw = exynos_adc_v3_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
.adc_isr = exynos_adc_v3_isr,
};
static const struct of_device_id exynos_adc_match[] = {
{
.compatible = "samsung,s3c2410-adc",
.data = &exynos_adc_s3c24xx_data,
}, {
.compatible = "samsung,s3c2416-adc",
.data = &exynos_adc_s3c2416_data,
}, {
.compatible = "samsung,s3c2440-adc",
.data = &exynos_adc_s3c24xx_data,
}, {
.compatible = "samsung,s3c2443-adc",
.data = &exynos_adc_s3c2443_data,
}, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
}, {
.compatible = "samsung,exynos-adc-v2",
.data = &exynos_adc_v2_data,
}, {
.compatible = "samsung,exynos-adc-v3",
.data = &exynos_adc_v3_data,
}, {
.compatible = "samsung,exynos3250-adc",
.data = &exynos3250_adc_data,
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos_adc_match, pdev->dev.of_node);
return (struct exynos_adc_data *)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;
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
ret = exynos_adc_enable_access(info);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
enable_irq(info->irq);
if (info->data->init_hw)
info->data->init_hw(info);
/* Select the channel to be used and Trigger conversion */
if (info->data->start_conv)
info->data->start_conv(info, chan->address);
timeout = wait_for_completion_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT);
if (timeout == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
ret = -ETIMEDOUT;
} else {
*val = info->value;
*val2 = 0;
ret = IIO_VAL_INT;
}
if (info->data->exit_hw)
info->data->exit_hw(info);
disable_irq(info->irq);
exynos_adc_disable_access(info);
mutex_unlock(&indio_dev->mlock);
return ret;
}
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);
int ret;
if (readval == NULL)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
ret = exynos_adc_enable_access(info);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
*readval = readl(info->regs + reg);
exynos_adc_disable_access(info);
mutex_unlock(&indio_dev->mlock);
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 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 = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
info->data = exynos_adc_get_data(pdev);
if (!info->data) {
dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
return -EINVAL;
}
if (of_find_property(np, "samsung,adc-phy-control", NULL))
info->needs_adc_phy = true;
else
info->needs_adc_phy = false;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
if (info->needs_adc_phy) {
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->enable_reg))
return PTR_ERR(info->enable_reg);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return irq;
}
info->irq = irq;
info->dev = &pdev->dev;
info->idle_ip_index = exynos_get_idle_ip_index(dev_name(&pdev->dev));
init_completion(&info->completion);
info->clk = devm_clk_get(&pdev->dev, "gate_adcif");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
return PTR_ERR(info->clk);
}
if (info->data->needs_sclk) {
info->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(info->sclk)) {
dev_err(&pdev->dev,
"failed getting sclk clock, err = %ld\n",
PTR_ERR(info->sclk));
return PTR_ERR(info->sclk);
}
}
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));
info->vdd = NULL;
}
exynos_update_ip_idle_status(info->idle_ip_index, 0);
if (info->vdd) {
ret = regulator_enable(info->vdd);
if (ret)
return ret;
}
ret = exynos_adc_prepare_clk(info);
if (ret)
goto err_disable_reg;
ret = exynos_adc_enable_clk(info);
if (ret)
goto err_unprepare_clk;
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;
indio_dev->num_channels = info->data->num_channels;
ret = devm_request_irq(&pdev->dev, info->irq, info->data->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_disable_clk;
}
disable_irq(info->irq);
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
if (info->vdd)
regulator_disable(info->vdd);
exynos_update_ip_idle_status(info->idle_ip_index, 1);
ret = iio_device_register(indio_dev);
if (ret)
goto err_irq;
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
goto err_of_populate;
}
dev_info(&pdev->dev, "Probed successfully driver.\n");
return 0;
err_of_populate:
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
err_disable_clk:
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_clk(info);
err_unprepare_clk:
exynos_adc_unprepare_clk(info);
err_disable_reg:
if (info->vdd)
regulator_disable(info->vdd);
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);
int ret;
device_for_each_child(&indio_dev->dev, NULL,
exynos_adc_remove_devices);
iio_device_unregister(indio_dev);
ret = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_access(info);
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);
int ret;
ret = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->exit_hw)
info->data->exit_hw(info);
exynos_adc_disable_access(info);
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 = exynos_adc_enable_access(info);
if (ret)
return ret;
if (info->data->init_hw)
info->data->init_hw(info);
exynos_adc_disable_access(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",
.of_match_table = exynos_adc_match,
},
};
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,254 @@
/*
* 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 = devm_iio_device_alloc(&pdev->dev, 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)
return ret;
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);
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);
return 0;
}
static struct platform_driver lp8788_adc_driver = {
.probe = lp8788_adc_probe,
.remove = lp8788_adc_remove,
.driver = {
.name = LP8788_DEV_ADC,
},
};
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");

521
drivers/iio/adc/max1027.c Normal file
View file

@ -0,0 +1,521 @@
/*
* iio/adc/max1027.c
* Copyright (C) 2014 Philippe Reynes
*
* based on linux/drivers/iio/ad7923.c
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
* 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.
*
* max1027.c
*
* Partial support for max1027 and similar chips.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.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>
#define MAX1027_CONV_REG BIT(7)
#define MAX1027_SETUP_REG BIT(6)
#define MAX1027_AVG_REG BIT(5)
#define MAX1027_RST_REG BIT(4)
/* conversion register */
#define MAX1027_TEMP BIT(0)
#define MAX1027_SCAN_0_N (0x00 << 1)
#define MAX1027_SCAN_N_M (0x01 << 1)
#define MAX1027_SCAN_N (0x02 << 1)
#define MAX1027_NOSCAN (0x03 << 1)
#define MAX1027_CHAN(n) ((n) << 3)
/* setup register */
#define MAX1027_UNIPOLAR 0x02
#define MAX1027_BIPOLAR 0x03
#define MAX1027_REF_MODE0 (0x00 << 2)
#define MAX1027_REF_MODE1 (0x01 << 2)
#define MAX1027_REF_MODE2 (0x02 << 2)
#define MAX1027_REF_MODE3 (0x03 << 2)
#define MAX1027_CKS_MODE0 (0x00 << 4)
#define MAX1027_CKS_MODE1 (0x01 << 4)
#define MAX1027_CKS_MODE2 (0x02 << 4)
#define MAX1027_CKS_MODE3 (0x03 << 4)
/* averaging register */
#define MAX1027_NSCAN_4 0x00
#define MAX1027_NSCAN_8 0x01
#define MAX1027_NSCAN_12 0x02
#define MAX1027_NSCAN_16 0x03
#define MAX1027_NAVG_4 (0x00 << 2)
#define MAX1027_NAVG_8 (0x01 << 2)
#define MAX1027_NAVG_16 (0x02 << 2)
#define MAX1027_NAVG_32 (0x03 << 2)
#define MAX1027_AVG_EN BIT(4)
enum max1027_id {
max1027,
max1029,
max1031,
};
static const struct spi_device_id max1027_id[] = {
{"max1027", max1027},
{"max1029", max1029},
{"max1031", max1031},
{}
};
MODULE_DEVICE_TABLE(spi, max1027_id);
#ifdef CONFIG_OF
static const struct of_device_id max1027_adc_dt_ids[] = {
{ .compatible = "maxim,max1027" },
{ .compatible = "maxim,max1029" },
{ .compatible = "maxim,max1031" },
{},
};
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
#endif
#define MAX1027_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), \
.scan_index = index + 1, \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
}, \
}
#define MAX1027_T_CHAN \
{ \
.type = IIO_TEMP, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = 0, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec max1027_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7)
};
static const struct iio_chan_spec max1029_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11)
};
static const struct iio_chan_spec max1031_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11),
MAX1027_V_CHAN(12),
MAX1027_V_CHAN(13),
MAX1027_V_CHAN(14),
MAX1027_V_CHAN(15)
};
static const unsigned long max1027_available_scan_masks[] = {
0x000001ff,
0x00000000,
};
static const unsigned long max1029_available_scan_masks[] = {
0x00001fff,
0x00000000,
};
static const unsigned long max1031_available_scan_masks[] = {
0x0001ffff,
0x00000000,
};
struct max1027_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
const unsigned long *available_scan_masks;
};
static const struct max1027_chip_info max1027_chip_info_tbl[] = {
[max1027] = {
.channels = max1027_channels,
.num_channels = ARRAY_SIZE(max1027_channels),
.available_scan_masks = max1027_available_scan_masks,
},
[max1029] = {
.channels = max1029_channels,
.num_channels = ARRAY_SIZE(max1029_channels),
.available_scan_masks = max1029_available_scan_masks,
},
[max1031] = {
.channels = max1031_channels,
.num_channels = ARRAY_SIZE(max1031_channels),
.available_scan_masks = max1031_available_scan_masks,
},
};
struct max1027_state {
const struct max1027_chip_info *info;
struct spi_device *spi;
struct iio_trigger *trig;
__be16 *buffer;
struct mutex lock;
u8 reg ____cacheline_aligned;
};
static int max1027_read_single_value(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
int ret;
struct max1027_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev)) {
dev_warn(&indio_dev->dev, "trigger mode already enabled");
return -EBUSY;
}
/* Start acquisition on conversion register write */
st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev,
"Failed to configure setup register\n");
return ret;
}
/* Configure conversion register with the requested chan */
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) |
MAX1027_NOSCAN | !!(chan->type == IIO_TEMP);
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev,
"Failed to configure conversion register\n");
return ret;
}
/*
* For an unknown reason, when we use the mode "10" (write
* conversion register), the interrupt doesn't occur every time.
* So we just wait 1 ms.
*/
mdelay(1);
/* Read result */
ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2);
if (ret < 0)
return ret;
*val = be16_to_cpu(st->buffer[0]);
return IIO_VAL_INT;
}
static int max1027_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = 0;
struct max1027_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = max1027_read_single_value(indio_dev, chan, val);
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
*val = 1;
*val2 = 8;
ret = IIO_VAL_FRACTIONAL;
break;
case IIO_VOLTAGE:
*val = 2500;
*val2 = 10;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
ret = -EINVAL;
break;
}
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&st->lock);
return ret;
}
static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct max1027_state *st = iio_priv(indio_dev);
u8 *val = (u8 *)st->buffer;
if (readval != NULL)
return -EINVAL;
*val = (u8)writeval;
return spi_write(st->spi, val, 1);
}
static int max1027_validate_trigger(struct iio_dev *indio_dev,
struct iio_trigger *trig)
{
struct max1027_state *st = iio_priv(indio_dev);
if (st->trig != trig)
return -EINVAL;
return 0;
}
static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct max1027_state *st = iio_priv(indio_dev);
int ret;
if (state) {
/* Start acquisition on cnvst */
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 |
MAX1027_REF_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
/* Scan from 0 to max */
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) |
MAX1027_SCAN_N_M | MAX1027_TEMP;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
} else {
/* Start acquisition on conversion register write */
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 |
MAX1027_REF_MODE2;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0)
return ret;
}
return 0;
}
static int max1027_validate_device(struct iio_trigger *trig,
struct iio_dev *indio_dev)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
if (indio != indio_dev)
return -EINVAL;
return 0;
}
static irqreturn_t max1027_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = (struct iio_poll_func *)private;
struct iio_dev *indio_dev = pf->indio_dev;
struct max1027_state *st = iio_priv(indio_dev);
pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private);
/* fill buffer with all channel */
spi_read(st->spi, st->buffer, indio_dev->masklength * 2);
iio_push_to_buffers(indio_dev, st->buffer);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_trigger_ops max1027_trigger_ops = {
.owner = THIS_MODULE,
.validate_device = &max1027_validate_device,
.set_trigger_state = &max1027_set_trigger_state,
};
static const struct iio_info max1027_info = {
.driver_module = THIS_MODULE,
.read_raw = &max1027_read_raw,
.validate_trigger = &max1027_validate_trigger,
.debugfs_reg_access = &max1027_debugfs_reg_access,
};
static int max1027_probe(struct spi_device *spi)
{
int ret;
struct iio_dev *indio_dev;
struct max1027_state *st;
pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi);
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) {
pr_err("Can't allocate iio device\n");
return -ENOMEM;
}
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->spi = spi;
st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
mutex_init(&st->lock);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &max1027_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->info->channels;
indio_dev->num_channels = st->info->num_channels;
indio_dev->available_scan_masks = st->info->available_scan_masks;
st->buffer = devm_kmalloc(&indio_dev->dev,
indio_dev->num_channels * 2,
GFP_KERNEL);
if (st->buffer == NULL) {
dev_err(&indio_dev->dev, "Can't allocate bufffer\n");
return -ENOMEM;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&max1027_trigger_handler, NULL);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
return ret;
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
indio_dev->name);
if (st->trig == NULL) {
ret = -ENOMEM;
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
goto fail_trigger_alloc;
}
st->trig->ops = &max1027_trigger_ops;
st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
iio_trigger_register(st->trig);
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_FALLING,
spi->dev.driver->name, st->trig);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
goto fail_dev_register;
}
/* Disable averaging */
st->reg = MAX1027_AVG_REG;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to configure averaging register\n");
goto fail_dev_register;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to register iio device\n");
goto fail_dev_register;
}
return 0;
fail_dev_register:
fail_trigger_alloc:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int max1027_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static struct spi_driver max1027_driver = {
.driver = {
.name = "max1027",
.owner = THIS_MODULE,
},
.probe = max1027_probe,
.remove = max1027_remove,
.id_table = max1027_id,
};
module_spi_driver(max1027_driver);
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
MODULE_LICENSE("GPL v2");

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

File diff suppressed because it is too large Load diff

249
drivers/iio/adc/mcp320x.c Normal file
View file

@ -0,0 +1,249 @@
/*
* Copyright (C) 2013 Oskar Andero <oskar.andero@gmail.com>
*
* Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
* Datasheet can be found here:
* http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
*
* 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/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
#define MCP_SINGLE_ENDED (1 << 3)
#define MCP_START_BIT (1 << 4)
enum {
mcp3204,
mcp3208,
};
struct mcp320x {
struct spi_device *spi;
struct spi_message msg;
struct spi_transfer transfer[2];
u8 tx_buf;
u8 rx_buf[2];
struct regulator *reg;
struct mutex lock;
};
static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
{
int ret;
adc->tx_buf = msg;
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
return ((adc->rx_buf[0] & 0x3f) << 6) |
(adc->rx_buf[1] >> 2);
}
static int mcp320x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct mcp320x *adc = iio_priv(indio_dev);
int ret = -EINVAL;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (channel->differential)
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | channel->address);
else
ret = mcp320x_adc_conversion(adc,
MCP_START_BIT | MCP_SINGLE_ENDED |
channel->address);
if (ret < 0)
goto out;
*val = ret;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
/* Digital output code = (4096 * Vin) / Vref */
ret = regulator_get_voltage(adc->reg);
if (ret < 0)
goto out;
*val = ret / 1000;
*val2 = 12;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
break;
}
out:
mutex_unlock(&adc->lock);
return ret;
}
#define MCP320X_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num), \
.address = (num), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
#define MCP320X_VOLTAGE_CHANNEL_DIFF(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num * 2), \
.channel2 = (num * 2 + 1), \
.address = (num * 2), \
.differential = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec mcp3204_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
MCP320X_VOLTAGE_CHANNEL(2),
MCP320X_VOLTAGE_CHANNEL(3),
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
};
static const struct iio_chan_spec mcp3208_channels[] = {
MCP320X_VOLTAGE_CHANNEL(0),
MCP320X_VOLTAGE_CHANNEL(1),
MCP320X_VOLTAGE_CHANNEL(2),
MCP320X_VOLTAGE_CHANNEL(3),
MCP320X_VOLTAGE_CHANNEL(4),
MCP320X_VOLTAGE_CHANNEL(5),
MCP320X_VOLTAGE_CHANNEL(6),
MCP320X_VOLTAGE_CHANNEL(7),
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
MCP320X_VOLTAGE_CHANNEL_DIFF(2),
MCP320X_VOLTAGE_CHANNEL_DIFF(3),
};
static const struct iio_info mcp320x_info = {
.read_raw = mcp320x_read_raw,
.driver_module = THIS_MODULE,
};
struct mcp3208_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
[mcp3204] = {
.channels = mcp3204_channels,
.num_channels = ARRAY_SIZE(mcp3204_channels)
},
[mcp3208] = {
.channels = mcp3208_channels,
.num_channels = ARRAY_SIZE(mcp3208_channels)
},
};
static int mcp320x_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mcp320x *adc;
const struct mcp3208_chip_info *chip_info;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->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 = &mcp320x_info;
chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
adc->transfer[0].tx_buf = &adc->tx_buf;
adc->transfer[0].len = sizeof(adc->tx_buf);
adc->transfer[1].rx_buf = adc->rx_buf;
adc->transfer[1].len = sizeof(adc->rx_buf);
spi_message_init_with_transfers(&adc->msg, adc->transfer,
ARRAY_SIZE(adc->transfer));
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret < 0)
return ret;
mutex_init(&adc->lock);
ret = iio_device_register(indio_dev);
if (ret < 0)
goto reg_disable;
return 0;
reg_disable:
regulator_disable(adc->reg);
return ret;
}
static int mcp320x_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct mcp320x *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
static const struct spi_device_id mcp320x_id[] = {
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
static struct spi_driver mcp320x_driver = {
.driver = {
.name = "mcp320x",
.owner = THIS_MODULE,
},
.probe = mcp320x_probe,
.remove = mcp320x_remove,
.id_table = mcp320x_id,
};
module_spi_driver(mcp320x_driver);
MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
MODULE_LICENSE("GPL v2");

417
drivers/iio/adc/mcp3422.c Normal file
View file

@ -0,0 +1,417 @@
/*
* mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
*
* Copyright (C) 2013, Angelo Compagnucci
* Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
* http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
*
* This driver exports the value of analog input voltage to sysfs, the
* voltage unit is nV.
*
* 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/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* Masks */
#define MCP3422_CHANNEL_MASK 0x60
#define MCP3422_PGA_MASK 0x03
#define MCP3422_SRATE_MASK 0x0C
#define MCP3422_SRATE_240 0x0
#define MCP3422_SRATE_60 0x1
#define MCP3422_SRATE_15 0x2
#define MCP3422_SRATE_3 0x3
#define MCP3422_PGA_1 0
#define MCP3422_PGA_2 1
#define MCP3422_PGA_4 2
#define MCP3422_PGA_8 3
#define MCP3422_CONT_SAMPLING 0x10
#define MCP3422_CHANNEL(config) (((config) & MCP3422_CHANNEL_MASK) >> 5)
#define MCP3422_PGA(config) ((config) & MCP3422_PGA_MASK)
#define MCP3422_SAMPLE_RATE(config) (((config) & MCP3422_SRATE_MASK) >> 2)
#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK)
#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK)
#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK)
#define MCP3422_CHAN(_index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
| BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const int mcp3422_scales[4][4] = {
{ 1000000, 500000, 250000, 125000 },
{ 250000 , 125000, 62500 , 31250 },
{ 62500 , 31250 , 15625 , 7812 },
{ 15625 , 7812 , 3906 , 1953 } };
/* Constant msleep times for data acquisitions */
static const int mcp3422_read_times[4] = {
[MCP3422_SRATE_240] = 1000 / 240,
[MCP3422_SRATE_60] = 1000 / 60,
[MCP3422_SRATE_15] = 1000 / 15,
[MCP3422_SRATE_3] = 1000 / 3 };
/* sample rates to integer conversion table */
static const int mcp3422_sample_rates[4] = {
[MCP3422_SRATE_240] = 240,
[MCP3422_SRATE_60] = 60,
[MCP3422_SRATE_15] = 15,
[MCP3422_SRATE_3] = 3 };
/* sample rates to sign extension table */
static const int mcp3422_sign_extend[4] = {
[MCP3422_SRATE_240] = 11,
[MCP3422_SRATE_60] = 13,
[MCP3422_SRATE_15] = 15,
[MCP3422_SRATE_3] = 17 };
/* Client data (each client gets its own) */
struct mcp3422 {
struct i2c_client *i2c;
u8 id;
u8 config;
u8 pga[4];
struct mutex lock;
};
static int mcp3422_update_config(struct mcp3422 *adc, u8 newconfig)
{
int ret;
mutex_lock(&adc->lock);
ret = i2c_master_send(adc->i2c, &newconfig, 1);
if (ret > 0) {
adc->config = newconfig;
ret = 0;
}
mutex_unlock(&adc->lock);
return ret;
}
static int mcp3422_read(struct mcp3422 *adc, int *value, u8 *config)
{
int ret = 0;
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
u8 buf[4] = {0, 0, 0, 0};
u32 temp;
if (sample_rate == MCP3422_SRATE_3) {
ret = i2c_master_recv(adc->i2c, buf, 4);
temp = buf[0] << 16 | buf[1] << 8 | buf[2];
*config = buf[3];
} else {
ret = i2c_master_recv(adc->i2c, buf, 3);
temp = buf[0] << 8 | buf[1];
*config = buf[2];
}
*value = sign_extend32(temp, mcp3422_sign_extend[sample_rate]);
return ret;
}
static int mcp3422_read_channel(struct mcp3422 *adc,
struct iio_chan_spec const *channel, int *value)
{
int ret;
u8 config;
u8 req_channel = channel->channel;
if (req_channel != MCP3422_CHANNEL(adc->config)) {
config = adc->config;
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_PGA_MASK;
config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
ret = mcp3422_update_config(adc, config);
if (ret < 0)
return ret;
msleep(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
}
return mcp3422_read(adc, value, &config);
}
static int mcp3422_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *val1,
int *val2, long mask)
{
struct mcp3422 *adc = iio_priv(iio);
int err;
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
u8 pga = MCP3422_PGA(adc->config);
switch (mask) {
case IIO_CHAN_INFO_RAW:
err = mcp3422_read_channel(adc, channel, val1);
if (err < 0)
return -EINVAL;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val1 = 0;
*val2 = mcp3422_scales[sample_rate][pga];
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
*val1 = mcp3422_sample_rates[MCP3422_SAMPLE_RATE(adc->config)];
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int mcp3422_write_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int val1,
int val2, long mask)
{
struct mcp3422 *adc = iio_priv(iio);
u8 temp;
u8 config = adc->config;
u8 req_channel = channel->channel;
u8 sample_rate = MCP3422_SAMPLE_RATE(config);
u8 i;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (val1 != 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(mcp3422_scales[0]); i++) {
if (val2 == mcp3422_scales[sample_rate][i]) {
adc->pga[req_channel] = i;
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_PGA_MASK;
config |= MCP3422_PGA_VALUE(adc->pga[req_channel]);
return mcp3422_update_config(adc, config);
}
}
return -EINVAL;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (val1) {
case 240:
temp = MCP3422_SRATE_240;
break;
case 60:
temp = MCP3422_SRATE_60;
break;
case 15:
temp = MCP3422_SRATE_15;
break;
case 3:
if (adc->id > 4)
return -EINVAL;
temp = MCP3422_SRATE_3;
break;
default:
return -EINVAL;
}
config &= ~MCP3422_CHANNEL_MASK;
config |= MCP3422_CHANNEL_VALUE(req_channel);
config &= ~MCP3422_SRATE_MASK;
config |= MCP3422_SAMPLE_RATE_VALUE(temp);
return mcp3422_update_config(adc, config);
default:
break;
}
return -EINVAL;
}
static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static ssize_t mcp3422_show_samp_freqs(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
if (adc->id > 4)
return sprintf(buf, "240 60 15\n");
return sprintf(buf, "240 60 15 3\n");
}
static ssize_t mcp3422_show_scales(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mcp3422 *adc = iio_priv(dev_to_iio_dev(dev));
u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
return sprintf(buf, "0.%09u 0.%09u 0.%09u 0.%09u\n",
mcp3422_scales[sample_rate][0],
mcp3422_scales[sample_rate][1],
mcp3422_scales[sample_rate][2],
mcp3422_scales[sample_rate][3]);
}
static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO,
mcp3422_show_samp_freqs, NULL, 0);
static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
mcp3422_show_scales, NULL, 0);
static struct attribute *mcp3422_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group mcp3422_attribute_group = {
.attrs = mcp3422_attributes,
};
static const struct iio_chan_spec mcp3422_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
};
static const struct iio_chan_spec mcp3424_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
MCP3422_CHAN(2),
MCP3422_CHAN(3),
};
static const struct iio_info mcp3422_info = {
.read_raw = mcp3422_read_raw,
.write_raw = mcp3422_write_raw,
.write_raw_get_fmt = mcp3422_write_raw_get_fmt,
.attrs = &mcp3422_attribute_group,
.driver_module = THIS_MODULE,
};
static int mcp3422_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct mcp3422 *adc;
int err;
u8 config;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->i2c = client;
adc->id = (u8)(id->driver_data);
mutex_init(&adc->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp3422_info;
switch (adc->id) {
case 2:
case 3:
case 6:
case 7:
indio_dev->channels = mcp3422_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3422_channels);
break;
case 4:
case 8:
indio_dev->channels = mcp3424_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3424_channels);
break;
}
/* meaningful default configuration */
config = (MCP3422_CONT_SAMPLING
| MCP3422_CHANNEL_VALUE(1)
| MCP3422_PGA_VALUE(MCP3422_PGA_1)
| MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240));
mcp3422_update_config(adc, config);
err = devm_iio_device_register(&client->dev, indio_dev);
if (err < 0)
return err;
i2c_set_clientdata(client, indio_dev);
return 0;
}
static const struct i2c_device_id mcp3422_id[] = {
{ "mcp3422", 2 },
{ "mcp3423", 3 },
{ "mcp3424", 4 },
{ "mcp3426", 6 },
{ "mcp3427", 7 },
{ "mcp3428", 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3422_id);
#ifdef CONFIG_OF
static const struct of_device_id mcp3422_of_match[] = {
{ .compatible = "mcp3422" },
{ }
};
MODULE_DEVICE_TABLE(of, mcp3422_of_match);
#endif
static struct i2c_driver mcp3422_driver = {
.driver = {
.name = "mcp3422",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(mcp3422_of_match),
},
.probe = mcp3422_probe,
.id_table = mcp3422_id,
};
module_i2c_driver(mcp3422_driver);
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,173 @@
/*
* MEN 16z188 Analog to Digial Converter
*
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
*
* 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 of the License.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mcb.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#define Z188_ADC_MAX_CHAN 8
#define Z188_ADC_GAIN 0x0700000
#define Z188_MODE_VOLTAGE BIT(27)
#define Z188_CFG_AUTO 0x1
#define Z188_CTRL_REG 0x40
#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
#define ADC_OVR(x) ((x) & 0x1)
struct z188_adc {
struct resource *mem;
void __iomem *base;
};
#define Z188_ADC_CHANNEL(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static const struct iio_chan_spec z188_adc_iio_channels[] = {
Z188_ADC_CHANNEL(0),
Z188_ADC_CHANNEL(1),
Z188_ADC_CHANNEL(2),
Z188_ADC_CHANNEL(3),
Z188_ADC_CHANNEL(4),
Z188_ADC_CHANNEL(5),
Z188_ADC_CHANNEL(6),
Z188_ADC_CHANNEL(7),
};
static int z188_iio_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
struct z188_adc *adc = iio_priv(iio_dev);
int ret;
u16 tmp;
switch (info) {
case IIO_CHAN_INFO_RAW:
tmp = readw(adc->base + chan->channel * 4);
if (ADC_OVR(tmp)) {
dev_info(&iio_dev->dev,
"Oversampling error on ADC channel %d\n",
chan->channel);
return -EIO;
}
*val = ADC_DATA(tmp);
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct iio_info z188_adc_info = {
.read_raw = &z188_iio_read_raw,
.driver_module = THIS_MODULE,
};
static void men_z188_config_channels(void __iomem *addr)
{
int i;
u32 cfg;
u32 ctl;
ctl = readl(addr + Z188_CTRL_REG);
ctl |= Z188_CFG_AUTO;
writel(ctl, addr + Z188_CTRL_REG);
for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
cfg = readl(addr + i);
cfg &= ~Z188_ADC_GAIN;
cfg |= Z188_MODE_VOLTAGE;
writel(cfg, addr + i);
}
}
static int men_z188_probe(struct mcb_device *dev,
const struct mcb_device_id *id)
{
struct z188_adc *adc;
struct iio_dev *indio_dev;
struct resource *mem;
indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
indio_dev->name = "z188-adc";
indio_dev->dev.parent = &dev->dev;
indio_dev->info = &z188_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = z188_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
mem = mcb_request_mem(dev, "z188-adc");
if (IS_ERR(mem))
return PTR_ERR(mem);
adc->base = ioremap(mem->start, resource_size(mem));
if (adc->base == NULL)
goto err;
men_z188_config_channels(adc->base);
adc->mem = mem;
mcb_set_drvdata(dev, indio_dev);
return iio_device_register(indio_dev);
err:
mcb_release_mem(mem);
return -ENXIO;
}
static void men_z188_remove(struct mcb_device *dev)
{
struct iio_dev *indio_dev = mcb_get_drvdata(dev);
struct z188_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iounmap(adc->base);
mcb_release_mem(adc->mem);
}
static const struct mcb_device_id men_z188_ids[] = {
{ .device = 0xbc },
{ }
};
MODULE_DEVICE_TABLE(mcb, men_z188_ids);
static struct mcb_driver men_z188_driver = {
.driver = {
.name = "z188-adc",
.owner = THIS_MODULE,
},
.probe = men_z188_probe,
.remove = men_z188_remove,
.id_table = men_z188_ids,
};
module_mcb_driver(men_z188_driver);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
MODULE_ALIAS("mcb:16z188");

582
drivers/iio/adc/nau7802.c Normal file
View file

@ -0,0 +1,582 @@
/*
* Driver for the Nuvoton NAU7802 ADC
*
* Copyright 2013 Free Electrons
*
* Licensed under the GPLv2 or later.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/log2.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define NAU7802_REG_PUCTRL 0x00
#define NAU7802_PUCTRL_RR(x) (x << 0)
#define NAU7802_PUCTRL_RR_BIT NAU7802_PUCTRL_RR(1)
#define NAU7802_PUCTRL_PUD(x) (x << 1)
#define NAU7802_PUCTRL_PUD_BIT NAU7802_PUCTRL_PUD(1)
#define NAU7802_PUCTRL_PUA(x) (x << 2)
#define NAU7802_PUCTRL_PUA_BIT NAU7802_PUCTRL_PUA(1)
#define NAU7802_PUCTRL_PUR(x) (x << 3)
#define NAU7802_PUCTRL_PUR_BIT NAU7802_PUCTRL_PUR(1)
#define NAU7802_PUCTRL_CS(x) (x << 4)
#define NAU7802_PUCTRL_CS_BIT NAU7802_PUCTRL_CS(1)
#define NAU7802_PUCTRL_CR(x) (x << 5)
#define NAU7802_PUCTRL_CR_BIT NAU7802_PUCTRL_CR(1)
#define NAU7802_PUCTRL_AVDDS(x) (x << 7)
#define NAU7802_PUCTRL_AVDDS_BIT NAU7802_PUCTRL_AVDDS(1)
#define NAU7802_REG_CTRL1 0x01
#define NAU7802_CTRL1_VLDO(x) (x << 3)
#define NAU7802_CTRL1_GAINS(x) (x)
#define NAU7802_CTRL1_GAINS_BITS 0x07
#define NAU7802_REG_CTRL2 0x02
#define NAU7802_CTRL2_CHS(x) (x << 7)
#define NAU7802_CTRL2_CRS(x) (x << 4)
#define NAU7802_SAMP_FREQ_320 0x07
#define NAU7802_CTRL2_CHS_BIT NAU7802_CTRL2_CHS(1)
#define NAU7802_REG_ADC_B2 0x12
#define NAU7802_REG_ADC_B1 0x13
#define NAU7802_REG_ADC_B0 0x14
#define NAU7802_REG_ADC_CTRL 0x15
#define NAU7802_MIN_CONVERSIONS 6
struct nau7802_state {
struct i2c_client *client;
s32 last_value;
struct mutex lock;
struct mutex data_lock;
u32 vref_mv;
u32 conversion_count;
u32 min_conversions;
u8 sample_rate;
u32 scale_avail[8];
struct completion value_ok;
};
#define NAU7802_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan), \
.scan_index = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) \
}
static const struct iio_chan_spec nau7802_chan_array[] = {
NAU7802_CHANNEL(0),
NAU7802_CHANNEL(1),
};
static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
10, 10, 10, 320};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
static struct attribute *nau7802_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group nau7802_attribute_group = {
.attrs = nau7802_attributes,
};
static int nau7802_set_gain(struct nau7802_state *st, int gain)
{
int ret;
mutex_lock(&st->lock);
st->conversion_count = 0;
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
if (ret < 0)
goto nau7802_sysfs_set_gain_out;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
(ret & (~NAU7802_CTRL1_GAINS_BITS)) |
gain);
nau7802_sysfs_set_gain_out:
mutex_unlock(&st->lock);
return ret;
}
static int nau7802_read_conversion(struct nau7802_state *st)
{
int data;
mutex_lock(&st->data_lock);
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B2);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value = data << 16;
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B1);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value |= data << 8;
data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B0);
if (data < 0)
goto nau7802_read_conversion_out;
st->last_value |= data;
st->last_value = sign_extend32(st->last_value, 23);
nau7802_read_conversion_out:
mutex_unlock(&st->data_lock);
return data;
}
/*
* Conversions are synchronised on the rising edge of NAU7802_PUCTRL_CS_BIT
*/
static int nau7802_sync(struct nau7802_state *st)
{
int ret;
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
ret | NAU7802_PUCTRL_CS_BIT);
return ret;
}
static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct nau7802_state *st = iio_priv(indio_dev);
int status;
status = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (status < 0)
return IRQ_HANDLED;
if (!(status & NAU7802_PUCTRL_CR_BIT))
return IRQ_NONE;
if (nau7802_read_conversion(st) < 0)
return IRQ_HANDLED;
/*
* Because there is actually only one ADC for both channels, we have to
* wait for enough conversions to happen before getting a significant
* value when changing channels and the values are far apart.
*/
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
complete_all(&st->value_ok);
return IRQ_HANDLED;
}
static int nau7802_read_irq(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
reinit_completion(&st->value_ok);
enable_irq(st->client->irq);
nau7802_sync(st);
/* read registers to ensure we flush everything */
ret = nau7802_read_conversion(st);
if (ret < 0)
goto read_chan_info_failure;
/* Wait for a conversion to finish */
ret = wait_for_completion_interruptible_timeout(&st->value_ok,
msecs_to_jiffies(1000));
if (ret == 0)
ret = -ETIMEDOUT;
if (ret < 0)
goto read_chan_info_failure;
disable_irq(st->client->irq);
*val = st->last_value;
return IIO_VAL_INT;
read_chan_info_failure:
disable_irq(st->client->irq);
return ret;
}
static int nau7802_read_poll(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
nau7802_sync(st);
/* read registers to ensure we flush everything */
ret = nau7802_read_conversion(st);
if (ret < 0)
return ret;
/*
* Because there is actually only one ADC for both channels, we have to
* wait for enough conversions to happen before getting a significant
* value when changing channels and the values are far appart.
*/
do {
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
while (!(ret & NAU7802_PUCTRL_CR_BIT)) {
if (st->sample_rate != NAU7802_SAMP_FREQ_320)
msleep(20);
else
mdelay(4);
ret = i2c_smbus_read_byte_data(st->client,
NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
}
ret = nau7802_read_conversion(st);
if (ret < 0)
return ret;
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
} while (st->conversion_count < NAU7802_MIN_CONVERSIONS);
*val = st->last_value;
return IIO_VAL_INT;
}
static int nau7802_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct nau7802_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
/*
* Select the channel to use
* - Channel 1 is value 0 in the CHS register
* - Channel 2 is value 1 in the CHS register
*/
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL2);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
if (((ret & NAU7802_CTRL2_CHS_BIT) && !chan->channel) ||
(!(ret & NAU7802_CTRL2_CHS_BIT) &&
chan->channel)) {
st->conversion_count = 0;
ret = i2c_smbus_write_byte_data(st->client,
NAU7802_REG_CTRL2,
NAU7802_CTRL2_CHS(chan->channel) |
NAU7802_CTRL2_CRS(st->sample_rate));
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
}
if (st->client->irq)
ret = nau7802_read_irq(indio_dev, chan, val);
else
ret = nau7802_read_poll(indio_dev, chan, val);
mutex_unlock(&st->lock);
return ret;
case IIO_CHAN_INFO_SCALE:
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
if (ret < 0)
return ret;
/*
* We have 24 bits of signed data, that means 23 bits of data
* plus the sign bit
*/
*val = st->vref_mv;
*val2 = 23 + (ret & NAU7802_CTRL1_GAINS_BITS);
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = nau7802_sample_freq_avail[st->sample_rate];
*val2 = 0;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int nau7802_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct nau7802_state *st = iio_priv(indio_dev);
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i])
return nau7802_set_gain(st, i);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0; i < ARRAY_SIZE(nau7802_sample_freq_avail); i++)
if (val == nau7802_sample_freq_avail[i]) {
mutex_lock(&st->lock);
st->sample_rate = i;
st->conversion_count = 0;
ret = i2c_smbus_write_byte_data(st->client,
NAU7802_REG_CTRL2,
NAU7802_CTRL2_CRS(st->sample_rate));
mutex_unlock(&st->lock);
return ret;
}
break;
default:
break;
}
return -EINVAL;
}
static int nau7802_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 nau7802_info = {
.driver_module = THIS_MODULE,
.read_raw = &nau7802_read_raw,
.write_raw = &nau7802_write_raw,
.write_raw_get_fmt = nau7802_write_raw_get_fmt,
.attrs = &nau7802_attribute_group,
};
static int nau7802_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct nau7802_state *st;
struct device_node *np = client->dev.of_node;
int i, ret;
u8 data;
u32 tmp = 0;
if (!client->dev.of_node) {
dev_err(&client->dev, "No device tree node available.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &nau7802_info;
st->client = client;
/* Reset the device */
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
NAU7802_PUCTRL_RR_BIT);
if (ret < 0)
return ret;
/* Enter normal operation mode */
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
NAU7802_PUCTRL_PUD_BIT);
if (ret < 0)
return ret;
/*
* After about 200 usecs, the device should be ready and then
* the Power Up bit will be set to 1. If not, wait for it.
*/
udelay(210);
ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
if (ret < 0)
return ret;
if (!(ret & NAU7802_PUCTRL_PUR_BIT))
return ret;
of_property_read_u32(np, "nuvoton,vldo", &tmp);
st->vref_mv = tmp;
data = NAU7802_PUCTRL_PUD_BIT | NAU7802_PUCTRL_PUA_BIT |
NAU7802_PUCTRL_CS_BIT;
if (tmp >= 2400)
data |= NAU7802_PUCTRL_AVDDS_BIT;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, data);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_ADC_CTRL, 0x30);
if (ret < 0)
return ret;
if (tmp >= 2400) {
data = NAU7802_CTRL1_VLDO((4500 - tmp) / 300);
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
data);
if (ret < 0)
return ret;
}
/* Populate available ADC input ranges */
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
st->scale_avail[i] = (((u64)st->vref_mv) * 1000000000ULL)
>> (23 + i);
init_completion(&st->value_ok);
/*
* The ADC fires continuously and we can't do anything about
* it. So we need to have the IRQ disabled by default, and we
* will enable them back when we will need them..
*/
if (client->irq) {
ret = request_threaded_irq(client->irq,
NULL,
nau7802_eoc_trigger,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
client->dev.driver->name,
indio_dev);
if (ret) {
/*
* What may happen here is that our IRQ controller is
* not able to get level interrupt but this is required
* by this ADC as when going over 40 sample per second,
* the interrupt line may stay high between conversions.
* So, we continue no matter what but we switch to
* polling mode.
*/
dev_info(&client->dev,
"Failed to allocate IRQ, using polling mode\n");
client->irq = 0;
} else
disable_irq(client->irq);
}
if (!client->irq) {
/*
* We are polling, use the fastest sample rate by
* default
*/
st->sample_rate = NAU7802_SAMP_FREQ_320;
ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2,
NAU7802_CTRL2_CRS(st->sample_rate));
if (ret)
goto error_free_irq;
}
/* Setup the ADC channels available on the board */
indio_dev->num_channels = ARRAY_SIZE(nau7802_chan_array);
indio_dev->channels = nau7802_chan_array;
mutex_init(&st->lock);
mutex_init(&st->data_lock);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Couldn't register the device.\n");
goto error_device_register;
}
return 0;
error_device_register:
mutex_destroy(&st->lock);
mutex_destroy(&st->data_lock);
error_free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
return ret;
}
static int nau7802_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct nau7802_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_destroy(&st->lock);
mutex_destroy(&st->data_lock);
if (client->irq)
free_irq(client->irq, indio_dev);
return 0;
}
static const struct i2c_device_id nau7802_i2c_id[] = {
{ "nau7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
static const struct of_device_id nau7802_dt_ids[] = {
{ .compatible = "nuvoton,nau7802" },
{},
};
MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
static struct i2c_driver nau7802_driver = {
.probe = nau7802_probe,
.remove = nau7802_remove,
.id_table = nau7802_i2c_id,
.driver = {
.name = "nau7802",
.of_match_table = nau7802_dt_ids,
},
};
module_i2c_driver(nau7802_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Nuvoton NAU7802 ADC Driver");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");

View file

@ -0,0 +1,316 @@
/*
* Rockchip Successive Approximation Register (SAR) A/D Converter
* Copyright (C) 2014 ROCKCHIP, Inc.
*
* 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.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#define SARADC_DATA 0x00
#define SARADC_DATA_MASK 0x3ff
#define SARADC_STAS 0x04
#define SARADC_STAS_BUSY BIT(0)
#define SARADC_CTRL 0x08
#define SARADC_CTRL_IRQ_STATUS BIT(6)
#define SARADC_CTRL_IRQ_ENABLE BIT(5)
#define SARADC_CTRL_POWER_CTRL BIT(3)
#define SARADC_CTRL_CHN_MASK 0x7
#define SARADC_DLY_PU_SOC 0x0c
#define SARADC_DLY_PU_SOC_MASK 0x3f
#define SARADC_BITS 10
#define SARADC_TIMEOUT msecs_to_jiffies(100)
struct rockchip_saradc {
void __iomem *regs;
struct clk *pclk;
struct clk *clk;
struct completion completion;
struct regulator *vref;
u16 last_val;
};
static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct rockchip_saradc *info = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
/* 8 clock periods as delay between power up and start cmd */
writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
/* Select the channel to be used and trigger conversion */
writel(SARADC_CTRL_POWER_CTRL
| (chan->channel & SARADC_CTRL_CHN_MASK)
| SARADC_CTRL_IRQ_ENABLE,
info->regs + SARADC_CTRL);
if (!wait_for_completion_timeout(&info->completion,
SARADC_TIMEOUT)) {
writel_relaxed(0, info->regs + SARADC_CTRL);
mutex_unlock(&indio_dev->mlock);
return -ETIMEDOUT;
}
*val = info->last_val;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(info->vref);
if (ret < 0) {
dev_err(&indio_dev->dev, "failed to get voltage\n");
return ret;
}
*val = ret / 1000;
*val2 = SARADC_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
{
struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id;
/* Read value */
info->last_val = readl_relaxed(info->regs + SARADC_DATA);
info->last_val &= SARADC_DATA_MASK;
/* Clear irq & power down adc */
writel_relaxed(0, info->regs + SARADC_CTRL);
complete(&info->completion);
return IRQ_HANDLED;
}
static const struct iio_info rockchip_saradc_iio_info = {
.read_raw = rockchip_saradc_read_raw,
.driver_module = THIS_MODULE,
};
#define ADC_CHANNEL(_index, _id) { \
.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), \
.datasheet_name = _id, \
}
static const struct iio_chan_spec rockchip_saradc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
};
static int rockchip_saradc_probe(struct platform_device *pdev)
{
struct rockchip_saradc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
int ret;
int irq;
if (!np)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
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_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
init_completion(&info->completion);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return irq;
}
ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
0, dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
return ret;
}
info->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
if (IS_ERR(info->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
return PTR_ERR(info->pclk);
}
info->clk = devm_clk_get(&pdev->dev, "saradc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get adc clock\n");
return PTR_ERR(info->clk);
}
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref)) {
dev_err(&pdev->dev, "failed to get regulator, %ld\n",
PTR_ERR(info->vref));
return PTR_ERR(info->vref);
}
/*
* Use a default of 1MHz for the converter clock.
* This may become user-configurable in the future.
*/
ret = clk_set_rate(info->clk, 1000000);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
return ret;
}
ret = regulator_enable(info->vref);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable vref regulator\n");
return ret;
}
ret = clk_prepare_enable(info->pclk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable pclk\n");
goto err_reg_voltage;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable converter clock\n");
goto err_pclk;
}
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 = &rockchip_saradc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = rockchip_saradc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels);
ret = iio_device_register(indio_dev);
if (ret)
goto err_clk;
return 0;
err_clk:
clk_disable_unprepare(info->clk);
err_pclk:
clk_disable_unprepare(info->pclk);
err_reg_voltage:
regulator_disable(info->vref);
return ret;
}
static int rockchip_saradc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct rockchip_saradc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
clk_disable_unprepare(info->clk);
clk_disable_unprepare(info->pclk);
regulator_disable(info->vref);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rockchip_saradc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rockchip_saradc *info = iio_priv(indio_dev);
clk_disable_unprepare(info->clk);
clk_disable_unprepare(info->pclk);
regulator_disable(info->vref);
return 0;
}
static int rockchip_saradc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct rockchip_saradc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vref);
if (ret)
return ret;
ret = clk_prepare_enable(info->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(info->clk);
if (ret)
return ret;
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops,
rockchip_saradc_suspend, rockchip_saradc_resume);
static const struct of_device_id rockchip_saradc_match[] = {
{ .compatible = "rockchip,saradc" },
{},
};
MODULE_DEVICE_TABLE(of, rockchip_saradc_match);
static struct platform_driver rockchip_saradc_driver = {
.probe = rockchip_saradc_probe,
.remove = rockchip_saradc_remove,
.driver = {
.name = "rockchip-saradc",
.owner = THIS_MODULE,
.of_match_table = rockchip_saradc_match,
.pm = &rockchip_saradc_pm_ops,
},
};
module_platform_driver(rockchip_saradc_driver);

View file

@ -0,0 +1,154 @@
/*
* 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/of.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 = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
return -ENOMEM;
adc = iio_priv(iio);
adc->i2c = client;
adc->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(adc->ref))
return PTR_ERR(adc->ref);
err = regulator_enable(adc->ref);
if (err < 0)
return err;
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);
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);
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,179 @@
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Driver for Texas Instruments' ADC128S052 ADC chip.
* Datasheet can be found here:
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
*
* 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/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
struct adc128 {
struct spi_device *spi;
struct regulator *reg;
struct mutex lock;
u8 buffer[2] ____cacheline_aligned;
};
static int adc128_adc_conversion(struct adc128 *adc, u8 channel)
{
int ret;
mutex_lock(&adc->lock);
adc->buffer[0] = channel << 3;
adc->buffer[1] = 0;
ret = spi_write(adc->spi, &adc->buffer, 2);
if (ret < 0) {
mutex_unlock(&adc->lock);
return ret;
}
ret = spi_read(adc->spi, &adc->buffer, 2);
mutex_unlock(&adc->lock);
if (ret < 0)
return ret;
return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF);
}
static int adc128_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct adc128 *adc = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = adc128_adc_conversion(adc, channel->channel);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(adc->reg);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define ADC128_VOLTAGE_CHANNEL(num) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (num), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec adc128_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
ADC128_VOLTAGE_CHANNEL(2),
ADC128_VOLTAGE_CHANNEL(3),
ADC128_VOLTAGE_CHANNEL(4),
ADC128_VOLTAGE_CHANNEL(5),
ADC128_VOLTAGE_CHANNEL(6),
ADC128_VOLTAGE_CHANNEL(7),
};
static const struct iio_info adc128_info = {
.read_raw = adc128_read_raw,
.driver_module = THIS_MODULE,
};
static int adc128_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc128 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
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->info = &adc128_info;
indio_dev->channels = adc128_channels;
indio_dev->num_channels = ARRAY_SIZE(adc128_channels);
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
ret = regulator_enable(adc->reg);
if (ret < 0)
return ret;
mutex_init(&adc->lock);
ret = iio_device_register(indio_dev);
return ret;
}
static int adc128_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adc128 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(adc->reg);
return 0;
}
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0},
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.owner = THIS_MODULE,
},
.probe = adc128_probe,
.remove = adc128_remove,
.id_table = adc128_id,
};
module_spi_driver(adc128_driver);
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
MODULE_DESCRIPTION("Texas Instruments ADC128S052");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,558 @@
/*
* 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/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/of.h>
#include <linux/of_device.h>
#include <linux/iio/machine.h>
#include <linux/iio/driver.h>
#include <linux/mfd/ti_am335x_tscadc.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
struct tiadc_device {
struct ti_tscadc_dev *mfd_tscadc;
int channels;
u8 channel_line[8];
u8 channel_step[8];
int buffer_en_ch_steps;
u16 data[8];
};
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 u32 get_adc_step_mask(struct tiadc_device *adc_dev)
{
u32 step_en;
step_en = ((1 << adc_dev->channels) - 1);
step_en <<= TOTAL_STEPS - adc_dev->channels + 1;
return step_en;
}
static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev,
struct iio_chan_spec const *chan)
{
int i;
for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
if (chan->channel == adc_dev->channel_line[i]) {
u32 step;
step = adc_dev->channel_step[i];
/* +1 for the charger */
return 1 << (step + 1);
}
}
WARN_ON(1);
return 0;
}
static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
{
return 1 << adc_dev->channel_step[chan];
}
static void tiadc_step_config(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int stepconfig;
int i, 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;
if (iio_buffer_enabled(indio_dev))
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
| STEPCONFIG_MODE_SWCNT;
else
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
for (i = 0; i < adc_dev->channels; i++) {
int chan;
chan = adc_dev->channel_line[i];
tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
stepconfig | STEPCONFIG_INP(chan));
tiadc_writel(adc_dev, REG_STEPDELAY(steps),
STEPCONFIG_OPENDLY);
adc_dev->channel_step[i] = steps;
steps++;
}
}
static irqreturn_t tiadc_irq_h(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int status, config;
status = tiadc_readl(adc_dev, REG_IRQSTATUS);
/*
* ADC and touchscreen share the IRQ line.
* FIFO0 interrupts are used by TSC. Handle FIFO1 IRQs here only
*/
if (status & IRQENB_FIFO1OVRRUN) {
/* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */
config = tiadc_readl(adc_dev, REG_CTRL);
config &= ~(CNTRLREG_TSCSSENB);
tiadc_writel(adc_dev, REG_CTRL, config);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN
| IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES);
tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB));
return IRQ_HANDLED;
} else if (status & IRQENB_FIFO1THRES) {
/* Disable irq and wake worker thread */
tiadc_writel(adc_dev, REG_IRQCLR, IRQENB_FIFO1THRES);
return IRQ_WAKE_THREAD;
}
return IRQ_NONE;
}
static irqreturn_t tiadc_worker_h(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i, k, fifo1count, read;
u16 *data = adc_dev->data;
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (k = 0; k < fifo1count; k = k + i) {
for (i = 0; i < (indio_dev->scan_bytes)/2; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1);
data[i] = read & FIFOREAD_DATA_MASK;
}
iio_push_to_buffers(indio_dev, (u8 *) data);
}
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES);
tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
return IRQ_HANDLED;
}
static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i, fifo1count, read;
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
IRQENB_FIFO1OVRRUN |
IRQENB_FIFO1UNDRFLW));
/* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++)
read = tiadc_readl(adc_dev, REG_FIFO1);
return 0;
}
static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct iio_buffer *buffer = indio_dev->buffer;
unsigned int enb = 0;
u8 bit;
tiadc_step_config(indio_dev);
for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels)
enb |= (get_adc_step_bit(adc_dev, bit) << 1);
adc_dev->buffer_en_ch_steps = enb;
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb);
tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES
| IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW);
tiadc_writel(adc_dev, REG_IRQENABLE, IRQENB_FIFO1THRES
| IRQENB_FIFO1OVRRUN);
return 0;
}
static int tiadc_buffer_predisable(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int fifo1count, i, read;
tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES |
IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW));
am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps);
adc_dev->buffer_en_ch_steps = 0;
/* Flush FIFO of leftover data in the time it takes to disable adc */
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++)
read = tiadc_readl(adc_dev, REG_FIFO1);
return 0;
}
static int tiadc_buffer_postdisable(struct iio_dev *indio_dev)
{
tiadc_step_config(indio_dev);
return 0;
}
static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = {
.preenable = &tiadc_buffer_preenable,
.postenable = &tiadc_buffer_postenable,
.predisable = &tiadc_buffer_predisable,
.postdisable = &tiadc_buffer_postdisable,
};
static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
irqreturn_t (*pollfunc_bh)(int irq, void *p),
irqreturn_t (*pollfunc_th)(int irq, void *p),
int irq,
unsigned long flags,
const struct iio_buffer_setup_ops *setup_ops)
{
struct iio_buffer *buffer;
int ret;
buffer = iio_kfifo_allocate(indio_dev);
if (!buffer)
return -ENOMEM;
iio_device_attach_buffer(indio_dev, buffer);
ret = request_threaded_irq(irq, pollfunc_th, pollfunc_bh,
flags, indio_dev->name, indio_dev);
if (ret)
goto error_kfifo_free;
indio_dev->setup_ops = setup_ops;
indio_dev->modes |= INDIO_BUFFER_HARDWARE;
ret = iio_buffer_register(indio_dev,
indio_dev->channels,
indio_dev->num_channels);
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(irq, indio_dev);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
}
static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
free_irq(adc_dev->mfd_tscadc->irq, indio_dev);
iio_kfifo_free(indio_dev->buffer);
iio_buffer_unregister(indio_dev);
}
static const char * const chan_name_ain[] = {
"AIN0",
"AIN1",
"AIN2",
"AIN3",
"AIN4",
"AIN5",
"AIN6",
"AIN7",
};
static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct iio_chan_spec *chan_array;
struct iio_chan_spec *chan;
int i;
indio_dev->num_channels = channels;
chan_array = kcalloc(channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (chan_array == NULL)
return -ENOMEM;
chan = chan_array;
for (i = 0; i < channels; i++, chan++) {
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = adc_dev->channel_line[i];
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->datasheet_name = chan_name_ain[chan->channel];
chan->scan_index = i;
chan->scan_type.sign = 'u';
chan->scan_type.realbits = 12;
chan->scan_type.storagebits = 16;
}
indio_dev->channels = chan_array;
return 0;
}
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, map_val;
unsigned int fifo1count, read, stepid;
bool found = false;
u32 step_en;
unsigned long timeout;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
step_en = get_adc_chan_step_mask(adc_dev, chan);
if (!step_en)
return -EINVAL;
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
while (fifo1count--)
tiadc_readl(adc_dev, REG_FIFO1);
am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en);
timeout = jiffies + usecs_to_jiffies
(IDLE_TIMEOUT * adc_dev->channels);
/* Wait for Fifo threshold interrupt */
while (1) {
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
if (fifo1count)
break;
if (time_after(jiffies, timeout)) {
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
return -EAGAIN;
}
}
map_val = adc_dev->channel_step[chan->scan_index];
/*
* We check the complete FIFO. We programmed just one entry but in case
* something went wrong we left empty handed (-EAGAIN previously) and
* then the value apeared somehow in the FIFO we would have two entries.
* Therefore we read every item and keep only the latest version of the
* requested channel.
*/
for (i = 0; i < fifo1count; i++) {
read = tiadc_readl(adc_dev, REG_FIFO1);
stepid = read & FIFOREAD_CHNLID_MASK;
stepid = stepid >> 0x10;
if (stepid == map_val) {
read = read & FIFOREAD_DATA_MASK;
found = true;
*val = (u16) read;
}
}
am335x_tsc_se_adc_done(adc_dev->mfd_tscadc);
if (found == false)
return -EBUSY;
return IIO_VAL_INT;
}
static const struct iio_info tiadc_info = {
.read_raw = &tiadc_read_raw,
.driver_module = THIS_MODULE,
};
static int tiadc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct tiadc_device *adc_dev;
struct device_node *node = pdev->dev.of_node;
struct property *prop;
const __be32 *cur;
int err;
u32 val;
int channels = 0;
if (!node) {
dev_err(&pdev->dev, "Could not find valid DT data.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct tiadc_device));
if (indio_dev == NULL) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
return -ENOMEM;
}
adc_dev = iio_priv(indio_dev);
adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
adc_dev->channel_line[channels] = val;
channels++;
}
adc_dev->channels = 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(indio_dev);
tiadc_writel(adc_dev, REG_FIFO1THR, FIFO1_THRESHOLD);
err = tiadc_channel_init(indio_dev, adc_dev->channels);
if (err < 0)
return err;
err = tiadc_iio_buffered_hardware_setup(indio_dev,
&tiadc_worker_h,
&tiadc_irq_h,
adc_dev->mfd_tscadc->irq,
IRQF_SHARED,
&tiadc_buffer_setup_ops);
if (err)
goto err_free_channels;
err = iio_device_register(indio_dev);
if (err)
goto err_buffer_unregister;
platform_set_drvdata(pdev, indio_dev);
return 0;
err_buffer_unregister:
tiadc_iio_buffered_hardware_remove(indio_dev);
err_free_channels:
tiadc_channels_remove(indio_dev);
return err;
}
static int tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
u32 step_en;
iio_device_unregister(indio_dev);
tiadc_iio_buffered_hardware_remove(indio_dev);
tiadc_channels_remove(indio_dev);
step_en = get_adc_step_mask(adc_dev);
am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
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;
unsigned int idle;
tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
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(indio_dev);
am335x_tsc_se_set_cache(adc_dev->mfd_tscadc,
adc_dev->buffer_en_ch_steps);
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 const struct of_device_id ti_adc_dt_ids[] = {
{ .compatible = "ti,am3359-adc", },
{ }
};
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static struct platform_driver tiadc_driver = {
.driver = {
.name = "TI-am335x-adc",
.pm = TIADC_PM_OPS,
.of_match_table = ti_adc_dt_ids,
},
.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,895 @@
/*
*
* TWL4030 MADC module driver-This driver monitors the real time
* conversion of analog signals like battery temperature,
* battery type, battery level etc.
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* J Keerthy <j-keerthy@ti.com>
*
* Based on twl4030-madc.c
* Copyright (C) 2008 Nokia Corporation
* Mikko Ylinen <mikko.k.ylinen@nokia.com>
*
* Amit Kucheria <amit.kucheria@canonical.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.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/i2c/twl.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
/**
* struct twl4030_madc_data - a container for madc info
* @dev: Pointer to device structure for madc
* @lock: Mutex protecting this data structure
* @requests: Array of request struct corresponding to SW1, SW2 and RT
* @use_second_irq: IRQ selection (main or co-processor)
* @imr: Interrupt mask register of MADC
* @isr: Interrupt status register of MADC
*/
struct twl4030_madc_data {
struct device *dev;
struct mutex lock; /* mutex protecting this data structure */
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
bool use_second_irq;
u8 imr;
u8 isr;
};
static int twl4030_madc_read(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct twl4030_madc_data *madc = iio_priv(iio_dev);
struct twl4030_madc_request req;
int ret;
req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
req.channels = BIT(chan->channel);
req.active = false;
req.func_cb = NULL;
req.type = TWL4030_MADC_WAIT;
req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
*val = req.rbuf[chan->channel];
return IIO_VAL_INT;
}
static const struct iio_info twl4030_madc_iio_info = {
.read_raw = &twl4030_madc_read,
.driver_module = THIS_MODULE,
};
#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
.type = _type, \
.channel = _channel, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
BIT(IIO_CHAN_INFO_PROCESSED), \
.datasheet_name = _name, \
.indexed = 1, \
}
static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
};
static struct twl4030_madc_data *twl4030_madc;
struct twl4030_prescale_divider_ratios {
s16 numerator;
s16 denominator;
};
static const struct twl4030_prescale_divider_ratios
twl4030_divider_ratios[16] = {
{1, 1}, /* CHANNEL 0 No Prescaler */
{1, 1}, /* CHANNEL 1 No Prescaler */
{6, 10}, /* CHANNEL 2 */
{6, 10}, /* CHANNEL 3 */
{6, 10}, /* CHANNEL 4 */
{6, 10}, /* CHANNEL 5 */
{6, 10}, /* CHANNEL 6 */
{6, 10}, /* CHANNEL 7 */
{3, 14}, /* CHANNEL 8 */
{1, 3}, /* CHANNEL 9 */
{1, 1}, /* CHANNEL 10 No Prescaler */
{15, 100}, /* CHANNEL 11 */
{1, 4}, /* CHANNEL 12 */
{1, 1}, /* CHANNEL 13 Reserved channels */
{1, 1}, /* CHANNEL 14 Reseved channels */
{5, 11}, /* CHANNEL 15 */
};
/* Conversion table from -3 to 55 degrees Celcius */
static int twl4030_therm_tbl[] = {
30800, 29500, 28300, 27100,
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
3550
};
/*
* Structure containing the registers
* of different conversion methods supported by MADC.
* Hardware or RT real time conversion request initiated by external host
* processor for RT Signal conversions.
* External host processors can also request for non RT conversions
* SW1 and SW2 software conversions also called asynchronous or GPC request.
*/
static
const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
[TWL4030_MADC_RT] = {
.sel = TWL4030_MADC_RTSELECT_LSB,
.avg = TWL4030_MADC_RTAVERAGE_LSB,
.rbase = TWL4030_MADC_RTCH0_LSB,
},
[TWL4030_MADC_SW1] = {
.sel = TWL4030_MADC_SW1SELECT_LSB,
.avg = TWL4030_MADC_SW1AVERAGE_LSB,
.rbase = TWL4030_MADC_GPCH0_LSB,
.ctrl = TWL4030_MADC_CTRL_SW1,
},
[TWL4030_MADC_SW2] = {
.sel = TWL4030_MADC_SW2SELECT_LSB,
.avg = TWL4030_MADC_SW2AVERAGE_LSB,
.rbase = TWL4030_MADC_GPCH0_LSB,
.ctrl = TWL4030_MADC_CTRL_SW2,
},
};
/**
* twl4030_madc_channel_raw_read() - Function to read a particular channel value
* @madc: pointer to struct twl4030_madc_data
* @reg: lsb of ADC Channel
*
* Return: 0 on success, an error code otherwise.
*/
static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
{
u16 val;
int ret;
/*
* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the address of LSB register
*/
ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
if (ret) {
dev_err(madc->dev, "unable to read register 0x%X\n", reg);
return ret;
}
return (int)(val >> 6);
}
/*
* Return battery temperature in degrees Celsius
* Or < 0 on failure.
*/
static int twl4030battery_temperature(int raw_volt)
{
u8 val;
int temp, curr, volt, res, ret;
volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
/* Getting and calculating the supply current in micro amperes */
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
REG_BCICTL2);
if (ret < 0)
return ret;
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
/* Getting and calculating the thermistor resistance in ohms */
res = volt * 1000 / curr;
/* calculating temperature */
for (temp = 58; temp >= 0; temp--) {
int actual = twl4030_therm_tbl[temp];
if ((actual - res) >= 0)
break;
}
return temp + 1;
}
static int twl4030battery_current(int raw_volt)
{
int ret;
u8 val;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
TWL4030_BCI_BCICTL1);
if (ret)
return ret;
if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
else /* slope of 0.88 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
}
/*
* Function to read channel values
* @madc - pointer to twl4030_madc_data struct
* @reg_base - Base address of the first channel
* @Channels - 16 bit bitmap. If the bit is set, channel's value is read
* @buf - The channel values are stored here. if read fails error
* @raw - Return raw values without conversion
* value is stored
* Returns the number of successfully read channels.
*/
static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
u8 reg_base, unsigned
long channels, int *buf,
bool raw)
{
int count = 0;
int i;
u8 reg;
for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
reg = reg_base + (2 * i);
buf[i] = twl4030_madc_channel_raw_read(madc, reg);
if (buf[i] < 0) {
dev_err(madc->dev, "Unable to read register 0x%X\n",
reg);
return buf[i];
}
if (raw) {
count++;
continue;
}
switch (i) {
case 10:
buf[i] = twl4030battery_current(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading current\n");
return buf[i];
} else {
count++;
buf[i] = buf[i] - 750;
}
break;
case 1:
buf[i] = twl4030battery_temperature(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading temperature\n");
return buf[i];
} else {
buf[i] -= 3;
count++;
}
break;
default:
count++;
/* Analog Input (V) = conv_result * step_size / R
* conv_result = decimal value of 10-bit conversion
* result
* step size = 1.5 / (2 ^ 10 -1)
* R = Prescaler ratio for input channels.
* Result given in mV hence multiplied by 1000.
*/
buf[i] = (buf[i] * 3 * 1000 *
twl4030_divider_ratios[i].denominator)
/ (2 * 1023 *
twl4030_divider_ratios[i].numerator);
}
}
return count;
}
/*
* Enables irq.
* @madc - pointer to twl4030_madc_data struct
* @id - irq number to be enabled
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
* corresponding to RT, SW1, SW2 conversion requests.
* If the i2c read fails it returns an error else returns 0.
*/
static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
return ret;
}
val &= ~(1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
}
/*
* Disables irq.
* @madc - pointer to twl4030_madc_data struct
* @id - irq number to be disabled
* can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
* corresponding to RT, SW1, SW2 conversion requests.
* Returns error if i2c read/write fails.
*/
static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
return ret;
}
val |= (1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
}
static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
{
struct twl4030_madc_data *madc = _madc;
const struct twl4030_madc_conversion_method *method;
u8 isr_val, imr_val;
int i, len, ret;
struct twl4030_madc_request *r;
mutex_lock(&madc->lock);
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
if (ret) {
dev_err(madc->dev, "unable to read isr register 0x%X\n",
madc->isr);
goto err_i2c;
}
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
if (ret) {
dev_err(madc->dev, "unable to read imr register 0x%X\n",
madc->imr);
goto err_i2c;
}
isr_val &= ~imr_val;
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
if (!(isr_val & (1 << i)))
continue;
ret = twl4030_madc_disable_irq(madc, i);
if (ret < 0)
dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
madc->requests[i].result_pending = 1;
}
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
/* No pending results for this method, move to next one */
if (!r->result_pending)
continue;
method = &twl4030_conversion_methods[r->method];
/* Read results */
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */
r->result_pending = 0;
r->active = 0;
}
mutex_unlock(&madc->lock);
return IRQ_HANDLED;
err_i2c:
/*
* In case of error check whichever request is active
* and service the same.
*/
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
if (r->active == 0)
continue;
method = &twl4030_conversion_methods[r->method];
/* Read results */
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Return results to caller */
if (r->func_cb != NULL) {
r->func_cb(len, r->channels, r->rbuf);
r->func_cb = NULL;
}
/* Free request */
r->result_pending = 0;
r->active = 0;
}
mutex_unlock(&madc->lock);
return IRQ_HANDLED;
}
static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
struct twl4030_madc_request *req)
{
struct twl4030_madc_request *p;
int ret;
p = &madc->requests[req->method];
memcpy(p, req, sizeof(*req));
ret = twl4030_madc_enable_irq(madc, req->method);
if (ret < 0) {
dev_err(madc->dev, "enable irq failed!!\n");
return ret;
}
return 0;
}
/*
* Function which enables the madc conversion
* by writing to the control register.
* @madc - pointer to twl4030_madc_data struct
* @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
* corresponding to RT SW1 or SW2 conversion methods.
* Returns 0 if succeeds else a negative error value
*/
static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
int conv_method)
{
const struct twl4030_madc_conversion_method *method;
int ret = 0;
if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
return -ENOTSUPP;
method = &twl4030_conversion_methods[conv_method];
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
method->ctrl);
if (ret) {
dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
method->ctrl);
return ret;
}
return 0;
}
/*
* Function that waits for conversion to be ready
* @madc - pointer to twl4030_madc_data struct
* @timeout_ms - timeout value in milliseconds
* @status_reg - ctrl register
* returns 0 if succeeds else a negative error value
*/
static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
unsigned int timeout_ms,
u8 status_reg)
{
unsigned long timeout;
int ret;
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
u8 reg;
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
if (ret) {
dev_err(madc->dev,
"unable to read status register 0x%X\n",
status_reg);
return ret;
}
if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
return 0;
usleep_range(500, 2000);
} while (!time_after(jiffies, timeout));
dev_err(madc->dev, "conversion timeout!\n");
return -EAGAIN;
}
/*
* An exported function which can be called from other kernel drivers.
* @req twl4030_madc_request structure
* req->rbuf will be filled with read values of channels based on the
* channel index. If a particular channel reading fails there will
* be a negative error value in the corresponding array element.
* returns 0 if succeeds else error value
*/
int twl4030_madc_conversion(struct twl4030_madc_request *req)
{
const struct twl4030_madc_conversion_method *method;
int ret;
if (!req || !twl4030_madc)
return -EINVAL;
mutex_lock(&twl4030_madc->lock);
if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
ret = -EINVAL;
goto out;
}
/* Do we have a conversion request ongoing */
if (twl4030_madc->requests[req->method].active) {
ret = -EBUSY;
goto out;
}
method = &twl4030_conversion_methods[req->method];
/* Select channels to be converted */
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write sel register 0x%X\n", method->sel);
goto out;
}
/* Select averaging for all channels if do_avg is set */
if (req->do_avg) {
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write avg register 0x%X\n",
method->avg);
goto out;
}
}
if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
ret = twl4030_madc_set_irq(twl4030_madc, req);
if (ret < 0)
goto out;
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
ret = 0;
goto out;
}
/* With RT method we should not be here anymore */
if (req->method == TWL4030_MADC_RT) {
ret = -EINVAL;
goto out;
}
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
/* Wait until conversion is ready (ctrl register returns EOC) */
ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
if (ret) {
twl4030_madc->requests[req->method].active = 0;
goto out;
}
ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
req->channels, req->rbuf, req->raw);
twl4030_madc->requests[req->method].active = 0;
out:
mutex_unlock(&twl4030_madc->lock);
return ret;
}
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
int twl4030_get_madc_conversion(int channel_no)
{
struct twl4030_madc_request req;
int temp = 0;
int ret;
req.channels = (1 << channel_no);
req.method = TWL4030_MADC_SW2;
req.active = 0;
req.raw = 0;
req.func_cb = NULL;
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
if (req.rbuf[channel_no] > 0)
temp = req.rbuf[channel_no];
return temp;
}
EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
/**
* twl4030_madc_set_current_generator() - setup bias current
*
* @madc: pointer to twl4030_madc_data struct
* @chan: can be one of the two values:
* TWL4030_BCI_ITHEN
* Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN
* Enables bias current for main battery temperature sensing
* @on: enable or disable chan.
*
* Function to enable or disable bias current for
* main battery type reading or temperature sensing
*/
static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
int chan, int on)
{
int ret;
int regmask;
u8 regval;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
TWL4030_BCI_BCICTL1);
return ret;
}
regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
if (on)
regval |= regmask;
else
regval &= ~regmask;
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
TWL4030_BCI_BCICTL1);
return ret;
}
return 0;
}
/*
* Function that sets MADC software power on bit to enable MADC
* @madc - pointer to twl4030_madc_data struct
* @on - Enable or disable MADC software power on bit.
* returns error if i2c read/write fails else 0
*/
static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
{
u8 regval;
int ret;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_MADC_CTRL1);
if (ret) {
dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
TWL4030_MADC_CTRL1);
return ret;
}
if (on)
regval |= TWL4030_MADC_MADCON;
else
regval &= ~TWL4030_MADC_MADCON;
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
if (ret) {
dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
TWL4030_MADC_CTRL1);
return ret;
}
return 0;
}
/*
* Initialize MADC and request for threaded irq
*/
static int twl4030_madc_probe(struct platform_device *pdev)
{
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int irq, ret;
u8 regval;
struct iio_dev *iio_dev = NULL;
if (!pdata && !np) {
dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
return -EINVAL;
}
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
if (!iio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
madc = iio_priv(iio_dev);
madc->dev = &pdev->dev;
iio_dev->name = dev_name(&pdev->dev);
iio_dev->dev.parent = &pdev->dev;
iio_dev->dev.of_node = pdev->dev.of_node;
iio_dev->info = &twl4030_madc_iio_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = twl4030_madc_iio_channels;
iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
* as modem. Hence two separate ISR and IMR registers.
*/
if (pdata)
madc->use_second_irq = (pdata->irq_line != 1);
else
madc->use_second_irq = of_property_read_bool(np,
"ti,system-uses-second-madc-irq");
madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
TWL4030_MADC_IMR1;
madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
TWL4030_MADC_ISR1;
ret = twl4030_madc_set_power(madc, 1);
if (ret < 0)
return ret;
ret = twl4030_madc_set_current_generator(madc, 0, 1);
if (ret < 0)
goto err_current_generator;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
&regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
TWL4030_BCI_BCICTL1);
goto err_i2c;
}
regval |= TWL4030_BCI_MESBAT;
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
TWL4030_BCI_BCICTL1);
goto err_i2c;
}
/* Check that MADC clock is on */
ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
if (ret) {
dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
TWL4030_REG_GPBR1);
goto err_i2c;
}
/* If MADC clk is not on, turn it on */
if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
dev_info(&pdev->dev, "clk disabled, enabling\n");
regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
TWL4030_REG_GPBR1);
if (ret) {
dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
TWL4030_REG_GPBR1);
goto err_i2c;
}
}
platform_set_drvdata(pdev, iio_dev);
mutex_init(&madc->lock);
irq = platform_get_irq(pdev, 0);
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl4030_madc_threaded_irq_handler,
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
dev_err(&pdev->dev, "could not request irq\n");
goto err_i2c;
}
twl4030_madc = madc;
ret = iio_device_register(iio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio device\n");
goto err_i2c;
}
return 0;
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
twl4030_madc_set_power(madc, 0);
return ret;
}
static int twl4030_madc_remove(struct platform_device *pdev)
{
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
struct twl4030_madc_data *madc = iio_priv(iio_dev);
iio_device_unregister(iio_dev);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id twl_madc_of_match[] = {
{ .compatible = "ti,twl4030-madc", },
{ },
};
MODULE_DEVICE_TABLE(of, twl_madc_of_match);
#endif
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
.remove = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.of_match_table = of_match_ptr(twl_madc_of_match),
},
};
module_platform_driver(twl4030_madc_driver);
MODULE_DESCRIPTION("TWL4030 ADC driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("J Keerthy");
MODULE_ALIAS("platform:twl4030_madc");

File diff suppressed because it is too large Load diff

741
drivers/iio/adc/vf610_adc.c Normal file
View file

@ -0,0 +1,741 @@
/*
* Freescale Vybrid vf610 ADC driver
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* 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/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/driver.h>
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "vf610-adc"
/* Vybrid/IMX ADC registers */
#define VF610_REG_ADC_HC0 0x00
#define VF610_REG_ADC_HC1 0x04
#define VF610_REG_ADC_HS 0x08
#define VF610_REG_ADC_R0 0x0c
#define VF610_REG_ADC_R1 0x10
#define VF610_REG_ADC_CFG 0x14
#define VF610_REG_ADC_GC 0x18
#define VF610_REG_ADC_GS 0x1c
#define VF610_REG_ADC_CV 0x20
#define VF610_REG_ADC_OFS 0x24
#define VF610_REG_ADC_CAL 0x28
#define VF610_REG_ADC_PCTL 0x30
/* Configuration register field define */
#define VF610_ADC_MODE_BIT8 0x00
#define VF610_ADC_MODE_BIT10 0x04
#define VF610_ADC_MODE_BIT12 0x08
#define VF610_ADC_MODE_MASK 0x0c
#define VF610_ADC_BUSCLK2_SEL 0x01
#define VF610_ADC_ALTCLK_SEL 0x02
#define VF610_ADC_ADACK_SEL 0x03
#define VF610_ADC_ADCCLK_MASK 0x03
#define VF610_ADC_CLK_DIV2 0x20
#define VF610_ADC_CLK_DIV4 0x40
#define VF610_ADC_CLK_DIV8 0x60
#define VF610_ADC_CLK_MASK 0x60
#define VF610_ADC_ADLSMP_LONG 0x10
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
#define VF610_ADC_REFSEL_VALT 0x100
#define VF610_ADC_REFSEL_VBG 0x1000
#define VF610_ADC_ADTRG_HARD 0x2000
#define VF610_ADC_AVGS_8 0x4000
#define VF610_ADC_AVGS_16 0x8000
#define VF610_ADC_AVGS_32 0xC000
#define VF610_ADC_AVGS_MASK 0xC000
#define VF610_ADC_OVWREN 0x10000
/* General control register field define */
#define VF610_ADC_ADACKEN 0x1
#define VF610_ADC_DMAEN 0x2
#define VF610_ADC_ACREN 0x4
#define VF610_ADC_ACFGT 0x8
#define VF610_ADC_ACFE 0x10
#define VF610_ADC_AVGEN 0x20
#define VF610_ADC_ADCON 0x40
#define VF610_ADC_CAL 0x80
/* Other field define */
#define VF610_ADC_ADCHC(x) ((x) & 0xF)
#define VF610_ADC_AIEN (0x1 << 7)
#define VF610_ADC_CONV_DISABLE 0x1F
#define VF610_ADC_HS_COCO0 0x1
#define VF610_ADC_CALF 0x2
#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET,
VF610_ADCIOC_ALTCLK_SET,
VF610_ADCIOC_ADACK_SET,
};
enum vol_ref {
VF610_ADCIOC_VR_VREF_SET,
VF610_ADCIOC_VR_VALT_SET,
VF610_ADCIOC_VR_VBG_SET,
};
enum average_sel {
VF610_ADC_SAMPLE_1,
VF610_ADC_SAMPLE_4,
VF610_ADC_SAMPLE_8,
VF610_ADC_SAMPLE_16,
VF610_ADC_SAMPLE_32,
};
struct vf610_adc_feature {
enum clk_sel clk_sel;
enum vol_ref vol_ref;
int clk_div;
int sample_rate;
int res_mode;
bool lpm;
bool calibration;
bool ovwren;
};
struct vf610_adc {
struct device *dev;
void __iomem *regs;
struct clk *clk;
u32 vref_uv;
u32 value;
struct regulator *vref;
struct vf610_adc_feature adc_feature;
u32 sample_freq_avail[5];
struct completion completion;
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
#define VF610_ADC_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.indexed = 1, \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(0, IIO_VOLTAGE),
VF610_ADC_CHAN(1, IIO_VOLTAGE),
VF610_ADC_CHAN(2, IIO_VOLTAGE),
VF610_ADC_CHAN(3, IIO_VOLTAGE),
VF610_ADC_CHAN(4, IIO_VOLTAGE),
VF610_ADC_CHAN(5, IIO_VOLTAGE),
VF610_ADC_CHAN(6, IIO_VOLTAGE),
VF610_ADC_CHAN(7, IIO_VOLTAGE),
VF610_ADC_CHAN(8, IIO_VOLTAGE),
VF610_ADC_CHAN(9, IIO_VOLTAGE),
VF610_ADC_CHAN(10, IIO_VOLTAGE),
VF610_ADC_CHAN(11, IIO_VOLTAGE),
VF610_ADC_CHAN(12, IIO_VOLTAGE),
VF610_ADC_CHAN(13, IIO_VOLTAGE),
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
/* sentinel */
};
static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
int i;
/*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
* which is the same as bus clock.
*
* ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder)
* SFCAdder: fixed to 6 ADCK cycles
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
* LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
*/
adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
}
static inline void vf610_adc_cfg_init(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
/* set default Configuration for ADC controller */
adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET;
adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET;
adc_feature->calibration = true;
adc_feature->ovwren = true;
adc_feature->res_mode = 12;
adc_feature->sample_rate = 1;
adc_feature->lpm = true;
/* Use a save ADCK which is below 20MHz on all devices */
adc_feature->clk_div = 8;
vf610_adc_calculate_rates(info);
}
static void vf610_adc_cfg_post_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
int cfg_data = 0;
int gc_data = 0;
switch (adc_feature->clk_sel) {
case VF610_ADCIOC_ALTCLK_SET:
cfg_data |= VF610_ADC_ALTCLK_SEL;
break;
case VF610_ADCIOC_ADACK_SET:
cfg_data |= VF610_ADC_ADACK_SEL;
break;
default:
break;
}
/* low power set for calibration */
cfg_data |= VF610_ADC_ADLPC_EN;
/* enable high speed for calibration */
cfg_data |= VF610_ADC_ADHSC_EN;
/* voltage reference */
switch (adc_feature->vol_ref) {
case VF610_ADCIOC_VR_VREF_SET:
break;
case VF610_ADCIOC_VR_VALT_SET:
cfg_data |= VF610_ADC_REFSEL_VALT;
break;
case VF610_ADCIOC_VR_VBG_SET:
cfg_data |= VF610_ADC_REFSEL_VBG;
break;
default:
dev_err(info->dev, "error voltage reference\n");
}
/* data overwrite enable */
if (adc_feature->ovwren)
cfg_data |= VF610_ADC_OVWREN;
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
writel(gc_data, info->regs + VF610_REG_ADC_GC);
}
static void vf610_adc_calibration(struct vf610_adc *info)
{
int adc_gc, hc_cfg;
int timeout;
if (!info->adc_feature.calibration)
return;
/* enable calibration interrupt */
hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
adc_gc = readl(info->regs + VF610_REG_ADC_GC);
writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
timeout = wait_for_completion_timeout
(&info->completion, VF610_ADC_TIMEOUT);
if (timeout == 0)
dev_err(info->dev, "Timeout for adc calibration\n");
adc_gc = readl(info->regs + VF610_REG_ADC_GS);
if (adc_gc & VF610_ADC_CALF)
dev_err(info->dev, "ADC calibration failed\n");
info->adc_feature.calibration = false;
}
static void vf610_adc_cfg_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &(info->adc_feature);
int cfg_data;
cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
cfg_data &= ~VF610_ADC_ADLPC_EN;
if (adc_feature->lpm)
cfg_data |= VF610_ADC_ADLPC_EN;
cfg_data &= ~VF610_ADC_ADHSC_EN;
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
}
static void vf610_adc_sample_set(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &(info->adc_feature);
int cfg_data, gc_data;
cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
gc_data = readl(info->regs + VF610_REG_ADC_GC);
/* resolution mode */
cfg_data &= ~VF610_ADC_MODE_MASK;
switch (adc_feature->res_mode) {
case 8:
cfg_data |= VF610_ADC_MODE_BIT8;
break;
case 10:
cfg_data |= VF610_ADC_MODE_BIT10;
break;
case 12:
cfg_data |= VF610_ADC_MODE_BIT12;
break;
default:
dev_err(info->dev, "error resolution mode\n");
break;
}
/* clock select and clock divider */
cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK);
switch (adc_feature->clk_div) {
case 1:
break;
case 2:
cfg_data |= VF610_ADC_CLK_DIV2;
break;
case 4:
cfg_data |= VF610_ADC_CLK_DIV4;
break;
case 8:
cfg_data |= VF610_ADC_CLK_DIV8;
break;
case 16:
switch (adc_feature->clk_sel) {
case VF610_ADCIOC_BUSCLK_SET:
cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8;
break;
default:
dev_err(info->dev, "error clk divider\n");
break;
}
break;
}
/* Use the short sample mode */
cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
/* update hardware average selection */
cfg_data &= ~VF610_ADC_AVGS_MASK;
gc_data &= ~VF610_ADC_AVGEN;
switch (adc_feature->sample_rate) {
case VF610_ADC_SAMPLE_1:
break;
case VF610_ADC_SAMPLE_4:
gc_data |= VF610_ADC_AVGEN;
break;
case VF610_ADC_SAMPLE_8:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_8;
break;
case VF610_ADC_SAMPLE_16:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_16;
break;
case VF610_ADC_SAMPLE_32:
gc_data |= VF610_ADC_AVGEN;
cfg_data |= VF610_ADC_AVGS_32;
break;
default:
dev_err(info->dev,
"error hardware sample average select\n");
}
writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
writel(gc_data, info->regs + VF610_REG_ADC_GC);
}
static void vf610_adc_hw_init(struct vf610_adc *info)
{
/* CFG: Feature set */
vf610_adc_cfg_post_set(info);
vf610_adc_sample_set(info);
/* adc calibration */
vf610_adc_calibration(info);
/* CFG: power and speed set */
vf610_adc_cfg_set(info);
}
static int vf610_adc_read_data(struct vf610_adc *info)
{
int result;
result = readl(info->regs + VF610_REG_ADC_R0);
switch (info->adc_feature.res_mode) {
case 8:
result &= 0xFF;
break;
case 10:
result &= 0x3FF;
break;
case 12:
result &= 0xFFF;
break;
default:
break;
}
return result;
}
static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
{
struct vf610_adc *info = (struct vf610_adc *)dev_id;
int coco;
coco = readl(info->regs + VF610_REG_ADC_HS);
if (coco & VF610_ADC_HS_COCO0) {
info->value = vf610_adc_read_data(info);
complete(&info->completion);
}
return IRQ_HANDLED;
}
static ssize_t vf610_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev));
size_t len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%u ", info->sample_freq_avail[i]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail);
static struct attribute *vf610_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group vf610_attribute_group = {
.attrs = vf610_attributes,
};
static int vf610_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
unsigned int hc_cfg;
long ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
hc_cfg = VF610_ADC_ADCHC(chan->channel);
hc_cfg |= VF610_ADC_AIEN;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
ret = wait_for_completion_interruptible_timeout
(&info->completion, VF610_ADC_TIMEOUT);
if (ret == 0) {
mutex_unlock(&indio_dev->mlock);
return -ETIMEDOUT;
}
if (ret < 0) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
*val = info->value;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = info->vref_uv / 1000;
*val2 = info->adc_feature.res_mode;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = info->sample_freq_avail[info->adc_feature.sample_rate];
*val2 = 0;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int vf610_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct vf610_adc *info = iio_priv(indio_dev);
int i;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0;
i < ARRAY_SIZE(info->sample_freq_avail);
i++)
if (val == info->sample_freq_avail[i]) {
info->adc_feature.sample_rate = i;
vf610_adc_sample_set(info);
return 0;
}
break;
default:
break;
}
return -EINVAL;
}
static int vf610_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct vf610_adc *info = iio_priv(indio_dev);
if ((readval == NULL) ||
(!(reg % 4) || (reg > VF610_REG_ADC_PCTL)))
return -EINVAL;
*readval = readl(info->regs + reg);
return 0;
}
static const struct iio_info vf610_adc_iio_info = {
.driver_module = THIS_MODULE,
.read_raw = &vf610_read_raw,
.write_raw = &vf610_write_raw,
.debugfs_reg_access = &vf610_adc_reg_access,
.attrs = &vf610_attribute_group,
};
static const struct of_device_id vf610_adc_match[] = {
{ .compatible = "fsl,vf610-adc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, vf610_adc_match);
static int vf610_adc_probe(struct platform_device *pdev)
{
struct vf610_adc *info;
struct iio_dev *indio_dev;
struct resource *mem;
int irq;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "Failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "no irq resource?\n");
return -EINVAL;
}
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,
dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
return ret;
}
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);
return ret;
}
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref))
return PTR_ERR(info->vref);
ret = regulator_enable(info->vref);
if (ret)
return ret;
info->vref_uv = regulator_get_voltage(info->vref);
platform_set_drvdata(pdev, indio_dev);
init_completion(&info->completion);
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 = &vf610_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vf610_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev,
"Could not prepare or enable the clock.\n");
goto error_adc_clk_enable;
}
vf610_adc_cfg_init(info);
vf610_adc_hw_init(info);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto error_iio_device_register;
}
return 0;
error_iio_device_register:
clk_disable_unprepare(info->clk);
error_adc_clk_enable:
regulator_disable(info->vref);
return ret;
}
static int vf610_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct vf610_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int vf610_adc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct vf610_adc *info = iio_priv(indio_dev);
int hc_cfg;
/* ADC controller enters to stop mode */
hc_cfg = readl(info->regs + VF610_REG_ADC_HC0);
hc_cfg |= VF610_ADC_CONV_DISABLE;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
clk_disable_unprepare(info->clk);
regulator_disable(info->vref);
return 0;
}
static int vf610_adc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct vf610_adc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vref);
if (ret)
return ret;
ret = clk_prepare_enable(info->clk);
if (ret)
return ret;
vf610_adc_hw_init(info);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops,
vf610_adc_suspend,
vf610_adc_resume);
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
.remove = vf610_adc_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = vf610_adc_match,
.pm = &vf610_adc_pm_ops,
},
};
module_platform_driver(vf610_adc_driver);
MODULE_AUTHOR("Fugang Duan <B38611@freescale.com>");
MODULE_DESCRIPTION("Freescale VF610 ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,157 @@
/*
* 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), \
}
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->channel;
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 = devm_iio_device_alloc(&pdev->dev, 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 = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio (adc)");
return ret;
}
return 0;
}
static struct platform_driver vprbrd_adc_driver = {
.driver = {
.name = "viperboard-adc",
},
.probe = vprbrd_adc_probe,
};
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");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,248 @@
/*
* Xilinx XADC driver
*
* Copyright 2013 Analog Devices Inc.
* Author: Lars-Peter Clauen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include "xilinx-xadc.h"
static const struct iio_chan_spec *xadc_event_to_channel(
struct iio_dev *indio_dev, unsigned int event)
{
switch (event) {
case XADC_THRESHOLD_OT_MAX:
case XADC_THRESHOLD_TEMP_MAX:
return &indio_dev->channels[0];
case XADC_THRESHOLD_VCCINT_MAX:
case XADC_THRESHOLD_VCCAUX_MAX:
return &indio_dev->channels[event];
default:
return &indio_dev->channels[event-1];
}
}
static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
{
const struct iio_chan_spec *chan;
/* Temperature threshold error, we don't handle this yet */
if (event == 0)
return;
chan = xadc_event_to_channel(indio_dev, event);
if (chan->type == IIO_TEMP) {
/*
* The temperature channel only supports over-temperature
* events.
*/
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
iio_get_time_ns());
} else {
/*
* For other channels we don't know whether it is a upper or
* lower threshold event. Userspace will have to check the
* channel value if it wants to know.
*/
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
iio_get_time_ns());
}
}
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
{
unsigned int i;
for_each_set_bit(i, &events, 8)
xadc_handle_event(indio_dev, i);
}
static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan,
enum iio_event_direction dir)
{
unsigned int offset;
if (chan->type == IIO_TEMP) {
offset = XADC_THRESHOLD_OT_MAX;
} else {
if (chan->channel < 2)
offset = chan->channel + 1;
else
offset = chan->channel + 6;
}
if (dir == IIO_EV_DIR_FALLING)
offset += 4;
return offset;
}
static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
{
if (chan->type == IIO_TEMP) {
return XADC_ALARM_OT_MASK;
} else {
switch (chan->channel) {
case 0:
return XADC_ALARM_VCCINT_MASK;
case 1:
return XADC_ALARM_VCCAUX_MASK;
case 2:
return XADC_ALARM_VCCBRAM_MASK;
case 3:
return XADC_ALARM_VCCPINT_MASK;
case 4:
return XADC_ALARM_VCCPAUX_MASK;
case 5:
return XADC_ALARM_VCCODDR_MASK;
default:
/* We will never get here */
return 0;
}
}
}
int xadc_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir)
{
struct xadc *xadc = iio_priv(indio_dev);
return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
}
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
unsigned int alarm = xadc_get_alarm_mask(chan);
struct xadc *xadc = iio_priv(indio_dev);
uint16_t cfg, old_cfg;
int ret;
mutex_lock(&xadc->mutex);
if (state)
xadc->alarm_mask |= alarm;
else
xadc->alarm_mask &= ~alarm;
xadc->ops->update_alarm(xadc, xadc->alarm_mask);
ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
if (ret)
goto err_out;
old_cfg = cfg;
cfg |= XADC_CONF1_ALARM_MASK;
cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
if (old_cfg != cfg)
ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
err_out:
mutex_unlock(&xadc->mutex);
return ret;
}
/* Register value is msb aligned, the lower 4 bits are ignored */
#define XADC_THRESHOLD_VALUE_SHIFT 4
int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2)
{
unsigned int offset = xadc_get_threshold_offset(chan, dir);
struct xadc *xadc = iio_priv(indio_dev);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = xadc->threshold[offset];
break;
case IIO_EV_INFO_HYSTERESIS:
*val = xadc->temp_hysteresis;
break;
default:
return -EINVAL;
}
*val >>= XADC_THRESHOLD_VALUE_SHIFT;
return IIO_VAL_INT;
}
int xadc_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2)
{
unsigned int offset = xadc_get_threshold_offset(chan, dir);
struct xadc *xadc = iio_priv(indio_dev);
int ret = 0;
val <<= XADC_THRESHOLD_VALUE_SHIFT;
if (val < 0 || val > 0xffff)
return -EINVAL;
mutex_lock(&xadc->mutex);
switch (info) {
case IIO_EV_INFO_VALUE:
xadc->threshold[offset] = val;
break;
case IIO_EV_INFO_HYSTERESIS:
xadc->temp_hysteresis = val;
break;
default:
mutex_unlock(&xadc->mutex);
return -EINVAL;
}
if (chan->type == IIO_TEMP) {
/*
* According to the datasheet we need to set the lower 4 bits to
* 0x3, otherwise 125 degree celsius will be used as the
* threshold.
*/
val |= 0x3;
/*
* Since we store the hysteresis as relative (to the threshold)
* value, but the hardware expects an absolute value we need to
* recalcualte this value whenever the hysteresis or the
* threshold changes.
*/
if (xadc->threshold[offset] < xadc->temp_hysteresis)
xadc->threshold[offset + 4] = 0;
else
xadc->threshold[offset + 4] = xadc->threshold[offset] -
xadc->temp_hysteresis;
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
xadc->threshold[offset + 4]);
if (ret)
goto out_unlock;
}
if (info == IIO_EV_INFO_VALUE)
ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
out_unlock:
mutex_unlock(&xadc->mutex);
return ret;
}

View file

@ -0,0 +1,209 @@
/*
* Xilinx XADC driver
*
* Copyright 2013 Analog Devices Inc.
* Author: Lars-Peter Clauen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#ifndef __IIO_XILINX_XADC__
#define __IIO_XILINX_XADC__
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
struct iio_dev;
struct clk;
struct xadc_ops;
struct platform_device;
void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events);
int xadc_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir);
int xadc_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state);
int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2);
int xadc_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2);
enum xadc_external_mux_mode {
XADC_EXTERNAL_MUX_NONE,
XADC_EXTERNAL_MUX_SINGLE,
XADC_EXTERNAL_MUX_DUAL,
};
struct xadc {
void __iomem *base;
struct clk *clk;
const struct xadc_ops *ops;
uint16_t threshold[16];
uint16_t temp_hysteresis;
unsigned int alarm_mask;
uint16_t *data;
struct iio_trigger *trigger;
struct iio_trigger *convst_trigger;
struct iio_trigger *samplerate_trigger;
enum xadc_external_mux_mode external_mux_mode;
unsigned int zynq_alarm;
unsigned int zynq_masked_alarm;
unsigned int zynq_intmask;
struct delayed_work zynq_unmask_work;
struct mutex mutex;
spinlock_t lock;
struct completion completion;
};
struct xadc_ops {
int (*read)(struct xadc *, unsigned int, uint16_t *);
int (*write)(struct xadc *, unsigned int, uint16_t);
int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev,
int irq);
void (*update_alarm)(struct xadc *, unsigned int);
unsigned long (*get_dclk_rate)(struct xadc *);
irqreturn_t (*interrupt_handler)(int, void *);
irqreturn_t (*threaded_interrupt_handler)(int, void *);
unsigned int flags;
};
static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t *val)
{
lockdep_assert_held(&xadc->mutex);
return xadc->ops->read(xadc, reg, val);
}
static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t val)
{
lockdep_assert_held(&xadc->mutex);
return xadc->ops->write(xadc, reg, val);
}
static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t *val)
{
int ret;
mutex_lock(&xadc->mutex);
ret = _xadc_read_adc_reg(xadc, reg, val);
mutex_unlock(&xadc->mutex);
return ret;
}
static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t val)
{
int ret;
mutex_lock(&xadc->mutex);
ret = _xadc_write_adc_reg(xadc, reg, val);
mutex_unlock(&xadc->mutex);
return ret;
}
/* XADC hardmacro register definitions */
#define XADC_REG_TEMP 0x00
#define XADC_REG_VCCINT 0x01
#define XADC_REG_VCCAUX 0x02
#define XADC_REG_VPVN 0x03
#define XADC_REG_VREFP 0x04
#define XADC_REG_VREFN 0x05
#define XADC_REG_VCCBRAM 0x06
#define XADC_REG_VCCPINT 0x0d
#define XADC_REG_VCCPAUX 0x0e
#define XADC_REG_VCCO_DDR 0x0f
#define XADC_REG_VAUX(x) (0x10 + (x))
#define XADC_REG_MAX_TEMP 0x20
#define XADC_REG_MAX_VCCINT 0x21
#define XADC_REG_MAX_VCCAUX 0x22
#define XADC_REG_MAX_VCCBRAM 0x23
#define XADC_REG_MIN_TEMP 0x24
#define XADC_REG_MIN_VCCINT 0x25
#define XADC_REG_MIN_VCCAUX 0x26
#define XADC_REG_MIN_VCCBRAM 0x27
#define XADC_REG_MAX_VCCPINT 0x28
#define XADC_REG_MAX_VCCPAUX 0x29
#define XADC_REG_MAX_VCCO_DDR 0x2a
#define XADC_REG_MIN_VCCPINT 0x2b
#define XADC_REG_MIN_VCCPAUX 0x2c
#define XADC_REG_MIN_VCCO_DDR 0x2d
#define XADC_REG_CONF0 0x40
#define XADC_REG_CONF1 0x41
#define XADC_REG_CONF2 0x42
#define XADC_REG_SEQ(x) (0x48 + (x))
#define XADC_REG_INPUT_MODE(x) (0x4c + (x))
#define XADC_REG_THRESHOLD(x) (0x50 + (x))
#define XADC_REG_FLAG 0x3f
#define XADC_CONF0_EC BIT(9)
#define XADC_CONF0_ACQ BIT(8)
#define XADC_CONF0_MUX BIT(11)
#define XADC_CONF0_CHAN(x) (x)
#define XADC_CONF1_SEQ_MASK (0xf << 12)
#define XADC_CONF1_SEQ_DEFAULT (0 << 12)
#define XADC_CONF1_SEQ_SINGLE_PASS (1 << 12)
#define XADC_CONF1_SEQ_CONTINUOUS (2 << 12)
#define XADC_CONF1_SEQ_SINGLE_CHANNEL (3 << 12)
#define XADC_CONF1_SEQ_SIMULTANEOUS (4 << 12)
#define XADC_CONF1_SEQ_INDEPENDENT (8 << 12)
#define XADC_CONF1_ALARM_MASK 0x0f0f
#define XADC_CONF2_DIV_MASK 0xff00
#define XADC_CONF2_DIV_OFFSET 8
#define XADC_CONF2_PD_MASK (0x3 << 4)
#define XADC_CONF2_PD_NONE (0x0 << 4)
#define XADC_CONF2_PD_ADC_B (0x2 << 4)
#define XADC_CONF2_PD_BOTH (0x3 << 4)
#define XADC_ALARM_TEMP_MASK BIT(0)
#define XADC_ALARM_VCCINT_MASK BIT(1)
#define XADC_ALARM_VCCAUX_MASK BIT(2)
#define XADC_ALARM_OT_MASK BIT(3)
#define XADC_ALARM_VCCBRAM_MASK BIT(4)
#define XADC_ALARM_VCCPINT_MASK BIT(5)
#define XADC_ALARM_VCCPAUX_MASK BIT(6)
#define XADC_ALARM_VCCODDR_MASK BIT(7)
#define XADC_THRESHOLD_TEMP_MAX 0x0
#define XADC_THRESHOLD_VCCINT_MAX 0x1
#define XADC_THRESHOLD_VCCAUX_MAX 0x2
#define XADC_THRESHOLD_OT_MAX 0x3
#define XADC_THRESHOLD_TEMP_MIN 0x4
#define XADC_THRESHOLD_VCCINT_MIN 0x5
#define XADC_THRESHOLD_VCCAUX_MIN 0x6
#define XADC_THRESHOLD_OT_MIN 0x7
#define XADC_THRESHOLD_VCCBRAM_MAX 0x8
#define XADC_THRESHOLD_VCCPINT_MAX 0x9
#define XADC_THRESHOLD_VCCPAUX_MAX 0xa
#define XADC_THRESHOLD_VCCODDR_MAX 0xb
#define XADC_THRESHOLD_VCCBRAM_MIN 0xc
#define XADC_THRESHOLD_VCCPINT_MIN 0xd
#define XADC_THRESHOLD_VCCPAUX_MIN 0xe
#define XADC_THRESHOLD_VCCODDR_MIN 0xf
#endif