From d6b09bd85d57752395c6407bd8a9b32eb7b279ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Jan 2013 12:48:00 +0000 Subject: staging:iio: Move adis16400 out of staging This adis16400 driver is in pretty good shape now, so move it out of staging. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 3d79a40..47f66ed 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -3,6 +3,17 @@ # menu "Inertial measurement units" +config ADIS16400 + tristate "Analog Devices ADIS16400 and similar IMU SPI 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 adis16300, adis16344, + adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, + adis16365, adis16400 and adis16405 triaxial inertial sensors + (adis16400 series also have magnetometers). + config ADIS16480 tristate "Analog Devices ADIS16480 and similar IMU driver" depends on SPI diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index cfe5763..019b717 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -2,6 +2,9 @@ # Makefile for Inertial Measurement Units # +adis16400-y := adis16400_core.o +adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o +obj-$(CONFIG_ADIS16400) += adis16400.o obj-$(CONFIG_ADIS16480) += adis16480.o adis_lib-y += adis.o diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h new file mode 100644 index 0000000..a3b9e56 --- /dev/null +++ b/drivers/iio/imu/adis16400.h @@ -0,0 +1,204 @@ +/* + * adis16400.h support Analog Devices ADIS16400 + * 3d 18g accelerometers, + * 3d gyroscopes, + * 3d 2.5gauss magnetometers via SPI + * + * Copyright (c) 2009 Manuel Stahl + * Copyright (c) 2007 Jonathan Cameron + * + * 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_ + +#include + +#define ADIS16400_STARTUP_DELAY 290 /* ms */ +#define ADIS16400_MTEST_DELAY 90 /* ms */ + +#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 0x14 /* Y axis inclinometer output measurement */ +#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC 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 15 +#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 +#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 +#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 +#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 +#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 +#define ADIS16400_DIAG_STAT_ALARM2 9 +#define ADIS16400_DIAG_STAT_ALARM1 8 +#define ADIS16400_DIAG_STAT_FLASH_CHK 6 +#define ADIS16400_DIAG_STAT_SELF_TEST 5 +#define ADIS16400_DIAG_STAT_OVERFLOW 4 +#define ADIS16400_DIAG_STAT_SPI_FAIL 3 +#define ADIS16400_DIAG_STAT_FLASH_UPT 2 +#define ADIS16400_DIAG_STAT_POWER_HIGH 1 +#define ADIS16400_DIAG_STAT_POWER_LOW 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 ADIS16334_RATE_DIV_SHIFT 8 +#define ADIS16334_RATE_INT_CLK BIT(0) + +#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 BIT(0) +#define ADIS16400_NO_BURST BIT(1) +#define ADIS16400_HAS_SLOW_MODE BIT(2) + +struct adis16400_state; + +struct adis16400_chip_info { + const struct iio_chan_spec *channels; + const int num_channels; + const long flags; + unsigned int gyro_scale_micro; + unsigned int accel_scale_micro; + int temp_scale_nano; + int temp_offset; + int (*set_freq)(struct adis16400_state *st, unsigned int freq); + int (*get_freq)(struct adis16400_state *st); +}; + +/** + * struct adis16400_state - device instance specific data + * @variant: chip variant info + * @filt_int: integer part of requested filter frequency + * @adis: adis device + **/ +struct adis16400_state { + struct adis16400_chip_info *variant; + int filt_int; + + struct adis adis; +}; + +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +enum { + ADIS16400_SCAN_SUPPLY, + ADIS16400_SCAN_GYRO_X, + ADIS16400_SCAN_GYRO_Y, + ADIS16400_SCAN_GYRO_Z, + ADIS16400_SCAN_ACC_X, + ADIS16400_SCAN_ACC_Y, + ADIS16400_SCAN_ACC_Z, + ADIS16400_SCAN_MAGN_X, + ADIS16400_SCAN_MAGN_Y, + ADIS16400_SCAN_MAGN_Z, + ADIS16350_SCAN_TEMP_X, + ADIS16350_SCAN_TEMP_Y, + ADIS16350_SCAN_TEMP_Z, + ADIS16300_SCAN_INCLI_X, + ADIS16300_SCAN_INCLI_Y, + ADIS16400_SCAN_ADC, +}; + +#ifdef CONFIG_IIO_BUFFER + +ssize_t adis16400_read_data_from_ring(struct device *dev, + struct device_attribute *attr, + char *buf); + + +int adis16400_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask); +irqreturn_t adis16400_trigger_handler(int irq, void *p); + +#else /* CONFIG_IIO_BUFFER */ + +#define adis16400_update_scan_mode NULL +#define adis16400_trigger_handler NULL + +#endif /* CONFIG_IIO_BUFFER */ + +#endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c new file mode 100644 index 0000000..054c01d --- /dev/null +++ b/drivers/iio/imu/adis16400_buffer.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "adis16400.h" + +int adis16400_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct adis16400_state *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + uint16_t *tx, *rx; + + if (st->variant->flags & ADIS16400_NO_BURST) + return adis_update_scan_mode(indio_dev, scan_mask); + + kfree(adis->xfer); + kfree(adis->buffer); + + adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); + if (!adis->xfer) + return -ENOMEM; + + adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), + GFP_KERNEL); + if (!adis->buffer) + return -ENOMEM; + + rx = adis->buffer; + tx = adis->buffer + indio_dev->scan_bytes; + + tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); + tx[1] = 0; + + adis->xfer[0].tx_buf = tx; + adis->xfer[0].bits_per_word = 8; + adis->xfer[0].len = 2; + adis->xfer[1].tx_buf = tx; + adis->xfer[1].bits_per_word = 8; + adis->xfer[1].len = indio_dev->scan_bytes; + + spi_message_init(&adis->msg); + spi_message_add_tail(&adis->xfer[0], &adis->msg); + spi_message_add_tail(&adis->xfer[1], &adis->msg); + + return 0; +} + +irqreturn_t adis16400_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adis16400_state *st = iio_priv(indio_dev); + struct adis *adis = &st->adis; + u32 old_speed_hz = st->adis.spi->max_speed_hz; + int ret; + + if (!adis->buffer) + return -ENOMEM; + + if (!(st->variant->flags & ADIS16400_NO_BURST) && + st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { + st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; + spi_setup(st->adis.spi); + } + + ret = spi_sync(adis->spi, &adis->msg); + if (ret) + dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); + + if (!(st->variant->flags & ADIS16400_NO_BURST)) { + st->adis.spi->max_speed_hz = old_speed_hz; + spi_setup(st->adis.spi); + } + + /* 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; +} diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c new file mode 100644 index 0000000..1bbe5ee --- /dev/null +++ b/drivers/iio/imu/adis16400_core.c @@ -0,0 +1,812 @@ +/* + * adis16400.c support Analog Devices ADIS16400/5 + * 3d 2g Linear Accelerometers, + * 3d Gyroscopes, + * 3d Magnetometers via SPI + * + * Copyright (c) 2009 Manuel Stahl + * Copyright (c) 2007 Jonathan Cameron + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "adis16400.h" + +enum adis16400_chip_variant { + ADIS16300, + ADIS16334, + ADIS16350, + ADIS16360, + ADIS16362, + ADIS16364, + ADIS16400, +}; + +static int adis16334_get_freq(struct adis16400_state *st) +{ + int ret; + uint16_t t; + + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); + if (ret < 0) + return ret; + + t >>= ADIS16334_RATE_DIV_SHIFT; + + return (8192 >> t) / 10; +} + +static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) +{ + unsigned int t; + + freq *= 10; + if (freq < 8192) + t = ilog2(8192 / freq); + else + t = 0; + + if (t > 0x31) + t = 0x31; + + t <<= ADIS16334_RATE_DIV_SHIFT; + t |= ADIS16334_RATE_INT_CLK; + + return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); +} + +static int adis16400_get_freq(struct adis16400_state *st) +{ + int sps, ret; + uint16_t t; + + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); + if (ret < 0) + return ret; + + sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; + sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; + + return sps; +} + +static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) +{ + unsigned int t; + + t = 1638 / freq; + if (t > 0) + t--; + t &= ADIS16400_SMPL_PRD_DIV_MASK; + + if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; + else + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; + + return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); +} + +static ssize_t adis16400_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adis16400_state *st = iio_priv(indio_dev); + int ret; + + ret = st->variant->get_freq(st); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", ret); +} + +static const unsigned adis16400_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 adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) +{ + struct adis16400_state *st = iio_priv(indio_dev); + uint16_t val16; + int i, ret; + + for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { + if (sps / adis16400_3db_divisors[i] >= val) + break; + } + + ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); + if (ret < 0) + return ret; + + ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, + (val16 & ~0x07) | i); + return ret; +} + +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_to_iio_dev(dev); + struct adis16400_state *st = iio_priv(indio_dev); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + + if (val == 0) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + st->variant->set_freq(st, val); + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +/* Power down the device */ +static int adis16400_stop_device(struct iio_dev *indio_dev) +{ + struct adis16400_state *st = iio_priv(indio_dev); + int ret; + + ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, + ADIS16400_SLP_CNT_POWER_OFF); + if (ret) + dev_err(&indio_dev->dev, + "problem with turning device off: SLP_CNT"); + + return ret; +} + +static int adis16400_initial_setup(struct iio_dev *indio_dev) +{ + struct adis16400_state *st = iio_priv(indio_dev); + uint16_t prod_id, smp_prd; + unsigned int device_id; + int ret; + + /* use low spi speed for init if the device has a slow mode */ + if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; + else + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; + st->adis.spi->mode = SPI_MODE_3; + spi_setup(st->adis.spi); + + ret = adis_initial_startup(&st->adis); + if (ret) + return ret; + + if (st->variant->flags & ADIS16400_HAS_PROD_ID) { + ret = adis_read_reg_16(&st->adis, + ADIS16400_PRODUCT_ID, &prod_id); + if (ret) + goto err_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); + + dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", + indio_dev->name, prod_id, + st->adis.spi->chip_select, st->adis.spi->irq); + } + /* use high spi speed if possible */ + if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); + if (ret) + goto err_ret; + + if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; + spi_setup(st->adis.spi); + } + } + +err_ret: + return ret; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + adis16400_read_frequency, + adis16400_write_frequency); + +static const uint8_t adis16400_addresses[] = { + [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, + [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, + [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, + [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, + [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, + [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, +}; + +static int adis16400_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long info) +{ + struct adis16400_state *st = iio_priv(indio_dev); + int ret, sps; + + switch (info) { + case IIO_CHAN_INFO_CALIBBIAS: + mutex_lock(&indio_dev->mlock); + ret = adis_write_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], val); + mutex_unlock(&indio_dev->mlock); + return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + /* + * Need to cache values so we can update if the frequency + * changes. + */ + mutex_lock(&indio_dev->mlock); + st->filt_int = val; + /* Work out update to current value */ + sps = st->variant->get_freq(st); + if (sps < 0) { + mutex_unlock(&indio_dev->mlock); + return sps; + } + + ret = adis16400_set_filter(indio_dev, sps, 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 info) +{ + struct adis16400_state *st = iio_priv(indio_dev); + int16_t val16; + 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 = 0; + *val2 = st->variant->gyro_scale_micro; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_VOLTAGE: + *val = 0; + if (chan->channel == 0) { + *val = 2; + *val2 = 418000; /* 2.418 mV */ + } else { + *val = 0; + *val2 = 805800; /* 805.8 uV */ + } + 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; /* 0.5 mgauss */ + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = st->variant->temp_scale_nano / 1000000; + *val2 = (st->variant->temp_scale_nano % 1000000); + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBBIAS: + mutex_lock(&indio_dev->mlock); + ret = adis_read_reg_16(&st->adis, + adis16400_addresses[chan->scan_index], &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 = st->variant->temp_offset; + return IIO_VAL_INT; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&indio_dev->mlock); + /* Need both the number of taps and the sampling frequency */ + ret = adis_read_reg_16(&st->adis, + ADIS16400_SENS_AVG, + &val16); + if (ret < 0) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + ret = st->variant->get_freq(st); + if (ret >= 0) + *val = ret / adis16400_3db_divisors[val16 & 0x07]; + *val2 = 0; + mutex_unlock(&indio_dev->mlock); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 0, \ + .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, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_SUPPLY_CHAN(addr, bits) \ + ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) + +#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ + ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) + +#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .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_SHARED_BIT, \ + .address = addr, \ + .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .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_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_MOD_TEMP_NAME_X "x" +#define ADIS16400_MOD_TEMP_NAME_Y "y" +#define ADIS16400_MOD_TEMP_NAME_Z "z" + +#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = 0, \ + .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_TEMP_CHAN(addr, bits) { \ + .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 = (addr), \ + .scan_index = ADIS16350_SCAN_TEMP_X, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ + .type = IIO_INCLI, \ + .modified = 1, \ + .channel2 = IIO_MOD_ ## mod, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = (addr), \ + .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec adis16400_channels[] = { + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), + ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), + IIO_CHAN_SOFT_TIMESTAMP(12) +}; + +static const struct iio_chan_spec adis16350_channels[] = { + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), + ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), + ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), + ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(11) +}; + +static const struct iio_chan_spec adis16300_channels[] = { + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), + ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), + ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), + IIO_CHAN_SOFT_TIMESTAMP(14) +}; + +static const struct iio_chan_spec adis16334_channels[] = { + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(8) +}; + +static struct attribute *adis16400_attributes[] = { + &iio_dev_attr_sampling_frequency.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), + .flags = ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = 5884, + .temp_scale_nano = 140000000, /* 0.14 C */ + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, + [ADIS16334] = { + .channels = adis16334_channels, + .num_channels = ARRAY_SIZE(adis16334_channels), + .flags = ADIS16400_HAS_PROD_ID, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ + .temp_scale_nano = 67850000, /* 0.06785 C */ + .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + }, + [ADIS16350] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ + .temp_scale_nano = 145300000, /* 0.1453 C */ + .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ + .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, + [ADIS16360] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, + [ADIS16362] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, + [ADIS16364] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, + [ADIS16400] = { + .channels = adis16400_channels, + .num_channels = ARRAY_SIZE(adis16400_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 140000000, /* 0.14 C */ + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + } +}; + +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, + .update_scan_mode = adis16400_update_scan_mode, +}; + +static const unsigned long adis16400_burst_scan_mask[] = { + ~0UL, + 0, +}; + +static const char * const adis16400_status_error_msgs[] = { + [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", + [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", + [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", + [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", + [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", + [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", + [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", + [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", + [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", + [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", + [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", +}; + +static const struct adis_data adis16400_data = { + .msc_ctrl_reg = ADIS16400_MSC_CTRL, + .glob_cmd_reg = ADIS16400_GLOB_CMD, + .diag_stat_reg = ADIS16400_DIAG_STAT, + + .read_delay = 50, + .write_delay = 50, + + .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, + .startup_delay = ADIS16400_STARTUP_DELAY, + + .status_error_msgs = adis16400_status_error_msgs, + .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | + BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | + BIT(ADIS16400_DIAG_STAT_ALARM2) | + BIT(ADIS16400_DIAG_STAT_ALARM1) | + BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | + BIT(ADIS16400_DIAG_STAT_SELF_TEST) | + BIT(ADIS16400_DIAG_STAT_OVERFLOW) | + BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | + BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | + BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | + BIT(ADIS16400_DIAG_STAT_POWER_LOW), +}; + +static int adis16400_probe(struct spi_device *spi) +{ + struct adis16400_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + /* this is only used for removal purposes */ + spi_set_drvdata(spi, indio_dev); + + /* 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; + indio_dev->modes = INDIO_DIRECT_MODE; + + if (!(st->variant->flags & ADIS16400_NO_BURST)) + indio_dev->available_scan_masks = adis16400_burst_scan_mask; + + ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); + if (ret) + goto error_free_dev; + + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, + adis16400_trigger_handler); + if (ret) + goto error_free_dev; + + /* Get the device into a sane initial state */ + ret = adis16400_initial_setup(indio_dev); + if (ret) + goto error_cleanup_buffer; + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer; + + return 0; + +error_cleanup_buffer: + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); +error_free_dev: + iio_device_free(indio_dev); + return ret; +} + +static int adis16400_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis16400_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis16400_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 adis16400_id[] = { + {"adis16300", ADIS16300}, + {"adis16334", ADIS16334}, + {"adis16350", ADIS16350}, + {"adis16354", ADIS16350}, + {"adis16355", ADIS16350}, + {"adis16360", ADIS16360}, + {"adis16362", ADIS16362}, + {"adis16364", ADIS16364}, + {"adis16365", ADIS16360}, + {"adis16400", ADIS16400}, + {"adis16405", ADIS16400}, + {} +}; +MODULE_DEVICE_TABLE(spi, adis16400_id); + +static struct spi_driver adis16400_driver = { + .driver = { + .name = "adis16400", + .owner = THIS_MODULE, + }, + .id_table = adis16400_id, + .probe = adis16400_probe, + .remove = adis16400_remove, +}; +module_spi_driver(adis16400_driver); + +MODULE_AUTHOR("Manuel Stahl "); +MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index ca56c75..94d60d5 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -32,7 +32,6 @@ source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/imu/Kconfig" source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/meter/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index fa6937d..468b7f8 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -20,7 +20,6 @@ obj-y += cdc/ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ -obj-y += imu/ obj-y += light/ obj-y += magnetometer/ obj-y += meter/ diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig deleted file mode 100644 index 096afc8..0000000 --- a/drivers/staging/iio/imu/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# IIO imu drivers configuration -# -menu "Inertial measurement units" - -config ADIS16400 - tristate "Analog Devices ADIS16400 and similar IMU SPI 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 adis16300, adis16344, - adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, - adis16365, adis16400 and adis16405 triaxial inertial sensors - (adis16400 series also have magnetometers). - -endmenu diff --git a/drivers/staging/iio/imu/Makefile b/drivers/staging/iio/imu/Makefile deleted file mode 100644 index c9988f6..0000000 --- a/drivers/staging/iio/imu/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for Inertial Measurement Units -# - -adis16400-y := adis16400_core.o -adis16400-$(CONFIG_IIO_BUFFER) += adis16400_ring.o -obj-$(CONFIG_ADIS16400) += adis16400.o diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h deleted file mode 100644 index a3b9e56..0000000 --- a/drivers/staging/iio/imu/adis16400.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * adis16400.h support Analog Devices ADIS16400 - * 3d 18g accelerometers, - * 3d gyroscopes, - * 3d 2.5gauss magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl - * Copyright (c) 2007 Jonathan Cameron - * - * 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_ - -#include - -#define ADIS16400_STARTUP_DELAY 290 /* ms */ -#define ADIS16400_MTEST_DELAY 90 /* ms */ - -#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 0x14 /* Y axis inclinometer output measurement */ -#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC 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 15 -#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 -#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 -#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 -#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 -#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 -#define ADIS16400_DIAG_STAT_ALARM2 9 -#define ADIS16400_DIAG_STAT_ALARM1 8 -#define ADIS16400_DIAG_STAT_FLASH_CHK 6 -#define ADIS16400_DIAG_STAT_SELF_TEST 5 -#define ADIS16400_DIAG_STAT_OVERFLOW 4 -#define ADIS16400_DIAG_STAT_SPI_FAIL 3 -#define ADIS16400_DIAG_STAT_FLASH_UPT 2 -#define ADIS16400_DIAG_STAT_POWER_HIGH 1 -#define ADIS16400_DIAG_STAT_POWER_LOW 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 ADIS16334_RATE_DIV_SHIFT 8 -#define ADIS16334_RATE_INT_CLK BIT(0) - -#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 BIT(0) -#define ADIS16400_NO_BURST BIT(1) -#define ADIS16400_HAS_SLOW_MODE BIT(2) - -struct adis16400_state; - -struct adis16400_chip_info { - const struct iio_chan_spec *channels; - const int num_channels; - const long flags; - unsigned int gyro_scale_micro; - unsigned int accel_scale_micro; - int temp_scale_nano; - int temp_offset; - int (*set_freq)(struct adis16400_state *st, unsigned int freq); - int (*get_freq)(struct adis16400_state *st); -}; - -/** - * struct adis16400_state - device instance specific data - * @variant: chip variant info - * @filt_int: integer part of requested filter frequency - * @adis: adis device - **/ -struct adis16400_state { - struct adis16400_chip_info *variant; - int filt_int; - - struct adis adis; -}; - -/* At the moment triggers are only used for ring buffer - * filling. This may change! - */ - -enum { - ADIS16400_SCAN_SUPPLY, - ADIS16400_SCAN_GYRO_X, - ADIS16400_SCAN_GYRO_Y, - ADIS16400_SCAN_GYRO_Z, - ADIS16400_SCAN_ACC_X, - ADIS16400_SCAN_ACC_Y, - ADIS16400_SCAN_ACC_Z, - ADIS16400_SCAN_MAGN_X, - ADIS16400_SCAN_MAGN_Y, - ADIS16400_SCAN_MAGN_Z, - ADIS16350_SCAN_TEMP_X, - ADIS16350_SCAN_TEMP_Y, - ADIS16350_SCAN_TEMP_Z, - ADIS16300_SCAN_INCLI_X, - ADIS16300_SCAN_INCLI_Y, - ADIS16400_SCAN_ADC, -}; - -#ifdef CONFIG_IIO_BUFFER - -ssize_t adis16400_read_data_from_ring(struct device *dev, - struct device_attribute *attr, - char *buf); - - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask); -irqreturn_t adis16400_trigger_handler(int irq, void *p); - -#else /* CONFIG_IIO_BUFFER */ - -#define adis16400_update_scan_mode NULL -#define adis16400_trigger_handler NULL - -#endif /* CONFIG_IIO_BUFFER */ - -#endif /* SPI_ADIS16400_H_ */ diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c deleted file mode 100644 index 1bbe5ee..0000000 --- a/drivers/staging/iio/imu/adis16400_core.c +++ /dev/null @@ -1,812 +0,0 @@ -/* - * adis16400.c support Analog Devices ADIS16400/5 - * 3d 2g Linear Accelerometers, - * 3d Gyroscopes, - * 3d Magnetometers via SPI - * - * Copyright (c) 2009 Manuel Stahl - * Copyright (c) 2007 Jonathan Cameron - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "adis16400.h" - -enum adis16400_chip_variant { - ADIS16300, - ADIS16334, - ADIS16350, - ADIS16360, - ADIS16362, - ADIS16364, - ADIS16400, -}; - -static int adis16334_get_freq(struct adis16400_state *st) -{ - int ret; - uint16_t t; - - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); - if (ret < 0) - return ret; - - t >>= ADIS16334_RATE_DIV_SHIFT; - - return (8192 >> t) / 10; -} - -static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) -{ - unsigned int t; - - freq *= 10; - if (freq < 8192) - t = ilog2(8192 / freq); - else - t = 0; - - if (t > 0x31) - t = 0x31; - - t <<= ADIS16334_RATE_DIV_SHIFT; - t |= ADIS16334_RATE_INT_CLK; - - return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); -} - -static int adis16400_get_freq(struct adis16400_state *st) -{ - int sps, ret; - uint16_t t; - - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); - if (ret < 0) - return ret; - - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; - sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; - - return sps; -} - -static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) -{ - unsigned int t; - - t = 1638 / freq; - if (t > 0) - t--; - t &= ADIS16400_SMPL_PRD_DIV_MASK; - - if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; - else - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - - return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); -} - -static ssize_t adis16400_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - - ret = st->variant->get_freq(st); - if (ret < 0) - return ret; - - return sprintf(buf, "%d\n", ret); -} - -static const unsigned adis16400_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 adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) -{ - struct adis16400_state *st = iio_priv(indio_dev); - uint16_t val16; - int i, ret; - - for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { - if (sps / adis16400_3db_divisors[i] >= val) - break; - } - - ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); - if (ret < 0) - return ret; - - ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, - (val16 & ~0x07) | i); - return ret; -} - -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_to_iio_dev(dev); - struct adis16400_state *st = iio_priv(indio_dev); - long val; - int ret; - - ret = kstrtol(buf, 10, &val); - if (ret) - return ret; - - if (val == 0) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - st->variant->set_freq(st, val); - mutex_unlock(&indio_dev->mlock); - - return ret ? ret : len; -} - -/* Power down the device */ -static int adis16400_stop_device(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - int ret; - - ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, - ADIS16400_SLP_CNT_POWER_OFF); - if (ret) - dev_err(&indio_dev->dev, - "problem with turning device off: SLP_CNT"); - - return ret; -} - -static int adis16400_initial_setup(struct iio_dev *indio_dev) -{ - struct adis16400_state *st = iio_priv(indio_dev); - uint16_t prod_id, smp_prd; - unsigned int device_id; - int ret; - - /* use low spi speed for init if the device has a slow mode */ - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; - else - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - st->adis.spi->mode = SPI_MODE_3; - spi_setup(st->adis.spi); - - ret = adis_initial_startup(&st->adis); - if (ret) - return ret; - - if (st->variant->flags & ADIS16400_HAS_PROD_ID) { - ret = adis_read_reg_16(&st->adis, - ADIS16400_PRODUCT_ID, &prod_id); - if (ret) - goto err_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); - - dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", - indio_dev->name, prod_id, - st->adis.spi->chip_select, st->adis.spi->irq); - } - /* use high spi speed if possible */ - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); - if (ret) - goto err_ret; - - if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; - spi_setup(st->adis.spi); - } - } - -err_ret: - return ret; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - adis16400_read_frequency, - adis16400_write_frequency); - -static const uint8_t adis16400_addresses[] = { - [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, - [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, - [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, - [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, - [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, - [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, -}; - -static int adis16400_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, long info) -{ - struct adis16400_state *st = iio_priv(indio_dev); - int ret, sps; - - switch (info) { - case IIO_CHAN_INFO_CALIBBIAS: - mutex_lock(&indio_dev->mlock); - ret = adis_write_reg_16(&st->adis, - adis16400_addresses[chan->scan_index], val); - mutex_unlock(&indio_dev->mlock); - return ret; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - /* - * Need to cache values so we can update if the frequency - * changes. - */ - mutex_lock(&indio_dev->mlock); - st->filt_int = val; - /* Work out update to current value */ - sps = st->variant->get_freq(st); - if (sps < 0) { - mutex_unlock(&indio_dev->mlock); - return sps; - } - - ret = adis16400_set_filter(indio_dev, sps, 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 info) -{ - struct adis16400_state *st = iio_priv(indio_dev); - int16_t val16; - 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 = 0; - *val2 = st->variant->gyro_scale_micro; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_VOLTAGE: - *val = 0; - if (chan->channel == 0) { - *val = 2; - *val2 = 418000; /* 2.418 mV */ - } else { - *val = 0; - *val2 = 805800; /* 805.8 uV */ - } - 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; /* 0.5 mgauss */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = st->variant->temp_scale_nano / 1000000; - *val2 = (st->variant->temp_scale_nano % 1000000); - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_CALIBBIAS: - mutex_lock(&indio_dev->mlock); - ret = adis_read_reg_16(&st->adis, - adis16400_addresses[chan->scan_index], &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 = st->variant->temp_offset; - return IIO_VAL_INT; - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: - mutex_lock(&indio_dev->mlock); - /* Need both the number of taps and the sampling frequency */ - ret = adis_read_reg_16(&st->adis, - ADIS16400_SENS_AVG, - &val16); - if (ret < 0) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - ret = st->variant->get_freq(st); - if (ret >= 0) - *val = ret / adis16400_3db_divisors[val16 & 0x07]; - *val2 = 0; - mutex_unlock(&indio_dev->mlock); - if (ret < 0) - return ret; - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } -} - -#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = 0, \ - .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, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_SUPPLY_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) - -#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ - ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) - -#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ - .type = IIO_ANGL_VEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .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_SHARED_BIT, \ - .address = addr, \ - .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .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_SHARED_BIT, \ - .address = (addr), \ - .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ - .type = IIO_MAGN, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ - .address = (addr), \ - .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_MOD_TEMP_NAME_X "x" -#define ADIS16400_MOD_TEMP_NAME_Y "y" -#define ADIS16400_MOD_TEMP_NAME_Z "z" - -#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ - .type = IIO_TEMP, \ - .indexed = 1, \ - .channel = 0, \ - .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ - .address = (addr), \ - .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_TEMP_CHAN(addr, bits) { \ - .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 = (addr), \ - .scan_index = ADIS16350_SCAN_TEMP_X, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ - .type = IIO_INCLI, \ - .modified = 1, \ - .channel2 = IIO_MOD_ ## mod, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT, \ - .address = (addr), \ - .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 0, \ - .endianness = IIO_BE, \ - }, \ -} - -static const struct iio_chan_spec adis16400_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), - ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), - IIO_CHAN_SOFT_TIMESTAMP(12) -}; - -static const struct iio_chan_spec adis16350_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), - ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), - ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), - ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) -}; - -static const struct iio_chan_spec adis16300_channels[] = { - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), - ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), - ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), - IIO_CHAN_SOFT_TIMESTAMP(14) -}; - -static const struct iio_chan_spec adis16334_channels[] = { - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(8) -}; - -static struct attribute *adis16400_attributes[] = { - &iio_dev_attr_sampling_frequency.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), - .flags = ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = 5884, - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16334] = { - .channels = adis16334_channels, - .num_channels = ARRAY_SIZE(adis16334_channels), - .flags = ADIS16400_HAS_PROD_ID, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 67850000, /* 0.06785 C */ - .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ - .set_freq = adis16334_set_freq, - .get_freq = adis16334_get_freq, - }, - [ADIS16350] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ - .temp_scale_nano = 145300000, /* 0.1453 C */ - .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ - .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16360] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16362] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16364] = { - .channels = adis16350_channels, - .num_channels = ARRAY_SIZE(adis16350_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ - .temp_scale_nano = 136000000, /* 0.136 C */ - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - }, - [ADIS16400] = { - .channels = adis16400_channels, - .num_channels = ARRAY_SIZE(adis16400_channels), - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ - .temp_scale_nano = 140000000, /* 0.14 C */ - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ - .set_freq = adis16400_set_freq, - .get_freq = adis16400_get_freq, - } -}; - -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, - .update_scan_mode = adis16400_update_scan_mode, -}; - -static const unsigned long adis16400_burst_scan_mask[] = { - ~0UL, - 0, -}; - -static const char * const adis16400_status_error_msgs[] = { - [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", - [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", - [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", - [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", - [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", - [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", - [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", - [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", - [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", - [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", - [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", -}; - -static const struct adis_data adis16400_data = { - .msc_ctrl_reg = ADIS16400_MSC_CTRL, - .glob_cmd_reg = ADIS16400_GLOB_CMD, - .diag_stat_reg = ADIS16400_DIAG_STAT, - - .read_delay = 50, - .write_delay = 50, - - .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, - .startup_delay = ADIS16400_STARTUP_DELAY, - - .status_error_msgs = adis16400_status_error_msgs, - .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | - BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | - BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | - BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | - BIT(ADIS16400_DIAG_STAT_ALARM2) | - BIT(ADIS16400_DIAG_STAT_ALARM1) | - BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | - BIT(ADIS16400_DIAG_STAT_SELF_TEST) | - BIT(ADIS16400_DIAG_STAT_OVERFLOW) | - BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | - BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | - BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | - BIT(ADIS16400_DIAG_STAT_POWER_LOW), -}; - -static int adis16400_probe(struct spi_device *spi) -{ - struct adis16400_state *st; - struct iio_dev *indio_dev; - int ret; - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - /* 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; - indio_dev->modes = INDIO_DIRECT_MODE; - - if (!(st->variant->flags & ADIS16400_NO_BURST)) - indio_dev->available_scan_masks = adis16400_burst_scan_mask; - - ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); - if (ret) - goto error_free_dev; - - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, - adis16400_trigger_handler); - if (ret) - goto error_free_dev; - - /* Get the device into a sane initial state */ - ret = adis16400_initial_setup(indio_dev); - if (ret) - goto error_cleanup_buffer; - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_buffer; - - return 0; - -error_cleanup_buffer: - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); -error_free_dev: - iio_device_free(indio_dev); - return ret; -} - -static int adis16400_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis16400_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis16400_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 adis16400_id[] = { - {"adis16300", ADIS16300}, - {"adis16334", ADIS16334}, - {"adis16350", ADIS16350}, - {"adis16354", ADIS16350}, - {"adis16355", ADIS16350}, - {"adis16360", ADIS16360}, - {"adis16362", ADIS16362}, - {"adis16364", ADIS16364}, - {"adis16365", ADIS16360}, - {"adis16400", ADIS16400}, - {"adis16405", ADIS16400}, - {} -}; -MODULE_DEVICE_TABLE(spi, adis16400_id); - -static struct spi_driver adis16400_driver = { - .driver = { - .name = "adis16400", - .owner = THIS_MODULE, - }, - .id_table = adis16400_id, - .probe = adis16400_probe, - .remove = adis16400_remove, -}; -module_spi_driver(adis16400_driver); - -MODULE_AUTHOR("Manuel Stahl "); -MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c deleted file mode 100644 index 054c01d..0000000 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "adis16400.h" - -int adis16400_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - uint16_t *tx, *rx; - - if (st->variant->flags & ADIS16400_NO_BURST) - return adis_update_scan_mode(indio_dev, scan_mask); - - kfree(adis->xfer); - kfree(adis->buffer); - - adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); - if (!adis->xfer) - return -ENOMEM; - - adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), - GFP_KERNEL); - if (!adis->buffer) - return -ENOMEM; - - rx = adis->buffer; - tx = adis->buffer + indio_dev->scan_bytes; - - tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); - tx[1] = 0; - - adis->xfer[0].tx_buf = tx; - adis->xfer[0].bits_per_word = 8; - adis->xfer[0].len = 2; - adis->xfer[1].tx_buf = tx; - adis->xfer[1].bits_per_word = 8; - adis->xfer[1].len = indio_dev->scan_bytes; - - spi_message_init(&adis->msg); - spi_message_add_tail(&adis->xfer[0], &adis->msg); - spi_message_add_tail(&adis->xfer[1], &adis->msg); - - return 0; -} - -irqreturn_t adis16400_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct adis16400_state *st = iio_priv(indio_dev); - struct adis *adis = &st->adis; - u32 old_speed_hz = st->adis.spi->max_speed_hz; - int ret; - - if (!adis->buffer) - return -ENOMEM; - - if (!(st->variant->flags & ADIS16400_NO_BURST) && - st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { - st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; - spi_setup(st->adis.spi); - } - - ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); - - if (!(st->variant->flags & ADIS16400_NO_BURST)) { - st->adis.spi->max_speed_hz = old_speed_hz; - spi_setup(st->adis.spi); - } - - /* 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; -} -- cgit v0.10.2