304 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer4 *5 * Copyright 2010 Analog Devices Inc.6 */7 8#include <linux/device.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/spi/spi.h>12 13#include <linux/iio/iio.h>14#include <linux/iio/imu/adis.h>15 16#define ADIS16201_STARTUP_DELAY_MS 22017#define ADIS16201_FLASH_CNT 0x0018 19/* Data Output Register Information */20#define ADIS16201_SUPPLY_OUT_REG 0x0221#define ADIS16201_XACCL_OUT_REG 0x0422#define ADIS16201_YACCL_OUT_REG 0x0623#define ADIS16201_AUX_ADC_REG 0x0824#define ADIS16201_TEMP_OUT_REG 0x0A25#define ADIS16201_XINCL_OUT_REG 0x0C26#define ADIS16201_YINCL_OUT_REG 0x0E27 28/* Calibration Register Definition */29#define ADIS16201_XACCL_OFFS_REG 0x1030#define ADIS16201_YACCL_OFFS_REG 0x1231#define ADIS16201_XACCL_SCALE_REG 0x1432#define ADIS16201_YACCL_SCALE_REG 0x1633#define ADIS16201_XINCL_OFFS_REG 0x1834#define ADIS16201_YINCL_OFFS_REG 0x1A35#define ADIS16201_XINCL_SCALE_REG 0x1C36#define ADIS16201_YINCL_SCALE_REG 0x1E37 38/* Alarm Register Definition */39#define ADIS16201_ALM_MAG1_REG 0x2040#define ADIS16201_ALM_MAG2_REG 0x2241#define ADIS16201_ALM_SMPL1_REG 0x2442#define ADIS16201_ALM_SMPL2_REG 0x2643#define ADIS16201_ALM_CTRL_REG 0x2844 45#define ADIS16201_AUX_DAC_REG 0x3046#define ADIS16201_GPIO_CTRL_REG 0x3247#define ADIS16201_SMPL_PRD_REG 0x3648/* Operation, filter configuration */49#define ADIS16201_AVG_CNT_REG 0x3850#define ADIS16201_SLP_CNT_REG 0x3A51 52/* Miscellaneous Control Register Definition */53#define ADIS16201_MSC_CTRL_REG 0x3454#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8)55/* Data-ready enable: 1 = enabled, 0 = disabled */56#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2)57/* Data-ready polarity: 1 = active high, 0 = active low */58#define ADIS16201_MSC_CTRL_ACTIVE_DATA_RDY_HIGH BIT(1)59/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */60#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0)61 62/* Diagnostics System Status Register Definition */63#define ADIS16201_DIAG_STAT_REG 0x3C64#define ADIS16201_DIAG_STAT_ALARM2 BIT(9)65#define ADIS16201_DIAG_STAT_ALARM1 BIT(8)66#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 367#define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 268/* Power supply above 3.625 V */69#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 170/* Power supply below 2.975 V */71#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 072 73/* System Command Register Definition */74#define ADIS16201_GLOB_CMD_REG 0x3E75#define ADIS16201_GLOB_CMD_SW_RESET BIT(7)76#define ADIS16201_GLOB_CMD_FACTORY_RESET BIT(1)77 78#define ADIS16201_ERROR_ACTIVE BIT(14)79 80enum adis16201_scan {81 ADIS16201_SCAN_ACC_X,82 ADIS16201_SCAN_ACC_Y,83 ADIS16201_SCAN_INCLI_X,84 ADIS16201_SCAN_INCLI_Y,85 ADIS16201_SCAN_SUPPLY,86 ADIS16201_SCAN_AUX_ADC,87 ADIS16201_SCAN_TEMP,88};89 90static const u8 adis16201_addresses[] = {91 [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS_REG,92 [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS_REG,93 [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS_REG,94 [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS_REG,95};96 97static int adis16201_read_raw(struct iio_dev *indio_dev,98 struct iio_chan_spec const *chan,99 int *val, int *val2,100 long mask)101{102 struct adis *st = iio_priv(indio_dev);103 int ret;104 int bits;105 u8 addr;106 s16 val16;107 108 switch (mask) {109 case IIO_CHAN_INFO_RAW:110 return adis_single_conversion(indio_dev, chan,111 ADIS16201_ERROR_ACTIVE, val);112 case IIO_CHAN_INFO_SCALE:113 switch (chan->type) {114 case IIO_VOLTAGE:115 if (chan->channel == 0) {116 /* Voltage base units are mV hence 1.22 mV */117 *val = 1;118 *val2 = 220000;119 } else {120 /* Voltage base units are mV hence 0.61 mV */121 *val = 0;122 *val2 = 610000;123 }124 return IIO_VAL_INT_PLUS_MICRO;125 case IIO_TEMP:126 *val = -470;127 *val2 = 0;128 return IIO_VAL_INT_PLUS_MICRO;129 case IIO_ACCEL:130 /*131 * IIO base unit for sensitivity of accelerometer132 * is milli g.133 * 1 LSB represents 0.244 mg.134 */135 *val = 0;136 *val2 = IIO_G_TO_M_S_2(462400);137 return IIO_VAL_INT_PLUS_NANO;138 case IIO_INCLI:139 *val = 0;140 *val2 = 100000;141 return IIO_VAL_INT_PLUS_MICRO;142 default:143 return -EINVAL;144 }145 break;146 case IIO_CHAN_INFO_OFFSET:147 /*148 * The raw ADC value is 1278 when the temperature149 * is 25 degrees and the scale factor per milli150 * degree celcius is -470.151 */152 *val = 25000 / -470 - 1278;153 return IIO_VAL_INT;154 case IIO_CHAN_INFO_CALIBBIAS:155 switch (chan->type) {156 case IIO_ACCEL:157 bits = 12;158 break;159 case IIO_INCLI:160 bits = 9;161 break;162 default:163 return -EINVAL;164 }165 addr = adis16201_addresses[chan->scan_index];166 ret = adis_read_reg_16(st, addr, &val16);167 if (ret)168 return ret;169 170 *val = sign_extend32(val16, bits - 1);171 return IIO_VAL_INT;172 }173 174 return -EINVAL;175}176 177static int adis16201_write_raw(struct iio_dev *indio_dev,178 struct iio_chan_spec const *chan,179 int val,180 int val2,181 long mask)182{183 struct adis *st = iio_priv(indio_dev);184 int m;185 186 if (mask != IIO_CHAN_INFO_CALIBBIAS)187 return -EINVAL;188 189 switch (chan->type) {190 case IIO_ACCEL:191 m = GENMASK(11, 0);192 break;193 case IIO_INCLI:194 m = GENMASK(8, 0);195 break;196 default:197 return -EINVAL;198 }199 200 return adis_write_reg_16(st, adis16201_addresses[chan->scan_index],201 val & m);202}203 204static const struct iio_chan_spec adis16201_channels[] = {205 ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0,206 12),207 ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12),208 ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT_REG, ADIS16201_SCAN_ACC_X,209 BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),210 ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT_REG, ADIS16201_SCAN_ACC_Y,211 BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),212 ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12),213 ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X,214 BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),215 ADIS_INCLI_CHAN(Y, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y,216 BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),217 IIO_CHAN_SOFT_TIMESTAMP(7)218};219 220static const struct iio_info adis16201_info = {221 .read_raw = adis16201_read_raw,222 .write_raw = adis16201_write_raw,223 .update_scan_mode = adis_update_scan_mode,224};225 226static const char * const adis16201_status_error_msgs[] = {227 [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",228 [ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",229 [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",230 [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",231};232 233static const struct adis_timeout adis16201_timeouts = {234 .reset_ms = ADIS16201_STARTUP_DELAY_MS,235 .sw_reset_ms = ADIS16201_STARTUP_DELAY_MS,236 .self_test_ms = ADIS16201_STARTUP_DELAY_MS,237};238 239static const struct adis_data adis16201_data = {240 .read_delay = 20,241 .msc_ctrl_reg = ADIS16201_MSC_CTRL_REG,242 .glob_cmd_reg = ADIS16201_GLOB_CMD_REG,243 .diag_stat_reg = ADIS16201_DIAG_STAT_REG,244 245 .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,246 .self_test_reg = ADIS16201_MSC_CTRL_REG,247 .self_test_no_autoclear = true,248 .timeouts = &adis16201_timeouts,249 250 .status_error_msgs = adis16201_status_error_msgs,251 .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |252 BIT(ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT) |253 BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) |254 BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT),255};256 257static int adis16201_probe(struct spi_device *spi)258{259 struct iio_dev *indio_dev;260 struct adis *st;261 int ret;262 263 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));264 if (!indio_dev)265 return -ENOMEM;266 267 st = iio_priv(indio_dev);268 269 indio_dev->name = spi->dev.driver->name;270 indio_dev->info = &adis16201_info;271 272 indio_dev->channels = adis16201_channels;273 indio_dev->num_channels = ARRAY_SIZE(adis16201_channels);274 indio_dev->modes = INDIO_DIRECT_MODE;275 276 ret = adis_init(st, indio_dev, spi, &adis16201_data);277 if (ret)278 return ret;279 280 ret = devm_adis_setup_buffer_and_trigger(st, indio_dev, NULL);281 if (ret)282 return ret;283 284 ret = __adis_initial_startup(st);285 if (ret)286 return ret;287 288 return devm_iio_device_register(&spi->dev, indio_dev);289}290 291static struct spi_driver adis16201_driver = {292 .driver = {293 .name = "adis16201",294 },295 .probe = adis16201_probe,296};297module_spi_driver(adis16201_driver);298 299MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");300MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");301MODULE_LICENSE("GPL v2");302MODULE_ALIAS("spi:adis16201");303MODULE_IMPORT_NS(IIO_ADISLIB);304