summaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2012-11-20 13:36:00 +0000
committerJonathan Cameron <jic23@kernel.org>2012-11-20 19:51:29 +0000
commit57a1228a06b7a5939a8b0078a92b44fa30855bcb (patch)
treeb0cfaf71667f2026fc1d1e7d3ede704731e7d7b6 /drivers/iio
parent78026a6fde8f7b0ca77c059da11f476d69dfde3b (diff)
downloadtalos-op-linux-57a1228a06b7a5939a8b0078a92b44fa30855bcb.tar.gz
talos-op-linux-57a1228a06b7a5939a8b0078a92b44fa30855bcb.zip
iio:imu:adis: Add support for 32bit registers
Some of the newer generation devices from the ADIS16XXX family have 32bit wide register which spans two 16bit wide registers. This patch adds support for reading and writing a 32bit wide register. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/imu/adis.c145
-rw-r--r--drivers/iio/imu/adis_buffer.c2
2 files changed, 94 insertions, 53 deletions
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 28d4df2fe76a..280a49584adf 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -27,36 +27,10 @@
#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
#define ADIS_GLOB_CMD_SW_RESET BIT(7)
-/**
- * adis_write_reg_8() - Write single byte to a register
- * @adis: The adis device
- * @reg: The address of the register to be written
- * @val: The value to write
- */
-int adis_write_reg_8(struct adis *adis, unsigned int reg, uint8_t val)
-{
- int ret;
-
- mutex_lock(&adis->txrx_lock);
- adis->tx[0] = ADIS_WRITE_REG(reg);
- adis->tx[1] = val;
-
- ret = spi_write(adis->spi, adis->tx, 2);
- mutex_unlock(&adis->txrx_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(adis_write_reg_8);
-
-/**
- * adis_write_reg_16() - Write 2 bytes to a pair of registers
- * @adis: The adis device
- * @reg: The address of the lower of the two registers
- * @val: Value to be written
- */
-int adis_write_reg_16(struct adis *adis, unsigned int reg, uint16_t value)
+int adis_write_reg(struct adis *adis, unsigned int reg,
+ unsigned int value, unsigned int size)
{
- int ret;
+ int ret, i;
struct spi_message msg;
struct spi_transfer xfers[] = {
{
@@ -69,33 +43,69 @@ int adis_write_reg_16(struct adis *adis, unsigned int reg, uint16_t value)
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 4,
+ .bits_per_word = 8,
+ .len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->write_delay,
+ }, {
+ .tx_buf = adis->tx + 6,
+ .bits_per_word = 8,
+ .len = 2,
.delay_usecs = adis->data->write_delay,
},
};
mutex_lock(&adis->txrx_lock);
- adis->tx[0] = ADIS_WRITE_REG(reg);
- adis->tx[1] = value & 0xff;
- adis->tx[2] = ADIS_WRITE_REG(reg + 1);
- adis->tx[3] = (value >> 8) & 0xff;
spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
+ switch (size) {
+ case 4:
+ adis->tx[6] = ADIS_WRITE_REG(reg + 3);
+ adis->tx[7] = (value >> 24) & 0xff;
+ adis->tx[4] = ADIS_WRITE_REG(reg + 2);
+ adis->tx[5] = (value >> 16) & 0xff;
+ case 2:
+ adis->tx[2] = ADIS_WRITE_REG(reg + 1);
+ adis->tx[3] = (value >> 8) & 0xff;
+ case 1:
+ adis->tx[0] = ADIS_WRITE_REG(reg);
+ adis->tx[1] = value & 0xff;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ xfers[size - 1].cs_change = 0;
+
+ for (i = 0; i < size; i++)
+ spi_message_add_tail(&xfers[i], &msg);
+
ret = spi_sync(adis->spi, &msg);
+ if (ret) {
+ dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
+ reg, ret);
+ }
+
+out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(adis_write_reg_16);
+EXPORT_SYMBOL_GPL(adis_write_reg);
/**
- * adis_read_reg_16() - read 2 bytes from a 16-bit register
+ * adis_read_reg() - read 2 bytes from a 16-bit register
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
*/
-int adis_read_reg_16(struct adis *adis, unsigned int reg, uint16_t *val)
+int adis_read_reg(struct adis *adis, unsigned int reg,
+ unsigned int *val, unsigned int size)
{
struct spi_message msg;
int ret;
@@ -107,33 +117,61 @@ int adis_read_reg_16(struct adis *adis, unsigned int reg, uint16_t *val)
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
}, {
+ .tx_buf = adis->tx + 2,
.rx_buf = adis->rx,
.bits_per_word = 8,
.len = 2,
+ .cs_change = 1,
+ .delay_usecs = adis->data->read_delay,
+ }, {
+ .rx_buf = adis->rx + 2,
+ .bits_per_word = 8,
+ .len = 2,
.delay_usecs = adis->data->read_delay,
},
};
mutex_lock(&adis->txrx_lock);
- adis->tx[0] = ADIS_READ_REG(reg);
- adis->tx[1] = 0;
-
spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
+
+ switch (size) {
+ case 4:
+ adis->tx[0] = ADIS_READ_REG(reg + 2);
+ adis->tx[1] = 0;
+ spi_message_add_tail(&xfers[0], &msg);
+ case 2:
+ adis->tx[2] = ADIS_READ_REG(reg);
+ adis->tx[3] = 0;
+ spi_message_add_tail(&xfers[1], &msg);
+ spi_message_add_tail(&xfers[2], &msg);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
ret = spi_sync(adis->spi, &msg);
if (ret) {
- dev_err(&adis->spi->dev, "Failed to read 16 bit register 0x%02X: %d\n",
+ dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
reg, ret);
- goto error_ret;
+ goto out_unlock;
}
- *val = get_unaligned_be16(adis->rx);
-error_ret:
+ switch (size) {
+ case 4:
+ *val = get_unaligned_be32(adis->rx);
+ break;
+ case 2:
+ *val = get_unaligned_be16(adis->rx + 2);
+ break;
+ }
+
+out_unlock:
mutex_unlock(&adis->txrx_lock);
+
return ret;
}
-EXPORT_SYMBOL_GPL(adis_read_reg_16);
+EXPORT_SYMBOL_GPL(adis_read_reg);
#ifdef CONFIG_DEBUG_FS
@@ -304,25 +342,26 @@ int adis_single_conversion(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
- uint16_t val16;
+ unsigned int uval;
int ret;
mutex_lock(&indio_dev->mlock);
- ret = adis_read_reg_16(adis, chan->address, &val16);
+ ret = adis_read_reg(adis, chan->address, &uval,
+ chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
- if (val16 & error_mask) {
+ if (uval & error_mask) {
ret = adis_check_status(adis);
if (ret)
goto err_unlock;
}
if (chan->scan_type.sign == 's')
- *val = sign_extend32(val16, chan->scan_type.realbits - 1);
+ *val = sign_extend32(uval, chan->scan_type.realbits - 1);
else
- *val = val16 & ((1 << chan->scan_type.realbits) - 1);
+ *val = uval & ((1 << chan->scan_type.realbits) - 1);
ret = IIO_VAL_INT;
err_unlock:
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index a91b4cbdc73a..785713349e9f 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -64,6 +64,8 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
for (i = 0; i < indio_dev->num_channels; i++, chan++) {
if (!test_bit(chan->scan_index, scan_mask))
continue;
+ if (chan->scan_type.storagebits == 32)
+ *tx++ = cpu_to_be16((chan->address + 2) << 8);
*tx++ = cpu_to_be16(chan->address << 8);
}
OpenPOWER on IntegriCloud