adis16240_core.c revision 51a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4
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>
202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "../iio.h"
222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "../sysfs.h"
232662051e0868d1bde0abeea19bd54c3c18941afcJonathan Cameron#include "../ring_generic.h"
242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "accel.h"
252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "../adc/adc.h"
262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#include "adis16240.h"
282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song#define DRIVER_NAME		"adis16240"
302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_check_status(struct device *dev);
322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_write_reg_8() - write single byte to a register
352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @dev: device associated with child of actual device (iio_dev or iio_trig)
362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the register to be written
372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: the value to write
382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_spi_write_reg_8(struct device *dev,
402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u8 reg_address,
412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u8 val)
422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = dev_get_drvdata(dev);
452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct adis16240_state *st = iio_dev_get_devdata(indio_dev);
462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_WRITE_REG(reg_address);
492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = val;
502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_write(st->us, st->tx, 2);
522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_write_reg_16() - write 2 bytes to a pair of registers
592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @dev: device associated with child of actual device (iio_dev or iio_trig)
602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the lower of the two registers. Second register
612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *               is assumed to have address one greater.
622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: value to be written
632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_spi_write_reg_16(struct device *dev,
652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u8 lower_reg_address,
662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u16 value)
672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_message msg;
702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = dev_get_drvdata(dev);
712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct adis16240_state *st = iio_dev_get_devdata(indio_dev);
722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_transfer xfers[] = {
732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		{
742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx,
752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
7800ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}, {
802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx + 2,
812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
8400ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		},
862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	};
872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_WRITE_REG(lower_reg_address);
902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = value & 0xFF;
912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[2] = ADIS16240_WRITE_REG(lower_reg_address + 1);
922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[3] = (value >> 8) & 0xFF;
932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_init(&msg);
952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[0], &msg);
962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[1], &msg);
972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_sync(st->us, &msg);
982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
1012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song/**
1042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * adis16240_spi_read_reg_16() - read 2 bytes from a 16-bit register
1052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @dev: device associated with child of actual device (iio_dev or iio_trig)
1062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @reg_address: the address of the lower of the two registers. Second register
1072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song *               is assumed to have address one greater.
1082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song * @val: somewhere to pass back the value read
1092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song **/
1102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_spi_read_reg_16(struct device *dev,
1112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u8 lower_reg_address,
1122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		u16 *val)
1132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_message msg;
1152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = dev_get_drvdata(dev);
1162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct adis16240_state *st = iio_dev_get_devdata(indio_dev);
1172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
1182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct spi_transfer xfers[] = {
1192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		{
1202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.tx_buf = st->tx,
1212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
1222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
1232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
12400ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
1252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}, {
1262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.rx_buf = st->rx,
1272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.bits_per_word = 8,
1282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.len = 2,
1292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			.cs_change = 1,
13000ae79463e026b8bc45c93a87aadf118f04069e0Barry Song			.delay_usecs = 35,
1312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		},
1322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	};
1332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&st->buf_lock);
1352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[0] = ADIS16240_READ_REG(lower_reg_address);
1362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[1] = 0;
1372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[2] = 0;
1382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx[3] = 0;
1392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_init(&msg);
1412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[0], &msg);
1422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_message_add_tail(&xfers[1], &msg);
1432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = spi_sync(st->us, &msg);
1442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
1452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(&st->us->dev,
1462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			"problem when reading 16 bit register 0x%02X",
1472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			lower_reg_address);
1482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
1492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
1502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	*val = (st->rx[0] << 8) | st->rx[1];
1512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
1532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&st->buf_lock);
1542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
1552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_spi_read_signed(struct device *dev,
1582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
1592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf,
1602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		unsigned bits)
1612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
1632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	s16 val = 0;
1642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	unsigned shift = 16 - bits;
1652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
1662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
1682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
1692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return ret;
1702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (val & ADIS16240_ERROR_ACTIVE)
1722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_check_status(dev);
1732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	val = ((s16)(val << shift) >> shift);
1752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return sprintf(buf, "%d\n", val);
1762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_read_10bit_unsigned(struct device *dev,
1792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
1802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf)
1812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
1822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
1832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	u16 val = 0;
1842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
1852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_read_reg_16(dev, this_attr->address, &val);
1872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
1882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return ret;
1892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (val & ADIS16240_ERROR_ACTIVE)
1912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_check_status(dev);
1922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return sprintf(buf, "%u\n", val & 0x03FF);
1942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
1952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
1962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_read_10bit_signed(struct device *dev,
1972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
1982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf)
1992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = dev_get_drvdata(dev);
2012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ssize_t ret;
2022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Take the iio_dev status lock */
2042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&indio_dev->mlock);
2052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret =  adis16240_spi_read_signed(dev, attr, buf, 10);
2062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&indio_dev->mlock);
2072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_read_12bit_signed(struct device *dev,
2122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
2132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		char *buf)
2142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = dev_get_drvdata(dev);
2162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ssize_t ret;
2172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Take the iio_dev status lock */
2192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_lock(&indio_dev->mlock);
2202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret =  adis16240_spi_read_signed(dev, attr, buf, 12);
2212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_unlock(&indio_dev->mlock);
2222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_write_16bit(struct device *dev,
2272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
2282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		const char *buf,
2292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		size_t len)
2302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
2322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
2332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	long val;
2342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = strict_strtol(buf, 10, &val);
2362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
2372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
2382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_write_reg_16(dev, this_attr->address, val);
2392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
2412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret ? ret : len;
2422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_reset(struct device *dev)
2452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
2472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_write_reg_8(dev,
2482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_GLOB_CMD,
2492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_GLOB_CMD_SW_RESET);
2502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
2512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "problem resetting device");
2522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic ssize_t adis16240_write_reset(struct device *dev,
2572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		struct device_attribute *attr,
2582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		const char *buf, size_t len)
2592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (len < 1)
2612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return -EINVAL;
2622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	switch (buf[0]) {
2632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case '1':
2642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case 'y':
2652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	case 'Y':
2662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		return adis16240_reset(dev);
2672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
2682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return -EINVAL;
2692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songint adis16240_set_irq(struct device *dev, bool enable)
2722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret = 0;
2742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	u16 msc;
2752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_read_reg_16(dev, ADIS16240_MSC_CTRL, &msc);
2772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
2782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
2792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msc |= ADIS16240_MSC_CTRL_ACTIVE_HIGH;
2812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_DIO2;
2822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (enable)
2832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msc |= ADIS16240_MSC_CTRL_DATA_RDY_EN;
2842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	else
2852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msc &= ~ADIS16240_MSC_CTRL_DATA_RDY_EN;
2862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_write_reg_16(dev, ADIS16240_MSC_CTRL, msc);
2882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
2902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
2912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
2922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
2932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_self_test(struct device *dev)
2942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
2952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
2962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_write_reg_16(dev,
2972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_MSC_CTRL,
2982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			ADIS16240_MSC_CTRL_SELF_TEST_EN);
2992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "problem starting self test");
3012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
3022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	msleep(ADIS16240_STARTUP_DELAY);
3052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_check_status(dev);
3072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerr_ret:
3092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
3102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
3112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_check_status(struct device *dev)
3132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
3142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	u16 status;
3152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
3162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_spi_read_reg_16(dev, ADIS16240_DIAG_STAT, &status);
3182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret < 0) {
3202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Reading status failed\n");
3212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
3222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = status & 0x2F;
3252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_PWRON_FAIL)
3262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power-on, self-test fail\n");
3272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_SPI_FAIL)
3282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "SPI failure\n");
3292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_FLASH_UPT)
3302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Flash update failed\n");
3312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_POWER_HIGH)
3322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power supply above 3.625V\n");
3332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (status & ADIS16240_DIAG_STAT_POWER_LOW)
3342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "Power supply below 2.225V\n");
3352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
3372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
3382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
3392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_initial_setup(struct adis16240_state *st)
3412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
3422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret;
3432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct device *dev = &st->indio_dev->dev;
3442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Disable IRQ */
3462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_set_irq(dev, false);
3472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "disable irq failed");
3492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
3502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Do self test */
3532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_self_test(dev);
3542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "self test failure");
3562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto err_ret;
3572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Read status register to check the result */
3602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_check_status(dev);
3612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
3622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_reset(dev);
3632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		dev_err(dev, "device not playing ball -> reset");
3642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		msleep(ADIS16240_STARTUP_DELAY);
3652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = adis16240_check_status(dev);
3662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		if (ret) {
3672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			dev_err(dev, "giving up");
3682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			goto err_ret;
3692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		}
3702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
3712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
3732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			st->us->chip_select, st->us->irq);
3742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerr_ret:
3762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
3772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
3782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
3792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16240_read_10bit_unsigned,
3802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_SUPPLY_OUT);
3812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_IN_RAW(0, adis16240_read_10bit_signed,
3822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_AUX_ADC);
38351a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_CONST_ATTR_IN_NAMED_SCALE(supply, "0.00488");
3842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_ACCEL_X(adis16240_read_10bit_signed,
3852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_XACCL_OUT);
3862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(accel_x_peak_raw, S_IRUGO,
3872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       adis16240_read_10bit_signed, NULL,
3882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       ADIS16240_XPEAK_OUT);
3892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_ACCEL_Y(adis16240_read_10bit_signed,
3902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_YACCL_OUT);
3912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(accel_y_peak_raw, S_IRUGO,
3922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       adis16240_read_10bit_signed, NULL,
3932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       ADIS16240_YPEAK_OUT);
3942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_ACCEL_Z(adis16240_read_10bit_signed,
3952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_ZACCL_OUT);
3962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(accel_z_peak_raw, S_IRUGO,
3972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       adis16240_read_10bit_signed, NULL,
3982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       ADIS16240_ZPEAK_OUT);
3992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(accel_xyz_squared_peak_raw, S_IRUGO,
4012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       adis16240_read_12bit_signed, NULL,
4022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		       ADIS16240_XYZPEAK_OUT);
40351a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(S_IWUSR | S_IRUGO,
4042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_read_10bit_signed,
4052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_write_16bit,
4062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_XACCL_OFF);
40751a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(S_IWUSR | S_IRUGO,
4082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_read_10bit_signed,
4092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_write_16bit,
4102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_YACCL_OFF);
41151a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(S_IWUSR | S_IRUGO,
4122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_read_10bit_signed,
4132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		adis16240_write_16bit,
4142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ADIS16240_ZACCL_OFF);
4152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEV_ATTR_TEMP_RAW(adis16240_read_10bit_unsigned);
41651a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_CONST_ATTR_TEMP_SCALE("0.244");
4172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16240_write_reset, 0);
4192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
42051a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096");
4212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
42251a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahlstatic IIO_CONST_ATTR_NAME("adis16240");
4232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct attribute *adis16240_event_attributes[] = {
4252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	NULL
4262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
4272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct attribute_group adis16240_event_attribute_group = {
4292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.attrs = adis16240_event_attributes,
4302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
4312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct attribute *adis16240_attributes[] = {
4332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_in_supply_raw.dev_attr.attr,
4342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_const_attr_in_supply_scale.dev_attr.attr,
4352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_in0_raw.dev_attr.attr,
4362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_x_raw.dev_attr.attr,
43751a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl	&iio_dev_attr_accel_x_calibbias.dev_attr.attr,
4382c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_x_peak_raw.dev_attr.attr,
4392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_y_raw.dev_attr.attr,
44051a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl	&iio_dev_attr_accel_y_calibbias.dev_attr.attr,
4412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_y_peak_raw.dev_attr.attr,
4422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_z_raw.dev_attr.attr,
44351a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl	&iio_dev_attr_accel_z_calibbias.dev_attr.attr,
4442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_z_peak_raw.dev_attr.attr,
4452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_accel_xyz_squared_peak_raw.dev_attr.attr,
4462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_temp_raw.dev_attr.attr,
4472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_const_attr_temp_scale.dev_attr.attr,
44851a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
4492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_dev_attr_reset.dev_attr.attr,
4502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	&iio_const_attr_name.dev_attr.attr,
4512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	NULL
4522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
4532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic const struct attribute_group adis16240_attribute_group = {
4552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.attrs = adis16240_attributes,
4562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
4572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int __devinit adis16240_probe(struct spi_device *spi)
4592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
4602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	int ret, regdone = 0;
4612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct adis16240_state *st = kzalloc(sizeof *st, GFP_KERNEL);
4622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (!st) {
4632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret =  -ENOMEM;
4642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_ret;
4652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
4662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* this is only used for removal purposes */
4672c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_set_drvdata(spi, st);
4682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Allocate the comms buffers */
4702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->rx = kzalloc(sizeof(*st->rx)*ADIS16240_MAX_RX, GFP_KERNEL);
4712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (st->rx == NULL) {
4722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = -ENOMEM;
4732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_free_st;
4742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
4752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->tx = kzalloc(sizeof(*st->tx)*ADIS16240_MAX_TX, GFP_KERNEL);
4762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (st->tx == NULL) {
4772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = -ENOMEM;
4782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_free_rx;
4792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
4802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->us = spi;
4812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	mutex_init(&st->buf_lock);
4822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* setup the industrialio driver allocated elements */
4832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev = iio_allocate_device();
4842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (st->indio_dev == NULL) {
4852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = -ENOMEM;
4862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_free_tx;
4872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
4882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->dev.parent = &spi->dev;
4902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->num_interrupt_lines = 1;
4912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->event_attrs = &adis16240_event_attribute_group;
4922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->attrs = &adis16240_attribute_group;
4932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->dev_data = (void *)(st);
4942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->driver_module = THIS_MODULE;
4952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	st->indio_dev->modes = INDIO_DIRECT_MODE;
4962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
4972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_configure_ring(st->indio_dev);
4982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
4992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_free_dev;
5002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = iio_device_register(st->indio_dev);
5022c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
5032c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_unreg_ring_funcs;
5042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	regdone = 1;
5052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5062662051e0868d1bde0abeea19bd54c3c18941afcJonathan Cameron	ret = iio_ring_buffer_register(st->indio_dev->ring, 0);
5072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret) {
5082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		printk(KERN_ERR "failed to initialize the ring\n");
5092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_unreg_ring_funcs;
5102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
5112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5122c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (spi->irq) {
5132c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = iio_register_interrupt_line(spi->irq,
5142c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song				st->indio_dev,
5152c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song				0,
5162c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song				IRQF_TRIGGER_RISING,
5172c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song				"adis16240");
5182c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		if (ret)
5192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			goto error_uninitialize_ring;
5202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5212c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		ret = adis16240_probe_trigger(st->indio_dev);
5222c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		if (ret)
5232c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song			goto error_unregister_line;
5242c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	}
5252c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5262c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	/* Get the device into a sane initial state */
5272c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	ret = adis16240_initial_setup(st);
5282c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (ret)
5292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		goto error_remove_trigger;
5302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return 0;
5312c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_remove_trigger:
5332c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_remove_trigger(st->indio_dev);
5342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_unregister_line:
5352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (spi->irq)
5362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		iio_unregister_interrupt_line(st->indio_dev, 0);
5372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_uninitialize_ring:
5382662051e0868d1bde0abeea19bd54c3c18941afcJonathan Cameron	iio_ring_buffer_unregister(st->indio_dev->ring);
5392c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_unreg_ring_funcs:
5402c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_unconfigure_ring(st->indio_dev);
5412c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_dev:
5422c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (regdone)
5432c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		iio_device_unregister(st->indio_dev);
5442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	else
5452c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		iio_free_device(st->indio_dev);
5462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_tx:
5472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st->tx);
5482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_rx:
5492c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st->rx);
5502c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_st:
5512c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st);
5522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret:
5532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return ret;
5542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_remove(struct spi_device *spi)
5572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
5582c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct adis16240_state *st = spi_get_drvdata(spi);
5592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	struct iio_dev *indio_dev = st->indio_dev;
5602c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	flush_scheduled_work();
5622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_remove_trigger(indio_dev);
5642c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	if (spi->irq)
5652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		iio_unregister_interrupt_line(indio_dev, 0);
5662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5672662051e0868d1bde0abeea19bd54c3c18941afcJonathan Cameron	iio_ring_buffer_unregister(indio_dev->ring);
5682c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	iio_device_unregister(indio_dev);
5692c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	adis16240_unconfigure_ring(indio_dev);
5702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st->tx);
5712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st->rx);
5722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	kfree(st);
5732c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return 0;
5752c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5772c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct spi_driver adis16240_driver = {
5782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.driver = {
5792c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		.name = "adis16240",
5802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song		.owner = THIS_MODULE,
5812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	},
5822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.probe = adis16240_probe,
5832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	.remove = __devexit_p(adis16240_remove),
5842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song};
5852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5862c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic __init int adis16240_init(void)
5872c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
5882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	return spi_register_driver(&adis16240_driver);
5892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songmodule_init(adis16240_init);
5912c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic __exit void adis16240_exit(void)
5932c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{
5942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song	spi_unregister_driver(&adis16240_driver);
5952c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}
5962c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songmodule_exit(adis16240_exit);
5972c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song
5982c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
5992c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder");
6002c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry SongMODULE_LICENSE("GPL v2");
601