adis16240_core.c revision 55e4390cb04e8b0fbae8983c3494c9e24132db1b
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" 24af5046af1c812839f085030f358a01814666fc80Jonathan Cameron#include "../buffer.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; 392c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_SCALE: 393cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron switch (chan->type) { 3946835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron case IIO_VOLTAGE: 395cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = 0; 396cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron if (chan->channel == 0) 397cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val2 = 4880; 398cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron else 399cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return -EINVAL; 400cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 401cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron case IIO_TEMP: 402cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = 0; 403cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val2 = 244000; 404cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 405cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron case IIO_ACCEL: 406cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = 0; 407cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val2 = 504062; 408cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 409cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron default: 410cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return -EINVAL; 411cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron } 412cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron break; 413c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_PEAK_SCALE: 414cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = 6; 415cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val2 = 629295; 416cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 417c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_OFFSET: 418cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = 25; 419cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT; 420c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_CALIBBIAS: 421cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron bits = 10; 422cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_lock(&indio_dev->mlock); 423cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron addr = adis16240_addresses[chan->address][1]; 424cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16); 425cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron if (ret) { 426cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_unlock(&indio_dev->mlock); 427cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return ret; 428cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron } 429cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron val16 &= (1 << bits) - 1; 430cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); 431cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = val16; 432cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_unlock(&indio_dev->mlock); 433cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT; 434c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_PEAK: 435cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron bits = 10; 436cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_lock(&indio_dev->mlock); 437cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron addr = adis16240_addresses[chan->address][2]; 438cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16); 439cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron if (ret) { 440cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_unlock(&indio_dev->mlock); 441cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return ret; 442cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron } 443cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron val16 &= (1 << bits) - 1; 444cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); 445cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron *val = val16; 446cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron mutex_unlock(&indio_dev->mlock); 447cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return IIO_VAL_INT; 448cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron } 449cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return -EINVAL; 450cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron} 451cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron 452cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic int adis16240_write_raw(struct iio_dev *indio_dev, 453cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron struct iio_chan_spec const *chan, 454cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron int val, 455cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron int val2, 456cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron long mask) 457cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron{ 458cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron int bits = 10; 459cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron s16 val16; 460cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron u8 addr; 461cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron switch (mask) { 462c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_CALIBBIAS: 463cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron val16 = val & ((1 << bits) - 1); 464cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron addr = adis16240_addresses[chan->address][1]; 465cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return adis16240_spi_write_reg_16(indio_dev, addr, val16); 466cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron } 467cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron return -EINVAL; 468cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron} 469cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron 470cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameronstatic struct iio_chan_spec adis16240_channels[] = { 4716835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, 472c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 473cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron in_supply, ADIS16240_SCAN_SUPPLY, 474cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('u', 10, 16, 0), 0), 4756835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, 476cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron 0, 477cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron in_aux, ADIS16240_SCAN_AUX_ADC, 478cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('u', 10, 16, 0), 0), 479cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, 480c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SHARED_BIT | 481c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 482cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron accel_x, ADIS16240_SCAN_ACC_X, 483cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('s', 10, 16, 0), 0), 484cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, 485c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SHARED_BIT | 486c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 487cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron accel_y, ADIS16240_SCAN_ACC_Y, 488cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('s', 10, 16, 0), 0), 489cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, 490c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SHARED_BIT | 491c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 492cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron accel_z, ADIS16240_SCAN_ACC_Z, 493cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('s', 10, 16, 0), 0), 494cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, 495c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 496cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron temp, ADIS16240_SCAN_TEMP, 497cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_ST('u', 10, 16, 0), 0), 498cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron IIO_CHAN_SOFT_TIMESTAMP(6) 499cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron}; 500cd69f57dee75cb27337bf5438359aae86503873fJonathan Cameron 5012c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic struct attribute *adis16240_attributes[] = { 502322c95636739420631e51f3d3f24132dc220762aJonathan Cameron &iio_dev_attr_in_accel_xyz_squared_peak_raw.dev_attr.attr, 50351a0a5b02132f880ff2d2bd7dbbe73b2dfd708a4Manuel Stahl &iio_const_attr_sampling_frequency_available.dev_attr.attr, 5042c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song &iio_dev_attr_reset.dev_attr.attr, 5052c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song NULL 5062c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}; 5072c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5082c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic const struct attribute_group adis16240_attribute_group = { 5092c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song .attrs = adis16240_attributes, 5102c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song}; 5112c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5126fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameronstatic const struct iio_info adis16240_info = { 5136fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .attrs = &adis16240_attribute_group, 5146fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .read_raw = &adis16240_read_raw, 5156fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .write_raw = &adis16240_write_raw, 5166fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .driver_module = THIS_MODULE, 5176fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron}; 5186fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron 5192c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int __devinit adis16240_probe(struct spi_device *spi) 5202c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{ 52126d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron int ret; 522a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron struct adis16240_state *st; 523a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron struct iio_dev *indio_dev; 524a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron 525a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron /* setup the industrialio driver allocated elements */ 526a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev = iio_allocate_device(sizeof(*st)); 527a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron if (indio_dev == NULL) { 528a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron ret = -ENOMEM; 5292c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song goto error_ret; 5302c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song } 531a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron st = iio_priv(indio_dev); 5322c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song /* this is only used for removal purposes */ 533a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron spi_set_drvdata(spi, indio_dev); 5342c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5352c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song st->us = spi; 5362c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song mutex_init(&st->buf_lock); 5372c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 538a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->name = spi->dev.driver->name; 539a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->dev.parent = &spi->dev; 540a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->info = &adis16240_info; 541a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->channels = adis16240_channels; 542a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->num_channels = ARRAY_SIZE(adis16240_channels); 543a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron indio_dev->modes = INDIO_DIRECT_MODE; 5442c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 545a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron ret = adis16240_configure_ring(indio_dev); 5462c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song if (ret) 5472c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song goto error_free_dev; 5482c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 54914555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron ret = iio_buffer_register(indio_dev, 55014555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron adis16240_channels, 55114555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron ARRAY_SIZE(adis16240_channels)); 5522c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song if (ret) { 5532c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song printk(KERN_ERR "failed to initialize the ring\n"); 5542c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song goto error_unreg_ring_funcs; 5552c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song } 5562c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5572c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song if (spi->irq) { 558a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron ret = adis16240_probe_trigger(indio_dev); 5592c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song if (ret) 560bdd560c52b023cd23b6b082ca64c062cacc23e3fJonathan Cameron goto error_uninitialize_ring; 5612c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song } 5622c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5632c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song /* Get the device into a sane initial state */ 564a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron ret = adis16240_initial_setup(indio_dev); 5652c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song if (ret) 5662c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song goto error_remove_trigger; 56726d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron ret = iio_device_register(indio_dev); 56826d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron if (ret) 56926d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron goto error_remove_trigger; 5702c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song return 0; 5712c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5722c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_remove_trigger: 573a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron adis16240_remove_trigger(indio_dev); 5742c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_uninitialize_ring: 57514555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron iio_buffer_unregister(indio_dev); 5762c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_unreg_ring_funcs: 577a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron adis16240_unconfigure_ring(indio_dev); 5782c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_free_dev: 57926d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron iio_free_device(indio_dev); 5802c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songerror_ret: 5812c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song return ret; 5822c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song} 5832c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5842c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Songstatic int adis16240_remove(struct spi_device *spi) 5852c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song{ 586a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron 587a22ff7066c0561c2aa92967f0eed4a1c77f088e7Jonathan Cameron struct iio_dev *indio_dev = spi_get_drvdata(spi); 5882c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 5892c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song flush_scheduled_work(); 5902c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song 591d2fffd6c2fd60fe9ab63ef30758d9d43a5057549Jonathan Cameron iio_device_unregister(indio_dev); 5922c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song adis16240_remove_trigger(indio_dev); 59314555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron iio_buffer_unregister(indio_dev); 5942c834b4d2d30c8f8ae5365a66c50da95aed7b7eaBarry Song adis16240_unconfigure_ring(indio_dev); 595d2fffd6c2fd60fe9ab63ef30758d9d43a5057549Jonathan Cameron iio_free_device(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"); 62455e4390cb04e8b0fbae8983c3494c9e24132db1bLars-Peter ClausenMODULE_ALIAS("spi:adis16240"); 625