iio:imu:adis: Add support for 32bit registers
authorLars-Peter Clausen <lars@metafoo.de>
Tue, 20 Nov 2012 13:36:00 +0000 (13:36 +0000)
committerJonathan Cameron <jic23@kernel.org>
Tue, 20 Nov 2012 19:51:29 +0000 (19:51 +0000)
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>
drivers/iio/imu/adis.c
drivers/iio/imu/adis_buffer.c
include/linux/iio/imu/adis.h

index 28d4df2..280a495 100644 (file)
 #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:
index a91b4cb..7857133 100644 (file)
@@ -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);
        }
 
index fce7bc3..6402a08 100644 (file)
@@ -53,7 +53,7 @@ struct adis {
        struct spi_transfer     *xfer;
        void                    *buffer;
 
-       uint8_t                 tx[8] ____cacheline_aligned;
+       uint8_t                 tx[10] ____cacheline_aligned;
        uint8_t                 rx[4];
 };
 
@@ -61,9 +61,82 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
        struct spi_device *spi, const struct adis_data *data);
 int adis_reset(struct adis *adis);
 
-int adis_write_reg_8(struct adis *adis, unsigned int reg, uint8_t val);
-int adis_write_reg_16(struct adis *adis, unsigned int reg, uint16_t val);
-int adis_read_reg_16(struct adis *adis, unsigned int reg, uint16_t *val);
+int adis_write_reg(struct adis *adis, unsigned int reg,
+       unsigned int val, unsigned int size);
+int adis_read_reg(struct adis *adis, unsigned int reg,
+       unsigned int *val, unsigned int size);
+
+/**
+ * adis_write_reg_8() - Write single byte to a register
+ * @adis: The adis device
+ * @reg: The address of the register to be written
+ * @value: The value to write
+ */
+static inline int adis_write_reg_8(struct adis *adis, unsigned int reg,
+       uint8_t val)
+{
+       return adis_write_reg(adis, reg, val, 1);
+}
+
+/**
+ * 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
+ * @value: Value to be written
+ */
+static inline int adis_write_reg_16(struct adis *adis, unsigned int reg,
+       uint16_t val)
+{
+       return adis_write_reg(adis, reg, val, 2);
+}
+
+/**
+ * adis_write_reg_32() - write 4 bytes to four registers
+ * @adis: The adis device
+ * @reg: The address of the lower of the four register
+ * @value: Value to be written
+ */
+static inline int adis_write_reg_32(struct adis *adis, unsigned int reg,
+       uint32_t val)
+{
+       return adis_write_reg(adis, reg, val, 4);
+}
+
+/**
+ * adis_read_reg_16() - 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
+ */
+static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
+       uint16_t *val)
+{
+       unsigned int tmp;
+       int ret;
+
+       ret = adis_read_reg(adis, reg, &tmp, 2);
+       *val = tmp;
+
+       return ret;
+}
+
+/**
+ * adis_read_reg_32() - read 4 bytes from a 32-bit register
+ * @adis: The adis device
+ * @reg: The address of the lower of the two registers
+ * @val: The value read back from the device
+ */
+static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
+       uint32_t *val)
+{
+       unsigned int tmp;
+       int ret;
+
+       ret = adis_read_reg(adis, reg, &tmp, 4);
+       *val = tmp;
+
+       return ret;
+}
 
 int adis_enable_irq(struct adis *adis, bool enable);
 int adis_check_status(struct adis *adis);