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!
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJQrR8KAAoJEFSFNJnE9BaIzmAP/0QawDmjpYsPRRDn8Ou758ri
 Vx4wC4Xp7g8eYysMTK/R5ScAnDSVfvF21aWppCdr/LbZhg6dTw+sDR0BlE775NbA
 BveAXFuGOfdDFkkMgtw+Se7Ek00uqZy5chdkrT09SmYX3592HyN9CYacF3f1EHiS
 GXEUHW7gau0MHk988HCj2GhoradSkNiB6L0585oadNozcmesMZmvqFxEoel+g+DJ
 0JQ+KTbheLfriSDvNMD00XuEzuoLCfBlqE6Ij24fl3UTpRY/3JJqp2ddXzSO9YMM
 RBC4x5RGOltLYsgPmAuvZCV6T8k7rfjQDmsjmNwTrSvYkKA+0Uzj2OhNRi9Zam8z
 HGMuppJPhzSaR8iVOMzj5JVIs0MkjemXK/OYVvNnoCY7dDCDK66dlYXWM/L6IYDN
 atHOX98p56qaQpuSkZd+wNxjD0oNo3oPas+vfecMQ+zNuAhJFwh4IsQOmTzwrtz4
 Wms6Gm8P5lR9WqPiCGD3p5gKVT0gDcJrmgrKSYL6eWguHsCoXeY3IlnW355xIv44
 ciX/siRUvZxBr25cpGjL0E9xyZNZ7CiXowNHbuyMbxtF/5dfKdzGQppxLA8nPz+c
 aIZRgVvqaoeHaAB+nhb+67rriotgY1TyP4ZuvufQYqo0BMXUo9pT05a84tSXVOo4
 +wBiuhTJU+c+3e/9Oka+
 =SCgj
 -----END PGP SIGNATURE-----

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!"
This commit is contained in:
Greg Kroah-Hartman 2012-11-21 12:32:57 -08:00
commit 3ce14acb90
64 changed files with 3367 additions and 4650 deletions

View File

@ -189,6 +189,14 @@ Description:
A computed peak value based on the sum squared magnitude of
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_x_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
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_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_y_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_illuminance0_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_illuminance0_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_altvoltageX_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_incli_x_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_voltageY_supply_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
Contact: linux-iio@vger.kernel.org
Description:
@ -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_y_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
Contact: linux-iio@vger.kernel.org
Description:

View File

@ -63,11 +63,12 @@ config IIO_CONSUMERS_PER_TRIGGER
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/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/dac/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
source "drivers/iio/imu/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
endif # IIO

View File

@ -14,9 +14,10 @@ obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
obj-y += light/
obj-y += frequency/
obj-y += dac/
obj-y += common/
obj-y += dac/
obj-y += gyro/
obj-y += frequency/
obj-y += imu/
obj-y += light/
obj-y += magnetometer/

View File

@ -306,10 +306,10 @@ static int __devinit hid_accel_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
channels = kmemdup(accel_3d_channels,
sizeof(accel_3d_channels),
GFP_KERNEL);
channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
GFP_KERNEL);
if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}

View File

@ -18,6 +18,18 @@ config AD7266
Say yes here to build support for Analog Devices AD7265 and AD7266
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
tristate "Analog Devices AD7791 ADC driver"
depends on SPI

View File

@ -4,6 +4,7 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7887) += ad7887.o

View File

@ -15,12 +15,48 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "ad7298.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) \
{ \
@ -35,6 +71,7 @@
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
@ -44,7 +81,8 @@ static const struct iio_chan_spec ad7298_channels[] = {
.indexed = 1,
.channel = 0,
.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,
.scan_index = -1,
.scan_type = {
@ -64,6 +102,84 @@ static const struct iio_chan_spec ad7298_channels[] = {
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)
{
int ret;
@ -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)
{
int tmp, ret;
int ret;
__be16 buf;
buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE |
@ -101,26 +217,26 @@ static int ad7298_scan_temp(struct ad7298_state *st, int *val)
if (ret)
return ret;
tmp = be16_to_cpu(buf) & RES_MASK(AD7298_BITS);
/*
* 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))) {
tmp = (4096 - tmp) * 250;
tmp -= (2 * tmp);
} else {
tmp *= 250; /* temperature in milli degrees Celsius */
}
*val = tmp;
*val = sign_extend32(be16_to_cpu(buf), 11);
return 0;
}
static int ad7298_get_ref_voltage(struct ad7298_state *st)
{
int vref;
if (st->ext_ref) {
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
return vref / 1000;
} else {
return AD7298_INTREF_mV;
}
}
static int ad7298_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@ -129,7 +245,6 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
{
int ret;
struct ad7298_state *st = iio_priv(indio_dev);
unsigned int scale_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
@ -154,17 +269,19 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS;
*val = scale_uv / 1000;
*val2 = (scale_uv % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
*val = ad7298_get_ref_voltage(st);
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
*val = 1;
*val2 = 0;
return IIO_VAL_INT_PLUS_MICRO;
*val = ad7298_get_ref_voltage(st);
*val2 = 10;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 1093 - 2732500 / ad7298_get_ref_voltage(st);
return IIO_VAL_INT;
}
return -EINVAL;
}
@ -179,16 +296,23 @@ static int __devinit ad7298_probe(struct spi_device *spi)
{
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
int ret;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
int ret;
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reg = regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
if (pdata && pdata->ext_ref)
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);
if (ret)
goto error_put_reg;
@ -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[2], &st->scan_single_msg);
if (pdata && pdata->vref_mv) {
st->int_vref_mv = pdata->vref_mv;
st->ext_ref = AD7298_EXTREF;
} else {
st->int_vref_mv = AD7298_INTREF_mV;
}
ret = ad7298_register_ring_funcs_and_init(indio_dev);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7298_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
@ -239,13 +357,14 @@ static int __devinit ad7298_probe(struct spi_device *spi)
return 0;
error_cleanup_ring:
ad7298_ring_cleanup(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
if (!IS_ERR(st->reg))
if (st->ext_ref)
regulator_disable(st->reg);
error_put_reg:
if (!IS_ERR(st->reg))
if (st->ext_ref)
regulator_put(st->reg);
error_free:
iio_device_free(indio_dev);
return ret;
@ -257,8 +376,8 @@ static int __devexit ad7298_remove(struct spi_device *spi)
struct ad7298_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
ad7298_ring_cleanup(indio_dev);
if (!IS_ERR(st->reg)) {
iio_triggered_buffer_cleanup(indio_dev);
if (st->ext_ref) {
regulator_disable(st->reg);
regulator_put(st->reg);
}

View File

@ -15,7 +15,7 @@ config HID_SENSOR_IIO_COMMON
attributes.
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
help
Say yes here to build support for sensor hub FW using

View File

@ -36,10 +36,8 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
int state_val;
state_val = state ? 1 : 0;
#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \
(defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE)
++state_val;
#endif
if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS))
++state_val;
st->data_ready = state;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,

View File

@ -3,6 +3,15 @@
#
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
depends on HID_SENSOR_HUB
select IIO_BUFFER

View File

@ -2,4 +2,5 @@
# Makefile for industrial I/O gyroscope sensor drivers
#
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o

View File

@ -0,0 +1,581 @@
/*
* 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");

View File

@ -306,10 +306,10 @@ static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
channels = kmemdup(gyro_3d_channels,
sizeof(gyro_3d_channels),
GFP_KERNEL);
channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
GFP_KERNEL);
if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}

27
drivers/iio/imu/Kconfig Normal file
View File

@ -0,0 +1,27 @@
#
# 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.

10
drivers/iio/imu/Makefile Normal file
View File

@ -0,0 +1,10 @@
#
# 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

440
drivers/iio/imu/adis.c Normal file
View File

@ -0,0 +1,440 @@
/*
* 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");

925
drivers/iio/imu/adis16480.c Normal file
View File

@ -0,0 +1,925 @@
/*
* 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");

View File

@ -0,0 +1,176 @@
/*
* 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);

View File

@ -0,0 +1,89 @@
/*
* 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);

View File

@ -65,6 +65,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CAPACITANCE] = "capacitance",
[IIO_ALTVOLTAGE] = "altvoltage",
[IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
};
static const char * const iio_modifier_names[] = {
@ -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,
struct device_attribute *attr,
const char *buf,
@ -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_attr *this_attr = to_iio_dev_attr(attr);
int ret, integer = 0, fract = 0, fract_mult = 100000;
bool integer_part = true, negative = false;
int ret, fract_mult = 100000;
int integer, fract;
/* Assumes decimal - precision based on number of digits */
if (!indio_dev->info->write_raw)
@ -434,39 +493,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
return -EINVAL;
}
if (buf[0] == '-') {
negative = true;
buf++;
} 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 = iio_str_to_fixpoint(buf, fract_mult, &integer, &fract);
if (ret)
return ret;
ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
integer, fract, this_attr->address);

View File

@ -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,
&indio_dev->channels[j]);
if (ret < 0)
goto error_clear_attrs;
return ret;
attrcount += ret;
}
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)

View File

@ -272,10 +272,9 @@ static int __devinit hid_als_probe(struct platform_device *pdev)
goto error_free_dev;
}
channels = kmemdup(als_channels,
sizeof(als_channels),
GFP_KERNEL);
channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}

View File

@ -307,10 +307,10 @@ static int __devinit hid_magn_3d_probe(struct platform_device *pdev)
goto error_free_dev;
}
channels = kmemdup(magn_3d_channels,
sizeof(magn_3d_channels),
GFP_KERNEL);
channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
GFP_KERNEL);
if (!channels) {
ret = -ENOMEM;
dev_err(&pdev->dev, "failed to duplicate channels\n");
goto error_free_dev;
}

View File

@ -6,8 +6,8 @@ menu "Accelerometers"
config ADIS16201
tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_SW_RING if IIO_BUFFER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices adis16201 dual-axis
digital inclinometer and accelerometer.
@ -15,8 +15,8 @@ config ADIS16201
config ADIS16203
tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_SW_RING if IIO_BUFFER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices adis16203 Programmable
360 Degrees Inclinometer.
@ -24,8 +24,8 @@ config ADIS16203
config ADIS16204
tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_SW_RING if IIO_BUFFER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices adis16204 Programmable
High-g Digital Impact Sensor and Recorder.
@ -33,8 +33,8 @@ config ADIS16204
config ADIS16209
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_SW_RING if IIO_BUFFER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
and accelerometer.
@ -42,6 +42,7 @@ config ADIS16209
config ADIS16220
tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor"
depends on SPI
select IIO_ADIS_LIB
help
Say yes here to build support for Analog Devices adis16220 programmable
digital vibration sensor.
@ -49,8 +50,8 @@ config ADIS16220
config ADIS16240
tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
select IIO_SW_RING if IIO_BUFFER
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices adis16240 programmable
impact Sensor and recorder.

View File

@ -3,26 +3,21 @@
#
adis16201-y := adis16201_core.o
adis16201-$(CONFIG_IIO_BUFFER) += adis16201_ring.o adis16201_trigger.o
obj-$(CONFIG_ADIS16201) += adis16201.o
adis16203-y := adis16203_core.o
adis16203-$(CONFIG_IIO_BUFFER) += adis16203_ring.o adis16203_trigger.o
obj-$(CONFIG_ADIS16203) += adis16203.o
adis16204-y := adis16204_core.o
adis16204-$(CONFIG_IIO_BUFFER) += adis16204_ring.o adis16204_trigger.o
obj-$(CONFIG_ADIS16204) += adis16204.o
adis16209-y := adis16209_core.o
adis16209-$(CONFIG_IIO_BUFFER) += adis16209_ring.o adis16209_trigger.o
obj-$(CONFIG_ADIS16209) += adis16209.o
adis16220-y := adis16220_core.o
obj-$(CONFIG_ADIS16220) += adis16220.o
adis16240-y := adis16240_core.o
adis16240-$(CONFIG_IIO_BUFFER) += adis16240_ring.o adis16240_trigger.o
obj-$(CONFIG_ADIS16240) += adis16240.o
obj-$(CONFIG_KXSD9) += kxsd9.o

View File

@ -3,9 +3,6 @@
#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_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16201_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
@ -36,8 +33,6 @@
#define ADIS16201_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16201_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16201_OUTPUTS 7
/* MSC_CTRL */
#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 */
@ -47,95 +42,25 @@
/* DIAG_STAT */
#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_SPI_FAIL (1<<3) /* SPI communications failure */
#define ADIS16201_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
#define ADIS16201_DIAG_STAT_POWER_HIGH (1<<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_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 3.15 V */
/* GLOB_CMD */
#define ADIS16201_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16201_MAX_TX 14
#define ADIS16201_MAX_RX 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 {
ADIS16201_SCAN_SUPPLY,
ADIS16201_SCAN_ACC_X,
ADIS16201_SCAN_ACC_Y,
ADIS16201_SCAN_AUX_ADC,
ADIS16201_SCAN_TEMP,
ADIS16201_SCAN_INCLI_X,
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_ */

View File

@ -18,258 +18,15 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include "adis16201.h"
enum adis16201_chan {
in_supply,
temp,
accel_x,
accel_y,
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 const u8 adis16201_addresses[] = {
[ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS,
[ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS,
[ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS,
[ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS,
};
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
@ -284,29 +42,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16201_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16201_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@ -349,8 +86,8 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
addr = adis16201_addresses[chan->address][1];
ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16201_addresses[chan->scan_index];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -370,6 +107,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int bits;
s16 val16;
u8 addr;
@ -386,124 +124,61 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
val16 = val & ((1 << bits) - 1);
addr = adis16201_addresses[chan->address][1];
return adis16201_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16201_addresses[chan->scan_index];
return adis_write_reg_16(st, addr, val16);
}
return -EINVAL;
}
static const struct iio_chan_spec adis16201_channels[] = {
{
.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 = ADIS16201_SCAN_SUPPLY,
.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 = 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,
},
},
ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 12),
ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
static const struct iio_info adis16201_info = {
.read_raw = &adis16201_read_raw,
.write_raw = &adis16201_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
struct adis16201_state *st;
struct adis *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
@ -516,9 +191,6 @@ static int __devinit adis16201_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16201_info;
@ -527,40 +199,25 @@ static int __devinit adis16201_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);
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)
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 */
ret = adis16201_initial_setup(indio_dev);
ret = adis_initial_startup(st);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret < 0)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16201_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16201_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -570,11 +227,10 @@ static int __devinit adis16201_probe(struct spi_device *spi)
static int __devexit adis16201_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16201_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16201_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,136 +0,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;
}

View File

@ -1,71 +0,0 @@
#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);
}

View File

@ -3,9 +3,6 @@
#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_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16203_AUX_ADC 0x08 /* Output, auxiliary ADC input */
@ -27,8 +24,6 @@
#define ADIS16203_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16203_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16203_OUTPUTS 5
/* MSC_CTRL */
#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 */
@ -40,86 +35,25 @@
/* DIAG_STAT */
#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_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag */
#define ADIS16203_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */
#define ADIS16203_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
#define ADIS16203_DIAG_STAT_POWER_HIGH (1<<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_SELFTEST_FAIL_BIT 5 /* Self-test diagnostic error flag */
#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 3.15 V */
/* GLOB_CMD */
#define ADIS16203_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16203_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16203_MAX_TX 12
#define ADIS16203_MAX_RX 10
#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 {
ADIS16203_SCAN_INCLI_X,
ADIS16203_SCAN_INCLI_Y,
ADIS16203_SCAN_SUPPLY,
ADIS16203_SCAN_AUX_ADC,
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_ */

View File

@ -1,7 +1,7 @@
/*
* ADIS16203 Programmable Digital Vibration Sensor driver
*
* Copyright 2010 Analog Devices Inc.
* Copyright 2030 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@ -18,252 +18,14 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include "adis16203.h"
/**
* 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);
#define DRIVER_NAME "adis16203"
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);
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 const u8 adis16203_addresses[] = {
[ADIS16203_SCAN_INCLI_X] = ADIS16203_INCL_NULL,
};
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
/* currently only one writable parameter which keeps this simple */
u8 addr = adis16203_addresses[chan->address][1];
return adis16203_spi_write_reg_16(indio_dev, addr, val & 0x3FFF);
u8 addr = adis16203_addresses[chan->scan_index];
return adis_write_reg_16(st, addr, val & 0x3FFF);
}
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
s16 val16;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16203_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@ -339,8 +82,8 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
bits = 14;
mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->address][1];
ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16203_addresses[chan->scan_index];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -356,89 +99,53 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
}
static const struct iio_chan_spec adis16203_channels[] = {
{
.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 = 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,
},
},
ADIS_SUPPLY_CHAN(ADIS16203_SUPPLY_OUT, ADIS16203_SCAN_SUPPLY, 12),
ADIS_AUX_ADC_CHAN(ADIS16203_AUX_ADC, ADIS16203_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16203_XINCL_OUT, ADIS16203_SCAN_INCLI_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
/* Fixme: Not what it appears to be - see data sheet */
ADIS_INCLI_CHAN(Y, ADIS16203_YINCL_OUT, ADIS16203_SCAN_INCLI_Y, 0, 14),
ADIS_TEMP_CHAN(ADIS16203_TEMP_OUT, ADIS16203_SCAN_TEMP, 12),
IIO_CHAN_SOFT_TIMESTAMP(5),
};
static const struct iio_info adis16203_info = {
.read_raw = &adis16203_read_raw,
.write_raw = &adis16203_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
struct iio_dev *indio_dev;
struct adis16203_state *st;
struct adis *st;
/* setup the industrialio driver allocated elements */
indio_dev = iio_device_alloc(sizeof(*st));
@ -449,8 +156,6 @@ static int __devinit adis16203_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
@ -459,41 +164,27 @@ static int __devinit adis16203_probe(struct spi_device *spi)
indio_dev->info = &adis16203_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16203_configure_ring(indio_dev);
ret = adis_init(st, indio_dev, spi, &adis16203_data);
if (ret)
goto error_free_dev;
ret = iio_buffer_register(indio_dev,
adis16203_channels,
ARRAY_SIZE(adis16203_channels));
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;
}
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
goto error_free_dev;
/* Get the device into a sane initial state */
ret = adis16203_initial_setup(indio_dev);
ret = adis_initial_startup(st);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16203_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16203_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -503,11 +194,10 @@ static int __devinit adis16203_probe(struct spi_device *spi)
static int __devexit adis16203_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16203_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16203_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,136 +0,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;
}

View File

@ -1,73 +0,0 @@
#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);
}

View File

@ -3,9 +3,6 @@
#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_SUPPLY_OUT 0x02 /* Output, power supply */
#define ADIS16204_XACCL_OUT 0x04 /* Output, x-axis accelerometer */
@ -35,8 +32,6 @@
#define ADIS16204_DIAG_STAT 0x3C /* Diagnostics, system status register */
#define ADIS16204_GLOB_CMD 0x3E /* Operation, system command register */
#define ADIS16204_OUTPUTS 5
/* MSC_CTRL */
#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 */
@ -47,87 +42,27 @@
/* DIAG_STAT */
#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_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 */
#define ADIS16204_DIAG_STAT_SPI_FAIL (1<<3) /* SPI communications failure */
#define ADIS16204_DIAG_STAT_FLASH_UPT (1<<2) /* Flash update failure */
#define ADIS16204_DIAG_STAT_POWER_HIGH (1<<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_SPI_FAIL_BIT 3 /* SPI communications failure */
#define ADIS16204_DIAG_STAT_FLASH_UPT_BIT 2 /* Flash update failure */
#define ADIS16204_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
#define ADIS16204_DIAG_STAT_POWER_LOW_BIT 0 /* Power supply below 2.975 V */
/* GLOB_CMD */
#define ADIS16204_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16204_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16204_MAX_TX 24
#define ADIS16204_MAX_RX 24
#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 {
ADIS16204_SCAN_SUPPLY,
ADIS16204_SCAN_ACC_X,
ADIS16204_SCAN_ACC_Y,
ADIS16204_SCAN_ACC_XY,
ADIS16204_SCAN_SUPPLY,
ADIS16204_SCAN_AUX_ADC,
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_ */

View File

@ -21,259 +21,16 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.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 */
enum adis16204_channel {
in_supply,
in_aux,
temp,
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 const u8 adis16204_addresses[][2] = {
[ADIS16204_SCAN_ACC_X] = { ADIS16204_XACCL_NULL, ADIS16204_X_PEAK_OUT },
[ADIS16204_SCAN_ACC_Y] = { ADIS16204_YACCL_NULL, ADIS16204_Y_PEAK_OUT },
[ADIS16204_SCAN_ACC_XY] = { 0, ADIS16204_XY_PEAK_OUT },
};
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
@ -289,29 +47,8 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16204_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16204_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@ -351,14 +88,14 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PEAK:
if (mask == IIO_CHAN_INFO_CALIBBIAS) {
bits = 12;
addrind = 1;
addrind = 0;
} else { /* PEAK_SEPARATE */
bits = 14;
addrind = 2;
addrind = 1;
}
mutex_lock(&indio_dev->mlock);
addr = adis16204_addresses[chan->address][addrind];
ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16204_addresses[chan->scan_index][addrind];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -378,6 +115,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int bits;
s16 val16;
u8 addr;
@ -391,112 +129,63 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
val16 = val & ((1 << bits) - 1);
addr = adis16204_addresses[chan->address][1];
return adis16204_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16204_addresses[chan->scan_index][1];
return adis_write_reg_16(st, addr, val16);
}
return -EINVAL;
}
static const struct iio_chan_spec adis16204_channels[] = {
{
.type = IIO_VOLTAGE,
.indexed = 1, /* Note was not previously indexed */
.channel = 0,
.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 |
ADIS_SUPPLY_CHAN(ADIS16204_SUPPLY_OUT, ADIS16204_SCAN_SUPPLY, 12),
ADIS_AUX_ADC_CHAN(ADIS16204_AUX_ADC, ADIS16204_SCAN_AUX_ADC, 12),
ADIS_TEMP_CHAN(ADIS16204_TEMP_OUT, ADIS16204_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16204_XACCL_OUT, ADIS16204_SCAN_ACC_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_x,
.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_PEAK_SEPARATE_BIT, 14),
ADIS_ACCEL_CHAN(Y, ADIS16204_YACCL_OUT, ADIS16204_SCAN_ACC_Y,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_y,
.scan_index = ADIS16204_SCAN_ACC_Y,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
ADIS_ACCEL_CHAN(ROOT_SUM_SQUARED_X_Y, ADIS16204_XY_RSS_OUT,
ADIS16204_SCAN_ACC_XY, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
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 = {
.read_raw = &adis16204_read_raw,
.write_raw = &adis16204_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
struct adis16204_state *st;
struct adis *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
@ -508,8 +197,6 @@ static int __devinit adis16204_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
@ -518,40 +205,26 @@ static int __devinit adis16204_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16204_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis16204_configure_ring(indio_dev);
ret = adis_init(st, indio_dev, spi, &adis16204_data);
if (ret)
goto error_free_dev;
ret = iio_buffer_register(indio_dev,
adis16204_channels,
6);
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;
}
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
if (ret)
goto error_free_dev;
/* Get the device into a sane initial state */
ret = adis16204_initial_setup(indio_dev);
ret = adis_initial_startup(st);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16204_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16204_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -561,11 +234,10 @@ static int __devinit adis16204_probe(struct spi_device *spi)
static int __devexit adis16204_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16204_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16204_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,134 +0,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;
}

View File

@ -1,73 +0,0 @@
#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);
}

View File

@ -3,9 +3,6 @@
#define ADIS16209_STARTUP_DELAY 220 /* ms */
#define ADIS16209_READ_REG(a) a
#define ADIS16209_WRITE_REG(a) ((a) | 0x80)
/* Flash memory write count */
#define ADIS16209_FLASH_CNT 0x00
/* Output, power supply */
@ -61,8 +58,6 @@
/* Operation, system command register */
#define ADIS16209_GLOB_CMD 0x3E
#define ADIS16209_OUTPUTS 8
/* MSC_CTRL */
/* Self-test at power-on: 1 = disabled, 0 = enabled */
#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST (1 << 10)
@ -81,44 +76,23 @@
/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
#define ADIS16209_DIAG_STAT_ALARM1 (1<<8)
/* 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 */
#define ADIS16209_DIAG_STAT_SPI_FAIL (1<<3)
#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3
/* 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 */
#define ADIS16209_DIAG_STAT_POWER_HIGH (1<<1)
#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
#define ADIS16209_DIAG_STAT_POWER_LOW (1<<0)
#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16209_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16209_GLOB_CMD_CLEAR_STAT (1<<4)
#define ADIS16209_GLOB_CMD_FACTORY_CAL (1<<1)
#define ADIS16209_MAX_TX 24
#define ADIS16209_MAX_RX 24
#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_ACC_X 1
#define ADIS16209_SCAN_ACC_Y 2
@ -128,45 +102,4 @@ int adis16209_set_irq(struct iio_dev *indio_dev, bool enable);
#define ADIS16209_SCAN_INCLI_Y 6
#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_ */

View File

@ -19,260 +19,19 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include "adis16209.h"
/**
* adis16209_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio device associated with actual device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16209_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
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 const u8 adis16209_addresses[8][1] = {
[ADIS16209_SCAN_SUPPLY] = { },
[ADIS16209_SCAN_AUX_ADC] = { },
[ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL },
[ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL },
[ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL },
[ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL },
[ADIS16209_SCAN_ROT] = { },
[ADIS16209_SCAN_TEMP] = { },
};
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int bits;
s16 val16;
u8 addr;
@ -295,8 +55,8 @@ static int adis16209_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
val16 = val & ((1 << bits) - 1);
addr = adis16209_addresses[chan->address][1];
return adis16209_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16209_addresses[chan->scan_index][0];
return adis_write_reg_16(st, addr, val16);
}
return -EINVAL;
}
@ -306,6 +66,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
@ -313,29 +74,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16209_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16209_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@ -374,8 +114,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
addr = adis16209_addresses[chan->address][1];
ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16209_addresses[chan->scan_index][0];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -390,128 +130,56 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
}
static const struct iio_chan_spec adis16209_channels[] = {
{
.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 = ADIS16209_SCAN_SUPPLY,
.scan_type = {
.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,
},
},
ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 14),
ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, 0, 14),
ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, 0, 14),
ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 14),
IIO_CHAN_SOFT_TIMESTAMP(8)
};
static const struct iio_info adis16209_info = {
.read_raw = &adis16209_read_raw,
.write_raw = &adis16209_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
struct adis16209_state *st;
struct adis *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
@ -523,8 +191,6 @@ static int __devinit adis16209_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
@ -533,40 +199,25 @@ static int __devinit adis16209_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16209_channels);
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)
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 */
ret = adis16209_initial_setup(indio_dev);
ret = adis_initial_startup(st);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16209_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16209_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -576,11 +227,10 @@ static int __devinit adis16209_probe(struct spi_device *spi)
static int __devexit adis16209_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16209_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16209_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,134 +0,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;
}

View File

@ -1,72 +0,0 @@
#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);
}

View File

@ -1,10 +1,9 @@
#ifndef 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_WRITE_REG(a) ((a) | 0x80)
#define ADIS16220_STARTUP_DELAY 220 /* ms */
/* Flash memory write count */
#define ADIS16220_FLASH_CNT 0x00
@ -102,15 +101,15 @@
#define ADIS16220_DIAG_STAT_FLASH_CHK (1<<6)
#define ADIS16220_DIAG_STAT_SELF_TEST (1<<5)
/* Capture period violation/interruption */
#define ADIS16220_DIAG_STAT_VIOLATION (1<<4)
#define ADIS16220_DIAG_STAT_VIOLATION_BIT 4
/* SPI communications failure */
#define ADIS16220_DIAG_STAT_SPI_FAIL (1<<3)
#define ADIS16220_DIAG_STAT_SPI_FAIL_BIT 3
/* 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 */
#define ADIS16220_DIAG_STAT_POWER_HIGH (1<<1)
#define ADIS16220_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
#define ADIS16220_DIAG_STAT_POWER_LOW (1<<0)
#define ADIS16220_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16220_GLOB_CMD_SW_RESET (1<<7)
@ -125,13 +124,14 @@
/**
* struct adis16220_state - device instance specific data
* @us: actual spi_device
* @adis: adis device
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16220_state {
struct spi_device *us;
struct adis adis;
struct mutex buf_lock;
u8 tx[ADIS16220_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16220_MAX_RX];

View File

@ -20,136 +20,19 @@
#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,
struct device_attribute *attr,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16220_state *st = iio_priv(indio_dev);
ssize_t ret;
s16 val = 0;
/* Take the iio_dev status lock */
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);
mutex_unlock(&indio_dev->mlock);
if (ret)
@ -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_attr *this_attr = to_iio_dev_attr(attr);
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (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:
return ret ? ret : len;
@ -178,10 +62,11 @@ static ssize_t adis16220_write_16bit(struct device *dev,
static int adis16220_capture(struct iio_dev *indio_dev)
{
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
ret = adis16220_spi_write_reg_16(indio_dev,
ADIS16220_GLOB_CMD,
0xBF08); /* initiates a manual data capture */
/* initiates a manual data capture */
ret = adis_write_reg_16(&st->adis, ADIS16220_GLOB_CMD, 0xBF08);
if (ret)
dev_err(&indio_dev->dev, "problem beginning capture");
@ -190,18 +75,6 @@ static int adis16220_capture(struct iio_dev *indio_dev)
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,
struct device_attribute *attr,
const char *buf, size_t len)
@ -222,81 +95,6 @@ static ssize_t adis16220_write_capture(struct device *dev,
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,
char *buf,
loff_t off,
@ -333,7 +131,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
count = ADIS16220_CAPTURE_SIZE - off;
/* 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,
off > 1);
if (ret)
@ -342,8 +140,9 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
/* read count/2 values from capture buffer */
mutex_lock(&st->buf_lock);
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;
}
xfers[1].len = count;
@ -351,7 +150,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
ret = spi_sync(st->adis.spi, &msg);
if (ret) {
mutex_unlock(&st->buf_lock);
@ -472,6 +271,8 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
struct adis16220_state *st = iio_priv(indio_dev);
const struct adis16220_address_spec *addr;
int ret = -EINVAL;
int addrind = 0;
u16 uval;
@ -516,28 +317,21 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
if (adis16220_addresses[chan->address][addrind].sign) {
ret = adis16220_spi_read_reg_16(indio_dev,
adis16220_addresses[chan
->address]
[addrind].addr,
&sval);
addr = &adis16220_addresses[chan->address][addrind];
if (addr->sign) {
ret = adis_read_reg_16(&st->adis, addr->addr, &sval);
if (ret)
return ret;
bits = adis16220_addresses[chan->address][addrind].bits;
bits = addr->bits;
sval &= (1 << bits) - 1;
sval = (s16)(sval << (16 - bits)) >> (16 - bits);
*val = sval;
return IIO_VAL_INT;
} else {
ret = adis16220_spi_read_reg_16(indio_dev,
adis16220_addresses[chan
->address]
[addrind].addr,
&uval);
ret = adis_read_reg_16(&st->adis, addr->addr, &uval);
if (ret)
return ret;
bits = adis16220_addresses[chan->address][addrind].bits;
bits = addr->bits;
uval &= (1 << bits) - 1;
*val = uval;
return IIO_VAL_INT;
@ -601,6 +395,32 @@ static const struct iio_info adis16220_info = {
.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)
{
int ret;
@ -618,9 +438,6 @@ static int __devinit adis16220_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16220_info;
@ -644,8 +461,11 @@ static int __devinit adis16220_probe(struct spi_device *spi)
if (ret)
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 */
ret = adis16220_initial_setup(indio_dev);
ret = adis_initial_startup(&st->adis);
if (ret)
goto error_rm_adc2_bin;
return 0;

View File

@ -3,9 +3,6 @@
#define ADIS16240_STARTUP_DELAY 220 /* ms */
#define ADIS16240_READ_REG(a) a
#define ADIS16240_WRITE_REG(a) ((a) | 0x80)
/* Flash memory write count */
#define ADIS16240_FLASH_CNT 0x00
/* Output, power supply */
@ -75,8 +72,6 @@
/* System command */
#define ADIS16240_GLOB_CMD 0x4A
#define ADIS16240_OUTPUTS 6
/* MSC_CTRL */
/* Enables sum-of-squares output (XYZPEAK_OUT) */
#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN (1 << 15)
@ -101,17 +96,17 @@
/* Flash test, checksum flag: 1 = mismatch, 0 = match */
#define ADIS16240_DIAG_STAT_CHKSUM (1<<6)
/* 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 */
#define ADIS16240_DIAG_STAT_PWRON_BUSY (1<<4)
/* SPI communications failure */
#define ADIS16240_DIAG_STAT_SPI_FAIL (1<<3)
#define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3
/* 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 */
#define ADIS16240_DIAG_STAT_POWER_HIGH (1<<1)
#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
#define ADIS16240_DIAG_STAT_POWER_LOW (1<<0)
#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16240_GLOB_CMD_RESUME (1<<8)
@ -120,77 +115,15 @@
#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
* filling. This may change!
*/
#define ADIS16240_SCAN_SUPPLY 0
#define ADIS16240_SCAN_ACC_X 1
#define ADIS16240_SCAN_ACC_Y 2
#define ADIS16240_SCAN_ACC_Z 3
#define ADIS16240_SCAN_ACC_X 0
#define ADIS16240_SCAN_ACC_Y 1
#define ADIS16240_SCAN_ACC_Z 2
#define ADIS16240_SCAN_SUPPLY 3
#define ADIS16240_SCAN_AUX_ADC 4
#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_ */

View File

@ -22,149 +22,29 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.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,
struct device_attribute *attr,
char *buf,
unsigned bits)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis *st = iio_priv(indio_dev);
int ret;
s16 val = 0;
unsigned shift = 16 - bits;
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);
if (ret)
return ret;
if (val & ADIS16240_ERROR_ACTIVE)
adis16240_check_status(indio_dev);
adis_check_status(st);
val = ((s16)(val << shift) >> shift);
return sprintf(buf, "%d\n", val);
@ -185,152 +65,16 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev,
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,
adis16240_read_12bit_signed, NULL,
ADIS16240_XYZPEAK_OUT);
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096");
enum adis16240_chan {
in_supply,
in_aux,
accel_x,
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 const u8 adis16240_addresses[][2] = {
[ADIS16240_SCAN_ACC_X] = { ADIS16240_XACCL_OFF, ADIS16240_XPEAK_OUT },
[ADIS16240_SCAN_ACC_Y] = { ADIS16240_YACCL_OFF, ADIS16240_YPEAK_OUT },
[ADIS16240_SCAN_ACC_Z] = { ADIS16240_ZACCL_OFF, ADIS16240_ZPEAK_OUT },
};
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,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int ret;
int bits;
u8 addr;
@ -345,29 +90,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16240_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
@ -400,8 +124,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
bits = 10;
mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][1];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16240_addresses[chan->scan_index][0];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -414,8 +138,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PEAK:
bits = 10;
mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][2];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16240_addresses[chan->scan_index][1];
ret = adis_read_reg_16(st, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -435,104 +159,32 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
struct adis *st = iio_priv(indio_dev);
int bits = 10;
s16 val16;
u8 addr;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
val16 = val & ((1 << bits) - 1);
addr = adis16240_addresses[chan->address][1];
return adis16240_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16240_addresses[chan->scan_index][0];
return adis_write_reg_16(st, addr, val16);
}
return -EINVAL;
}
static const struct iio_chan_spec adis16240_channels[] = {
{
.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 = 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 |
ADIS_SUPPLY_CHAN(ADIS16240_SUPPLY_OUT, ADIS16240_SCAN_SUPPLY, 10),
ADIS_AUX_ADC_CHAN(ADIS16240_AUX_ADC, ADIS16240_SCAN_AUX_ADC, 10),
ADIS_ACCEL_CHAN(X, ADIS16240_XACCL_OUT, ADIS16240_SCAN_ACC_X,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_x,
.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_PEAK_SEPARATE_BIT, 10),
ADIS_ACCEL_CHAN(Y, ADIS16240_YACCL_OUT, ADIS16240_SCAN_ACC_Y,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_y,
.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_PEAK_SEPARATE_BIT, 10),
ADIS_ACCEL_CHAN(Z, ADIS16240_ZACCL_OUT, ADIS16240_SCAN_ACC_Z,
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel_z,
.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_INFO_PEAK_SEPARATE_BIT, 10),
ADIS_TEMP_CHAN(ADIS16240_TEMP_OUT, ADIS16240_SCAN_TEMP, 10),
IIO_CHAN_SOFT_TIMESTAMP(6)
};
@ -550,13 +202,40 @@ static const struct iio_info adis16240_info = {
.attrs = &adis16240_attribute_group,
.read_raw = &adis16240_read_raw,
.write_raw = &adis16240_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
struct adis16240_state *st;
struct adis *st;
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
@ -569,9 +248,6 @@ static int __devinit adis16240_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16240_info;
@ -579,39 +255,24 @@ static int __devinit adis16240_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16240_channels);
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)
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 */
ret = adis16240_initial_setup(indio_dev);
ret = adis_initial_startup(st);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16240_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16240_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(st, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -620,13 +281,11 @@ static int __devinit adis16240_probe(struct spi_device *spi)
static int __devexit adis16240_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16240_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16240_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(st, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,132 +0,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;
}

View File

@ -1,73 +0,0 @@
#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);
}

View File

@ -10,17 +10,6 @@ config AD7291
Say yes here to build support for Analog Devices AD7291
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
tristate "Analog Devices AD7606 ADC driver"
depends on GPIOLIB

View File

@ -12,10 +12,6 @@ ad799x-y := ad799x_core.o
ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.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_AD7780) += ad7780.o
obj-$(CONFIG_AD7793) += ad7793.o

View File

@ -1,75 +0,0 @@
/*
* 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_ */

View File

@ -1,113 +0,0 @@
/*
* 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);
}

View File

@ -181,7 +181,7 @@ static ssize_t adt7410_store_mode(struct device *dev,
chip->config = config;
return ret;
return len;
}
static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,

View File

@ -12,7 +12,6 @@ adis16130-y := adis16130_core.o
obj-$(CONFIG_ADIS16130) += adis16130.o
adis16260-y := adis16260_core.o
adis16260-$(CONFIG_IIO_BUFFER) += adis16260_ring.o adis16260_trigger.o
obj-$(CONFIG_ADIS16260) += adis16260.o
adis16251-y := adis16251_core.o

View File

@ -1,12 +1,11 @@
#ifndef SPI_ADIS16260_H_
#define SPI_ADIS16260_H_
#include "adis16260_platform_data.h"
#include <linux/iio/imu/adis.h>
#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_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */
@ -34,8 +33,6 @@
* convert to decimal = 16,265/16,260 */
#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
#define ADIS16260_OUTPUTS 5
#define ADIS16260_ERROR_ACTIVE (1<<14)
#define ADIS16260_NEW_DATA (1<<15)
@ -60,13 +57,13 @@
/* DIAG_STAT */
#define ADIS16260_DIAG_STAT_ALARM2 (1<<9)
#define ADIS16260_DIAG_STAT_ALARM1 (1<<8)
#define ADIS16260_DIAG_STAT_FLASH_CHK (1<<6)
#define ADIS16260_DIAG_STAT_SELF_TEST (1<<5)
#define ADIS16260_DIAG_STAT_OVERFLOW (1<<4)
#define ADIS16260_DIAG_STAT_SPI_FAIL (1<<3)
#define ADIS16260_DIAG_STAT_FLASH_UPT (1<<2)
#define ADIS16260_DIAG_STAT_POWER_HIGH (1<<1)
#define ADIS16260_DIAG_STAT_POWER_LOW (1<<0)
#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6
#define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5
#define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4
#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3
#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2
#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1
#define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16260_GLOB_CMD_SW_RESET (1<<7)
@ -75,82 +72,27 @@
#define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1)
#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_BURST (u32)(1000 * 1000)
#define ADIS16260_SPI_FAST (u32)(2000 * 1000)
/**
* 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
* @tx: transmit buffer
* @rx: receive buffer
**/
struct adis16260_state {
struct spi_device *us;
struct iio_trigger *trig;
struct mutex buf_lock;
unsigned negate:1;
u8 tx[ADIS16260_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16260_MAX_RX];
unsigned negate:1;
struct adis adis;
};
int adis16260_set_irq(struct iio_dev *indio_dev, bool enable);
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
#define ADIS16260_SCAN_SUPPLY 0
#define ADIS16260_SCAN_GYRO 1
#define ADIS16260_SCAN_GYRO 0
#define ADIS16260_SCAN_SUPPLY 1
#define ADIS16260_SCAN_AUX_ADC 2
#define ADIS16260_SCAN_TEMP 3
#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_ */

View File

@ -24,132 +24,13 @@
#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,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(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");
else
return sprintf(buf, "%s\n", "256 2048");
@ -164,13 +45,11 @@ static ssize_t adis16260_read_frequency(struct device *dev,
int ret, len = 0;
u16 t;
int sps;
ret = adis16260_spi_read_reg_16(indio_dev,
ADIS16260_SMPL_PRD,
&t);
ret = adis_read_reg_16(&st->adis, ADIS16260_SMPL_PRD, &t);
if (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;
else
sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
@ -197,7 +76,7 @@ static ssize_t adis16260_write_frequency(struct device *dev,
return -EINVAL;
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);
if (t > 0)
t--;
@ -209,10 +88,10 @@ static ssize_t adis16260_write_frequency(struct device *dev,
t &= ADIS16260_SMPL_PRD_DIV_MASK;
}
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
st->us->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis16260_spi_write_reg_8(indio_dev,
st->adis.spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis_write_reg_8(&st->adis,
ADIS16260_SMPL_PRD,
t);
@ -221,140 +100,20 @@ static ssize_t adis16260_write_frequency(struct device *dev,
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 */
static int adis16260_stop_device(struct iio_dev *indio_dev)
{
struct adis16260_state *st = iio_priv(indio_dev);
int ret;
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)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
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,
adis16260_read_frequency,
adis16260_write_frequency);
@ -362,100 +121,26 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static IIO_DEVICE_ATTR(sampling_frequency_available,
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) \
struct iio_chan_spec adis16260_channels_##axis[] = { \
{ \
.type = IIO_ANGL_VEL, \
.modified = 1, \
.channel2 = mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.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), \
}
struct iio_chan_spec adis16260_channels_##axis[] = { \
ADIS_GYRO_CHAN(mod, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, 14), \
ADIS_INCLI_CHAN(mod, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), \
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), \
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), \
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12), \
IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X);
static const ADIS16260_GYRO_CHANNEL_SET(y, IIO_MOD_Y);
static const ADIS16260_GYRO_CHANNEL_SET(z, IIO_MOD_Z);
static const ADIS16260_GYRO_CHANNEL_SET(x, X);
static const ADIS16260_GYRO_CHANNEL_SET(y, Y);
static const ADIS16260_GYRO_CHANNEL_SET(z, Z);
static const u8 adis16260_addresses[5][3] = {
[gyro] = { ADIS16260_GYRO_OUT,
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 const u8 adis16260_addresses[][2] = {
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
};
static int adis16260_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
@ -469,34 +154,13 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][0];
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;
return adis_single_conversion(indio_dev, chan,
ADIS16260_ERROR_ACTIVE, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*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 */
*val2 = IIO_DEGREE_TO_RAD(18320);
} else {
@ -533,8 +197,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][1];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16260_addresses[chan->scan_index][0];
ret = adis_read_reg_16(&st->adis, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -553,8 +217,8 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][2];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
addr = adis16260_addresses[chan->scan_index][1];
ret = adis_read_reg_16(&st->adis, addr, &val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
@ -572,18 +236,19 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
struct adis16260_state *st = iio_priv(indio_dev);
int bits = 12;
s16 val16;
u8 addr;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
val16 = val & ((1 << bits) - 1);
addr = adis16260_addresses[chan->address][1];
return adis16260_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16260_addresses[chan->scan_index][0];
return adis_write_reg_16(&st->adis, addr, val16);
case IIO_CHAN_INFO_CALIBSCALE:
val16 = val & ((1 << bits) - 1);
addr = adis16260_addresses[chan->address][2];
return adis16260_spi_write_reg_16(indio_dev, addr, val16);
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(&st->adis, addr, val16);
}
return -EINVAL;
}
@ -602,9 +267,40 @@ static const struct iio_info adis16260_info = {
.attrs = &adis16260_attribute_group,
.read_raw = &adis16260_read_raw,
.write_raw = &adis16260_write_raw,
.update_scan_mode = adis_update_scan_mode,
.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)
{
int ret;
@ -624,10 +320,7 @@ static int __devinit adis16260_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi_get_device_id(st->us)->name;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info;
indio_dev->num_channels
@ -651,17 +344,14 @@ static int __devinit adis16260_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16260_channels_x);
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)
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) {
/* Set default scan mode */
iio_scan_mask_set(indio_dev, indio_dev->buffer,
@ -675,28 +365,19 @@ static int __devinit adis16260_probe(struct spi_device *spi)
iio_scan_mask_set(indio_dev, indio_dev->buffer,
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 */
ret = adis16260_initial_setup(indio_dev);
ret = adis_initial_startup(&st->adis);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
if (ret)
goto error_remove_trigger;
goto error_cleanup_buffer_trigger;
return 0;
error_remove_trigger:
adis16260_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16260_unconfigure_ring(indio_dev);
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
error_free_dev:
iio_device_free(indio_dev);
error_ret:
@ -706,12 +387,11 @@ static int __devinit adis16260_probe(struct spi_device *spi)
static int __devexit adis16260_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16260_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev);
adis16260_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16260_unconfigure_ring(indio_dev);
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
iio_device_free(indio_dev);
return 0;

View File

@ -1,136 +0,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;
}

View File

@ -1,75 +0,0 @@
#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);
}

View File

@ -356,7 +356,7 @@ static int isl29018_write_raw(struct iio_dev *indio_dev,
}
mutex_unlock(&chip->lock);
return 0;
return ret;
}
static int isl29018_read_raw(struct iio_dev *indio_dev,

View File

@ -652,7 +652,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
}
if (!state && (chip->intr & 0x30)) {
chip->intr |= ~0x30;
chip->intr &= ~0x30;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT,
chip->intr);
@ -814,7 +814,7 @@ static int __devexit tsl2563_remove(struct i2c_client *client)
if (!chip->int_enabled)
cancel_delayed_work(&chip->poweroff_work);
/* 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,
chip->intr);
flush_scheduled_work();

View File

@ -195,7 +195,7 @@ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
#else /* CONFIG_IIO_BUFFER */
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)
{
return 0;

View File

@ -620,6 +620,9 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
};
#endif
int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
int *fract);
/**
* IIO_DEGREE_TO_RAD() - Convert degree to rad
* @deg: A value in degree

View File

@ -0,0 +1,280 @@
/*
* 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

View File

@ -28,6 +28,7 @@ enum iio_chan_type {
IIO_CAPACITANCE,
IIO_ALTVOLTAGE,
IIO_CCT,
IIO_PRESSURE,
};
enum iio_modifier {

View File

@ -0,0 +1,20 @@
/*
* 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_ */