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