linux/drivers/iio/imu/adis.c
<<
>>
Prefs
   1/*
   2 * Common library for ADIS16XXX devices
   3 *
   4 * Copyright 2012 Analog Devices Inc.
   5 *   Author: Lars-Peter Clausen <lars@metafoo.de>
   6 *
   7 * Licensed under the GPL-2 or later.
   8 */
   9
  10#include <linux/delay.h>
  11#include <linux/mutex.h>
  12#include <linux/device.h>
  13#include <linux/kernel.h>
  14#include <linux/spi/spi.h>
  15#include <linux/slab.h>
  16#include <linux/sysfs.h>
  17#include <linux/module.h>
  18#include <asm/unaligned.h>
  19
  20#include <linux/iio/iio.h>
  21#include <linux/iio/sysfs.h>
  22#include <linux/iio/buffer.h>
  23#include <linux/iio/imu/adis.h>
  24
  25#define ADIS_MSC_CTRL_DATA_RDY_EN       BIT(2)
  26#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
  27#define ADIS_MSC_CTRL_DATA_RDY_DIO2     BIT(0)
  28#define ADIS_GLOB_CMD_SW_RESET          BIT(7)
  29
  30int adis_write_reg(struct adis *adis, unsigned int reg,
  31        unsigned int value, unsigned int size)
  32{
  33        unsigned int page = reg / ADIS_PAGE_SIZE;
  34        int ret, i;
  35        struct spi_message msg;
  36        struct spi_transfer xfers[] = {
  37                {
  38                        .tx_buf = adis->tx,
  39                        .bits_per_word = 8,
  40                        .len = 2,
  41                        .cs_change = 1,
  42                        .delay_usecs = adis->data->write_delay,
  43                }, {
  44                        .tx_buf = adis->tx + 2,
  45                        .bits_per_word = 8,
  46                        .len = 2,
  47                        .cs_change = 1,
  48                        .delay_usecs = adis->data->write_delay,
  49                }, {
  50                        .tx_buf = adis->tx + 4,
  51                        .bits_per_word = 8,
  52                        .len = 2,
  53                        .cs_change = 1,
  54                        .delay_usecs = adis->data->write_delay,
  55                }, {
  56                        .tx_buf = adis->tx + 6,
  57                        .bits_per_word = 8,
  58                        .len = 2,
  59                        .delay_usecs = adis->data->write_delay,
  60                }, {
  61                        .tx_buf = adis->tx + 8,
  62                        .bits_per_word = 8,
  63                        .len = 2,
  64                        .delay_usecs = adis->data->write_delay,
  65                },
  66        };
  67
  68        mutex_lock(&adis->txrx_lock);
  69
  70        spi_message_init(&msg);
  71
  72        if (adis->current_page != page) {
  73                adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
  74                adis->tx[1] = page;
  75                spi_message_add_tail(&xfers[0], &msg);
  76        }
  77
  78        switch (size) {
  79        case 4:
  80                adis->tx[8] = ADIS_WRITE_REG(reg + 3);
  81                adis->tx[9] = (value >> 24) & 0xff;
  82                adis->tx[6] = ADIS_WRITE_REG(reg + 2);
  83                adis->tx[7] = (value >> 16) & 0xff;
  84        case 2:
  85                adis->tx[4] = ADIS_WRITE_REG(reg + 1);
  86                adis->tx[5] = (value >> 8) & 0xff;
  87        case 1:
  88                adis->tx[2] = ADIS_WRITE_REG(reg);
  89                adis->tx[3] = value & 0xff;
  90                break;
  91        default:
  92                ret = -EINVAL;
  93                goto out_unlock;
  94        }
  95
  96        xfers[size].cs_change = 0;
  97
  98        for (i = 1; i <= size; i++)
  99                spi_message_add_tail(&xfers[i], &msg);
 100
 101        ret = spi_sync(adis->spi, &msg);
 102        if (ret) {
 103                dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
 104                                reg, ret);
 105        } else {
 106                adis->current_page = page;
 107        }
 108
 109out_unlock:
 110        mutex_unlock(&adis->txrx_lock);
 111
 112        return ret;
 113}
 114EXPORT_SYMBOL_GPL(adis_write_reg);
 115
 116/**
 117 * adis_read_reg() - read 2 bytes from a 16-bit register
 118 * @adis: The adis device
 119 * @reg: The address of the lower of the two registers
 120 * @val: The value read back from the device
 121 */
 122int adis_read_reg(struct adis *adis, unsigned int reg,
 123        unsigned int *val, unsigned int size)
 124{
 125        unsigned int page = reg / ADIS_PAGE_SIZE;
 126        struct spi_message msg;
 127        int ret;
 128        struct spi_transfer xfers[] = {
 129                {
 130                        .tx_buf = adis->tx,
 131                        .bits_per_word = 8,
 132                        .len = 2,
 133                        .cs_change = 1,
 134                        .delay_usecs = adis->data->write_delay,
 135                }, {
 136                        .tx_buf = adis->tx + 2,
 137                        .bits_per_word = 8,
 138                        .len = 2,
 139                        .cs_change = 1,
 140                        .delay_usecs = adis->data->read_delay,
 141                }, {
 142                        .tx_buf = adis->tx + 4,
 143                        .rx_buf = adis->rx,
 144                        .bits_per_word = 8,
 145                        .len = 2,
 146                        .cs_change = 1,
 147                        .delay_usecs = adis->data->read_delay,
 148                }, {
 149                        .rx_buf = adis->rx + 2,
 150                        .bits_per_word = 8,
 151                        .len = 2,
 152                        .delay_usecs = adis->data->read_delay,
 153                },
 154        };
 155
 156        mutex_lock(&adis->txrx_lock);
 157        spi_message_init(&msg);
 158
 159        if (adis->current_page != page) {
 160                adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
 161                adis->tx[1] = page;
 162                spi_message_add_tail(&xfers[0], &msg);
 163        }
 164
 165        switch (size) {
 166        case 4:
 167                adis->tx[2] = ADIS_READ_REG(reg + 2);
 168                adis->tx[3] = 0;
 169                spi_message_add_tail(&xfers[1], &msg);
 170        case 2:
 171                adis->tx[4] = ADIS_READ_REG(reg);
 172                adis->tx[5] = 0;
 173                spi_message_add_tail(&xfers[2], &msg);
 174                spi_message_add_tail(&xfers[3], &msg);
 175                break;
 176        default:
 177                ret = -EINVAL;
 178                goto out_unlock;
 179        }
 180
 181        ret = spi_sync(adis->spi, &msg);
 182        if (ret) {
 183                dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
 184                                reg, ret);
 185                goto out_unlock;
 186        } else {
 187                adis->current_page = page;
 188        }
 189
 190        switch (size) {
 191        case 4:
 192                *val = get_unaligned_be32(adis->rx);
 193                break;
 194        case 2:
 195                *val = get_unaligned_be16(adis->rx + 2);
 196                break;
 197        }
 198
 199out_unlock:
 200        mutex_unlock(&adis->txrx_lock);
 201
 202        return ret;
 203}
 204EXPORT_SYMBOL_GPL(adis_read_reg);
 205
 206#ifdef CONFIG_DEBUG_FS
 207
 208int adis_debugfs_reg_access(struct iio_dev *indio_dev,
 209        unsigned int reg, unsigned int writeval, unsigned int *readval)
 210{
 211        struct adis *adis = iio_device_get_drvdata(indio_dev);
 212
 213        if (readval) {
 214                uint16_t val16;
 215                int ret;
 216
 217                ret = adis_read_reg_16(adis, reg, &val16);
 218                *readval = val16;
 219
 220                return ret;
 221        } else {
 222                return adis_write_reg_16(adis, reg, writeval);
 223        }
 224}
 225EXPORT_SYMBOL(adis_debugfs_reg_access);
 226
 227#endif
 228
 229/**
 230 * adis_enable_irq() - Enable or disable data ready IRQ
 231 * @adis: The adis device
 232 * @enable: Whether to enable the IRQ
 233 *
 234 * Returns 0 on success, negative error code otherwise
 235 */
 236int adis_enable_irq(struct adis *adis, bool enable)
 237{
 238        int ret = 0;
 239        uint16_t msc;
 240
 241        if (adis->data->enable_irq)
 242                return adis->data->enable_irq(adis, enable);
 243
 244        ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
 245        if (ret)
 246                goto error_ret;
 247
 248        msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
 249        msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
 250        if (enable)
 251                msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
 252        else
 253                msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
 254
 255        ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
 256
 257error_ret:
 258        return ret;
 259}
 260EXPORT_SYMBOL(adis_enable_irq);
 261
 262/**
 263 * adis_check_status() - Check the device for error conditions
 264 * @adis: The adis device
 265 *
 266 * Returns 0 on success, a negative error code otherwise
 267 */
 268int adis_check_status(struct adis *adis)
 269{
 270        uint16_t status;
 271        int ret;
 272        int i;
 273
 274        ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
 275        if (ret < 0)
 276                return ret;
 277
 278        status &= adis->data->status_error_mask;
 279
 280        if (status == 0)
 281                return 0;
 282
 283        for (i = 0; i < 16; ++i) {
 284                if (status & BIT(i)) {
 285                        dev_err(&adis->spi->dev, "%s.\n",
 286                                adis->data->status_error_msgs[i]);
 287                }
 288        }
 289
 290        return -EIO;
 291}
 292EXPORT_SYMBOL_GPL(adis_check_status);
 293
 294/**
 295 * adis_reset() - Reset the device
 296 * @adis: The adis device
 297 *
 298 * Returns 0 on success, a negative error code otherwise
 299 */
 300int adis_reset(struct adis *adis)
 301{
 302        int ret;
 303
 304        ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
 305                        ADIS_GLOB_CMD_SW_RESET);
 306        if (ret)
 307                dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
 308
 309        return ret;
 310}
 311EXPORT_SYMBOL_GPL(adis_reset);
 312
 313static int adis_self_test(struct adis *adis)
 314{
 315        int ret;
 316
 317        ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
 318                        adis->data->self_test_mask);
 319        if (ret) {
 320                dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
 321                        ret);
 322                return ret;
 323        }
 324
 325        msleep(adis->data->startup_delay);
 326
 327        ret = adis_check_status(adis);
 328
 329        if (adis->data->self_test_no_autoclear)
 330                adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
 331
 332        return ret;
 333}
 334
 335/**
 336 * adis_inital_startup() - Performs device self-test
 337 * @adis: The adis device
 338 *
 339 * Returns 0 if the device is operational, a negative error code otherwise.
 340 *
 341 * This function should be called early on in the device initialization sequence
 342 * to ensure that the device is in a sane and known state and that it is usable.
 343 */
 344int adis_initial_startup(struct adis *adis)
 345{
 346        int ret;
 347
 348        ret = adis_self_test(adis);
 349        if (ret) {
 350                dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
 351                adis_reset(adis);
 352                msleep(adis->data->startup_delay);
 353                ret = adis_self_test(adis);
 354                if (ret) {
 355                        dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
 356                        return ret;
 357                }
 358        }
 359
 360        return 0;
 361}
 362EXPORT_SYMBOL_GPL(adis_initial_startup);
 363
 364/**
 365 * adis_single_conversion() - Performs a single sample conversion
 366 * @indio_dev: The IIO device
 367 * @chan: The IIO channel
 368 * @error_mask: Mask for the error bit
 369 * @val: Result of the conversion
 370 *
 371 * Returns IIO_VAL_INT on success, a negative error code otherwise.
 372 *
 373 * The function performs a single conversion on a given channel and post
 374 * processes the value accordingly to the channel spec. If a error_mask is given
 375 * the function will check if the mask is set in the returned raw value. If it
 376 * is set the function will perform a self-check. If the device does not report
 377 * a error bit in the channels raw value set error_mask to 0.
 378 */
 379int adis_single_conversion(struct iio_dev *indio_dev,
 380        const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
 381{
 382        struct adis *adis = iio_device_get_drvdata(indio_dev);
 383        unsigned int uval;
 384        int ret;
 385
 386        mutex_lock(&indio_dev->mlock);
 387
 388        ret = adis_read_reg(adis, chan->address, &uval,
 389                        chan->scan_type.storagebits / 8);
 390        if (ret)
 391                goto err_unlock;
 392
 393        if (uval & error_mask) {
 394                ret = adis_check_status(adis);
 395                if (ret)
 396                        goto err_unlock;
 397        }
 398
 399        if (chan->scan_type.sign == 's')
 400                *val = sign_extend32(uval, chan->scan_type.realbits - 1);
 401        else
 402                *val = uval & ((1 << chan->scan_type.realbits) - 1);
 403
 404        ret = IIO_VAL_INT;
 405err_unlock:
 406        mutex_unlock(&indio_dev->mlock);
 407        return ret;
 408}
 409EXPORT_SYMBOL_GPL(adis_single_conversion);
 410
 411/**
 412 * adis_init() - Initialize adis device structure
 413 * @adis:       The adis device
 414 * @indio_dev:  The iio device
 415 * @spi:        The spi device
 416 * @data:       Chip specific data
 417 *
 418 * Returns 0 on success, a negative error code otherwise.
 419 *
 420 * This function must be called, before any other adis helper function may be
 421 * called.
 422 */
 423int adis_init(struct adis *adis, struct iio_dev *indio_dev,
 424        struct spi_device *spi, const struct adis_data *data)
 425{
 426        mutex_init(&adis->txrx_lock);
 427        adis->spi = spi;
 428        adis->data = data;
 429        iio_device_set_drvdata(indio_dev, adis);
 430
 431        if (data->has_paging) {
 432                /* Need to set the page before first read/write */
 433                adis->current_page = -1;
 434        } else {
 435                /* Page will always be 0 */
 436                adis->current_page = 0;
 437        }
 438
 439        return adis_enable_irq(adis, false);
 440}
 441EXPORT_SYMBOL_GPL(adis_init);
 442
 443MODULE_LICENSE("GPL");
 444MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 445MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");
 446