staging:iio:adis16220: Use adis library

Use the new adis library for the adis16220 driver. The adis16220 driver is a bit
special and so we can only make use of the generic register access and control
functions for now.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
Lars-Peter Clausen 2012-11-13 13:28:00 +00:00 committed by Jonathan Cameron
parent 511fb29e35
commit edcf600912
2 changed files with 60 additions and 240 deletions

View File

@ -1,10 +1,9 @@
#ifndef SPI_ADIS16220_H_
#define SPI_ADIS16220_H_
#define ADIS16220_STARTUP_DELAY 220 /* ms */
#include "../imu/adis.h"
#define ADIS16220_READ_REG(a) a
#define ADIS16220_WRITE_REG(a) ((a) | 0x80)
#define ADIS16220_STARTUP_DELAY 220 /* ms */
/* Flash memory write count */
#define ADIS16220_FLASH_CNT 0x00
@ -102,15 +101,15 @@
#define ADIS16220_DIAG_STAT_FLASH_CHK (1<<6)
#define ADIS16220_DIAG_STAT_SELF_TEST (1<<5)
/* Capture period violation/interruption */
#define ADIS16220_DIAG_STAT_VIOLATION (1<<4)
#define ADIS16220_DIAG_STAT_VIOLATION_BIT 4
/* SPI communications failure */
#define ADIS16220_DIAG_STAT_SPI_FAIL (1<<3)
#define ADIS16220_DIAG_STAT_SPI_FAIL_BIT 3
/* Flash update failure */
#define ADIS16220_DIAG_STAT_FLASH_UPT (1<<2)
#define ADIS16220_DIAG_STAT_FLASH_UPT_BIT 2
/* Power supply above 3.625 V */
#define ADIS16220_DIAG_STAT_POWER_HIGH (1<<1)
#define ADIS16220_DIAG_STAT_POWER_HIGH_BIT 1
/* Power supply below 3.15 V */
#define ADIS16220_DIAG_STAT_POWER_LOW (1<<0)
#define ADIS16220_DIAG_STAT_POWER_LOW_BIT 0
/* GLOB_CMD */
#define ADIS16220_GLOB_CMD_SW_RESET (1<<7)
@ -125,13 +124,14 @@
/**
* struct adis16220_state - device instance specific data
* @us: actual spi_device
* @adis: adis device
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
**/
struct adis16220_state {
struct spi_device *us;
struct adis adis;
struct mutex buf_lock;
u8 tx[ADIS16220_MAX_TX] ____cacheline_aligned;
u8 rx[ADIS16220_MAX_RX];

View File

@ -20,136 +20,19 @@
#include "adis16220.h"
/**
* adis16220_spi_write_reg_8() - write single byte to a register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the register to be written
* @val: the value to write
**/
static int adis16220_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 val)
{
int ret;
struct adis16220_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_WRITE_REG(reg_address);
st->tx[1] = val;
ret = spi_write(st->us, st->tx, 2);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16220_spi_write_reg_16() - write 2 bytes to a pair of registers
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: value to be written
**/
static int adis16220_spi_write_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 value)
{
int ret;
struct spi_message msg;
struct adis16220_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.tx_buf = st->tx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_WRITE_REG(lower_reg_address);
st->tx[1] = value & 0xFF;
st->tx[2] = ADIS16220_WRITE_REG(lower_reg_address + 1);
st->tx[3] = (value >> 8) & 0xFF;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
mutex_unlock(&st->buf_lock);
return ret;
}
/**
* adis16220_spi_read_reg_16() - read 2 bytes from a 16-bit register
* @indio_dev: iio device associated with child of actual device
* @reg_address: the address of the lower of the two registers. Second register
* is assumed to have address one greater.
* @val: somewhere to pass back the value read
**/
static int adis16220_spi_read_reg_16(struct iio_dev *indio_dev,
u8 lower_reg_address,
u16 *val)
{
struct spi_message msg;
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
}, {
.rx_buf = st->rx,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = 35,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = ADIS16220_READ_REG(lower_reg_address);
st->tx[1] = 0;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
if (ret) {
dev_err(&st->us->dev,
"problem when reading 16 bit register 0x%02X",
lower_reg_address);
goto error_ret;
}
*val = (st->rx[0] << 8) | st->rx[1];
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
static ssize_t adis16220_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16220_state *st = iio_priv(indio_dev);
ssize_t ret;
s16 val = 0;
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
ret = adis16220_spi_read_reg_16(indio_dev, this_attr->address,
ret = adis_read_reg_16(&st->adis, this_attr->address,
(u16 *)&val);
mutex_unlock(&indio_dev->mlock);
if (ret)
@ -164,13 +47,14 @@ static ssize_t adis16220_write_16bit(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
u16 val;
ret = kstrtou16(buf, 10, &val);
if (ret)
goto error_ret;
ret = adis16220_spi_write_reg_16(indio_dev, this_attr->address, val);
ret = adis_write_reg_16(&st->adis, this_attr->address, val);
error_ret:
return ret ? ret : len;
@ -178,10 +62,11 @@ static ssize_t adis16220_write_16bit(struct device *dev,
static int adis16220_capture(struct iio_dev *indio_dev)
{
struct adis16220_state *st = iio_priv(indio_dev);
int ret;
ret = adis16220_spi_write_reg_16(indio_dev,
ADIS16220_GLOB_CMD,
0xBF08); /* initiates a manual data capture */
/* initiates a manual data capture */
ret = adis_write_reg_16(&st->adis, ADIS16220_GLOB_CMD, 0xBF08);
if (ret)
dev_err(&indio_dev->dev, "problem beginning capture");
@ -190,18 +75,6 @@ static int adis16220_capture(struct iio_dev *indio_dev)
return ret;
}
static int adis16220_reset(struct iio_dev *indio_dev)
{
int ret;
ret = adis16220_spi_write_reg_8(indio_dev,
ADIS16220_GLOB_CMD,
ADIS16220_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&indio_dev->dev, "problem resetting device");
return ret;
}
static ssize_t adis16220_write_capture(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
@ -222,81 +95,6 @@ static ssize_t adis16220_write_capture(struct device *dev,
return len;
}
static int adis16220_check_status(struct iio_dev *indio_dev)
{
u16 status;
int ret;
ret = adis16220_spi_read_reg_16(indio_dev, ADIS16220_DIAG_STAT,
&status);
if (ret < 0) {
dev_err(&indio_dev->dev, "Reading status failed\n");
goto error_ret;
}
ret = status & 0x7F;
if (status & ADIS16220_DIAG_STAT_VIOLATION)
dev_err(&indio_dev->dev,
"Capture period violation/interruption\n");
if (status & ADIS16220_DIAG_STAT_SPI_FAIL)
dev_err(&indio_dev->dev, "SPI failure\n");
if (status & ADIS16220_DIAG_STAT_FLASH_UPT)
dev_err(&indio_dev->dev, "Flash update failed\n");
if (status & ADIS16220_DIAG_STAT_POWER_HIGH)
dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
if (status & ADIS16220_DIAG_STAT_POWER_LOW)
dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
error_ret:
return ret;
}
static int adis16220_self_test(struct iio_dev *indio_dev)
{
int ret;
ret = adis16220_spi_write_reg_16(indio_dev,
ADIS16220_MSC_CTRL,
ADIS16220_MSC_CTRL_SELF_TEST_EN);
if (ret) {
dev_err(&indio_dev->dev, "problem starting self test");
goto err_ret;
}
adis16220_check_status(indio_dev);
err_ret:
return ret;
}
static int adis16220_initial_setup(struct iio_dev *indio_dev)
{
int ret;
/* Do self test */
ret = adis16220_self_test(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "self test failure");
goto err_ret;
}
/* Read status register to check the result */
ret = adis16220_check_status(indio_dev);
if (ret) {
adis16220_reset(indio_dev);
dev_err(&indio_dev->dev, "device not playing ball -> reset");
msleep(ADIS16220_STARTUP_DELAY);
ret = adis16220_check_status(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "giving up");
goto err_ret;
}
}
err_ret:
return ret;
}
static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
char *buf,
loff_t off,
@ -333,7 +131,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
count = ADIS16220_CAPTURE_SIZE - off;
/* write the begin position of capture buffer */
ret = adis16220_spi_write_reg_16(indio_dev,
ret = adis_write_reg_16(&st->adis,
ADIS16220_CAPT_PNTR,
off > 1);
if (ret)
@ -342,8 +140,9 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
/* read count/2 values from capture buffer */
mutex_lock(&st->buf_lock);
for (i = 0; i < count; i += 2) {
st->tx[i] = ADIS16220_READ_REG(addr);
st->tx[i] = ADIS_READ_REG(addr);
st->tx[i + 1] = 0;
}
xfers[1].len = count;
@ -351,7 +150,7 @@ static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
ret = spi_sync(st->us, &msg);
ret = spi_sync(st->adis.spi, &msg);
if (ret) {
mutex_unlock(&st->buf_lock);
@ -472,6 +271,8 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
struct adis16220_state *st = iio_priv(indio_dev);
const struct adis16220_address_spec *addr;
int ret = -EINVAL;
int addrind = 0;
u16 uval;
@ -516,28 +317,21 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
if (adis16220_addresses[chan->address][addrind].sign) {
ret = adis16220_spi_read_reg_16(indio_dev,
adis16220_addresses[chan
->address]
[addrind].addr,
&sval);
addr = &adis16220_addresses[chan->address][addrind];
if (addr->sign) {
ret = adis_read_reg_16(&st->adis, addr->addr, &sval);
if (ret)
return ret;
bits = adis16220_addresses[chan->address][addrind].bits;
bits = addr->bits;
sval &= (1 << bits) - 1;
sval = (s16)(sval << (16 - bits)) >> (16 - bits);
*val = sval;
return IIO_VAL_INT;
} else {
ret = adis16220_spi_read_reg_16(indio_dev,
adis16220_addresses[chan
->address]
[addrind].addr,
&uval);
ret = adis_read_reg_16(&st->adis, addr->addr, &uval);
if (ret)
return ret;
bits = adis16220_addresses[chan->address][addrind].bits;
bits = addr->bits;
uval &= (1 << bits) - 1;
*val = uval;
return IIO_VAL_INT;
@ -601,6 +395,32 @@ static const struct iio_info adis16220_info = {
.read_raw = &adis16220_read_raw,
};
static const char * const adis16220_status_error_msgs[] = {
[ADIS16220_DIAG_STAT_VIOLATION_BIT] = "Capture period violation/interruption",
[ADIS16220_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
[ADIS16220_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
[ADIS16220_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
[ADIS16220_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
};
static const struct adis_data adis16220_data = {
.read_delay = 35,
.write_delay = 35,
.msc_ctrl_reg = ADIS16220_MSC_CTRL,
.glob_cmd_reg = ADIS16220_GLOB_CMD,
.diag_stat_reg = ADIS16220_DIAG_STAT,
.self_test_mask = ADIS16220_MSC_CTRL_SELF_TEST_EN,
.startup_delay = ADIS16220_STARTUP_DELAY,
.status_error_msgs = adis16220_status_error_msgs,
.status_error_mask = BIT(ADIS16220_DIAG_STAT_VIOLATION_BIT) |
BIT(ADIS16220_DIAG_STAT_SPI_FAIL_BIT) |
BIT(ADIS16220_DIAG_STAT_FLASH_UPT_BIT) |
BIT(ADIS16220_DIAG_STAT_POWER_HIGH_BIT) |
BIT(ADIS16220_DIAG_STAT_POWER_LOW_BIT),
};
static int __devinit adis16220_probe(struct spi_device *spi)
{
int ret;
@ -618,9 +438,6 @@ static int __devinit adis16220_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16220_info;
@ -644,8 +461,11 @@ static int __devinit adis16220_probe(struct spi_device *spi)
if (ret)
goto error_rm_adc1_bin;
ret = adis_init(&st->adis, indio_dev, spi, &adis16220_data);
if (ret)
goto error_rm_adc2_bin;
/* Get the device into a sane initial state */
ret = adis16220_initial_setup(indio_dev);
ret = adis_initial_startup(&st->adis);
if (ret)
goto error_rm_adc2_bin;
return 0;