1
0
Fork 0

IIO new drivers, features and rework for the 3.7 cycle, 4th set.

Here we have
 
 1) a set cleaning up and moving the ad7476 driver out of staging.
 Support for a number of additional parts is also added to that driver.
 
 2) cleanups from various people for the in kernel interface code as that
 is getting more an more real use and hence people are picking up on
 minor issues that made it through review.  Also a related useful set
 of utility functions to avoid duplicate code for converting IIO
 representations to other forms.
 
 3) a new fractional type for our read_raw / write_raw functions.
   This allows avoiding loss of accuracy via the in kernel interfaces in some
   cases as well as being rather convenient for a lot of range -> scale
   conversions.
 
 4) New AD5755 DAC driver.
 
 5) Some Blackfin timer trigger improvements including hardware pulse control
 for device triggering.
 
 6) Support for the ad7091r in the ad7476 driver.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJQV5WKAAoJEFSFNJnE9BaIbksQAIcpGldo+clgHtLyNYdY0dsz
 CO3Ypj9CExWGLeSnUgFUf1RrevCFSaOCblxscV9S0Ms5vVCrlvg8SLX8Nm+DHS9e
 zROJMzo7mjfvoplOzuN2jXGn/T1SPPcsMBnpzJeeILVJm2G/LkUbIUU2KbCd8nBI
 xO6cehKGwg6kBz+Az8ZJXOamfr7S2THIMVDucAKNjF4Cg3lLfmKKgDqEXT2oR6xc
 yzaOnu3ObJuHi0GF6hcRFn5Q4J5MN/Lnw7M2BRQd6SazR4uLRI+17Hq7pDnXvMgJ
 QYCUUJx2uCg+5bmfYeLfgcFXUMGg6wF5Q7UO/94IiI/r5PKiNHwKwFrYMM30cZcs
 A/aRZm/YndnwpL2NUahqi/14Hoj0DnwsVSmCF2IGIzy7687xpuL4FZVuTuYc9uvX
 xlfc52stQ14xgtcsO5hpAMnTtqNiFHJHD9cCrzszGRQvqXOxMolgMOokEM02XRK9
 AUGdZjeSpE6rc6FFFgdkmElpRFLHBpiKjmq82zuMMz3kbpkQWmw5IrJNXBH65KRM
 sJUSHXZ/sXBRooDgGJej+Kg1DJzKQFxD3jB21wt0Zic3HvE73zHP0grtR5z5TnH6
 ABeMTDNkK04yGlPggJUtiT/ocdtlcvT4HzH1nKIHxLNOgYfVJabmfP1barArOc5W
 P3rBUFAbfQDTsL3aqkfu
 =BlMh
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-v3.7d' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

IIO new drivers, features and rework for the 3.7 cycle, 4th set.

Here we have

1) a set cleaning up and moving the ad7476 driver out of staging.
Support for a number of additional parts is also added to that driver.

2) cleanups from various people for the in kernel interface code as that
is getting more an more real use and hence people are picking up on
minor issues that made it through review.  Also a related useful set
of utility functions to avoid duplicate code for converting IIO
representations to other forms.

3) a new fractional type for our read_raw / write_raw functions.
  This allows avoiding loss of accuracy via the in kernel interfaces in some
  cases as well as being rather convenient for a lot of range -> scale
  conversions.

4) New AD5755 DAC driver.

5) Some Blackfin timer trigger improvements including hardware pulse control
for device triggering.

6) Support for the ad7091r in the ad7476 driver.
hifive-unleashed-5.1
Greg Kroah-Hartman 2012-09-17 14:42:54 -07:00
commit 8508317c96
20 changed files with 1238 additions and 278 deletions

View File

@ -30,6 +30,21 @@ config AD7791
To compile this driver as a module, choose M here: the module will be
called ad7791.
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 AT91_ADC
tristate "Atmel AT91 ADC"
depends on ARCH_AT91

View File

@ -4,5 +4,6 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o

View File

@ -18,8 +18,76 @@
#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 "ad7476.h"
#define RES_MASK(bits) ((1 << (bits)) - 1)
struct ad7476_state;
struct ad7476_chip_info {
unsigned int int_vref_uv;
struct iio_chan_spec channel[2];
void (*reset)(struct ad7476_state *);
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
struct spi_transfer xfer;
struct spi_message msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* Make the buffer large enough for one 16 bit sample and one 64 bit
* aligned 64 bit timestamp.
*/
unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)]
____cacheline_aligned;
};
enum ad7476_supported_device_ids {
ID_AD7091R,
ID_AD7276,
ID_AD7277,
ID_AD7278,
ID_AD7466,
ID_AD7467,
ID_AD7468,
ID_AD7495,
ID_AD7940,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7476_state *st = iio_priv(indio_dev);
s64 time_ns;
int b_sent;
b_sent = spi_sync(st->spi, &st->msg);
if (b_sent < 0)
goto done;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
iio_push_to_buffer(indio_dev->buffer, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static void ad7091_reset(struct ad7476_state *st)
{
/* Any transfers with 8 scl cycles will reset the device */
spi_read(st->spi, st->data, 1);
}
static int ad7476_scan_direct(struct ad7476_state *st)
{
@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st)
if (ret)
return ret;
return (st->data[0] << 8) | st->data[1];
return be16_to_cpup((__be16 *)st->data);
}
static int ad7476_read_raw(struct iio_dev *indio_dev,
@ -40,7 +108,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
{
int ret;
struct ad7476_state *st = iio_priv(indio_dev);
unsigned int scale_uv;
int scale_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
@ -57,30 +125,60 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
RES_MASK(st->chip_info->channel[0].scan_type.realbits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = (st->int_vref_mv * 1000)
>> st->chip_info->channel[0].scan_type.realbits;
*val = scale_uv/1000;
*val2 = (scale_uv%1000)*1000;
if (!st->chip_info->int_vref_uv) {
scale_uv = regulator_get_voltage(st->reg);
if (scale_uv < 0)
return scale_uv;
} else {
scale_uv = st->chip_info->int_vref_uv;
}
scale_uv >>= chan->scan_type.realbits;
*val = scale_uv / 1000;
*val2 = (scale_uv % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
#define AD7476_CHAN(bits) \
#define _AD7476_CHAN(bits, _shift, _info_mask) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
.info_mask = _info_mask | \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.scan_type = { \
.sign = 'u', \
.realbits = bits, \
.realbits = (bits), \
.storagebits = 16, \
.shift = 12 - bits, \
.shift = (_shift), \
.endianness = IIO_BE, \
}, \
}
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#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),
@ -93,26 +191,14 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7475] = {
.channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7476] = {
.channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7477] = {
.channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7478] = {
.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_mv = 2500,
.int_vref_uv = 2500000,
},
[ID_AD7940] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
};
@ -123,10 +209,9 @@ static const struct iio_info ad7476_info = {
static int __devinit ad7476_probe(struct spi_device *spi)
{
struct ad7476_platform_data *pdata = spi->dev.platform_data;
struct ad7476_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi)
goto error_ret;
}
st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
voltage_uv = regulator_get_voltage(st->reg);
}
st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (st->chip_info->int_vref_mv)
st->int_vref_mv = st->chip_info->int_vref_mv;
else if (pdata && pdata->vref_mv)
st->int_vref_mv = pdata->vref_mv;
else if (voltage_uv)
st->int_vref_mv = voltage_uv / 1000;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
st->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free_dev;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
spi_set_drvdata(spi, indio_dev);
@ -173,23 +251,26 @@ static int __devinit ad7476_probe(struct spi_device *spi)
spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &st->msg);
ret = ad7476_register_ring_funcs_and_init(indio_dev);
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:
ad7476_ring_cleanup(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
regulator_disable(st->reg);
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
regulator_put(st->reg);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -202,28 +283,35 @@ static int __devexit ad7476_remove(struct spi_device *spi)
struct ad7476_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad7476_ring_cleanup(indio_dev);
if (!IS_ERR(st->reg)) {
regulator_disable(st->reg);
regulator_put(st->reg);
}
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
regulator_put(st->reg);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7476_id[] = {
{"ad7091r", ID_AD7091R},
{"ad7273", ID_AD7277},
{"ad7274", ID_AD7276},
{"ad7276", ID_AD7276},
{"ad7277", ID_AD7277},
{"ad7278", ID_AD7278},
{"ad7466", ID_AD7466},
{"ad7467", ID_AD7467},
{"ad7468", ID_AD7468},
{"ad7475", ID_AD7475},
{"ad7476", ID_AD7476},
{"ad7476a", ID_AD7476},
{"ad7477", ID_AD7477},
{"ad7477a", ID_AD7477},
{"ad7478", ID_AD7478},
{"ad7478a", ID_AD7478},
{"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);
@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = {
module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC");
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2");

View File

@ -77,6 +77,17 @@ config AD5504
To compile this driver as a module, choose M here: the
module will be called ad5504.
config AD5755
tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5755, AD5755-1,
AD5757, AD5735, AD5737 quad channel Digital to
Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5755.
config AD5764
tristate "Analog Devices AD5764/64R/44/44R DAC driver"
depends on SPI_MASTER

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o

View File

@ -0,0 +1,650 @@
/*
* AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver
*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/ad5755.h>
#define AD5755_NUM_CHANNELS 4
#define AD5755_ADDR(x) ((x) << 16)
#define AD5755_WRITE_REG_DATA(chan) (chan)
#define AD5755_WRITE_REG_GAIN(chan) (0x08 | (chan))
#define AD5755_WRITE_REG_OFFSET(chan) (0x10 | (chan))
#define AD5755_WRITE_REG_CTRL(chan) (0x1c | (chan))
#define AD5755_READ_REG_DATA(chan) (chan)
#define AD5755_READ_REG_CTRL(chan) (0x4 | (chan))
#define AD5755_READ_REG_GAIN(chan) (0x8 | (chan))
#define AD5755_READ_REG_OFFSET(chan) (0xc | (chan))
#define AD5755_READ_REG_CLEAR(chan) (0x10 | (chan))
#define AD5755_READ_REG_SLEW(chan) (0x14 | (chan))
#define AD5755_READ_REG_STATUS 0x18
#define AD5755_READ_REG_MAIN 0x19
#define AD5755_READ_REG_DC_DC 0x1a
#define AD5755_CTRL_REG_SLEW 0x0
#define AD5755_CTRL_REG_MAIN 0x1
#define AD5755_CTRL_REG_DAC 0x2
#define AD5755_CTRL_REG_DC_DC 0x3
#define AD5755_CTRL_REG_SW 0x4
#define AD5755_READ_FLAG 0x800000
#define AD5755_NOOP 0x1CE000
#define AD5755_DAC_INT_EN BIT(8)
#define AD5755_DAC_CLR_EN BIT(7)
#define AD5755_DAC_OUT_EN BIT(6)
#define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR BIT(5)
#define AD5755_DAC_DC_DC_EN BIT(4)
#define AD5755_DAC_VOLTAGE_OVERRANGE_EN BIT(3)
#define AD5755_DC_DC_MAXV 0
#define AD5755_DC_DC_FREQ_SHIFT 2
#define AD5755_DC_DC_PHASE_SHIFT 4
#define AD5755_EXT_DC_DC_COMP_RES BIT(6)
#define AD5755_SLEW_STEP_SIZE_SHIFT 0
#define AD5755_SLEW_RATE_SHIFT 3
#define AD5755_SLEW_ENABLE BIT(12)
/**
* struct ad5755_chip_info - chip specific information
* @channel_template: channel specification
* @calib_shift: shift for the calibration data registers
* @has_voltage_out: whether the chip has voltage outputs
*/
struct ad5755_chip_info {
const struct iio_chan_spec channel_template;
unsigned int calib_shift;
bool has_voltage_out;
};
/**
* struct ad5755_state - driver instance specific data
* @spi: spi device the driver is attached to
* @chip_info: chip model specific constants, available modes etc
* @pwr_down: bitmask which contains hether a channel is powered down or not
* @ctrl: software shadow of the channel ctrl registers
* @channels: iio channel spec for the device
* @data: spi transfer buffers
*/
struct ad5755_state {
struct spi_device *spi;
const struct ad5755_chip_info *chip_info;
unsigned int pwr_down;
unsigned int ctrl[AD5755_NUM_CHANNELS];
struct iio_chan_spec channels[AD5755_NUM_CHANNELS];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
union {
u32 d32;
u8 d8[4];
} data[2] ____cacheline_aligned;
};
enum ad5755_type {
ID_AD5755,
ID_AD5757,
ID_AD5735,
ID_AD5737,
};
static int ad5755_write_unlocked(struct iio_dev *indio_dev,
unsigned int reg, unsigned int val)
{
struct ad5755_state *st = iio_priv(indio_dev);
st->data[0].d32 = cpu_to_be32((reg << 16) | val);
return spi_write(st->spi, &st->data[0].d8[1], 3);
}
static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev,
unsigned int channel, unsigned int reg, unsigned int val)
{
return ad5755_write_unlocked(indio_dev,
AD5755_WRITE_REG_CTRL(channel), (reg << 13) | val);
}
static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg,
unsigned int val)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5755_write_unlocked(indio_dev, reg, val);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel,
unsigned int reg, unsigned int val)
{
int ret;
mutex_lock(&indio_dev->mlock);
ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val);
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr)
{
struct ad5755_state *st = iio_priv(indio_dev);
struct spi_message m;
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->data[0].d8[1],
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[1].d8[1],
.len = 3,
},
};
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
mutex_lock(&indio_dev->mlock);
st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16));
st->data[1].d32 = cpu_to_be32(AD5755_NOOP);
ret = spi_sync(st->spi, &m);
if (ret >= 0)
ret = be32_to_cpu(st->data[1].d32) & 0xffff;
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ad5755_update_dac_ctrl(struct iio_dev *indio_dev,
unsigned int channel, unsigned int set, unsigned int clr)
{
struct ad5755_state *st = iio_priv(indio_dev);
int ret;
st->ctrl[channel] |= set;
st->ctrl[channel] &= ~clr;
ret = ad5755_write_ctrl_unlocked(indio_dev, channel,
AD5755_CTRL_REG_DAC, st->ctrl[channel]);
return ret;
}
static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev,
unsigned int channel, bool pwr_down)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int mask = BIT(channel);
mutex_lock(&indio_dev->mlock);
if ((bool)(st->pwr_down & mask) == pwr_down)
goto out_unlock;
if (!pwr_down) {
st->pwr_down &= ~mask;
ad5755_update_dac_ctrl(indio_dev, channel,
AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN, 0);
udelay(200);
ad5755_update_dac_ctrl(indio_dev, channel,
AD5755_DAC_OUT_EN, 0);
} else {
st->pwr_down |= mask;
ad5755_update_dac_ctrl(indio_dev, channel,
0, AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN |
AD5755_DAC_DC_DC_EN);
}
out_unlock:
mutex_unlock(&indio_dev->mlock);
return 0;
}
static const int ad5755_min_max_table[][2] = {
[AD5755_MODE_VOLTAGE_0V_5V] = { 0, 5000 },
[AD5755_MODE_VOLTAGE_0V_10V] = { 0, 10000 },
[AD5755_MODE_VOLTAGE_PLUSMINUS_5V] = { -5000, 5000 },
[AD5755_MODE_VOLTAGE_PLUSMINUS_10V] = { -10000, 10000 },
[AD5755_MODE_CURRENT_4mA_20mA] = { 4, 20 },
[AD5755_MODE_CURRENT_0mA_20mA] = { 0, 20 },
[AD5755_MODE_CURRENT_0mA_24mA] = { 0, 24 },
};
static void ad5755_get_min_max(struct ad5755_state *st,
struct iio_chan_spec const *chan, int *min, int *max)
{
enum ad5755_mode mode = st->ctrl[chan->channel] & 7;
*min = ad5755_min_max_table[mode][0];
*max = ad5755_min_max_table[mode][1];
}
static inline int ad5755_get_offset(struct ad5755_state *st,
struct iio_chan_spec const *chan)
{
int min, max;
ad5755_get_min_max(st, chan, &min, &max);
return (min * (1 << chan->scan_type.realbits)) / (max - min);
}
static inline int ad5755_get_scale(struct ad5755_state *st,
struct iio_chan_spec const *chan)
{
int min, max;
ad5755_get_min_max(st, chan, &min, &max);
return ((max - min) * 1000000000ULL) >> chan->scan_type.realbits;
}
static int ad5755_chan_reg_info(struct ad5755_state *st,
struct iio_chan_spec const *chan, long info, bool write,
unsigned int *reg, unsigned int *shift, unsigned int *offset)
{
switch (info) {
case IIO_CHAN_INFO_RAW:
if (write)
*reg = AD5755_WRITE_REG_DATA(chan->address);
else
*reg = AD5755_READ_REG_DATA(chan->address);
*shift = chan->scan_type.shift;
*offset = 0;
break;
case IIO_CHAN_INFO_CALIBBIAS:
if (write)
*reg = AD5755_WRITE_REG_OFFSET(chan->address);
else
*reg = AD5755_READ_REG_OFFSET(chan->address);
*shift = st->chip_info->calib_shift;
*offset = 32768;
break;
case IIO_CHAN_INFO_CALIBSCALE:
if (write)
*reg = AD5755_WRITE_REG_GAIN(chan->address);
else
*reg = AD5755_READ_REG_GAIN(chan->address);
*shift = st->chip_info->calib_shift;
*offset = 0;
break;
default:
return -EINVAL;
}
return 0;
}
static int ad5755_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int reg, shift, offset;
int ret;
switch (info) {
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = ad5755_get_scale(st, chan);
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_OFFSET:
*val = ad5755_get_offset(st, chan);
return IIO_VAL_INT;
default:
ret = ad5755_chan_reg_info(st, chan, info, false,
&reg, &shift, &offset);
if (ret)
return ret;
ret = ad5755_read(indio_dev, reg);
if (ret < 0)
return ret;
*val = (ret - offset) >> shift;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad5755_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int shift, reg, offset;
int ret;
ret = ad5755_chan_reg_info(st, chan, info, true,
&reg, &shift, &offset);
if (ret)
return ret;
val <<= shift;
val += offset;
if (val < 0 || val > 0xffff)
return -EINVAL;
return ad5755_write(indio_dev, reg, val);
}
static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
const struct iio_chan_spec *chan, char *buf)
{
struct ad5755_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
(bool)(st->pwr_down & (1 << chan->channel)));
}
static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv,
struct iio_chan_spec const *chan, const char *buf, size_t len)
{
bool pwr_down;
int ret;
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
ret = ad5755_set_channel_pwr_down(indio_dev, chan->channel, pwr_down);
return ret ? ret : len;
}
static const struct iio_info ad5755_info = {
.read_raw = ad5755_read_raw,
.write_raw = ad5755_write_raw,
.driver_module = THIS_MODULE,
};
static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
{
.name = "powerdown",
.read = ad5755_read_powerdown,
.write = ad5755_write_powerdown,
},
{ },
};
#define AD5755_CHANNEL(_bits) { \
.indexed = 1, \
.output = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
.ext_info = ad5755_ext_info, \
}
static const struct ad5755_chip_info ad5755_chip_info_tbl[] = {
[ID_AD5735] = {
.channel_template = AD5755_CHANNEL(14),
.has_voltage_out = true,
.calib_shift = 4,
},
[ID_AD5737] = {
.channel_template = AD5755_CHANNEL(14),
.has_voltage_out = false,
.calib_shift = 4,
},
[ID_AD5755] = {
.channel_template = AD5755_CHANNEL(16),
.has_voltage_out = true,
.calib_shift = 0,
},
[ID_AD5757] = {
.channel_template = AD5755_CHANNEL(16),
.has_voltage_out = false,
.calib_shift = 0,
},
};
static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode)
{
switch (mode) {
case AD5755_MODE_VOLTAGE_0V_5V:
case AD5755_MODE_VOLTAGE_0V_10V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
return st->chip_info->has_voltage_out;
case AD5755_MODE_CURRENT_4mA_20mA:
case AD5755_MODE_CURRENT_0mA_20mA:
case AD5755_MODE_CURRENT_0mA_24mA:
return true;
default:
return false;
}
}
static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev,
const struct ad5755_platform_data *pdata)
{
struct ad5755_state *st = iio_priv(indio_dev);
unsigned int ret;
unsigned int val;
unsigned int i;
if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE ||
pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ ||
pdata->dc_dc_maxv > AD5755_DC_DC_MAXV_29V5)
return -EINVAL;
val = pdata->dc_dc_maxv << AD5755_DC_DC_MAXV;
val |= pdata->dc_dc_freq << AD5755_DC_DC_FREQ_SHIFT;
val |= pdata->dc_dc_phase << AD5755_DC_DC_PHASE_SHIFT;
if (pdata->ext_dc_dc_compenstation_resistor)
val |= AD5755_EXT_DC_DC_COMP_RES;
ret = ad5755_write_ctrl(indio_dev, 0, AD5755_CTRL_REG_DC_DC, val);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
val = pdata->dac[i].slew.step_size <<
AD5755_SLEW_STEP_SIZE_SHIFT;
val |= pdata->dac[i].slew.rate <<
AD5755_SLEW_RATE_SHIFT;
if (pdata->dac[i].slew.enable)
val |= AD5755_SLEW_ENABLE;
ret = ad5755_write_ctrl(indio_dev, i,
AD5755_CTRL_REG_SLEW, val);
if (ret < 0)
return ret;
}
for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) {
if (!ad5755_is_valid_mode(st, pdata->dac[i].mode))
return -EINVAL;
val = 0;
if (!pdata->dac[i].ext_current_sense_resistor)
val |= AD5755_DAC_INT_CURRENT_SENSE_RESISTOR;
if (pdata->dac[i].enable_voltage_overrange)
val |= AD5755_DAC_VOLTAGE_OVERRANGE_EN;
val |= pdata->dac[i].mode;
ret = ad5755_update_dac_ctrl(indio_dev, i, val, 0);
if (ret < 0)
return ret;
}
return 0;
}
static bool __devinit ad5755_is_voltage_mode(enum ad5755_mode mode)
{
switch (mode) {
case AD5755_MODE_VOLTAGE_0V_5V:
case AD5755_MODE_VOLTAGE_0V_10V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_5V:
case AD5755_MODE_VOLTAGE_PLUSMINUS_10V:
return true;
default:
return false;
}
}
static int __devinit ad5755_init_channels(struct iio_dev *indio_dev,
const struct ad5755_platform_data *pdata)
{
struct ad5755_state *st = iio_priv(indio_dev);
struct iio_chan_spec *channels = st->channels;
unsigned int i;
for (i = 0; i < AD5755_NUM_CHANNELS; ++i) {
channels[i] = st->chip_info->channel_template;
channels[i].channel = i;
channels[i].address = i;
if (pdata && ad5755_is_voltage_mode(pdata->dac[i].mode))
channels[i].type = IIO_VOLTAGE;
else
channels[i].type = IIO_CURRENT;
}
indio_dev->channels = channels;
return 0;
}
#define AD5755_DEFAULT_DAC_PDATA { \
.mode = AD5755_MODE_CURRENT_4mA_20mA, \
.ext_current_sense_resistor = true, \
.enable_voltage_overrange = false, \
.slew = { \
.enable = false, \
.rate = AD5755_SLEW_RATE_64k, \
.step_size = AD5755_SLEW_STEP_SIZE_1, \
}, \
}
static const struct ad5755_platform_data ad5755_default_pdata = {
.ext_dc_dc_compenstation_resistor = false,
.dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE,
.dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ,
.dc_dc_maxv = AD5755_DC_DC_MAXV_23V,
.dac = {
[0] = AD5755_DEFAULT_DAC_PDATA,
[1] = AD5755_DEFAULT_DAC_PDATA,
[2] = AD5755_DEFAULT_DAC_PDATA,
[3] = AD5755_DEFAULT_DAC_PDATA,
},
};
static int __devinit ad5755_probe(struct spi_device *spi)
{
enum ad5755_type type = spi_get_device_id(spi)->driver_data;
const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad5755_state *st;
int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->chip_info = &ad5755_chip_info_tbl[type];
st->spi = spi;
st->pwr_down = 0xf;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5755_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5755_NUM_CHANNELS;
if (!pdata)
pdata = &ad5755_default_pdata;
ret = ad5755_init_channels(indio_dev, pdata);
if (ret)
goto error_free;
ret = ad5755_setup_pdata(indio_dev, pdata);
if (ret)
goto error_free;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
goto error_free;
}
return 0;
error_free:
iio_device_free(indio_dev);
return ret;
}
static int __devexit ad5755_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad5755_id[] = {
{ "ad5755", ID_AD5755 },
{ "ad5755-1", ID_AD5755 },
{ "ad5757", ID_AD5757 },
{ "ad5735", ID_AD5735 },
{ "ad5737", ID_AD5737 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5755_id);
static struct spi_driver ad5755_driver = {
.driver = {
.name = "ad5755",
.owner = THIS_MODULE,
},
.probe = ad5755_probe,
.remove = __devexit_p(ad5755_remove),
.id_table = ad5755_id,
};
module_spi_driver(ad5755_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5755/55-1/57/35/37 DAC");
MODULE_LICENSE("GPL v2");

View File

@ -366,6 +366,7 @@ static ssize_t iio_read_channel_info(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long long tmp;
int val, val2;
bool scale_db = false;
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
@ -391,6 +392,11 @@ static ssize_t iio_read_channel_info(struct device *dev,
return sprintf(buf, "-%d.%09u\n", val, -val2);
else
return sprintf(buf, "%d.%09u\n", val, val2);
case IIO_VAL_FRACTIONAL:
tmp = div_s64((s64)val * 1000000000LL, val2);
val2 = do_div(tmp, 1000000000LL);
val = tmp;
return sprintf(buf, "%d.%09u\n", val, val2);
default:
return 0;
}

View File

@ -130,18 +130,27 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
if (c == NULL)
return ERR_PTR(-ENODEV);
channel = kmalloc(sizeof(*channel), GFP_KERNEL);
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (channel == NULL)
return ERR_PTR(-ENOMEM);
channel->indio_dev = c->indio_dev;
if (c->map->adc_channel_label)
if (c->map->adc_channel_label) {
channel->channel =
iio_chan_spec_from_name(channel->indio_dev,
c->map->adc_channel_label);
if (channel->channel == NULL)
goto error_no_chan;
}
return channel;
error_no_chan:
iio_device_put(c->indio_dev);
kfree(channel);
return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(iio_channel_get);
@ -229,9 +238,21 @@ void iio_channel_release_all(struct iio_channel *channels)
}
EXPORT_SYMBOL_GPL(iio_channel_release_all);
static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum info)
{
int unused;
if (val2 == NULL)
val2 = &unused;
return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
val, val2, info);
}
int iio_read_channel_raw(struct iio_channel *chan, int *val)
{
int val2, ret;
int ret;
mutex_lock(&chan->indio_dev->info_exist_lock);
if (chan->indio_dev->info == NULL) {
@ -239,10 +260,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
goto err_unlock;
}
ret = chan->indio_dev->info->read_raw(chan->indio_dev,
chan->channel,
val, &val2,
IIO_CHAN_INFO_RAW);
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock);
@ -250,6 +268,100 @@ err_unlock:
}
EXPORT_SYMBOL_GPL(iio_read_channel_raw);
static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
int raw, int *processed, unsigned int scale)
{
int scale_type, scale_val, scale_val2, offset;
s64 raw64 = raw;
int ret;
ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE);
if (ret == 0)
raw64 += offset;
scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
IIO_CHAN_INFO_SCALE);
if (scale_type < 0)
return scale_type;
switch (scale_type) {
case IIO_VAL_INT:
*processed = raw64 * scale_val;
break;
case IIO_VAL_INT_PLUS_MICRO:
if (scale_val2 < 0)
*processed = -raw64 * scale_val;
else
*processed = raw64 * scale_val;
*processed += div_s64(raw64 * (s64)scale_val2 * scale,
1000000LL);
break;
case IIO_VAL_INT_PLUS_NANO:
if (scale_val2 < 0)
*processed = -raw64 * scale_val;
else
*processed = raw64 * scale_val;
*processed += div_s64(raw64 * (s64)scale_val2 * scale,
1000000000LL);
break;
case IIO_VAL_FRACTIONAL:
*processed = div_s64(raw64 * (s64)scale_val * scale,
scale_val2);
break;
default:
return -EINVAL;
}
return 0;
}
int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale)
{
int ret;
mutex_lock(&chan->indio_dev->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
}
ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed,
scale);
err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock);
return ret;
}
EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed);
int iio_read_channel_processed(struct iio_channel *chan, int *val)
{
int ret;
mutex_lock(&chan->indio_dev->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
}
if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) {
ret = iio_channel_read(chan, val, NULL,
IIO_CHAN_INFO_PROCESSED);
} else {
ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
if (ret < 0)
goto err_unlock;
ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1);
}
err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock);
return ret;
}
EXPORT_SYMBOL_GPL(iio_read_channel_processed);
int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
{
int ret;
@ -260,10 +372,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
goto err_unlock;
}
ret = chan->indio_dev->info->read_raw(chan->indio_dev,
chan->channel,
val, val2,
IIO_CHAN_INFO_SCALE);
ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE);
err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock);

View File

@ -48,11 +48,11 @@ There are then a number of functions that can be used to get information
about this channel such as it's current reading.
e.g.
iio_st_read_channel_raw() - get a reading
iio_st_read_channel_type() - get the type of channel
iio_read_channel_raw() - get a reading
iio_get_channel_type() - get the type of channel
There is also provision for retrieving all of the channels associated
with a given consumer. This is useful for generic drivers such as
iio_hwmon where the number and naming of channels is not known by the
consumer driver. To do this, use iio_st_channel_get_all.
consumer driver. To do this, use iio_channel_get_all.

View File

@ -68,20 +68,6 @@ config AD799X_RING_BUFFER
Say yes here to include ring buffer support in the AD799X
ADC driver.
config AD7476
tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495
SPI analog to digital converters (ADC).
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7476.
config AD7887
tristate "Analog Devices AD7887 ADC driver"
depends on SPI

View File

@ -17,10 +17,6 @@ ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
obj-$(CONFIG_AD799X) += ad799x.o
ad7476-y := ad7476_core.o
ad7476-$(CONFIG_IIO_BUFFER) += ad7476_ring.o
obj-$(CONFIG_AD7476) += ad7476.o
ad7887-y := ad7887_core.o
ad7887-$(CONFIG_IIO_BUFFER) += ad7887_ring.o
obj-$(CONFIG_AD7887) += ad7887.o

View File

@ -1,66 +0,0 @@
/*
* AD7476/5/7/8 (A) SPI ADC driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef IIO_ADC_AD7476_H_
#define IIO_ADC_AD7476_H_
#define RES_MASK(bits) ((1 << (bits)) - 1)
/*
* TODO: struct ad7476_platform_data needs to go into include/linux/iio
*/
struct ad7476_platform_data {
u16 vref_mv;
};
struct ad7476_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[2];
};
struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
u16 int_vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned char data[2] ____cacheline_aligned;
};
enum ad7476_supported_device_ids {
ID_AD7466,
ID_AD7467,
ID_AD7468,
ID_AD7475,
ID_AD7476,
ID_AD7477,
ID_AD7478,
ID_AD7495
};
#ifdef CONFIG_IIO_BUFFER
int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void ad7476_ring_cleanup(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline int
ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return 0;
}
static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* IIO_ADC_AD7476_H_ */

View File

@ -1,64 +0,0 @@
/*
* Copyright 2010-2012 Analog Devices Inc.
* Copyright (C) 2008 Jonathan Cameron
*
* Licensed under the GPL-2 or later.
*
* ad7476_ring.c
*/
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "ad7476.h"
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7476_state *st = iio_priv(indio_dev);
s64 time_ns;
__u8 *rxbuf;
int b_sent;
rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (rxbuf == NULL)
goto done;
b_sent = spi_read(st->spi, rxbuf,
st->chip_info->channel[0].scan_type.storagebits / 8);
if (b_sent < 0)
goto done;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
iio_push_to_buffer(indio_dev->buffer, rxbuf);
done:
iio_trigger_notify_done(indio_dev->trig);
kfree(rxbuf);
return IRQ_HANDLED;
}
int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, NULL,
&ad7476_trigger_handler, NULL);
}
void ad7476_ring_cleanup(struct iio_dev *indio_dev)
{
iio_triggered_buffer_cleanup(indio_dev);
}

View File

@ -42,40 +42,17 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
struct device_attribute *attr,
char *buf)
{
long result;
int val, ret, scaleint, scalepart;
int result;
int ret;
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct iio_hwmon_state *state = dev_get_drvdata(dev);
/*
* No locking between this pair, so theoretically possible
* the scale has changed.
*/
ret = iio_read_channel_raw(&state->channels[sattr->index],
&val);
ret = iio_read_channel_processed(&state->channels[sattr->index],
&result);
if (ret < 0)
return ret;
ret = iio_read_channel_scale(&state->channels[sattr->index],
&scaleint, &scalepart);
if (ret < 0)
return ret;
switch (ret) {
case IIO_VAL_INT:
result = val * scaleint;
break;
case IIO_VAL_INT_PLUS_MICRO:
result = (s64)val * (s64)scaleint +
div_s64((s64)val * (s64)scalepart, 1000000LL);
break;
case IIO_VAL_INT_PLUS_NANO:
result = (s64)val * (s64)scaleint +
div_s64((s64)val * (s64)scalepart, 1000000000LL);
break;
default:
return -EINVAL;
}
return sprintf(buf, "%ld\n", result);
return sprintf(buf, "%d\n", result);
}
static void iio_hwmon_free_attrs(struct iio_hwmon_state *st)

View File

@ -14,14 +14,18 @@
#include <linux/delay.h>
#include <asm/gptimers.h>
#include <asm/portmux.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "iio-trig-bfin-timer.h"
struct bfin_timer {
unsigned short id, bit;
unsigned long irqbit;
int irq;
int pin;
};
/*
@ -30,22 +34,22 @@ struct bfin_timer {
*/
static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
{TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0},
{TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1},
{TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2},
{TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0, P_TMR0},
{TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1, P_TMR1},
{TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2, P_TMR2},
#if (MAX_BLACKFIN_GPTIMERS > 3)
{TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3},
{TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4},
{TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5},
{TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6},
{TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7},
{TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3, P_TMR3},
{TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4, P_TMR4},
{TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5, P_TMR5},
{TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6, P_TMR6},
{TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7, P_TMR7},
#endif
#if (MAX_BLACKFIN_GPTIMERS > 8)
{TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8},
{TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9},
{TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10},
{TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8, P_TMR8},
{TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9, P_TMR9},
{TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10},
#if (MAX_BLACKFIN_GPTIMERS > 11)
{TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11},
{TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11, P_TMR11},
#endif
#endif
};
@ -54,15 +58,33 @@ struct bfin_tmr_state {
struct iio_trigger *trig;
struct bfin_timer *t;
unsigned timer_num;
bool output_enable;
unsigned int duty;
int irq;
};
static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
{
struct bfin_tmr_state *st = trig->private_data;
if (get_gptimer_period(st->t->id) == 0)
return -EINVAL;
if (state)
enable_gptimers(st->t->bit);
else
disable_gptimers(st->t->bit);
return 0;
}
static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct bfin_tmr_state *st = trig->private_data;
long val;
unsigned long val;
bool enabled;
int ret;
ret = strict_strtoul(buf, 10, &val);
@ -74,20 +96,25 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
goto error_ret;
}
disable_gptimers(st->t->bit);
enabled = get_enabled_gptimers() & st->t->bit;
if (enabled)
disable_gptimers(st->t->bit);
if (!val)
goto error_ret;
val = get_sclk() / val;
if (val <= 4) {
if (val <= 4 || val <= st->duty) {
ret = -EINVAL;
goto error_ret;
}
set_gptimer_period(st->t->id, val);
set_gptimer_pwidth(st->t->id, 1);
enable_gptimers(st->t->bit);
set_gptimer_pwidth(st->t->id, val - st->duty);
if (enabled)
enable_gptimers(st->t->bit);
error_ret:
return ret ? ret : count;
@ -99,9 +126,15 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct bfin_tmr_state *st = trig->private_data;
unsigned int period = get_gptimer_period(st->t->id);
unsigned long val;
return sprintf(buf, "%lu\n",
get_sclk() / get_gptimer_period(st->t->id));
if (period == 0)
val = 0;
else
val = get_sclk() / get_gptimer_period(st->t->id);
return sprintf(buf, "%lu\n", val);
}
static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
@ -121,7 +154,6 @@ static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = {
NULL
};
static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
{
struct bfin_tmr_state *st = devid;
@ -145,11 +177,14 @@ static int iio_bfin_tmr_get_number(int irq)
static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = iio_bfin_tmr_set_state,
};
static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
{
struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data;
struct bfin_tmr_state *st;
unsigned int config;
int ret;
st = kzalloc(sizeof(*st), GFP_KERNEL);
@ -193,13 +228,43 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
goto out4;
}
set_gptimer_config(st->t->id, OUT_DIS | PWM_OUT | PERIOD_CNT | IRQ_ENA);
config = PWM_OUT | PERIOD_CNT | IRQ_ENA;
if (pdata && pdata->output_enable) {
unsigned long long val;
st->output_enable = true;
ret = peripheral_request(st->t->pin, st->trig->name);
if (ret)
goto out_free_irq;
val = (unsigned long long)get_sclk() * pdata->duty_ns;
do_div(val, NSEC_PER_SEC);
st->duty = val;
/**
* The interrupt will be generated at the end of the period,
* since we want the interrupt to be generated at end of the
* pulse we invert both polarity and duty cycle, so that the
* pulse will be generated directly before the interrupt.
*/
if (pdata->active_low)
config |= PULSE_HI;
} else {
st->duty = 1;
config |= OUT_DIS;
}
set_gptimer_config(st->t->id, config);
dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
st->timer_num, st->irq);
platform_set_drvdata(pdev, st);
return 0;
out_free_irq:
free_irq(st->irq, st);
out4:
iio_trigger_unregister(st->trig);
out2:
@ -215,6 +280,8 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
struct bfin_tmr_state *st = platform_get_drvdata(pdev);
disable_gptimers(st->t->bit);
if (st->output_enable)
peripheral_free(st->t->pin);
free_irq(st->irq, st);
iio_trigger_unregister(st->trig);
iio_trigger_put(st->trig);

View File

@ -0,0 +1,24 @@
#ifndef __IIO_BFIN_TIMER_TRIGGER_H__
#define __IIO_BFIN_TIMER_TRIGGER_H__
/**
* struct iio_bfin_timer_trigger_pdata - timer trigger platform data
* @output_enable: Enable external trigger pulse generation.
* @active_low: Whether the trigger pulse is active low.
* @duty_ns: Length of the trigger pulse in nanoseconds.
*
* This struct is used to configure the output pulse generation of the blackfin
* timer trigger. If output_enable is set to true an external trigger signal
* will generated on the pin corresponding to the timer. This is useful for
* converters which needs an external signal to start conversion. active_low and
* duty_ns are used to configure the type of the trigger pulse. If output_enable
* is set to false no external trigger pulse will be generated and active_low
* and duty_ns are ignored.
**/
struct iio_bfin_timer_trigger_pdata {
bool output_enable;
bool active_low;
unsigned int duty_ns;
};
#endif

View File

@ -61,7 +61,7 @@ void iio_channel_release_all(struct iio_channel *chan);
/**
* iio_read_channel_raw() - read from a given channel
* @channel: The channel being queried.
* @chan: The channel being queried.
* @val: Value read back.
*
* Note raw reads from iio channels are in adc counts and hence
@ -70,6 +70,21 @@ void iio_channel_release_all(struct iio_channel *chan);
int iio_read_channel_raw(struct iio_channel *chan,
int *val);
/**
* iio_read_channel_processed() - read processed value from a given channel
* @chan: The channel being queried.
* @val: Value read back.
*
* Returns an error code or 0.
*
* This function will read a processed value from a channel. A processed value
* means that this value will have the correct unit and not some device internal
* representation. If the device does not support reporting a processed value
* the function will query the raw value and the channels scale and offset and
* do the appropriate transformation.
*/
int iio_read_channel_processed(struct iio_channel *chan, int *val);
/**
* iio_get_channel_type() - get the type of a channel
* @channel: The channel being queried.
@ -82,7 +97,7 @@ int iio_get_channel_type(struct iio_channel *channel,
/**
* iio_read_channel_scale() - read the scale value for a channel
* @channel: The channel being queried.
* @chan: The channel being queried.
* @val: First part of value read back.
* @val2: Second part of value read back.
*
@ -93,4 +108,27 @@ int iio_get_channel_type(struct iio_channel *channel,
int iio_read_channel_scale(struct iio_channel *chan, int *val,
int *val2);
/**
* iio_convert_raw_to_processed() - Converts a raw value to a processed value
* @chan: The channel being queried
* @raw: The raw IIO to convert
* @processed: The result of the conversion
* @scale: Scale factor to apply during the conversion
*
* Returns an error code or 0.
*
* This function converts a raw value to processed value for a specific channel.
* A raw value is the device internal representation of a sample and the value
* returned by iio_read_channel_raw, so the unit of that value is device
* depended. A processed value on the other hand is value has a normed unit
* according with the IIO specification.
*
* The scale factor allows to increase the precession of the returned value. For
* a scale factor of 1 the function will return the result in the normal IIO
* unit for the channel type. E.g. millivolt for voltage channels, if you want
* nanovolts instead pass 1000 as the scale factor.
*/
int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale);
#endif

View File

@ -40,6 +40,8 @@ enum iio_chan_info_enum {
#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
#define IIO_CHAN_INFO_BITS(type) (IIO_CHAN_INFO_SHARED_BIT(type) | \
IIO_CHAN_INFO_SEPARATE_BIT(type))
#define IIO_CHAN_INFO_RAW_SEPARATE_BIT \
IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
@ -261,6 +263,21 @@ struct iio_chan_spec {
unsigned differential:1;
};
/**
* iio_channel_has_info() - Checks whether a channel supports a info attribute
* @chan: The channel to be queried
* @type: Type of the info attribute to be checked
*
* Returns true if the channels supports reporting values for the given info
* attribute type, false otherwise.
*/
static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
enum iio_chan_info_enum type)
{
return chan->info_mask & IIO_CHAN_INFO_BITS(type);
}
#define IIO_ST(si, rb, sb, sh) \
{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }

View File

@ -57,5 +57,6 @@ enum iio_modifier {
#define IIO_VAL_INT_PLUS_MICRO 2
#define IIO_VAL_INT_PLUS_NANO 3
#define IIO_VAL_INT_PLUS_MICRO_DB 4
#define IIO_VAL_FRACTIONAL 10
#endif /* _IIO_TYPES_H_ */

View File

@ -0,0 +1,103 @@
/*
* Copyright 2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef __LINUX_PLATFORM_DATA_AD5755_H__
#define __LINUX_PLATFORM_DATA_AD5755_H__
enum ad5755_mode {
AD5755_MODE_VOLTAGE_0V_5V = 0,
AD5755_MODE_VOLTAGE_0V_10V = 1,
AD5755_MODE_VOLTAGE_PLUSMINUS_5V = 2,
AD5755_MODE_VOLTAGE_PLUSMINUS_10V = 3,
AD5755_MODE_CURRENT_4mA_20mA = 4,
AD5755_MODE_CURRENT_0mA_20mA = 5,
AD5755_MODE_CURRENT_0mA_24mA = 6,
};
enum ad5755_dc_dc_phase {
AD5755_DC_DC_PHASE_ALL_SAME_EDGE = 0,
AD5755_DC_DC_PHASE_A_B_SAME_EDGE_C_D_OPP_EDGE = 1,
AD5755_DC_DC_PHASE_A_C_SAME_EDGE_B_D_OPP_EDGE = 2,
AD5755_DC_DC_PHASE_90_DEGREE = 3,
};
enum ad5755_dc_dc_freq {
AD5755_DC_DC_FREQ_250kHZ = 0,
AD5755_DC_DC_FREQ_410kHZ = 1,
AD5755_DC_DC_FREQ_650kHZ = 2,
};
enum ad5755_dc_dc_maxv {
AD5755_DC_DC_MAXV_23V = 0,
AD5755_DC_DC_MAXV_24V5 = 1,
AD5755_DC_DC_MAXV_27V = 2,
AD5755_DC_DC_MAXV_29V5 = 3,
};
enum ad5755_slew_rate {
AD5755_SLEW_RATE_64k = 0,
AD5755_SLEW_RATE_32k = 1,
AD5755_SLEW_RATE_16k = 2,
AD5755_SLEW_RATE_8k = 3,
AD5755_SLEW_RATE_4k = 4,
AD5755_SLEW_RATE_2k = 5,
AD5755_SLEW_RATE_1k = 6,
AD5755_SLEW_RATE_500 = 7,
AD5755_SLEW_RATE_250 = 8,
AD5755_SLEW_RATE_125 = 9,
AD5755_SLEW_RATE_64 = 10,
AD5755_SLEW_RATE_32 = 11,
AD5755_SLEW_RATE_16 = 12,
AD5755_SLEW_RATE_8 = 13,
AD5755_SLEW_RATE_4 = 14,
AD5755_SLEW_RATE_0_5 = 15,
};
enum ad5755_slew_step_size {
AD5755_SLEW_STEP_SIZE_1 = 0,
AD5755_SLEW_STEP_SIZE_2 = 1,
AD5755_SLEW_STEP_SIZE_4 = 2,
AD5755_SLEW_STEP_SIZE_8 = 3,
AD5755_SLEW_STEP_SIZE_16 = 4,
AD5755_SLEW_STEP_SIZE_32 = 5,
AD5755_SLEW_STEP_SIZE_64 = 6,
AD5755_SLEW_STEP_SIZE_128 = 7,
AD5755_SLEW_STEP_SIZE_256 = 8,
};
/**
* struct ad5755_platform_data - AD5755 DAC driver platform data
* @ext_dc_dc_compenstation_resistor: Whether an external DC-DC converter
* compensation register is used.
* @dc_dc_phase: DC-DC converter phase.
* @dc_dc_freq: DC-DC converter frequency.
* @dc_dc_maxv: DC-DC maximum allowed boost voltage.
* @dac.mode: The mode to be used for the DAC output.
* @dac.ext_current_sense_resistor: Whether an external current sense resistor
* is used.
* @dac.enable_voltage_overrange: Whether to enable 20% voltage output overrange.
* @dac.slew.enable: Whether to enable digital slew.
* @dac.slew.rate: Slew rate of the digital slew.
* @dac.slew.step_size: Slew step size of the digital slew.
**/
struct ad5755_platform_data {
bool ext_dc_dc_compenstation_resistor;
enum ad5755_dc_dc_phase dc_dc_phase;
enum ad5755_dc_dc_freq dc_dc_freq;
enum ad5755_dc_dc_maxv dc_dc_maxv;
struct {
enum ad5755_mode mode;
bool ext_current_sense_resistor;
bool enable_voltage_overrange;
struct {
bool enable;
enum ad5755_slew_rate rate;
enum ad5755_slew_step_size step_size;
} slew;
} dac[4];
};
#endif