xref: /openbmc/linux/drivers/iio/imu/adis16480.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22f3abe6cSLars-Peter Clausen /*
32f3abe6cSLars-Peter Clausen  * ADIS16480 and similar IMUs driver
42f3abe6cSLars-Peter Clausen  *
52f3abe6cSLars-Peter Clausen  * Copyright 2012 Analog Devices Inc.
62f3abe6cSLars-Peter Clausen  */
72f3abe6cSLars-Peter Clausen 
8326e2357SStefan Popa #include <linux/clk.h>
9cede2f89SStefan Popa #include <linux/bitfield.h>
102f3abe6cSLars-Peter Clausen #include <linux/interrupt.h>
119eec6e51SAndy Shevchenko #include <linux/irq.h>
120463e60fSNuno Sa #include <linux/math.h>
132f3abe6cSLars-Peter Clausen #include <linux/device.h>
142f3abe6cSLars-Peter Clausen #include <linux/kernel.h>
152f3abe6cSLars-Peter Clausen #include <linux/spi/spi.h>
169eec6e51SAndy Shevchenko #include <linux/mod_devicetable.h>
172f3abe6cSLars-Peter Clausen #include <linux/module.h>
180463e60fSNuno Sa #include <linux/lcm.h>
199eec6e51SAndy Shevchenko #include <linux/property.h>
20941f1308SNuno Sa #include <linux/swab.h>
21941f1308SNuno Sa #include <linux/crc32.h>
222f3abe6cSLars-Peter Clausen 
232f3abe6cSLars-Peter Clausen #include <linux/iio/iio.h>
242f3abe6cSLars-Peter Clausen #include <linux/iio/buffer.h>
252f3abe6cSLars-Peter Clausen #include <linux/iio/imu/adis.h>
26941f1308SNuno Sa #include <linux/iio/trigger_consumer.h>
272f3abe6cSLars-Peter Clausen 
282f3abe6cSLars-Peter Clausen #include <linux/debugfs.h>
292f3abe6cSLars-Peter Clausen 
302f3abe6cSLars-Peter Clausen #define ADIS16480_PAGE_SIZE 0x80
312f3abe6cSLars-Peter Clausen 
322f3abe6cSLars-Peter Clausen #define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
332f3abe6cSLars-Peter Clausen 
342f3abe6cSLars-Peter Clausen #define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
352f3abe6cSLars-Peter Clausen #define ADIS16480_REG_SEQ_CNT			ADIS16480_REG(0x00, 0x06)
362f3abe6cSLars-Peter Clausen #define ADIS16480_REG_SYS_E_FLA			ADIS16480_REG(0x00, 0x08)
372f3abe6cSLars-Peter Clausen #define ADIS16480_REG_DIAG_STS			ADIS16480_REG(0x00, 0x0A)
382f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ALM_STS			ADIS16480_REG(0x00, 0x0C)
392f3abe6cSLars-Peter Clausen #define ADIS16480_REG_TEMP_OUT			ADIS16480_REG(0x00, 0x0E)
402f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_GYRO_OUT		ADIS16480_REG(0x00, 0x10)
412f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_GYRO_OUT		ADIS16480_REG(0x00, 0x14)
422f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_GYRO_OUT		ADIS16480_REG(0x00, 0x18)
432f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_ACCEL_OUT		ADIS16480_REG(0x00, 0x1C)
442f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_ACCEL_OUT		ADIS16480_REG(0x00, 0x20)
452f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_ACCEL_OUT		ADIS16480_REG(0x00, 0x24)
462f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_MAGN_OUT		ADIS16480_REG(0x00, 0x28)
472f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_MAGN_OUT		ADIS16480_REG(0x00, 0x2A)
482f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_MAGN_OUT		ADIS16480_REG(0x00, 0x2C)
492f3abe6cSLars-Peter Clausen #define ADIS16480_REG_BAROM_OUT			ADIS16480_REG(0x00, 0x2E)
502f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_DELTAANG_OUT		ADIS16480_REG(0x00, 0x40)
512f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_DELTAANG_OUT		ADIS16480_REG(0x00, 0x44)
522f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_DELTAANG_OUT		ADIS16480_REG(0x00, 0x48)
532f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x4C)
542f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x50)
552f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x54)
562f3abe6cSLars-Peter Clausen #define ADIS16480_REG_PROD_ID			ADIS16480_REG(0x00, 0x7E)
572f3abe6cSLars-Peter Clausen 
582f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_GYRO_SCALE		ADIS16480_REG(0x02, 0x04)
592f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_GYRO_SCALE		ADIS16480_REG(0x02, 0x06)
602f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_GYRO_SCALE		ADIS16480_REG(0x02, 0x08)
612f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0A)
622f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0C)
632f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0E)
642f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_GYRO_BIAS		ADIS16480_REG(0x02, 0x10)
652f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_GYRO_BIAS		ADIS16480_REG(0x02, 0x14)
662f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_GYRO_BIAS		ADIS16480_REG(0x02, 0x18)
672f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_ACCEL_BIAS		ADIS16480_REG(0x02, 0x1C)
682f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_ACCEL_BIAS		ADIS16480_REG(0x02, 0x20)
692f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_ACCEL_BIAS		ADIS16480_REG(0x02, 0x24)
702f3abe6cSLars-Peter Clausen #define ADIS16480_REG_X_HARD_IRON		ADIS16480_REG(0x02, 0x28)
712f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Y_HARD_IRON		ADIS16480_REG(0x02, 0x2A)
722f3abe6cSLars-Peter Clausen #define ADIS16480_REG_Z_HARD_IRON		ADIS16480_REG(0x02, 0x2C)
732f3abe6cSLars-Peter Clausen #define ADIS16480_REG_BAROM_BIAS		ADIS16480_REG(0x02, 0x40)
742f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FLASH_CNT			ADIS16480_REG(0x02, 0x7C)
752f3abe6cSLars-Peter Clausen 
762f3abe6cSLars-Peter Clausen #define ADIS16480_REG_GLOB_CMD			ADIS16480_REG(0x03, 0x02)
772f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FNCTIO_CTRL		ADIS16480_REG(0x03, 0x06)
782f3abe6cSLars-Peter Clausen #define ADIS16480_REG_GPIO_CTRL			ADIS16480_REG(0x03, 0x08)
792f3abe6cSLars-Peter Clausen #define ADIS16480_REG_CONFIG			ADIS16480_REG(0x03, 0x0A)
802f3abe6cSLars-Peter Clausen #define ADIS16480_REG_DEC_RATE			ADIS16480_REG(0x03, 0x0C)
812f3abe6cSLars-Peter Clausen #define ADIS16480_REG_SLP_CNT			ADIS16480_REG(0x03, 0x10)
822f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FILTER_BNK0		ADIS16480_REG(0x03, 0x16)
832f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FILTER_BNK1		ADIS16480_REG(0x03, 0x18)
842f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ALM_CNFG0			ADIS16480_REG(0x03, 0x20)
852f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ALM_CNFG1			ADIS16480_REG(0x03, 0x22)
862f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ALM_CNFG2			ADIS16480_REG(0x03, 0x24)
872f3abe6cSLars-Peter Clausen #define ADIS16480_REG_XG_ALM_MAGN		ADIS16480_REG(0x03, 0x28)
882f3abe6cSLars-Peter Clausen #define ADIS16480_REG_YG_ALM_MAGN		ADIS16480_REG(0x03, 0x2A)
892f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ZG_ALM_MAGN		ADIS16480_REG(0x03, 0x2C)
902f3abe6cSLars-Peter Clausen #define ADIS16480_REG_XA_ALM_MAGN		ADIS16480_REG(0x03, 0x2E)
912f3abe6cSLars-Peter Clausen #define ADIS16480_REG_YA_ALM_MAGN		ADIS16480_REG(0x03, 0x30)
922f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ZA_ALM_MAGN		ADIS16480_REG(0x03, 0x32)
932f3abe6cSLars-Peter Clausen #define ADIS16480_REG_XM_ALM_MAGN		ADIS16480_REG(0x03, 0x34)
942f3abe6cSLars-Peter Clausen #define ADIS16480_REG_YM_ALM_MAGN		ADIS16480_REG(0x03, 0x36)
952f3abe6cSLars-Peter Clausen #define ADIS16480_REG_ZM_ALM_MAGN		ADIS16480_REG(0x03, 0x38)
962f3abe6cSLars-Peter Clausen #define ADIS16480_REG_BR_ALM_MAGN		ADIS16480_REG(0x03, 0x3A)
972f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FIRM_REV			ADIS16480_REG(0x03, 0x78)
982f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FIRM_DM			ADIS16480_REG(0x03, 0x7A)
992f3abe6cSLars-Peter Clausen #define ADIS16480_REG_FIRM_Y			ADIS16480_REG(0x03, 0x7C)
1002f3abe6cSLars-Peter Clausen 
101326e2357SStefan Popa /*
102326e2357SStefan Popa  * External clock scaling in PPS mode.
103326e2357SStefan Popa  * Available only for ADIS1649x devices
104326e2357SStefan Popa  */
105326e2357SStefan Popa #define ADIS16495_REG_SYNC_SCALE		ADIS16480_REG(0x03, 0x10)
106941f1308SNuno Sa #define ADIS16495_REG_BURST_CMD			ADIS16480_REG(0x00, 0x7C)
107941f1308SNuno Sa #define ADIS16495_BURST_ID			0xA5A5
108941f1308SNuno Sa /* total number of segments in burst */
109941f1308SNuno Sa #define ADIS16495_BURST_MAX_DATA		20
110941f1308SNuno Sa /* spi max speed in burst mode */
111941f1308SNuno Sa #define ADIS16495_BURST_MAX_SPEED              6000000
112326e2357SStefan Popa 
1132f3abe6cSLars-Peter Clausen #define ADIS16480_REG_SERIAL_NUM		ADIS16480_REG(0x04, 0x20)
1142f3abe6cSLars-Peter Clausen 
1152f3abe6cSLars-Peter Clausen /* Each filter coefficent bank spans two pages */
1162f3abe6cSLars-Peter Clausen #define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
1172f3abe6cSLars-Peter Clausen 		ADIS16480_REG((page) + 1, (x) - 60 + 8))
1182f3abe6cSLars-Peter Clausen #define ADIS16480_FIR_COEF_A(x)			ADIS16480_FIR_COEF(0x05, (x))
1192f3abe6cSLars-Peter Clausen #define ADIS16480_FIR_COEF_B(x)			ADIS16480_FIR_COEF(0x07, (x))
1202f3abe6cSLars-Peter Clausen #define ADIS16480_FIR_COEF_C(x)			ADIS16480_FIR_COEF(0x09, (x))
1212f3abe6cSLars-Peter Clausen #define ADIS16480_FIR_COEF_D(x)			ADIS16480_FIR_COEF(0x0B, (x))
1222f3abe6cSLars-Peter Clausen 
123cede2f89SStefan Popa /* ADIS16480_REG_FNCTIO_CTRL */
124cede2f89SStefan Popa #define ADIS16480_DRDY_SEL_MSK		GENMASK(1, 0)
125cede2f89SStefan Popa #define ADIS16480_DRDY_SEL(x)		FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x)
126cede2f89SStefan Popa #define ADIS16480_DRDY_POL_MSK		BIT(2)
127cede2f89SStefan Popa #define ADIS16480_DRDY_POL(x)		FIELD_PREP(ADIS16480_DRDY_POL_MSK, x)
128cede2f89SStefan Popa #define ADIS16480_DRDY_EN_MSK		BIT(3)
129cede2f89SStefan Popa #define ADIS16480_DRDY_EN(x)		FIELD_PREP(ADIS16480_DRDY_EN_MSK, x)
130326e2357SStefan Popa #define ADIS16480_SYNC_SEL_MSK		GENMASK(5, 4)
131326e2357SStefan Popa #define ADIS16480_SYNC_SEL(x)		FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x)
132326e2357SStefan Popa #define ADIS16480_SYNC_EN_MSK		BIT(7)
133326e2357SStefan Popa #define ADIS16480_SYNC_EN(x)		FIELD_PREP(ADIS16480_SYNC_EN_MSK, x)
134326e2357SStefan Popa #define ADIS16480_SYNC_MODE_MSK		BIT(8)
135326e2357SStefan Popa #define ADIS16480_SYNC_MODE(x)		FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
136cede2f89SStefan Popa 
1372f3abe6cSLars-Peter Clausen struct adis16480_chip_info {
1382f3abe6cSLars-Peter Clausen 	unsigned int num_channels;
1392f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *channels;
1407abad106SLars-Peter Clausen 	unsigned int gyro_max_val;
1417abad106SLars-Peter Clausen 	unsigned int gyro_max_scale;
1427abad106SLars-Peter Clausen 	unsigned int accel_max_val;
1437abad106SLars-Peter Clausen 	unsigned int accel_max_scale;
1446cf7b866SStefan Popa 	unsigned int temp_scale;
145e0e6398eSStefan Popa 	unsigned int int_clk;
146e0e6398eSStefan Popa 	unsigned int max_dec_rate;
14783ec2d54SStefan Popa 	const unsigned int *filter_freqs;
148326e2357SStefan Popa 	bool has_pps_clk_mode;
149ea1945c2SNuno Sá 	bool has_sleep_cnt;
15097928677SAlexandru Ardelean 	const struct adis_data adis_data;
1512f3abe6cSLars-Peter Clausen };
1522f3abe6cSLars-Peter Clausen 
153cede2f89SStefan Popa enum adis16480_int_pin {
154cede2f89SStefan Popa 	ADIS16480_PIN_DIO1,
155cede2f89SStefan Popa 	ADIS16480_PIN_DIO2,
156cede2f89SStefan Popa 	ADIS16480_PIN_DIO3,
157cede2f89SStefan Popa 	ADIS16480_PIN_DIO4
158cede2f89SStefan Popa };
159cede2f89SStefan Popa 
160326e2357SStefan Popa enum adis16480_clock_mode {
161326e2357SStefan Popa 	ADIS16480_CLK_SYNC,
162326e2357SStefan Popa 	ADIS16480_CLK_PPS,
163326e2357SStefan Popa 	ADIS16480_CLK_INT
164326e2357SStefan Popa };
165326e2357SStefan Popa 
1662f3abe6cSLars-Peter Clausen struct adis16480 {
1672f3abe6cSLars-Peter Clausen 	const struct adis16480_chip_info *chip_info;
1682f3abe6cSLars-Peter Clausen 
1692f3abe6cSLars-Peter Clausen 	struct adis adis;
170326e2357SStefan Popa 	struct clk *ext_clk;
171326e2357SStefan Popa 	enum adis16480_clock_mode clk_mode;
172326e2357SStefan Popa 	unsigned int clk_freq;
173941f1308SNuno Sa 	/* Alignment needed for the timestamp */
174941f1308SNuno Sa 	__be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
1752f3abe6cSLars-Peter Clausen };
1762f3abe6cSLars-Peter Clausen 
177cede2f89SStefan Popa static const char * const adis16480_int_pin_names[4] = {
178cede2f89SStefan Popa 	[ADIS16480_PIN_DIO1] = "DIO1",
179cede2f89SStefan Popa 	[ADIS16480_PIN_DIO2] = "DIO2",
180cede2f89SStefan Popa 	[ADIS16480_PIN_DIO3] = "DIO3",
181cede2f89SStefan Popa 	[ADIS16480_PIN_DIO4] = "DIO4",
182cede2f89SStefan Popa };
183cede2f89SStefan Popa 
1840463e60fSNuno Sa static bool low_rate_allow;
1850463e60fSNuno Sa module_param(low_rate_allow, bool, 0444);
1860463e60fSNuno Sa MODULE_PARM_DESC(low_rate_allow,
1870463e60fSNuno Sa 		 "Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)");
1880463e60fSNuno Sa 
1892f3abe6cSLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
1902f3abe6cSLars-Peter Clausen 
adis16480_show_firmware_revision(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)1912f3abe6cSLars-Peter Clausen static ssize_t adis16480_show_firmware_revision(struct file *file,
1922f3abe6cSLars-Peter Clausen 		char __user *userbuf, size_t count, loff_t *ppos)
1932f3abe6cSLars-Peter Clausen {
1942f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = file->private_data;
195afc3a57aSDan Carpenter 	char buf[7];
1962f3abe6cSLars-Peter Clausen 	size_t len;
1972f3abe6cSLars-Peter Clausen 	u16 rev;
1982f3abe6cSLars-Peter Clausen 	int ret;
1992f3abe6cSLars-Peter Clausen 
2002f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
20192c7529fSAlexandru Ardelean 	if (ret)
2022f3abe6cSLars-Peter Clausen 		return ret;
2032f3abe6cSLars-Peter Clausen 
204afc3a57aSDan Carpenter 	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
2052f3abe6cSLars-Peter Clausen 
2062f3abe6cSLars-Peter Clausen 	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
2072f3abe6cSLars-Peter Clausen }
2082f3abe6cSLars-Peter Clausen 
2092f3abe6cSLars-Peter Clausen static const struct file_operations adis16480_firmware_revision_fops = {
2102f3abe6cSLars-Peter Clausen 	.open = simple_open,
2112f3abe6cSLars-Peter Clausen 	.read = adis16480_show_firmware_revision,
2122f3abe6cSLars-Peter Clausen 	.llseek = default_llseek,
2132f3abe6cSLars-Peter Clausen 	.owner = THIS_MODULE,
2142f3abe6cSLars-Peter Clausen };
2152f3abe6cSLars-Peter Clausen 
adis16480_show_firmware_date(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)2162f3abe6cSLars-Peter Clausen static ssize_t adis16480_show_firmware_date(struct file *file,
2172f3abe6cSLars-Peter Clausen 		char __user *userbuf, size_t count, loff_t *ppos)
2182f3abe6cSLars-Peter Clausen {
2192f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = file->private_data;
2202f3abe6cSLars-Peter Clausen 	u16 md, year;
2212f3abe6cSLars-Peter Clausen 	char buf[12];
2222f3abe6cSLars-Peter Clausen 	size_t len;
2232f3abe6cSLars-Peter Clausen 	int ret;
2242f3abe6cSLars-Peter Clausen 
2252f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
22692c7529fSAlexandru Ardelean 	if (ret)
2272f3abe6cSLars-Peter Clausen 		return ret;
2282f3abe6cSLars-Peter Clausen 
2292f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
23092c7529fSAlexandru Ardelean 	if (ret)
2312f3abe6cSLars-Peter Clausen 		return ret;
2322f3abe6cSLars-Peter Clausen 
2332f3abe6cSLars-Peter Clausen 	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
2342f3abe6cSLars-Peter Clausen 			md >> 8, md & 0xff, year);
2352f3abe6cSLars-Peter Clausen 
2362f3abe6cSLars-Peter Clausen 	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
2372f3abe6cSLars-Peter Clausen }
2382f3abe6cSLars-Peter Clausen 
2392f3abe6cSLars-Peter Clausen static const struct file_operations adis16480_firmware_date_fops = {
2402f3abe6cSLars-Peter Clausen 	.open = simple_open,
2412f3abe6cSLars-Peter Clausen 	.read = adis16480_show_firmware_date,
2422f3abe6cSLars-Peter Clausen 	.llseek = default_llseek,
2432f3abe6cSLars-Peter Clausen 	.owner = THIS_MODULE,
2442f3abe6cSLars-Peter Clausen };
2452f3abe6cSLars-Peter Clausen 
adis16480_show_serial_number(void * arg,u64 * val)2462f3abe6cSLars-Peter Clausen static int adis16480_show_serial_number(void *arg, u64 *val)
2472f3abe6cSLars-Peter Clausen {
2482f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = arg;
2492f3abe6cSLars-Peter Clausen 	u16 serial;
2502f3abe6cSLars-Peter Clausen 	int ret;
2512f3abe6cSLars-Peter Clausen 
2522f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
2532f3abe6cSLars-Peter Clausen 		&serial);
25492c7529fSAlexandru Ardelean 	if (ret)
2552f3abe6cSLars-Peter Clausen 		return ret;
2562f3abe6cSLars-Peter Clausen 
2572f3abe6cSLars-Peter Clausen 	*val = serial;
2582f3abe6cSLars-Peter Clausen 
2592f3abe6cSLars-Peter Clausen 	return 0;
2602f3abe6cSLars-Peter Clausen }
2619bf94f83SVenkat Prashanth B U DEFINE_DEBUGFS_ATTRIBUTE(adis16480_serial_number_fops,
2622f3abe6cSLars-Peter Clausen 	adis16480_show_serial_number, NULL, "0x%.4llx\n");
2632f3abe6cSLars-Peter Clausen 
adis16480_show_product_id(void * arg,u64 * val)2642f3abe6cSLars-Peter Clausen static int adis16480_show_product_id(void *arg, u64 *val)
2652f3abe6cSLars-Peter Clausen {
2662f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = arg;
2672f3abe6cSLars-Peter Clausen 	u16 prod_id;
2682f3abe6cSLars-Peter Clausen 	int ret;
2692f3abe6cSLars-Peter Clausen 
2702f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
2712f3abe6cSLars-Peter Clausen 		&prod_id);
27292c7529fSAlexandru Ardelean 	if (ret)
2732f3abe6cSLars-Peter Clausen 		return ret;
2742f3abe6cSLars-Peter Clausen 
2752f3abe6cSLars-Peter Clausen 	*val = prod_id;
2762f3abe6cSLars-Peter Clausen 
2772f3abe6cSLars-Peter Clausen 	return 0;
2782f3abe6cSLars-Peter Clausen }
2799bf94f83SVenkat Prashanth B U DEFINE_DEBUGFS_ATTRIBUTE(adis16480_product_id_fops,
2802f3abe6cSLars-Peter Clausen 	adis16480_show_product_id, NULL, "%llu\n");
2812f3abe6cSLars-Peter Clausen 
adis16480_show_flash_count(void * arg,u64 * val)2822f3abe6cSLars-Peter Clausen static int adis16480_show_flash_count(void *arg, u64 *val)
2832f3abe6cSLars-Peter Clausen {
2842f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = arg;
2852f3abe6cSLars-Peter Clausen 	u32 flash_count;
2862f3abe6cSLars-Peter Clausen 	int ret;
2872f3abe6cSLars-Peter Clausen 
2882f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
2892f3abe6cSLars-Peter Clausen 		&flash_count);
29092c7529fSAlexandru Ardelean 	if (ret)
2912f3abe6cSLars-Peter Clausen 		return ret;
2922f3abe6cSLars-Peter Clausen 
2932f3abe6cSLars-Peter Clausen 	*val = flash_count;
2942f3abe6cSLars-Peter Clausen 
2952f3abe6cSLars-Peter Clausen 	return 0;
2962f3abe6cSLars-Peter Clausen }
2979bf94f83SVenkat Prashanth B U DEFINE_DEBUGFS_ATTRIBUTE(adis16480_flash_count_fops,
2982f3abe6cSLars-Peter Clausen 	adis16480_show_flash_count, NULL, "%lld\n");
2992f3abe6cSLars-Peter Clausen 
adis16480_debugfs_init(struct iio_dev * indio_dev)3002f3abe6cSLars-Peter Clausen static int adis16480_debugfs_init(struct iio_dev *indio_dev)
3012f3abe6cSLars-Peter Clausen {
3022f3abe6cSLars-Peter Clausen 	struct adis16480 *adis16480 = iio_priv(indio_dev);
303b7190859SAlexandru Ardelean 	struct dentry *d = iio_get_debugfs_dentry(indio_dev);
3042f3abe6cSLars-Peter Clausen 
3059bf94f83SVenkat Prashanth B U 	debugfs_create_file_unsafe("firmware_revision", 0400,
306b7190859SAlexandru Ardelean 		d, adis16480, &adis16480_firmware_revision_fops);
3079bf94f83SVenkat Prashanth B U 	debugfs_create_file_unsafe("firmware_date", 0400,
308b7190859SAlexandru Ardelean 		d, adis16480, &adis16480_firmware_date_fops);
3099bf94f83SVenkat Prashanth B U 	debugfs_create_file_unsafe("serial_number", 0400,
310b7190859SAlexandru Ardelean 		d, adis16480, &adis16480_serial_number_fops);
3119bf94f83SVenkat Prashanth B U 	debugfs_create_file_unsafe("product_id", 0400,
312b7190859SAlexandru Ardelean 		d, adis16480, &adis16480_product_id_fops);
3139bf94f83SVenkat Prashanth B U 	debugfs_create_file_unsafe("flash_count", 0400,
314b7190859SAlexandru Ardelean 		d, adis16480, &adis16480_flash_count_fops);
3152f3abe6cSLars-Peter Clausen 
3162f3abe6cSLars-Peter Clausen 	return 0;
3172f3abe6cSLars-Peter Clausen }
3182f3abe6cSLars-Peter Clausen 
3192f3abe6cSLars-Peter Clausen #else
3202f3abe6cSLars-Peter Clausen 
adis16480_debugfs_init(struct iio_dev * indio_dev)3212f3abe6cSLars-Peter Clausen static int adis16480_debugfs_init(struct iio_dev *indio_dev)
3222f3abe6cSLars-Peter Clausen {
3232f3abe6cSLars-Peter Clausen 	return 0;
3242f3abe6cSLars-Peter Clausen }
3252f3abe6cSLars-Peter Clausen 
3262f3abe6cSLars-Peter Clausen #endif
3272f3abe6cSLars-Peter Clausen 
adis16480_set_freq(struct iio_dev * indio_dev,int val,int val2)328e4f95939SJonathan Cameron static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
3292f3abe6cSLars-Peter Clausen {
330e4f95939SJonathan Cameron 	struct adis16480 *st = iio_priv(indio_dev);
3310463e60fSNuno Sa 	unsigned int t, sample_rate = st->clk_freq;
3320463e60fSNuno Sa 	int ret;
3332f3abe6cSLars-Peter Clausen 
33424e1eb5cSAlexandru Ardelean 	if (val < 0 || val2 < 0)
33524e1eb5cSAlexandru Ardelean 		return -EINVAL;
33624e1eb5cSAlexandru Ardelean 
337e4f95939SJonathan Cameron 	t =  val * 1000 + val2 / 1000;
33824e1eb5cSAlexandru Ardelean 	if (t == 0)
339e4f95939SJonathan Cameron 		return -EINVAL;
340e4f95939SJonathan Cameron 
34115aacc98SNuno Sa 	adis_dev_lock(&st->adis);
342326e2357SStefan Popa 	/*
3430463e60fSNuno Sa 	 * When using PPS mode, the input clock needs to be scaled so that we have an IMU
3440463e60fSNuno Sa 	 * sample rate between (optimally) 4000 and 4250. After this, we can use the
3450463e60fSNuno Sa 	 * decimation filter to lower the sampling rate in order to get what the user wants.
3460463e60fSNuno Sa 	 * Optimally, the user sample rate is a multiple of both the IMU sample rate and
3470463e60fSNuno Sa 	 * the input clock. Hence, calculating the sync_scale dynamically gives us better
3480463e60fSNuno Sa 	 * chances of achieving a perfect/integer value for DEC_RATE. The math here is:
3490463e60fSNuno Sa 	 *	1. lcm of the input clock and the desired output rate.
3500463e60fSNuno Sa 	 *	2. get the highest multiple of the previous result lower than the adis max rate.
3510463e60fSNuno Sa 	 *	3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE
3520463e60fSNuno Sa 	 *	   and DEC_RATE (to get the user output rate)
353326e2357SStefan Popa 	 */
354326e2357SStefan Popa 	if (st->clk_mode == ADIS16480_CLK_PPS) {
3550463e60fSNuno Sa 		unsigned long scaled_rate = lcm(st->clk_freq, t);
3560463e60fSNuno Sa 		int sync_scale;
3570463e60fSNuno Sa 
3580463e60fSNuno Sa 		/*
3590463e60fSNuno Sa 		 * If lcm is bigger than the IMU maximum sampling rate there's no perfect
3600463e60fSNuno Sa 		 * solution. In this case, we get the highest multiple of the input clock
3610463e60fSNuno Sa 		 * lower than the IMU max sample rate.
3620463e60fSNuno Sa 		 */
3630463e60fSNuno Sa 		if (scaled_rate > st->chip_info->int_clk)
3640463e60fSNuno Sa 			scaled_rate = st->chip_info->int_clk / st->clk_freq * st->clk_freq;
3650463e60fSNuno Sa 		else
3660463e60fSNuno Sa 			scaled_rate = st->chip_info->int_clk / scaled_rate * scaled_rate;
3670463e60fSNuno Sa 
3680463e60fSNuno Sa 		/*
3690463e60fSNuno Sa 		 * This is not an hard requirement but it's not advised to run the IMU
3700463e60fSNuno Sa 		 * with a sample rate lower than 4000Hz due to possible undersampling
3710463e60fSNuno Sa 		 * issues. However, there are users that might really want to take the risk.
3720463e60fSNuno Sa 		 * Hence, we provide a module parameter for them. If set, we allow sample
3730463e60fSNuno Sa 		 * rates lower than 4KHz. By default, we won't allow this and we just roundup
3740463e60fSNuno Sa 		 * the rate to the next multiple of the input clock bigger than 4KHz. This
3750463e60fSNuno Sa 		 * is done like this as in some cases (when DEC_RATE is 0) might give
3760463e60fSNuno Sa 		 * us the closest value to the one desired by the user...
3770463e60fSNuno Sa 		 */
3780463e60fSNuno Sa 		if (scaled_rate < 4000000 && !low_rate_allow)
3790463e60fSNuno Sa 			scaled_rate = roundup(4000000, st->clk_freq);
3800463e60fSNuno Sa 
3810463e60fSNuno Sa 		sync_scale = scaled_rate / st->clk_freq;
3820463e60fSNuno Sa 		ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
3830463e60fSNuno Sa 		if (ret)
3840463e60fSNuno Sa 			goto error;
3850463e60fSNuno Sa 
3860463e60fSNuno Sa 		sample_rate = scaled_rate;
387326e2357SStefan Popa 	}
388326e2357SStefan Popa 
3890463e60fSNuno Sa 	t = DIV_ROUND_CLOSEST(sample_rate, t);
3900463e60fSNuno Sa 	if (t)
3910463e60fSNuno Sa 		t--;
3920463e60fSNuno Sa 
393e0e6398eSStefan Popa 	if (t > st->chip_info->max_dec_rate)
394e0e6398eSStefan Popa 		t = st->chip_info->max_dec_rate;
3952f3abe6cSLars-Peter Clausen 
3960463e60fSNuno Sa 	ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
3970463e60fSNuno Sa error:
39815aacc98SNuno Sa 	adis_dev_unlock(&st->adis);
3990463e60fSNuno Sa 	return ret;
4002f3abe6cSLars-Peter Clausen }
4012f3abe6cSLars-Peter Clausen 
adis16480_get_freq(struct iio_dev * indio_dev,int * val,int * val2)402e4f95939SJonathan Cameron static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
4032f3abe6cSLars-Peter Clausen {
404e4f95939SJonathan Cameron 	struct adis16480 *st = iio_priv(indio_dev);
4052f3abe6cSLars-Peter Clausen 	uint16_t t;
4062f3abe6cSLars-Peter Clausen 	int ret;
4070463e60fSNuno Sa 	unsigned int freq, sample_rate = st->clk_freq;
4082f3abe6cSLars-Peter Clausen 
40915aacc98SNuno Sa 	adis_dev_lock(&st->adis);
410326e2357SStefan Popa 
4110463e60fSNuno Sa 	if (st->clk_mode == ADIS16480_CLK_PPS) {
4120463e60fSNuno Sa 		u16 sync_scale;
4130463e60fSNuno Sa 
4140463e60fSNuno Sa 		ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
41592c7529fSAlexandru Ardelean 		if (ret)
4160463e60fSNuno Sa 			goto error;
4172f3abe6cSLars-Peter Clausen 
4180463e60fSNuno Sa 		sample_rate = st->clk_freq * sync_scale;
4190463e60fSNuno Sa 	}
4200463e60fSNuno Sa 
4210463e60fSNuno Sa 	ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
4220463e60fSNuno Sa 	if (ret)
4230463e60fSNuno Sa 		goto error;
4240463e60fSNuno Sa 
42515aacc98SNuno Sa 	adis_dev_unlock(&st->adis);
4260463e60fSNuno Sa 
4270463e60fSNuno Sa 	freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
428326e2357SStefan Popa 
429e4f95939SJonathan Cameron 	*val = freq / 1000;
430e4f95939SJonathan Cameron 	*val2 = (freq % 1000) * 1000;
4312f3abe6cSLars-Peter Clausen 
432e4f95939SJonathan Cameron 	return IIO_VAL_INT_PLUS_MICRO;
4330463e60fSNuno Sa error:
43415aacc98SNuno Sa 	adis_dev_unlock(&st->adis);
4350463e60fSNuno Sa 	return ret;
4362f3abe6cSLars-Peter Clausen }
4372f3abe6cSLars-Peter Clausen 
4382f3abe6cSLars-Peter Clausen enum {
4392f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_GYRO_X,
4402f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_GYRO_Y,
4412f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_GYRO_Z,
4422f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_ACCEL_X,
4432f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_ACCEL_Y,
4442f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_ACCEL_Z,
4452f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_MAGN_X,
4462f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_MAGN_Y,
4472f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_MAGN_Z,
4482f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_BARO,
4492f3abe6cSLars-Peter Clausen 	ADIS16480_SCAN_TEMP,
4502f3abe6cSLars-Peter Clausen };
4512f3abe6cSLars-Peter Clausen 
4522f3abe6cSLars-Peter Clausen static const unsigned int adis16480_calibbias_regs[] = {
4532f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS,
4542f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS,
4552f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS,
4562f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS,
4572f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS,
4582f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS,
4592f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON,
4602f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON,
4612f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON,
4622f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS,
4632f3abe6cSLars-Peter Clausen };
4642f3abe6cSLars-Peter Clausen 
4652f3abe6cSLars-Peter Clausen static const unsigned int adis16480_calibscale_regs[] = {
4662f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE,
4672f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE,
4682f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE,
4692f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE,
4702f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE,
4712f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE,
4722f3abe6cSLars-Peter Clausen };
4732f3abe6cSLars-Peter Clausen 
adis16480_set_calibbias(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int bias)4742f3abe6cSLars-Peter Clausen static int adis16480_set_calibbias(struct iio_dev *indio_dev,
4752f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int bias)
4762f3abe6cSLars-Peter Clausen {
4772f3abe6cSLars-Peter Clausen 	unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
4782f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
4792f3abe6cSLars-Peter Clausen 
4802f3abe6cSLars-Peter Clausen 	switch (chan->type) {
4812f3abe6cSLars-Peter Clausen 	case IIO_MAGN:
4822f3abe6cSLars-Peter Clausen 	case IIO_PRESSURE:
4832f3abe6cSLars-Peter Clausen 		if (bias < -0x8000 || bias >= 0x8000)
4842f3abe6cSLars-Peter Clausen 			return -EINVAL;
4852f3abe6cSLars-Peter Clausen 		return adis_write_reg_16(&st->adis, reg, bias);
4862f3abe6cSLars-Peter Clausen 	case IIO_ANGL_VEL:
4872f3abe6cSLars-Peter Clausen 	case IIO_ACCEL:
4882f3abe6cSLars-Peter Clausen 		return adis_write_reg_32(&st->adis, reg, bias);
4892f3abe6cSLars-Peter Clausen 	default:
4902f3abe6cSLars-Peter Clausen 		break;
4912f3abe6cSLars-Peter Clausen 	}
4922f3abe6cSLars-Peter Clausen 
4932f3abe6cSLars-Peter Clausen 	return -EINVAL;
4942f3abe6cSLars-Peter Clausen }
4952f3abe6cSLars-Peter Clausen 
adis16480_get_calibbias(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * bias)4962f3abe6cSLars-Peter Clausen static int adis16480_get_calibbias(struct iio_dev *indio_dev,
4972f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int *bias)
4982f3abe6cSLars-Peter Clausen {
4992f3abe6cSLars-Peter Clausen 	unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
5002f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
5012f3abe6cSLars-Peter Clausen 	uint16_t val16;
5022f3abe6cSLars-Peter Clausen 	uint32_t val32;
5032f3abe6cSLars-Peter Clausen 	int ret;
5042f3abe6cSLars-Peter Clausen 
5052f3abe6cSLars-Peter Clausen 	switch (chan->type) {
5062f3abe6cSLars-Peter Clausen 	case IIO_MAGN:
5072f3abe6cSLars-Peter Clausen 	case IIO_PRESSURE:
5082f3abe6cSLars-Peter Clausen 		ret = adis_read_reg_16(&st->adis, reg, &val16);
5099b742763SAlexandru Ardelean 		if (ret == 0)
5102f3abe6cSLars-Peter Clausen 			*bias = sign_extend32(val16, 15);
5112f3abe6cSLars-Peter Clausen 		break;
5122f3abe6cSLars-Peter Clausen 	case IIO_ANGL_VEL:
5132f3abe6cSLars-Peter Clausen 	case IIO_ACCEL:
5142f3abe6cSLars-Peter Clausen 		ret = adis_read_reg_32(&st->adis, reg, &val32);
5159b742763SAlexandru Ardelean 		if (ret == 0)
5162f3abe6cSLars-Peter Clausen 			*bias = sign_extend32(val32, 31);
5172f3abe6cSLars-Peter Clausen 		break;
5182f3abe6cSLars-Peter Clausen 	default:
5192f3abe6cSLars-Peter Clausen 		ret = -EINVAL;
5202f3abe6cSLars-Peter Clausen 	}
5212f3abe6cSLars-Peter Clausen 
52292c7529fSAlexandru Ardelean 	if (ret)
5232f3abe6cSLars-Peter Clausen 		return ret;
5242f3abe6cSLars-Peter Clausen 
5252f3abe6cSLars-Peter Clausen 	return IIO_VAL_INT;
5262f3abe6cSLars-Peter Clausen }
5272f3abe6cSLars-Peter Clausen 
adis16480_set_calibscale(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int scale)5282f3abe6cSLars-Peter Clausen static int adis16480_set_calibscale(struct iio_dev *indio_dev,
5292f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int scale)
5302f3abe6cSLars-Peter Clausen {
5312f3abe6cSLars-Peter Clausen 	unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
5322f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
5332f3abe6cSLars-Peter Clausen 
5342f3abe6cSLars-Peter Clausen 	if (scale < -0x8000 || scale >= 0x8000)
5352f3abe6cSLars-Peter Clausen 		return -EINVAL;
5362f3abe6cSLars-Peter Clausen 
5372f3abe6cSLars-Peter Clausen 	return adis_write_reg_16(&st->adis, reg, scale);
5382f3abe6cSLars-Peter Clausen }
5392f3abe6cSLars-Peter Clausen 
adis16480_get_calibscale(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * scale)5402f3abe6cSLars-Peter Clausen static int adis16480_get_calibscale(struct iio_dev *indio_dev,
5412f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int *scale)
5422f3abe6cSLars-Peter Clausen {
5432f3abe6cSLars-Peter Clausen 	unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
5442f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
5452f3abe6cSLars-Peter Clausen 	uint16_t val16;
5462f3abe6cSLars-Peter Clausen 	int ret;
5472f3abe6cSLars-Peter Clausen 
5482f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&st->adis, reg, &val16);
54992c7529fSAlexandru Ardelean 	if (ret)
5502f3abe6cSLars-Peter Clausen 		return ret;
5512f3abe6cSLars-Peter Clausen 
5522f3abe6cSLars-Peter Clausen 	*scale = sign_extend32(val16, 15);
5532f3abe6cSLars-Peter Clausen 	return IIO_VAL_INT;
5542f3abe6cSLars-Peter Clausen }
5552f3abe6cSLars-Peter Clausen 
5562f3abe6cSLars-Peter Clausen static const unsigned int adis16480_def_filter_freqs[] = {
5572f3abe6cSLars-Peter Clausen 	310,
5582f3abe6cSLars-Peter Clausen 	55,
5592f3abe6cSLars-Peter Clausen 	275,
5602f3abe6cSLars-Peter Clausen 	63,
5612f3abe6cSLars-Peter Clausen };
5622f3abe6cSLars-Peter Clausen 
56382e7a1b2SStefan Popa static const unsigned int adis16495_def_filter_freqs[] = {
56482e7a1b2SStefan Popa 	300,
56582e7a1b2SStefan Popa 	100,
56682e7a1b2SStefan Popa 	300,
56782e7a1b2SStefan Popa 	100,
56882e7a1b2SStefan Popa };
56982e7a1b2SStefan Popa 
5702f3abe6cSLars-Peter Clausen static const unsigned int ad16480_filter_data[][2] = {
5712f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_X]		= { ADIS16480_REG_FILTER_BNK0, 0 },
5722f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Y]		= { ADIS16480_REG_FILTER_BNK0, 3 },
5732f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_GYRO_Z]		= { ADIS16480_REG_FILTER_BNK0, 6 },
5742f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_X]	= { ADIS16480_REG_FILTER_BNK0, 9 },
5752f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Y]	= { ADIS16480_REG_FILTER_BNK0, 12 },
5762f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_ACCEL_Z]	= { ADIS16480_REG_FILTER_BNK1, 0 },
5772f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_X]		= { ADIS16480_REG_FILTER_BNK1, 3 },
5782f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_Y]		= { ADIS16480_REG_FILTER_BNK1, 6 },
5792f3abe6cSLars-Peter Clausen 	[ADIS16480_SCAN_MAGN_Z]		= { ADIS16480_REG_FILTER_BNK1, 9 },
5802f3abe6cSLars-Peter Clausen };
5812f3abe6cSLars-Peter Clausen 
adis16480_get_filter_freq(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * freq)5822f3abe6cSLars-Peter Clausen static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
5832f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int *freq)
5842f3abe6cSLars-Peter Clausen {
5852f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
5862f3abe6cSLars-Peter Clausen 	unsigned int enable_mask, offset, reg;
5872f3abe6cSLars-Peter Clausen 	uint16_t val;
5882f3abe6cSLars-Peter Clausen 	int ret;
5892f3abe6cSLars-Peter Clausen 
5902f3abe6cSLars-Peter Clausen 	reg = ad16480_filter_data[chan->scan_index][0];
5912f3abe6cSLars-Peter Clausen 	offset = ad16480_filter_data[chan->scan_index][1];
5922f3abe6cSLars-Peter Clausen 	enable_mask = BIT(offset + 2);
5932f3abe6cSLars-Peter Clausen 
5942f3abe6cSLars-Peter Clausen 	ret = adis_read_reg_16(&st->adis, reg, &val);
59592c7529fSAlexandru Ardelean 	if (ret)
5962f3abe6cSLars-Peter Clausen 		return ret;
5972f3abe6cSLars-Peter Clausen 
5982f3abe6cSLars-Peter Clausen 	if (!(val & enable_mask))
5992f3abe6cSLars-Peter Clausen 		*freq = 0;
6002f3abe6cSLars-Peter Clausen 	else
60183ec2d54SStefan Popa 		*freq = st->chip_info->filter_freqs[(val >> offset) & 0x3];
6022f3abe6cSLars-Peter Clausen 
6032f3abe6cSLars-Peter Clausen 	return IIO_VAL_INT;
6042f3abe6cSLars-Peter Clausen }
6052f3abe6cSLars-Peter Clausen 
adis16480_set_filter_freq(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,unsigned int freq)6062f3abe6cSLars-Peter Clausen static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
6072f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, unsigned int freq)
6082f3abe6cSLars-Peter Clausen {
6092f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
6102f3abe6cSLars-Peter Clausen 	unsigned int enable_mask, offset, reg;
6112f3abe6cSLars-Peter Clausen 	unsigned int diff, best_diff;
6122f3abe6cSLars-Peter Clausen 	unsigned int i, best_freq;
6132f3abe6cSLars-Peter Clausen 	uint16_t val;
6142f3abe6cSLars-Peter Clausen 	int ret;
6152f3abe6cSLars-Peter Clausen 
6162f3abe6cSLars-Peter Clausen 	reg = ad16480_filter_data[chan->scan_index][0];
6172f3abe6cSLars-Peter Clausen 	offset = ad16480_filter_data[chan->scan_index][1];
6182f3abe6cSLars-Peter Clausen 	enable_mask = BIT(offset + 2);
6192f3abe6cSLars-Peter Clausen 
62015aacc98SNuno Sa 	adis_dev_lock(&st->adis);
621d693845dSAlexandru Ardelean 
622d693845dSAlexandru Ardelean 	ret = __adis_read_reg_16(&st->adis, reg, &val);
62392c7529fSAlexandru Ardelean 	if (ret)
624d693845dSAlexandru Ardelean 		goto out_unlock;
6252f3abe6cSLars-Peter Clausen 
6262f3abe6cSLars-Peter Clausen 	if (freq == 0) {
6272f3abe6cSLars-Peter Clausen 		val &= ~enable_mask;
6282f3abe6cSLars-Peter Clausen 	} else {
6292f3abe6cSLars-Peter Clausen 		best_freq = 0;
63083ec2d54SStefan Popa 		best_diff = st->chip_info->filter_freqs[0];
6312f3abe6cSLars-Peter Clausen 		for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
63283ec2d54SStefan Popa 			if (st->chip_info->filter_freqs[i] >= freq) {
63383ec2d54SStefan Popa 				diff = st->chip_info->filter_freqs[i] - freq;
6342f3abe6cSLars-Peter Clausen 				if (diff < best_diff) {
6352f3abe6cSLars-Peter Clausen 					best_diff = diff;
6362f3abe6cSLars-Peter Clausen 					best_freq = i;
6372f3abe6cSLars-Peter Clausen 				}
6382f3abe6cSLars-Peter Clausen 			}
6392f3abe6cSLars-Peter Clausen 		}
6402f3abe6cSLars-Peter Clausen 
6412f3abe6cSLars-Peter Clausen 		val &= ~(0x3 << offset);
6422f3abe6cSLars-Peter Clausen 		val |= best_freq << offset;
6432f3abe6cSLars-Peter Clausen 		val |= enable_mask;
6442f3abe6cSLars-Peter Clausen 	}
6452f3abe6cSLars-Peter Clausen 
646d693845dSAlexandru Ardelean 	ret = __adis_write_reg_16(&st->adis, reg, val);
647d693845dSAlexandru Ardelean out_unlock:
64815aacc98SNuno Sa 	adis_dev_unlock(&st->adis);
649d693845dSAlexandru Ardelean 
650d693845dSAlexandru Ardelean 	return ret;
6512f3abe6cSLars-Peter Clausen }
6522f3abe6cSLars-Peter Clausen 
adis16480_read_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * val,int * val2,long info)6532f3abe6cSLars-Peter Clausen static int adis16480_read_raw(struct iio_dev *indio_dev,
6542f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int *val, int *val2, long info)
6552f3abe6cSLars-Peter Clausen {
6567abad106SLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
6576cf7b866SStefan Popa 	unsigned int temp;
6587abad106SLars-Peter Clausen 
6592f3abe6cSLars-Peter Clausen 	switch (info) {
6602f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_RAW:
6612f3abe6cSLars-Peter Clausen 		return adis_single_conversion(indio_dev, chan, 0, val);
6622f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_SCALE:
6632f3abe6cSLars-Peter Clausen 		switch (chan->type) {
6642f3abe6cSLars-Peter Clausen 		case IIO_ANGL_VEL:
6657abad106SLars-Peter Clausen 			*val = st->chip_info->gyro_max_scale;
6667abad106SLars-Peter Clausen 			*val2 = st->chip_info->gyro_max_val;
6677abad106SLars-Peter Clausen 			return IIO_VAL_FRACTIONAL;
6682f3abe6cSLars-Peter Clausen 		case IIO_ACCEL:
6697abad106SLars-Peter Clausen 			*val = st->chip_info->accel_max_scale;
6707abad106SLars-Peter Clausen 			*val2 = st->chip_info->accel_max_val;
6717abad106SLars-Peter Clausen 			return IIO_VAL_FRACTIONAL;
6722f3abe6cSLars-Peter Clausen 		case IIO_MAGN:
6732f3abe6cSLars-Peter Clausen 			*val = 0;
6742f3abe6cSLars-Peter Clausen 			*val2 = 100; /* 0.0001 gauss */
6752f3abe6cSLars-Peter Clausen 			return IIO_VAL_INT_PLUS_MICRO;
6762f3abe6cSLars-Peter Clausen 		case IIO_TEMP:
6776cf7b866SStefan Popa 			/*
6786cf7b866SStefan Popa 			 * +85 degrees Celsius = temp_max_scale
6796cf7b866SStefan Popa 			 * +25 degrees Celsius = 0
6806cf7b866SStefan Popa 			 * LSB, 25 degrees Celsius  = 60 / temp_max_scale
6816cf7b866SStefan Popa 			 */
6826cf7b866SStefan Popa 			*val = st->chip_info->temp_scale / 1000;
6836cf7b866SStefan Popa 			*val2 = (st->chip_info->temp_scale % 1000) * 1000;
6842f3abe6cSLars-Peter Clausen 			return IIO_VAL_INT_PLUS_MICRO;
6852f3abe6cSLars-Peter Clausen 		case IIO_PRESSURE:
68649549cb2SNuno Sá 			/*
68749549cb2SNuno Sá 			 * max scale is 1310 mbar
68849549cb2SNuno Sá 			 * max raw value is 32767 shifted for 32bits
68949549cb2SNuno Sá 			 */
69049549cb2SNuno Sá 			*val = 131; /* 1310mbar = 131 kPa */
69149549cb2SNuno Sá 			*val2 = 32767 << 16;
69249549cb2SNuno Sá 			return IIO_VAL_FRACTIONAL;
6932f3abe6cSLars-Peter Clausen 		default:
6942f3abe6cSLars-Peter Clausen 			return -EINVAL;
6952f3abe6cSLars-Peter Clausen 		}
6962f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_OFFSET:
6972f3abe6cSLars-Peter Clausen 		/* Only the temperature channel has a offset */
6986cf7b866SStefan Popa 		temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */
6996cf7b866SStefan Popa 		*val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale);
7002f3abe6cSLars-Peter Clausen 		return IIO_VAL_INT;
7012f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
7022f3abe6cSLars-Peter Clausen 		return adis16480_get_calibbias(indio_dev, chan, val);
7032f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBSCALE:
7042f3abe6cSLars-Peter Clausen 		return adis16480_get_calibscale(indio_dev, chan, val);
7052f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
7062f3abe6cSLars-Peter Clausen 		return adis16480_get_filter_freq(indio_dev, chan, val);
707e4f95939SJonathan Cameron 	case IIO_CHAN_INFO_SAMP_FREQ:
708e4f95939SJonathan Cameron 		return adis16480_get_freq(indio_dev, val, val2);
7092f3abe6cSLars-Peter Clausen 	default:
7102f3abe6cSLars-Peter Clausen 		return -EINVAL;
7112f3abe6cSLars-Peter Clausen 	}
7122f3abe6cSLars-Peter Clausen }
7132f3abe6cSLars-Peter Clausen 
adis16480_write_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int val,int val2,long info)7142f3abe6cSLars-Peter Clausen static int adis16480_write_raw(struct iio_dev *indio_dev,
7152f3abe6cSLars-Peter Clausen 	const struct iio_chan_spec *chan, int val, int val2, long info)
7162f3abe6cSLars-Peter Clausen {
7172f3abe6cSLars-Peter Clausen 	switch (info) {
7182f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
7192f3abe6cSLars-Peter Clausen 		return adis16480_set_calibbias(indio_dev, chan, val);
7202f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBSCALE:
7212f3abe6cSLars-Peter Clausen 		return adis16480_set_calibscale(indio_dev, chan, val);
7222f3abe6cSLars-Peter Clausen 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
7232f3abe6cSLars-Peter Clausen 		return adis16480_set_filter_freq(indio_dev, chan, val);
724e4f95939SJonathan Cameron 	case IIO_CHAN_INFO_SAMP_FREQ:
725e4f95939SJonathan Cameron 		return adis16480_set_freq(indio_dev, val, val2);
726e4f95939SJonathan Cameron 
7272f3abe6cSLars-Peter Clausen 	default:
7282f3abe6cSLars-Peter Clausen 		return -EINVAL;
7292f3abe6cSLars-Peter Clausen 	}
7302f3abe6cSLars-Peter Clausen }
7312f3abe6cSLars-Peter Clausen 
73286b64c9dSJonathan Cameron #define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \
7332f3abe6cSLars-Peter Clausen 	{ \
7342f3abe6cSLars-Peter Clausen 		.type = (_type), \
7352f3abe6cSLars-Peter Clausen 		.modified = 1, \
7362f3abe6cSLars-Peter Clausen 		.channel2 = (_mod), \
73786b64c9dSJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
73886b64c9dSJonathan Cameron 			BIT(IIO_CHAN_INFO_CALIBBIAS) | \
73986b64c9dSJonathan Cameron 			_info_sep, \
74086b64c9dSJonathan Cameron 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
741e4f95939SJonathan Cameron 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
7422f3abe6cSLars-Peter Clausen 		.address = (_address), \
7432f3abe6cSLars-Peter Clausen 		.scan_index = (_si), \
7442f3abe6cSLars-Peter Clausen 		.scan_type = { \
7452f3abe6cSLars-Peter Clausen 			.sign = 's', \
7462f3abe6cSLars-Peter Clausen 			.realbits = (_bits), \
7472f3abe6cSLars-Peter Clausen 			.storagebits = (_bits), \
7482f3abe6cSLars-Peter Clausen 			.endianness = IIO_BE, \
7492f3abe6cSLars-Peter Clausen 		}, \
7502f3abe6cSLars-Peter Clausen 	}
7512f3abe6cSLars-Peter Clausen 
7522f3abe6cSLars-Peter Clausen #define ADIS16480_GYRO_CHANNEL(_mod) \
7532f3abe6cSLars-Peter Clausen 	ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
7542f3abe6cSLars-Peter Clausen 	ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
75586b64c9dSJonathan Cameron 	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
75686b64c9dSJonathan Cameron 	BIT(IIO_CHAN_INFO_CALIBSCALE), \
7572f3abe6cSLars-Peter Clausen 	32)
7582f3abe6cSLars-Peter Clausen 
7592f3abe6cSLars-Peter Clausen #define ADIS16480_ACCEL_CHANNEL(_mod) \
7602f3abe6cSLars-Peter Clausen 	ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
7612f3abe6cSLars-Peter Clausen 	ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
76286b64c9dSJonathan Cameron 	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
76386b64c9dSJonathan Cameron 	BIT(IIO_CHAN_INFO_CALIBSCALE), \
7642f3abe6cSLars-Peter Clausen 	32)
7652f3abe6cSLars-Peter Clausen 
7662f3abe6cSLars-Peter Clausen #define ADIS16480_MAGN_CHANNEL(_mod) \
7672f3abe6cSLars-Peter Clausen 	ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
7682f3abe6cSLars-Peter Clausen 	ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
76986b64c9dSJonathan Cameron 	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
7702f3abe6cSLars-Peter Clausen 	16)
7712f3abe6cSLars-Peter Clausen 
7722f3abe6cSLars-Peter Clausen #define ADIS16480_PRESSURE_CHANNEL() \
7732f3abe6cSLars-Peter Clausen 	{ \
7742f3abe6cSLars-Peter Clausen 		.type = IIO_PRESSURE, \
7752f3abe6cSLars-Peter Clausen 		.indexed = 1, \
7762f3abe6cSLars-Peter Clausen 		.channel = 0, \
77786b64c9dSJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
77886b64c9dSJonathan Cameron 			BIT(IIO_CHAN_INFO_CALIBBIAS) | \
77986b64c9dSJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE), \
780e4f95939SJonathan Cameron 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
7812f3abe6cSLars-Peter Clausen 		.address = ADIS16480_REG_BAROM_OUT, \
7822f3abe6cSLars-Peter Clausen 		.scan_index = ADIS16480_SCAN_BARO, \
7832f3abe6cSLars-Peter Clausen 		.scan_type = { \
7842f3abe6cSLars-Peter Clausen 			.sign = 's', \
7852f3abe6cSLars-Peter Clausen 			.realbits = 32, \
7862f3abe6cSLars-Peter Clausen 			.storagebits = 32, \
7872f3abe6cSLars-Peter Clausen 			.endianness = IIO_BE, \
7882f3abe6cSLars-Peter Clausen 		}, \
7892f3abe6cSLars-Peter Clausen 	}
7902f3abe6cSLars-Peter Clausen 
7912f3abe6cSLars-Peter Clausen #define ADIS16480_TEMP_CHANNEL() { \
7922f3abe6cSLars-Peter Clausen 		.type = IIO_TEMP, \
7932f3abe6cSLars-Peter Clausen 		.indexed = 1, \
7942f3abe6cSLars-Peter Clausen 		.channel = 0, \
79586b64c9dSJonathan Cameron 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
79686b64c9dSJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE) | \
79786b64c9dSJonathan Cameron 			BIT(IIO_CHAN_INFO_OFFSET), \
798e4f95939SJonathan Cameron 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
7992f3abe6cSLars-Peter Clausen 		.address = ADIS16480_REG_TEMP_OUT, \
8002f3abe6cSLars-Peter Clausen 		.scan_index = ADIS16480_SCAN_TEMP, \
8012f3abe6cSLars-Peter Clausen 		.scan_type = { \
8022f3abe6cSLars-Peter Clausen 			.sign = 's', \
8032f3abe6cSLars-Peter Clausen 			.realbits = 16, \
8042f3abe6cSLars-Peter Clausen 			.storagebits = 16, \
8052f3abe6cSLars-Peter Clausen 			.endianness = IIO_BE, \
8062f3abe6cSLars-Peter Clausen 		}, \
8072f3abe6cSLars-Peter Clausen 	}
8082f3abe6cSLars-Peter Clausen 
8092f3abe6cSLars-Peter Clausen static const struct iio_chan_spec adis16480_channels[] = {
8102f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(X),
8112f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(Y),
8122f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(Z),
8132f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(X),
8142f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(Y),
8152f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(Z),
8162f3abe6cSLars-Peter Clausen 	ADIS16480_MAGN_CHANNEL(X),
8172f3abe6cSLars-Peter Clausen 	ADIS16480_MAGN_CHANNEL(Y),
8182f3abe6cSLars-Peter Clausen 	ADIS16480_MAGN_CHANNEL(Z),
8192f3abe6cSLars-Peter Clausen 	ADIS16480_PRESSURE_CHANNEL(),
8202f3abe6cSLars-Peter Clausen 	ADIS16480_TEMP_CHANNEL(),
8212f3abe6cSLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(11)
8222f3abe6cSLars-Peter Clausen };
8232f3abe6cSLars-Peter Clausen 
8242f3abe6cSLars-Peter Clausen static const struct iio_chan_spec adis16485_channels[] = {
8252f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(X),
8262f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(Y),
8272f3abe6cSLars-Peter Clausen 	ADIS16480_GYRO_CHANNEL(Z),
8282f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(X),
8292f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(Y),
8302f3abe6cSLars-Peter Clausen 	ADIS16480_ACCEL_CHANNEL(Z),
8312f3abe6cSLars-Peter Clausen 	ADIS16480_TEMP_CHANNEL(),
8322f3abe6cSLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(7)
8332f3abe6cSLars-Peter Clausen };
8342f3abe6cSLars-Peter Clausen 
8352f3abe6cSLars-Peter Clausen enum adis16480_variant {
8362f3abe6cSLars-Peter Clausen 	ADIS16375,
8372f3abe6cSLars-Peter Clausen 	ADIS16480,
8382f3abe6cSLars-Peter Clausen 	ADIS16485,
8392f3abe6cSLars-Peter Clausen 	ADIS16488,
84080cbc848SStefan Popa 	ADIS16490,
84182e7a1b2SStefan Popa 	ADIS16495_1,
84282e7a1b2SStefan Popa 	ADIS16495_2,
84382e7a1b2SStefan Popa 	ADIS16495_3,
84482e7a1b2SStefan Popa 	ADIS16497_1,
84582e7a1b2SStefan Popa 	ADIS16497_2,
84682e7a1b2SStefan Popa 	ADIS16497_3,
8472f3abe6cSLars-Peter Clausen };
8482f3abe6cSLars-Peter Clausen 
84997928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
85097928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
85197928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
85297928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_XACCL_FAIL 3
85397928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_YACCL_FAIL 4
85497928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
85597928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
85697928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
85797928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
85897928677SAlexandru Ardelean #define ADIS16480_DIAG_STAT_BARO_FAIL 11
85997928677SAlexandru Ardelean 
86097928677SAlexandru Ardelean static const char * const adis16480_status_error_msgs[] = {
86197928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
86297928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
86397928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
86497928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
86597928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
86697928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
86797928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
86897928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
86997928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
87097928677SAlexandru Ardelean 	[ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
87197928677SAlexandru Ardelean };
87297928677SAlexandru Ardelean 
87397928677SAlexandru Ardelean static int adis16480_enable_irq(struct adis *adis, bool enable);
87497928677SAlexandru Ardelean 
875941f1308SNuno Sa #define ADIS16480_DATA(_prod_id, _timeouts, _burst_len)			\
87697928677SAlexandru Ardelean {									\
87797928677SAlexandru Ardelean 	.diag_stat_reg = ADIS16480_REG_DIAG_STS,			\
87897928677SAlexandru Ardelean 	.glob_cmd_reg = ADIS16480_REG_GLOB_CMD,				\
879366a5434SNuno Sá 	.prod_id_reg = ADIS16480_REG_PROD_ID,				\
880366a5434SNuno Sá 	.prod_id = (_prod_id),						\
88197928677SAlexandru Ardelean 	.has_paging = true,						\
88297928677SAlexandru Ardelean 	.read_delay = 5,						\
88397928677SAlexandru Ardelean 	.write_delay = 5,						\
88497928677SAlexandru Ardelean 	.self_test_mask = BIT(1),					\
885fdcf6bbbSNuno Sá 	.self_test_reg = ADIS16480_REG_GLOB_CMD,			\
88697928677SAlexandru Ardelean 	.status_error_msgs = adis16480_status_error_msgs,		\
88797928677SAlexandru Ardelean 	.status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |	\
88897928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |			\
88997928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |			\
89097928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |			\
89197928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |			\
89297928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |			\
89397928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |			\
89497928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |			\
89597928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |			\
89697928677SAlexandru Ardelean 		BIT(ADIS16480_DIAG_STAT_BARO_FAIL),			\
89797928677SAlexandru Ardelean 	.enable_irq = adis16480_enable_irq,				\
89897928677SAlexandru Ardelean 	.timeouts = (_timeouts),					\
899941f1308SNuno Sa 	.burst_reg_cmd = ADIS16495_REG_BURST_CMD,			\
900941f1308SNuno Sa 	.burst_len = (_burst_len),					\
901941f1308SNuno Sa 	.burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED			\
90297928677SAlexandru Ardelean }
90397928677SAlexandru Ardelean 
904380b107bSNuno Sá static const struct adis_timeout adis16485_timeouts = {
905380b107bSNuno Sá 	.reset_ms = 560,
906380b107bSNuno Sá 	.sw_reset_ms = 120,
907380b107bSNuno Sá 	.self_test_ms = 12,
908380b107bSNuno Sá };
909380b107bSNuno Sá 
910380b107bSNuno Sá static const struct adis_timeout adis16480_timeouts = {
911380b107bSNuno Sá 	.reset_ms = 560,
912380b107bSNuno Sá 	.sw_reset_ms = 560,
913380b107bSNuno Sá 	.self_test_ms = 12,
914380b107bSNuno Sá };
915380b107bSNuno Sá 
916380b107bSNuno Sá static const struct adis_timeout adis16495_timeouts = {
917380b107bSNuno Sá 	.reset_ms = 170,
918380b107bSNuno Sá 	.sw_reset_ms = 130,
919380b107bSNuno Sá 	.self_test_ms = 40,
920380b107bSNuno Sá };
921380b107bSNuno Sá 
922380b107bSNuno Sá static const struct adis_timeout adis16495_1_timeouts = {
923380b107bSNuno Sá 	.reset_ms = 250,
924380b107bSNuno Sá 	.sw_reset_ms = 210,
925380b107bSNuno Sá 	.self_test_ms = 20,
926380b107bSNuno Sá };
927380b107bSNuno Sá 
9282f3abe6cSLars-Peter Clausen static const struct adis16480_chip_info adis16480_chip_info[] = {
9292f3abe6cSLars-Peter Clausen 	[ADIS16375] = {
9302f3abe6cSLars-Peter Clausen 		.channels = adis16485_channels,
9312f3abe6cSLars-Peter Clausen 		.num_channels = ARRAY_SIZE(adis16485_channels),
9327abad106SLars-Peter Clausen 		/*
93349549cb2SNuno Sá 		 * Typically we do IIO_RAD_TO_DEGREE in the denominator, which
93449549cb2SNuno Sá 		 * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since
93549549cb2SNuno Sá 		 * it gives better approximation. However, in this case we
93649549cb2SNuno Sá 		 * cannot do it since it would not fit in a 32bit variable.
9377abad106SLars-Peter Clausen 		 */
93849549cb2SNuno Sá 		.gyro_max_val = 22887 << 16,
93949549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(300),
94049549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
9417abad106SLars-Peter Clausen 		.accel_max_scale = 18,
9426cf7b866SStefan Popa 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
943e0e6398eSStefan Popa 		.int_clk = 2460000,
944e0e6398eSStefan Popa 		.max_dec_rate = 2048,
945ea1945c2SNuno Sá 		.has_sleep_cnt = true,
94683ec2d54SStefan Popa 		.filter_freqs = adis16480_def_filter_freqs,
947941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
9482f3abe6cSLars-Peter Clausen 	},
9492f3abe6cSLars-Peter Clausen 	[ADIS16480] = {
9502f3abe6cSLars-Peter Clausen 		.channels = adis16480_channels,
9512f3abe6cSLars-Peter Clausen 		.num_channels = ARRAY_SIZE(adis16480_channels),
95249549cb2SNuno Sá 		.gyro_max_val = 22500 << 16,
95349549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
95449549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
955fdd0d32eSDragos Bogdan 		.accel_max_scale = 10,
9566cf7b866SStefan Popa 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
957e0e6398eSStefan Popa 		.int_clk = 2460000,
958e0e6398eSStefan Popa 		.max_dec_rate = 2048,
959ea1945c2SNuno Sá 		.has_sleep_cnt = true,
96083ec2d54SStefan Popa 		.filter_freqs = adis16480_def_filter_freqs,
961941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
9622f3abe6cSLars-Peter Clausen 	},
9632f3abe6cSLars-Peter Clausen 	[ADIS16485] = {
9642f3abe6cSLars-Peter Clausen 		.channels = adis16485_channels,
9652f3abe6cSLars-Peter Clausen 		.num_channels = ARRAY_SIZE(adis16485_channels),
96649549cb2SNuno Sá 		.gyro_max_val = 22500 << 16,
96749549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
96849549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
9697abad106SLars-Peter Clausen 		.accel_max_scale = 5,
9706cf7b866SStefan Popa 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
971e0e6398eSStefan Popa 		.int_clk = 2460000,
972e0e6398eSStefan Popa 		.max_dec_rate = 2048,
973ea1945c2SNuno Sá 		.has_sleep_cnt = true,
97483ec2d54SStefan Popa 		.filter_freqs = adis16480_def_filter_freqs,
975941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
9762f3abe6cSLars-Peter Clausen 	},
9772f3abe6cSLars-Peter Clausen 	[ADIS16488] = {
9782f3abe6cSLars-Peter Clausen 		.channels = adis16480_channels,
9792f3abe6cSLars-Peter Clausen 		.num_channels = ARRAY_SIZE(adis16480_channels),
98049549cb2SNuno Sá 		.gyro_max_val = 22500 << 16,
98149549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
98249549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
9837abad106SLars-Peter Clausen 		.accel_max_scale = 18,
9846cf7b866SStefan Popa 		.temp_scale = 5650, /* 5.65 milli degree Celsius */
985e0e6398eSStefan Popa 		.int_clk = 2460000,
986e0e6398eSStefan Popa 		.max_dec_rate = 2048,
987ea1945c2SNuno Sá 		.has_sleep_cnt = true,
98883ec2d54SStefan Popa 		.filter_freqs = adis16480_def_filter_freqs,
989941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
9902f3abe6cSLars-Peter Clausen 	},
99180cbc848SStefan Popa 	[ADIS16490] = {
99280cbc848SStefan Popa 		.channels = adis16485_channels,
99380cbc848SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
99480cbc848SStefan Popa 		.gyro_max_val = 20000 << 16,
99580cbc848SStefan Popa 		.gyro_max_scale = IIO_DEGREE_TO_RAD(100),
99680cbc848SStefan Popa 		.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
99780cbc848SStefan Popa 		.accel_max_scale = 8,
99880cbc848SStefan Popa 		.temp_scale = 14285, /* 14.285 milli degree Celsius */
99980cbc848SStefan Popa 		.int_clk = 4250000,
100080cbc848SStefan Popa 		.max_dec_rate = 4250,
100180cbc848SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
100280cbc848SStefan Popa 		.has_pps_clk_mode = true,
1003941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
100480cbc848SStefan Popa 	},
100582e7a1b2SStefan Popa 	[ADIS16495_1] = {
100682e7a1b2SStefan Popa 		.channels = adis16485_channels,
100782e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
100849549cb2SNuno Sá 		.gyro_max_val = 20000 << 16,
100949549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
101049549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
101182e7a1b2SStefan Popa 		.accel_max_scale = 8,
101282e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
101382e7a1b2SStefan Popa 		.int_clk = 4250000,
101482e7a1b2SStefan Popa 		.max_dec_rate = 4250,
101582e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1016326e2357SStefan Popa 		.has_pps_clk_mode = true,
1017941f1308SNuno Sa 		/* 20 elements of 16bits */
1018941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
1019941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
102082e7a1b2SStefan Popa 	},
102182e7a1b2SStefan Popa 	[ADIS16495_2] = {
102282e7a1b2SStefan Popa 		.channels = adis16485_channels,
102382e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
102449549cb2SNuno Sá 		.gyro_max_val = 18000 << 16,
102549549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
102649549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
102782e7a1b2SStefan Popa 		.accel_max_scale = 8,
102882e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
102982e7a1b2SStefan Popa 		.int_clk = 4250000,
103082e7a1b2SStefan Popa 		.max_dec_rate = 4250,
103182e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1032326e2357SStefan Popa 		.has_pps_clk_mode = true,
1033941f1308SNuno Sa 		/* 20 elements of 16bits */
1034941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
1035941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
103682e7a1b2SStefan Popa 	},
103782e7a1b2SStefan Popa 	[ADIS16495_3] = {
103882e7a1b2SStefan Popa 		.channels = adis16485_channels,
103982e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
104049549cb2SNuno Sá 		.gyro_max_val = 20000 << 16,
104149549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
104249549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
104382e7a1b2SStefan Popa 		.accel_max_scale = 8,
104482e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
104582e7a1b2SStefan Popa 		.int_clk = 4250000,
104682e7a1b2SStefan Popa 		.max_dec_rate = 4250,
104782e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1048326e2357SStefan Popa 		.has_pps_clk_mode = true,
1049941f1308SNuno Sa 		/* 20 elements of 16bits */
1050941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
1051941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
105282e7a1b2SStefan Popa 	},
105382e7a1b2SStefan Popa 	[ADIS16497_1] = {
105482e7a1b2SStefan Popa 		.channels = adis16485_channels,
105582e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
105649549cb2SNuno Sá 		.gyro_max_val = 20000 << 16,
105749549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
105849549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
105982e7a1b2SStefan Popa 		.accel_max_scale = 40,
106082e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
106182e7a1b2SStefan Popa 		.int_clk = 4250000,
106282e7a1b2SStefan Popa 		.max_dec_rate = 4250,
106382e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1064326e2357SStefan Popa 		.has_pps_clk_mode = true,
1065941f1308SNuno Sa 		/* 20 elements of 16bits */
1066941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
1067941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
106882e7a1b2SStefan Popa 	},
106982e7a1b2SStefan Popa 	[ADIS16497_2] = {
107082e7a1b2SStefan Popa 		.channels = adis16485_channels,
107182e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
107249549cb2SNuno Sá 		.gyro_max_val = 18000 << 16,
107349549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
107449549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
107582e7a1b2SStefan Popa 		.accel_max_scale = 40,
107682e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
107782e7a1b2SStefan Popa 		.int_clk = 4250000,
107882e7a1b2SStefan Popa 		.max_dec_rate = 4250,
107982e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1080326e2357SStefan Popa 		.has_pps_clk_mode = true,
1081941f1308SNuno Sa 		/* 20 elements of 16bits */
1082941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
1083941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
108482e7a1b2SStefan Popa 	},
108582e7a1b2SStefan Popa 	[ADIS16497_3] = {
108682e7a1b2SStefan Popa 		.channels = adis16485_channels,
108782e7a1b2SStefan Popa 		.num_channels = ARRAY_SIZE(adis16485_channels),
108849549cb2SNuno Sá 		.gyro_max_val = 20000 << 16,
108949549cb2SNuno Sá 		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
109049549cb2SNuno Sá 		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
109182e7a1b2SStefan Popa 		.accel_max_scale = 40,
109282e7a1b2SStefan Popa 		.temp_scale = 12500, /* 12.5 milli degree Celsius */
109382e7a1b2SStefan Popa 		.int_clk = 4250000,
109482e7a1b2SStefan Popa 		.max_dec_rate = 4250,
109582e7a1b2SStefan Popa 		.filter_freqs = adis16495_def_filter_freqs,
1096326e2357SStefan Popa 		.has_pps_clk_mode = true,
1097941f1308SNuno Sa 		/* 20 elements of 16bits */
1098941f1308SNuno Sa 		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
1099941f1308SNuno Sa 					    ADIS16495_BURST_MAX_DATA * 2),
110082e7a1b2SStefan Popa 	},
11012f3abe6cSLars-Peter Clausen };
11022f3abe6cSLars-Peter Clausen 
adis16480_validate_crc(const u16 * buf,const u8 n_elem,const u32 crc)1103941f1308SNuno Sa static bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc)
1104941f1308SNuno Sa {
1105941f1308SNuno Sa 	u32 crc_calc;
1106941f1308SNuno Sa 	u16 crc_buf[15];
1107941f1308SNuno Sa 	int j;
1108941f1308SNuno Sa 
1109941f1308SNuno Sa 	for (j = 0; j < n_elem; j++)
1110941f1308SNuno Sa 		crc_buf[j] = swab16(buf[j]);
1111941f1308SNuno Sa 
1112941f1308SNuno Sa 	crc_calc = crc32(~0, crc_buf, n_elem * 2);
1113941f1308SNuno Sa 	crc_calc ^= ~0;
1114941f1308SNuno Sa 
1115941f1308SNuno Sa 	return (crc == crc_calc);
1116941f1308SNuno Sa }
1117941f1308SNuno Sa 
adis16480_trigger_handler(int irq,void * p)1118941f1308SNuno Sa static irqreturn_t adis16480_trigger_handler(int irq, void *p)
1119941f1308SNuno Sa {
1120941f1308SNuno Sa 	struct iio_poll_func *pf = p;
1121941f1308SNuno Sa 	struct iio_dev *indio_dev = pf->indio_dev;
1122941f1308SNuno Sa 	struct adis16480 *st = iio_priv(indio_dev);
1123941f1308SNuno Sa 	struct adis *adis = &st->adis;
112479f4dc9dSAndy Shevchenko 	struct device *dev = &adis->spi->dev;
1125941f1308SNuno Sa 	int ret, bit, offset, i = 0;
1126941f1308SNuno Sa 	__be16 *buffer;
1127941f1308SNuno Sa 	u32 crc;
1128941f1308SNuno Sa 	bool valid;
1129941f1308SNuno Sa 
1130941f1308SNuno Sa 	adis_dev_lock(adis);
1131941f1308SNuno Sa 	if (adis->current_page != 0) {
1132941f1308SNuno Sa 		adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
1133941f1308SNuno Sa 		adis->tx[1] = 0;
1134941f1308SNuno Sa 		ret = spi_write(adis->spi, adis->tx, 2);
1135941f1308SNuno Sa 		if (ret) {
113679f4dc9dSAndy Shevchenko 			dev_err(dev, "Failed to change device page: %d\n", ret);
1137941f1308SNuno Sa 			adis_dev_unlock(adis);
1138941f1308SNuno Sa 			goto irq_done;
1139941f1308SNuno Sa 		}
1140941f1308SNuno Sa 
1141941f1308SNuno Sa 		adis->current_page = 0;
1142941f1308SNuno Sa 	}
1143941f1308SNuno Sa 
1144941f1308SNuno Sa 	ret = spi_sync(adis->spi, &adis->msg);
1145941f1308SNuno Sa 	if (ret) {
114679f4dc9dSAndy Shevchenko 		dev_err(dev, "Failed to read data: %d\n", ret);
1147941f1308SNuno Sa 		adis_dev_unlock(adis);
1148941f1308SNuno Sa 		goto irq_done;
1149941f1308SNuno Sa 	}
1150941f1308SNuno Sa 
1151941f1308SNuno Sa 	adis_dev_unlock(adis);
1152941f1308SNuno Sa 
1153941f1308SNuno Sa 	/*
1154941f1308SNuno Sa 	 * After making the burst request, the response can have one or two
1155941f1308SNuno Sa 	 * 16-bit responses containing the BURST_ID depending on the sclk. If
1156941f1308SNuno Sa 	 * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
1157941f1308SNuno Sa 	 * we have only one. To manage that variation, we use the transition from the
1158941f1308SNuno Sa 	 * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
1159941f1308SNuno Sa 	 * we not find this variation in the first 4 segments, then the data should
1160941f1308SNuno Sa 	 * not be valid.
1161941f1308SNuno Sa 	 */
1162941f1308SNuno Sa 	buffer = adis->buffer;
1163941f1308SNuno Sa 	for (offset = 0; offset < 4; offset++) {
1164941f1308SNuno Sa 		u16 curr = be16_to_cpu(buffer[offset]);
1165941f1308SNuno Sa 		u16 next = be16_to_cpu(buffer[offset + 1]);
1166941f1308SNuno Sa 
1167941f1308SNuno Sa 		if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
1168941f1308SNuno Sa 			offset++;
1169941f1308SNuno Sa 			break;
1170941f1308SNuno Sa 		}
1171941f1308SNuno Sa 	}
1172941f1308SNuno Sa 
1173941f1308SNuno Sa 	if (offset == 4) {
117479f4dc9dSAndy Shevchenko 		dev_err(dev, "Invalid burst data\n");
1175941f1308SNuno Sa 		goto irq_done;
1176941f1308SNuno Sa 	}
1177941f1308SNuno Sa 
1178941f1308SNuno Sa 	crc = be16_to_cpu(buffer[offset + 16]) << 16 | be16_to_cpu(buffer[offset + 15]);
1179941f1308SNuno Sa 	valid = adis16480_validate_crc((u16 *)&buffer[offset], 15, crc);
1180941f1308SNuno Sa 	if (!valid) {
118179f4dc9dSAndy Shevchenko 		dev_err(dev, "Invalid crc\n");
1182941f1308SNuno Sa 		goto irq_done;
1183941f1308SNuno Sa 	}
1184941f1308SNuno Sa 
1185941f1308SNuno Sa 	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
1186941f1308SNuno Sa 		/*
1187941f1308SNuno Sa 		 * When burst mode is used, temperature is the first data
1188941f1308SNuno Sa 		 * channel in the sequence, but the temperature scan index
1189941f1308SNuno Sa 		 * is 10.
1190941f1308SNuno Sa 		 */
1191941f1308SNuno Sa 		switch (bit) {
1192941f1308SNuno Sa 		case ADIS16480_SCAN_TEMP:
1193941f1308SNuno Sa 			st->data[i++] = buffer[offset + 1];
1194941f1308SNuno Sa 			break;
1195941f1308SNuno Sa 		case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
1196941f1308SNuno Sa 			/* The lower register data is sequenced first */
1197941f1308SNuno Sa 			st->data[i++] = buffer[2 * bit + offset + 3];
1198941f1308SNuno Sa 			st->data[i++] = buffer[2 * bit + offset + 2];
1199941f1308SNuno Sa 			break;
1200941f1308SNuno Sa 		}
1201941f1308SNuno Sa 	}
1202941f1308SNuno Sa 
1203941f1308SNuno Sa 	iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
1204941f1308SNuno Sa irq_done:
1205941f1308SNuno Sa 	iio_trigger_notify_done(indio_dev->trig);
1206941f1308SNuno Sa 
1207941f1308SNuno Sa 	return IRQ_HANDLED;
1208941f1308SNuno Sa }
1209941f1308SNuno Sa 
12102f3abe6cSLars-Peter Clausen static const struct iio_info adis16480_info = {
12112f3abe6cSLars-Peter Clausen 	.read_raw = &adis16480_read_raw,
12122f3abe6cSLars-Peter Clausen 	.write_raw = &adis16480_write_raw,
12132f3abe6cSLars-Peter Clausen 	.update_scan_mode = adis_update_scan_mode,
12144c35b7a5SNuno Sá 	.debugfs_reg_access = adis_debugfs_reg_access,
12152f3abe6cSLars-Peter Clausen };
12162f3abe6cSLars-Peter Clausen 
adis16480_stop_device(struct iio_dev * indio_dev)12172f3abe6cSLars-Peter Clausen static int adis16480_stop_device(struct iio_dev *indio_dev)
12182f3abe6cSLars-Peter Clausen {
12192f3abe6cSLars-Peter Clausen 	struct adis16480 *st = iio_priv(indio_dev);
122079f4dc9dSAndy Shevchenko 	struct device *dev = &st->adis.spi->dev;
12212f3abe6cSLars-Peter Clausen 	int ret;
12222f3abe6cSLars-Peter Clausen 
12232f3abe6cSLars-Peter Clausen 	ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9));
12242f3abe6cSLars-Peter Clausen 	if (ret)
122579f4dc9dSAndy Shevchenko 		dev_err(dev, "Could not power down device: %d\n", ret);
12262f3abe6cSLars-Peter Clausen 
12272f3abe6cSLars-Peter Clausen 	return ret;
12282f3abe6cSLars-Peter Clausen }
12292f3abe6cSLars-Peter Clausen 
adis16480_enable_irq(struct adis * adis,bool enable)12302f3abe6cSLars-Peter Clausen static int adis16480_enable_irq(struct adis *adis, bool enable)
12312f3abe6cSLars-Peter Clausen {
1232cede2f89SStefan Popa 	uint16_t val;
1233cede2f89SStefan Popa 	int ret;
1234cede2f89SStefan Popa 
1235100bfa38SAlexandru Ardelean 	ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
123692c7529fSAlexandru Ardelean 	if (ret)
1237cede2f89SStefan Popa 		return ret;
1238cede2f89SStefan Popa 
1239cede2f89SStefan Popa 	val &= ~ADIS16480_DRDY_EN_MSK;
1240cede2f89SStefan Popa 	val |= ADIS16480_DRDY_EN(enable);
1241cede2f89SStefan Popa 
1242100bfa38SAlexandru Ardelean 	return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
12432f3abe6cSLars-Peter Clausen }
12442f3abe6cSLars-Peter Clausen 
adis16480_config_irq_pin(struct adis16480 * st)12459eec6e51SAndy Shevchenko static int adis16480_config_irq_pin(struct adis16480 *st)
1246cede2f89SStefan Popa {
12479eec6e51SAndy Shevchenko 	struct device *dev = &st->adis.spi->dev;
12489eec6e51SAndy Shevchenko 	struct fwnode_handle *fwnode = dev_fwnode(dev);
1249cede2f89SStefan Popa 	struct irq_data *desc;
1250cede2f89SStefan Popa 	enum adis16480_int_pin pin;
1251cede2f89SStefan Popa 	unsigned int irq_type;
1252cede2f89SStefan Popa 	uint16_t val;
1253cede2f89SStefan Popa 	int i, irq = 0;
1254cede2f89SStefan Popa 
1255cede2f89SStefan Popa 	desc = irq_get_irq_data(st->adis.spi->irq);
1256cede2f89SStefan Popa 	if (!desc) {
125779f4dc9dSAndy Shevchenko 		dev_err(dev, "Could not find IRQ %d\n", irq);
1258cede2f89SStefan Popa 		return -EINVAL;
1259cede2f89SStefan Popa 	}
1260cede2f89SStefan Popa 
1261cede2f89SStefan Popa 	/* Disable data ready since the default after reset is on */
1262cede2f89SStefan Popa 	val = ADIS16480_DRDY_EN(0);
1263cede2f89SStefan Popa 
1264cede2f89SStefan Popa 	/*
1265cede2f89SStefan Popa 	 * Get the interrupt from the devicetre by reading the interrupt-names
1266cede2f89SStefan Popa 	 * property. If it is not specified, use DIO1 pin as default.
1267cede2f89SStefan Popa 	 * According to the datasheet, the factory default assigns DIO2 as data
1268cede2f89SStefan Popa 	 * ready signal. However, in the previous versions of the driver, DIO1
1269cede2f89SStefan Popa 	 * pin was used. So, we should leave it as is since some devices might
1270cede2f89SStefan Popa 	 * be expecting the interrupt on the wrong physical pin.
1271cede2f89SStefan Popa 	 */
1272cede2f89SStefan Popa 	pin = ADIS16480_PIN_DIO1;
1273cede2f89SStefan Popa 	for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
12749eec6e51SAndy Shevchenko 		irq = fwnode_irq_get_byname(fwnode, adis16480_int_pin_names[i]);
1275cede2f89SStefan Popa 		if (irq > 0) {
1276cede2f89SStefan Popa 			pin = i;
1277cede2f89SStefan Popa 			break;
1278cede2f89SStefan Popa 		}
1279cede2f89SStefan Popa 	}
1280cede2f89SStefan Popa 
1281cede2f89SStefan Popa 	val |= ADIS16480_DRDY_SEL(pin);
1282cede2f89SStefan Popa 
1283cede2f89SStefan Popa 	/*
1284cede2f89SStefan Popa 	 * Get the interrupt line behaviour. The data ready polarity can be
1285cede2f89SStefan Popa 	 * configured as positive or negative, corresponding to
1286471622c9SNuno Sá 	 * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively.
1287cede2f89SStefan Popa 	 */
1288cede2f89SStefan Popa 	irq_type = irqd_get_trigger_type(desc);
1289471622c9SNuno Sá 	if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */
1290cede2f89SStefan Popa 		val |= ADIS16480_DRDY_POL(1);
1291471622c9SNuno Sá 	} else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
1292cede2f89SStefan Popa 		val |= ADIS16480_DRDY_POL(0);
1293cede2f89SStefan Popa 	} else {
129479f4dc9dSAndy Shevchenko 		dev_err(dev, "Invalid interrupt type 0x%x specified\n", irq_type);
1295cede2f89SStefan Popa 		return -EINVAL;
1296cede2f89SStefan Popa 	}
1297cede2f89SStefan Popa 	/* Write the data ready configuration to the FNCTIO_CTRL register */
1298cede2f89SStefan Popa 	return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
1299cede2f89SStefan Popa }
1300cede2f89SStefan Popa 
adis16480_fw_get_ext_clk_pin(struct adis16480 * st)13019eec6e51SAndy Shevchenko static int adis16480_fw_get_ext_clk_pin(struct adis16480 *st)
1302326e2357SStefan Popa {
13039eec6e51SAndy Shevchenko 	struct device *dev = &st->adis.spi->dev;
1304326e2357SStefan Popa 	const char *ext_clk_pin;
1305326e2357SStefan Popa 	enum adis16480_int_pin pin;
1306326e2357SStefan Popa 	int i;
1307326e2357SStefan Popa 
1308326e2357SStefan Popa 	pin = ADIS16480_PIN_DIO2;
13099eec6e51SAndy Shevchenko 	if (device_property_read_string(dev, "adi,ext-clk-pin", &ext_clk_pin))
1310326e2357SStefan Popa 		goto clk_input_not_found;
1311326e2357SStefan Popa 
1312326e2357SStefan Popa 	for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
1313326e2357SStefan Popa 		if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0)
1314326e2357SStefan Popa 			return i;
1315326e2357SStefan Popa 	}
1316326e2357SStefan Popa 
1317326e2357SStefan Popa clk_input_not_found:
131879f4dc9dSAndy Shevchenko 	dev_info(dev, "clk input line not specified, using DIO2\n");
1319326e2357SStefan Popa 	return pin;
1320326e2357SStefan Popa }
1321326e2357SStefan Popa 
adis16480_ext_clk_config(struct adis16480 * st,bool enable)13229eec6e51SAndy Shevchenko static int adis16480_ext_clk_config(struct adis16480 *st, bool enable)
1323326e2357SStefan Popa {
132479f4dc9dSAndy Shevchenko 	struct device *dev = &st->adis.spi->dev;
1325326e2357SStefan Popa 	unsigned int mode, mask;
1326326e2357SStefan Popa 	enum adis16480_int_pin pin;
1327326e2357SStefan Popa 	uint16_t val;
1328326e2357SStefan Popa 	int ret;
1329326e2357SStefan Popa 
1330326e2357SStefan Popa 	ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val);
133192c7529fSAlexandru Ardelean 	if (ret)
1332326e2357SStefan Popa 		return ret;
1333326e2357SStefan Popa 
13349eec6e51SAndy Shevchenko 	pin = adis16480_fw_get_ext_clk_pin(st);
1335326e2357SStefan Popa 	/*
1336326e2357SStefan Popa 	 * Each DIOx pin supports only one function at a time. When a single pin
1337326e2357SStefan Popa 	 * has two assignments, the enable bit for a lower priority function
1338326e2357SStefan Popa 	 * automatically resets to zero (disabling the lower priority function).
1339326e2357SStefan Popa 	 */
1340326e2357SStefan Popa 	if (pin == ADIS16480_DRDY_SEL(val))
134179f4dc9dSAndy Shevchenko 		dev_warn(dev, "DIO%x pin supports only one function at a time\n", pin + 1);
1342326e2357SStefan Popa 
1343326e2357SStefan Popa 	mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin);
1344326e2357SStefan Popa 	mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK;
1345326e2357SStefan Popa 	/* Only ADIS1649x devices support pps ext clock mode */
1346326e2357SStefan Popa 	if (st->chip_info->has_pps_clk_mode) {
1347326e2357SStefan Popa 		mode |= ADIS16480_SYNC_MODE(st->clk_mode);
1348326e2357SStefan Popa 		mask |= ADIS16480_SYNC_MODE_MSK;
1349326e2357SStefan Popa 	}
1350326e2357SStefan Popa 
1351326e2357SStefan Popa 	val &= ~mask;
1352326e2357SStefan Popa 	val |= mode;
1353326e2357SStefan Popa 
1354326e2357SStefan Popa 	ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
135592c7529fSAlexandru Ardelean 	if (ret)
1356326e2357SStefan Popa 		return ret;
1357326e2357SStefan Popa 
1358326e2357SStefan Popa 	return clk_prepare_enable(st->ext_clk);
1359326e2357SStefan Popa }
1360326e2357SStefan Popa 
adis16480_get_ext_clocks(struct adis16480 * st)1361326e2357SStefan Popa static int adis16480_get_ext_clocks(struct adis16480 *st)
1362326e2357SStefan Popa {
136379f4dc9dSAndy Shevchenko 	struct device *dev = &st->adis.spi->dev;
136479f4dc9dSAndy Shevchenko 
1365*cb55b442SAndy Shevchenko 	st->ext_clk = devm_clk_get_optional(dev, "sync");
1366*cb55b442SAndy Shevchenko 	if (IS_ERR(st->ext_clk))
1367*cb55b442SAndy Shevchenko 		return dev_err_probe(dev, PTR_ERR(st->ext_clk), "failed to get ext clk\n");
1368*cb55b442SAndy Shevchenko 	if (st->ext_clk) {
1369326e2357SStefan Popa 		st->clk_mode = ADIS16480_CLK_SYNC;
1370326e2357SStefan Popa 		return 0;
1371326e2357SStefan Popa 	}
1372326e2357SStefan Popa 
1373326e2357SStefan Popa 	if (st->chip_info->has_pps_clk_mode) {
1374*cb55b442SAndy Shevchenko 		st->ext_clk = devm_clk_get_optional(dev, "pps");
1375*cb55b442SAndy Shevchenko 		if (IS_ERR(st->ext_clk))
1376*cb55b442SAndy Shevchenko 			return dev_err_probe(dev, PTR_ERR(st->ext_clk), "failed to get ext clk\n");
1377*cb55b442SAndy Shevchenko 		if (st->ext_clk) {
1378326e2357SStefan Popa 			st->clk_mode = ADIS16480_CLK_PPS;
1379326e2357SStefan Popa 			return 0;
1380326e2357SStefan Popa 		}
1381326e2357SStefan Popa 	}
1382326e2357SStefan Popa 
1383*cb55b442SAndy Shevchenko 	st->clk_mode = ADIS16480_CLK_INT;
1384326e2357SStefan Popa 	return 0;
1385326e2357SStefan Popa }
1386326e2357SStefan Popa 
adis16480_stop(void * data)1387514f641bSNuno Sá static void adis16480_stop(void *data)
1388514f641bSNuno Sá {
1389514f641bSNuno Sá 	adis16480_stop_device(data);
1390514f641bSNuno Sá }
1391514f641bSNuno Sá 
adis16480_clk_disable(void * data)1392514f641bSNuno Sá static void adis16480_clk_disable(void *data)
1393514f641bSNuno Sá {
1394514f641bSNuno Sá 	clk_disable_unprepare(data);
1395514f641bSNuno Sá }
1396514f641bSNuno Sá 
adis16480_probe(struct spi_device * spi)13972f3abe6cSLars-Peter Clausen static int adis16480_probe(struct spi_device *spi)
13982f3abe6cSLars-Peter Clausen {
13992f3abe6cSLars-Peter Clausen 	const struct spi_device_id *id = spi_get_device_id(spi);
1400380b107bSNuno Sá 	const struct adis_data *adis16480_data;
1401b0e85f95SNuno Sá 	irq_handler_t trigger_handler = NULL;
140279f4dc9dSAndy Shevchenko 	struct device *dev = &spi->dev;
14032f3abe6cSLars-Peter Clausen 	struct iio_dev *indio_dev;
14042f3abe6cSLars-Peter Clausen 	struct adis16480 *st;
14052f3abe6cSLars-Peter Clausen 	int ret;
14062f3abe6cSLars-Peter Clausen 
140779f4dc9dSAndy Shevchenko 	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
14082f3abe6cSLars-Peter Clausen 	if (indio_dev == NULL)
14092f3abe6cSLars-Peter Clausen 		return -ENOMEM;
14102f3abe6cSLars-Peter Clausen 
14112f3abe6cSLars-Peter Clausen 	st = iio_priv(indio_dev);
14122f3abe6cSLars-Peter Clausen 
14132f3abe6cSLars-Peter Clausen 	st->chip_info = &adis16480_chip_info[id->driver_data];
14142f3abe6cSLars-Peter Clausen 	indio_dev->name = spi_get_device_id(spi)->name;
14152f3abe6cSLars-Peter Clausen 	indio_dev->channels = st->chip_info->channels;
14162f3abe6cSLars-Peter Clausen 	indio_dev->num_channels = st->chip_info->num_channels;
14172f3abe6cSLars-Peter Clausen 	indio_dev->info = &adis16480_info;
14182f3abe6cSLars-Peter Clausen 	indio_dev->modes = INDIO_DIRECT_MODE;
14192f3abe6cSLars-Peter Clausen 
142097928677SAlexandru Ardelean 	adis16480_data = &st->chip_info->adis_data;
1421380b107bSNuno Sá 
1422380b107bSNuno Sá 	ret = adis_init(&st->adis, indio_dev, spi, adis16480_data);
14232f3abe6cSLars-Peter Clausen 	if (ret)
1424297c8876SSachin Kamat 		return ret;
14252f3abe6cSLars-Peter Clausen 
1426366a5434SNuno Sá 	ret = __adis_initial_startup(&st->adis);
1427cede2f89SStefan Popa 	if (ret)
1428cede2f89SStefan Popa 		return ret;
1429cede2f89SStefan Popa 
1430ea1945c2SNuno Sá 	if (st->chip_info->has_sleep_cnt) {
143179f4dc9dSAndy Shevchenko 		ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev);
1432514f641bSNuno Sá 		if (ret)
1433514f641bSNuno Sá 			return ret;
1434ea1945c2SNuno Sá 	}
1435514f641bSNuno Sá 
14369eec6e51SAndy Shevchenko 	ret = adis16480_config_irq_pin(st);
1437366a5434SNuno Sá 	if (ret)
1438514f641bSNuno Sá 		return ret;
1439366a5434SNuno Sá 
1440326e2357SStefan Popa 	ret = adis16480_get_ext_clocks(st);
14412f3abe6cSLars-Peter Clausen 	if (ret)
1442514f641bSNuno Sá 		return ret;
14432f3abe6cSLars-Peter Clausen 
1444*cb55b442SAndy Shevchenko 	if (st->ext_clk) {
14459eec6e51SAndy Shevchenko 		ret = adis16480_ext_clk_config(st, true);
1446326e2357SStefan Popa 		if (ret)
1447514f641bSNuno Sá 			return ret;
1448514f641bSNuno Sá 
144979f4dc9dSAndy Shevchenko 		ret = devm_add_action_or_reset(dev, adis16480_clk_disable, st->ext_clk);
1450514f641bSNuno Sá 		if (ret)
1451514f641bSNuno Sá 			return ret;
1452326e2357SStefan Popa 
1453326e2357SStefan Popa 		st->clk_freq = clk_get_rate(st->ext_clk);
1454326e2357SStefan Popa 		st->clk_freq *= 1000; /* micro */
14550463e60fSNuno Sa 		if (st->clk_mode == ADIS16480_CLK_PPS) {
14560463e60fSNuno Sa 			u16 sync_scale;
14570463e60fSNuno Sa 
14580463e60fSNuno Sa 			/*
14590463e60fSNuno Sa 			 * In PPS mode, the IMU sample rate is the clk_freq * sync_scale. Hence,
14600463e60fSNuno Sa 			 * default the IMU sample rate to the highest multiple of the input clock
14610463e60fSNuno Sa 			 * lower than the IMU max sample rate. The internal sample rate is the
14620463e60fSNuno Sa 			 * max...
14630463e60fSNuno Sa 			 */
14640463e60fSNuno Sa 			sync_scale = st->chip_info->int_clk / st->clk_freq;
14650463e60fSNuno Sa 			ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
14660463e60fSNuno Sa 			if (ret)
14670463e60fSNuno Sa 				return ret;
14680463e60fSNuno Sa 		}
1469326e2357SStefan Popa 	} else {
1470326e2357SStefan Popa 		st->clk_freq = st->chip_info->int_clk;
1471326e2357SStefan Popa 	}
1472326e2357SStefan Popa 
1473b0e85f95SNuno Sá 	/* Only use our trigger handler if burst mode is supported */
1474b0e85f95SNuno Sá 	if (adis16480_data->burst_len)
1475b0e85f95SNuno Sá 		trigger_handler = adis16480_trigger_handler;
1476b0e85f95SNuno Sá 
1477941f1308SNuno Sa 	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
1478b0e85f95SNuno Sá 						 trigger_handler);
1479326e2357SStefan Popa 	if (ret)
1480514f641bSNuno Sá 		return ret;
1481326e2357SStefan Popa 
148279f4dc9dSAndy Shevchenko 	ret = devm_iio_device_register(dev, indio_dev);
14832f3abe6cSLars-Peter Clausen 	if (ret)
1484514f641bSNuno Sá 		return ret;
14852f3abe6cSLars-Peter Clausen 
14862f3abe6cSLars-Peter Clausen 	adis16480_debugfs_init(indio_dev);
14872f3abe6cSLars-Peter Clausen 
14882f3abe6cSLars-Peter Clausen 	return 0;
14892f3abe6cSLars-Peter Clausen }
14902f3abe6cSLars-Peter Clausen 
14912f3abe6cSLars-Peter Clausen static const struct spi_device_id adis16480_ids[] = {
14922f3abe6cSLars-Peter Clausen 	{ "adis16375", ADIS16375 },
14932f3abe6cSLars-Peter Clausen 	{ "adis16480", ADIS16480 },
14942f3abe6cSLars-Peter Clausen 	{ "adis16485", ADIS16485 },
14952f3abe6cSLars-Peter Clausen 	{ "adis16488", ADIS16488 },
149680cbc848SStefan Popa 	{ "adis16490", ADIS16490 },
149782e7a1b2SStefan Popa 	{ "adis16495-1", ADIS16495_1 },
149882e7a1b2SStefan Popa 	{ "adis16495-2", ADIS16495_2 },
149982e7a1b2SStefan Popa 	{ "adis16495-3", ADIS16495_3 },
150082e7a1b2SStefan Popa 	{ "adis16497-1", ADIS16497_1 },
150182e7a1b2SStefan Popa 	{ "adis16497-2", ADIS16497_2 },
150282e7a1b2SStefan Popa 	{ "adis16497-3", ADIS16497_3 },
15032f3abe6cSLars-Peter Clausen 	{ }
15042f3abe6cSLars-Peter Clausen };
15052f3abe6cSLars-Peter Clausen MODULE_DEVICE_TABLE(spi, adis16480_ids);
15062f3abe6cSLars-Peter Clausen 
1507304840c4SStefan Popa static const struct of_device_id adis16480_of_match[] = {
1508304840c4SStefan Popa 	{ .compatible = "adi,adis16375" },
1509304840c4SStefan Popa 	{ .compatible = "adi,adis16480" },
1510304840c4SStefan Popa 	{ .compatible = "adi,adis16485" },
1511304840c4SStefan Popa 	{ .compatible = "adi,adis16488" },
151280cbc848SStefan Popa 	{ .compatible = "adi,adis16490" },
151382e7a1b2SStefan Popa 	{ .compatible = "adi,adis16495-1" },
151482e7a1b2SStefan Popa 	{ .compatible = "adi,adis16495-2" },
151582e7a1b2SStefan Popa 	{ .compatible = "adi,adis16495-3" },
151682e7a1b2SStefan Popa 	{ .compatible = "adi,adis16497-1" },
151782e7a1b2SStefan Popa 	{ .compatible = "adi,adis16497-2" },
151882e7a1b2SStefan Popa 	{ .compatible = "adi,adis16497-3" },
1519304840c4SStefan Popa 	{ },
1520304840c4SStefan Popa };
1521304840c4SStefan Popa MODULE_DEVICE_TABLE(of, adis16480_of_match);
1522304840c4SStefan Popa 
15232f3abe6cSLars-Peter Clausen static struct spi_driver adis16480_driver = {
15242f3abe6cSLars-Peter Clausen 	.driver = {
15252f3abe6cSLars-Peter Clausen 		.name = "adis16480",
1526304840c4SStefan Popa 		.of_match_table = adis16480_of_match,
15272f3abe6cSLars-Peter Clausen 	},
15282f3abe6cSLars-Peter Clausen 	.id_table = adis16480_ids,
15292f3abe6cSLars-Peter Clausen 	.probe = adis16480_probe,
15302f3abe6cSLars-Peter Clausen };
15312f3abe6cSLars-Peter Clausen module_spi_driver(adis16480_driver);
15322f3abe6cSLars-Peter Clausen 
15332f3abe6cSLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
15342f3abe6cSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
15352f3abe6cSLars-Peter Clausen MODULE_LICENSE("GPL v2");
15366c9304d6SJonathan Cameron MODULE_IMPORT_NS(IIO_ADISLIB);
1537