Commit dc4871ad authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Jonathan Cameron

staging:iio:ad7298: Squash everything into one file

The recent cleanups have decimated the drivers code size by quite a bit. It is
only a few hundred lines in total now. Putting everything into one file also
allows to reduce the code size a bit more by removing a few lines of boilerplate
code. The only functional change made by this patch is that we now always
include buffer support, instead of making it optional. This is more consistent
with what we do for other drivers.
Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 01a10e04
...@@ -13,7 +13,8 @@ config AD7291 ...@@ -13,7 +13,8 @@ config AD7291
config AD7298 config AD7298
tristate "Analog Devices AD7298 ADC driver" tristate "Analog Devices AD7298 ADC driver"
depends on SPI depends on SPI
select IIO_TRIGGERED_BUFFER if IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help help
Say yes here to build support for Analog Devices AD7298 Say yes here to build support for Analog Devices AD7298
8 Channel ADC with temperature sensor. 8 Channel ADC with temperature sensor.
......
...@@ -12,8 +12,6 @@ ad799x-y := ad799x_core.o ...@@ -12,8 +12,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
ad7298-y := ad7298_core.o
ad7298-$(CONFIG_IIO_BUFFER) += ad7298_ring.o
obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7291) += ad7291.o
......
...@@ -15,13 +15,49 @@ ...@@ -15,13 +15,49 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h>
#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 "ad7298.h" #include "ad7298.h"
#define AD7298_WRITE (1 << 15) /* write to the control register */
#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
#define AD7298_EXTREF (1 << 2) /* external reference enable */
#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
#define AD7298_PDD (1 << 0) /* partial power down enable */
#define AD7298_MAX_CHAN 8
#define AD7298_BITS 12
#define AD7298_STORAGE_BITS 16
#define AD7298_INTREF_mV 2500
#define AD7298_CH_TEMP 9
#define RES_MASK(bits) ((1 << (bits)) - 1)
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
struct spi_transfer scan_single_xfer[3];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned short rx_buf[12] ____cacheline_aligned;
unsigned short tx_buf[2];
};
#define AD7298_V_CHAN(index) \ #define AD7298_V_CHAN(index) \
{ \ { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
...@@ -66,6 +102,84 @@ static const struct iio_chan_spec ad7298_channels[] = { ...@@ -66,6 +102,84 @@ static const struct iio_chan_spec ad7298_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(8), IIO_CHAN_SOFT_TIMESTAMP(8),
}; };
/**
* ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7298_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7298_state *st = iio_priv(indio_dev);
int i, m;
unsigned short command;
int scan_count;
/* Now compute overall size */
scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
if (test_bit(i, active_scan_mask))
command |= m;
st->tx_buf[0] = cpu_to_be16(command);
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = 2;
st->ring_xfer[0].cs_change = 1;
st->ring_xfer[1].tx_buf = &st->tx_buf[1];
st->ring_xfer[1].len = 2;
st->ring_xfer[1].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
for (i = 0; i < scan_count; i++) {
st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 2].len = 2;
st->ring_xfer[i + 2].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7298_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7298_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
s64 time_ns = 0;
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
{ {
int ret; int ret;
...@@ -231,7 +345,8 @@ static int __devinit ad7298_probe(struct spi_device *spi) ...@@ -231,7 +345,8 @@ static int __devinit ad7298_probe(struct spi_device *spi)
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg);
ret = ad7298_register_ring_funcs_and_init(indio_dev); ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7298_trigger_handler, NULL);
if (ret) if (ret)
goto error_disable_reg; goto error_disable_reg;
...@@ -242,7 +357,7 @@ static int __devinit ad7298_probe(struct spi_device *spi) ...@@ -242,7 +357,7 @@ static int __devinit ad7298_probe(struct spi_device *spi)
return 0; return 0;
error_cleanup_ring: error_cleanup_ring:
ad7298_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg: error_disable_reg:
if (st->ext_ref) if (st->ext_ref)
regulator_disable(st->reg); regulator_disable(st->reg);
...@@ -261,7 +376,7 @@ static int __devexit ad7298_remove(struct spi_device *spi) ...@@ -261,7 +376,7 @@ static int __devexit ad7298_remove(struct spi_device *spi)
struct ad7298_state *st = iio_priv(indio_dev); struct ad7298_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
ad7298_ring_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
if (st->ext_ref) { if (st->ext_ref) {
regulator_disable(st->reg); regulator_disable(st->reg);
regulator_put(st->reg); regulator_put(st->reg);
......
...@@ -9,23 +9,6 @@ ...@@ -9,23 +9,6 @@
#ifndef IIO_ADC_AD7298_H_ #ifndef IIO_ADC_AD7298_H_
#define IIO_ADC_AD7298_H_ #define IIO_ADC_AD7298_H_
#define AD7298_WRITE (1 << 15) /* write to the control register */
#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
#define AD7298_EXTREF (1 << 2) /* external reference enable */
#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
#define AD7298_PDD (1 << 0) /* partial power down enable */
#define AD7298_MAX_CHAN 8
#define AD7298_BITS 12
#define AD7298_STORAGE_BITS 16
#define AD7298_INTREF_mV 2500
#define AD7298_CH_TEMP 9
#define RES_MASK(bits) ((1 << (bits)) - 1)
/** /**
* struct ad7298_platform_data - Platform data for the ad7298 ADC driver * struct ad7298_platform_data - Platform data for the ad7298 ADC driver
* @ext_ref: Whether to use an external reference voltage. * @ext_ref: Whether to use an external reference voltage.
...@@ -34,40 +17,4 @@ struct ad7298_platform_data { ...@@ -34,40 +17,4 @@ struct ad7298_platform_data {
bool ext_ref; bool ext_ref;
}; };
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
struct spi_transfer scan_single_xfer[3];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned short rx_buf[12] ____cacheline_aligned;
unsigned short tx_buf[2];
};
#ifdef CONFIG_IIO_BUFFER
int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev);
void ad7298_ring_cleanup(struct iio_dev *indio_dev);
int ad7298_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask);
#else /* CONFIG_IIO_BUFFER */
static inline int
ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return 0;
}
static inline void ad7298_ring_cleanup(struct iio_dev *indio_dev)
{
}
#define ad7298_update_scan_mode NULL
#endif /* CONFIG_IIO_BUFFER */
#endif /* IIO_ADC_AD7298_H_ */ #endif /* IIO_ADC_AD7298_H_ */
/*
* AD7298 SPI ADC driver
*
* Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.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 "ad7298.h"
/**
* ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
int ad7298_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7298_state *st = iio_priv(indio_dev);
int i, m;
unsigned short command;
int scan_count;
/* Now compute overall size */
scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1)
if (test_bit(i, active_scan_mask))
command |= m;
st->tx_buf[0] = cpu_to_be16(command);
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = 2;
st->ring_xfer[0].cs_change = 1;
st->ring_xfer[1].tx_buf = &st->tx_buf[1];
st->ring_xfer[1].len = 2;
st->ring_xfer[1].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg);
for (i = 0; i < scan_count; i++) {
st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 2].len = 2;
st->ring_xfer[i + 2].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7298_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7298_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
s64 time_ns = 0;
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, NULL,
&ad7298_trigger_handler, NULL);
}
void ad7298_ring_cleanup(struct iio_dev *indio_dev)
{
iio_triggered_buffer_cleanup(indio_dev);
}
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