brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 0035e4f Raw
314 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ADIS16209 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 ADIS16209_STARTUP_DELAY_MS	22017#define ADIS16209_FLASH_CNT_REG		0x0018 19/* Data Output Register Definitions */20#define ADIS16209_SUPPLY_OUT_REG	0x0221#define ADIS16209_XACCL_OUT_REG		0x0422#define ADIS16209_YACCL_OUT_REG		0x0623/* Output, auxiliary ADC input */24#define ADIS16209_AUX_ADC_REG		0x0825/* Output, temperature */26#define ADIS16209_TEMP_OUT_REG		0x0A27/* Output, +/- 90 degrees X-axis inclination */28#define ADIS16209_XINCL_OUT_REG		0x0C29#define ADIS16209_YINCL_OUT_REG		0x0E30/* Output, +/-180 vertical rotational position */31#define ADIS16209_ROT_OUT_REG		0x1032 33/*34 * Calibration Register Definitions.35 * Acceleration, inclination or rotation offset null.36 */37#define ADIS16209_XACCL_NULL_REG	0x1238#define ADIS16209_YACCL_NULL_REG	0x1439#define ADIS16209_XINCL_NULL_REG	0x1640#define ADIS16209_YINCL_NULL_REG	0x1841#define ADIS16209_ROT_NULL_REG		0x1A42 43/* Alarm Register Definitions */44#define ADIS16209_ALM_MAG1_REG		0x2045#define ADIS16209_ALM_MAG2_REG		0x2246#define ADIS16209_ALM_SMPL1_REG		0x2447#define ADIS16209_ALM_SMPL2_REG		0x2648#define ADIS16209_ALM_CTRL_REG		0x2849 50#define ADIS16209_AUX_DAC_REG		0x3051#define ADIS16209_GPIO_CTRL_REG		0x3252#define ADIS16209_SMPL_PRD_REG		0x3653#define ADIS16209_AVG_CNT_REG		0x3854#define ADIS16209_SLP_CNT_REG		0x3A55 56#define ADIS16209_MSC_CTRL_REG			0x3457#define  ADIS16209_MSC_CTRL_PWRUP_SELF_TEST	BIT(10)58#define  ADIS16209_MSC_CTRL_SELF_TEST_EN	BIT(8)59#define  ADIS16209_MSC_CTRL_DATA_RDY_EN		BIT(2)60/* Data-ready polarity: 1 = active high, 0 = active low */61#define  ADIS16209_MSC_CTRL_ACTIVE_HIGH		BIT(1)62#define  ADIS16209_MSC_CTRL_DATA_RDY_DIO2	BIT(0)63 64#define ADIS16209_STAT_REG			0x3C65#define  ADIS16209_STAT_ALARM2			BIT(9)66#define  ADIS16209_STAT_ALARM1			BIT(8)67#define  ADIS16209_STAT_SELFTEST_FAIL_BIT	568#define  ADIS16209_STAT_SPI_FAIL_BIT		369#define  ADIS16209_STAT_FLASH_UPT_FAIL_BIT	270/* Power supply above 3.625 V */71#define  ADIS16209_STAT_POWER_HIGH_BIT		172/* Power supply below 2.975 V */73#define  ADIS16209_STAT_POWER_LOW_BIT		074 75#define ADIS16209_CMD_REG			0x3E76#define  ADIS16209_CMD_SW_RESET			BIT(7)77#define  ADIS16209_CMD_CLEAR_STAT		BIT(4)78#define  ADIS16209_CMD_FACTORY_CAL		BIT(1)79 80#define ADIS16209_ERROR_ACTIVE			BIT(14)81 82enum adis16209_scan {83	ADIS16209_SCAN_SUPPLY,84	ADIS16209_SCAN_ACC_X,85	ADIS16209_SCAN_ACC_Y,86	ADIS16209_SCAN_AUX_ADC,87	ADIS16209_SCAN_TEMP,88	ADIS16209_SCAN_INCLI_X,89	ADIS16209_SCAN_INCLI_Y,90	ADIS16209_SCAN_ROT,91};92 93static const u8 adis16209_addresses[8][1] = {94	[ADIS16209_SCAN_SUPPLY] = { },95	[ADIS16209_SCAN_AUX_ADC] = { },96	[ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL_REG },97	[ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL_REG },98	[ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL_REG },99	[ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL_REG },100	[ADIS16209_SCAN_ROT] = { },101	[ADIS16209_SCAN_TEMP] = { },102};103 104static int adis16209_write_raw(struct iio_dev *indio_dev,105			       struct iio_chan_spec const *chan,106			       int val,107			       int val2,108			       long mask)109{110	struct adis *st = iio_priv(indio_dev);111	int m;112 113	if (mask != IIO_CHAN_INFO_CALIBBIAS)114		return -EINVAL;115 116	switch (chan->type) {117	case IIO_ACCEL:118	case IIO_INCLI:119		m = GENMASK(13, 0);120		break;121	default:122		return -EINVAL;123	}124 125	return adis_write_reg_16(st, adis16209_addresses[chan->scan_index][0],126				 val & m);127}128 129static int adis16209_read_raw(struct iio_dev *indio_dev,130			      struct iio_chan_spec const *chan,131			      int *val, int *val2,132			      long mask)133{134	struct adis *st = iio_priv(indio_dev);135	int ret;136	int bits;137	u8 addr;138	s16 val16;139 140	switch (mask) {141	case IIO_CHAN_INFO_RAW:142		return adis_single_conversion(indio_dev, chan,143			ADIS16209_ERROR_ACTIVE, val);144	case IIO_CHAN_INFO_SCALE:145		switch (chan->type) {146		case IIO_VOLTAGE:147			*val = 0;148			switch (chan->channel) {149			case 0:150				*val2 = 305180; /* 0.30518 mV */151				break;152			case 1:153				*val2 = 610500; /* 0.6105 mV */154				break;155			default:156				return -EINVAL;157			}158			return IIO_VAL_INT_PLUS_MICRO;159		case IIO_TEMP:160			*val = -470;161			*val2 = 0;162			return IIO_VAL_INT_PLUS_MICRO;163		case IIO_ACCEL:164			/*165			 * IIO base unit for sensitivity of accelerometer166			 * is milli g.167			 * 1 LSB represents 0.244 mg.168			 */169			*val = 0;170			*val2 = IIO_G_TO_M_S_2(244140);171			return IIO_VAL_INT_PLUS_NANO;172		case IIO_INCLI:173		case IIO_ROT:174			/*175			 * IIO base units for rotation are degrees.176			 * 1 LSB represents 0.025 milli degrees.177			 */178			*val = 0;179			*val2 = 25000;180			return IIO_VAL_INT_PLUS_MICRO;181		default:182			return -EINVAL;183		}184		break;185	case IIO_CHAN_INFO_OFFSET:186		/*187		 * The raw ADC value is 0x4FE when the temperature188		 * is 45 degrees and the scale factor per milli189		 * degree celcius is -470.190		 */191		*val = 25000 / -470 - 0x4FE;192		return IIO_VAL_INT;193	case IIO_CHAN_INFO_CALIBBIAS:194		switch (chan->type) {195		case IIO_ACCEL:196			bits = 14;197			break;198		default:199			return -EINVAL;200		}201		addr = adis16209_addresses[chan->scan_index][0];202		ret = adis_read_reg_16(st, addr, &val16);203		if (ret)204			return ret;205 206		*val = sign_extend32(val16, bits - 1);207		return IIO_VAL_INT;208	}209	return -EINVAL;210}211 212static const struct iio_chan_spec adis16209_channels[] = {213	ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT_REG, ADIS16209_SCAN_SUPPLY,214			 0, 14),215	ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT_REG, ADIS16209_SCAN_TEMP, 0, 12),216	ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT_REG, ADIS16209_SCAN_ACC_X,217			BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),218	ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT_REG, ADIS16209_SCAN_ACC_Y,219			BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14),220	ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC_REG, ADIS16209_SCAN_AUX_ADC, 0, 12),221	ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT_REG, ADIS16209_SCAN_INCLI_X,222			0, 0, 14),223	ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT_REG, ADIS16209_SCAN_INCLI_Y,224			0, 0, 14),225	ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT_REG, ADIS16209_SCAN_ROT, 0, 0, 14),226	IIO_CHAN_SOFT_TIMESTAMP(8)227};228 229static const struct iio_info adis16209_info = {230	.read_raw = adis16209_read_raw,231	.write_raw = adis16209_write_raw,232	.update_scan_mode = adis_update_scan_mode,233};234 235static const char * const adis16209_status_error_msgs[] = {236	[ADIS16209_STAT_SELFTEST_FAIL_BIT] = "Self test failure",237	[ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure",238	[ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed",239	[ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",240	[ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",241};242 243static const struct adis_timeout adis16209_timeouts = {244	.reset_ms = ADIS16209_STARTUP_DELAY_MS,245	.self_test_ms = ADIS16209_STARTUP_DELAY_MS,246	.sw_reset_ms = ADIS16209_STARTUP_DELAY_MS,247};248 249static const struct adis_data adis16209_data = {250	.read_delay = 30,251	.msc_ctrl_reg = ADIS16209_MSC_CTRL_REG,252	.glob_cmd_reg = ADIS16209_CMD_REG,253	.diag_stat_reg = ADIS16209_STAT_REG,254 255	.self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,256	.self_test_reg = ADIS16209_MSC_CTRL_REG,257	.self_test_no_autoclear = true,258	.timeouts = &adis16209_timeouts,259 260	.status_error_msgs = adis16209_status_error_msgs,261	.status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) |262		BIT(ADIS16209_STAT_SPI_FAIL_BIT) |263		BIT(ADIS16209_STAT_FLASH_UPT_FAIL_BIT) |264		BIT(ADIS16209_STAT_POWER_HIGH_BIT) |265		BIT(ADIS16209_STAT_POWER_LOW_BIT),266};267 268static int adis16209_probe(struct spi_device *spi)269{270	struct iio_dev *indio_dev;271	struct adis *st;272	int ret;273 274	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));275	if (!indio_dev)276		return -ENOMEM;277 278	st = iio_priv(indio_dev);279 280	indio_dev->name = spi->dev.driver->name;281	indio_dev->info = &adis16209_info;282	indio_dev->channels = adis16209_channels;283	indio_dev->num_channels = ARRAY_SIZE(adis16209_channels);284	indio_dev->modes = INDIO_DIRECT_MODE;285 286	ret = adis_init(st, indio_dev, spi, &adis16209_data);287	if (ret)288		return ret;289 290	ret = devm_adis_setup_buffer_and_trigger(st, indio_dev, NULL);291	if (ret)292		return ret;293 294	ret = __adis_initial_startup(st);295	if (ret)296		return ret;297 298	return devm_iio_device_register(&spi->dev, indio_dev);299}300 301static struct spi_driver adis16209_driver = {302	.driver = {303		.name = "adis16209",304	},305	.probe = adis16209_probe,306};307module_spi_driver(adis16209_driver);308 309MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");310MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer");311MODULE_LICENSE("GPL v2");312MODULE_ALIAS("spi:adis16209");313MODULE_IMPORT_NS(IIO_ADISLIB);314