Commit 8508317c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-v3.7d' of...

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.
parents 3afcb91c 87c5b10f
...@@ -30,6 +30,21 @@ config AD7791 ...@@ -30,6 +30,21 @@ config AD7791
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called ad7791. 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 config AT91_ADC
tristate "Atmel AT91 ADC" tristate "Atmel AT91 ADC"
depends on ARCH_AT91 depends on ARCH_AT91
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o
...@@ -18,8 +18,76 @@ ...@@ -18,8 +18,76 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/buffer.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) static int ad7476_scan_direct(struct ad7476_state *st)
{ {
...@@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st) ...@@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st)
if (ret) if (ret)
return 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, static int ad7476_read_raw(struct iio_dev *indio_dev,
...@@ -40,7 +108,7 @@ 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; int ret;
struct ad7476_state *st = iio_priv(indio_dev); struct ad7476_state *st = iio_priv(indio_dev);
unsigned int scale_uv; int scale_uv;
switch (m) { switch (m) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
...@@ -57,62 +125,80 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, ...@@ -57,62 +125,80 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
RES_MASK(st->chip_info->channel[0].scan_type.realbits); RES_MASK(st->chip_info->channel[0].scan_type.realbits);
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
scale_uv = (st->int_vref_mv * 1000) if (!st->chip_info->int_vref_uv) {
>> st->chip_info->channel[0].scan_type.realbits; scale_uv = regulator_get_voltage(st->reg);
*val = scale_uv/1000; if (scale_uv < 0)
*val2 = (scale_uv%1000)*1000; 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 IIO_VAL_INT_PLUS_MICRO;
} }
return -EINVAL; return -EINVAL;
} }
#define AD7476_CHAN(bits) \ #define _AD7476_CHAN(bits, _shift, _info_mask) \
{ \ { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask = _info_mask | \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
.realbits = bits, \ .realbits = (bits), \
.storagebits = 16, \ .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[] = { static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7466] = { [ID_AD7091R] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.reset = ad7091_reset,
}, },
[ID_AD7467] = { [ID_AD7276] = {
.channel[0] = AD7476_CHAN(10), .channel[0] = AD7940_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7468] = { [ID_AD7277] = {
.channel[0] = AD7476_CHAN(8), .channel[0] = AD7940_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7475] = { [ID_AD7278] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7940_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7476] = { [ID_AD7466] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7477] = { [ID_AD7467] = {
.channel[0] = AD7476_CHAN(10), .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7478] = { [ID_AD7468] = {
.channel[0] = AD7476_CHAN(8), .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_AD7495] = { [ID_AD7495] = {
.channel[0] = AD7476_CHAN(12), .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .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 = { ...@@ -123,10 +209,9 @@ static const struct iio_info ad7476_info = {
static int __devinit ad7476_probe(struct spi_device *spi) static int __devinit ad7476_probe(struct spi_device *spi)
{ {
struct ad7476_platform_data *pdata = spi->dev.platform_data;
struct ad7476_state *st; struct ad7476_state *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
int ret, voltage_uv = 0; int ret;
indio_dev = iio_device_alloc(sizeof(*st)); indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) { if (indio_dev == NULL) {
...@@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi) ...@@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi)
goto error_ret; goto error_ret;
} }
st = iio_priv(indio_dev); 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 = st->chip_info =
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
if (st->chip_info->int_vref_mv) st->reg = regulator_get(&spi->dev, "vcc");
st->int_vref_mv = st->chip_info->int_vref_mv; if (IS_ERR(st->reg)) {
else if (pdata && pdata->vref_mv) ret = PTR_ERR(st->reg);
st->int_vref_mv = pdata->vref_mv; goto error_free_dev;
else if (voltage_uv) }
st->int_vref_mv = voltage_uv / 1000;
else ret = regulator_enable(st->reg);
dev_warn(&spi->dev, "reference voltage unspecified\n"); if (ret)
goto error_put_reg;
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
...@@ -173,23 +251,26 @@ static int __devinit ad7476_probe(struct spi_device *spi) ...@@ -173,23 +251,26 @@ static int __devinit ad7476_probe(struct spi_device *spi)
spi_message_init(&st->msg); spi_message_init(&st->msg);
spi_message_add_tail(&st->xfer, &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) if (ret)
goto error_disable_reg; goto error_disable_reg;
if (st->chip_info->reset)
st->chip_info->reset(st);
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_ring_unregister; goto error_ring_unregister;
return 0; return 0;
error_ring_unregister: error_ring_unregister:
ad7476_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg: error_disable_reg:
if (!IS_ERR(st->reg)) regulator_disable(st->reg);
regulator_disable(st->reg);
error_put_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); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -202,28 +283,35 @@ static int __devexit ad7476_remove(struct spi_device *spi) ...@@ -202,28 +283,35 @@ static int __devexit ad7476_remove(struct spi_device *spi)
struct ad7476_state *st = iio_priv(indio_dev); struct ad7476_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
ad7476_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
if (!IS_ERR(st->reg)) { regulator_disable(st->reg);
regulator_disable(st->reg); regulator_put(st->reg);
regulator_put(st->reg);
}
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
} }
static const struct spi_device_id ad7476_id[] = { 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}, {"ad7466", ID_AD7466},
{"ad7467", ID_AD7467}, {"ad7467", ID_AD7467},
{"ad7468", ID_AD7468}, {"ad7468", ID_AD7468},
{"ad7475", ID_AD7475}, {"ad7475", ID_AD7466},
{"ad7476", ID_AD7476}, {"ad7476", ID_AD7466},
{"ad7476a", ID_AD7476}, {"ad7476a", ID_AD7466},
{"ad7477", ID_AD7477}, {"ad7477", ID_AD7467},
{"ad7477a", ID_AD7477}, {"ad7477a", ID_AD7467},
{"ad7478", ID_AD7478}, {"ad7478", ID_AD7468},
{"ad7478a", ID_AD7478}, {"ad7478a", ID_AD7468},
{"ad7495", ID_AD7495}, {"ad7495", ID_AD7495},
{"ad7910", ID_AD7467},
{"ad7920", ID_AD7466},
{"ad7940", ID_AD7940},
{} {}
}; };
MODULE_DEVICE_TABLE(spi, ad7476_id); MODULE_DEVICE_TABLE(spi, ad7476_id);
...@@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = { ...@@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = {
module_spi_driver(ad7476_driver); module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); 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"); MODULE_LICENSE("GPL v2");
...@@ -77,6 +77,17 @@ config AD5504 ...@@ -77,6 +77,17 @@ config AD5504
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5504. 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 config AD5764
tristate "Analog Devices AD5764/64R/44/44R DAC driver" tristate "Analog Devices AD5764/64R/44/44R DAC driver"
depends on SPI_MASTER depends on SPI_MASTER
......
...@@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o ...@@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5064) += ad5064.o obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD5686) += ad5686.o
......
This diff is collapsed.
...@@ -366,6 +366,7 @@ static ssize_t iio_read_channel_info(struct device *dev, ...@@ -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 *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long long tmp;
int val, val2; int val, val2;
bool scale_db = false; bool scale_db = false;
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, 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, ...@@ -391,6 +392,11 @@ static ssize_t iio_read_channel_info(struct device *dev,
return sprintf(buf, "-%d.%09u\n", val, -val2); return sprintf(buf, "-%d.%09u\n", val, -val2);
else else
return sprintf(buf, "%d.%09u\n", val, val2); 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: default:
return 0; return 0;
} }
......
...@@ -130,18 +130,27 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) ...@@ -130,18 +130,27 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
if (c == NULL) if (c == NULL)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
channel = kmalloc(sizeof(*channel), GFP_KERNEL); channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (channel == NULL) if (channel == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
channel->indio_dev = c->indio_dev; channel->indio_dev = c->indio_dev;
if (c->map->adc_channel_label) if (c->map->adc_channel_label) {
channel->channel = channel->channel =
iio_chan_spec_from_name(channel->indio_dev, iio_chan_spec_from_name(channel->indio_dev,
c->map->adc_channel_label); c->map->adc_channel_label);
if (channel->channel == NULL)
goto error_no_chan;
}
return channel; return channel;
error_no_chan:
iio_device_put(c->indio_dev);
kfree(channel);
return ERR_PTR(-EINVAL);
} }
EXPORT_SYMBOL_GPL(iio_channel_get); EXPORT_SYMBOL_GPL(iio_channel_get);
...@@ -229,9 +238,21 @@ void iio_channel_release_all(struct iio_channel *channels) ...@@ -229,9 +238,21 @@ void iio_channel_release_all(struct iio_channel *channels)
} }
EXPORT_SYMBOL_GPL(iio_channel_release_all); 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 iio_read_channel_raw(struct iio_channel *chan, int *val)
{ {
int val2, ret; int ret;
mutex_lock(&chan->indio_dev->info_exist_lock); mutex_lock(&chan->indio_dev->info_exist_lock);
if (chan->indio_dev->info == NULL) { if (chan->indio_dev->info == NULL) {
...@@ -239,10 +260,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) ...@@ -239,10 +260,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
goto err_unlock; goto err_unlock;
} }
ret = chan->indio_dev->info->read_raw(chan->indio_dev, ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW);
chan->channel,
val, &val2,
IIO_CHAN_INFO_RAW);
err_unlock: err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock); mutex_unlock(&chan->indio_dev->info_exist_lock);
...@@ -250,6 +268,100 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) ...@@ -250,6 +268,100 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val)
} }
EXPORT_SYMBOL_GPL(iio_read_channel_raw); 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 iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
{ {
int ret; int ret;
...@@ -260,10 +372,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) ...@@ -260,10 +372,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
goto err_unlock; goto err_unlock;
} }
ret = chan->indio_dev->info->read_raw(chan->indio_dev, ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE);
chan->channel,
val, val2,
IIO_CHAN_INFO_SCALE);
err_unlock: err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock); mutex_unlock(&chan->indio_dev->info_exist_lock);
......
...@@ -48,11 +48,11 @@ There are then a number of functions that can be used to get information ...@@ -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. about this channel such as it's current reading.
e.g. e.g.
iio_st_read_channel_raw() - get a reading iio_read_channel_raw() - get a reading
iio_st_read_channel_type() - get the type of channel iio_get_channel_type() - get the type of channel
There is also provision for retrieving all of the channels associated There is also provision for retrieving all of the channels associated
with a given consumer. This is useful for generic drivers such as 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 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.
...@@ -68,20 +68,6 @@ config AD799X_RING_BUFFER ...@@ -68,20 +68,6 @@ config AD799X_RING_BUFFER
Say yes here to include ring buffer support in the AD799X Say yes here to include ring buffer support in the AD799X
ADC driver. 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 config AD7887
tristate "Analog Devices AD7887 ADC driver" tristate "Analog Devices AD7887 ADC driver"
depends on SPI depends on SPI
......
...@@ -17,10 +17,6 @@ ad799x-y := ad799x_core.o ...@@ -17,10 +17,6 @@ ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o
obj-$(CONFIG_AD799X) += ad799x.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-y := ad7887_core.o
ad7887-$(CONFIG_IIO_BUFFER) += ad7887_ring.o ad7887-$(CONFIG_IIO_BUFFER) += ad7887_ring.o
obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7887) += ad7887.o
......
/*
* 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_ */
/*
* 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);
}
...@@ -42,40 +42,17 @@ static ssize_t iio_hwmon_read_val(struct device *dev, ...@@ -42,40 +42,17 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
long result; int result;
int val, ret, scaleint, scalepart; int ret;
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct iio_hwmon_state *state = dev_get_drvdata(dev); struct iio_hwmon_state *state = dev_get_drvdata(dev);
/* ret = iio_read_channel_processed(&state->channels[sattr->index],
* No locking between this pair, so theoretically possible &result);
* the scale has changed.
*/
ret = iio_read_channel_raw(&state->channels[sattr->index],
&val);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = iio_read_channel_scale(&state->channels[sattr->index], return sprintf(buf, "%d\n", result);
&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);
} }
static void iio_hwmon_free_attrs(struct iio_hwmon_state *st) static void iio_hwmon_free_attrs(struct iio_hwmon_state *st)
......
...@@ -14,14 +14,18 @@ ...@@ -14,14 +14,18 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/gptimers.h> #include <asm/gptimers.h>
#include <asm/portmux.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/trigger.h> #include <linux/iio/trigger.h>
#include "iio-trig-bfin-timer.h"
struct bfin_timer { struct bfin_timer {
unsigned short id, bit; unsigned short id, bit;
unsigned long irqbit; unsigned long irqbit;
int irq; int irq;
int pin;
}; };
/* /*
...@@ -30,22 +34,22 @@ struct bfin_timer { ...@@ -30,22 +34,22 @@ struct bfin_timer {
*/ */
static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = { static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
{TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0}, {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0, P_TMR0},
{TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1}, {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1, P_TMR1},
{TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2}, {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2, P_TMR2},
#if (MAX_BLACKFIN_GPTIMERS > 3) #if (MAX_BLACKFIN_GPTIMERS > 3)
{TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3}, {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3, P_TMR3},
{TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4}, {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4, P_TMR4},
{TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5}, {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5, P_TMR5},
{TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6}, {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6, P_TMR6},
{TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7}, {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7, P_TMR7},
#endif #endif
#if (MAX_BLACKFIN_GPTIMERS > 8) #if (MAX_BLACKFIN_GPTIMERS > 8)
{TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8}, {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8, P_TMR8},
{TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9}, {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9, P_TMR9},
{TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10}, {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10},
#if (MAX_BLACKFIN_GPTIMERS > 11) #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
#endif #endif
}; };
...@@ -54,15 +58,33 @@ struct bfin_tmr_state { ...@@ -54,15 +58,33 @@ struct bfin_tmr_state {
struct iio_trigger *trig; struct iio_trigger *trig;
struct bfin_timer *t; struct bfin_timer *t;
unsigned timer_num; unsigned timer_num;
bool output_enable;
unsigned int duty;
int irq; 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, static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count) struct device_attribute *attr, const char *buf, size_t count)
{ {
struct iio_trigger *trig = to_iio_trigger(dev); struct iio_trigger *trig = to_iio_trigger(dev);
struct bfin_tmr_state *st = trig->private_data; struct bfin_tmr_state *st = trig->private_data;
long val; unsigned long val;
bool enabled;
int ret; int ret;
ret = strict_strtoul(buf, 10, &val); ret = strict_strtoul(buf, 10, &val);
...@@ -74,20 +96,25 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, ...@@ -74,20 +96,25 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
goto error_ret; goto error_ret;
} }
disable_gptimers(st->t->bit); enabled = get_enabled_gptimers() & st->t->bit;
if (enabled)
disable_gptimers(st->t->bit);
if (!val) if (!val)
goto error_ret; goto error_ret;
val = get_sclk() / val; val = get_sclk() / val;
if (val <= 4) { if (val <= 4 || val <= st->duty) {
ret = -EINVAL; ret = -EINVAL;
goto error_ret; goto error_ret;
} }
set_gptimer_period(st->t->id, val); set_gptimer_period(st->t->id, val);
set_gptimer_pwidth(st->t->id, 1); set_gptimer_pwidth(st->t->id, val - st->duty);
enable_gptimers(st->t->bit);
if (enabled)
enable_gptimers(st->t->bit);
error_ret: error_ret:
return ret ? ret : count; return ret ? ret : count;
...@@ -99,9 +126,15 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev, ...@@ -99,9 +126,15 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
{ {
struct iio_trigger *trig = to_iio_trigger(dev); struct iio_trigger *trig = to_iio_trigger(dev);
struct bfin_tmr_state *st = trig->private_data; struct bfin_tmr_state *st = trig->private_data;
unsigned int period = get_gptimer_period(st->t->id);
unsigned long val;
if (period == 0)
val = 0;
else
val = get_sclk() / get_gptimer_period(st->t->id);
return sprintf(buf, "%lu\n", return sprintf(buf, "%lu\n", val);
get_sclk() / get_gptimer_period(st->t->id));
} }
static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show, 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[] = { ...@@ -121,7 +154,6 @@ static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = {
NULL NULL
}; };
static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid) static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
{ {
struct bfin_tmr_state *st = devid; struct bfin_tmr_state *st = devid;
...@@ -145,11 +177,14 @@ static int iio_bfin_tmr_get_number(int irq) ...@@ -145,11 +177,14 @@ static int iio_bfin_tmr_get_number(int irq)
static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = { static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.set_trigger_state = iio_bfin_tmr_set_state,
}; };
static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) 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; struct bfin_tmr_state *st;
unsigned int config;
int ret; int ret;
st = kzalloc(sizeof(*st), GFP_KERNEL); st = kzalloc(sizeof(*st), GFP_KERNEL);
...@@ -193,13 +228,43 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) ...@@ -193,13 +228,43 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
goto out4; 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", dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
st->timer_num, st->irq); st->timer_num, st->irq);
platform_set_drvdata(pdev, st); platform_set_drvdata(pdev, st);
return 0; return 0;
out_free_irq:
free_irq(st->irq, st);
out4: out4:
iio_trigger_unregister(st->trig); iio_trigger_unregister(st->trig);
out2: out2:
...@@ -215,6 +280,8 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev) ...@@ -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); struct bfin_tmr_state *st = platform_get_drvdata(pdev);
disable_gptimers(st->t->bit); disable_gptimers(st->t->bit);
if (st->output_enable)
peripheral_free(st->t->pin);
free_irq(st->irq, st); free_irq(st->irq, st);
iio_trigger_unregister(st->trig); iio_trigger_unregister(st->trig);
iio_trigger_put(st->trig); iio_trigger_put(st->trig);
......
#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
...@@ -61,7 +61,7 @@ void iio_channel_release_all(struct iio_channel *chan); ...@@ -61,7 +61,7 @@ void iio_channel_release_all(struct iio_channel *chan);
/** /**
* iio_read_channel_raw() - read from a given channel * iio_read_channel_raw() - read from a given channel
* @channel: The channel being queried. * @chan: The channel being queried.
* @val: Value read back. * @val: Value read back.
* *
* Note raw reads from iio channels are in adc counts and hence * 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); ...@@ -70,6 +70,21 @@ void iio_channel_release_all(struct iio_channel *chan);
int iio_read_channel_raw(struct iio_channel *chan, int iio_read_channel_raw(struct iio_channel *chan,
int *val); 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 * iio_get_channel_type() - get the type of a channel
* @channel: The channel being queried. * @channel: The channel being queried.
...@@ -82,7 +97,7 @@ int iio_get_channel_type(struct iio_channel *channel, ...@@ -82,7 +97,7 @@ int iio_get_channel_type(struct iio_channel *channel,
/** /**
* iio_read_channel_scale() - read the scale value for a 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. * @val: First part of value read back.
* @val2: Second 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, ...@@ -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 iio_read_channel_scale(struct iio_channel *chan, int *val,
int *val2); 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 #endif
...@@ -40,6 +40,8 @@ enum iio_chan_info_enum { ...@@ -40,6 +40,8 @@ enum iio_chan_info_enum {
#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2) #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_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 \ #define IIO_CHAN_INFO_RAW_SEPARATE_BIT \
IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW) IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
...@@ -261,6 +263,21 @@ struct iio_chan_spec { ...@@ -261,6 +263,21 @@ struct iio_chan_spec {
unsigned differential:1; 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) \ #define IIO_ST(si, rb, sb, sh) \
{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh } { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
......
...@@ -57,5 +57,6 @@ enum iio_modifier { ...@@ -57,5 +57,6 @@ enum iio_modifier {
#define IIO_VAL_INT_PLUS_MICRO 2 #define IIO_VAL_INT_PLUS_MICRO 2
#define IIO_VAL_INT_PLUS_NANO 3 #define IIO_VAL_INT_PLUS_NANO 3
#define IIO_VAL_INT_PLUS_MICRO_DB 4 #define IIO_VAL_INT_PLUS_MICRO_DB 4
#define IIO_VAL_FRACTIONAL 10
#endif /* _IIO_TYPES_H_ */ #endif /* _IIO_TYPES_H_ */
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment