linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michael Hennerich <michael.hennerich@analog.com>
To: "jic23@cam.ac.uk" <jic23@cam.ac.uk>
Cc: "linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"guenter.roeck@ericsson.com" <guenter.roeck@ericsson.com>,
	"khali@linux-fr.org" <khali@linux-fr.org>,
	"dmitry.torokhov@gmail.com" <dmitry.torokhov@gmail.com>,
	"broonie@opensource.wolfsonmicro.com" 
	<broonie@opensource.wolfsonmicro.com>,
	"gregkh@suse.de" <gregkh@suse.de>,
	"alan@lxorguk.ukuu.org.uk" <alan@lxorguk.ukuu.org.uk>,
	"arnd@arndb.de" <arnd@arndb.de>,
	"linus.walleij@linaro.org" <linus.walleij@linaro.org>,
	"lars@metafoo.de" <lars@metafoo.de>,
	"maxime.ripard@free-electrons.com"
	<maxime.ripard@free-electrons.com>,
	Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
Subject: Re: [PATCH 5/6] IIO:imu:adis16400 partial move from staging.
Date: Fri, 11 Nov 2011 11:41:34 +0100	[thread overview]
Message-ID: <4EBCFBDE.4000103@analog.com> (raw)
In-Reply-To: <1320677563-18378-6-git-send-email-jic23@cam.ac.uk>

On 11/07/2011 03:52 PM, jic23@cam.ac.uk wrote:
> From: Manuel Stahl<manuel.stahl@iis.fraunhofer.de>
>
> This driver made use of a few convenient corners of scan_type so
> I have lifted those elements into iio_chan_spec structure for now
> (in initial iio core support patch).
>
> Signed-off-by: Jonathan Cameron<jic23@cam.ac.uk>
Acked-by: Michael Hennerich <michael.hennerich@analog.com>
> ---
>   drivers/iio/Kconfig              |    1 +
>   drivers/iio/Makefile             |    1 +
>   drivers/iio/imu/Kconfig          |   12 +
>   drivers/iio/imu/Makefile         |    6 +
>   drivers/iio/imu/adis16400.h      |  180 ++++++
>   drivers/iio/imu/adis16400_core.c | 1142 ++++++++++++++++++++++++++++++++++++++
>   6 files changed, 1342 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index 5dcd9e5..308bc97 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -12,6 +12,7 @@ menuconfig IIO
>   if IIO
>
>   source "drivers/iio/adc/Kconfig"
> +source "drivers/iio/imu/Kconfig"
>   source "drivers/iio/light/Kconfig"
>
>   endif # IIO
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> index 0e59946..db3c426 100644
> --- a/drivers/iio/Makefile
> +++ b/drivers/iio/Makefile
> @@ -6,4 +6,5 @@ obj-$(CONFIG_IIO) += iio.o
>   industrialio-y := core.o
>
>   obj-y += adc/
> +obj-y += imu/
>   obj-y += light/
> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
> new file mode 100644
> index 0000000..fe3c28c
> --- /dev/null
> +++ b/drivers/iio/imu/Kconfig
> @@ -0,0 +1,12 @@
> +menu "Inertial measurement units (IMUs)"
> +
> +config IIO_ADIS16400
> +       tristate "Analog Devices ADIS16400 and similar IMU SPI driver"
> +       depends on SPI
> +       help
> +         Say yes here to build support for Analog Devices adis16300, adis16350,
> +         adis16354, adis16355, adis16360, adis16362, adis16364, adis16365,
> +         adis16400 and adis16405 triaxial inertial sensors (adis16400 series
> +         also have magnetometers).
> +
> +endmenu
> diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
> new file mode 100644
> index 0000000..eb4d31e
> --- /dev/null
> +++ b/drivers/iio/imu/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for IIO IMUs
> +#
> +
> +iio_adis16400-y := adis16400_core.o
> +obj-$(CONFIG_IIO_ADIS16400) += iio_adis16400.o
> \ No newline at end of file
> diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h
> new file mode 100644
> index 0000000..78377ea
> --- /dev/null
> +++ b/drivers/iio/imu/adis16400.h
> @@ -0,0 +1,180 @@
> +/*
> + * adis16400.h support Analog Devices ADIS16400
> + *             3d 18g accelerometers,
> + *             3d gyroscopes,
> + *             3d 2.5gauss magnetometers via SPI
> + *
> + * Copyright (c) 2009 Manuel Stahl<manuel.stahl@iis.fraunhofer.de>
> + * Copyright (c) 2007 Jonathan Cameron<jic23@cam.ac.uk>
> + *
> + * Loosely based upon lis3l02dq.h
> + *
> + * 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.
> + */
> +
> +#ifndef SPI_ADIS16400_H_
> +#define SPI_ADIS16400_H_
> +
> +#define ADIS16400_STARTUP_DELAY        290 /* ms */
> +#define ADIS16400_MTEST_DELAY 90 /* ms */
> +
> +#define ADIS16400_READ_REG(a)    a
> +#define ADIS16400_WRITE_REG(a) ((a) | 0x80)
> +
> +#define ADIS16400_FLASH_CNT  0x00 /* Flash memory write count */
> +#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
> +#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
> +#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */
> +#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */
> +#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */
> +#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */
> +#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */
> +#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */
> +#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */
> +#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */
> +#define ADIS16400_TEMP_OUT  0x16 /* Temperature output */
> +#define ADIS16400_AUX_ADC   0x18 /* Auxiliary ADC measurement */
> +
> +#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */
> +#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */
> +#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
> +
> +#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
> +#define ADIS16300_ROLL_OUT  0x12 /* Y axis inclinometer output measurement */
> +
> +/* Calibration parameters */
> +#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
> +#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
> +#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */
> +#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */
> +#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */
> +#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */
> +#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */
> +#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */
> +#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */
> +#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */
> +#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */
> +#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */
> +
> +#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */
> +#define ADIS16400_MSC_CTRL  0x34 /* Miscellaneous control */
> +#define ADIS16400_SMPL_PRD  0x36 /* Internal sample period (rate) control */
> +#define ADIS16400_SENS_AVG  0x38 /* Dynamic range and digital filter control */
> +#define ADIS16400_SLP_CNT   0x3A /* Sleep mode control */
> +#define ADIS16400_DIAG_STAT 0x3C /* System status */
> +
> +/* Alarm functions */
> +#define ADIS16400_GLOB_CMD  0x3E /* System command */
> +#define ADIS16400_ALM_MAG1  0x40 /* Alarm 1 amplitude threshold */
> +#define ADIS16400_ALM_MAG2  0x42 /* Alarm 2 amplitude threshold */
> +#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */
> +#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */
> +#define ADIS16400_ALM_CTRL  0x48 /* Alarm control */
> +#define ADIS16400_AUX_DAC   0x4A /* Auxiliary DAC data */
> +
> +#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
> +
> +#define ADIS16400_ERROR_ACTIVE                 (1<<14)
> +#define ADIS16400_NEW_DATA                     (1<<14)
> +
> +/* MSC_CTRL */
> +#define ADIS16400_MSC_CTRL_MEM_TEST            (1<<11)
> +#define ADIS16400_MSC_CTRL_INT_SELF_TEST       (1<<10)
> +#define ADIS16400_MSC_CTRL_NEG_SELF_TEST       (1<<9)
> +#define ADIS16400_MSC_CTRL_POS_SELF_TEST       (1<<8)
> +#define ADIS16400_MSC_CTRL_GYRO_BIAS           (1<<7)
> +#define ADIS16400_MSC_CTRL_ACCL_ALIGN          (1<<6)
> +#define ADIS16400_MSC_CTRL_DATA_RDY_EN         (1<<2)
> +#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH   (1<<1)
> +#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2       (1<<0)
> +
> +/* SMPL_PRD */
> +#define ADIS16400_SMPL_PRD_TIME_BASE   (1<<7)
> +#define ADIS16400_SMPL_PRD_DIV_MASK    0x7F
> +
> +/* DIAG_STAT */
> +#define ADIS16400_DIAG_STAT_ZACCL_FAIL (1<<15)
> +#define ADIS16400_DIAG_STAT_YACCL_FAIL (1<<14)
> +#define ADIS16400_DIAG_STAT_XACCL_FAIL (1<<13)
> +#define ADIS16400_DIAG_STAT_XGYRO_FAIL (1<<12)
> +#define ADIS16400_DIAG_STAT_YGYRO_FAIL (1<<11)
> +#define ADIS16400_DIAG_STAT_ZGYRO_FAIL (1<<10)
> +#define ADIS16400_DIAG_STAT_ALARM2     (1<<9)
> +#define ADIS16400_DIAG_STAT_ALARM1     (1<<8)
> +#define ADIS16400_DIAG_STAT_FLASH_CHK  (1<<6)
> +#define ADIS16400_DIAG_STAT_SELF_TEST  (1<<5)
> +#define ADIS16400_DIAG_STAT_OVERFLOW   (1<<4)
> +#define ADIS16400_DIAG_STAT_SPI_FAIL   (1<<3)
> +#define ADIS16400_DIAG_STAT_FLASH_UPT  (1<<2)
> +#define ADIS16400_DIAG_STAT_POWER_HIGH (1<<1)
> +#define ADIS16400_DIAG_STAT_POWER_LOW  (1<<0)
> +
> +/* GLOB_CMD */
> +#define ADIS16400_GLOB_CMD_SW_RESET    (1<<7)
> +#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4)
> +#define ADIS16400_GLOB_CMD_FLASH_UPD   (1<<3)
> +#define ADIS16400_GLOB_CMD_DAC_LATCH   (1<<2)
> +#define ADIS16400_GLOB_CMD_FAC_CALIB   (1<<1)
> +#define ADIS16400_GLOB_CMD_AUTO_NULL   (1<<0)
> +
> +/* SLP_CNT */
> +#define ADIS16400_SLP_CNT_POWER_OFF    (1<<8)
> +
> +#define ADIS16400_MAX_TX 24
> +#define ADIS16400_MAX_RX 24
> +
> +#define ADIS16400_SPI_SLOW     (u32)(300 * 1000)
> +#define ADIS16400_SPI_BURST    (u32)(1000 * 1000)
> +#define ADIS16400_SPI_FAST     (u32)(2000 * 1000)
> +
> +#define ADIS16400_HAS_PROD_ID 1
> +
> +struct adis16400_chip_info {
> +       const struct iio_chan_spec *channels;
> +       const int num_channels;
> +       const int product_id;
> +       const long flags;
> +       unsigned int gyro_scale_micro;
> +       unsigned int accel_scale_micro;
> +};
> +
> +/**
> + * struct adis16400_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 adis16400_state {
> +       struct spi_device               *us;
> +       struct iio_trigger              *trig;
> +       struct mutex                    buf_lock;
> +       struct adis16400_chip_info      *variant;
> +
> +       u8      tx[ADIS16400_MAX_TX] ____cacheline_aligned;
> +       u8      rx[ADIS16400_MAX_RX] ____cacheline_aligned;
> +};
> +
> +#define ADIS16400_SCAN_SUPPLY  0
> +#define ADIS16400_SCAN_GYRO_X  1
> +#define ADIS16400_SCAN_GYRO_Y  2
> +#define ADIS16400_SCAN_GYRO_Z  3
> +#define ADIS16400_SCAN_ACC_X   4
> +#define ADIS16400_SCAN_ACC_Y   5
> +#define ADIS16400_SCAN_ACC_Z   6
> +#define ADIS16400_SCAN_MAGN_X  7
> +#define ADIS16350_SCAN_TEMP_X  7
> +#define ADIS16400_SCAN_MAGN_Y  8
> +#define ADIS16350_SCAN_TEMP_Y  8
> +#define ADIS16400_SCAN_MAGN_Z  9
> +#define ADIS16350_SCAN_TEMP_Z  9
> +#define ADIS16400_SCAN_TEMP    10
> +#define ADIS16350_SCAN_ADC_0   10
> +#define ADIS16400_SCAN_ADC_0   11
> +#define ADIS16300_SCAN_INCLI_X 12
> +#define ADIS16300_SCAN_INCLI_Y 13
> +
> +#endif /* SPI_ADIS16400_H_ */
> diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
> new file mode 100644
> index 0000000..5e49742
> --- /dev/null
> +++ b/drivers/iio/imu/adis16400_core.c
> @@ -0,0 +1,1142 @@
> +/*
> + * adis16400.c support a number of ADI IMUs
> + *
> + * Copyright (c) 2009 Manuel Stahl<manuel.stahl@iis.fraunhofer.de>
> + * Copyright (c) 2007-2011 Jonathan Cameron<jic23@cam.ac.uk>
> + * Copyright (c) 2011 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/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/list.h>
> +
> +#include<linux/iio/iio.h>
> +#include<linux/iio/sysfs.h>
> +#include "adis16400.h"
> +
> +enum adis16400_chip_variant {
> +       ADIS16300,
> +       ADIS16334,
> +       ADIS16350,
> +       ADIS16360,
> +       ADIS16362,
> +       ADIS16364,
> +       ADIS16365,
> +       ADIS16400,
> +};
> +
> +/**
> + * adis16400_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 adis16400_spi_write_reg_8(struct iio_dev *indio_dev,
> +                                    u8 reg_address,
> +                                    u8 val)
> +{
> +       int ret;
> +       struct adis16400_state *st = iio_priv(indio_dev);
> +
> +       mutex_lock(&st->buf_lock);
> +       st->tx[0] = ADIS16400_WRITE_REG(reg_address);
> +       st->tx[1] = val;
> +
> +       ret = spi_write(st->us, st->tx, 2);
> +       mutex_unlock(&st->buf_lock);
> +
> +       return ret;
> +}
> +
> +/**
> + * adis16400_spi_write_reg_16() - write 2 bytes to a pair of registers
> + * @dev: device associated with child of actual device (iio_dev or iio_trig)
> + * @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
> + *
> + * At the moment the spi framework doesn't allow global setting of cs_change.
> + * This means that use cannot be made of spi_write.
> + */
> +static int adis16400_spi_write_reg_16(struct iio_dev *indio_dev,
> +               u8 lower_reg_address,
> +               u16 value)
> +{
> +       int ret;
> +       struct spi_message msg;
> +       struct adis16400_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] = ADIS16400_WRITE_REG(lower_reg_address);
> +       st->tx[1] = value&  0xFF;
> +       st->tx[2] = ADIS16400_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;
> +}
> +
> +/**
> + * adis16400_spi_read_reg_16() - read 2 bytes from a 16-bit register
> + * @indio_dev: iio 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
> + *
> + * At the moment the spi framework doesn't allow global setting of cs_change.
> + * This means that use cannot be made of spi_read.
> + **/
> +static int adis16400_spi_read_reg_16(struct iio_dev *indio_dev,
> +               u8 lower_reg_address,
> +               u16 *val)
> +{
> +       struct spi_message msg;
> +       struct adis16400_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,
> +               }, {
> +                       .rx_buf = st->rx,
> +                       .bits_per_word = 8,
> +                       .len = 2,
> +               },
> +       };
> +
> +       mutex_lock(&st->buf_lock);
> +       st->tx[0] = ADIS16400_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 adis16400_read_frequency(struct device *dev,
> +               struct device_attribute *attr,
> +               char *buf)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       int ret, len = 0;
> +       u16 t;
> +       int sps;
> +       ret = adis16400_spi_read_reg_16(indio_dev,
> +                       ADIS16400_SMPL_PRD,
> +&t);
> +       if (ret)
> +               return ret;
> +       sps =  (t&  ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638;
> +       sps /= (t&  ADIS16400_SMPL_PRD_DIV_MASK) + 1;
> +       len = sprintf(buf, "%d SPS\n", sps);
> +       return len;
> +}
> +
> +static ssize_t adis16400_write_frequency(struct device *dev,
> +               struct device_attribute *attr,
> +               const char *buf,
> +               size_t len)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       struct adis16400_state *st = iio_priv(indio_dev);
> +       long val;
> +       int ret;
> +       u8 t;
> +
> +       ret = strict_strtol(buf, 10,&val);
> +       if (ret)
> +               return ret;
> +
> +       mutex_lock(&indio_dev->mlock);
> +
> +       t = (1638 / val);
> +       if (t>  0)
> +               t--;
> +       t&= ADIS16400_SMPL_PRD_DIV_MASK;
> +       if ((t&  ADIS16400_SMPL_PRD_DIV_MASK)>= 0x0A)
> +               st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +       else
> +               st->us->max_speed_hz = ADIS16400_SPI_FAST;
> +
> +       ret = adis16400_spi_write_reg_8(indio_dev,
> +                       ADIS16400_SMPL_PRD,
> +                       t);
> +
> +       mutex_unlock(&indio_dev->mlock);
> +
> +       return ret ? ret : len;
> +}
> +
> +static int adis16400_reset(struct iio_dev *indio_dev)
> +{
> +       int ret;
> +       ret = adis16400_spi_write_reg_8(indio_dev,
> +                       ADIS16400_GLOB_CMD,
> +                       ADIS16400_GLOB_CMD_SW_RESET);
> +       if (ret)
> +               dev_err(&indio_dev->dev, "problem resetting device");
> +
> +       return ret;
> +}
> +
> +static ssize_t adis16400_write_reset(struct device *dev,
> +               struct device_attribute *attr,
> +               const char *buf, size_t len)
> +{
> +       bool val;
> +       int ret;
> +
> +       ret = strtobool(buf,&val);
> +       if (ret<  0)
> +               return ret;
> +       if (val) {
> +               ret = adis16400_reset(dev_get_drvdata(dev));
> +               if (ret<  0)
> +                       return ret;
> +       }
> +
> +       return len;
> +}
> +
> +/* Power down the device */
> +static int adis16400_stop_device(struct iio_dev *indio_dev)
> +{
> +       int ret;
> +       u16 val = ADIS16400_SLP_CNT_POWER_OFF;
> +
> +       ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SLP_CNT, val);
> +       if (ret)
> +               dev_err(&indio_dev->dev,
> +                       "problem with turning device off: SLP_CNT");
> +
> +       return ret;
> +}
> +
> +static int adis16400_check_status(struct iio_dev *indio_dev)
> +{
> +       u16 status;
> +       int ret;
> +       struct device *dev =&indio_dev->dev;
> +
> +       ret = adis16400_spi_read_reg_16(indio_dev,
> +                                       ADIS16400_DIAG_STAT,&status);
> +
> +       if (ret<  0) {
> +               dev_err(dev, "Reading status failed\n");
> +               goto error_ret;
> +       }
> +       ret = status;
> +       if (status&  ADIS16400_DIAG_STAT_ZACCL_FAIL)
> +               dev_err(dev, "Z-axis accelerometer self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_YACCL_FAIL)
> +               dev_err(dev, "Y-axis accelerometer self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_XACCL_FAIL)
> +               dev_err(dev, "X-axis accelerometer self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_XGYRO_FAIL)
> +               dev_err(dev, "X-axis gyroscope self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_YGYRO_FAIL)
> +               dev_err(dev, "Y-axis gyroscope self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_ZGYRO_FAIL)
> +               dev_err(dev, "Z-axis gyroscope self-test failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_ALARM2)
> +               dev_err(dev, "Alarm 2 active\n");
> +       if (status&  ADIS16400_DIAG_STAT_ALARM1)
> +               dev_err(dev, "Alarm 1 active\n");
> +       if (status&  ADIS16400_DIAG_STAT_FLASH_CHK)
> +               dev_err(dev, "Flash checksum error\n");
> +       if (status&  ADIS16400_DIAG_STAT_SELF_TEST)
> +               dev_err(dev, "Self test error\n");
> +       if (status&  ADIS16400_DIAG_STAT_OVERFLOW)
> +               dev_err(dev, "Sensor overrange\n");
> +       if (status&  ADIS16400_DIAG_STAT_SPI_FAIL)
> +               dev_err(dev, "SPI failure\n");
> +       if (status&  ADIS16400_DIAG_STAT_FLASH_UPT)
> +               dev_err(dev, "Flash update failed\n");
> +       if (status&  ADIS16400_DIAG_STAT_POWER_HIGH)
> +               dev_err(dev, "Power supply above 5.25V\n");
> +       if (status&  ADIS16400_DIAG_STAT_POWER_LOW)
> +               dev_err(dev, "Power supply below 4.75V\n");
> +
> +error_ret:
> +       return ret;
> +}
> +
> +static int adis16400_self_test(struct iio_dev *indio_dev)
> +{
> +       int ret;
> +       ret = adis16400_spi_write_reg_16(indio_dev,
> +                       ADIS16400_MSC_CTRL,
> +                       ADIS16400_MSC_CTRL_MEM_TEST);
> +       if (ret) {
> +               dev_err(&indio_dev->dev, "problem starting self test");
> +               goto err_ret;
> +       }
> +
> +       msleep(ADIS16400_MTEST_DELAY);
> +       adis16400_check_status(indio_dev);
> +
> +err_ret:
> +       return ret;
> +}
> +
> +static int adis16400_initial_setup(struct iio_dev *indio_dev)
> +{
> +       int ret;
> +       u16 prod_id, smp_prd;
> +       struct adis16400_state *st = iio_priv(indio_dev);
> +
> +       /* use low spi speed for init */
> +       st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +       st->us->mode = SPI_MODE_3;
> +       spi_setup(st->us);
> +
> +       ret = adis16400_self_test(indio_dev);
> +       if (ret) {
> +               dev_err(&indio_dev->dev, "self test failure");
> +               goto err_ret;
> +       }
> +
> +       ret = adis16400_check_status(indio_dev);
> +       if (ret) {
> +               adis16400_reset(indio_dev);
> +               dev_err(&indio_dev->dev, "device not playing ball ->  reset");
> +               msleep(ADIS16400_STARTUP_DELAY);
> +               ret = adis16400_check_status(indio_dev);
> +               if (ret) {
> +                       dev_err(&indio_dev->dev, "giving up");
> +                       goto err_ret;
> +               }
> +       }
> +       if (st->variant->flags&  ADIS16400_HAS_PROD_ID) {
> +               ret = adis16400_spi_read_reg_16(indio_dev,
> +                                               ADIS16400_PRODUCT_ID,&prod_id);
> +               if (ret)
> +                       goto err_ret;
> +
> +               if ((prod_id&  0xF000) != st->variant->product_id)
> +                       dev_warn(&indio_dev->dev, "incorrect id");
> +
> +               dev_info(&indio_dev->dev,
> +                        "%s: prod_id 0x%04x at CS%d (irq %d)\n",
> +                        indio_dev->name, prod_id,
> +                        st->us->chip_select, st->us->irq);
> +       }
> +       /* use high spi speed if possible */
> +       ret = adis16400_spi_read_reg_16(indio_dev,
> +                                       ADIS16400_SMPL_PRD,&smp_prd);
> +       if (!ret&&  (smp_prd&  ADIS16400_SMPL_PRD_DIV_MASK)<  0x0A) {
> +               st->us->max_speed_hz = ADIS16400_SPI_SLOW;
> +               spi_setup(st->us);
> +       }
> +
> +err_ret:
> +       return ret;
> +}
> +
> +static IIO_DEVICE_ATTR(sampling_frequency,
> +                      S_IWUSR | S_IRUGO,
> +                      adis16400_read_frequency,
> +                      adis16400_write_frequency,
> +                      0);
> +
> +static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16400_write_reset, 0);
> +
> +static IIO_CONST_ATTR(sampling_frequency_available, "409 546 819 1638");
> +
> +enum adis16400_chan {
> +       in_supply,
> +       gyro_x,
> +       gyro_y,
> +       gyro_z,
> +       accel_x,
> +       accel_y,
> +       accel_z,
> +       magn_x,
> +       magn_y,
> +       magn_z,
> +       temp,
> +       temp0, temp1, temp2,
> +       in1,
> +       incli_x,
> +       incli_y,
> +};
> +
> +static u8 adis16400_addresses[17][2] = {
> +       [in_supply] = { ADIS16400_SUPPLY_OUT },
> +       [gyro_x] = { ADIS16400_XGYRO_OUT, ADIS16400_XGYRO_OFF },
> +       [gyro_y] = { ADIS16400_YGYRO_OUT, ADIS16400_YGYRO_OFF },
> +       [gyro_z] = { ADIS16400_ZGYRO_OUT, ADIS16400_ZGYRO_OFF },
> +       [accel_x] = { ADIS16400_XACCL_OUT, ADIS16400_XACCL_OFF },
> +       [accel_y] = { ADIS16400_YACCL_OUT, ADIS16400_YACCL_OFF },
> +       [accel_z] = { ADIS16400_ZACCL_OUT, ADIS16400_ZACCL_OFF },
> +       [magn_x] = { ADIS16400_XMAGN_OUT },
> +       [magn_y] = { ADIS16400_YMAGN_OUT },
> +       [magn_z] = { ADIS16400_ZMAGN_OUT },
> +       [temp] = { ADIS16400_TEMP_OUT },
> +       [temp0] = { ADIS16350_XTEMP_OUT },
> +       [temp1] = { ADIS16350_YTEMP_OUT },
> +       [temp2] = { ADIS16350_ZTEMP_OUT },
> +       [in1] = { ADIS16400_AUX_ADC },
> +       [incli_x] = { ADIS16300_PITCH_OUT },
> +       [incli_y] = { ADIS16300_ROLL_OUT }
> +};
> +
> +static int adis16400_write_raw(struct iio_dev *indio_dev,
> +                              struct iio_chan_spec const *chan,
> +                              int val,
> +                              int val2,
> +                              long mask)
> +{
> +       int ret;
> +
> +       switch (mask) {
> +       case IIO_CHAN_INFO_CALIBBIAS:
> +               mutex_lock(&indio_dev->mlock);
> +               ret = adis16400_spi_write_reg_16(indio_dev,
> +                               adis16400_addresses[chan->address][1],
> +                               val);
> +               mutex_unlock(&indio_dev->mlock);
> +               return ret;
> +       default:
> +               return -EINVAL;
> +       }
> +}
> +
> +static int adis16400_read_raw(struct iio_dev *indio_dev,
> +                             struct iio_chan_spec const *chan,
> +                             int *val,
> +                             int *val2,
> +                             long mask)
> +{
> +       struct adis16400_state *st = iio_priv(indio_dev);
> +       int ret, shift;
> +       s16 val16;
> +
> +       switch (mask) {
> +       case 0:
> +               mutex_lock(&indio_dev->mlock);
> +               ret = adis16400_spi_read_reg_16(indio_dev,
> +                               adis16400_addresses[chan->address][0],
> +&val16);
> +               if (ret) {
> +                       mutex_unlock(&indio_dev->mlock);
> +                       return ret;
> +               }
> +               val16&= (1<<  chan->scan_type.realbits) - 1;
> +               if (chan->scan_type.sign == 's') {
> +                       shift = 16 - chan->scan_type.realbits;
> +                       val16 = (s16)(val16<<  shift)>>  shift;
> +               }
> +               *val = val16;
> +               mutex_unlock(&indio_dev->mlock);
> +               return IIO_VAL_INT;
> +       case IIO_CHAN_INFO_SCALE:
> +               switch (chan->type) {
> +               case IIO_ANGL_VEL:
> +                       *val = 0;
> +                       *val2 = st->variant->gyro_scale_micro;
> +                       return IIO_VAL_INT_PLUS_MICRO;
> +               case IIO_IN:
> +                       *val = 0;
> +                       if (chan->channel == 0)
> +                               *val2 = 2418;
> +                       else
> +                               *val2 = 806;
> +                       return IIO_VAL_INT_PLUS_MICRO;
> +               case IIO_ACCEL:
> +                       *val = 0;
> +                       *val2 = st->variant->accel_scale_micro;
> +                       return IIO_VAL_INT_PLUS_MICRO;
> +               case IIO_MAGN:
> +                       *val = 0;
> +                       *val2 = 500;
> +                       return IIO_VAL_INT_PLUS_MICRO;
> +               case IIO_TEMP:
> +                       *val = 0;
> +                       *val2 = 140000;
> +                       return IIO_VAL_INT_PLUS_MICRO;
> +               default:
> +                       return -EINVAL;
> +               }
> +       case IIO_CHAN_INFO_CALIBBIAS:
> +               mutex_lock(&indio_dev->mlock);
> +               ret = adis16400_spi_read_reg_16(indio_dev,
> +                               adis16400_addresses[chan->address][1],
> +&val16);
> +               mutex_unlock(&indio_dev->mlock);
> +               if (ret)
> +                       return ret;
> +               val16 = ((val16&  0xFFF)<<  4)>>  4;
> +               *val = val16;
> +               return IIO_VAL_INT;
> +       case IIO_CHAN_INFO_OFFSET:
> +               /* currently only temperature */
> +               *val = 198;
> +               *val2 = 160000;
> +               return IIO_VAL_INT_PLUS_MICRO;
> +       default:
> +               return -EINVAL;
> +       }
> +}
> +
> +static struct iio_chan_spec adis16400_channels[] = {
> +       {
> +               .type = IIO_VOLTAGE,
> +               .indexed = 1,
> +               .channel = 0,
> +               .extend_name = "supply",
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in_supply,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 'u',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_MAGN,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = magn_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_MAGN,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = magn_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_MAGN,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = magn_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 0,
> +               .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = temp,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_IN,
> +               .indexed = 1,
> +               .channel = 1,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in1,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 'u',
> +               },
> +       },
> +};
> +
> +static struct iio_chan_spec adis16350_channels[] = {
> +       {
> +               .type = IIO_VOLTAGE,
> +               .indexed = 1,
> +               .channel = 0,
> +               .extend_name = "supply",
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in_supply,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 'u',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 0,
> +               .extend_name = "x",
> +               .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = temp0,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 1,
> +               .extend_name = "y",
> +               .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = temp1,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 2,
> +               .extend_name = "z",
> +               .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = temp2,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_IN,
> +               .indexed = 1,
> +               .channel = 1,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in1,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 'u',
> +               },
> +       },
> +};
> +
> +static struct iio_chan_spec adis16300_channels[] = {
> +       {
> +               .type = IIO_VOLTAGE,
> +               .indexed = 1,
> +               .channel = 0,
> +               .extend_name = "supply",
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in_supply,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 'u',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 0,
> +               .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = temp,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_IN,
> +               .indexed = 1,
> +               .channel = 1,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
> +               .address = in1,
> +               .scan_type = {
> +                       .realbits = 12,
> +                       .sign = 'u',
> +               },
> +       }, {
> +               .type = IIO_INCLI,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = incli_x,
> +               .scan_type = {
> +                       .realbits = 13,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_INCLI,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = incli_y,
> +               .scan_type = {
> +                       .realbits = 13,
> +                       .sign = 's',
> +               },
> +       },
> +};
> +
> +static const struct iio_chan_spec adis16334_channels[] = {
> +       {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ANGL_VEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = gyro_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_X,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_x,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Y,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_y,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_ACCEL,
> +               .modified = 1,
> +               .channel2 = IIO_MOD_Z,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       }, {
> +               .type = IIO_TEMP,
> +               .indexed = 1,
> +               .channel = 0,
> +               .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
> +               IIO_CHAN_INFO_SCALE_SHARED_BIT,
> +               .address = accel_z,
> +               .scan_type = {
> +                       .realbits = 14,
> +                       .sign = 's',
> +               },
> +       },
> +};
> +
> +static struct attribute *adis16400_attributes[] = {
> +&iio_dev_attr_sampling_frequency.dev_attr.attr,
> +&iio_const_attr_sampling_frequency_available.dev_attr.attr,
> +&iio_dev_attr_reset.dev_attr.attr,
> +       NULL
> +};
> +
> +static const struct attribute_group adis16400_attribute_group = {
> +       .attrs = adis16400_attributes,
> +};
> +
> +static struct adis16400_chip_info adis16400_chips[] = {
> +       [ADIS16300] = {
> +               .channels = adis16300_channels,
> +               .num_channels = ARRAY_SIZE(adis16300_channels),
> +               .gyro_scale_micro = 873,
> +               .accel_scale_micro = 5884,
> +       },
> +       [ADIS16334] = {
> +               .channels = adis16334_channels,
> +               .num_channels = ARRAY_SIZE(adis16334_channels),
> +               .gyro_scale_micro = 873,
> +               .accel_scale_micro = 981,
> +       },
> +       [ADIS16350] = {
> +               .channels = adis16350_channels,
> +               .num_channels = ARRAY_SIZE(adis16350_channels),
> +               .gyro_scale_micro = 872664,
> +               .accel_scale_micro = 24732,
> +       },
> +       [ADIS16360] = {
> +               .channels = adis16350_channels,
> +               .num_channels = ARRAY_SIZE(adis16350_channels),
> +               .flags = ADIS16400_HAS_PROD_ID,
> +               .product_id = 0x3FE8,
> +               .gyro_scale_micro = 1279,
> +               .accel_scale_micro = 24732,
> +       },
> +       [ADIS16362] = {
> +               .channels = adis16350_channels,
> +               .num_channels = ARRAY_SIZE(adis16350_channels),
> +               .flags = ADIS16400_HAS_PROD_ID,
> +               .product_id = 0x3FEA,
> +               .gyro_scale_micro = 1279,
> +               .accel_scale_micro = 24732,
> +       },
> +       [ADIS16364] = {
> +               .channels = adis16350_channels,
> +               .num_channels = ARRAY_SIZE(adis16350_channels),
> +               .flags = ADIS16400_HAS_PROD_ID,
> +               .product_id = 0x3FEC,
> +               .gyro_scale_micro = 1279,
> +               .accel_scale_micro = 24732,
> +       },
> +       [ADIS16365] = {
> +               .channels = adis16350_channels,
> +               .num_channels = ARRAY_SIZE(adis16350_channels),
> +               .flags = ADIS16400_HAS_PROD_ID,
> +               .product_id = 0x3FED,
> +               .gyro_scale_micro = 1279,
> +               .accel_scale_micro = 24732,
> +       },
> +       [ADIS16400] = {
> +               .channels = adis16400_channels,
> +               .num_channels = ARRAY_SIZE(adis16400_channels),
> +               .flags = ADIS16400_HAS_PROD_ID,
> +               .product_id = 0x4015,
> +               .gyro_scale_micro = 873,
> +               .accel_scale_micro = 32656,
> +       }
> +};
> +
> +static const struct iio_info adis16400_info = {
> +       .driver_module = THIS_MODULE,
> +       .read_raw =&adis16400_read_raw,
> +       .write_raw =&adis16400_write_raw,
> +       .attrs =&adis16400_attribute_group,
> +};
> +
> +static int __devinit adis16400_probe(struct spi_device *spi)
> +{
> +       int ret;
> +       struct adis16400_state *st;
> +       struct iio_dev *indio_dev;
> +
> +       indio_dev = iio_device_allocate(sizeof(*st));
> +       if (indio_dev == NULL) {
> +               ret = -ENOMEM;
> +               goto error_ret;
> +       }
> +       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);
> +
> +       /* setup the industrialio driver allocated elements */
> +       st->variant =&adis16400_chips[spi_get_device_id(spi)->driver_data];
> +       indio_dev->dev.parent =&spi->dev;
> +       indio_dev->name = spi_get_device_id(spi)->name;
> +       indio_dev->channels = st->variant->channels;
> +       indio_dev->num_channels = st->variant->num_channels;
> +       indio_dev->info =&adis16400_info;
> +
> +       ret = iio_device_register(indio_dev);
> +       if (ret)
> +               goto error_free_dev;
> +
> +       /* Get the device into a sane initial state */
> +       ret = adis16400_initial_setup(indio_dev);
> +       if (ret)
> +               goto error_unregister_dev;
> +
> +       return 0;
> +
> +error_unregister_dev:
> +       iio_device_unregister(indio_dev);
> +error_free_dev:
> +       iio_device_free(indio_dev);
> +error_ret:
> +       return ret;
> +}
> +
> +/* fixme, confirm ordering in this function */
> +static int adis16400_remove(struct spi_device *spi)
> +{
> +       int ret;
> +       struct iio_dev *indio_dev = spi_get_drvdata(spi);
> +
> +       iio_device_unregister(indio_dev);
> +
> +       ret = adis16400_stop_device(indio_dev);
> +       if (ret)
> +               return ret;
> +
> +       iio_device_free(indio_dev);
> +
> +       return 0;
> +}
> +
> +static const struct spi_device_id adis16400_id[] = {
> +       {"adis16300", ADIS16300},
> +       {"adis16334", ADIS16334},
> +       {"adis16350", ADIS16350},
> +       {"adis16354", ADIS16350},
> +       {"adis16355", ADIS16350},
> +       {"adis16360", ADIS16360},
> +       {"adis16362", ADIS16362},
> +       {"adis16364", ADIS16364},
> +       {"adis16365", ADIS16365},
> +       {"adis16400", ADIS16400},
> +       {"adis16405", ADIS16400},
> +       {}
> +};
> +
> +static struct spi_driver adis16400_driver = {
> +       .driver = {
> +               .name = "adis16400",
> +               .owner = THIS_MODULE,
> +       },
> +       .id_table = adis16400_id,
> +       .probe = adis16400_probe,
> +       .remove = __devexit_p(adis16400_remove),
> +};
> +
> +static __init int adis16400_init(void)
> +{
> +       return spi_register_driver(&adis16400_driver);
> +}
> +module_init(adis16400_init);
> +
> +static __exit void adis16400_exit(void)
> +{
> +       spi_unregister_driver(&adis16400_driver);
> +}
> +module_exit(adis16400_exit);
> +
> +MODULE_AUTHOR("Manuel Stahl<manuel.stahl@iis.fraunhofer.de>");
> +MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.7.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif



  reply	other threads:[~2011-11-11 10:44 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-07 14:52 [PATCH 0/6 V2] IIO: Out of staging step 1: The core jic23
2011-11-07 14:52 ` [PATCH 1/6] IIO: Core sysfs only support jic23
2011-11-11 10:40   ` Michael Hennerich
2012-02-01 15:20   ` Maxime Ripard
2011-11-07 14:52 ` [PATCH 2/6] IIO:ADC: max1363 initial import jic23
2011-11-07 14:52 ` [PATCH 3/6] IIO:ADC:ad799x " jic23
2011-11-08 13:07   ` Lars-Peter Clausen
2011-11-08 13:35     ` Jonathan Cameron
2011-11-07 14:52 ` [PATCH 4/6] IIO:light:tsl2563 initial move out of staging jic23
2011-11-07 14:52 ` [PATCH 5/6] IIO:imu:adis16400 partial move from staging jic23
2011-11-11 10:41   ` Michael Hennerich [this message]
2011-11-07 14:52 ` [PATCH 6/6] IIO: ABI documetation jic23
2011-11-11 10:41   ` Michael Hennerich
2011-11-08 13:32 ` [PATCH 0/6 V2] IIO: Out of staging step 1: The core Lars-Peter Clausen
2011-11-08 14:23   ` Jonathan Cameron
2011-11-08 14:53     ` Lars-Peter Clausen
2011-11-08 15:29       ` Jonathan Cameron
  -- strict thread matches above, loose matches on Subject: below --
2011-10-17 13:16 [PATCH 0/6] " Jonathan Cameron
2011-10-17 13:16 ` [PATCH 5/6] IIO:imu:adis16400 partial move from staging Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4EBCFBDE.4000103@analog.com \
    --to=michael.hennerich@analog.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=arnd@arndb.de \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=gregkh@suse.de \
    --cc=guenter.roeck@ericsson.com \
    --cc=jic23@cam.ac.uk \
    --cc=khali@linux-fr.org \
    --cc=lars@metafoo.de \
    --cc=linus.walleij@linaro.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=manuel.stahl@iis.fraunhofer.de \
    --cc=maxime.ripard@free-electrons.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).