linux/drivers/iio/accel/adis16209.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer
   4 *
   5 * Copyright 2010 Analog Devices Inc.
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/kernel.h>
  10#include <linux/list.h>
  11#include <linux/module.h>
  12#include <linux/spi/spi.h>
  13#include <linux/slab.h>
  14#include <linux/sysfs.h>
  15
  16#include <linux/iio/iio.h>
  17#include <linux/iio/imu/adis.h>
  18
  19#define ADIS16209_STARTUP_DELAY_MS      220
  20#define ADIS16209_FLASH_CNT_REG         0x00
  21
  22/* Data Output Register Definitions */
  23#define ADIS16209_SUPPLY_OUT_REG        0x02
  24#define ADIS16209_XACCL_OUT_REG         0x04
  25#define ADIS16209_YACCL_OUT_REG         0x06
  26/* Output, auxiliary ADC input */
  27#define ADIS16209_AUX_ADC_REG           0x08
  28/* Output, temperature */
  29#define ADIS16209_TEMP_OUT_REG          0x0A
  30/* Output, +/- 90 degrees X-axis inclination */
  31#define ADIS16209_XINCL_OUT_REG         0x0C
  32#define ADIS16209_YINCL_OUT_REG         0x0E
  33/* Output, +/-180 vertical rotational position */
  34#define ADIS16209_ROT_OUT_REG           0x10
  35
  36/*
  37 * Calibration Register Definitions.
  38 * Acceleration, inclination or rotation offset null.
  39 */
  40#define ADIS16209_XACCL_NULL_REG        0x12
  41#define ADIS16209_YACCL_NULL_REG        0x14
  42#define ADIS16209_XINCL_NULL_REG        0x16
  43#define ADIS16209_YINCL_NULL_REG        0x18
  44#define ADIS16209_ROT_NULL_REG          0x1A
  45
  46/* Alarm Register Definitions */
  47#define ADIS16209_ALM_MAG1_REG          0x20
  48#define ADIS16209_ALM_MAG2_REG          0x22
  49#define ADIS16209_ALM_SMPL1_REG         0x24
  50#define ADIS16209_ALM_SMPL2_REG         0x26
  51#define ADIS16209_ALM_CTRL_REG          0x28
  52
  53#define ADIS16209_AUX_DAC_REG           0x30
  54#define ADIS16209_GPIO_CTRL_REG         0x32
  55#define ADIS16209_SMPL_PRD_REG          0x36
  56#define ADIS16209_AVG_CNT_REG           0x38
  57#define ADIS16209_SLP_CNT_REG           0x3A
  58
  59#define ADIS16209_MSC_CTRL_REG                  0x34
  60#define  ADIS16209_MSC_CTRL_PWRUP_SELF_TEST     BIT(10)
  61#define  ADIS16209_MSC_CTRL_SELF_TEST_EN        BIT(8)
  62#define  ADIS16209_MSC_CTRL_DATA_RDY_EN         BIT(2)
  63/* Data-ready polarity: 1 = active high, 0 = active low */
  64#define  ADIS16209_MSC_CTRL_ACTIVE_HIGH         BIT(1)
  65#define  ADIS16209_MSC_CTRL_DATA_RDY_DIO2       BIT(0)
  66
  67#define ADIS16209_STAT_REG                      0x3C
  68#define  ADIS16209_STAT_ALARM2                  BIT(9)
  69#define  ADIS16209_STAT_ALARM1                  BIT(8)
  70#define  ADIS16209_STAT_SELFTEST_FAIL_BIT       5
  71#define  ADIS16209_STAT_SPI_FAIL_BIT            3
  72#define  ADIS16209_STAT_FLASH_UPT_FAIL_BIT      2
  73/* Power supply above 3.625 V */
  74#define  ADIS16209_STAT_POWER_HIGH_BIT          1
  75/* Power supply below 2.975 V */
  76#define  ADIS16209_STAT_POWER_LOW_BIT           0
  77
  78#define ADIS16209_CMD_REG                       0x3E
  79#define  ADIS16209_CMD_SW_RESET                 BIT(7)
  80#define  ADIS16209_CMD_CLEAR_STAT               BIT(4)
  81#define  ADIS16209_CMD_FACTORY_CAL              BIT(1)
  82
  83#define ADIS16209_ERROR_ACTIVE                  BIT(14)
  84
  85enum adis16209_scan {
  86        ADIS16209_SCAN_SUPPLY,
  87        ADIS16209_SCAN_ACC_X,
  88        ADIS16209_SCAN_ACC_Y,
  89        ADIS16209_SCAN_AUX_ADC,
  90        ADIS16209_SCAN_TEMP,
  91        ADIS16209_SCAN_INCLI_X,
  92        ADIS16209_SCAN_INCLI_Y,
  93        ADIS16209_SCAN_ROT,
  94};
  95
  96static const u8 adis16209_addresses[8][1] = {
  97        [ADIS16209_SCAN_SUPPLY] = { },
  98        [ADIS16209_SCAN_AUX_ADC] = { },
  99        [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL_REG },
 100        [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL_REG },
 101        [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL_REG },
 102        [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL_REG },
 103        [ADIS16209_SCAN_ROT] = { },
 104        [ADIS16209_SCAN_TEMP] = { },
 105};
 106
 107static int adis16209_write_raw(struct iio_dev *indio_dev,
 108                               struct iio_chan_spec const *chan,
 109                               int val,
 110                               int val2,
 111                               long mask)
 112{
 113        struct adis *st = iio_priv(indio_dev);
 114        int m;
 115
 116        if (mask != IIO_CHAN_INFO_CALIBBIAS)
 117                return -EINVAL;
 118
 119        switch (chan->type) {
 120        case IIO_ACCEL:
 121        case IIO_INCLI:
 122                m = GENMASK(13, 0);
 123                break;
 124        default:
 125                return -EINVAL;
 126        }
 127
 128        return adis_write_reg_16(st, adis16209_addresses[chan->scan_index][0],
 129                                 val & m);
 130}
 131
 132static int adis16209_read_raw(struct iio_dev *indio_dev,
 133                              struct iio_chan_spec const *chan,
 134                              int *val, int *val2,
 135                              long mask)
 136{
 137        struct adis *st = iio_priv(indio_dev);
 138        int ret;
 139        int bits;
 140        u8 addr;
 141        s16 val16;
 142
 143        switch (mask) {
 144        case IIO_CHAN_INFO_RAW:
 145                return adis_single_conversion(indio_dev, chan,
 146                        ADIS16209_ERROR_ACTIVE, val);
 147        case IIO_CHAN_INFO_SCALE:
 148                switch (chan->type) {
 149                case IIO_VOLTAGE:
 150                        *val = 0;
 151                        switch (chan->channel) {
 152                        case 0:
 153                                *val2 = 305180; /* 0.30518 mV */
 154                                break;
 155                        case 1:
 156                                *val2 = 610500; /* 0.6105 mV */
 157                                break;
 158                        default:
 159                                return -EINVAL;
 160                        }
 161                        return IIO_VAL_INT_PLUS_MICRO;
 162                case IIO_TEMP:
 163                        *val = -470;
 164                        *val2 = 0;
 165                        return IIO_VAL_INT_PLUS_MICRO;
 166                case IIO_ACCEL:
 167                        /*
 168                         * IIO base unit for sensitivity of accelerometer
 169                         * is milli g.
 170                         * 1 LSB represents 0.244 mg.
 171                         */
 172                        *val = 0;
 173                        *val2 = IIO_G_TO_M_S_2(244140);
 174                        return IIO_VAL_INT_PLUS_NANO;
 175                case IIO_INCLI:
 176                case IIO_ROT:
 177                        /*
 178                         * IIO base units for rotation are degrees.
 179                         * 1 LSB represents 0.025 milli degrees.
 180                         */
 181                        *val = 0;
 182                        *val2 = 25000;
 183                        return IIO_VAL_INT_PLUS_MICRO;
 184                default:
 185                        return -EINVAL;
 186                }
 187                break;
 188        case IIO_CHAN_INFO_OFFSET:
 189                /*
 190                 * The raw ADC value is 0x4FE when the temperature
 191                 * is 45 degrees and the scale factor per milli
 192                 * degree celcius is -470.
 193                 */
 194                *val = 25000 / -470 - 0x4FE;
 195                return IIO_VAL_INT;
 196        case IIO_CHAN_INFO_CALIBBIAS:
 197                switch (chan->type) {
 198                case IIO_ACCEL:
 199                        bits = 14;
 200                        break;
 201                default:
 202                        return -EINVAL;
 203                }
 204                addr = adis16209_addresses[chan->scan_index][0];
 205                ret = adis_read_reg_16(st, addr, &val16);
 206                if (ret)
 207                        return ret;
 208
 209                *val = sign_extend32(val16, bits - 1);
 210                return IIO_VAL_INT;
 211        }
 212        return -EINVAL;
 213}
 214
 215static const struct iio_chan_spec adis16209_channels[] = {
 216        ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT_REG, ADIS16209_SCAN_SUPPLY,
 217                         0, 14),
 218        ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT_REG, ADIS16209_SCAN_TEMP, 0, 12),
 219        ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT_REG, ADIS16209_SCAN_ACC_X,
 220                        BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
 221        ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT_REG, ADIS16209_SCAN_ACC_Y,
 222                        BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
 223        ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC_REG, ADIS16209_SCAN_AUX_ADC, 0, 12),
 224        ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT_REG, ADIS16209_SCAN_INCLI_X,
 225                        0, 0, 14),
 226        ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT_REG, ADIS16209_SCAN_INCLI_Y,
 227                        0, 0, 14),
 228        ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT_REG, ADIS16209_SCAN_ROT, 0, 0, 14),
 229        IIO_CHAN_SOFT_TIMESTAMP(8)
 230};
 231
 232static const struct iio_info adis16209_info = {
 233        .read_raw = adis16209_read_raw,
 234        .write_raw = adis16209_write_raw,
 235        .update_scan_mode = adis_update_scan_mode,
 236};
 237
 238static const char * const adis16209_status_error_msgs[] = {
 239        [ADIS16209_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
 240        [ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",
 241        [ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
 242        [ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
 243        [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
 244};
 245
 246static const struct adis_data adis16209_data = {
 247        .read_delay = 30,
 248        .msc_ctrl_reg = ADIS16209_MSC_CTRL_REG,
 249        .glob_cmd_reg = ADIS16209_CMD_REG,
 250        .diag_stat_reg = ADIS16209_STAT_REG,
 251
 252        .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
 253        .self_test_no_autoclear = true,
 254        .startup_delay = ADIS16209_STARTUP_DELAY_MS,
 255
 256        .status_error_msgs = adis16209_status_error_msgs,
 257        .status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) |
 258                BIT(ADIS16209_STAT_SPI_FAIL_BIT) |
 259                BIT(ADIS16209_STAT_FLASH_UPT_FAIL_BIT) |
 260                BIT(ADIS16209_STAT_POWER_HIGH_BIT) |
 261                BIT(ADIS16209_STAT_POWER_LOW_BIT),
 262};
 263
 264static int adis16209_probe(struct spi_device *spi)
 265{
 266        struct iio_dev *indio_dev;
 267        struct adis *st;
 268        int ret;
 269
 270        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 271        if (!indio_dev)
 272                return -ENOMEM;
 273
 274        st = iio_priv(indio_dev);
 275        spi_set_drvdata(spi, indio_dev);
 276
 277        indio_dev->name = spi->dev.driver->name;
 278        indio_dev->dev.parent = &spi->dev;
 279        indio_dev->info = &adis16209_info;
 280        indio_dev->channels = adis16209_channels;
 281        indio_dev->num_channels = ARRAY_SIZE(adis16209_channels);
 282        indio_dev->modes = INDIO_DIRECT_MODE;
 283
 284        ret = adis_init(st, indio_dev, spi, &adis16209_data);
 285        if (ret)
 286                return ret;
 287
 288        ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 289        if (ret)
 290                return ret;
 291
 292        ret = adis_initial_startup(st);
 293        if (ret)
 294                goto error_cleanup_buffer_trigger;
 295        ret = iio_device_register(indio_dev);
 296        if (ret)
 297                goto error_cleanup_buffer_trigger;
 298
 299        return 0;
 300
 301error_cleanup_buffer_trigger:
 302        adis_cleanup_buffer_and_trigger(st, indio_dev);
 303        return ret;
 304}
 305
 306static int adis16209_remove(struct spi_device *spi)
 307{
 308        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 309        struct adis *st = iio_priv(indio_dev);
 310
 311        iio_device_unregister(indio_dev);
 312        adis_cleanup_buffer_and_trigger(st, indio_dev);
 313
 314        return 0;
 315}
 316
 317static struct spi_driver adis16209_driver = {
 318        .driver = {
 319                .name = "adis16209",
 320        },
 321        .probe = adis16209_probe,
 322        .remove = adis16209_remove,
 323};
 324module_spi_driver(adis16209_driver);
 325
 326MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
 327MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer");
 328MODULE_LICENSE("GPL v2");
 329MODULE_ALIAS("spi:adis16209");
 330