Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer
0004  *
0005  * Copyright 2010 Analog Devices Inc.
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/spi/spi.h>
0012 
0013 #include <linux/iio/iio.h>
0014 #include <linux/iio/imu/adis.h>
0015 
0016 #define ADIS16209_STARTUP_DELAY_MS  220
0017 #define ADIS16209_FLASH_CNT_REG     0x00
0018 
0019 /* Data Output Register Definitions */
0020 #define ADIS16209_SUPPLY_OUT_REG    0x02
0021 #define ADIS16209_XACCL_OUT_REG     0x04
0022 #define ADIS16209_YACCL_OUT_REG     0x06
0023 /* Output, auxiliary ADC input */
0024 #define ADIS16209_AUX_ADC_REG       0x08
0025 /* Output, temperature */
0026 #define ADIS16209_TEMP_OUT_REG      0x0A
0027 /* Output, +/- 90 degrees X-axis inclination */
0028 #define ADIS16209_XINCL_OUT_REG     0x0C
0029 #define ADIS16209_YINCL_OUT_REG     0x0E
0030 /* Output, +/-180 vertical rotational position */
0031 #define ADIS16209_ROT_OUT_REG       0x10
0032 
0033 /*
0034  * Calibration Register Definitions.
0035  * Acceleration, inclination or rotation offset null.
0036  */
0037 #define ADIS16209_XACCL_NULL_REG    0x12
0038 #define ADIS16209_YACCL_NULL_REG    0x14
0039 #define ADIS16209_XINCL_NULL_REG    0x16
0040 #define ADIS16209_YINCL_NULL_REG    0x18
0041 #define ADIS16209_ROT_NULL_REG      0x1A
0042 
0043 /* Alarm Register Definitions */
0044 #define ADIS16209_ALM_MAG1_REG      0x20
0045 #define ADIS16209_ALM_MAG2_REG      0x22
0046 #define ADIS16209_ALM_SMPL1_REG     0x24
0047 #define ADIS16209_ALM_SMPL2_REG     0x26
0048 #define ADIS16209_ALM_CTRL_REG      0x28
0049 
0050 #define ADIS16209_AUX_DAC_REG       0x30
0051 #define ADIS16209_GPIO_CTRL_REG     0x32
0052 #define ADIS16209_SMPL_PRD_REG      0x36
0053 #define ADIS16209_AVG_CNT_REG       0x38
0054 #define ADIS16209_SLP_CNT_REG       0x3A
0055 
0056 #define ADIS16209_MSC_CTRL_REG          0x34
0057 #define  ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10)
0058 #define  ADIS16209_MSC_CTRL_SELF_TEST_EN    BIT(8)
0059 #define  ADIS16209_MSC_CTRL_DATA_RDY_EN     BIT(2)
0060 /* Data-ready polarity: 1 = active high, 0 = active low */
0061 #define  ADIS16209_MSC_CTRL_ACTIVE_HIGH     BIT(1)
0062 #define  ADIS16209_MSC_CTRL_DATA_RDY_DIO2   BIT(0)
0063 
0064 #define ADIS16209_STAT_REG          0x3C
0065 #define  ADIS16209_STAT_ALARM2          BIT(9)
0066 #define  ADIS16209_STAT_ALARM1          BIT(8)
0067 #define  ADIS16209_STAT_SELFTEST_FAIL_BIT   5
0068 #define  ADIS16209_STAT_SPI_FAIL_BIT        3
0069 #define  ADIS16209_STAT_FLASH_UPT_FAIL_BIT  2
0070 /* Power supply above 3.625 V */
0071 #define  ADIS16209_STAT_POWER_HIGH_BIT      1
0072 /* Power supply below 2.975 V */
0073 #define  ADIS16209_STAT_POWER_LOW_BIT       0
0074 
0075 #define ADIS16209_CMD_REG           0x3E
0076 #define  ADIS16209_CMD_SW_RESET         BIT(7)
0077 #define  ADIS16209_CMD_CLEAR_STAT       BIT(4)
0078 #define  ADIS16209_CMD_FACTORY_CAL      BIT(1)
0079 
0080 #define ADIS16209_ERROR_ACTIVE          BIT(14)
0081 
0082 enum adis16209_scan {
0083     ADIS16209_SCAN_SUPPLY,
0084     ADIS16209_SCAN_ACC_X,
0085     ADIS16209_SCAN_ACC_Y,
0086     ADIS16209_SCAN_AUX_ADC,
0087     ADIS16209_SCAN_TEMP,
0088     ADIS16209_SCAN_INCLI_X,
0089     ADIS16209_SCAN_INCLI_Y,
0090     ADIS16209_SCAN_ROT,
0091 };
0092 
0093 static const u8 adis16209_addresses[8][1] = {
0094     [ADIS16209_SCAN_SUPPLY] = { },
0095     [ADIS16209_SCAN_AUX_ADC] = { },
0096     [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL_REG },
0097     [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL_REG },
0098     [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL_REG },
0099     [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL_REG },
0100     [ADIS16209_SCAN_ROT] = { },
0101     [ADIS16209_SCAN_TEMP] = { },
0102 };
0103 
0104 static int adis16209_write_raw(struct iio_dev *indio_dev,
0105                    struct iio_chan_spec const *chan,
0106                    int val,
0107                    int val2,
0108                    long mask)
0109 {
0110     struct adis *st = iio_priv(indio_dev);
0111     int m;
0112 
0113     if (mask != IIO_CHAN_INFO_CALIBBIAS)
0114         return -EINVAL;
0115 
0116     switch (chan->type) {
0117     case IIO_ACCEL:
0118     case IIO_INCLI:
0119         m = GENMASK(13, 0);
0120         break;
0121     default:
0122         return -EINVAL;
0123     }
0124 
0125     return adis_write_reg_16(st, adis16209_addresses[chan->scan_index][0],
0126                  val & m);
0127 }
0128 
0129 static int adis16209_read_raw(struct iio_dev *indio_dev,
0130                   struct iio_chan_spec const *chan,
0131                   int *val, int *val2,
0132                   long mask)
0133 {
0134     struct adis *st = iio_priv(indio_dev);
0135     int ret;
0136     int bits;
0137     u8 addr;
0138     s16 val16;
0139 
0140     switch (mask) {
0141     case IIO_CHAN_INFO_RAW:
0142         return adis_single_conversion(indio_dev, chan,
0143             ADIS16209_ERROR_ACTIVE, val);
0144     case IIO_CHAN_INFO_SCALE:
0145         switch (chan->type) {
0146         case IIO_VOLTAGE:
0147             *val = 0;
0148             switch (chan->channel) {
0149             case 0:
0150                 *val2 = 305180; /* 0.30518 mV */
0151                 break;
0152             case 1:
0153                 *val2 = 610500; /* 0.6105 mV */
0154                 break;
0155             default:
0156                 return -EINVAL;
0157             }
0158             return IIO_VAL_INT_PLUS_MICRO;
0159         case IIO_TEMP:
0160             *val = -470;
0161             *val2 = 0;
0162             return IIO_VAL_INT_PLUS_MICRO;
0163         case IIO_ACCEL:
0164             /*
0165              * IIO base unit for sensitivity of accelerometer
0166              * is milli g.
0167              * 1 LSB represents 0.244 mg.
0168              */
0169             *val = 0;
0170             *val2 = IIO_G_TO_M_S_2(244140);
0171             return IIO_VAL_INT_PLUS_NANO;
0172         case IIO_INCLI:
0173         case IIO_ROT:
0174             /*
0175              * IIO base units for rotation are degrees.
0176              * 1 LSB represents 0.025 milli degrees.
0177              */
0178             *val = 0;
0179             *val2 = 25000;
0180             return IIO_VAL_INT_PLUS_MICRO;
0181         default:
0182             return -EINVAL;
0183         }
0184         break;
0185     case IIO_CHAN_INFO_OFFSET:
0186         /*
0187          * The raw ADC value is 0x4FE when the temperature
0188          * is 45 degrees and the scale factor per milli
0189          * degree celcius is -470.
0190          */
0191         *val = 25000 / -470 - 0x4FE;
0192         return IIO_VAL_INT;
0193     case IIO_CHAN_INFO_CALIBBIAS:
0194         switch (chan->type) {
0195         case IIO_ACCEL:
0196             bits = 14;
0197             break;
0198         default:
0199             return -EINVAL;
0200         }
0201         addr = adis16209_addresses[chan->scan_index][0];
0202         ret = adis_read_reg_16(st, addr, &val16);
0203         if (ret)
0204             return ret;
0205 
0206         *val = sign_extend32(val16, bits - 1);
0207         return IIO_VAL_INT;
0208     }
0209     return -EINVAL;
0210 }
0211 
0212 static const struct iio_chan_spec adis16209_channels[] = {
0213     ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT_REG, ADIS16209_SCAN_SUPPLY,
0214              0, 14),
0215     ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT_REG, ADIS16209_SCAN_TEMP, 0, 12),
0216     ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT_REG, ADIS16209_SCAN_ACC_X,
0217             BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
0218     ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT_REG, ADIS16209_SCAN_ACC_Y,
0219             BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),
0220     ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC_REG, ADIS16209_SCAN_AUX_ADC, 0, 12),
0221     ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT_REG, ADIS16209_SCAN_INCLI_X,
0222             0, 0, 14),
0223     ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT_REG, ADIS16209_SCAN_INCLI_Y,
0224             0, 0, 14),
0225     ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT_REG, ADIS16209_SCAN_ROT, 0, 0, 14),
0226     IIO_CHAN_SOFT_TIMESTAMP(8)
0227 };
0228 
0229 static const struct iio_info adis16209_info = {
0230     .read_raw = adis16209_read_raw,
0231     .write_raw = adis16209_write_raw,
0232     .update_scan_mode = adis_update_scan_mode,
0233 };
0234 
0235 static const char * const adis16209_status_error_msgs[] = {
0236     [ADIS16209_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
0237     [ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",
0238     [ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",
0239     [ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
0240     [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
0241 };
0242 
0243 static const struct adis_timeout adis16209_timeouts = {
0244     .reset_ms = ADIS16209_STARTUP_DELAY_MS,
0245     .self_test_ms = ADIS16209_STARTUP_DELAY_MS,
0246     .sw_reset_ms = ADIS16209_STARTUP_DELAY_MS,
0247 };
0248 
0249 static const struct adis_data adis16209_data = {
0250     .read_delay = 30,
0251     .msc_ctrl_reg = ADIS16209_MSC_CTRL_REG,
0252     .glob_cmd_reg = ADIS16209_CMD_REG,
0253     .diag_stat_reg = ADIS16209_STAT_REG,
0254 
0255     .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
0256     .self_test_reg = ADIS16209_MSC_CTRL_REG,
0257     .self_test_no_autoclear = true,
0258     .timeouts = &adis16209_timeouts,
0259 
0260     .status_error_msgs = adis16209_status_error_msgs,
0261     .status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) |
0262         BIT(ADIS16209_STAT_SPI_FAIL_BIT) |
0263         BIT(ADIS16209_STAT_FLASH_UPT_FAIL_BIT) |
0264         BIT(ADIS16209_STAT_POWER_HIGH_BIT) |
0265         BIT(ADIS16209_STAT_POWER_LOW_BIT),
0266 };
0267 
0268 static int adis16209_probe(struct spi_device *spi)
0269 {
0270     struct iio_dev *indio_dev;
0271     struct adis *st;
0272     int ret;
0273 
0274     indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
0275     if (!indio_dev)
0276         return -ENOMEM;
0277 
0278     st = iio_priv(indio_dev);
0279 
0280     indio_dev->name = spi->dev.driver->name;
0281     indio_dev->info = &adis16209_info;
0282     indio_dev->channels = adis16209_channels;
0283     indio_dev->num_channels = ARRAY_SIZE(adis16209_channels);
0284     indio_dev->modes = INDIO_DIRECT_MODE;
0285 
0286     ret = adis_init(st, indio_dev, spi, &adis16209_data);
0287     if (ret)
0288         return ret;
0289 
0290     ret = devm_adis_setup_buffer_and_trigger(st, indio_dev, NULL);
0291     if (ret)
0292         return ret;
0293 
0294     ret = adis_initial_startup(st);
0295     if (ret)
0296         return ret;
0297 
0298     return devm_iio_device_register(&spi->dev, indio_dev);
0299 }
0300 
0301 static struct spi_driver adis16209_driver = {
0302     .driver = {
0303         .name = "adis16209",
0304     },
0305     .probe = adis16209_probe,
0306 };
0307 module_spi_driver(adis16209_driver);
0308 
0309 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
0310 MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer");
0311 MODULE_LICENSE("GPL v2");
0312 MODULE_ALIAS("spi:adis16209");
0313 MODULE_IMPORT_NS(IIO_ADISLIB);