adis16240_core.c revision 6835cb6b438b77ba82ad5a23944bbfb12128f5db
12c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/*
22c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * ADIS16240 Programmable Impact Sensor and Recorder driver
32c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *
42c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * Copyright 2010 Analog Devices Inc.
52c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *
62c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * Licensed under the GPL-2 or later.
72c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song */
82c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
92c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/interrupt.h>
102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/irq.h>
112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/gpio.h>
122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/delay.h>
132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/mutex.h>
142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/device.h>
152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/kernel.h>
162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/spi/spi.h>
171cb6c1f59431f16e46f0d07398cc789ee0a26731Mike Frysinger#include <linux/slab.h>
182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/sysfs.h>
192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include <linux/list.h>
2099c978529a40132a6f7a5f136b4362b56fc88d8cPaul Gortmaker#include <linux/module.h>
212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "../iio.h"
232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "../sysfs.h"
243811cd6291bb5a11c8d830831149d6369e7d3b68Jonathan Cameron#include "../buffer_generic.h"
252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "adis16240.h"
272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#define DRIVER_NAME		"adis16240"
292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
30cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_check_status(struct iio_dev *indio_dev);
312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_write_reg_8() - write single byte to a register
34cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron * @indio_dev: iio_dev associated with device
352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the register to be written
362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: the value to write
372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
38cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_spi_write_reg_8(struct iio_dev *indio_dev,
39cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				     u8 reg_address,
40cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				     u8 val)
412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
43a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct adis16240_state *st = iio_priv(indio_dev);
442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_WRITE_REG(reg_address);
472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = val;
482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_write(st->us, st->tx, 2);
502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_write_reg_16() - write 2 bytes to a pair of registers
57cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron * @indio_dev: iio_dev for this device
582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the lower of the two registers. Second register
592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *               is assumed to have address one greater.
602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: value to be written
612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
62cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_spi_write_reg_16(struct iio_dev *indio_dev,
63cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				      u8 lower_reg_address,
64cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				      u16 value)
652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_message msg;
68a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct adis16240_state *st = iio_priv(indio_dev);
692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_transfer xfers[] = {
702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		{
712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx,
722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
7500ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}, {
772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx + 2,
782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
8000ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		},
822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	};
832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_WRITE_REG(lower_reg_address);
862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = value & 0xFF;
872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[2] = ADIS16240_WRITE_REG(lower_reg_address + 1);
882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[3] = (value >> 8) & 0xFF;
892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_init(&msg);
912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[0], &msg);
922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[1], &msg);
932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_sync(st->us, &msg);
942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
1002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_read_reg_16() - read 2 bytes from a 16-bit register
101cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron * @indio_dev: iio_dev for this device
1022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the lower of the two registers. Second register
1032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *               is assumed to have address one greater.
1042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: somewhere to pass back the value read
1052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
106cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_spi_read_reg_16(struct iio_dev *indio_dev,
1072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u8 lower_reg_address,
1082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u16 *val)
1092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_message msg;
111a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct adis16240_state *st = iio_priv(indio_dev);
1122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
1132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_transfer xfers[] = {
1142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		{
1152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx,
1162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
1172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
1182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
11900ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
1202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}, {
1212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.rx_buf = st->rx,
1222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
1232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
1242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
12500ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
1262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		},
1272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	};
1282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
1302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_READ_REG(lower_reg_address);
1312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = 0;
1322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[2] = 0;
1332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[3] = 0;
1342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_init(&msg);
1362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[0], &msg);
1372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[1], &msg);
1382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_sync(st->us, &msg);
1392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
1402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(&st->us->dev,
1412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			"problem when reading 16 bit register 0x%02X",
1422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			lower_reg_address);
1432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
1442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
1452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	*val = (st->rx[0] << 8) | st->rx[1];
1462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
1482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
1492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
1502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_spi_read_signed(struct device *dev,
1532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
1542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf,
1552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		unsigned bits)
1562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
157cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
1582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
1592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	s16 val = 0;
1602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	unsigned shift = 16 - bits;
1612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
1622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
163cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_read_reg_16(indio_dev,
164cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron					this_attr->address, (u16 *)&val);
1652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
1662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return ret;
1672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (val & ADIS16240_ERROR_ACTIVE)
169cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		adis16240_check_status(indio_dev);
1702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	val = ((s16)(val << shift) >> shift);
1722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return sprintf(buf, "%d\n", val);
1732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_read_12bit_signed(struct device *dev,
1762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
1772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf)
1782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ssize_t ret;
180cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
1812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Take the iio_dev status lock */
1832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&indio_dev->mlock);
1842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret =  adis16240_spi_read_signed(dev, attr, buf, 12);
1852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&indio_dev->mlock);
1862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
1882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
190cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_reset(struct iio_dev *indio_dev)
1912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
193cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_write_reg_8(indio_dev,
1942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_GLOB_CMD,
1952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_GLOB_CMD_SW_RESET);
1962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
197cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		dev_err(&indio_dev->dev, "problem resetting device");
1982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_write_reset(struct device *dev,
2032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
2042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		const char *buf, size_t len)
2052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
206cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	struct iio_dev *indio_dev = dev_get_drvdata(dev);
207cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
2082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (len < 1)
2092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return -EINVAL;
2102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	switch (buf[0]) {
2112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case '1':
2122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case 'y':
2132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case 'Y':
214cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return adis16240_reset(indio_dev);
2152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
2162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return -EINVAL;
2172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
219cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronint adis16240_set_irq(struct iio_dev *indio_dev, bool enable)
2202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret = 0;
2222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	u16 msc;
2232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
224cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_read_reg_16(indio_dev,
225cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron					ADIS16240_MSC_CTRL, &msc);
2262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
2272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
2282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msc |= ADIS16240_MSC_CTRL_ACTIVE_HIGH;
2302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_DIO2;
2312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (enable)
2322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msc |= ADIS16240_MSC_CTRL_DATA_RDY_EN;
2332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	else
2342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_EN;
2352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
236cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_write_reg_16(indio_dev,
237cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron					 ADIS16240_MSC_CTRL, msc);
2382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
2402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
243cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_self_test(struct iio_dev *indio_dev)
2442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
246cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_write_reg_16(indio_dev,
2472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_MSC_CTRL,
2482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_MSC_CTRL_SELF_TEST_EN);
2492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
250cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		dev_err(&indio_dev->dev, "problem starting self test");
2512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
2522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
2532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msleep(ADIS16240_STARTUP_DELAY);
2552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
256cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	adis16240_check_status(indio_dev);
2572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerr_ret:
2592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
262cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_check_status(struct iio_dev *indio_dev)
2632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	u16 status;
2652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
266cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	struct device *dev = &indio_dev->dev;
2672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
268cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_spi_read_reg_16(indio_dev,
269cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron					ADIS16240_DIAG_STAT, &status);
2702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret < 0) {
2722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Reading status failed\n");
2732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
2742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
2752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = status & 0x2F;
2772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_PWRON_FAIL)
2782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power-on, self-test fail\n");
2792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_SPI_FAIL)
2802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "SPI failure\n");
2812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_FLASH_UPT)
2822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Flash update failed\n");
2832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_POWER_HIGH)
2842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power supply above 3.625V\n");
2852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_POWER_LOW)
2862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power supply below 2.225V\n");
2872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
2892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
292cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_initial_setup(struct iio_dev *indio_dev)
2932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
295cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	struct device *dev = &indio_dev->dev;
2962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Disable IRQ */
298cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_set_irq(indio_dev, false);
2992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "disable irq failed");
3012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
3022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Do self test */
305cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_self_test(indio_dev);
3062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "self test failure");
3082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
3092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Read status register to check the result */
312cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	ret = adis16240_check_status(indio_dev);
3132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
314cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		adis16240_reset(indio_dev);
3152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "device not playing ball -> reset");
3162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msleep(ADIS16240_STARTUP_DELAY);
317cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		ret = adis16240_check_status(indio_dev);
3182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		if (ret) {
3192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			dev_err(dev, "giving up");
3202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			goto err_ret;
3212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}
3222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerr_ret:
3252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
3262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
3272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
328322c95636739420631e51f3d3f24132dc220762aJonathan Cameronstatic IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, S_IRUGO,
3292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       adis16240_read_12bit_signed, NULL,
3302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       ADIS16240_XYZPEAK_OUT);
3312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16240_write_reset, 0);
3332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
33451a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096");
3352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
336cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronenum adis16240_chan {
337cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	in_supply,
338cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	in_aux,
339cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	accel_x,
340cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	accel_y,
341cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	accel_z,
342cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	temp,
343cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron};
344cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
345cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic const u8 adis16240_addresses[6][3] = {
346cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[in_supply] = { ADIS16240_SUPPLY_OUT },
347cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[in_aux] = { ADIS16240_AUX_ADC },
348cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[accel_x] = { ADIS16240_XACCL_OUT, ADIS16240_XACCL_OFF,
349cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		      ADIS16240_XPEAK_OUT },
350cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[accel_y] = { ADIS16240_YACCL_OUT, ADIS16240_YACCL_OFF,
351cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		      ADIS16240_YPEAK_OUT },
352cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[accel_z] = { ADIS16240_ZACCL_OUT, ADIS16240_ZACCL_OFF,
353cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		      ADIS16240_ZPEAK_OUT },
354cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	[temp] = { ADIS16240_TEMP_OUT },
355cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron};
356cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
357cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_read_raw(struct iio_dev *indio_dev,
358cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			      struct iio_chan_spec const *chan,
359cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			      int *val, int *val2,
360cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			      long mask)
361cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron{
362cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	int ret;
363cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	int bits;
364cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	u8 addr;
365cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	s16 val16;
366cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
367cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	switch (mask) {
368cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case 0:
369cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_lock(&indio_dev->mlock);
370cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		addr = adis16240_addresses[chan->address][0];
371cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
3728f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter		if (ret) {
3738f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter			mutex_unlock(&indio_dev->mlock);
374cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return ret;
3758f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter		}
376cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
377cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		if (val16 & ADIS16240_ERROR_ACTIVE) {
378cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			ret = adis16240_check_status(indio_dev);
3798f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter			if (ret) {
3808f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter				mutex_unlock(&indio_dev->mlock);
381cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				return ret;
3828f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter			}
383cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		}
384cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
385cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		if (chan->scan_type.sign == 's')
386cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			val16 = (s16)(val16 <<
387cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				      (16 - chan->scan_type.realbits)) >>
388cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				(16 - chan->scan_type.realbits);
389cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val = val16;
390cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_unlock(&indio_dev->mlock);
391cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return IIO_VAL_INT;
392cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_SCALE_SEPARATE):
393cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_SCALE_SHARED):
394cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		switch (chan->type) {
3956835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron		case IIO_VOLTAGE:
396cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			*val = 0;
397cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			if (chan->channel == 0)
398cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				*val2 = 4880;
399cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			else
400cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron				return -EINVAL;
401cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return IIO_VAL_INT_PLUS_MICRO;
402cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		case IIO_TEMP:
403cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			*val = 0;
404cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			*val2 = 244000;
405cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return IIO_VAL_INT_PLUS_MICRO;
406cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		case IIO_ACCEL:
407cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			*val = 0;
408cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			*val2 = 504062;
409cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return IIO_VAL_INT_PLUS_MICRO;
410cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		default:
411cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return -EINVAL;
412cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		}
413cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		break;
414cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_PEAK_SCALE_SHARED):
415cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val = 6;
416cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val2 = 629295;
417cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return IIO_VAL_INT_PLUS_MICRO;
418cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE):
419cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val = 25;
420cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return IIO_VAL_INT;
421cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE):
422cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		bits = 10;
423cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_lock(&indio_dev->mlock);
424cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		addr = adis16240_addresses[chan->address][1];
425cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
426cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		if (ret) {
427cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			mutex_unlock(&indio_dev->mlock);
428cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return ret;
429cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		}
430cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 &= (1 << bits) - 1;
431cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
432cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val = val16;
433cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_unlock(&indio_dev->mlock);
434cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return IIO_VAL_INT;
435cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_PEAK_SEPARATE):
436cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		bits = 10;
437cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_lock(&indio_dev->mlock);
438cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		addr = adis16240_addresses[chan->address][2];
439cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
440cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		if (ret) {
441cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			mutex_unlock(&indio_dev->mlock);
442cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			return ret;
443cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		}
444cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 &= (1 << bits) - 1;
445cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
446cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		*val = val16;
447cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		mutex_unlock(&indio_dev->mlock);
448cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return IIO_VAL_INT;
449cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	}
450cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	return -EINVAL;
451cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron}
452cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
453cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_write_raw(struct iio_dev *indio_dev,
454cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			       struct iio_chan_spec const *chan,
455cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			       int val,
456cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			       int val2,
457cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron			       long mask)
458cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron{
459cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	int bits = 10;
460cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	s16 val16;
461cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	u8 addr;
462cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	switch (mask) {
463cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE):
464cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		val16 = val & ((1 << bits) - 1);
465cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		addr = adis16240_addresses[chan->address][1];
466cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		return adis16240_spi_write_reg_16(indio_dev, addr, val16);
467cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	}
468cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	return -EINVAL;
469cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron}
470cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
471cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic struct iio_chan_spec adis16240_channels[] = {
4726835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
473cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_SCALE_SEPARATE),
474cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 in_supply, ADIS16240_SCAN_SUPPLY,
475cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('u', 10, 16, 0), 0),
4766835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron	IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
477cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 0,
478cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 in_aux, ADIS16240_SCAN_AUX_ADC,
479cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('u', 10, 16, 0), 0),
480cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
481cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_SCALE_SHARED) |
482cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE),
483cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 accel_x, ADIS16240_SCAN_ACC_X,
484cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('s', 10, 16, 0), 0),
485cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
486cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_SCALE_SHARED) |
487cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE),
488cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 accel_y, ADIS16240_SCAN_ACC_Y,
489cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('s', 10, 16, 0), 0),
490cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z,
491cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_SCALE_SHARED) |
492cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE),
493cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 accel_z, ADIS16240_SCAN_ACC_Z,
494cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('s', 10, 16, 0), 0),
495cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
496cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 (1 << IIO_CHAN_INFO_SCALE_SEPARATE),
497cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 temp, ADIS16240_SCAN_TEMP,
498cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron		 IIO_ST('u', 10, 16, 0), 0),
499cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron	IIO_CHAN_SOFT_TIMESTAMP(6)
500cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron};
501cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron
5022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct attribute *adis16240_attributes[] = {
503322c95636739420631e51f3d3f24132dc220762aJonathan Cameron	&iio_dev_attr_in_accel_xyz_squared_peak_raw.dev_attr.attr,
50451a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
5052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_reset.dev_attr.attr,
5062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	NULL
5072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
5082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic const struct attribute_group adis16240_attribute_group = {
5102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.attrs = adis16240_attributes,
5112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
5122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5136fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameronstatic const struct iio_info adis16240_info = {
5146fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.attrs = &adis16240_attribute_group,
5156fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.read_raw = &adis16240_read_raw,
5166fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.write_raw = &adis16240_write_raw,
5176fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron	.driver_module = THIS_MODULE,
5186fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron};
5196fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron
5202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int __devinit adis16240_probe(struct spi_device *spi)
5212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
52226d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron	int ret;
523a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct adis16240_state *st;
524a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct iio_dev *indio_dev;
525a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron
526a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	/* setup the industrialio driver allocated elements */
527a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev = iio_allocate_device(sizeof(*st));
528a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	if (indio_dev == NULL) {
529a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron		ret = -ENOMEM;
5302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
5312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
532a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	st = iio_priv(indio_dev);
5332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* this is only used for removal purposes */
534a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	spi_set_drvdata(spi, indio_dev);
5352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->us = spi;
5372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_init(&st->buf_lock);
5382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
539a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->name = spi->dev.driver->name;
540a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->dev.parent = &spi->dev;
541a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->info = &adis16240_info;
542a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->channels = adis16240_channels;
543a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->num_channels = ARRAY_SIZE(adis16240_channels);
544a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	indio_dev->modes = INDIO_DIRECT_MODE;
5452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
546a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	ret = adis16240_configure_ring(indio_dev);
5472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
5482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_free_dev;
5492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
55014555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron	ret = iio_buffer_register(indio_dev,
55114555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron				  adis16240_channels,
55214555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron				  ARRAY_SIZE(adis16240_channels));
5532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
5542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		printk(KERN_ERR "failed to initialize the ring\n");
5552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_unreg_ring_funcs;
5562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
5572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (spi->irq) {
559a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron		ret = adis16240_probe_trigger(indio_dev);
5602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		if (ret)
561bdd560c52b023cd23b6b082ca64c062cacc23e3fJonathan Cameron			goto error_uninitialize_ring;
5622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
5632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Get the device into a sane initial state */
565a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	ret = adis16240_initial_setup(indio_dev);
5662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
5672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_remove_trigger;
56826d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron	ret = iio_device_register(indio_dev);
56926d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron	if (ret)
57026d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron		goto error_remove_trigger;
5712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return 0;
5722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_remove_trigger:
574a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	adis16240_remove_trigger(indio_dev);
5752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_uninitialize_ring:
57614555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron	iio_buffer_unregister(indio_dev);
5772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_unreg_ring_funcs:
578a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	adis16240_unconfigure_ring(indio_dev);
5792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_dev:
58026d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron	iio_free_device(indio_dev);
5812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
5822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
5832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_remove(struct spi_device *spi)
5862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
587a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron
588a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron	struct iio_dev *indio_dev = spi_get_drvdata(spi);
5892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	flush_scheduled_work();
5912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_remove_trigger(indio_dev);
59314555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron	iio_buffer_unregister(indio_dev);
5942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_unconfigure_ring(indio_dev);
5953e39440789adef103422ce201538b4da8745fe8eJonathan Cameron	iio_device_unregister(indio_dev);
5962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return 0;
5982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
6002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct spi_driver adis16240_driver = {
6012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.driver = {
6022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		.name = "adis16240",
6032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		.owner = THIS_MODULE,
6042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	},
6052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.probe = adis16240_probe,
6062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.remove = __devexit_p(adis16240_remove),
6072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
6082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
6092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic __init int adis16240_init(void)
6102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
6112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return spi_register_driver(&adis16240_driver);
6122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
6132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songmodule_init(adis16240_init);
6142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
6152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic __exit void adis16240_exit(void)
6162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
6172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_unregister_driver(&adis16240_driver);
6182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
6192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songmodule_exit(adis16240_exit);
6202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
6212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
6222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder");
6232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_LICENSE("GPL v2");
624