Commit 3ce14acb authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-3.8e' of...

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

From Jonathan:

  "Fifth round of new IIO drivers, cleanups and fixes for the 3.8 cycle.

  Here we have a number of minor fixes.
  * a quirk for the hid sensor driver should be a boolean option.
  * return an error for a failed memdup in the hid sensor driver.
  * Fix a return value in adt7410.
  * A double free in the IIO event infrastructure.
  * Disabling interrupts in tsl2563 was wrong (never been correct!)
  * Incorrect signature for the iio_buffer_register stub
  * Incorrect return for isl29018 write_raw callback.
  * A number of minor fixes as part of the various rework series.

  New drivers and major rework.
  * Introduce and use extensively an adis library for numerous spi
    Analog Devices mems sensors.  This then moves out of staging.
  * Lots of new stuff then added to this library to support newer
    sensors.
  * New drivers for ADIS16136 and ADIS16480 and similar.
  * Core support for barometric pressure sensors.
  * ad7298 cleanup and move out of staging.

  The bulk of this is from Lars-Peter Clausen.  He's been rather
  busy!"
parents acf1cf6a be7fd3b8
...@@ -189,6 +189,14 @@ Description: ...@@ -189,6 +189,14 @@ Description:
A computed peak value based on the sum squared magnitude of A computed peak value based on the sum squared magnitude of
the underlying value in the specified directions. the underlying value in the specified directions.
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_raw
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_raw
KernelVersion: 3.8
Contact: linux-iio@vger.kernel.org
Description:
Raw pressure measurement from channel Y. Units after
application of scale and offset are kilopascal.
What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
...@@ -197,6 +205,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset ...@@ -197,6 +205,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -226,6 +236,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale ...@@ -226,6 +236,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -245,6 +257,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias ...@@ -245,6 +257,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibbias
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -262,6 +276,8 @@ What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale ...@@ -262,6 +276,8 @@ What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -275,6 +291,8 @@ What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available ...@@ -275,6 +291,8 @@ What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
What: /sys/.../iio:deviceX/out_voltageX_scale_available What: /sys/.../iio:deviceX/out_voltageX_scale_available
What: /sys/.../iio:deviceX/out_altvoltageX_scale_available What: /sys/.../iio:deviceX/out_altvoltageX_scale_available
What: /sys/.../iio:deviceX/in_capacitance_scale_available What: /sys/.../iio:deviceX/in_capacitance_scale_available
What: /sys/.../iio:deviceX/in_pressure_scale_available
What: /sys/.../iio:deviceX/in_pressureY_scale_available
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -694,6 +712,8 @@ What: /sys/.../buffer/scan_elements/in_voltageY_en ...@@ -694,6 +712,8 @@ What: /sys/.../buffer/scan_elements/in_voltageY_en
What: /sys/.../buffer/scan_elements/in_voltageY-voltageZ_en What: /sys/.../buffer/scan_elements/in_voltageY-voltageZ_en
What: /sys/.../buffer/scan_elements/in_incli_x_en What: /sys/.../buffer/scan_elements/in_incli_x_en
What: /sys/.../buffer/scan_elements/in_incli_y_en What: /sys/.../buffer/scan_elements/in_incli_y_en
What: /sys/.../buffer/scan_elements/in_pressureY_en
What: /sys/.../buffer/scan_elements/in_pressure_en
KernelVersion: 2.6.37 KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -707,6 +727,8 @@ What: /sys/.../buffer/scan_elements/in_voltageY_type ...@@ -707,6 +727,8 @@ What: /sys/.../buffer/scan_elements/in_voltageY_type
What: /sys/.../buffer/scan_elements/in_voltage_type What: /sys/.../buffer/scan_elements/in_voltage_type
What: /sys/.../buffer/scan_elements/in_voltageY_supply_type What: /sys/.../buffer/scan_elements/in_voltageY_supply_type
What: /sys/.../buffer/scan_elements/in_timestamp_type What: /sys/.../buffer/scan_elements/in_timestamp_type
What: /sys/.../buffer/scan_elements/in_pressureY_type
What: /sys/.../buffer/scan_elements/in_pressure_type
KernelVersion: 2.6.37 KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -751,6 +773,8 @@ What: /sys/.../buffer/scan_elements/in_magn_z_index ...@@ -751,6 +773,8 @@ What: /sys/.../buffer/scan_elements/in_magn_z_index
What: /sys/.../buffer/scan_elements/in_incli_x_index What: /sys/.../buffer/scan_elements/in_incli_x_index
What: /sys/.../buffer/scan_elements/in_incli_y_index What: /sys/.../buffer/scan_elements/in_incli_y_index
What: /sys/.../buffer/scan_elements/in_timestamp_index What: /sys/.../buffer/scan_elements/in_timestamp_index
What: /sys/.../buffer/scan_elements/in_pressureY_index
What: /sys/.../buffer/scan_elements/in_pressure_index
KernelVersion: 2.6.37 KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
......
...@@ -63,11 +63,12 @@ config IIO_CONSUMERS_PER_TRIGGER ...@@ -63,11 +63,12 @@ config IIO_CONSUMERS_PER_TRIGGER
source "drivers/iio/accel/Kconfig" source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig" source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/common/Kconfig" source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig" source "drivers/iio/gyro/Kconfig"
source "drivers/iio/imu/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig" source "drivers/iio/magnetometer/Kconfig"
endif # IIO endif # IIO
...@@ -14,9 +14,10 @@ obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o ...@@ -14,9 +14,10 @@ obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/ obj-y += accel/
obj-y += adc/ obj-y += adc/
obj-y += amplifiers/ obj-y += amplifiers/
obj-y += light/
obj-y += frequency/
obj-y += dac/
obj-y += common/ obj-y += common/
obj-y += dac/
obj-y += gyro/ obj-y += gyro/
obj-y += frequency/
obj-y += imu/
obj-y += light/
obj-y += magnetometer/ obj-y += magnetometer/
...@@ -306,10 +306,10 @@ static int __devinit hid_accel_3d_probe(struct platform_device *pdev) ...@@ -306,10 +306,10 @@ static int __devinit hid_accel_3d_probe(struct platform_device *pdev)
goto error_free_dev; goto error_free_dev;
} }
channels = kmemdup(accel_3d_channels, channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
sizeof(accel_3d_channels), GFP_KERNEL);
GFP_KERNEL);
if (!channels) { if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n"); dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev; goto error_free_dev;
} }
......
...@@ -18,6 +18,18 @@ config AD7266 ...@@ -18,6 +18,18 @@ config AD7266
Say yes here to build support for Analog Devices AD7265 and AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266
ADCs. ADCs.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7298
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7298.
config AD7791 config AD7791
tristate "Analog Devices AD7791 ADC driver" tristate "Analog Devices AD7791 ADC driver"
depends on SPI depends on SPI
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
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_AD7298) += ad7298.o
obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7887) += ad7887.o
......
...@@ -15,12 +15,48 @@ ...@@ -15,12 +15,48 @@
#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 "ad7298.h" #include <linux/iio/triggered_buffer.h>
#include <linux/platform_data/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.
*/
__be16 rx_buf[12] ____cacheline_aligned;
__be16 tx_buf[2];
};
#define AD7298_V_CHAN(index) \ #define AD7298_V_CHAN(index) \
{ \ { \
...@@ -35,6 +71,7 @@ ...@@ -35,6 +71,7 @@
.sign = 'u', \ .sign = 'u', \
.realbits = 12, \ .realbits = 12, \
.storagebits = 16, \ .storagebits = 16, \
.endianness = IIO_BE, \
}, \ }, \
} }
...@@ -44,7 +81,8 @@ static const struct iio_chan_spec ad7298_channels[] = { ...@@ -44,7 +81,8 @@ static const struct iio_chan_spec ad7298_channels[] = {
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = AD7298_CH_TEMP, .address = AD7298_CH_TEMP,
.scan_index = -1, .scan_index = -1,
.scan_type = { .scan_type = {
...@@ -64,6 +102,84 @@ static const struct iio_chan_spec ad7298_channels[] = { ...@@ -64,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;
...@@ -79,7 +195,7 @@ static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) ...@@ -79,7 +195,7 @@ static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch)
static int ad7298_scan_temp(struct ad7298_state *st, int *val) static int ad7298_scan_temp(struct ad7298_state *st, int *val)
{ {
int tmp, ret; int ret;
__be16 buf; __be16 buf;
buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
...@@ -101,24 +217,24 @@ static int ad7298_scan_temp(struct ad7298_state *st, int *val) ...@@ -101,24 +217,24 @@ static int ad7298_scan_temp(struct ad7298_state *st, int *val)
if (ret) if (ret)
return ret; return ret;
tmp = be16_to_cpu(buf) & RES_MASK(AD7298_BITS); *val = sign_extend32(be16_to_cpu(buf), 11);
/* return 0;
* One LSB of the ADC corresponds to 0.25 deg C. }
* The temperature reading is in 12-bit twos complement format
*/
if (tmp & (1 << (AD7298_BITS - 1))) { static int ad7298_get_ref_voltage(struct ad7298_state *st)
tmp = (4096 - tmp) * 250; {
tmp -= (2 * tmp); int vref;
if (st->ext_ref) {
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
return vref / 1000;
} else { } else {
tmp *= 250; /* temperature in milli degrees Celsius */ return AD7298_INTREF_mV;
} }
*val = tmp;
return 0;
} }
static int ad7298_read_raw(struct iio_dev *indio_dev, static int ad7298_read_raw(struct iio_dev *indio_dev,
...@@ -129,7 +245,6 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, ...@@ -129,7 +245,6 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
{ {
int ret; int ret;
struct ad7298_state *st = iio_priv(indio_dev); struct ad7298_state *st = iio_priv(indio_dev);
unsigned int scale_uv;
switch (m) { switch (m) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
...@@ -154,17 +269,19 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, ...@@ -154,17 +269,19 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS; *val = ad7298_get_ref_voltage(st);
*val = scale_uv / 1000; *val2 = chan->scan_type.realbits;
*val2 = (scale_uv % 1000) * 1000; return IIO_VAL_FRACTIONAL_LOG2;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 1; *val = ad7298_get_ref_voltage(st);
*val2 = 0; *val2 = 10;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_FRACTIONAL;
default: default:
return -EINVAL; return -EINVAL;
} }
case IIO_CHAN_INFO_OFFSET:
*val = 1093 - 2732500 / ad7298_get_ref_voltage(st);
return IIO_VAL_INT;
} }
return -EINVAL; return -EINVAL;
} }
...@@ -179,16 +296,23 @@ static int __devinit ad7298_probe(struct spi_device *spi) ...@@ -179,16 +296,23 @@ static int __devinit ad7298_probe(struct spi_device *spi)
{ {
struct ad7298_platform_data *pdata = spi->dev.platform_data; struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st; struct ad7298_state *st;
int ret;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
int ret;
if (indio_dev == NULL) if (indio_dev == NULL)
return -ENOMEM; return -ENOMEM;
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "vcc"); if (pdata && pdata->ext_ref)
if (!IS_ERR(st->reg)) { st->ext_ref = AD7298_EXTREF;
if (st->ext_ref) {
st->reg = regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free;
}
ret = regulator_enable(st->reg); ret = regulator_enable(st->reg);
if (ret) if (ret)
goto error_put_reg; goto error_put_reg;
...@@ -221,14 +345,8 @@ static int __devinit ad7298_probe(struct spi_device *spi) ...@@ -221,14 +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);
if (pdata && pdata->vref_mv) { ret = iio_triggered_buffer_setup(indio_dev, NULL,
st->int_vref_mv = pdata->vref_mv; &ad7298_trigger_handler, NULL);
st->ext_ref = AD7298_EXTREF;
} else {
st->int_vref_mv = AD7298_INTREF_mV;
}
ret = ad7298_register_ring_funcs_and_init(indio_dev);
if (ret) if (ret)
goto error_disable_reg; goto error_disable_reg;
...@@ -239,13 +357,14 @@ static int __devinit ad7298_probe(struct spi_device *spi) ...@@ -239,13 +357,14 @@ 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 (!IS_ERR(st->reg)) if (st->ext_ref)
regulator_disable(st->reg); regulator_disable(st->reg);
error_put_reg: error_put_reg:
if (!IS_ERR(st->reg)) if (st->ext_ref)
regulator_put(st->reg); regulator_put(st->reg);
error_free:
iio_device_free(indio_dev); iio_device_free(indio_dev);
return ret; return ret;
...@@ -257,8 +376,8 @@ static int __devexit ad7298_remove(struct spi_device *spi) ...@@ -257,8 +376,8 @@ 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 (!IS_ERR(st->reg)) { if (st->ext_ref) {
regulator_disable(st->reg); regulator_disable(st->reg);
regulator_put(st->reg); regulator_put(st->reg);
} }
......
...@@ -15,7 +15,7 @@ config HID_SENSOR_IIO_COMMON ...@@ -15,7 +15,7 @@ config HID_SENSOR_IIO_COMMON
attributes. attributes.
config HID_SENSOR_ENUM_BASE_QUIRKS config HID_SENSOR_ENUM_BASE_QUIRKS
tristate "ENUM base quirks for HID Sensor IIO drivers" bool "ENUM base quirks for HID Sensor IIO drivers"
depends on HID_SENSOR_IIO_COMMON depends on HID_SENSOR_IIO_COMMON
help help
Say yes here to build support for sensor hub FW using Say yes here to build support for sensor hub FW using
......
...@@ -36,10 +36,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, ...@@ -36,10 +36,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
int state_val; int state_val;
state_val = state ? 1 : 0; state_val = state ? 1 : 0;
#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \ if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS))
(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE) ++state_val;
++state_val;
#endif
st->data_ready = state; st->data_ready = state;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id, sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index,
......
...@@ -3,6 +3,15 @@ ...@@ -3,6 +3,15 @@
# #
menu "Digital gyroscope sensors" menu "Digital gyroscope sensors"
config ADIS16136
tristate "Analog devices ADIS16136 and similar gyroscopes driver"
depends on SPI_MASTER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
ADIS16136 gyroscope devices.
config HID_SENSOR_GYRO_3D config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB depends on HID_SENSOR_HUB
select IIO_BUFFER select IIO_BUFFER
......
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
# Makefile for industrial I/O gyroscope sensor drivers # Makefile for industrial I/O gyroscope sensor drivers
# #
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
/*
* ADIS16133/ADIS16135/ADIS16136 gyroscope driver
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/iio/iio.h>
#include <linux/debugfs.h>
#define ADIS16136_REG_FLASH_CNT 0x00
#define ADIS16136_REG_TEMP_OUT 0x02
#define ADIS16136_REG_GYRO_OUT2 0x04
#define ADIS16136_REG_GYRO_OUT 0x06
#define ADIS16136_REG_GYRO_OFF2 0x08
#define ADIS16136_REG_GYRO_OFF 0x0A
#define ADIS16136_REG_ALM_MAG1 0x10
#define ADIS16136_REG_ALM_MAG2 0x12
#define ADIS16136_REG_ALM_SAMPL1 0x14
#define ADIS16136_REG_ALM_SAMPL2 0x16
#define ADIS16136_REG_ALM_CTRL 0x18
#define ADIS16136_REG_GPIO_CTRL 0x1A
#define ADIS16136_REG_MSC_CTRL 0x1C
#define ADIS16136_REG_SMPL_PRD 0x1E
#define ADIS16136_REG_AVG_CNT 0x20
#define ADIS16136_REG_DEC_RATE 0x22
#define ADIS16136_REG_SLP_CTRL 0x24
#define ADIS16136_REG_DIAG_STAT 0x26
#define ADIS16136_REG_GLOB_CMD 0x28
#define ADIS16136_REG_LOT1 0x32
#define ADIS16136_REG_LOT2 0x34
#define ADIS16136_REG_LOT3 0x36
#define ADIS16136_REG_PROD_ID 0x38
#define ADIS16136_REG_SERIAL_NUM 0x3A
#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2
#define ADIS16136_DIAG_STAT_SPI_FAIL 3
#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5
#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6
#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11)
#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10)
struct adis16136_chip_info {
unsigned int precision;
unsigned int fullscale;
};
struct adis16136 {
const struct adis16136_chip_info *chip_info;
struct adis adis;
};
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16136_show_serial(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
struct adis16136 *adis16136 = file->private_data;
uint16_t lot1, lot2, lot3, serial;
char buf[20];
size_t len;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
&serial);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
if (ret < 0)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
lot3, serial);
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
static const struct file_operations adis16136_serial_fops = {
.open = simple_open,
.read = adis16136_show_serial,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static int adis16136_show_product_id(void *arg, u64 *val)
{
struct adis16136 *adis16136 = arg;
u16 prod_id;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
if (ret < 0)
return ret;
*val = prod_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops,
adis16136_show_product_id, NULL, "%llu\n");
static int adis16136_show_flash_count(void *arg, u64 *val)
{
struct adis16136 *adis16136 = arg;
uint16_t flash_count;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
return ret;
*val = flash_count;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops,
adis16136_show_flash_count, NULL, "%lld\n");
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_serial_fops);
debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_product_id_fops);
debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
adis16136, &adis16136_flash_count_fops);
return 0;
}
#else
static int adis16136_debugfs_init(struct iio_dev *indio_dev)
{
return 0;
}
#endif
static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
{
unsigned int t;
t = 32768 / freq;
if (t < 0xf)
t = 0xf;
else if (t > 0xffff)
t = 0xffff;
else
t--;
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
}
static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
{
uint16_t t;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
if (ret < 0)
return ret;
*freq = 32768 / (t + 1);
return 0;
}
static ssize_t adis16136_write_frequency(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
long val;
int ret;
ret = kstrtol(buf, 10, &val);
if (ret)
return ret;
if (val == 0)
return -EINVAL;
ret = adis16136_set_freq(adis16136, val);
return ret ? ret : len;
}
static ssize_t adis16136_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
int ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16136_read_frequency,
adis16136_write_frequency);
static const unsigned adis16136_3db_divisors[] = {
[0] = 2, /* Special case */
[1] = 6,
[2] = 12,
[3] = 25,
[4] = 50,
[5] = 100,
[6] = 200,
[7] = 200, /* Not a valid setting */
};
static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
int i, ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int freq;
uint16_t val16;
int ret;
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
if (ret < 0)
goto err_unlock;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
goto err_unlock;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
mutex_unlock(&indio_dev->mlock);
return ret ? ret : IIO_VAL_INT;
}
static int adis16136_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
uint32_t val32;
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = adis16136->chip_info->precision;
*val2 = (adis16136->chip_info->fullscale << 16);
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
*val = 10;
*val2 = 697000; /* 0.010697 degree Celsius */
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, &val32);
if (ret < 0)
return ret;
*val = sign_extend32(val32, 31);
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16136_get_filter(indio_dev, val);
default:
return -EINVAL;
}
}
static int adis16136_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
return adis_write_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16136_set_filter(indio_dev, val);
default:
break;
}
return -EINVAL;
}
enum {
ADIS16136_SCAN_GYRO,
ADIS16136_SCAN_TEMP,
};
static const struct iio_chan_spec adis16136_channels[] = {
{
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT,
.address = ADIS16136_REG_GYRO_OUT2,
.scan_index = ADIS16136_SCAN_GYRO,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = ADIS16136_REG_TEMP_OUT,
.scan_index = ADIS16136_SCAN_TEMP,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static struct attribute *adis16136_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
NULL
};
static const struct attribute_group adis16136_attribute_group = {
.attrs = adis16136_attributes,
};
static const struct iio_info adis16136_info = {
.driver_module = THIS_MODULE,
.attrs = &adis16136_attribute_group,
.read_raw = &adis16136_read_raw,
.write_raw = &adis16136_write_raw,
.update_scan_mode = adis_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
static int adis16136_stop_device(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
int ret;
ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff);
if (ret)
dev_err(&indio_dev->dev,
"Could not power down device: %d\n", ret);
return ret;
}
static int adis16136_initial_setup(struct iio_dev *indio_dev)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
unsigned int device_id;
uint16_t prod_id;
int ret;
ret = adis_initial_startup(&adis16136->adis);
if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
if (ret)
return ret;
sscanf(indio_dev->name, "adis%u\n", &device_id);
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
device_id, prod_id);
return 0;
}
static const char * const adis16136_status_error_msgs[] = {
[ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed",
[ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure",
[ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error",
[ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
};
static const struct adis_data adis16136_data = {
.diag_stat_reg = ADIS16136_REG_DIAG_STAT,
.glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
.msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
.self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
.startup_delay = 80,
.read_delay = 10,
.write_delay = 10,
.status_error_msgs = adis16136_status_error_msgs,
.status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
};
enum adis16136_id {
ID_ADIS16133,
ID_ADIS16135,
ID_ADIS16136,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
[ID_ADIS16133] = {
.precision = IIO_DEGREE_TO_RAD(1200),
.fullscale = 24000,
},
[ID_ADIS16135] = {
.precision = IIO_DEGREE_TO_RAD(300),
.fullscale = 24000,
},
[ID_ADIS16136] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
},
};
static int adis16136_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct adis16136 *adis16136;
struct iio_dev *indio_dev;
int ret;
indio_dev = iio_device_alloc(sizeof(*adis16136));
if (indio_dev == NULL)
return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
adis16136 = iio_priv(indio_dev);
adis16136->chip_info = &adis16136_chip_info[id->driver_data];
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = adis16136_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
indio_dev->info = &adis16136_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
if (ret)
goto error_free_dev;
ret = adis16136_initial_setup(indio_dev);
if (ret)
goto error_cleanup_buffer;
ret = iio_device_register(indio_dev);
if (ret)
goto error_stop_device;
adis16136_debugfs_init(indio_dev);
return 0;
error_stop_device:
adis16136_stop_device(indio_dev);
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
return ret;
}
static int adis16136_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16136 *adis16136 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16136_stop_device(indio_dev);
adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id adis16136_ids[] = {
{ "adis16133", ID_ADIS16133 },
{ "adis16135", ID_ADIS16135 },
{ "adis16136", ID_ADIS16136 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);
static struct spi_driver adis16136_driver = {
.driver = {
.name = "adis16136",
.owner = THIS_MODULE,
},
.id_table = adis16136_ids,
.probe = adis16136_probe,
.remove = adis16136_remove,
};
module_spi_driver(adis16136_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
MODULE_LICENSE("GPL v2");
...@@ -306,10 +306,10 @@ static int __devinit hid_gyro_3d_probe(struct platform_device *pdev) ...@@ -306,10 +306,10 @@ static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
goto error_free_dev; goto error_free_dev;
} }
channels = kmemdup(gyro_3d_channels, channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
sizeof(gyro_3d_channels), GFP_KERNEL);
GFP_KERNEL);
if (!channels) { if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n"); dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev; goto error_free_dev;
} }
......
#
# IIO imu drivers configuration
#
menu "Inertial measurement units"
config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
endmenu
config IIO_ADIS_LIB
tristate
help
A set of IO helper functions for the Analog Devices ADIS* device family.
config IIO_ADIS_LIB_BUFFER
bool
select IIO_TRIGGERED_BUFFER
help
A set of buffer helper functions for the Analog Devices ADIS* device
family.
#
# Makefile for Inertial Measurement Units
#
obj-$(CONFIG_ADIS16480) += adis16480.o
adis_lib-y += adis.o
adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
/*
* Common library for ADIS16XXX devices
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
#define ADIS_GLOB_CMD_SW_RESET BIT(7)
int adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int value, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
int ret, i;
struct spi_message msg;
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 4,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 6,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 8,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = page;
spi_message_add_tail(&xfers[0], &msg);
}
switch (size) {
case 4:
adis->tx[8] = ADIS_WRITE_REG(reg + 3);
adis->tx[9] = (value >> 24) & 0xff;
adis->tx[6] = ADIS_WRITE_REG(reg + 2);
adis->tx[7] = (value >> 16) & 0xff;
case 2:
adis->tx[4] = ADIS_WRITE_REG(reg + 1);
adis->tx[5] = (value >> 8) & 0xff;
case 1:
adis->tx[2] = ADIS_WRITE_REG(reg);
adis->tx[3] = value & 0xff;
break;
default:
ret = -EINVAL;
goto out_unlock;
}
xfers[size].cs_change = 0;
for (i = 1; i <= size; i++)
spi_message_add_tail(&xfers[i], &msg);
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
reg, ret);
} else {
adis->current_page = page;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_write_reg);
/**
* adis_read_reg() - read 2 bytes from a 16-bit register
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
*/
int adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
struct spi_message msg;
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
}, {
.tx_buf = adis->tx + 4,
.rx_buf = adis->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
}, {
.rx_buf = adis->rx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->read_delay,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = page;
spi_message_add_tail(&xfers[0], &msg);
}
switch (size) {
case 4:
adis->tx[2] = ADIS_READ_REG(reg + 2);
adis->tx[3] = 0;
spi_message_add_tail(&xfers[1], &msg);
case 2:
adis->tx[4] = ADIS_READ_REG(reg);
adis->tx[5] = 0;
spi_message_add_tail(&xfers[2], &msg);
spi_message_add_tail(&xfers[3], &msg);
break;
default:
ret = -EINVAL;
goto out_unlock;
}
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
reg, ret);
goto out_unlock;
} else {
adis->current_page = page;
}
switch (size) {
case 4:
*val = get_unaligned_be32(adis->rx);
break;
case 2:
*val = get_unaligned_be16(adis->rx + 2);
break;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_read_reg);
#ifdef CONFIG_DEBUG_FS
int adis_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval, unsigned int *readval)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
if (readval) {
uint16_t val16;
int ret;
ret = adis_read_reg_16(adis, reg, &val16);
*readval = val16;
return ret;
} else {
return adis_write_reg_16(adis, reg, writeval);
}
}
EXPORT_SYMBOL(adis_debugfs_reg_access);
#endif
/**
* adis_enable_irq() - Enable or disable data ready IRQ
* @adis: The adis device
* @enable: Whether to enable the IRQ
*
* Returns 0 on success, negative error code otherwise
*/
int adis_enable_irq(struct adis *adis, bool enable)
{
int ret = 0;
uint16_t msc;
if (adis->data->enable_irq)
return adis->data->enable_irq(adis, enable);
ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (ret)
goto error_ret;
msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
if (enable)
msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
error_ret:
return ret;
}
EXPORT_SYMBOL(adis_enable_irq);
/**
* adis_check_status() - Check the device for error conditions
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_check_status(struct adis *adis)
{
uint16_t status;
int ret;
int i;
ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
if (ret < 0)
return ret;
status &= adis->data->status_error_mask;
if (status == 0)
return 0;
for (i = 0; i < 16; ++i) {
if (status & BIT(i)) {
dev_err(&adis->spi->dev, "%s.\n",
adis->data->status_error_msgs[i]);
}
}
return -EIO;
}
EXPORT_SYMBOL_GPL(adis_check_status);
/**
* adis_reset() - Reset the device
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_reset(struct adis *adis)
{
int ret;
ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ADIS_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(adis_reset);
static int adis_self_test(struct adis *adis)
{
int ret;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
adis->data->self_test_mask);
if (ret) {
dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
ret);
return ret;
}
msleep(adis->data->startup_delay);
return adis_check_status(adis);
}
/**
* adis_inital_startup() - Performs device self-test
* @adis: The adis device
*
* Returns 0 if the device is operational, a negative error code otherwise.
*
* This function should be called early on in the device initialization sequence
* to ensure that the device is in a sane and known state and that it is usable.
*/
int adis_initial_startup(struct adis *adis)
{
int ret;
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
adis_reset(adis);
msleep(adis->data->startup_delay);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(adis_initial_startup);
/**
* adis_single_conversion() - Performs a single sample conversion
* @indio_dev: The IIO device
* @chan: The IIO channel
* @error_mask: Mask for the error bit
* @val: Result of the conversion
*
* Returns IIO_VAL_INT on success, a negative error code otherwise.
*
* The function performs a single conversion on a given channel and post
* processes the value accordingly to the channel spec. If a error_mask is given
* the function will check if the mask is set in the returned raw value. If it
* is set the function will perform a self-check. If the device does not report
* a error bit in the channels raw value set error_mask to 0.
*/
int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
unsigned int uval;
int ret;
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
if (uval & error_mask) {
ret = adis_check_status(adis);
if (ret)
goto err_unlock;
}
if (chan->scan_type.sign == 's')
*val = sign_extend32(uval, chan->scan_type.realbits - 1);
else
*val = uval & ((1 << chan->scan_type.realbits) - 1);
ret = IIO_VAL_INT;
err_unlock:
mutex_unlock(&indio_dev->mlock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_single_conversion);
/**
* adis_init() - Initialize adis device structure
* @adis: The adis device
* @indio_dev: The iio device
* @spi: The spi device
* @data: Chip specific data
*
* Returns 0 on success, a negative error code otherwise.
*
* This function must be called, before any other adis helper function may be
* called.
*/
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
struct spi_device *spi, const struct adis_data *data)
{
mutex_init(&adis->txrx_lock);
adis->spi = spi;
adis->data = data;
iio_device_set_drvdata(indio_dev, adis);
if (data->has_paging) {
/* Need to set the page before first read/write */
adis->current_page = -1;
} else {
/* Page will always be 0 */
adis->current_page = 0;
}
return adis_enable_irq(adis, false);
}
EXPORT_SYMBOL_GPL(adis_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");
/*
* ADIS16480 and similar IMUs driver
*
* Copyright 2012 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/iio/iio.h>
#include <linux/debugfs.h>
#define ADIS16480_PAGE_SIZE 0x80
#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
#define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06)
#define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08)
#define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A)
#define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C)
#define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E)
#define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10)
#define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14)
#define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18)
#define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C)
#define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20)
#define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24)
#define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28)
#define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A)
#define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C)
#define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E)
#define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40)
#define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44)
#define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48)
#define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C)
#define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50)
#define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54)
#define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E)
#define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04)
#define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06)
#define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08)
#define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A)
#define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C)
#define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E)
#define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10)
#define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14)
#define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18)
#define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C)
#define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20)
#define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24)
#define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28)
#define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A)
#define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C)
#define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40)
#define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C)
#define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02)
#define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06)
#define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08)
#define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A)
#define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C)
#define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10)
#define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16)
#define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18)
#define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20)
#define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22)
#define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24)
#define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28)
#define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A)
#define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C)
#define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E)
#define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30)
#define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32)
#define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34)
#define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36)
#define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38)
#define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A)
#define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78)
#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A)
#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C)
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
/* Each filter coefficent bank spans two pages */
#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
ADIS16480_REG((page) + 1, (x) - 60 + 8))
#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
#define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x))
#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x))
#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x))
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
};
struct adis16480 {
const struct adis16480_chip_info *chip_info;
struct adis adis;
};
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16480_show_firmware_revision(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
struct adis16480 *adis16480 = file->private_data;
char buf[6];
size_t len;
u16 rev;
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
if (ret < 0)
return ret;
len = snprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
static const struct file_operations adis16480_firmware_revision_fops = {
.open = simple_open,
.read = adis16480_show_firmware_revision,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static ssize_t adis16480_show_firmware_date(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
struct adis16480 *adis16480 = file->private_data;
u16 md, year;
char buf[12];
size_t len;
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
if (ret < 0)
return ret;
len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
md >> 8, md & 0xff, year);
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
static const struct file_operations adis16480_firmware_date_fops = {
.open = simple_open,
.read = adis16480_show_firmware_date,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static int adis16480_show_serial_number(void *arg, u64 *val)
{
struct adis16480 *adis16480 = arg;
u16 serial;
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
&serial);
if (ret < 0)
return ret;
*val = serial;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16480_serial_number_fops,
adis16480_show_serial_number, NULL, "0x%.4llx\n");
static int adis16480_show_product_id(void *arg, u64 *val)
{
struct adis16480 *adis16480 = arg;
u16 prod_id;
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
&prod_id);
if (ret < 0)
return ret;
*val = prod_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16480_product_id_fops,
adis16480_show_product_id, NULL, "%llu\n");
static int adis16480_show_flash_count(void *arg, u64 *val)
{
struct adis16480 *adis16480 = arg;
u32 flash_count;
int ret;
ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
return ret;
*val = flash_count;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16480_flash_count_fops,
adis16480_show_flash_count, NULL, "%lld\n");
static int adis16480_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16480 *adis16480 = iio_priv(indio_dev);
debugfs_create_file("firmware_revision", 0400,
indio_dev->debugfs_dentry, adis16480,
&adis16480_firmware_revision_fops);
debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry,
adis16480, &adis16480_firmware_date_fops);
debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
adis16480, &adis16480_serial_number_fops);
debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
adis16480, &adis16480_product_id_fops);
debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
adis16480, &adis16480_flash_count_fops);
return 0;
}
#else
static int adis16480_debugfs_init(struct iio_dev *indio_dev)
{
return 0;
}
#endif
static int adis16480_set_freq(struct adis16480 *st, unsigned int freq)
{
unsigned int t;
t = 2460000 / freq;
if (t > 2048)
t = 2048;
if (t != 0)
t--;
return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
}
static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq)
{
uint16_t t;
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
if (ret < 0)
return ret;
*freq = 2460000 / (t + 1);
return 0;
}
static ssize_t adis16480_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16480 *st = iio_priv(indio_dev);
unsigned int freq;
int ret;
ret = adis16480_get_freq(st, &freq);
if (ret < 0)
return ret;
return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000);
}
static ssize_t adis16480_write_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16480 *st = iio_priv(indio_dev);
int freq_int, freq_fract;
long val;
int ret;
ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract);
if (ret)
return ret;
val = freq_int * 1000 + freq_fract;
if (val <= 0)
return -EINVAL;
ret = adis16480_set_freq(st, val);
return ret ? ret : len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16480_read_frequency,
adis16480_write_frequency);
enum {
ADIS16480_SCAN_GYRO_X,
ADIS16480_SCAN_GYRO_Y,
ADIS16480_SCAN_GYRO_Z,
ADIS16480_SCAN_ACCEL_X,
ADIS16480_SCAN_ACCEL_Y,
ADIS16480_SCAN_ACCEL_Z,
ADIS16480_SCAN_MAGN_X,
ADIS16480_SCAN_MAGN_Y,
ADIS16480_SCAN_MAGN_Z,
ADIS16480_SCAN_BARO,
ADIS16480_SCAN_TEMP,
};
static const unsigned int adis16480_calibbias_regs[] = {
[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS,
[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS,
[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS,
[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS,
[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS,
[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS,
[ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON,
[ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON,
[ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON,
[ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS,
};
static const unsigned int adis16480_calibscale_regs[] = {
[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE,
[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE,
[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE,
[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE,
[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE,
[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE,
};
static int adis16480_set_calibbias(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int bias)
{
unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
struct adis16480 *st = iio_priv(indio_dev);
switch (chan->type) {
case IIO_MAGN:
case IIO_PRESSURE:
if (bias < -0x8000 || bias >= 0x8000)
return -EINVAL;
return adis_write_reg_16(&st->adis, reg, bias);
case IIO_ANGL_VEL:
case IIO_ACCEL:
return adis_write_reg_32(&st->adis, reg, bias);
default:
break;
}
return -EINVAL;
}
static int adis16480_get_calibbias(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *bias)
{
unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
struct adis16480 *st = iio_priv(indio_dev);
uint16_t val16;
uint32_t val32;
int ret;
switch (chan->type) {
case IIO_MAGN:
case IIO_PRESSURE:
ret = adis_read_reg_16(&st->adis, reg, &val16);
*bias = sign_extend32(val16, 15);
break;
case IIO_ANGL_VEL:
case IIO_ACCEL:
ret = adis_read_reg_32(&st->adis, reg, &val32);
*bias = sign_extend32(val32, 31);
break;
default:
ret = -EINVAL;
}
if (ret < 0)
return ret;
return IIO_VAL_INT;
}
static int adis16480_set_calibscale(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int scale)
{
unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
struct adis16480 *st = iio_priv(indio_dev);
if (scale < -0x8000 || scale >= 0x8000)
return -EINVAL;
return adis_write_reg_16(&st->adis, reg, scale);
}
static int adis16480_get_calibscale(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *scale)
{
unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
struct adis16480 *st = iio_priv(indio_dev);
uint16_t val16;
int ret;
ret = adis_read_reg_16(&st->adis, reg, &val16);
if (ret < 0)
return ret;
*scale = sign_extend32(val16, 15);
return IIO_VAL_INT;
}
static const unsigned int adis16480_def_filter_freqs[] = {
310,
55,
275,
63,
};
static const unsigned int ad16480_filter_data[][2] = {
[ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 },
[ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 },
[ADIS16480_SCAN_GYRO_Z] = { ADIS16480_REG_FILTER_BNK0, 6 },
[ADIS16480_SCAN_ACCEL_X] = { ADIS16480_REG_FILTER_BNK0, 9 },
[ADIS16480_SCAN_ACCEL_Y] = { ADIS16480_REG_FILTER_BNK0, 12 },
[ADIS16480_SCAN_ACCEL_Z] = { ADIS16480_REG_FILTER_BNK1, 0 },
[ADIS16480_SCAN_MAGN_X] = { ADIS16480_REG_FILTER_BNK1, 3 },
[ADIS16480_SCAN_MAGN_Y] = { ADIS16480_REG_FILTER_BNK1, 6 },
[ADIS16480_SCAN_MAGN_Z] = { ADIS16480_REG_FILTER_BNK1, 9 },
};
static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *freq)
{
struct adis16480 *st = iio_priv(indio_dev);
unsigned int enable_mask, offset, reg;
uint16_t val;
int ret;
reg = ad16480_filter_data[chan->scan_index][0];
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
if (ret < 0)
return ret;
if (!(val & enable_mask))
*freq = 0;
else
*freq = adis16480_def_filter_freqs[(val >> offset) & 0x3];
return IIO_VAL_INT;
}
static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int freq)
{
struct adis16480 *st = iio_priv(indio_dev);
unsigned int enable_mask, offset, reg;
unsigned int diff, best_diff;
unsigned int i, best_freq;
uint16_t val;
int ret;
reg = ad16480_filter_data[chan->scan_index][0];
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
if (ret < 0)
return ret;
if (freq == 0) {
val &= ~enable_mask;
} else {
best_freq = 0;
best_diff = 310;
for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
if (adis16480_def_filter_freqs[i] >= freq) {
diff = adis16480_def_filter_freqs[i] - freq;
if (diff < best_diff) {
best_diff = diff;
best_freq = i;
}
}
}
val &= ~(0x3 << offset);
val |= best_freq << offset;
val |= enable_mask;
}
return adis_write_reg_16(&st->adis, reg, val);
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
*val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL:
*val = 0;
*val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
return IIO_VAL_INT_PLUS_MICRO;
case IIO_MAGN:
*val = 0;
*val2 = 100; /* 0.0001 gauss */
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
*val = 5;
*val2 = 650000; /* 5.65 milli degree Celsius */
return IIO_VAL_INT_PLUS_MICRO;
case IIO_PRESSURE:
*val = 0;
*val2 = 4000; /* 40ubar = 0.004 kPa */
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
/* Only the temperature channel has a offset */
*val = 4425; /* 25 degree Celsius = 0x0000 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS:
return adis16480_get_calibbias(indio_dev, chan, val);
case IIO_CHAN_INFO_CALIBSCALE:
return adis16480_get_calibscale(indio_dev, chan, val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16480_get_filter_freq(indio_dev, chan, val);
default:
return -EINVAL;
}
}
static int adis16480_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
return adis16480_set_calibbias(indio_dev, chan, val);
case IIO_CHAN_INFO_CALIBSCALE:
return adis16480_set_calibscale(indio_dev, chan, val);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return adis16480_set_filter_freq(indio_dev, chan, val);
default:
return -EINVAL;
}
}
#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info, _bits) \
{ \
.type = (_type), \
.modified = 1, \
.channel2 = (_mod), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
_info, \
.address = (_address), \
.scan_index = (_si), \
.scan_type = { \
.sign = 's', \
.realbits = (_bits), \
.storagebits = (_bits), \
.endianness = IIO_BE, \
}, \
}
#define ADIS16480_GYRO_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
32)
#define ADIS16480_ACCEL_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
32)
#define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, \
16)
#define ADIS16480_PRESSURE_CHANNEL() \
{ \
.type = IIO_PRESSURE, \
.indexed = 1, \
.channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = ADIS16480_REG_BAROM_OUT, \
.scan_index = ADIS16480_SCAN_BARO, \
.scan_type = { \
.sign = 's', \
.realbits = 32, \
.storagebits = 32, \
.endianness = IIO_BE, \
}, \
}
#define ADIS16480_TEMP_CHANNEL() { \
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
.address = ADIS16480_REG_TEMP_OUT, \
.scan_index = ADIS16480_SCAN_TEMP, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec adis16480_channels[] = {
ADIS16480_GYRO_CHANNEL(X),
ADIS16480_GYRO_CHANNEL(Y),
ADIS16480_GYRO_CHANNEL(Z),
ADIS16480_ACCEL_CHANNEL(X),
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_MAGN_CHANNEL(X),
ADIS16480_MAGN_CHANNEL(Y),
ADIS16480_MAGN_CHANNEL(Z),
ADIS16480_PRESSURE_CHANNEL(),
ADIS16480_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(11)
};
static const struct iio_chan_spec adis16485_channels[] = {
ADIS16480_GYRO_CHANNEL(X),
ADIS16480_GYRO_CHANNEL(Y),
ADIS16480_GYRO_CHANNEL(Z),
ADIS16480_ACCEL_CHANNEL(X),
ADIS16480_ACCEL_CHANNEL(Y),
ADIS16480_ACCEL_CHANNEL(Z),
ADIS16480_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
enum adis16480_variant {
ADIS16375,
ADIS16480,
ADIS16485,
ADIS16488,
};
static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
},
[ADIS16480] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
},
[ADIS16485] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
},
[ADIS16488] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
},
};
static struct attribute *adis16480_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
NULL
};
static const struct attribute_group adis16480_attribute_group = {
.attrs = adis16480_attributes,
};
static const struct iio_info adis16480_info = {
.attrs = &adis16480_attribute_group,
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int adis16480_stop_device(struct iio_dev *indio_dev)
{
struct adis16480 *st = iio_priv(indio_dev);
int ret;
ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9));
if (ret)
dev_err(&indio_dev->dev,
"Could not power down device: %d\n", ret);
return ret;
}
static int adis16480_enable_irq(struct adis *adis, bool enable)
{
return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL,
enable ? BIT(3) : 0);
}
static int adis16480_initial_setup(struct iio_dev *indio_dev)
{
struct adis16480 *st = iio_priv(indio_dev);
uint16_t prod_id;
unsigned int device_id;
int ret;
adis_reset(&st->adis);
msleep(70);
ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1));
if (ret)
return ret;
msleep(30);
ret = adis_check_status(&st->adis);
if (ret)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_PROD_ID, &prod_id);
if (ret)
return ret;
sscanf(indio_dev->name, "adis%u\n", &device_id);
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
device_id, prod_id);
return 0;
}
#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
#define ADIS16480_DIAG_STAT_BARO_FAIL 11
static const char * const adis16480_status_error_msgs[] = {
[ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
[ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
[ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
[ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
[ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
[ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
[ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
[ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
[ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
[ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
};
static const struct adis_data adis16480_data = {
.diag_stat_reg = ADIS16480_REG_DIAG_STS,
.glob_cmd_reg = ADIS16480_REG_GLOB_CMD,
.has_paging = true,
.read_delay = 5,
.write_delay = 5,
.status_error_msgs = adis16480_status_error_msgs,
.status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |
BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |
BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |
BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |
BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |
BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |
BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |
BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |
BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |
BIT(ADIS16480_DIAG_STAT_BARO_FAIL),
.enable_irq = adis16480_enable_irq,
};
static int adis16480_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct adis16480 *st;
int ret;
indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->chip_info = &adis16480_chip_info[id->driver_data];
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = &adis16480_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
if (ret)
goto error_free_dev;
ret = adis16480_initial_setup(indio_dev);
if (ret)
goto error_cleanup_buffer;
ret = iio_device_register(indio_dev);
if (ret)
goto error_stop_device;
adis16480_debugfs_init(indio_dev);
return 0;
error_stop_device:
adis16480_stop_device(indio_dev);
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
return ret;
}
static int adis16480_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16480 *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16480_stop_device(indio_dev);
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id adis16480_ids[] = {
{ "adis16375", ADIS16375 },
{ "adis16480", ADIS16480 },
{ "adis16485", ADIS16485 },
{ "adis16488", ADIS16488 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16480_ids);
static struct spi_driver adis16480_driver = {
.driver = {
.name = "adis16480",
.owner = THIS_MODULE,
},
.id_table = adis16480_ids,
.probe = adis16480_probe,
.remove = adis16480_remove,
};
module_spi_driver(adis16480_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
MODULE_LICENSE("GPL v2");
/*
* Common library for ADIS16XXX devices
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/imu/adis.h>
int adis_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
const struct iio_chan_spec *chan;
unsigned int scan_count;
unsigned int i, j;
__be16 *tx, *rx;
kfree(adis->xfer);
kfree(adis->buffer);
scan_count = indio_dev->scan_bytes / 2;
adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
if (!adis->xfer)
return -ENOMEM;
adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL);
if (!adis->buffer)
return -ENOMEM;
rx = adis->buffer;
tx = rx + indio_dev->scan_bytes;
spi_message_init(&adis->msg);
for (j = 0; j <= scan_count; j++) {
adis->xfer[j].bits_per_word = 8;
if (j != scan_count)
adis->xfer[j].cs_change = 1;
adis->xfer[j].len = 2;
adis->xfer[j].delay_usecs = adis->data->read_delay;
if (j < scan_count)
adis->xfer[j].tx_buf = &tx[j];
if (j >= 1)
adis->xfer[j].rx_buf = &rx[j - 1];
spi_message_add_tail(&adis->xfer[j], &adis->msg);
}
chan = indio_dev->channels;
for (i = 0; i < indio_dev->num_channels; i++, chan++) {
if (!test_bit(chan->scan_index, scan_mask))
continue;
if (chan->scan_type.storagebits == 32)
*tx++ = cpu_to_be16((chan->address + 2) << 8);
*tx++ = cpu_to_be16(chan->address << 8);
}
return 0;
}
EXPORT_SYMBOL_GPL(adis_update_scan_mode);
static irqreturn_t adis_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis *adis = iio_device_get_drvdata(indio_dev);
int ret;
if (!adis->buffer)
return -ENOMEM;
if (adis->data->has_paging) {
mutex_lock(&adis->txrx_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
spi_write(adis->spi, adis->tx, 2);
}
}
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
if (adis->data->has_paging) {
adis->current_page = 0;
mutex_unlock(&adis->txrx_lock);
}
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp) {
void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
*(s64 *)b = pf->timestamp;
}
iio_push_to_buffers(indio_dev, adis->buffer);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
/**
* adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device
* @adis: The adis device.
* @indio_dev: The IIO device.
* @trigger_handler: Optional trigger handler, may be NULL.
*
* Returns 0 on success, a negative error code otherwise.
*
* This function sets up the buffer and trigger for a adis devices. If
* 'trigger_handler' is NULL the default trigger handler will be used. The
* default trigger handler will simply read the registers assigned to the
* currently active channels.
*
* adis_cleanup_buffer_and_trigger() should be called to free the resources
* allocated by this function.
*/
int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
irqreturn_t (*trigger_handler)(int, void *))
{
int ret;
if (!trigger_handler)
trigger_handler = adis_trigger_handler;
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
trigger_handler, NULL);
if (ret)
return ret;
if (adis->spi->irq) {
ret = adis_probe_trigger(adis, indio_dev);
if (ret)
goto error_buffer_cleanup;
}
return 0;
error_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
/**
* adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
* @adis: The adis device.
* @indio_dev: The IIO device.
*
* Frees resources allocated by adis_setup_buffer_and_trigger()
*/
void adis_cleanup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev)
{
if (adis->spi->irq)
adis_remove_trigger(adis);
kfree(adis->buffer);
kfree(adis->xfer);
iio_triggered_buffer_cleanup(indio_dev);
}
EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger);
/*
* Common library for ADIS16XXX devices
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/imu/adis.h>
static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct adis *adis = trig->private_data;
return adis_enable_irq(adis, state);
}
static const struct iio_trigger_ops adis_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis_data_rdy_trigger_set_state,
};
/**
* adis_probe_trigger() - Sets up trigger for a adis device
* @adis: The adis device
* @indio_dev: The IIO device
*
* Returns 0 on success or a negative error code
*
* adis_remove_trigger() should be used to free the trigger.
*/
int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
{
int ret;
adis->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
indio_dev->id);
if (adis->trig == NULL)
return -ENOMEM;
ret = request_irq(adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
indio_dev->name,
adis->trig);
if (ret)
goto error_free_trig;
adis->trig->dev.parent = &adis->spi->dev;
adis->trig->ops = &adis_trigger_ops;
adis->trig->private_data = adis;
ret = iio_trigger_register(adis->trig);
indio_dev->trig = adis->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(adis->spi->irq, adis->trig);
error_free_trig:
iio_trigger_free(adis->trig);
return ret;
}
EXPORT_SYMBOL_GPL(adis_probe_trigger);
/**
* adis_remove_trigger() - Remove trigger for a adis devices
* @adis: The adis device
*
* Removes the trigger previously registered with adis_probe_trigger().
*/
void adis_remove_trigger(struct adis *adis)
{
iio_trigger_unregister(adis->trig);
free_irq(adis->spi->irq, adis->trig);
iio_trigger_free(adis->trig);
}
EXPORT_SYMBOL_GPL(adis_remove_trigger);
...@@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = { ...@@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CAPACITANCE] = "capacitance", [IIO_CAPACITANCE] = "capacitance",
[IIO_ALTVOLTAGE] = "altvoltage", [IIO_ALTVOLTAGE] = "altvoltage",
[IIO_CCT] = "cct", [IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
}; };
static const char * const iio_modifier_names[] = { static const char * const iio_modifier_names[] = {
...@@ -407,6 +408,64 @@ static ssize_t iio_read_channel_info(struct device *dev, ...@@ -407,6 +408,64 @@ static ssize_t iio_read_channel_info(struct device *dev,
} }
} }
/**
* iio_str_to_fixpoint() - Parse a fixed-point number from a string
* @str: The string to parse
* @fract_mult: Multiplier for the first decimal place, should be a power of 10
* @integer: The integer part of the number
* @fract: The fractional part of the number
*
* Returns 0 on success, or a negative error code if the string could not be
* parsed.
*/
int iio_str_to_fixpoint(const char *str, int fract_mult,
int *integer, int *fract)
{
int i = 0, f = 0;
bool integer_part = true, negative = false;
if (str[0] == '-') {
negative = true;
str++;
} else if (str[0] == '+') {
str++;
}
while (*str) {
if ('0' <= *str && *str <= '9') {
if (integer_part) {
i = i * 10 + *str - '0';
} else {
f += fract_mult * (*str - '0');
fract_mult /= 10;
}
} else if (*str == '\n') {
if (*(str + 1) == '\0')
break;
else
return -EINVAL;
} else if (*str == '.' && integer_part) {
integer_part = false;
} else {
return -EINVAL;
}
str++;
}
if (negative) {
if (i)
i = -i;
else
f = -f;
}
*integer = i;
*fract = f;
return 0;
}
EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
static ssize_t iio_write_channel_info(struct device *dev, static ssize_t iio_write_channel_info(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, const char *buf,
...@@ -414,8 +473,8 @@ static ssize_t iio_write_channel_info(struct device *dev, ...@@ -414,8 +473,8 @@ static ssize_t iio_write_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);
int ret, integer = 0, fract = 0, fract_mult = 100000; int ret, fract_mult = 100000;
bool integer_part = true, negative = false; int integer, fract;
/* Assumes decimal - precision based on number of digits */ /* Assumes decimal - precision based on number of digits */
if (!indio_dev->info->write_raw) if (!indio_dev->info->write_raw)
...@@ -434,39 +493,9 @@ static ssize_t iio_write_channel_info(struct device *dev, ...@@ -434,39 +493,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
return -EINVAL; return -EINVAL;
} }
if (buf[0] == '-') { ret = iio_str_to_fixpoint(buf, fract_mult, &integer, &fract);
negative = true; if (ret)
buf++; return ret;
} else if (buf[0] == '+') {
buf++;
}
while (*buf) {
if ('0' <= *buf && *buf <= '9') {
if (integer_part)
integer = integer*10 + *buf - '0';
else {
fract += fract_mult*(*buf - '0');
fract_mult /= 10;
}
} else if (*buf == '\n') {
if (*(buf + 1) == '\0')
break;
else
return -EINVAL;
} else if (*buf == '.' && integer_part) {
integer_part = false;
} else {
return -EINVAL;
}
buf++;
}
if (negative) {
if (integer)
integer = -integer;
else
fract = -fract;
}
ret = indio_dev->info->write_raw(indio_dev, this_attr->c, ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
integer, fract, this_attr->address); integer, fract, this_attr->address);
......
...@@ -350,15 +350,10 @@ static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) ...@@ -350,15 +350,10 @@ static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
ret = iio_device_add_event_sysfs(indio_dev, ret = iio_device_add_event_sysfs(indio_dev,
&indio_dev->channels[j]); &indio_dev->channels[j]);
if (ret < 0) if (ret < 0)
goto error_clear_attrs; return ret;
attrcount += ret; attrcount += ret;
} }
return attrcount; return attrcount;
error_clear_attrs:
__iio_remove_event_config_attrs(indio_dev);
return ret;
} }
static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
......
...@@ -272,10 +272,9 @@ static int __devinit hid_als_probe(struct platform_device *pdev) ...@@ -272,10 +272,9 @@ static int __devinit hid_als_probe(struct platform_device *pdev)
goto error_free_dev; goto error_free_dev;
} }
channels = kmemdup(als_channels, channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
sizeof(als_channels),
GFP_KERNEL);
if (!channels) { if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n"); dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev; goto error_free_dev;
} }
......
...@@ -307,10 +307,10 @@ static int __devinit hid_magn_3d_probe(struct platform_device *pdev) ...@@ -307,10 +307,10 @@ static int __devinit hid_magn_3d_probe(struct platform_device *pdev)
goto error_free_dev; goto error_free_dev;
} }
channels = kmemdup(magn_3d_channels, channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
sizeof(magn_3d_channels), GFP_KERNEL);
GFP_KERNEL);
if (!channels) { if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n"); dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev; goto error_free_dev;
} }
......
...@@ -6,8 +6,8 @@ menu "Accelerometers" ...@@ -6,8 +6,8 @@ menu "Accelerometers"
config ADIS16201 config ADIS16201
tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI depends on SPI
select IIO_TRIGGER if IIO_BUFFER select IIO_ADIS_LIB
select IIO_SW_RING if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say yes here to build support for Analog Devices adis16201 dual-axis Say yes here to build support for Analog Devices adis16201 dual-axis
digital inclinometer and accelerometer. digital inclinometer and accelerometer.
...@@ -15,8 +15,8 @@ config ADIS16201 ...@@ -15,8 +15,8 @@ config ADIS16201
config ADIS16203 config ADIS16203
tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer" tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"
depends on SPI depends on SPI
select IIO_TRIGGER if IIO_BUFFER select IIO_ADIS_LIB
select IIO_SW_RING if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say yes here to build support for Analog Devices adis16203 Programmable Say yes here to build support for Analog Devices adis16203 Programmable
360 Degrees Inclinometer. 360 Degrees Inclinometer.
...@@ -24,8 +24,8 @@ config ADIS16203 ...@@ -24,8 +24,8 @@ config ADIS16203
config ADIS16204 config ADIS16204
tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder" tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
depends on SPI depends on SPI
select IIO_TRIGGER if IIO_BUFFER select IIO_ADIS_LIB
select IIO_SW_RING if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say yes here to build support for Analog Devices adis16204 Programmable Say yes here to build support for Analog Devices adis16204 Programmable
High-g Digital Impact Sensor and Recorder. High-g Digital Impact Sensor and Recorder.
...@@ -33,8 +33,8 @@ config ADIS16204 ...@@ -33,8 +33,8 @@ config ADIS16204
config ADIS16209 config ADIS16209
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI depends on SPI
select IIO_TRIGGER if IIO_BUFFER select IIO_ADIS_LIB
select IIO_SW_RING if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
and accelerometer. and accelerometer.
...@@ -42,6 +42,7 @@ config ADIS16209 ...@@ -42,6 +42,7 @@ config ADIS16209
config ADIS16220 config ADIS16220
tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor" tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor"
depends on SPI depends on SPI
select IIO_ADIS_LIB
help help
Say yes here to build support for Analog Devices adis16220 programmable Say yes here to build support for Analog Devices adis16220 programmable
digital vibration sensor. digital vibration sensor.
...@@ -49,8 +50,8 @@ config ADIS16220 ...@@ -49,8 +50,8 @@ config ADIS16220
config ADIS16240 config ADIS16240
tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
depends on SPI depends on SPI
select IIO_TRIGGER if IIO_BUFFER select IIO_ADIS_LIB
select IIO_SW_RING if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say yes here to build support for Analog Devices adis16240 programmable Say yes here to build support for Analog Devices adis16240 programmable
impact Sensor and recorder. impact Sensor and recorder.
......
...@@ -3,26 +3,21 @@ ...@@ -3,26 +3,21 @@
# #
adis16201-y := adis16201_core.o adis16201-y := adis16201_core.o
adis16201-$(CONFIG_IIO_BUFFER) += adis16201_ring.o adis16201_trigger.o
obj-$(CONFIG_ADIS16201) += adis16201.o obj-$(CONFIG_ADIS16201) += adis16201.o
adis16203-y := adis16203_core.o adis16203-y := adis16203_core.o
adis16203-$(CONFIG_IIO_BUFFER) += adis16203_ring.o adis16203_trigger.o
obj-$(CONFIG_ADIS16203) += adis16203.o obj-$(CONFIG_ADIS16203) += adis16203.o
adis16204-y := adis16204_core.o adis16204-y := adis16204_core.o
adis16204-$(CONFIG_IIO_BUFFER) += adis16204_ring.o adis16204_trigger.o
obj-$(CONFIG_ADIS16204) += adis16204.o obj-$(CONFIG_ADIS16204) += adis16204.o
adis16209-y := adis16209_core.o adis16209-y := adis16209_core.o
adis16209-$(CONFIG_IIO_BUFFER) += adis16209_ring.o adis16209_trigger.o
obj-$(CONFIG_ADIS16209) += adis16209.o obj-$(CONFIG_ADIS16209) += adis16209.o
adis16220-y := adis16220_core.o adis16220-y := adis16220_core.o
obj-$(CONFIG_ADIS16220) += adis16220.o obj-$(CONFIG_ADIS16220) += adis16220.o
adis16240-y := adis16240_core.o adis16240-y := adis16240_core.o
adis16240-$(CONFIG_IIO_BUFFER) += adis16240_ring.o adis16240_trigger.o
obj-$(CONFIG_ADIS16240) += adis16240.o obj-$(CONFIG_ADIS16240) += adis16240.o
obj-$(CONFIG_KXSD9) += kxsd9.o obj-$(CONFIG_KXSD9) += kxsd9.o
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#define ADIS16201_STARTUP_DELAY 220 /* ms */ #define ADIS16201_STARTUP_DELAY 220 /* ms */
#define ADIS16201_READ_REG(a) a
#define ADIS16201_WRITE_REG(a) ((a) | 0x80)
#define ADIS16201_FLASH_CNT 0x00 /* Flash memory write count */ #define ADIS16201_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16201_SUPPLY_OUT 0x02 /* Output, power supply */ #define ADIS16201_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16201_XACCL_OUT 0x04 /* Output, x-axis accelerometer */ #define ADIS16201_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
...@@ -36,8 +33,6 @@ ...@@ -36,8 +33,6 @@
#define ADIS16201_DIAG_STAT 0x3C /* Diagnostics, system status register */ #define ADIS16201_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16201_GLOB_CMD 0x3E /* Operation, system command register */ #define ADIS16201_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16201_OUTPUTS 7
/* MSC_CTRL */ /* MSC_CTRL */
#define ADIS16201_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */ #define ADIS16201_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */
#define ADIS16201_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */ #define ADIS16201_MSC_CTRL_DATA_RDY_EN (1 << 2) /* Data-ready enable: 1 = enabled, 0 = disabled */
...@@ -47,95 +42,25 @@ ...@@ -47,95 +42,25 @@
/* DIAG_STAT */ /* DIAG_STAT */
#define ADIS16201_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16201_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16201_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16201_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16201_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ #define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16201_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ #define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16201_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ #define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16201_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */ #define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 3.15 V */
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16201_GLOB_CMD_SW_RESET (1<<7) #define ADIS16201_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1) #define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16201_MAX_TX 14
#define ADIS16201_MAX_RX 14
#define ADIS16201_ERROR_ACTIVE (1<<14) #define ADIS16201_ERROR_ACTIVE (1<<14)
/**
* struct adis16201_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16201_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
u8 tx[14] ____cacheline_aligned;
u8 rx[14];
};
int adis16201_set_irq(struct iio_dev *indio_dev, bool enable);
enum adis16201_scan { enum adis16201_scan {
ADIS16201_SCAN_SUPPLY,
ADIS16201_SCAN_ACC_X, ADIS16201_SCAN_ACC_X,
ADIS16201_SCAN_ACC_Y, ADIS16201_SCAN_ACC_Y,
ADIS16201_SCAN_AUX_ADC,
ADIS16201_SCAN_TEMP,
ADIS16201_SCAN_INCLI_X, ADIS16201_SCAN_INCLI_X,
ADIS16201_SCAN_INCLI_Y, ADIS16201_SCAN_INCLI_Y,
ADIS16201_SCAN_SUPPLY,
ADIS16201_SCAN_AUX_ADC,
ADIS16201_SCAN_TEMP,
}; };
#ifdef CONFIG_IIO_BUFFER
void adis16201_remove_trigger(struct iio_dev *indio_dev);
int adis16201_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16201_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16201_configure_ring(struct iio_dev *indio_dev);
void adis16201_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16201_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16201_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16201_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16201_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
{
}
static inline int adis16201_initialize_ring(struct iio_ring_buffer *ring)
{
return 0;
}
static inline void adis16201_uninitialize_ring(struct iio_ring_buffer *ring)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16201_H_ */ #endif /* SPI_ADIS16201_H_ */
...@@ -18,258 +18,15 @@ ...@@ -18,258 +18,15 @@
#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/imu/adis.h>
#include "adis16201.h" #include "adis16201.h"
enum adis16201_chan { static const u8 adis16201_addresses[] = {
in_supply, [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS,
temp, [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS,
accel_x, [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS,
accel_y, [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS,
incli_x,
incli_y,
in_aux,
};
/**
* adis16201_spi_write_reg_8() - write single byte to a register
* @dev: device associated with child of actual device (iio_dev or iio_trig)
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16201_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16201_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16201_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16201_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16201_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16201_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16201_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16201_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16201_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16201_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16201_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 20,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 20,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16201_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16201_reset(struct iio_dev *indio_dev)
{
int ret;
struct adis16201_state *st = iio_priv(indio_dev);
ret = adis16201_spi_write_reg_8(indio_dev,
ADIS16201_GLOB_CMD,
ADIS16201_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&st->us->dev, "problem resetting device");
return ret;
}
int adis16201_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret = 0;
u16 msc;
ret = adis16201_spi_read_reg_16(indio_dev, ADIS16201_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16201_MSC_CTRL_ACTIVE_HIGH;
msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_DIO1;
if (enable)
msc |= ADIS16201_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_EN;
ret = adis16201_spi_write_reg_16(indio_dev, ADIS16201_MSC_CTRL, msc);
error_ret:
return ret;
}
static int adis16201_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16201_spi_read_reg_16(indio_dev,
ADIS16201_DIAG_STAT, &status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0xF;
if (ret)
ret = -EFAULT;
if (status & ADIS16201_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16201_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16201_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16201_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
error_ret:
return ret;
}
static int adis16201_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16201_spi_write_reg_16(indio_dev,
ADIS16201_MSC_CTRL,
ADIS16201_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
ret = adis16201_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16201_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct device *dev = &indio_dev->dev;
/* Disable IRQ */
ret = adis16201_set_irq(indio_dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16201_self_test(indio_dev);
if (ret) {
dev_err(dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16201_check_status(indio_dev);
if (ret) {
adis16201_reset(indio_dev);
dev_err(dev, "device not playing ball -> reset");
msleep(ADIS16201_STARTUP_DELAY);
ret = adis16201_check_status(indio_dev);
if (ret) {
dev_err(dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
static u8 adis16201_addresses[7][2] = {
[in_supply] = { ADIS16201_SUPPLY_OUT, },
[temp] = { ADIS16201_TEMP_OUT },
[accel_x] = { ADIS16201_XACCL_OUT, ADIS16201_XACCL_OFFS },
[accel_y] = { ADIS16201_YACCL_OUT, ADIS16201_YACCL_OFFS },
[in_aux] = { ADIS16201_AUX_ADC },
[incli_x] = { ADIS16201_XINCL_OUT },
[incli_y] = { ADIS16201_YINCL_OUT },
}; };
static int adis16201_read_raw(struct iio_dev *indio_dev, static int adis16201_read_raw(struct iio_dev *indio_dev,
...@@ -277,6 +34,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, ...@@ -277,6 +34,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
int bits; int bits;
u8 addr; u8 addr;
...@@ -284,29 +42,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, ...@@ -284,29 +42,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16201_addresses[chan->address][0]; ADIS16201_ERROR_ACTIVE, val);
ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16201_ERROR_ACTIVE) {
ret = adis16201_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
...@@ -349,8 +86,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, ...@@ -349,8 +86,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16201_addresses[chan->address][1]; addr = adis16201_addresses[chan->scan_index];
ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -370,6 +107,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, ...@@ -370,6 +107,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int bits; int bits;
s16 val16; s16 val16;
u8 addr; u8 addr;
...@@ -386,124 +124,61 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, ...@@ -386,124 +124,61 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16201_addresses[chan->address][1]; addr = adis16201_addresses[chan->scan_index];
return adis16201_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(st, addr, val16);
} }
return -EINVAL; return -EINVAL;
} }
static const struct iio_chan_spec adis16201_channels[] = { static const struct iio_chan_spec adis16201_channels[] = {
{ ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 12),
.type = IIO_VOLTAGE, ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 12),
.indexed = 1, ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X,
.channel = 0, IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
.extend_name = "supply", ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 12),
.address = in_supply, ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X,
.scan_index = ADIS16201_SCAN_SUPPLY, IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
.scan_type = { ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y,
.sign = 'u', IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16201_SCAN_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = accel_x,
.scan_index = ADIS16201_SCAN_ACC_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = accel_y,
.scan_index = ADIS16201_SCAN_ACC_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_aux,
.scan_index = ADIS16201_SCAN_AUX_ADC,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = incli_x,
.scan_index = ADIS16201_SCAN_INCLI_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = incli_y,
.scan_index = ADIS16201_SCAN_INCLI_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(7) IIO_CHAN_SOFT_TIMESTAMP(7)
}; };
static const struct iio_info adis16201_info = { static const struct iio_info adis16201_info = {
.read_raw = &adis16201_read_raw, .read_raw = &adis16201_read_raw,
.write_raw = &adis16201_write_raw, .write_raw = &adis16201_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis16201_status_error_msgs[] = {
[ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16201_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16201_data = {
.read_delay = 20,
.msc_ctrl_reg = ADIS16201_MSC_CTRL,
.glob_cmd_reg = ADIS16201_GLOB_CMD,
.diag_stat_reg = ADIS16201_DIAG_STAT,
.self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16201_STARTUP_DELAY,
.status_error_msgs = adis16201_status_error_msgs,
.status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16201_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16201_probe(struct spi_device *spi) static int __devinit adis16201_probe(struct spi_device *spi)
{ {
int ret; int ret;
struct adis16201_state *st; struct adis *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */ /* setup the industrialio driver allocated elements */
...@@ -516,9 +191,6 @@ static int __devinit adis16201_probe(struct spi_device *spi) ...@@ -516,9 +191,6 @@ static int __devinit adis16201_probe(struct spi_device *spi)
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16201_info; indio_dev->info = &adis16201_info;
...@@ -527,40 +199,25 @@ static int __devinit adis16201_probe(struct spi_device *spi) ...@@ -527,40 +199,25 @@ static int __devinit adis16201_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16201_channels); indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16201_configure_ring(indio_dev); ret = adis_init(st, indio_dev, spi, &adis16201_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev,
adis16201_channels,
ARRAY_SIZE(adis16201_channels));
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq) {
ret = adis16201_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16201_initial_setup(indio_dev); ret = adis_initial_startup(st);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret < 0) if (ret < 0)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16201_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16201_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -570,11 +227,10 @@ static int __devinit adis16201_probe(struct spi_device *spi) ...@@ -570,11 +227,10 @@ static int __devinit adis16201_probe(struct spi_device *spi)
static int __devexit adis16201_remove(struct spi_device *spi) static int __devexit adis16201_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16201_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_buffer_unregister(indio_dev);
adis16201_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16201.h"
/**
* adis16201_read_ring_data() read data registers which will be placed into ring
* @dev: device associated with child of actual device (iio_dev or iio_trig)
* @rx: somewhere to pass back the value read
**/
static int adis16201_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16201_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16201_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16201_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 20;
if (i < ADIS16201_OUTPUTS) {
xfers[i].tx_buf = st->tx + 2 * i;
st->tx[2 * i] = ADIS16201_READ_REG(ADIS16201_SUPPLY_OUT +
2 * i);
st->tx[2 * i + 1] = 0;
}
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
static irqreturn_t adis16201_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16201_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)
&& adis16201_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16201_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16201_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16201_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16201_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"adis16201_consumer%d",
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16201.h"
/**
* adis16201_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16201_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16201_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16201_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16201_data_rdy_trigger_set_state,
};
int adis16201_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16201_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("adis16201-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16201",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16201_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16201_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16201_state *state = iio_priv(indio_dev);
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
iio_trigger_free(state->trig);
}
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#define ADIS16203_STARTUP_DELAY 220 /* ms */ #define ADIS16203_STARTUP_DELAY 220 /* ms */
#define ADIS16203_READ_REG(a) a
#define ADIS16203_WRITE_REG(a) ((a) | 0x80)
#define ADIS16203_FLASH_CNT 0x00 /* Flash memory write count */ #define ADIS16203_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16203_SUPPLY_OUT 0x02 /* Output, power supply */ #define ADIS16203_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16203_AUX_ADC 0x08 /* Output, auxiliary ADC input */ #define ADIS16203_AUX_ADC 0x08 /* Output, auxiliary ADC input */
...@@ -27,8 +24,6 @@ ...@@ -27,8 +24,6 @@
#define ADIS16203_DIAG_STAT 0x3C /* Diagnostics, system status register */ #define ADIS16203_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16203_GLOB_CMD 0x3E /* Operation, system command register */ #define ADIS16203_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16203_OUTPUTS 5
/* MSC_CTRL */ /* MSC_CTRL */
#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */ #define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN (1 << 9) /* Reverses rotation of both inclination outputs */ #define ADIS16203_MSC_CTRL_REVERSE_ROT_EN (1 << 9) /* Reverses rotation of both inclination outputs */
...@@ -40,86 +35,25 @@ ...@@ -40,86 +35,25 @@
/* DIAG_STAT */ /* DIAG_STAT */
#define ADIS16203_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16203_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16203_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16203_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16203_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag */ #define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 /* Self-test diagnostic error flag */
#define ADIS16203_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ #define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16203_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ #define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16203_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ #define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16203_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 3.15 V */ #define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 3.15 V */
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16203_GLOB_CMD_SW_RESET (1<<7) #define ADIS16203_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16203_GLOB_CMD_CLEAR_STAT (1<<4) #define ADIS16203_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1) #define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16203_MAX_TX 12
#define ADIS16203_MAX_RX 10
#define ADIS16203_ERROR_ACTIVE (1<<14) #define ADIS16203_ERROR_ACTIVE (1<<14)
/**
* struct adis16203_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16203_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
u8 tx[ADIS16203_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16203_MAX_RX];
};
int adis16203_set_irq(struct iio_dev *indio_dev, bool enable);
enum adis16203_scan { enum adis16203_scan {
ADIS16203_SCAN_INCLI_X,
ADIS16203_SCAN_INCLI_Y,
ADIS16203_SCAN_SUPPLY, ADIS16203_SCAN_SUPPLY,
ADIS16203_SCAN_AUX_ADC, ADIS16203_SCAN_AUX_ADC,
ADIS16203_SCAN_TEMP, ADIS16203_SCAN_TEMP,
ADIS16203_SCAN_INCLI_X,
ADIS16203_SCAN_INCLI_Y,
}; };
#ifdef CONFIG_IIO_BUFFER
void adis16203_remove_trigger(struct iio_dev *indio_dev);
int adis16203_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16203_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16203_configure_ring(struct iio_dev *indio_dev);
void adis16203_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16203_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16203_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16203_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16203_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16203_H_ */ #endif /* SPI_ADIS16203_H_ */
/* /*
* ADIS16203 Programmable Digital Vibration Sensor driver * ADIS16203 Programmable Digital Vibration Sensor driver
* *
* Copyright 2010 Analog Devices Inc. * Copyright 2030 Analog Devices Inc.
* *
* Licensed under the GPL-2 or later. * Licensed under the GPL-2 or later.
*/ */
...@@ -18,252 +18,14 @@ ...@@ -18,252 +18,14 @@
#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/imu/adis.h>
#include "adis16203.h" #include "adis16203.h"
/** #define DRIVER_NAME "adis16203"
* adis16203_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16203_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16203_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16203_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16203_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16203_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16203_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16203_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16203_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16203_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16203_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16203_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 20,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 20,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16203_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16203_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16203_spi_read_reg_16(indio_dev,
ADIS16203_DIAG_STAT,
&status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x1F;
if (status & ADIS16203_DIAG_STAT_SELFTEST_FAIL)
dev_err(&indio_dev->dev, "Self test failure\n");
if (status & ADIS16203_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16203_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16203_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16203_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
error_ret:
return ret;
}
static int adis16203_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16203_spi_write_reg_8(indio_dev,
ADIS16203_GLOB_CMD,
ADIS16203_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
int adis16203_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret = 0;
u16 msc;
ret = adis16203_spi_read_reg_16(indio_dev, ADIS16203_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16203_MSC_CTRL_ACTIVE_HIGH;
msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_DIO1;
if (enable)
msc |= ADIS16203_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_EN;
ret = adis16203_spi_write_reg_16(indio_dev, ADIS16203_MSC_CTRL, msc); static const u8 adis16203_addresses[] = {
[ADIS16203_SCAN_INCLI_X] = ADIS16203_INCL_NULL,
error_ret:
return ret;
}
static int adis16203_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16203_spi_write_reg_16(indio_dev,
ADIS16203_MSC_CTRL,
ADIS16203_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16203_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16203_initial_setup(struct iio_dev *indio_dev)
{
int ret;
/* Disable IRQ */
ret = adis16203_set_irq(indio_dev, false);
if (ret) {
dev_err(&indio_dev->dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16203_self_test(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16203_check_status(indio_dev);
if (ret) {
adis16203_reset(indio_dev);
dev_err(&indio_dev->dev, "device not playing ball -> reset");
msleep(ADIS16203_STARTUP_DELAY);
ret = adis16203_check_status(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
enum adis16203_chan {
in_supply,
in_aux,
incli_x,
incli_y,
temp,
};
static u8 adis16203_addresses[5][2] = {
[in_supply] = { ADIS16203_SUPPLY_OUT },
[in_aux] = { ADIS16203_AUX_ADC },
[incli_x] = { ADIS16203_XINCL_OUT, ADIS16203_INCL_NULL},
[incli_y] = { ADIS16203_YINCL_OUT },
[temp] = { ADIS16203_TEMP_OUT }
}; };
static int adis16203_write_raw(struct iio_dev *indio_dev, static int adis16203_write_raw(struct iio_dev *indio_dev,
...@@ -272,9 +34,10 @@ static int adis16203_write_raw(struct iio_dev *indio_dev, ...@@ -272,9 +34,10 @@ static int adis16203_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
/* currently only one writable parameter which keeps this simple */ /* currently only one writable parameter which keeps this simple */
u8 addr = adis16203_addresses[chan->address][1]; u8 addr = adis16203_addresses[chan->scan_index];
return adis16203_spi_write_reg_16(indio_dev, addr, val & 0x3FFF); return adis_write_reg_16(st, addr, val & 0x3FFF);
} }
static int adis16203_read_raw(struct iio_dev *indio_dev, static int adis16203_read_raw(struct iio_dev *indio_dev,
...@@ -282,35 +45,15 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, ...@@ -282,35 +45,15 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
int bits; int bits;
u8 addr; u8 addr;
s16 val16; s16 val16;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16203_addresses[chan->address][0]; ADIS16203_ERROR_ACTIVE, val);
ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16203_ERROR_ACTIVE) {
ret = adis16203_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
...@@ -339,8 +82,8 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, ...@@ -339,8 +82,8 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
bits = 14; bits = 14;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->address][1]; addr = adis16203_addresses[chan->scan_index];
ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -356,89 +99,53 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, ...@@ -356,89 +99,53 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
} }
static const struct iio_chan_spec adis16203_channels[] = { static const struct iio_chan_spec adis16203_channels[] = {
{ ADIS_SUPPLY_CHAN(ADIS16203_SUPPLY_OUT, ADIS16203_SCAN_SUPPLY, 12),
.type = IIO_VOLTAGE, ADIS_AUX_ADC_CHAN(ADIS16203_AUX_ADC, ADIS16203_SCAN_AUX_ADC, 12),
.indexed = 1, ADIS_INCLI_CHAN(X, ADIS16203_XINCL_OUT, ADIS16203_SCAN_INCLI_X,
.channel = 0, IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
.extend_name = "supply", /* Fixme: Not what it appears to be - see data sheet */
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | ADIS_INCLI_CHAN(Y, ADIS16203_YINCL_OUT, ADIS16203_SCAN_INCLI_Y, 0, 14),
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, ADIS_TEMP_CHAN(ADIS16203_TEMP_OUT, ADIS16203_SCAN_TEMP, 12),
.address = in_supply,
.scan_index = ADIS16203_SCAN_SUPPLY,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_aux,
.scan_index = ADIS16203_SCAN_AUX_ADC,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = incli_x,
.scan_index = ADIS16203_SCAN_INCLI_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, { /* Fixme: Not what it appears to be - see data sheet */
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_y,
.scan_index = ADIS16203_SCAN_INCLI_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16203_SCAN_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(5), IIO_CHAN_SOFT_TIMESTAMP(5),
}; };
static const struct iio_info adis16203_info = { static const struct iio_info adis16203_info = {
.read_raw = &adis16203_read_raw, .read_raw = &adis16203_read_raw,
.write_raw = &adis16203_write_raw, .write_raw = &adis16203_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis16203_status_error_msgs[] = {
[ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
[ADIS16203_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16203_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16203_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16203_data = {
.read_delay = 20,
.msc_ctrl_reg = ADIS16203_MSC_CTRL,
.glob_cmd_reg = ADIS16203_GLOB_CMD,
.diag_stat_reg = ADIS16203_DIAG_STAT,
.self_test_mask = ADIS16203_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16203_STARTUP_DELAY,
.status_error_msgs = adis16203_status_error_msgs,
.status_error_mask = BIT(ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT) |
BIT(ADIS16203_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16203_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16203_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16203_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16203_probe(struct spi_device *spi) static int __devinit adis16203_probe(struct spi_device *spi)
{ {
int ret; int ret;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct adis16203_state *st; struct adis *st;
/* setup the industrialio driver allocated elements */ /* setup the industrialio driver allocated elements */
indio_dev = iio_device_alloc(sizeof(*st)); indio_dev = iio_device_alloc(sizeof(*st));
...@@ -449,8 +156,6 @@ static int __devinit adis16203_probe(struct spi_device *spi) ...@@ -449,8 +156,6 @@ static int __devinit adis16203_probe(struct spi_device *spi)
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
...@@ -459,41 +164,27 @@ static int __devinit adis16203_probe(struct spi_device *spi) ...@@ -459,41 +164,27 @@ static int __devinit adis16203_probe(struct spi_device *spi)
indio_dev->info = &adis16203_info; indio_dev->info = &adis16203_info;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16203_configure_ring(indio_dev); ret = adis_init(st, indio_dev, spi, &adis16203_data);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev, ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
adis16203_channels, if (ret)
ARRAY_SIZE(adis16203_channels)); goto error_free_dev;
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq) {
ret = adis16203_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16203_initial_setup(indio_dev); ret = adis_initial_startup(st);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16203_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16203_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -503,11 +194,10 @@ static int __devinit adis16203_probe(struct spi_device *spi) ...@@ -503,11 +194,10 @@ static int __devinit adis16203_probe(struct spi_device *spi)
static int __devexit adis16203_remove(struct spi_device *spi) static int __devexit adis16203_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16203_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_buffer_unregister(indio_dev);
adis16203_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16203.h"
/**
* adis16203_read_ring_data() read data registers which will be placed into ring
* @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
static int adis16203_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16203_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16203_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 20;
xfers[i].tx_buf = st->tx + 2 * i;
if (i < 1) /* SUPPLY_OUT: 0x02, AUX_ADC: 0x08 */
st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i);
else
st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i + 6);
st->tx[2 * i + 1] = 0;
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
static irqreturn_t adis16203_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16203_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
adis16203_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16203_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16203_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16203_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16203_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"adis16203_consumer%d",
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16203.h"
/**
* adis16203_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16203_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16203_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16203_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16203_data_rdy_trigger_set_state,
};
int adis16203_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16203_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("adis16203-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16203",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16203_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16203_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16203_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
iio_trigger_free(st->trig);
}
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#define ADIS16204_STARTUP_DELAY 220 /* ms */ #define ADIS16204_STARTUP_DELAY 220 /* ms */
#define ADIS16204_READ_REG(a) a
#define ADIS16204_WRITE_REG(a) ((a) | 0x80)
#define ADIS16204_FLASH_CNT 0x00 /* Flash memory write count */ #define ADIS16204_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16204_SUPPLY_OUT 0x02 /* Output, power supply */ #define ADIS16204_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16204_XACCL_OUT 0x04 /* Output, x-axis accelerometer */ #define ADIS16204_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
...@@ -35,8 +32,6 @@ ...@@ -35,8 +32,6 @@
#define ADIS16204_DIAG_STAT 0x3C /* Diagnostics, system status register */ #define ADIS16204_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16204_GLOB_CMD 0x3E /* Operation, system command register */ #define ADIS16204_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16204_OUTPUTS 5
/* MSC_CTRL */ /* MSC_CTRL */
#define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */ #define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
#define ADIS16204_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */ #define ADIS16204_MSC_CTRL_SELF_TEST_EN (1 << 8) /* Self-test enable */
...@@ -47,87 +42,27 @@ ...@@ -47,87 +42,27 @@
/* DIAG_STAT */ /* DIAG_STAT */
#define ADIS16204_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16204_DIAG_STAT_ALARM2 (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16204_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ #define ADIS16204_DIAG_STAT_ALARM1 (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16204_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag: 1 = error condition, #define ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT 5 /* Self-test diagnostic error flag: 1 = error condition,
0 = normal operation */ 0 = normal operation */
#define ADIS16204_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */ #define ADIS16204_DIAG_STAT_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16204_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */ #define ADIS16204_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16204_DIAG_STAT_POWER_HIGH (1<<1) /* Power supply above 3.625 V */ #define ADIS16204_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16204_DIAG_STAT_POWER_LOW (1<<0) /* Power supply below 2.975 V */ #define ADIS16204_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 2.975 V */
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16204_GLOB_CMD_SW_RESET (1<<7) #define ADIS16204_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16204_GLOB_CMD_CLEAR_STAT (1<<4) #define ADIS16204_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1) #define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16204_MAX_TX 24
#define ADIS16204_MAX_RX 24
#define ADIS16204_ERROR_ACTIVE (1<<14) #define ADIS16204_ERROR_ACTIVE (1<<14)
/**
* struct adis16204_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16204_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
u8 tx[ADIS16204_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16204_MAX_RX];
};
int adis16204_set_irq(struct iio_dev *indio_dev, bool enable);
enum adis16204_scan { enum adis16204_scan {
ADIS16204_SCAN_SUPPLY,
ADIS16204_SCAN_ACC_X, ADIS16204_SCAN_ACC_X,
ADIS16204_SCAN_ACC_Y, ADIS16204_SCAN_ACC_Y,
ADIS16204_SCAN_ACC_XY,
ADIS16204_SCAN_SUPPLY,
ADIS16204_SCAN_AUX_ADC, ADIS16204_SCAN_AUX_ADC,
ADIS16204_SCAN_TEMP, ADIS16204_SCAN_TEMP,
}; };
#ifdef CONFIG_IIO_BUFFER
void adis16204_remove_trigger(struct iio_dev *indio_dev);
int adis16204_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16204_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16204_configure_ring(struct iio_dev *indio_dev);
void adis16204_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16204_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16204_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16204_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16204_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16204_H_ */ #endif /* SPI_ADIS16204_H_ */
...@@ -21,259 +21,16 @@ ...@@ -21,259 +21,16 @@
#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/imu/adis.h>
#include "adis16204.h" #include "adis16204.h"
/**
* adis16204_spi_write_reg_8() - write single byte to a register
* @dev: device associated with child of actual device (iio_dev or iio_trig)
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16204_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16204_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16204_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16204_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16204_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16204_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16204_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16204_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16204_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16204_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16204_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 20,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 20,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16204_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16204_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16204_spi_read_reg_16(indio_dev,
ADIS16204_DIAG_STAT, &status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x1F;
if (status & ADIS16204_DIAG_STAT_SELFTEST_FAIL)
dev_err(&indio_dev->dev, "Self test failure\n");
if (status & ADIS16204_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16204_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16204_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16204_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 2.975V\n");
error_ret:
return ret;
}
static int adis16204_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16204_spi_write_reg_8(indio_dev,
ADIS16204_GLOB_CMD,
ADIS16204_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
int adis16204_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret = 0;
u16 msc;
ret = adis16204_spi_read_reg_16(indio_dev, ADIS16204_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16204_MSC_CTRL_ACTIVE_HIGH;
msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_DIO2;
if (enable)
msc |= ADIS16204_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_EN;
ret = adis16204_spi_write_reg_16(indio_dev, ADIS16204_MSC_CTRL, msc);
error_ret:
return ret;
}
static int adis16204_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16204_spi_write_reg_16(indio_dev,
ADIS16204_MSC_CTRL,
ADIS16204_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16204_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16204_initial_setup(struct iio_dev *indio_dev)
{
int ret;
/* Disable IRQ */
ret = adis16204_set_irq(indio_dev, false);
if (ret) {
dev_err(&indio_dev->dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16204_self_test(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16204_check_status(indio_dev);
if (ret) {
adis16204_reset(indio_dev);
dev_err(&indio_dev->dev, "device not playing ball -> reset");
msleep(ADIS16204_STARTUP_DELAY);
ret = adis16204_check_status(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
/* Unique to this driver currently */ /* Unique to this driver currently */
enum adis16204_channel { static const u8 adis16204_addresses[][2] = {
in_supply, [ADIS16204_SCAN_ACC_X] = { ADIS16204_XACCL_NULL, ADIS16204_X_PEAK_OUT },
in_aux, [ADIS16204_SCAN_ACC_Y] = { ADIS16204_YACCL_NULL, ADIS16204_Y_PEAK_OUT },
temp, [ADIS16204_SCAN_ACC_XY] = { 0, ADIS16204_XY_PEAK_OUT },
accel_x,
accel_y,
accel_xy,
};
static u8 adis16204_addresses[6][3] = {
[in_supply] = { ADIS16204_SUPPLY_OUT },
[in_aux] = { ADIS16204_AUX_ADC },
[temp] = { ADIS16204_TEMP_OUT },
[accel_x] = { ADIS16204_XACCL_OUT, ADIS16204_XACCL_NULL,
ADIS16204_X_PEAK_OUT },
[accel_y] = { ADIS16204_XACCL_OUT, ADIS16204_YACCL_NULL,
ADIS16204_Y_PEAK_OUT },
[accel_xy] = { ADIS16204_XY_RSS_OUT, 0,
ADIS16204_XY_PEAK_OUT },
}; };
static int adis16204_read_raw(struct iio_dev *indio_dev, static int adis16204_read_raw(struct iio_dev *indio_dev,
...@@ -281,6 +38,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, ...@@ -281,6 +38,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
int bits; int bits;
u8 addr; u8 addr;
...@@ -289,29 +47,8 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, ...@@ -289,29 +47,8 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16204_addresses[chan->address][0]; ADIS16204_ERROR_ACTIVE, val);
ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16204_ERROR_ACTIVE) {
ret = adis16204_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
...@@ -351,14 +88,14 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, ...@@ -351,14 +88,14 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PEAK: case IIO_CHAN_INFO_PEAK:
if (mask == IIO_CHAN_INFO_CALIBBIAS) { if (mask == IIO_CHAN_INFO_CALIBBIAS) {
bits = 12; bits = 12;
addrind = 1; addrind = 0;
} else { /* PEAK_SEPARATE */ } else { /* PEAK_SEPARATE */
bits = 14; bits = 14;
addrind = 2; addrind = 1;
} }
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16204_addresses[chan->address][addrind]; addr = adis16204_addresses[chan->scan_index][addrind];
ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -378,6 +115,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, ...@@ -378,6 +115,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int bits; int bits;
s16 val16; s16 val16;
u8 addr; u8 addr;
...@@ -391,112 +129,63 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, ...@@ -391,112 +129,63 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16204_addresses[chan->address][1]; addr = adis16204_addresses[chan->scan_index][1];
return adis16204_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(st, addr, val16);
} }
return -EINVAL; return -EINVAL;
} }
static const struct iio_chan_spec adis16204_channels[] = { static const struct iio_chan_spec adis16204_channels[] = {
{ ADIS_SUPPLY_CHAN(ADIS16204_SUPPLY_OUT, ADIS16204_SCAN_SUPPLY, 12),
.type = IIO_VOLTAGE, ADIS_AUX_ADC_CHAN(ADIS16204_AUX_ADC, ADIS16204_SCAN_AUX_ADC, 12),
.indexed = 1, /* Note was not previously indexed */ ADIS_TEMP_CHAN(ADIS16204_TEMP_OUT, ADIS16204_SCAN_TEMP, 12),
.channel = 0, ADIS_ACCEL_CHAN(X, ADIS16204_XACCL_OUT, ADIS16204_SCAN_ACC_X,
.extend_name = "supply",
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16204_SCAN_SUPPLY,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_aux,
.scan_index = ADIS16204_SCAN_AUX_ADC,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16204_SCAN_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
.address = accel_x, ADIS_ACCEL_CHAN(Y, ADIS16204_YACCL_OUT, ADIS16204_SCAN_ACC_Y,
.scan_index = ADIS16204_SCAN_ACC_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
.address = accel_y, ADIS_ACCEL_CHAN(ROOT_SUM_SQUARED_X_Y, ADIS16204_XY_RSS_OUT,
.scan_index = ADIS16204_SCAN_ACC_Y, ADIS16204_SCAN_ACC_XY, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(5), IIO_CHAN_SOFT_TIMESTAMP(5),
{
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_ROOT_SUM_SQUARED_X_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_xy,
.scan_type = {
.sign = 'u',
.realbits = 14,
.storagebits = 16,
},
}
}; };
static const struct iio_info adis16204_info = { static const struct iio_info adis16204_info = {
.read_raw = &adis16204_read_raw, .read_raw = &adis16204_read_raw,
.write_raw = &adis16204_write_raw, .write_raw = &adis16204_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis16204_status_error_msgs[] = {
[ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
[ADIS16204_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16204_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16204_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16204_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_data adis16204_data = {
.read_delay = 20,
.msc_ctrl_reg = ADIS16204_MSC_CTRL,
.glob_cmd_reg = ADIS16204_GLOB_CMD,
.diag_stat_reg = ADIS16204_DIAG_STAT,
.self_test_mask = ADIS16204_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16204_STARTUP_DELAY,
.status_error_msgs = adis16204_status_error_msgs,
.status_error_mask = BIT(ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT) |
BIT(ADIS16204_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16204_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16204_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16204_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16204_probe(struct spi_device *spi) static int __devinit adis16204_probe(struct spi_device *spi)
{ {
int ret; int ret;
struct adis16204_state *st; struct adis *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */ /* setup the industrialio driver allocated elements */
...@@ -508,8 +197,6 @@ static int __devinit adis16204_probe(struct spi_device *spi) ...@@ -508,8 +197,6 @@ static int __devinit adis16204_probe(struct spi_device *spi)
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
...@@ -518,40 +205,26 @@ static int __devinit adis16204_probe(struct spi_device *spi) ...@@ -518,40 +205,26 @@ static int __devinit adis16204_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16204_channels); indio_dev->num_channels = ARRAY_SIZE(adis16204_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16204_configure_ring(indio_dev); ret = adis_init(st, indio_dev, spi, &adis16204_data);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev, ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
adis16204_channels, if (ret)
6); goto error_free_dev;
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq) {
ret = adis16204_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16204_initial_setup(indio_dev); ret = adis_initial_startup(st);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16204_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16204_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -561,11 +234,10 @@ static int __devinit adis16204_probe(struct spi_device *spi) ...@@ -561,11 +234,10 @@ static int __devinit adis16204_probe(struct spi_device *spi)
static int __devexit adis16204_remove(struct spi_device *spi) static int __devexit adis16204_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16204_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_buffer_unregister(indio_dev);
adis16204_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16204.h"
/**
* adis16204_read_ring_data() read data registers which will be placed into ring
* @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
static int adis16204_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16204_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16204_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 20;
xfers[i].tx_buf = st->tx + 2 * i;
st->tx[2 * i]
= ADIS16204_READ_REG(ADIS16204_SUPPLY_OUT + 2 * i);
st->tx[2 * i + 1] = 0;
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
static irqreturn_t adis16204_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16204_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
adis16204_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16204_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16204_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16204_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16204_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"%s_consumer%d",
indio_dev->name,
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16204.h"
/**
* adis16204_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16204_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16204_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16204_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16204_data_rdy_trigger_set_state,
};
int adis16204_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16204_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("adis16204-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16204",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16204_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16204_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16204_state *state = iio_priv(indio_dev);
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
iio_trigger_free(state->trig);
}
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#define ADIS16209_STARTUP_DELAY 220 /* ms */ #define ADIS16209_STARTUP_DELAY 220 /* ms */
#define ADIS16209_READ_REG(a) a
#define ADIS16209_WRITE_REG(a) ((a) | 0x80)
/* Flash memory write count */ /* Flash memory write count */
#define ADIS16209_FLASH_CNT 0x00 #define ADIS16209_FLASH_CNT 0x00
/* Output, power supply */ /* Output, power supply */
...@@ -61,8 +58,6 @@ ...@@ -61,8 +58,6 @@
/* Operation, system command register */ /* Operation, system command register */
#define ADIS16209_GLOB_CMD 0x3E #define ADIS16209_GLOB_CMD 0x3E
#define ADIS16209_OUTPUTS 8
/* MSC_CTRL */ /* MSC_CTRL */
/* Self-test at power-on: 1 = disabled, 0 = enabled */ /* Self-test at power-on: 1 = disabled, 0 = enabled */
#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST (1 << 10) #define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST (1 << 10)
...@@ -81,44 +76,23 @@ ...@@ -81,44 +76,23 @@
/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16209_DIAG_STAT_ALARM1 (1<<8) #define ADIS16209_DIAG_STAT_ALARM1 (1<<8)
/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ /* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */
#define ADIS16209_DIAG_STAT_SELFTEST_FAIL (1<<5) #define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5
/* SPI communications failure */ /* SPI communications failure */
#define ADIS16209_DIAG_STAT_SPI_FAIL (1<<3) #define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3
/* Flash update failure */ /* Flash update failure */
#define ADIS16209_DIAG_STAT_FLASH_UPT (1<<2) #define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2
/* Power supply above 3.625 V */ /* Power supply above 3.625 V */
#define ADIS16209_DIAG_STAT_POWER_HIGH (1<<1) #define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */ /* Power supply below 3.15 V */
#define ADIS16209_DIAG_STAT_POWER_LOW (1<<0) #define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16209_GLOB_CMD_SW_RESET (1<<7) #define ADIS16209_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16209_GLOB_CMD_CLEAR_STAT (1<<4) #define ADIS16209_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16209_GLOB_CMD_FACTORY_CAL (1<<1) #define ADIS16209_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16209_MAX_TX 24
#define ADIS16209_MAX_RX 24
#define ADIS16209_ERROR_ACTIVE (1<<14) #define ADIS16209_ERROR_ACTIVE (1<<14)
/**
* struct adis16209_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16209_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
u8 tx[ADIS16209_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16209_MAX_RX];
};
int adis16209_set_irq(struct iio_dev *indio_dev, bool enable);
#define ADIS16209_SCAN_SUPPLY 0 #define ADIS16209_SCAN_SUPPLY 0
#define ADIS16209_SCAN_ACC_X 1 #define ADIS16209_SCAN_ACC_X 1
#define ADIS16209_SCAN_ACC_Y 2 #define ADIS16209_SCAN_ACC_Y 2
...@@ -128,45 +102,4 @@ int adis16209_set_irq(struct iio_dev *indio_dev, bool enable); ...@@ -128,45 +102,4 @@ int adis16209_set_irq(struct iio_dev *indio_dev, bool enable);
#define ADIS16209_SCAN_INCLI_Y 6 #define ADIS16209_SCAN_INCLI_Y 6
#define ADIS16209_SCAN_ROT 7 #define ADIS16209_SCAN_ROT 7
#ifdef CONFIG_IIO_BUFFER
void adis16209_remove_trigger(struct iio_dev *indio_dev);
int adis16209_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16209_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16209_configure_ring(struct iio_dev *indio_dev);
void adis16209_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16209_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16209_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16209_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16209_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16209_H_ */ #endif /* SPI_ADIS16209_H_ */
...@@ -19,260 +19,19 @@ ...@@ -19,260 +19,19 @@
#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/imu/adis.h>
#include "adis16209.h" #include "adis16209.h"
/** static const u8 adis16209_addresses[8][1] = {
* adis16209_spi_write_reg_8() - write single byte to a register [ADIS16209_SCAN_SUPPLY] = { },
* @indio_dev: iio device associated with actual device [ADIS16209_SCAN_AUX_ADC] = { },
* @reg_address: the address of the register to be written [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL },
* @val: the value to write [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL },
**/ [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL },
static int adis16209_spi_write_reg_8(struct iio_dev *indio_dev, [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL },
u8 reg_address, [ADIS16209_SCAN_ROT] = { },
u8 val) [ADIS16209_SCAN_TEMP] = { },
{
int ret;
struct adis16209_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16209_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16209_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16209_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16209_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 30,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 30,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16209_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16209_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16209_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16209_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16209_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 30,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 30,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16209_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev,
"problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static int adis16209_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16209_spi_write_reg_8(indio_dev,
ADIS16209_GLOB_CMD,
ADIS16209_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
int adis16209_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret = 0;
u16 msc;
ret = adis16209_spi_read_reg_16(indio_dev, ADIS16209_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16209_MSC_CTRL_ACTIVE_HIGH;
msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_DIO2;
if (enable)
msc |= ADIS16209_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_EN;
ret = adis16209_spi_write_reg_16(indio_dev, ADIS16209_MSC_CTRL, msc);
error_ret:
return ret;
}
static int adis16209_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16209_spi_read_reg_16(indio_dev,
ADIS16209_DIAG_STAT, &status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x1F;
if (status & ADIS16209_DIAG_STAT_SELFTEST_FAIL)
dev_err(&indio_dev->dev, "Self test failure\n");
if (status & ADIS16209_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16209_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16209_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16209_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
error_ret:
return ret;
}
static int adis16209_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16209_spi_write_reg_16(indio_dev,
ADIS16209_MSC_CTRL,
ADIS16209_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16209_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16209_initial_setup(struct iio_dev *indio_dev)
{
int ret;
/* Disable IRQ */
ret = adis16209_set_irq(indio_dev, false);
if (ret) {
dev_err(&indio_dev->dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16209_self_test(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16209_check_status(indio_dev);
if (ret) {
adis16209_reset(indio_dev);
dev_err(&indio_dev->dev, "device not playing ball -> reset");
msleep(ADIS16209_STARTUP_DELAY);
ret = adis16209_check_status(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
enum adis16209_chan {
in_supply,
temp,
accel_x,
accel_y,
incli_x,
incli_y,
in_aux,
rot,
};
static const u8 adis16209_addresses[8][2] = {
[in_supply] = { ADIS16209_SUPPLY_OUT },
[in_aux] = { ADIS16209_AUX_ADC },
[accel_x] = { ADIS16209_XACCL_OUT, ADIS16209_XACCL_NULL },
[accel_y] = { ADIS16209_YACCL_OUT, ADIS16209_YACCL_NULL },
[incli_x] = { ADIS16209_XINCL_OUT, ADIS16209_XINCL_NULL },
[incli_y] = { ADIS16209_YINCL_OUT, ADIS16209_YINCL_NULL },
[rot] = { ADIS16209_ROT_OUT },
[temp] = { ADIS16209_TEMP_OUT },
}; };
static int adis16209_write_raw(struct iio_dev *indio_dev, static int adis16209_write_raw(struct iio_dev *indio_dev,
...@@ -281,6 +40,7 @@ static int adis16209_write_raw(struct iio_dev *indio_dev, ...@@ -281,6 +40,7 @@ static int adis16209_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int bits; int bits;
s16 val16; s16 val16;
u8 addr; u8 addr;
...@@ -295,8 +55,8 @@ static int adis16209_write_raw(struct iio_dev *indio_dev, ...@@ -295,8 +55,8 @@ static int adis16209_write_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16209_addresses[chan->address][1]; addr = adis16209_addresses[chan->scan_index][0];
return adis16209_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(st, addr, val16);
} }
return -EINVAL; return -EINVAL;
} }
...@@ -306,6 +66,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -306,6 +66,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
int bits; int bits;
u8 addr; u8 addr;
...@@ -313,29 +74,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -313,29 +74,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16209_addresses[chan->address][0]; ADIS16209_ERROR_ACTIVE, val);
ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16209_ERROR_ACTIVE) {
ret = adis16209_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
...@@ -374,8 +114,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -374,8 +114,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16209_addresses[chan->address][1]; addr = adis16209_addresses[chan->scan_index][0];
ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -390,128 +130,56 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -390,128 +130,56 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
} }
static const struct iio_chan_spec adis16209_channels[] = { static const struct iio_chan_spec adis16209_channels[] = {
{ ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 14),
.type = IIO_VOLTAGE, ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 12),
.indexed = 1, ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X,
.channel = 0, IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
.extend_name = "supply", ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 12),
.address = in_supply, ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, 0, 14),
.scan_index = ADIS16209_SCAN_SUPPLY, ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, 0, 14),
.scan_type = { ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 14),
.sign = 'u',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_TEMP,
.indexed = 0,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16209_SCAN_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = accel_x,
.scan_index = ADIS16209_SCAN_ACC_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
.address = accel_y,
.scan_index = ADIS16209_SCAN_ACC_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_aux,
.scan_index = ADIS16209_SCAN_AUX_ADC,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_x,
.scan_index = ADIS16209_SCAN_INCLI_X,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_y,
.scan_index = ADIS16209_SCAN_INCLI_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, {
.type = IIO_ROT,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = rot,
.scan_index = ADIS16209_SCAN_ROT,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(8) IIO_CHAN_SOFT_TIMESTAMP(8)
}; };
static const struct iio_info adis16209_info = { static const struct iio_info adis16209_info = {
.read_raw = &adis16209_read_raw, .read_raw = &adis16209_read_raw,
.write_raw = &adis16209_write_raw, .write_raw = &adis16209_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis16209_status_error_msgs[] = {
[ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
[ADIS16209_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16209_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16209_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16209_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16209_data = {
.read_delay = 30,
.msc_ctrl_reg = ADIS16209_MSC_CTRL,
.glob_cmd_reg = ADIS16209_GLOB_CMD,
.diag_stat_reg = ADIS16209_DIAG_STAT,
.self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16209_STARTUP_DELAY,
.status_error_msgs = adis16209_status_error_msgs,
.status_error_mask = BIT(ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT) |
BIT(ADIS16209_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16209_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16209_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16209_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16209_probe(struct spi_device *spi) static int __devinit adis16209_probe(struct spi_device *spi)
{ {
int ret; int ret;
struct adis16209_state *st; struct adis *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */ /* setup the industrialio driver allocated elements */
...@@ -523,8 +191,6 @@ static int __devinit adis16209_probe(struct spi_device *spi) ...@@ -523,8 +191,6 @@ static int __devinit adis16209_probe(struct spi_device *spi)
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
...@@ -533,40 +199,25 @@ static int __devinit adis16209_probe(struct spi_device *spi) ...@@ -533,40 +199,25 @@ static int __devinit adis16209_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16209_channels); indio_dev->num_channels = ARRAY_SIZE(adis16209_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16209_configure_ring(indio_dev); ret = adis_init(st, indio_dev, spi, &adis16209_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev,
adis16209_channels,
ARRAY_SIZE(adis16209_channels));
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq) {
ret = adis16209_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16209_initial_setup(indio_dev); ret = adis_initial_startup(st);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16209_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16209_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -576,11 +227,10 @@ static int __devinit adis16209_probe(struct spi_device *spi) ...@@ -576,11 +227,10 @@ static int __devinit adis16209_probe(struct spi_device *spi)
static int __devexit adis16209_remove(struct spi_device *spi) static int __devexit adis16209_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16209_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_buffer_unregister(indio_dev);
adis16209_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16209.h"
/**
* adis16209_read_ring_data() read data registers which will be placed into ring
* @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
static int adis16209_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16209_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16209_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 30;
xfers[i].tx_buf = st->tx + 2 * i;
st->tx[2 * i]
= ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i);
st->tx[2 * i + 1] = 0;
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
* specific to be rolled into the core.
*/
static irqreturn_t adis16209_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16209_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
adis16209_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16209_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16209_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16209_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16209_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"%s_consumer%d",
indio_dev->name,
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16209.h"
/**
* adis16209_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16209_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16209_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16209_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16209_data_rdy_trigger_set_state,
};
int adis16209_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16209_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("adis16209-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16209",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16209_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16209_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16209_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
iio_trigger_free(st->trig);
}
#ifndef SPI_ADIS16220_H_ #ifndef SPI_ADIS16220_H_
#define SPI_ADIS16220_H_ #define SPI_ADIS16220_H_
#define ADIS16220_STARTUP_DELAY 220 /* ms */ #include <linux/iio/imu/adis.h>
#define ADIS16220_READ_REG(a) a #define ADIS16220_STARTUP_DELAY 220 /* ms */
#define ADIS16220_WRITE_REG(a) ((a) | 0x80)
/* Flash memory write count */ /* Flash memory write count */
#define ADIS16220_FLASH_CNT 0x00 #define ADIS16220_FLASH_CNT 0x00
...@@ -102,15 +101,15 @@ ...@@ -102,15 +101,15 @@
#define ADIS16220_DIAG_STAT_FLASH_CHK (1<<6) #define ADIS16220_DIAG_STAT_FLASH_CHK (1<<6)
#define ADIS16220_DIAG_STAT_SELF_TEST (1<<5) #define ADIS16220_DIAG_STAT_SELF_TEST (1<<5)
/* Capture period violation/interruption */ /* Capture period violation/interruption */
#define ADIS16220_DIAG_STAT_VIOLATION (1<<4) #define ADIS16220_DIAG_STAT_VIOLATION_BIT 4
/* SPI communications failure */ /* SPI communications failure */
#define ADIS16220_DIAG_STAT_SPI_FAIL (1<<3) #define ADIS16220_DIAG_STAT_SPI_FAIL_BIT 3
/* Flash update failure */ /* Flash update failure */
#define ADIS16220_DIAG_STAT_FLASH_UPT (1<<2) #define ADIS16220_DIAG_STAT_FLASH_UPT_BIT 2
/* Power supply above 3.625 V */ /* Power supply above 3.625 V */
#define ADIS16220_DIAG_STAT_POWER_HIGH (1<<1) #define ADIS16220_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */ /* Power supply below 3.15 V */
#define ADIS16220_DIAG_STAT_POWER_LOW (1<<0) #define ADIS16220_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16220_GLOB_CMD_SW_RESET (1<<7) #define ADIS16220_GLOB_CMD_SW_RESET (1<<7)
...@@ -125,13 +124,14 @@ ...@@ -125,13 +124,14 @@
/** /**
* struct adis16220_state - device instance specific data * struct adis16220_state - device instance specific data
* @us: actual spi_device * @adis: adis device
* @tx: transmit buffer * @tx: transmit buffer
* @rx: receive buffer * @rx: receive buffer
* @buf_lock: mutex to protect tx and rx * @buf_lock: mutex to protect tx and rx
**/ **/
struct adis16220_state { struct adis16220_state {
struct spi_device *us; struct adis adis;
struct mutex buf_lock; struct mutex buf_lock;
u8 tx[ADIS16220_MAX_TX] ____cacheline_aligned; u8 tx[ADIS16220_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16220_MAX_RX]; u8 rx[ADIS16220_MAX_RX];
......
...@@ -20,136 +20,19 @@ ...@@ -20,136 +20,19 @@
#include "adis16220.h" #include "adis16220.h"
/**
* adis16220_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16220_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16220_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16220_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16220_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16220_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16220_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16220_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16220_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev,
"problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t adis16220_read_16bit(struct device *dev, static ssize_t adis16220_read_16bit(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16220_state *st = iio_priv(indio_dev);
ssize_t ret; ssize_t ret;
s16 val = 0; s16 val = 0;
/* Take the iio_dev status lock */ /* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = adis16220_spi_read_reg_16(indio_dev, this_attr->address, ret = adis_read_reg_16(&st->adis, this_attr->address,
(u16 *)&val); (u16 *)&val);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
if (ret) if (ret)
...@@ -164,13 +47,14 @@ static ssize_t adis16220_write_16bit(struct device *dev, ...@@ -164,13 +47,14 @@ static ssize_t adis16220_write_16bit(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);
struct adis16220_state *st = iio_priv(indio_dev);
int ret; int ret;
u16 val; u16 val;
ret = kstrtou16(buf, 10, &val); ret = kstrtou16(buf, 10, &val);
if (ret) if (ret)
goto error_ret; goto error_ret;
ret = adis16220_spi_write_reg_16(indio_dev, this_attr->address, val); ret = adis_write_reg_16(&st->adis, this_attr->address, val);
error_ret: error_ret:
return ret ? ret : len; return ret ? ret : len;
...@@ -178,10 +62,11 @@ static ssize_t adis16220_write_16bit(struct device *dev, ...@@ -178,10 +62,11 @@ static ssize_t adis16220_write_16bit(struct device *dev,
static int adis16220_capture(struct iio_dev *indio_dev) static int adis16220_capture(struct iio_dev *indio_dev)
{ {
struct adis16220_state *st = iio_priv(indio_dev);
int ret; int ret;
ret = adis16220_spi_write_reg_16(indio_dev,
ADIS16220_GLOB_CMD, /* initiates a manual data capture */
0xBF08); /* initiates a manual data capture */ ret = adis_write_reg_16(&st->adis, ADIS16220_GLOB_CMD, 0xBF08);
if (ret) if (ret)
dev_err(&indio_dev->dev, "problem beginning capture"); dev_err(&indio_dev->dev, "problem beginning capture");
...@@ -190,18 +75,6 @@ static int adis16220_capture(struct iio_dev *indio_dev) ...@@ -190,18 +75,6 @@ static int adis16220_capture(struct iio_dev *indio_dev)
return ret; return ret;
} }
static int adis16220_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16220_spi_write_reg_8(indio_dev,
ADIS16220_GLOB_CMD,
ADIS16220_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
static ssize_t adis16220_write_capture(struct device *dev, static ssize_t adis16220_write_capture(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
...@@ -222,81 +95,6 @@ static ssize_t adis16220_write_capture(struct device *dev, ...@@ -222,81 +95,6 @@ static ssize_t adis16220_write_capture(struct device *dev,
return len; return len;
} }
static int adis16220_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16220_spi_read_reg_16(indio_dev, ADIS16220_DIAG_STAT,
&status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x7F;
if (status & ADIS16220_DIAG_STAT_VIOLATION)
dev_err(&indio_dev->dev,
"Capture period violation/interruption\n");
if (status & ADIS16220_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16220_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16220_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16220_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
error_ret:
return ret;
}
static int adis16220_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16220_spi_write_reg_16(indio_dev,
ADIS16220_MSC_CTRL,
ADIS16220_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16220_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16220_initial_setup(struct iio_dev *indio_dev)
{
int ret;
/* Do self test */
ret = adis16220_self_test(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16220_check_status(indio_dev);
if (ret) {
adis16220_reset(indio_dev);
dev_err(&indio_dev->dev, "device not playing ball -> reset");
msleep(ADIS16220_STARTUP_DELAY);
ret = adis16220_check_status(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
char *buf, char *buf,
loff_t off, loff_t off,
...@@ -333,7 +131,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, ...@@ -333,7 +131,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
count = ADIS16220_CAPTURE_SIZE - off; count = ADIS16220_CAPTURE_SIZE - off;
/* write the begin position of capture buffer */ /* write the begin position of capture buffer */
ret = adis16220_spi_write_reg_16(indio_dev, ret = adis_write_reg_16(&st->adis,
ADIS16220_CAPT_PNTR, ADIS16220_CAPT_PNTR,
off > 1); off > 1);
if (ret) if (ret)
...@@ -342,8 +140,9 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, ...@@ -342,8 +140,9 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
/* read count/2 values from capture buffer */ /* read count/2 values from capture buffer */
mutex_lock(&st->buf_lock); mutex_lock(&st->buf_lock);
for (i = 0; i < count; i += 2) { for (i = 0; i < count; i += 2) {
st->tx[i] = ADIS16220_READ_REG(addr); st->tx[i] = ADIS_READ_REG(addr);
st->tx[i + 1] = 0; st->tx[i + 1] = 0;
} }
xfers[1].len = count; xfers[1].len = count;
...@@ -351,7 +150,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev, ...@@ -351,7 +150,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
spi_message_init(&msg); spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg); spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg); spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg); ret = spi_sync(st->adis.spi, &msg);
if (ret) { if (ret) {
mutex_unlock(&st->buf_lock); mutex_unlock(&st->buf_lock);
...@@ -472,6 +271,8 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, ...@@ -472,6 +271,8 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis16220_state *st = iio_priv(indio_dev);
const struct adis16220_address_spec *addr;
int ret = -EINVAL; int ret = -EINVAL;
int addrind = 0; int addrind = 0;
u16 uval; u16 uval;
...@@ -516,28 +317,21 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, ...@@ -516,28 +317,21 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
default: default:
return -EINVAL; return -EINVAL;
} }
if (adis16220_addresses[chan->address][addrind].sign) { addr = &adis16220_addresses[chan->address][addrind];
ret = adis16220_spi_read_reg_16(indio_dev, if (addr->sign) {
adis16220_addresses[chan ret = adis_read_reg_16(&st->adis, addr->addr, &sval);
->address]
[addrind].addr,
&sval);
if (ret) if (ret)
return ret; return ret;
bits = adis16220_addresses[chan->address][addrind].bits; bits = addr->bits;
sval &= (1 << bits) - 1; sval &= (1 << bits) - 1;
sval = (s16)(sval << (16 - bits)) >> (16 - bits); sval = (s16)(sval << (16 - bits)) >> (16 - bits);
*val = sval; *val = sval;
return IIO_VAL_INT; return IIO_VAL_INT;
} else { } else {
ret = adis16220_spi_read_reg_16(indio_dev, ret = adis_read_reg_16(&st->adis, addr->addr, &uval);
adis16220_addresses[chan
->address]
[addrind].addr,
&uval);
if (ret) if (ret)
return ret; return ret;
bits = adis16220_addresses[chan->address][addrind].bits; bits = addr->bits;
uval &= (1 << bits) - 1; uval &= (1 << bits) - 1;
*val = uval; *val = uval;
return IIO_VAL_INT; return IIO_VAL_INT;
...@@ -601,6 +395,32 @@ static const struct iio_info adis16220_info = { ...@@ -601,6 +395,32 @@ static const struct iio_info adis16220_info = {
.read_raw = &adis16220_read_raw, .read_raw = &adis16220_read_raw,
}; };
static const char * const adis16220_status_error_msgs[] = {
[ADIS16220_DIAG_STAT_VIOLATION_BIT] = "Capture period violation/interruption",
[ADIS16220_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16220_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16220_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16220_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16220_data = {
.read_delay = 35,
.write_delay = 35,
.msc_ctrl_reg = ADIS16220_MSC_CTRL,
.glob_cmd_reg = ADIS16220_GLOB_CMD,
.diag_stat_reg = ADIS16220_DIAG_STAT,
.self_test_mask = ADIS16220_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16220_STARTUP_DELAY,
.status_error_msgs = adis16220_status_error_msgs,
.status_error_mask = BIT(ADIS16220_DIAG_STAT_VIOLATION_BIT) |
BIT(ADIS16220_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16220_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16220_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16220_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16220_probe(struct spi_device *spi) static int __devinit adis16220_probe(struct spi_device *spi)
{ {
int ret; int ret;
...@@ -618,9 +438,6 @@ static int __devinit adis16220_probe(struct spi_device *spi) ...@@ -618,9 +438,6 @@ static int __devinit adis16220_probe(struct spi_device *spi)
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16220_info; indio_dev->info = &adis16220_info;
...@@ -644,8 +461,11 @@ static int __devinit adis16220_probe(struct spi_device *spi) ...@@ -644,8 +461,11 @@ static int __devinit adis16220_probe(struct spi_device *spi)
if (ret) if (ret)
goto error_rm_adc1_bin; goto error_rm_adc1_bin;
ret = adis_init(&st->adis, indio_dev, spi, &adis16220_data);
if (ret)
goto error_rm_adc2_bin;
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16220_initial_setup(indio_dev); ret = adis_initial_startup(&st->adis);
if (ret) if (ret)
goto error_rm_adc2_bin; goto error_rm_adc2_bin;
return 0; return 0;
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
#define ADIS16240_STARTUP_DELAY 220 /* ms */ #define ADIS16240_STARTUP_DELAY 220 /* ms */
#define ADIS16240_READ_REG(a) a
#define ADIS16240_WRITE_REG(a) ((a) | 0x80)
/* Flash memory write count */ /* Flash memory write count */
#define ADIS16240_FLASH_CNT 0x00 #define ADIS16240_FLASH_CNT 0x00
/* Output, power supply */ /* Output, power supply */
...@@ -75,8 +72,6 @@ ...@@ -75,8 +72,6 @@
/* System command */ /* System command */
#define ADIS16240_GLOB_CMD 0x4A #define ADIS16240_GLOB_CMD 0x4A
#define ADIS16240_OUTPUTS 6
/* MSC_CTRL */ /* MSC_CTRL */
/* Enables sum-of-squares output (XYZPEAK_OUT) */ /* Enables sum-of-squares output (XYZPEAK_OUT) */
#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN (1 << 15) #define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN (1 << 15)
...@@ -101,17 +96,17 @@ ...@@ -101,17 +96,17 @@
/* Flash test, checksum flag: 1 = mismatch, 0 = match */ /* Flash test, checksum flag: 1 = mismatch, 0 = match */
#define ADIS16240_DIAG_STAT_CHKSUM (1<<6) #define ADIS16240_DIAG_STAT_CHKSUM (1<<6)
/* Power-on, self-test flag: 1 = failure, 0 = pass */ /* Power-on, self-test flag: 1 = failure, 0 = pass */
#define ADIS16240_DIAG_STAT_PWRON_FAIL (1<<5) #define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT 5
/* Power-on self-test: 1 = in-progress, 0 = complete */ /* Power-on self-test: 1 = in-progress, 0 = complete */
#define ADIS16240_DIAG_STAT_PWRON_BUSY (1<<4) #define ADIS16240_DIAG_STAT_PWRON_BUSY (1<<4)
/* SPI communications failure */ /* SPI communications failure */
#define ADIS16240_DIAG_STAT_SPI_FAIL (1<<3) #define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3
/* Flash update failure */ /* Flash update failure */
#define ADIS16240_DIAG_STAT_FLASH_UPT (1<<2) #define ADIS16240_DIAG_STAT_FLASH_UPT_BIT 2
/* Power supply above 3.625 V */ /* Power supply above 3.625 V */
#define ADIS16240_DIAG_STAT_POWER_HIGH (1<<1) #define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */ /* Power supply below 3.15 V */
#define ADIS16240_DIAG_STAT_POWER_LOW (1<<0) #define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16240_GLOB_CMD_RESUME (1<<8) #define ADIS16240_GLOB_CMD_RESUME (1<<8)
...@@ -120,77 +115,15 @@ ...@@ -120,77 +115,15 @@
#define ADIS16240_ERROR_ACTIVE (1<<14) #define ADIS16240_ERROR_ACTIVE (1<<14)
#define ADIS16240_MAX_TX 24
#define ADIS16240_MAX_RX 24
/**
* struct adis16240_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16240_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
u8 tx[ADIS16240_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16240_MAX_RX];
};
int adis16240_set_irq(struct iio_dev *indio_dev, bool enable);
/* At the moment triggers are only used for ring buffer /* At the moment triggers are only used for ring buffer
* filling. This may change! * filling. This may change!
*/ */
#define ADIS16240_SCAN_SUPPLY 0 #define ADIS16240_SCAN_ACC_X 0
#define ADIS16240_SCAN_ACC_X 1 #define ADIS16240_SCAN_ACC_Y 1
#define ADIS16240_SCAN_ACC_Y 2 #define ADIS16240_SCAN_ACC_Z 2
#define ADIS16240_SCAN_ACC_Z 3 #define ADIS16240_SCAN_SUPPLY 3
#define ADIS16240_SCAN_AUX_ADC 4 #define ADIS16240_SCAN_AUX_ADC 4
#define ADIS16240_SCAN_TEMP 5 #define ADIS16240_SCAN_TEMP 5
#ifdef CONFIG_IIO_BUFFER
void adis16240_remove_trigger(struct iio_dev *indio_dev);
int adis16240_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16240_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16240_configure_ring(struct iio_dev *indio_dev);
void adis16240_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16240_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16240_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16240_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16240_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16240_unconfigure_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16240_H_ */ #endif /* SPI_ADIS16240_H_ */
...@@ -22,149 +22,29 @@ ...@@ -22,149 +22,29 @@
#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/imu/adis.h>
#include "adis16240.h" #include "adis16240.h"
static int adis16240_check_status(struct iio_dev *indio_dev);
/**
* adis16240_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio_dev associated with device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16240_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16240_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16240_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16240_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio_dev for this device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16240_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16240_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16240_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16240_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16240_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio_dev for this device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16240_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16240_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16240_READ_REG(lower_reg_address);
st->tx[1] = 0;
st->tx[2] = 0;
st->tx[3] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev,
"problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t adis16240_spi_read_signed(struct device *dev, static ssize_t adis16240_spi_read_signed(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf, char *buf,
unsigned bits) unsigned bits)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
s16 val = 0; s16 val = 0;
unsigned shift = 16 - bits; unsigned shift = 16 - bits;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = adis16240_spi_read_reg_16(indio_dev, ret = adis_read_reg_16(st,
this_attr->address, (u16 *)&val); this_attr->address, (u16 *)&val);
if (ret) if (ret)
return ret; return ret;
if (val & ADIS16240_ERROR_ACTIVE) if (val & ADIS16240_ERROR_ACTIVE)
adis16240_check_status(indio_dev); adis_check_status(st);
val = ((s16)(val << shift) >> shift); val = ((s16)(val << shift) >> shift);
return sprintf(buf, "%d\n", val); return sprintf(buf, "%d\n", val);
...@@ -185,152 +65,16 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev, ...@@ -185,152 +65,16 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev,
return ret; return ret;
} }
static int adis16240_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16240_spi_write_reg_8(indio_dev,
ADIS16240_GLOB_CMD,
ADIS16240_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
int adis16240_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret = 0;
u16 msc;
ret = adis16240_spi_read_reg_16(indio_dev,
ADIS16240_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16240_MSC_CTRL_ACTIVE_HIGH;
msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_DIO2;
if (enable)
msc |= ADIS16240_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_EN;
ret = adis16240_spi_write_reg_16(indio_dev,
ADIS16240_MSC_CTRL, msc);
error_ret:
return ret;
}
static int adis16240_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16240_spi_write_reg_16(indio_dev,
ADIS16240_MSC_CTRL,
ADIS16240_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
msleep(ADIS16240_STARTUP_DELAY);
adis16240_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16240_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
struct device *dev = &indio_dev->dev;
ret = adis16240_spi_read_reg_16(indio_dev,
ADIS16240_DIAG_STAT, &status);
if (ret < 0) {
dev_err(dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x2F;
if (status & ADIS16240_DIAG_STAT_PWRON_FAIL)
dev_err(dev, "Power-on, self-test fail\n");
if (status & ADIS16240_DIAG_STAT_SPI_FAIL)
dev_err(dev, "SPI failure\n");
if (status & ADIS16240_DIAG_STAT_FLASH_UPT)
dev_err(dev, "Flash update failed\n");
if (status & ADIS16240_DIAG_STAT_POWER_HIGH)
dev_err(dev, "Power supply above 3.625V\n");
if (status & ADIS16240_DIAG_STAT_POWER_LOW)
dev_err(dev, "Power supply below 2.225V\n");
error_ret:
return ret;
}
static int adis16240_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct device *dev = &indio_dev->dev;
/* Disable IRQ */
ret = adis16240_set_irq(indio_dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16240_self_test(indio_dev);
if (ret) {
dev_err(dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16240_check_status(indio_dev);
if (ret) {
adis16240_reset(indio_dev);
dev_err(dev, "device not playing ball -> reset");
msleep(ADIS16240_STARTUP_DELAY);
ret = adis16240_check_status(indio_dev);
if (ret) {
dev_err(dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, S_IRUGO, static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, S_IRUGO,
adis16240_read_12bit_signed, NULL, adis16240_read_12bit_signed, NULL,
ADIS16240_XYZPEAK_OUT); ADIS16240_XYZPEAK_OUT);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096"); static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096");
enum adis16240_chan { static const u8 adis16240_addresses[][2] = {
in_supply, [ADIS16240_SCAN_ACC_X] = { ADIS16240_XACCL_OFF, ADIS16240_XPEAK_OUT },
in_aux, [ADIS16240_SCAN_ACC_Y] = { ADIS16240_YACCL_OFF, ADIS16240_YPEAK_OUT },
accel_x, [ADIS16240_SCAN_ACC_Z] = { ADIS16240_ZACCL_OFF, ADIS16240_ZPEAK_OUT },
accel_y,
accel_z,
temp,
};
static const u8 adis16240_addresses[6][3] = {
[in_supply] = { ADIS16240_SUPPLY_OUT },
[in_aux] = { ADIS16240_AUX_ADC },
[accel_x] = { ADIS16240_XACCL_OUT, ADIS16240_XACCL_OFF,
ADIS16240_XPEAK_OUT },
[accel_y] = { ADIS16240_YACCL_OUT, ADIS16240_YACCL_OFF,
ADIS16240_YPEAK_OUT },
[accel_z] = { ADIS16240_ZACCL_OUT, ADIS16240_ZACCL_OFF,
ADIS16240_ZPEAK_OUT },
[temp] = { ADIS16240_TEMP_OUT },
}; };
static int adis16240_read_raw(struct iio_dev *indio_dev, static int adis16240_read_raw(struct iio_dev *indio_dev,
...@@ -338,6 +82,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -338,6 +82,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, int *val, int *val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int ret; int ret;
int bits; int bits;
u8 addr; u8 addr;
...@@ -345,29 +90,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -345,29 +90,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16240_addresses[chan->address][0]; ADIS16240_ERROR_ACTIVE, val);
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16240_ERROR_ACTIVE) {
ret = adis16240_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
...@@ -400,8 +124,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -400,8 +124,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
bits = 10; bits = 10;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][1]; addr = adis16240_addresses[chan->scan_index][0];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -414,8 +138,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -414,8 +138,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PEAK: case IIO_CHAN_INFO_PEAK:
bits = 10; bits = 10;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][2]; addr = adis16240_addresses[chan->scan_index][1];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -435,104 +159,32 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, ...@@ -435,104 +159,32 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis *st = iio_priv(indio_dev);
int bits = 10; int bits = 10;
s16 val16; s16 val16;
u8 addr; u8 addr;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16240_addresses[chan->address][1]; addr = adis16240_addresses[chan->scan_index][0];
return adis16240_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(st, addr, val16);
} }
return -EINVAL; return -EINVAL;
} }
static const struct iio_chan_spec adis16240_channels[] = { static const struct iio_chan_spec adis16240_channels[] = {
{ ADIS_SUPPLY_CHAN(ADIS16240_SUPPLY_OUT, ADIS16240_SCAN_SUPPLY, 10),
.type = IIO_VOLTAGE, ADIS_AUX_ADC_CHAN(ADIS16240_AUX_ADC, ADIS16240_SCAN_AUX_ADC, 10),
.indexed = 1, ADIS_ACCEL_CHAN(X, ADIS16240_XACCL_OUT, ADIS16240_SCAN_ACC_X,
.channel = 0,
.extend_name = "supply",
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16240_SCAN_SUPPLY,
.scan_type = {
.sign = 'u',
.realbits = 10,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = in_aux,
.scan_index = ADIS16240_SCAN_AUX_ADC,
.scan_type = {
.sign = 'u',
.realbits = 10,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
.address = accel_x, ADIS_ACCEL_CHAN(Y, ADIS16240_YACCL_OUT, ADIS16240_SCAN_ACC_Y,
.scan_index = ADIS16240_SCAN_ACC_X,
.scan_type = {
.sign = 's',
.realbits = 10,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
.address = accel_y, ADIS_ACCEL_CHAN(Z, ADIS16240_ZACCL_OUT, ADIS16240_SCAN_ACC_Z,
.scan_index = ADIS16240_SCAN_ACC_Y,
.scan_type = {
.sign = 's',
.realbits = 10,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
.address = accel_z, ADIS_TEMP_CHAN(ADIS16240_TEMP_OUT, ADIS16240_SCAN_TEMP, 10),
.scan_index = ADIS16240_SCAN_ACC_Z,
.scan_type = {
.sign = 's',
.realbits = 10,
.storagebits = 16,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16240_SCAN_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 10,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(6) IIO_CHAN_SOFT_TIMESTAMP(6)
}; };
...@@ -550,13 +202,40 @@ static const struct iio_info adis16240_info = { ...@@ -550,13 +202,40 @@ static const struct iio_info adis16240_info = {
.attrs = &adis16240_attribute_group, .attrs = &adis16240_attribute_group,
.read_raw = &adis16240_read_raw, .read_raw = &adis16240_read_raw,
.write_raw = &adis16240_write_raw, .write_raw = &adis16240_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis16240_status_error_msgs[] = {
[ADIS16240_DIAG_STAT_PWRON_FAIL_BIT] = "Power on, self-test failed",
[ADIS16240_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16240_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16240_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16240_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.225V",
};
static const struct adis_data adis16240_data = {
.write_delay = 35,
.read_delay = 35,
.msc_ctrl_reg = ADIS16240_MSC_CTRL,
.glob_cmd_reg = ADIS16240_GLOB_CMD,
.diag_stat_reg = ADIS16240_DIAG_STAT,
.self_test_mask = ADIS16240_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16240_STARTUP_DELAY,
.status_error_msgs = adis16240_status_error_msgs,
.status_error_mask = BIT(ADIS16240_DIAG_STAT_PWRON_FAIL_BIT) |
BIT(ADIS16240_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16240_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16240_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16240_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16240_probe(struct spi_device *spi) static int __devinit adis16240_probe(struct spi_device *spi)
{ {
int ret; int ret;
struct adis16240_state *st; struct adis *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */ /* setup the industrialio driver allocated elements */
...@@ -569,9 +248,6 @@ static int __devinit adis16240_probe(struct spi_device *spi) ...@@ -569,9 +248,6 @@ static int __devinit adis16240_probe(struct spi_device *spi)
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name; indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16240_info; indio_dev->info = &adis16240_info;
...@@ -579,39 +255,24 @@ static int __devinit adis16240_probe(struct spi_device *spi) ...@@ -579,39 +255,24 @@ static int __devinit adis16240_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16240_channels); indio_dev->num_channels = ARRAY_SIZE(adis16240_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16240_configure_ring(indio_dev); ret = adis_init(st, indio_dev, spi, &adis16240_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev,
adis16240_channels,
ARRAY_SIZE(adis16240_channels));
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (spi->irq) {
ret = adis16240_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16240_initial_setup(indio_dev); ret = adis_initial_startup(st);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16240_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16240_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -620,13 +281,11 @@ static int __devinit adis16240_probe(struct spi_device *spi) ...@@ -620,13 +281,11 @@ static int __devinit adis16240_probe(struct spi_device *spi)
static int __devexit adis16240_remove(struct spi_device *spi) static int __devexit adis16240_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16240_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_buffer_unregister(indio_dev);
adis16240_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16240.h"
/**
* adis16240_read_ring_data() read data registers which will be placed into ring
* @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
static int adis16240_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16240_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16240_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16240_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 30;
xfers[i].tx_buf = st->tx + 2 * i;
st->tx[2 * i]
= ADIS16240_READ_REG(ADIS16240_SUPPLY_OUT + 2 * i);
st->tx[2 * i + 1] = 0;
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
static irqreturn_t adis16240_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16240_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
adis16240_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16240_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16240_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16240_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16240_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16240_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"%s_consumer%d",
indio_dev->name,
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16240.h"
/**
* adis16240_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16240_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16240_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16240_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16240_data_rdy_trigger_set_state,
};
int adis16240_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16240_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("adis16240-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16240",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16240_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16240_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16240_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
iio_trigger_free(st->trig);
}
...@@ -10,17 +10,6 @@ config AD7291 ...@@ -10,17 +10,6 @@ config AD7291
Say yes here to build support for Analog Devices AD7291 Say yes here to build support for Analog Devices AD7291
8 Channel ADC with temperature sensor. 8 Channel ADC with temperature sensor.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices AD7298
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7298.
config AD7606 config AD7606
tristate "Analog Devices AD7606 ADC driver" tristate "Analog Devices AD7606 ADC driver"
depends on GPIOLIB depends on GPIOLIB
......
...@@ -12,10 +12,6 @@ ad799x-y := ad799x_core.o ...@@ -12,10 +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_AD7291) += ad7291.o obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7793) += ad7793.o
......
/*
* AD7298 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef 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)
/*
* TODO: struct ad7298_platform_data needs to go into include/linux/iio
*/
struct ad7298_platform_data {
/* External Vref voltage applied */
u16 vref_mv;
};
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
u16 int_vref_mv;
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[8] ____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_ */
/*
* 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;
__u16 buf[16];
int b_sent, i;
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 *)buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
for (i = 0; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
buf[i] = be16_to_cpu(st->rx_buf[i]);
iio_push_to_buffers(indio_dev, (u8 *)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);
}
...@@ -181,7 +181,7 @@ static ssize_t adt7410_store_mode(struct device *dev, ...@@ -181,7 +181,7 @@ static ssize_t adt7410_store_mode(struct device *dev,
chip->config = config; chip->config = config;
return ret; return len;
} }
static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
......
...@@ -12,7 +12,6 @@ adis16130-y := adis16130_core.o ...@@ -12,7 +12,6 @@ adis16130-y := adis16130_core.o
obj-$(CONFIG_ADIS16130) += adis16130.o obj-$(CONFIG_ADIS16130) += adis16130.o
adis16260-y := adis16260_core.o adis16260-y := adis16260_core.o
adis16260-$(CONFIG_IIO_BUFFER) += adis16260_ring.o adis16260_trigger.o
obj-$(CONFIG_ADIS16260) += adis16260.o obj-$(CONFIG_ADIS16260) += adis16260.o
adis16251-y := adis16251_core.o adis16251-y := adis16251_core.o
......
#ifndef SPI_ADIS16260_H_ #ifndef SPI_ADIS16260_H_
#define SPI_ADIS16260_H_ #define SPI_ADIS16260_H_
#include "adis16260_platform_data.h" #include "adis16260_platform_data.h"
#include <linux/iio/imu/adis.h>
#define ADIS16260_STARTUP_DELAY 220 /* ms */ #define ADIS16260_STARTUP_DELAY 220 /* ms */
#define ADIS16260_READ_REG(a) a
#define ADIS16260_WRITE_REG(a) ((a) | 0x80)
#define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */ #define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */ #define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */ #define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */
...@@ -34,8 +33,6 @@ ...@@ -34,8 +33,6 @@
* convert to decimal = 16,265/16,260 */ * convert to decimal = 16,265/16,260 */
#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */ #define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
#define ADIS16260_OUTPUTS 5
#define ADIS16260_ERROR_ACTIVE (1<<14) #define ADIS16260_ERROR_ACTIVE (1<<14)
#define ADIS16260_NEW_DATA (1<<15) #define ADIS16260_NEW_DATA (1<<15)
...@@ -60,13 +57,13 @@ ...@@ -60,13 +57,13 @@
/* DIAG_STAT */ /* DIAG_STAT */
#define ADIS16260_DIAG_STAT_ALARM2 (1<<9) #define ADIS16260_DIAG_STAT_ALARM2 (1<<9)
#define ADIS16260_DIAG_STAT_ALARM1 (1<<8) #define ADIS16260_DIAG_STAT_ALARM1 (1<<8)
#define ADIS16260_DIAG_STAT_FLASH_CHK (1<<6) #define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6
#define ADIS16260_DIAG_STAT_SELF_TEST (1<<5) #define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5
#define ADIS16260_DIAG_STAT_OVERFLOW (1<<4) #define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4
#define ADIS16260_DIAG_STAT_SPI_FAIL (1<<3) #define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3
#define ADIS16260_DIAG_STAT_FLASH_UPT (1<<2) #define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2
#define ADIS16260_DIAG_STAT_POWER_HIGH (1<<1) #define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1
#define ADIS16260_DIAG_STAT_POWER_LOW (1<<0) #define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */ /* GLOB_CMD */
#define ADIS16260_GLOB_CMD_SW_RESET (1<<7) #define ADIS16260_GLOB_CMD_SW_RESET (1<<7)
...@@ -75,82 +72,27 @@ ...@@ -75,82 +72,27 @@
#define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1) #define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1)
#define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0) #define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0)
#define ADIS16260_MAX_TX 24
#define ADIS16260_MAX_RX 24
#define ADIS16260_SPI_SLOW (u32)(300 * 1000) #define ADIS16260_SPI_SLOW (u32)(300 * 1000)
#define ADIS16260_SPI_BURST (u32)(1000 * 1000) #define ADIS16260_SPI_BURST (u32)(1000 * 1000)
#define ADIS16260_SPI_FAST (u32)(2000 * 1000) #define ADIS16260_SPI_FAST (u32)(2000 * 1000)
/** /**
* struct adis16260_state - device instance specific data * struct adis16260_state - device instance specific data
* @us: actual spi_device
* @trig: data ready trigger registered with iio
* @buf_lock: mutex to protect tx and rx
* @negate: negate the scale parameter * @negate: negate the scale parameter
* @tx: transmit buffer
* @rx: receive buffer
**/ **/
struct adis16260_state { struct adis16260_state {
struct spi_device *us; unsigned negate:1;
struct iio_trigger *trig; struct adis adis;
struct mutex buf_lock;
unsigned negate:1;
u8 tx[ADIS16260_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16260_MAX_RX];
}; };
int adis16260_set_irq(struct iio_dev *indio_dev, bool enable);
/* At the moment triggers are only used for ring buffer /* At the moment triggers are only used for ring buffer
* filling. This may change! * filling. This may change!
*/ */
#define ADIS16260_SCAN_SUPPLY 0 #define ADIS16260_SCAN_GYRO 0
#define ADIS16260_SCAN_GYRO 1 #define ADIS16260_SCAN_SUPPLY 1
#define ADIS16260_SCAN_AUX_ADC 2 #define ADIS16260_SCAN_AUX_ADC 2
#define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_TEMP 3
#define ADIS16260_SCAN_ANGL 4 #define ADIS16260_SCAN_ANGL 4
#ifdef CONFIG_IIO_BUFFER
void adis16260_remove_trigger(struct iio_dev *indio_dev);
int adis16260_probe_trigger(struct iio_dev *indio_dev);
ssize_t adis16260_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16260_configure_ring(struct iio_dev *indio_dev);
void adis16260_unconfigure_ring(struct iio_dev *indio_dev);
#else /* CONFIG_IIO_BUFFER */
static inline void adis16260_remove_trigger(struct iio_dev *indio_dev)
{
}
static inline int adis16260_probe_trigger(struct iio_dev *indio_dev)
{
return 0;
}
static inline ssize_t
adis16260_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static int adis16260_configure_ring(struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis16260_unconfigure_ring(struct iio_dev *indio_dev)
{
}
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16260_H_ */ #endif /* SPI_ADIS16260_H_ */
...@@ -24,132 +24,13 @@ ...@@ -24,132 +24,13 @@
#include "adis16260.h" #include "adis16260.h"
static int adis16260_check_status(struct iio_dev *indio_dev);
/**
* adis16260_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio_dev for the device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16260_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16260_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16260_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16260_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio_dev for the device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16260_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16260_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 20,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 20,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16260_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16260_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16260_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio_dev for the device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16260_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16260_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 30,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 30,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16260_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev,
"problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t adis16260_read_frequency_available(struct device *dev, static ssize_t adis16260_read_frequency_available(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev); struct adis16260_state *st = iio_priv(indio_dev);
if (spi_get_device_id(st->us)->driver_data) if (spi_get_device_id(st->adis.spi)->driver_data)
return sprintf(buf, "%s\n", "0.129 ~ 256"); return sprintf(buf, "%s\n", "0.129 ~ 256");
else else
return sprintf(buf, "%s\n", "256 2048"); return sprintf(buf, "%s\n", "256 2048");
...@@ -164,13 +45,11 @@ static ssize_t adis16260_read_frequency(struct device *dev, ...@@ -164,13 +45,11 @@ static ssize_t adis16260_read_frequency(struct device *dev,
int ret, len = 0; int ret, len = 0;
u16 t; u16 t;
int sps; int sps;
ret = adis16260_spi_read_reg_16(indio_dev, ret = adis_read_reg_16(&st->adis, ADIS16260_SMPL_PRD, &t);
ADIS16260_SMPL_PRD,
&t);
if (ret) if (ret)
return ret; return ret;
if (spi_get_device_id(st->us)->driver_data) /* If an adis16251 */ if (spi_get_device_id(st->adis.spi)->driver_data) /* If an adis16251 */
sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256; sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
else else
sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048; sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
...@@ -197,7 +76,7 @@ static ssize_t adis16260_write_frequency(struct device *dev, ...@@ -197,7 +76,7 @@ static ssize_t adis16260_write_frequency(struct device *dev,
return -EINVAL; return -EINVAL;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
if (spi_get_device_id(st->us)) { if (spi_get_device_id(st->adis.spi)->driver_data) {
t = (256 / val); t = (256 / val);
if (t > 0) if (t > 0)
t--; t--;
...@@ -209,10 +88,10 @@ static ssize_t adis16260_write_frequency(struct device *dev, ...@@ -209,10 +88,10 @@ static ssize_t adis16260_write_frequency(struct device *dev,
t &= ADIS16260_SMPL_PRD_DIV_MASK; t &= ADIS16260_SMPL_PRD_DIV_MASK;
} }
if ((t & ADIS16260_SMPL_PRD_DIV_MASK) >= 0x0A) if ((t & ADIS16260_SMPL_PRD_DIV_MASK) >= 0x0A)
st->us->max_speed_hz = ADIS16260_SPI_SLOW; st->adis.spi->max_speed_hz = ADIS16260_SPI_SLOW;
else else
st->us->max_speed_hz = ADIS16260_SPI_FAST; st->adis.spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis16260_spi_write_reg_8(indio_dev, ret = adis_write_reg_8(&st->adis,
ADIS16260_SMPL_PRD, ADIS16260_SMPL_PRD,
t); t);
...@@ -221,140 +100,20 @@ static ssize_t adis16260_write_frequency(struct device *dev, ...@@ -221,140 +100,20 @@ static ssize_t adis16260_write_frequency(struct device *dev,
return ret ? ret : len; return ret ? ret : len;
} }
static int adis16260_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16260_spi_write_reg_8(indio_dev,
ADIS16260_GLOB_CMD,
ADIS16260_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
int adis16260_set_irq(struct iio_dev *indio_dev, bool enable)
{
int ret;
u16 msc;
ret = adis16260_spi_read_reg_16(indio_dev, ADIS16260_MSC_CTRL, &msc);
if (ret)
goto error_ret;
msc |= ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH;
if (enable)
msc |= ADIS16260_MSC_CTRL_DATA_RDY_EN;
else
msc &= ~ADIS16260_MSC_CTRL_DATA_RDY_EN;
ret = adis16260_spi_write_reg_16(indio_dev, ADIS16260_MSC_CTRL, msc);
if (ret)
goto error_ret;
error_ret:
return ret;
}
/* Power down the device */ /* Power down the device */
static int adis16260_stop_device(struct iio_dev *indio_dev) static int adis16260_stop_device(struct iio_dev *indio_dev)
{ {
struct adis16260_state *st = iio_priv(indio_dev);
int ret; int ret;
u16 val = ADIS16260_SLP_CNT_POWER_OFF; u16 val = ADIS16260_SLP_CNT_POWER_OFF;
ret = adis16260_spi_write_reg_16(indio_dev, ADIS16260_SLP_CNT, val); ret = adis_write_reg_16(&st->adis, ADIS16260_SLP_CNT, val);
if (ret) if (ret)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
return ret; return ret;
} }
static int adis16260_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16260_spi_write_reg_16(indio_dev,
ADIS16260_MSC_CTRL,
ADIS16260_MSC_CTRL_MEM_TEST);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16260_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16260_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
struct device *dev = &indio_dev->dev;
ret = adis16260_spi_read_reg_16(indio_dev,
ADIS16260_DIAG_STAT,
&status);
if (ret < 0) {
dev_err(dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x7F;
if (status & ADIS16260_DIAG_STAT_FLASH_CHK)
dev_err(dev, "Flash checksum error\n");
if (status & ADIS16260_DIAG_STAT_SELF_TEST)
dev_err(dev, "Self test error\n");
if (status & ADIS16260_DIAG_STAT_OVERFLOW)
dev_err(dev, "Sensor overrange\n");
if (status & ADIS16260_DIAG_STAT_SPI_FAIL)
dev_err(dev, "SPI failure\n");
if (status & ADIS16260_DIAG_STAT_FLASH_UPT)
dev_err(dev, "Flash update failed\n");
if (status & ADIS16260_DIAG_STAT_POWER_HIGH)
dev_err(dev, "Power supply above 5.25V\n");
if (status & ADIS16260_DIAG_STAT_POWER_LOW)
dev_err(dev, "Power supply below 4.75V\n");
error_ret:
return ret;
}
static int adis16260_initial_setup(struct iio_dev *indio_dev)
{
int ret;
struct device *dev = &indio_dev->dev;
/* Disable IRQ */
ret = adis16260_set_irq(indio_dev, false);
if (ret) {
dev_err(dev, "disable irq failed");
goto err_ret;
}
/* Do self test */
ret = adis16260_self_test(indio_dev);
if (ret) {
dev_err(dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16260_check_status(indio_dev);
if (ret) {
adis16260_reset(indio_dev);
dev_err(dev, "device not playing ball -> reset");
msleep(ADIS16260_STARTUP_DELAY);
ret = adis16260_check_status(indio_dev);
if (ret) {
dev_err(dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
adis16260_read_frequency, adis16260_read_frequency,
adis16260_write_frequency); adis16260_write_frequency);
...@@ -362,100 +121,26 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, ...@@ -362,100 +121,26 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static IIO_DEVICE_ATTR(sampling_frequency_available, static IIO_DEVICE_ATTR(sampling_frequency_available,
S_IRUGO, adis16260_read_frequency_available, NULL, 0); S_IRUGO, adis16260_read_frequency_available, NULL, 0);
enum adis16260_channel {
gyro,
temp,
in_supply,
in_aux,
angle,
};
#define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \ #define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \
struct iio_chan_spec adis16260_channels_##axis[] = { \ struct iio_chan_spec adis16260_channels_##axis[] = { \
{ \ ADIS_GYRO_CHAN(mod, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, \
.type = IIO_ANGL_VEL, \ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
.modified = 1, \ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, 14), \
.channel2 = mod, \ ADIS_INCLI_CHAN(mod, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12), \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ IIO_CHAN_SOFT_TIMESTAMP(5), \
.address = gyro, \ }
.scan_index = ADIS16260_SCAN_GYRO, \
.scan_type = { \
.sign = 's', \
.realbits = 14, \
.storagebits = 16, \
}, \
}, { \
.type = IIO_ANGL, \
.modified = 1, \
.channel2 = mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
.address = angle, \
.scan_index = ADIS16260_SCAN_ANGL, \
.scan_type = { \
.sign = 'u', \
.realbits = 14, \
.storagebits = 16, \
}, \
}, { \
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = temp, \
.scan_index = ADIS16260_SCAN_TEMP, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
}, { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = 0, \
.extend_name = "supply", \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = in_supply, \
.scan_index = ADIS16260_SCAN_SUPPLY, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
}, { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = in_aux, \
.scan_index = ADIS16260_SCAN_AUX_ADC, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
}, \
IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X); static const ADIS16260_GYRO_CHANNEL_SET(x, X);
static const ADIS16260_GYRO_CHANNEL_SET(y, IIO_MOD_Y); static const ADIS16260_GYRO_CHANNEL_SET(y, Y);
static const ADIS16260_GYRO_CHANNEL_SET(z, IIO_MOD_Z); static const ADIS16260_GYRO_CHANNEL_SET(z, Z);
static const u8 adis16260_addresses[5][3] = { static const u8 adis16260_addresses[][2] = {
[gyro] = { ADIS16260_GYRO_OUT, [ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
ADIS16260_GYRO_OFF,
ADIS16260_GYRO_SCALE },
[angle] = { ADIS16260_ANGL_OUT },
[in_supply] = { ADIS16260_SUPPLY_OUT },
[in_aux] = { ADIS16260_AUX_ADC },
[temp] = { ADIS16260_TEMP_OUT },
}; };
static int adis16260_read_raw(struct iio_dev *indio_dev, static int adis16260_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int *val, int *val2, int *val, int *val2,
...@@ -469,34 +154,13 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, ...@@ -469,34 +154,13 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); return adis_single_conversion(indio_dev, chan,
addr = adis16260_addresses[chan->address][0]; ADIS16260_ERROR_ACTIVE, val);
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
if (val16 & ADIS16260_ERROR_ACTIVE) {
ret = adis16260_check_status(indio_dev);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
if (chan->scan_type.sign == 's')
val16 = (s16)(val16 <<
(16 - chan->scan_type.realbits)) >>
(16 - chan->scan_type.realbits);
*val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_ANGL_VEL: case IIO_ANGL_VEL:
*val = 0; *val = 0;
if (spi_get_device_id(st->us)->driver_data) { if (spi_get_device_id(st->adis.spi)->driver_data) {
/* 0.01832 degree / sec */ /* 0.01832 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(18320); *val2 = IIO_DEGREE_TO_RAD(18320);
} else { } else {
...@@ -533,8 +197,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, ...@@ -533,8 +197,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][1]; addr = adis16260_addresses[chan->scan_index][0];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(&st->adis, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -553,8 +217,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, ...@@ -553,8 +217,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][2]; addr = adis16260_addresses[chan->scan_index][1];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16); ret = adis_read_reg_16(&st->adis, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret; return ret;
...@@ -572,18 +236,19 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, ...@@ -572,18 +236,19 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
int val2, int val2,
long mask) long mask)
{ {
struct adis16260_state *st = iio_priv(indio_dev);
int bits = 12; int bits = 12;
s16 val16; s16 val16;
u8 addr; u8 addr;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16260_addresses[chan->address][1]; addr = adis16260_addresses[chan->scan_index][0];
return adis16260_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(&st->adis, addr, val16);
case IIO_CHAN_INFO_CALIBSCALE: case IIO_CHAN_INFO_CALIBSCALE:
val16 = val & ((1 << bits) - 1); val16 = val & ((1 << bits) - 1);
addr = adis16260_addresses[chan->address][2]; addr = adis16260_addresses[chan->scan_index][1];
return adis16260_spi_write_reg_16(indio_dev, addr, val16); return adis_write_reg_16(&st->adis, addr, val16);
} }
return -EINVAL; return -EINVAL;
} }
...@@ -602,9 +267,40 @@ static const struct iio_info adis16260_info = { ...@@ -602,9 +267,40 @@ static const struct iio_info adis16260_info = {
.attrs = &adis16260_attribute_group, .attrs = &adis16260_attribute_group,
.read_raw = &adis16260_read_raw, .read_raw = &adis16260_read_raw,
.write_raw = &adis16260_write_raw, .write_raw = &adis16260_write_raw,
.update_scan_mode = adis_update_scan_mode,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const char * const adis1620_status_error_msgs[] = {
[ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error",
[ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error",
[ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange",
[ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25",
[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",
};
static const struct adis_data adis16260_data = {
.write_delay = 30,
.read_delay = 30,
.msc_ctrl_reg = ADIS16260_MSC_CTRL,
.glob_cmd_reg = ADIS16260_GLOB_CMD,
.diag_stat_reg = ADIS16260_DIAG_STAT,
.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
.startup_delay = ADIS16260_STARTUP_DELAY,
.status_error_msgs = adis1620_status_error_msgs,
.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |
BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) |
BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) |
BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16260_probe(struct spi_device *spi) static int __devinit adis16260_probe(struct spi_device *spi)
{ {
int ret; int ret;
...@@ -624,10 +320,7 @@ static int __devinit adis16260_probe(struct spi_device *spi) ...@@ -624,10 +320,7 @@ static int __devinit adis16260_probe(struct spi_device *spi)
/* this is only used for removal purposes */ /* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->us = spi; indio_dev->name = spi_get_device_id(spi)->name;
mutex_init(&st->buf_lock);
indio_dev->name = spi_get_device_id(st->us)->name;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info; indio_dev->info = &adis16260_info;
indio_dev->num_channels indio_dev->num_channels
...@@ -651,17 +344,14 @@ static int __devinit adis16260_probe(struct spi_device *spi) ...@@ -651,17 +344,14 @@ static int __devinit adis16260_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16260_channels_x); indio_dev->num_channels = ARRAY_SIZE(adis16260_channels_x);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16260_configure_ring(indio_dev); ret = adis_init(&st->adis, indio_dev, spi, &adis16260_data);
if (ret)
goto error_free_dev;
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
if (ret) if (ret)
goto error_free_dev; goto error_free_dev;
ret = iio_buffer_register(indio_dev,
indio_dev->channels,
ARRAY_SIZE(adis16260_channels_x));
if (ret) {
printk(KERN_ERR "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
if (indio_dev->buffer) { if (indio_dev->buffer) {
/* Set default scan mode */ /* Set default scan mode */
iio_scan_mask_set(indio_dev, indio_dev->buffer, iio_scan_mask_set(indio_dev, indio_dev->buffer,
...@@ -675,28 +365,19 @@ static int __devinit adis16260_probe(struct spi_device *spi) ...@@ -675,28 +365,19 @@ static int __devinit adis16260_probe(struct spi_device *spi)
iio_scan_mask_set(indio_dev, indio_dev->buffer, iio_scan_mask_set(indio_dev, indio_dev->buffer,
ADIS16260_SCAN_ANGL); ADIS16260_SCAN_ANGL);
} }
if (spi->irq) {
ret = adis16260_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
}
/* Get the device into a sane initial state */ /* Get the device into a sane initial state */
ret = adis16260_initial_setup(indio_dev); ret = adis_initial_startup(&st->adis);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) if (ret)
goto error_remove_trigger; goto error_cleanup_buffer_trigger;
return 0; return 0;
error_remove_trigger: error_cleanup_buffer_trigger:
adis16260_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16260_unconfigure_ring(indio_dev);
error_free_dev: error_free_dev:
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret: error_ret:
...@@ -706,12 +387,11 @@ static int __devinit adis16260_probe(struct spi_device *spi) ...@@ -706,12 +387,11 @@ static int __devinit adis16260_probe(struct spi_device *spi)
static int __devexit adis16260_remove(struct spi_device *spi) static int __devexit adis16260_remove(struct spi_device *spi)
{ {
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16260_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev); adis16260_stop_device(indio_dev);
adis16260_remove_trigger(indio_dev); adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
iio_buffer_unregister(indio_dev);
adis16260_unconfigure_ring(indio_dev);
iio_device_free(indio_dev); iio_device_free(indio_dev);
return 0; return 0;
......
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include "../ring_sw.h"
#include <linux/iio/trigger_consumer.h>
#include "adis16260.h"
/**
* adis16260_read_ring_data() read data registers which will be placed into ring
* @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
static int adis16260_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
struct adis16260_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16260_OUTPUTS + 1];
int ret;
int i;
mutex_lock(&st->buf_lock);
spi_message_init(&msg);
memset(xfers, 0, sizeof(xfers));
for (i = 0; i <= ADIS16260_OUTPUTS; i++) {
xfers[i].bits_per_word = 8;
xfers[i].cs_change = 1;
xfers[i].len = 2;
xfers[i].delay_usecs = 30;
xfers[i].tx_buf = st->tx + 2 * i;
if (i < 2) /* SUPPLY_OUT:0x02 GYRO_OUT:0x04 */
st->tx[2 * i]
= ADIS16260_READ_REG(ADIS16260_SUPPLY_OUT
+ 2 * i);
else /* 0x06 to 0x09 is reserved */
st->tx[2 * i]
= ADIS16260_READ_REG(ADIS16260_SUPPLY_OUT
+ 2 * i + 4);
st->tx[2 * i + 1] = 0;
if (i >= 1)
xfers[i].rx_buf = rx + 2 * (i - 1);
spi_message_add_tail(&xfers[i], &msg);
}
ret = spi_sync(st->us, &msg);
if (ret)
dev_err(&st->us->dev, "problem when burst reading");
mutex_unlock(&st->buf_lock);
return ret;
}
static irqreturn_t adis16260_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16260_state *st = iio_priv(indio_dev);
int i = 0;
s16 *data;
data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
goto done;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
adis16260_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
void adis16260_unconfigure_ring(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_sw_rb_free(indio_dev->buffer);
}
static const struct iio_buffer_setup_ops adis16260_ring_setup_ops = {
.preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
int adis16260_configure_ring(struct iio_dev *indio_dev)
{
int ret = 0;
struct iio_buffer *ring;
ring = iio_sw_rb_allocate(indio_dev);
if (!ring) {
ret = -ENOMEM;
return ret;
}
indio_dev->buffer = ring;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16260_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&adis16260_trigger_handler,
IRQF_ONESHOT,
indio_dev,
"adis16260_consumer%d",
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
goto error_iio_sw_rb_free;
}
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
error_iio_sw_rb_free:
iio_sw_rb_free(indio_dev->buffer);
return ret;
}
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include "adis16260.h"
/**
* adis16260_data_rdy_trigger_set_state() set datardy interrupt state
**/
static int adis16260_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = trig->private_data;
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return adis16260_set_irq(indio_dev, state);
}
static const struct iio_trigger_ops adis16260_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = &adis16260_data_rdy_trigger_set_state,
};
int adis16260_probe_trigger(struct iio_dev *indio_dev)
{
int ret;
struct adis16260_state *st = iio_priv(indio_dev);
st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
}
ret = request_irq(st->us->irq,
&iio_trigger_generic_data_rdy_poll,
IRQF_TRIGGER_RISING,
"adis16260",
st->trig);
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &adis16260_trigger_ops;
st->trig->private_data = indio_dev;
ret = iio_trigger_register(st->trig);
/* select default trigger */
indio_dev->trig = st->trig;
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
iio_trigger_free(st->trig);
error_ret:
return ret;
}
void adis16260_remove_trigger(struct iio_dev *indio_dev)
{
struct adis16260_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
iio_trigger_free(st->trig);
}
...@@ -356,7 +356,7 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, ...@@ -356,7 +356,7 @@ static int isl29018_write_raw(struct iio_dev *indio_dev,
} }
mutex_unlock(&chip->lock); mutex_unlock(&chip->lock);
return 0; return ret;
} }
static int isl29018_read_raw(struct iio_dev *indio_dev, static int isl29018_read_raw(struct iio_dev *indio_dev,
......
...@@ -652,7 +652,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, ...@@ -652,7 +652,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
} }
if (!state && (chip->intr & 0x30)) { if (!state && (chip->intr & 0x30)) {
chip->intr |= ~0x30; chip->intr &= ~0x30;
ret = i2c_smbus_write_byte_data(chip->client, ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT, TSL2563_CMD | TSL2563_REG_INT,
chip->intr); chip->intr);
...@@ -814,7 +814,7 @@ static int __devexit tsl2563_remove(struct i2c_client *client) ...@@ -814,7 +814,7 @@ static int __devexit tsl2563_remove(struct i2c_client *client)
if (!chip->int_enabled) if (!chip->int_enabled)
cancel_delayed_work(&chip->poweroff_work); cancel_delayed_work(&chip->poweroff_work);
/* Ensure that interrupts are disabled - then flush any bottom halves */ /* Ensure that interrupts are disabled - then flush any bottom halves */
chip->intr |= ~0x30; chip->intr &= ~0x30;
i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT, i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT,
chip->intr); chip->intr);
flush_scheduled_work(); flush_scheduled_work();
......
...@@ -195,7 +195,7 @@ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, ...@@ -195,7 +195,7 @@ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
#else /* CONFIG_IIO_BUFFER */ #else /* CONFIG_IIO_BUFFER */
static inline int iio_buffer_register(struct iio_dev *indio_dev, static inline int iio_buffer_register(struct iio_dev *indio_dev,
struct iio_chan_spec *channels, const struct iio_chan_spec *channels,
int num_channels) int num_channels)
{ {
return 0; return 0;
......
...@@ -620,6 +620,9 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) ...@@ -620,6 +620,9 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
}; };
#endif #endif
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
int *fract);
/** /**
* IIO_DEGREE_TO_RAD() - Convert degree to rad * IIO_DEGREE_TO_RAD() - Convert degree to rad
* @deg: A value in degree * @deg: A value in degree
......
/*
* Common library for ADIS16XXX devices
*
* Copyright 2012 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#ifndef __IIO_ADIS_H__
#define __IIO_ADIS_H__
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/iio/types.h>
#define ADIS_WRITE_REG(reg) ((0x80 | (reg)))
#define ADIS_READ_REG(reg) ((reg) & 0x7f)
#define ADIS_PAGE_SIZE 0x80
#define ADIS_REG_PAGE_ID 0x00
struct adis;
/**
* struct adis_data - ADIS chip variant specific data
* @read_delay: SPI delay for read operations in us
* @write_delay: SPI delay for write operations in us
* @glob_cmd_reg: Register address of the GLOB_CMD register
* @msc_ctrl_reg: Register address of the MSC_CTRL register
* @diag_stat_reg: Register address of the DIAG_STAT register
* @status_error_msgs: Array of error messgaes
* @status_error_mask:
*/
struct adis_data {
unsigned int read_delay;
unsigned int write_delay;
unsigned int glob_cmd_reg;
unsigned int msc_ctrl_reg;
unsigned int diag_stat_reg;
unsigned int self_test_mask;
unsigned int startup_delay;
const char * const *status_error_msgs;
unsigned int status_error_mask;
int (*enable_irq)(struct adis *adis, bool enable);
bool has_paging;
};
struct adis {
struct spi_device *spi;
struct iio_trigger *trig;
const struct adis_data *data;
struct mutex txrx_lock;
struct spi_message msg;
struct spi_transfer *xfer;
unsigned int current_page;
void *buffer;
uint8_t tx[10] ____cacheline_aligned;
uint8_t rx[4];
};
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
struct spi_device *spi, const struct adis_data *data);
int adis_reset(struct adis *adis);
int adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int val, unsigned int size);
int adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size);
/**
* adis_write_reg_8() - Write single byte to a register
* @adis: The adis device
* @reg: The address of the register to be written
* @value: The value to write
*/
static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
uint8_t val)
{
return adis_write_reg(adis, reg, val, 1);
}
/**
* adis_write_reg_16() - Write 2 bytes to a pair of registers
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @value: Value to be written
*/
static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
uint16_t val)
{
return adis_write_reg(adis, reg, val, 2);
}
/**
* adis_write_reg_32() - write 4 bytes to four registers
* @adis: The adis device
* @reg: The address of the lower of the four register
* @value: Value to be written
*/
static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
uint32_t val)
{
return adis_write_reg(adis, reg, val, 4);
}
/**
* adis_read_reg_16() - read 2 bytes from a 16-bit register
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
*/
static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
uint16_t *val)
{
unsigned int tmp;
int ret;
ret = adis_read_reg(adis, reg, &tmp, 2);
*val = tmp;
return ret;
}
/**
* adis_read_reg_32() - read 4 bytes from a 32-bit register
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
*/
static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
uint32_t *val)
{
unsigned int tmp;
int ret;
ret = adis_read_reg(adis, reg, &tmp, 4);
*val = tmp;
return ret;
}
int adis_enable_irq(struct adis *adis, bool enable);
int adis_check_status(struct adis *adis);
int adis_initial_startup(struct adis *adis);
int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int error_mask,
int *val);
#define ADIS_VOLTAGE_CHAN(addr, si, chan, name, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan), \
.extend_name = name, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define ADIS_SUPPLY_CHAN(addr, si, bits) \
ADIS_VOLTAGE_CHAN(addr, si, 0, "supply", bits)
#define ADIS_AUX_ADC_CHAN(addr, si, bits) \
ADIS_VOLTAGE_CHAN(addr, si, 1, NULL, bits)
#define ADIS_TEMP_CHAN(addr, si, bits) { \
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define ADIS_MOD_CHAN(_type, mod, addr, si, info, bits) { \
.type = (_type), \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
info, \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
.sign = 's', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define ADIS_ACCEL_CHAN(mod, addr, si, info, bits) \
ADIS_MOD_CHAN(IIO_ACCEL, mod, addr, si, info, bits)
#define ADIS_GYRO_CHAN(mod, addr, si, info, bits) \
ADIS_MOD_CHAN(IIO_ANGL_VEL, mod, addr, si, info, bits)
#define ADIS_INCLI_CHAN(mod, addr, si, info, bits) \
ADIS_MOD_CHAN(IIO_INCLI, mod, addr, si, info, bits)
#define ADIS_ROT_CHAN(mod, addr, si, info, bits) \
ADIS_MOD_CHAN(IIO_ROT, mod, addr, si, info, bits)
#ifdef CONFIG_IIO_ADIS_LIB_BUFFER
int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *));
void adis_cleanup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev);
int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
void adis_remove_trigger(struct adis *adis);
int adis_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask);
#else /* CONFIG_IIO_BUFFER */
static inline int adis_setup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev, irqreturn_t (*trigger_handler)(int, void *))
{
return 0;
}
static inline void adis_cleanup_buffer_and_trigger(struct adis *adis,
struct iio_dev *indio_dev)
{
}
static inline int adis_probe_trigger(struct adis *adis,
struct iio_dev *indio_dev)
{
return 0;
}
static inline void adis_remove_trigger(struct adis *adis)
{
}
#define adis_update_scan_mode NULL
#endif /* CONFIG_IIO_BUFFER */
#ifdef CONFIG_DEBUG_FS
int adis_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval, unsigned int *readval);
#else
#define adis_debugfs_reg_access NULL
#endif
#endif
...@@ -28,6 +28,7 @@ enum iio_chan_type { ...@@ -28,6 +28,7 @@ enum iio_chan_type {
IIO_CAPACITANCE, IIO_CAPACITANCE,
IIO_ALTVOLTAGE, IIO_ALTVOLTAGE,
IIO_CCT, IIO_CCT,
IIO_PRESSURE,
}; };
enum iio_modifier { enum iio_modifier {
......
/*
* AD7298 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef __LINUX_PLATFORM_DATA_AD7298_H__
#define __LINUX_PLATFORM_DATA_AD7298_H__
/**
* struct ad7298_platform_data - Platform data for the ad7298 ADC driver
* @ext_ref: Whether to use an external reference voltage.
**/
struct ad7298_platform_data {
bool ext_ref;
};
#endif /* IIO_ADC_AD7298_H_ */
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