diff options
author | David Hunt <davidx.hunt@intel.com> | 2014-06-23 16:07:23 +0200 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2015-06-02 14:59:05 -0700 |
commit | f4251192d6f20c8895d2c7d23dd621ea05fbe33c (patch) | |
tree | 6d68dbfe111efb935e7448714729a6c9ad5d29e4 | |
parent | 7bb1e8d184acb3e3b87a6addb9ea66660a0faf52 (diff) | |
download | edison-v3.10-f4251192d6f20c8895d2c7d23dd621ea05fbe33c.tar.gz |
adc: enabling buffered read support for ti-ads7955
Add support for programming of a sequence of channel reads, and a
mechanism for triggering those reads to get back one packet containing
all reads.
Signed-off-by: David Hunt <davidx.hunt@intel.com>
-rw-r--r-- | arch/x86/configs/i386_edison_defconfig | 2 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads7955.c | 230 |
2 files changed, 189 insertions, 43 deletions
diff --git a/arch/x86/configs/i386_edison_defconfig b/arch/x86/configs/i386_edison_defconfig index 0099f394152..4e9a57ed1f8 100644 --- a/arch/x86/configs/i386_edison_defconfig +++ b/arch/x86/configs/i386_edison_defconfig @@ -2982,7 +2982,7 @@ CONFIG_STAGING=y # # CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set # CONFIG_IIO_GPIO_TRIGGER is not set -# CONFIG_IIO_SYSFS_TRIGGER is not set +CONFIG_IIO_SYSFS_TRIGGER=m # CONFIG_IIO_SIMPLE_DUMMY is not set # CONFIG_ZSMALLOC is not set # CONFIG_FB_SM7XX is not set diff --git a/drivers/iio/adc/ti-ads7955.c b/drivers/iio/adc/ti-ads7955.c index 10791165ee6..fde230b92b2 100644 --- a/drivers/iio/adc/ti-ads7955.c +++ b/drivers/iio/adc/ti-ads7955.c @@ -7,6 +7,16 @@ * Licensed under the GPL-2. */ +/* + * [FIXME] + * Notes: This version of the ti-ads7955 driver is written with a couple of + * workarounds for the functionality of the SPI driver on Edison at the time + * of writing. + * Issue 1: The CS is pushed low between every frame + * Issue 2: spi_message_add_tail() can only be called once in the driver. + * Subsequent messages are ignored. +*/ + #include <linux/device.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -17,7 +27,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/interrupt.h> - +#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> @@ -26,45 +36,63 @@ #include <linux/platform_data/ti-ads7955.h> -#define ADS7955_EXTREF 2.5 +#define ADS7955_EXTREF true +#define SPI_MAX_SPEED_HZ 20000000 +#define SPI_BITS_PER_WORD 16 + +#define ADS7955_MANUAL_MODE (0x1 << 12) /* Selects Manual Mode */ +#define ADS7955_AUTO1_MODE (0x2 << 12) /* Selects Auto Mode 1 */ +#define ADS7955_AUTO2_MODE (0x3 << 12) /* Selects Auto Mode 2 */ +#define ADS7955_AUTO1_PROGRAM (0x8 << 12) /* Programming Auto Mode 1 */ +#define ADS7955_AUTO2_PROGRAM (0x9 << 12) /* Programming Auto Mode 2 */ -#define ADS7955_MANUAL_MODE (1 << 12) /* Selects Manual Mode */ -#define ADS7955_CONFIG (1 << 11) /* Enable programming bits DI06-00*/ -#define ADS7955_CHANNEL(x) ((x) << 7) /* Channel select (DI10-07) */ +#define ADS7955_CONFIG BIT(11) /* program bits DI06-00 */ +#define ADS7955_AUTO1_RESET BIT(10) /* Reset to first channel */ +#define ADS7955_CHANNEL(x) ((x & 0xf) << 7)/* Channel select (DI10-07) */ -#define ADS7955_RANGE_1 0 /* Selects 2.5V input range (Range 1)*/ -#define ADS7955_RANGE_2 (1 << 6)/* Selects 5.0V input range (Range 2)*/ +#define ADS7955_RANGE_1 0 /* Selects 2.5V input range */ +#define ADS7955_RANGE_2 BIT(6) /* Selects 5.0V input range */ -#define ADS7955_POWER_NORMAL 0 /* No Powerdown */ -#define ADS7955_POWER_DOWN (1 << 5) /* Powerdown on 16th fall-edge of SCLK*/ +#define ADS7955_POWER_NORMAL 0 /* No Powerdown */ +#define ADS7955_POWER_DOWN BIT(5) /* Powerdown on last edge */ -#define ADS7955_GET_CONVERSION 0 /* Powerdown on 16th fall-edge of SCLK*/ -#define ADS7955_GET_GPIO (1 << 4)/* Powerdown on 16th fall-edge of SCLK*/ +#define ADS7955_GET_CONVERSION 0 /* High bits have ch index*/ +#define ADS7955_GET_GPIO BIT(4) /* High bits have GPIO bits */ #define ADS7955_SET_READ (ADS7955_MANUAL_MODE | ADS7955_CONFIG | \ ADS7955_RANGE_2 | ADS7955_POWER_NORMAL | \ ADS7955_GET_CONVERSION) -#define ADS7955_MAX_CHAN 8 -#define ADS7955_BITS 10 -#define ADS7955_STORAGE_BITS 12 -#define ADS7955_INTREF_mV 3300 +#define ADS7955_READ_AUTO1 (ADS7955_AUTO1_MODE | ADS7955_CONFIG | \ + ADS7955_RANGE_2 | ADS7955_POWER_NORMAL | \ + ADS7955_GET_CONVERSION) +#define ADS7955_MAX_CHAN 8 +#define ADS7955_BITS 12 +#define ADS7955_STORAGE_BITS 16 +/* + * Define the Reference Voltage for the board on which this ADC is used. + * May change depending on jumper settings or wiring configuration. + */ +#define ADS7955_INTREF_mV 5000 +#define SPI_MSG_MAX_LEN 20 /* 8 channels plus timestamp */ #define RES_MASK(bits) ((1 << (bits)) - 1) struct ads7955_state { - struct spi_device *spi; - struct regulator *reg; - unsigned ext_ref; - struct spi_transfer scan_single_xfer[3]; - struct spi_message scan_single_msg; + struct spi_device *spi; + struct regulator *reg; + unsigned ext_ref; + struct spi_transfer ring_xfer[10]; + struct spi_transfer scan_single_xfer[3]; + struct spi_message ring_msg; + struct spi_message scan_single_msg; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. */ - __be16 rx_buf[1] ____cacheline_aligned; - __be16 tx_buf[1]; + __u16 rx_buf[SPI_MSG_MAX_LEN] ____cacheline_aligned; + __u16 tx_buf[SPI_MSG_MAX_LEN]; }; #define ADS7955_V_CHAN(index) \ @@ -78,9 +106,9 @@ struct ads7955_state { .scan_index = index, \ .scan_type = { \ .sign = 'u', \ - .realbits = 10, \ - .storagebits = 16, \ - .endianness = IIO_BE, \ + .realbits = ADS7955_BITS, \ + .storagebits = ADS7955_STORAGE_BITS, \ + .endianness = IIO_CPU, \ }, \ } @@ -96,18 +124,124 @@ static const struct iio_chan_spec ads7955_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(8), }; +/** + * ads7955_update_scan_mode() setup the spi transfer buffer for the scan mask + **/ +static int ads7955_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct ads7955_state *st = iio_priv(indio_dev); + int i, ret; + unsigned short channel_count; + + /* + * For programming the auto1 mode, we need to send two words, one to + * specify program mode, and the other to give a bitmask of channels + * to be read when reading the auto sequence. + */ + /* + * [FIXME] + * Workaround: Build up a custom SPI message containing all required + * frames (including space for expected responses), and send as one + * SPI messge. This is to get around the issue that the current SPI + * driver only supports the first 'spi_message_add_tail' call. + */ + st->tx_buf[0] = ADS7955_AUTO1_PROGRAM; + st->tx_buf[1] = (unsigned short)*active_scan_mask; + st->tx_buf[2] = (ADS7955_SET_READ | ADS7955_POWER_DOWN); + + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + return ret; + + /* + * So now we've told the hardware about the channels we want to sample, + * now we set up the message sequence for when we're triggered. + */ + /* + * [FIXME] + * Workaround: Build up a custom SPI message containing all required + * frames (including space for expected responses), and send as one + * SPI messge. This is to get around the issue that the current SPI + * driver only supports the first 'spi_message_add_tail' call. + */ + channel_count = 0; + for (i = 0; i < ADS7955_MAX_CHAN; i++) { + if (test_bit(i, active_scan_mask)) { + if (channel_count == 0) + st->tx_buf[channel_count] = (ADS7955_READ_AUTO1 + | ADS7955_AUTO1_RESET); + else + st->tx_buf[channel_count] = + (ADS7955_READ_AUTO1); + channel_count++; + } + } + + /* Put in some extra tx frames to allow us to get the + rx frames (behind tx by two frames) */ + st->tx_buf[channel_count++] = (ADS7955_READ_AUTO1); + st->tx_buf[channel_count++] = (ADS7955_READ_AUTO1 | + ADS7955_POWER_DOWN); + + st->ring_xfer[0].tx_buf = &st->tx_buf[0]; + st->ring_xfer[0].rx_buf = &st->rx_buf[0]; + st->ring_xfer[0].len = channel_count * 2; + spi_message_init(&st->ring_msg); + spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); + return 0; +} + +/** + * ads7955_trigger_handler() bh of trigger launched polling to ring buffer + **/ +static irqreturn_t ads7955_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ads7955_state *st = iio_priv(indio_dev); + u8 *return_data = (u8 *)&(st->rx_buf[2]); + s64 time_ns = 0; + int ret; + + ret = spi_sync(st->spi, &st->ring_msg); + if (ret) + return IRQ_HANDLED; + + if (indio_dev->scan_timestamp) { + time_ns = iio_get_time_ns(); + memcpy(return_data + + indio_dev->scan_bytes - sizeof(s64), + &time_ns, sizeof(time_ns)); + } + + iio_push_to_buffers(indio_dev, return_data); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int ads7955_scan_direct(struct ads7955_state *st, unsigned ch) { - int ret, count = 3; + int ret; + /* + * [FIXME] + * Workaround: Build up a custom SPI message containing all required + * frames (including space for expected responses), and send as one + * SPI messge. This is to get around the issue that the current SPI + * driver only supports the first 'spi_message_add_tail' call. + */ st->tx_buf[0] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch)); - while (count--) { - ret = spi_sync(st->spi, &st->scan_single_msg); - if (ret) - return ret; - } + st->tx_buf[1] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch)); + st->tx_buf[2] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch) | + ADS7955_POWER_DOWN); - return st->rx_buf[0]; + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + return ret; + return st->rx_buf[2]; } @@ -143,12 +277,10 @@ static int ads7955_read_raw(struct iio_dev *indio_dev, else ret = ads7955_scan_direct(st, chan->address); mutex_unlock(&indio_dev->mlock); - if (ret < 0) return ret; *val = ret & RES_MASK(ADS7955_BITS); - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->type) { @@ -159,15 +291,13 @@ static int ads7955_read_raw(struct iio_dev *indio_dev, default: return -EINVAL; } - case IIO_CHAN_INFO_OFFSET: - *val = 1093 - 2732500 / ads7955_get_ref_voltage(st); - return IIO_VAL_INT; } return -EINVAL; } static const struct iio_info ads7955_info = { .read_raw = &ads7955_read_raw, + .update_scan_mode = ads7955_update_scan_mode, .driver_module = THIS_MODULE, }; @@ -208,24 +338,39 @@ static int ads7955_probe(struct spi_device *spi) indio_dev->num_channels = ARRAY_SIZE(ads7955_channels); indio_dev->info = &ads7955_info; - /* Setup default SPI comms parameters */ - spi->bits_per_word = 16; - spi->max_speed_hz = 20000000; + /* + * Setup default message + * [FIXME] + * Workaround: Send each frame as 16 bits to get over the fact that + * the current SPI hardware pulls CS low between every frame. + */ + spi->bits_per_word = SPI_BITS_PER_WORD; + spi->max_speed_hz = SPI_MAX_SPEED_HZ; spi_setup(spi); st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; st->scan_single_xfer[0].rx_buf = &st->rx_buf[0]; - st->scan_single_xfer[0].len = 2; + st->scan_single_xfer[0].len = 6; spi_message_init(&st->scan_single_msg); spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ads7955_trigger_handler, NULL); + if (ret) { + dev_warn(&indio_dev->dev, + "Failed to set up iio_triggered_buffer_setup\n"); + goto error_disable_reg; + } + ret = iio_device_register(indio_dev); if (ret) - goto error_disable_reg; + goto error_cleanup_ring; return 0; +error_cleanup_ring: + iio_triggered_buffer_cleanup(indio_dev); error_disable_reg: if (st->ext_ref) regulator_disable(st->reg); @@ -244,6 +389,7 @@ static int ads7955_remove(struct spi_device *spi) struct ads7955_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); if (st->ext_ref) { regulator_disable(st->reg); regulator_put(st->reg); |