1bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song/* 2bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * ADIS16204 Programmable High-g Digital Impact Sensor and Recorder 3bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * 4bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * Copyright 2010 Analog Devices Inc. 5bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * 6bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * Licensed under the GPL-2 or later. 7bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song */ 8bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 9bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/interrupt.h> 10bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/irq.h> 11bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/delay.h> 12bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/mutex.h> 13bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/device.h> 14bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/kernel.h> 15bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/spi/spi.h> 16bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/slab.h> 17bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/sysfs.h> 18bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include <linux/list.h> 1999c978529a40132a6f7a5f136b4362b56fc88d8cPaul Gortmaker#include <linux/module.h> 20bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 21bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include "../iio.h" 22bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include "../sysfs.h" 23af5046af1c812839f085030f358a01814666fc80Jonathan Cameron#include "../buffer.h" 24bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 25bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#include "adis16204.h" 26bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 27bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song#define DRIVER_NAME "adis16204" 28bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 29bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song/** 30bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * adis16204_spi_write_reg_8() - write single byte to a register 31bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @dev: device associated with child of actual device (iio_dev or iio_trig) 32bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @reg_address: the address of the register to be written 33bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @val: the value to write 34bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song **/ 35ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_spi_write_reg_8(struct iio_dev *indio_dev, 36bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song u8 reg_address, 37bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song u8 val) 38bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 39bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 404de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct adis16204_state *st = iio_priv(indio_dev); 41bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 42bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_lock(&st->buf_lock); 43bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[0] = ADIS16204_WRITE_REG(reg_address); 44bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[1] = val; 45bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 46bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ret = spi_write(st->us, st->tx, 2); 47bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_unlock(&st->buf_lock); 48bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 49bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 50bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 51bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 52bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song/** 53bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * adis16204_spi_write_reg_16() - write 2 bytes to a pair of registers 54ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron * @indio_dev: iio device associated with child of actual device 55bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @reg_address: the address of the lower of the two registers. Second register 56bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * is assumed to have address one greater. 57bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @val: value to be written 58bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song **/ 59ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_spi_write_reg_16(struct iio_dev *indio_dev, 60bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song u8 lower_reg_address, 61bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song u16 value) 62bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 63bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 64bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct spi_message msg; 654de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct adis16204_state *st = iio_priv(indio_dev); 66bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct spi_transfer xfers[] = { 67bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song { 68bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .tx_buf = st->tx, 69bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .bits_per_word = 8, 70bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .len = 2, 71bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .cs_change = 1, 72bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }, { 73bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .tx_buf = st->tx + 2, 74bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .bits_per_word = 8, 75bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .len = 2, 76bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .cs_change = 1, 77bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }, 78bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }; 79bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 80bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_lock(&st->buf_lock); 81bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[0] = ADIS16204_WRITE_REG(lower_reg_address); 82bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[1] = value & 0xFF; 83bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[2] = ADIS16204_WRITE_REG(lower_reg_address + 1); 84bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[3] = (value >> 8) & 0xFF; 85bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 86bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_init(&msg); 87bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_add_tail(&xfers[0], &msg); 88bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_add_tail(&xfers[1], &msg); 89bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ret = spi_sync(st->us, &msg); 90bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_unlock(&st->buf_lock); 91bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 92bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 93bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 94bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 95bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song/** 96bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * adis16204_spi_read_reg_16() - read 2 bytes from a 16-bit register 97ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron * @indio_dev: iio device associated with child of actual device 98bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @reg_address: the address of the lower of the two registers. Second register 99bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * is assumed to have address one greater. 100bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song * @val: somewhere to pass back the value read 101bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song **/ 102ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_spi_read_reg_16(struct iio_dev *indio_dev, 103ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron u8 lower_reg_address, 104ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron u16 *val) 105bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 106bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct spi_message msg; 1074de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct adis16204_state *st = iio_priv(indio_dev); 108bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 109bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct spi_transfer xfers[] = { 110bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song { 111bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .tx_buf = st->tx, 112bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .bits_per_word = 8, 113bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .len = 2, 114bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .cs_change = 1, 115bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .delay_usecs = 20, 116bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }, { 117bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .rx_buf = st->rx, 118bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .bits_per_word = 8, 119bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .len = 2, 120bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .delay_usecs = 20, 121bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }, 122bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }; 123bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 124bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_lock(&st->buf_lock); 125bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[0] = ADIS16204_READ_REG(lower_reg_address); 126bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->tx[1] = 0; 127bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 128bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_init(&msg); 129bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_add_tail(&xfers[0], &msg); 130bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song spi_message_add_tail(&xfers[1], &msg); 131bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ret = spi_sync(st->us, &msg); 132bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 133bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", 134bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song lower_reg_address); 135bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_ret; 136bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 137bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song *val = (st->rx[0] << 8) | st->rx[1]; 138bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 139bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_ret: 140bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_unlock(&st->buf_lock); 141bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 142bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 143bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 144ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_check_status(struct iio_dev *indio_dev) 145bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 146ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron u16 status; 147bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 148bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 149ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_read_reg_16(indio_dev, 150ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ADIS16204_DIAG_STAT, &status); 151ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (ret < 0) { 152ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "Reading status failed\n"); 153bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_ret; 154bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 155ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = status & 0x1F; 156bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 157ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (status & ADIS16204_DIAG_STAT_SELFTEST_FAIL) 158ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "Self test failure\n"); 159ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (status & ADIS16204_DIAG_STAT_SPI_FAIL) 160ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "SPI failure\n"); 161ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (status & ADIS16204_DIAG_STAT_FLASH_UPT) 162ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "Flash update failed\n"); 163ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (status & ADIS16204_DIAG_STAT_POWER_HIGH) 164ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "Power supply above 3.625V\n"); 165ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (status & ADIS16204_DIAG_STAT_POWER_LOW) 166ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "Power supply below 2.975V\n"); 167bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 168ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronerror_ret: 169bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 170bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 171bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 172bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic ssize_t adis16204_read_14bit_signed(struct device *dev, 173bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct device_attribute *attr, 174bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song char *buf) 175bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 176bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct iio_dev *indio_dev = dev_get_drvdata(dev); 177bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 178bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song s16 val = 0; 179bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ssize_t ret; 180bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 181bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_lock(&indio_dev->mlock); 182bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 183ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_read_reg_16(indio_dev, 184ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron this_attr->address, (u16 *)&val); 185bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (!ret) { 186bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (val & ADIS16204_ERROR_ACTIVE) 187ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron adis16204_check_status(indio_dev); 188bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 189bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song val = ((s16)(val << 2) >> 2); 190bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ret = sprintf(buf, "%d\n", val); 191bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 192bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 193bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_unlock(&indio_dev->mlock); 194bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 195bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 196bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 197bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 198ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_reset(struct iio_dev *indio_dev) 199bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 200bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 201ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_write_reg_8(indio_dev, 202bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_GLOB_CMD, 203bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_GLOB_CMD_SW_RESET); 204bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) 205ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "problem resetting device"); 206bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 207bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 208bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 209bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 210bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic ssize_t adis16204_write_reset(struct device *dev, 211bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song struct device_attribute *attr, 212bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song const char *buf, size_t len) 213bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 214ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron struct iio_dev *indio_dev = dev_get_drvdata(dev); 215ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 216bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (len < 1) 217bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return -EINVAL; 218bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song switch (buf[0]) { 219bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song case '1': 220bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song case 'y': 221bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song case 'Y': 222ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return adis16204_reset(indio_dev); 223bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 224bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return -EINVAL; 225bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 226bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 227ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronint adis16204_set_irq(struct iio_dev *indio_dev, bool enable) 228bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 229bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret = 0; 230bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song u16 msc; 231bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 232ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_read_reg_16(indio_dev, ADIS16204_MSC_CTRL, &msc); 233bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) 234bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_ret; 235bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 236bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song msc |= ADIS16204_MSC_CTRL_ACTIVE_HIGH; 237bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_DIO2; 238bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (enable) 239bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song msc |= ADIS16204_MSC_CTRL_DATA_RDY_EN; 240bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song else 241bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_EN; 242bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 243ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_write_reg_16(indio_dev, ADIS16204_MSC_CTRL, msc); 244bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 245bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_ret: 246bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 247bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 248bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 249ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_self_test(struct iio_dev *indio_dev) 250bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 251bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 252ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_write_reg_16(indio_dev, 253bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_MSC_CTRL, 254bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_MSC_CTRL_SELF_TEST_EN); 255bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 256ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "problem starting self test"); 257bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto err_ret; 258bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 259bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 260ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron adis16204_check_status(indio_dev); 261bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 262bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerr_ret: 263bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 264bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 265bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 266ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_initial_setup(struct iio_dev *indio_dev) 267bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 268bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song int ret; 269bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 270bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song /* Disable IRQ */ 271ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_set_irq(indio_dev, false); 272bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 273ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "disable irq failed"); 274bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto err_ret; 275bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 276bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 277bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song /* Do self test */ 278ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_self_test(indio_dev); 279bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 280ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "self test failure"); 281bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto err_ret; 282bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 283bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 284bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song /* Read status register to check the result */ 285ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_check_status(indio_dev); 286bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 287ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron adis16204_reset(indio_dev); 288ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "device not playing ball -> reset"); 289bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song msleep(ADIS16204_STARTUP_DELAY); 290ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_check_status(indio_dev); 291bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 292ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron dev_err(&indio_dev->dev, "giving up"); 293bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto err_ret; 294bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 295bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 296bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 297bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerr_ret: 298bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 299bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 300c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron 301c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron/* Unique to this driver currently */ 302c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron#define IIO_DEV_ATTR_ACCEL_XY(_show, _addr) \ 303322c95636739420631e51f3d3f24132dc220762aJonathan Cameron IIO_DEVICE_ATTR(in_accel_xy, S_IRUGO, _show, NULL, _addr) 304c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron#define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr) \ 305322c95636739420631e51f3d3f24132dc220762aJonathan Cameron IIO_DEVICE_ATTR(in_accel_xypeak, S_IRUGO, _show, NULL, _addr) 306c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron 307bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic IIO_DEV_ATTR_ACCEL_XY(adis16204_read_14bit_signed, 308bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_XY_RSS_OUT); 309bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed, 310bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ADIS16204_XY_PEAK_OUT); 311322c95636739420631e51f3d3f24132dc220762aJonathan Cameronstatic IIO_CONST_ATTR(in_accel_xy_scale, "0.017125"); 312bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 313bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16204_write_reset, 0); 314bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 315ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronenum adis16204_channel { 316ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron in_supply, 317ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron in_aux, 318ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron temp, 319ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron accel_x, 320ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron accel_y, 321ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron}; 322ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 323c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameronstatic u8 adis16204_addresses[5][3] = { 324ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron [in_supply] = { ADIS16204_SUPPLY_OUT }, 325ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron [in_aux] = { ADIS16204_AUX_ADC }, 326ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron [temp] = { ADIS16204_TEMP_OUT }, 327c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron [accel_x] = { ADIS16204_XACCL_OUT, ADIS16204_XACCL_NULL, 328c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron ADIS16204_X_PEAK_OUT }, 329c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron [accel_y] = { ADIS16204_XACCL_OUT, ADIS16204_YACCL_NULL, 330c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron ADIS16204_Y_PEAK_OUT }, 331ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron}; 332c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron 333ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_read_raw(struct iio_dev *indio_dev, 334ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron struct iio_chan_spec const *chan, 335ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int *val, int *val2, 336ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron long mask) 337ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron{ 338ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int ret; 339ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int bits; 340ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron u8 addr; 341ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron s16 val16; 342c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron int addrind; 343ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 344ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron switch (mask) { 345ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron case 0: 346ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron mutex_lock(&indio_dev->mlock); 347ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron addr = adis16204_addresses[chan->address][0]; 348ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16); 3498f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter if (ret) { 3508f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter mutex_unlock(&indio_dev->mlock); 351ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return ret; 3528f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter } 353ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 354ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (val16 & ADIS16204_ERROR_ACTIVE) { 355ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_check_status(indio_dev); 3568f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter if (ret) { 3578f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter mutex_unlock(&indio_dev->mlock); 358ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return ret; 3598f89615528b11eabda68faaf2438d09c9565a125Dan Carpenter } 360ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron } 361ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron val16 = val16 & ((1 << chan->scan_type.realbits) - 1); 362ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (chan->scan_type.sign == 's') 363ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron val16 = (s16)(val16 << 364ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron (16 - chan->scan_type.realbits)) >> 365ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron (16 - chan->scan_type.realbits); 366ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = val16; 367ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron mutex_unlock(&indio_dev->mlock); 368ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT; 369c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_SCALE: 370ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron switch (chan->type) { 3716835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron case IIO_VOLTAGE: 372ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = 0; 373ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (chan->channel == 0) 374ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val2 = 1220; 375ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron else 376ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val2 = 610; 377ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 378ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron case IIO_TEMP: 379ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = 0; 380ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val2 = -470000; 381ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 382ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron case IIO_ACCEL: 383ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = 0; 384ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (chan->channel == 'x') 385ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val2 = 17125; 386ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron else 387ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val2 = 8407; 388ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT_PLUS_MICRO; 389ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron default: 390ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return -EINVAL; 391ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron } 392ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron break; 393c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_OFFSET: 394ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = 25; 395ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT; 396c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_CALIBBIAS: 397c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_PEAK: 398c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron if (mask == IIO_CHAN_INFO_CALIBBIAS) { 399ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron bits = 12; 400c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron addrind = 1; 401c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron } else { /* PEAK_SEPARATE */ 402c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron bits = 14; 403c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron addrind = 2; 404c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron } 405ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron mutex_lock(&indio_dev->mlock); 406c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron addr = adis16204_addresses[chan->address][addrind]; 407ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16); 408ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron if (ret) { 409ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron mutex_unlock(&indio_dev->mlock); 410ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return ret; 411ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron } 412ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron val16 &= (1 << bits) - 1; 413ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); 414ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron *val = val16; 415ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron mutex_unlock(&indio_dev->mlock); 416ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return IIO_VAL_INT; 417ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron } 418ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return -EINVAL; 419ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron} 420ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 421ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic int adis16204_write_raw(struct iio_dev *indio_dev, 422ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron struct iio_chan_spec const *chan, 423ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int val, 424ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int val2, 425ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron long mask) 426ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron{ 427ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron int bits; 428ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron s16 val16; 429ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron u8 addr; 430ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron switch (mask) { 431c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_CALIBBIAS: 432ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron switch (chan->type) { 433ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron case IIO_ACCEL: 434ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron bits = 12; 435ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron break; 436ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron default: 437ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return -EINVAL; 438ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron }; 439ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron val16 = val & ((1 << bits) - 1); 440ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron addr = adis16204_addresses[chan->address][1]; 441ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return adis16204_spi_write_reg_16(indio_dev, addr, val16); 442ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron } 443ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron return -EINVAL; 444ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron} 445ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron 446ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameronstatic struct iio_chan_spec adis16204_channels[] = { 4476835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0, 448c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 449ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron in_supply, ADIS16204_SCAN_SUPPLY, 450ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_ST('u', 12, 16, 0), 0), 4516835cb6b438b77ba82ad5a23944bbfb12128f5dbJonathan Cameron IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, 452c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 453ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron in_aux, ADIS16204_SCAN_AUX_ADC, 454ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_ST('u', 12, 16, 0), 0), 455ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, 456c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT | 457c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, 458ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron temp, ADIS16204_SCAN_TEMP, 459ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_ST('u', 12, 16, 0), 0), 460ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, 461c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT | 462c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | 463c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 464ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron accel_x, ADIS16204_SCAN_ACC_X, 465ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_ST('s', 14, 16, 0), 0), 466ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, 467c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_SCALE_SEPARATE_BIT | 468c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | 469c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 470ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron accel_y, ADIS16204_SCAN_ACC_Y, 471ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_ST('s', 14, 16, 0), 0), 472ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron IIO_CHAN_SOFT_TIMESTAMP(5), 473ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan Cameron}; 474c9b9e49e131ccf51aad931b490134f0d1f04a8e7Jonathan Cameron 475bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic struct attribute *adis16204_attributes[] = { 476bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song &iio_dev_attr_reset.dev_attr.attr, 477322c95636739420631e51f3d3f24132dc220762aJonathan Cameron &iio_dev_attr_in_accel_xy.dev_attr.attr, 478322c95636739420631e51f3d3f24132dc220762aJonathan Cameron &iio_dev_attr_in_accel_xypeak.dev_attr.attr, 479322c95636739420631e51f3d3f24132dc220762aJonathan Cameron &iio_const_attr_in_accel_xy_scale.dev_attr.attr, 480bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song NULL 481bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song}; 482bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 483bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic const struct attribute_group adis16204_attribute_group = { 484bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .attrs = adis16204_attributes, 485bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song}; 486bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 4876fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameronstatic const struct iio_info adis16204_info = { 4886fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .attrs = &adis16204_attribute_group, 4896fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .read_raw = &adis16204_read_raw, 4906fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .write_raw = &adis16204_write_raw, 4916fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .driver_module = THIS_MODULE, 4926fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron}; 4936fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron 494bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic int __devinit adis16204_probe(struct spi_device *spi) 495bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 49626d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron int ret; 4974de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct adis16204_state *st; 4984de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct iio_dev *indio_dev; 499bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 5004de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron /* setup the industrialio driver allocated elements */ 5014de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev = iio_allocate_device(sizeof(*st)); 5024de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron if (indio_dev == NULL) { 503bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song ret = -ENOMEM; 5044de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron goto error_ret; 505bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 5064de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron st = iio_priv(indio_dev); 5074de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron /* this is only used for removal purposes */ 5084de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron spi_set_drvdata(spi, indio_dev); 509bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song st->us = spi; 510bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song mutex_init(&st->buf_lock); 511bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 5124de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->name = spi->dev.driver->name; 5134de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->dev.parent = &spi->dev; 5144de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->info = &adis16204_info; 5154de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->channels = adis16204_channels; 5164de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->num_channels = ARRAY_SIZE(adis16204_channels); 5174de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron indio_dev->modes = INDIO_DIRECT_MODE; 518bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 5194de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron ret = adis16204_configure_ring(indio_dev); 520bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) 521bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_free_dev; 522bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 52314555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron ret = iio_buffer_register(indio_dev, 52414555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron adis16204_channels, 52514555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron ARRAY_SIZE(adis16204_channels)); 526bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) { 527bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song printk(KERN_ERR "failed to initialize the ring\n"); 528bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_unreg_ring_funcs; 529bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 530bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 531bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (spi->irq) { 5324de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron ret = adis16204_probe_trigger(indio_dev); 533bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) 53437f9d2714a0a95cf7f45e0ed9422eea80490a77cJonathan Cameron goto error_uninitialize_ring; 535bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song } 536bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 537bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song /* Get the device into a sane initial state */ 5384de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron ret = adis16204_initial_setup(indio_dev); 539bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song if (ret) 540bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song goto error_remove_trigger; 54126d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron ret = iio_device_register(indio_dev); 54226d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron if (ret) 54326d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron goto error_remove_trigger; 54426d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron 545bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return 0; 546bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 547bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_remove_trigger: 5484de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron adis16204_remove_trigger(indio_dev); 549bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_uninitialize_ring: 55014555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron iio_buffer_unregister(indio_dev); 551bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_unreg_ring_funcs: 5524de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron adis16204_unconfigure_ring(indio_dev); 553bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_free_dev: 55426d25ae3f0d8ffe350aacc75b71198d6b35bd1f4Jonathan Cameron iio_free_device(indio_dev); 555bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songerror_ret: 556bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return ret; 557bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 558bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 559bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic int adis16204_remove(struct spi_device *spi) 560bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song{ 5614de66bbb3eb1099a76e1bbf87e376c7a31dc30d5Jonathan Cameron struct iio_dev *indio_dev = spi_get_drvdata(spi); 562bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 563d2fffd6c2fd60fe9ab63ef30758d9d43a5057549Jonathan Cameron iio_device_unregister(indio_dev); 564bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song adis16204_remove_trigger(indio_dev); 56514555b14455f9acbdf0e500ae96140828a970796Jonathan Cameron iio_buffer_unregister(indio_dev); 566bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song adis16204_unconfigure_ring(indio_dev); 567d2fffd6c2fd60fe9ab63ef30758d9d43a5057549Jonathan Cameron iio_free_device(indio_dev); 568bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 569bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song return 0; 570bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song} 571bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 572bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Songstatic struct spi_driver adis16204_driver = { 573bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .driver = { 574bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .name = "adis16204", 575bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .owner = THIS_MODULE, 576bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song }, 577bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .probe = adis16204_probe, 578bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song .remove = __devexit_p(adis16204_remove), 579bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song}; 580ae6ae6fec3f7d6919e0146996df37b665c75f662Lars-Peter Clausenmodule_spi_driver(adis16204_driver); 581bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry Song 582bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry SongMODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 583ad3eb9ab1276cc69bb9cc72dffc074d1a317a6c0Jonathan CameronMODULE_DESCRIPTION("ADIS16204 High-g Digital Impact Sensor and Recorder"); 584bb6f19eafe3a1a5dd937ce66668e70aeaa1b0bf4Barry SongMODULE_LICENSE("GPL v2"); 58555e4390cb04e8b0fbae8983c3494c9e24132db1bLars-Peter ClausenMODULE_ALIAS("spi:adis16204"); 586