brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · d054721 Raw
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