162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADIS16480 and similar IMUs driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012 Analog Devices Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/bitfield.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/irq.h>
1262306a36Sopenharmony_ci#include <linux/math.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/spi/spi.h>
1662306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/lcm.h>
1962306a36Sopenharmony_ci#include <linux/property.h>
2062306a36Sopenharmony_ci#include <linux/swab.h>
2162306a36Sopenharmony_ci#include <linux/crc32.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/iio/iio.h>
2462306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2562306a36Sopenharmony_ci#include <linux/iio/imu/adis.h>
2662306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/debugfs.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define ADIS16480_PAGE_SIZE 0x80
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
3562306a36Sopenharmony_ci#define ADIS16480_REG_SEQ_CNT			ADIS16480_REG(0x00, 0x06)
3662306a36Sopenharmony_ci#define ADIS16480_REG_SYS_E_FLA			ADIS16480_REG(0x00, 0x08)
3762306a36Sopenharmony_ci#define ADIS16480_REG_DIAG_STS			ADIS16480_REG(0x00, 0x0A)
3862306a36Sopenharmony_ci#define ADIS16480_REG_ALM_STS			ADIS16480_REG(0x00, 0x0C)
3962306a36Sopenharmony_ci#define ADIS16480_REG_TEMP_OUT			ADIS16480_REG(0x00, 0x0E)
4062306a36Sopenharmony_ci#define ADIS16480_REG_X_GYRO_OUT		ADIS16480_REG(0x00, 0x10)
4162306a36Sopenharmony_ci#define ADIS16480_REG_Y_GYRO_OUT		ADIS16480_REG(0x00, 0x14)
4262306a36Sopenharmony_ci#define ADIS16480_REG_Z_GYRO_OUT		ADIS16480_REG(0x00, 0x18)
4362306a36Sopenharmony_ci#define ADIS16480_REG_X_ACCEL_OUT		ADIS16480_REG(0x00, 0x1C)
4462306a36Sopenharmony_ci#define ADIS16480_REG_Y_ACCEL_OUT		ADIS16480_REG(0x00, 0x20)
4562306a36Sopenharmony_ci#define ADIS16480_REG_Z_ACCEL_OUT		ADIS16480_REG(0x00, 0x24)
4662306a36Sopenharmony_ci#define ADIS16480_REG_X_MAGN_OUT		ADIS16480_REG(0x00, 0x28)
4762306a36Sopenharmony_ci#define ADIS16480_REG_Y_MAGN_OUT		ADIS16480_REG(0x00, 0x2A)
4862306a36Sopenharmony_ci#define ADIS16480_REG_Z_MAGN_OUT		ADIS16480_REG(0x00, 0x2C)
4962306a36Sopenharmony_ci#define ADIS16480_REG_BAROM_OUT			ADIS16480_REG(0x00, 0x2E)
5062306a36Sopenharmony_ci#define ADIS16480_REG_X_DELTAANG_OUT		ADIS16480_REG(0x00, 0x40)
5162306a36Sopenharmony_ci#define ADIS16480_REG_Y_DELTAANG_OUT		ADIS16480_REG(0x00, 0x44)
5262306a36Sopenharmony_ci#define ADIS16480_REG_Z_DELTAANG_OUT		ADIS16480_REG(0x00, 0x48)
5362306a36Sopenharmony_ci#define ADIS16480_REG_X_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x4C)
5462306a36Sopenharmony_ci#define ADIS16480_REG_Y_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x50)
5562306a36Sopenharmony_ci#define ADIS16480_REG_Z_DELTAVEL_OUT		ADIS16480_REG(0x00, 0x54)
5662306a36Sopenharmony_ci#define ADIS16480_REG_PROD_ID			ADIS16480_REG(0x00, 0x7E)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define ADIS16480_REG_X_GYRO_SCALE		ADIS16480_REG(0x02, 0x04)
5962306a36Sopenharmony_ci#define ADIS16480_REG_Y_GYRO_SCALE		ADIS16480_REG(0x02, 0x06)
6062306a36Sopenharmony_ci#define ADIS16480_REG_Z_GYRO_SCALE		ADIS16480_REG(0x02, 0x08)
6162306a36Sopenharmony_ci#define ADIS16480_REG_X_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0A)
6262306a36Sopenharmony_ci#define ADIS16480_REG_Y_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0C)
6362306a36Sopenharmony_ci#define ADIS16480_REG_Z_ACCEL_SCALE		ADIS16480_REG(0x02, 0x0E)
6462306a36Sopenharmony_ci#define ADIS16480_REG_X_GYRO_BIAS		ADIS16480_REG(0x02, 0x10)
6562306a36Sopenharmony_ci#define ADIS16480_REG_Y_GYRO_BIAS		ADIS16480_REG(0x02, 0x14)
6662306a36Sopenharmony_ci#define ADIS16480_REG_Z_GYRO_BIAS		ADIS16480_REG(0x02, 0x18)
6762306a36Sopenharmony_ci#define ADIS16480_REG_X_ACCEL_BIAS		ADIS16480_REG(0x02, 0x1C)
6862306a36Sopenharmony_ci#define ADIS16480_REG_Y_ACCEL_BIAS		ADIS16480_REG(0x02, 0x20)
6962306a36Sopenharmony_ci#define ADIS16480_REG_Z_ACCEL_BIAS		ADIS16480_REG(0x02, 0x24)
7062306a36Sopenharmony_ci#define ADIS16480_REG_X_HARD_IRON		ADIS16480_REG(0x02, 0x28)
7162306a36Sopenharmony_ci#define ADIS16480_REG_Y_HARD_IRON		ADIS16480_REG(0x02, 0x2A)
7262306a36Sopenharmony_ci#define ADIS16480_REG_Z_HARD_IRON		ADIS16480_REG(0x02, 0x2C)
7362306a36Sopenharmony_ci#define ADIS16480_REG_BAROM_BIAS		ADIS16480_REG(0x02, 0x40)
7462306a36Sopenharmony_ci#define ADIS16480_REG_FLASH_CNT			ADIS16480_REG(0x02, 0x7C)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define ADIS16480_REG_GLOB_CMD			ADIS16480_REG(0x03, 0x02)
7762306a36Sopenharmony_ci#define ADIS16480_REG_FNCTIO_CTRL		ADIS16480_REG(0x03, 0x06)
7862306a36Sopenharmony_ci#define ADIS16480_REG_GPIO_CTRL			ADIS16480_REG(0x03, 0x08)
7962306a36Sopenharmony_ci#define ADIS16480_REG_CONFIG			ADIS16480_REG(0x03, 0x0A)
8062306a36Sopenharmony_ci#define ADIS16480_REG_DEC_RATE			ADIS16480_REG(0x03, 0x0C)
8162306a36Sopenharmony_ci#define ADIS16480_REG_SLP_CNT			ADIS16480_REG(0x03, 0x10)
8262306a36Sopenharmony_ci#define ADIS16480_REG_FILTER_BNK0		ADIS16480_REG(0x03, 0x16)
8362306a36Sopenharmony_ci#define ADIS16480_REG_FILTER_BNK1		ADIS16480_REG(0x03, 0x18)
8462306a36Sopenharmony_ci#define ADIS16480_REG_ALM_CNFG0			ADIS16480_REG(0x03, 0x20)
8562306a36Sopenharmony_ci#define ADIS16480_REG_ALM_CNFG1			ADIS16480_REG(0x03, 0x22)
8662306a36Sopenharmony_ci#define ADIS16480_REG_ALM_CNFG2			ADIS16480_REG(0x03, 0x24)
8762306a36Sopenharmony_ci#define ADIS16480_REG_XG_ALM_MAGN		ADIS16480_REG(0x03, 0x28)
8862306a36Sopenharmony_ci#define ADIS16480_REG_YG_ALM_MAGN		ADIS16480_REG(0x03, 0x2A)
8962306a36Sopenharmony_ci#define ADIS16480_REG_ZG_ALM_MAGN		ADIS16480_REG(0x03, 0x2C)
9062306a36Sopenharmony_ci#define ADIS16480_REG_XA_ALM_MAGN		ADIS16480_REG(0x03, 0x2E)
9162306a36Sopenharmony_ci#define ADIS16480_REG_YA_ALM_MAGN		ADIS16480_REG(0x03, 0x30)
9262306a36Sopenharmony_ci#define ADIS16480_REG_ZA_ALM_MAGN		ADIS16480_REG(0x03, 0x32)
9362306a36Sopenharmony_ci#define ADIS16480_REG_XM_ALM_MAGN		ADIS16480_REG(0x03, 0x34)
9462306a36Sopenharmony_ci#define ADIS16480_REG_YM_ALM_MAGN		ADIS16480_REG(0x03, 0x36)
9562306a36Sopenharmony_ci#define ADIS16480_REG_ZM_ALM_MAGN		ADIS16480_REG(0x03, 0x38)
9662306a36Sopenharmony_ci#define ADIS16480_REG_BR_ALM_MAGN		ADIS16480_REG(0x03, 0x3A)
9762306a36Sopenharmony_ci#define ADIS16480_REG_FIRM_REV			ADIS16480_REG(0x03, 0x78)
9862306a36Sopenharmony_ci#define ADIS16480_REG_FIRM_DM			ADIS16480_REG(0x03, 0x7A)
9962306a36Sopenharmony_ci#define ADIS16480_REG_FIRM_Y			ADIS16480_REG(0x03, 0x7C)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * External clock scaling in PPS mode.
10362306a36Sopenharmony_ci * Available only for ADIS1649x devices
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_ci#define ADIS16495_REG_SYNC_SCALE		ADIS16480_REG(0x03, 0x10)
10662306a36Sopenharmony_ci#define ADIS16495_REG_BURST_CMD			ADIS16480_REG(0x00, 0x7C)
10762306a36Sopenharmony_ci#define ADIS16495_BURST_ID			0xA5A5
10862306a36Sopenharmony_ci/* total number of segments in burst */
10962306a36Sopenharmony_ci#define ADIS16495_BURST_MAX_DATA		20
11062306a36Sopenharmony_ci/* spi max speed in burst mode */
11162306a36Sopenharmony_ci#define ADIS16495_BURST_MAX_SPEED              6000000
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define ADIS16480_REG_SERIAL_NUM		ADIS16480_REG(0x04, 0x20)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Each filter coefficent bank spans two pages */
11662306a36Sopenharmony_ci#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
11762306a36Sopenharmony_ci		ADIS16480_REG((page) + 1, (x) - 60 + 8))
11862306a36Sopenharmony_ci#define ADIS16480_FIR_COEF_A(x)			ADIS16480_FIR_COEF(0x05, (x))
11962306a36Sopenharmony_ci#define ADIS16480_FIR_COEF_B(x)			ADIS16480_FIR_COEF(0x07, (x))
12062306a36Sopenharmony_ci#define ADIS16480_FIR_COEF_C(x)			ADIS16480_FIR_COEF(0x09, (x))
12162306a36Sopenharmony_ci#define ADIS16480_FIR_COEF_D(x)			ADIS16480_FIR_COEF(0x0B, (x))
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* ADIS16480_REG_FNCTIO_CTRL */
12462306a36Sopenharmony_ci#define ADIS16480_DRDY_SEL_MSK		GENMASK(1, 0)
12562306a36Sopenharmony_ci#define ADIS16480_DRDY_SEL(x)		FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x)
12662306a36Sopenharmony_ci#define ADIS16480_DRDY_POL_MSK		BIT(2)
12762306a36Sopenharmony_ci#define ADIS16480_DRDY_POL(x)		FIELD_PREP(ADIS16480_DRDY_POL_MSK, x)
12862306a36Sopenharmony_ci#define ADIS16480_DRDY_EN_MSK		BIT(3)
12962306a36Sopenharmony_ci#define ADIS16480_DRDY_EN(x)		FIELD_PREP(ADIS16480_DRDY_EN_MSK, x)
13062306a36Sopenharmony_ci#define ADIS16480_SYNC_SEL_MSK		GENMASK(5, 4)
13162306a36Sopenharmony_ci#define ADIS16480_SYNC_SEL(x)		FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x)
13262306a36Sopenharmony_ci#define ADIS16480_SYNC_EN_MSK		BIT(7)
13362306a36Sopenharmony_ci#define ADIS16480_SYNC_EN(x)		FIELD_PREP(ADIS16480_SYNC_EN_MSK, x)
13462306a36Sopenharmony_ci#define ADIS16480_SYNC_MODE_MSK		BIT(8)
13562306a36Sopenharmony_ci#define ADIS16480_SYNC_MODE(x)		FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistruct adis16480_chip_info {
13862306a36Sopenharmony_ci	unsigned int num_channels;
13962306a36Sopenharmony_ci	const struct iio_chan_spec *channels;
14062306a36Sopenharmony_ci	unsigned int gyro_max_val;
14162306a36Sopenharmony_ci	unsigned int gyro_max_scale;
14262306a36Sopenharmony_ci	unsigned int accel_max_val;
14362306a36Sopenharmony_ci	unsigned int accel_max_scale;
14462306a36Sopenharmony_ci	unsigned int temp_scale;
14562306a36Sopenharmony_ci	unsigned int int_clk;
14662306a36Sopenharmony_ci	unsigned int max_dec_rate;
14762306a36Sopenharmony_ci	const unsigned int *filter_freqs;
14862306a36Sopenharmony_ci	bool has_pps_clk_mode;
14962306a36Sopenharmony_ci	bool has_sleep_cnt;
15062306a36Sopenharmony_ci	const struct adis_data adis_data;
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cienum adis16480_int_pin {
15462306a36Sopenharmony_ci	ADIS16480_PIN_DIO1,
15562306a36Sopenharmony_ci	ADIS16480_PIN_DIO2,
15662306a36Sopenharmony_ci	ADIS16480_PIN_DIO3,
15762306a36Sopenharmony_ci	ADIS16480_PIN_DIO4
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cienum adis16480_clock_mode {
16162306a36Sopenharmony_ci	ADIS16480_CLK_SYNC,
16262306a36Sopenharmony_ci	ADIS16480_CLK_PPS,
16362306a36Sopenharmony_ci	ADIS16480_CLK_INT
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct adis16480 {
16762306a36Sopenharmony_ci	const struct adis16480_chip_info *chip_info;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	struct adis adis;
17062306a36Sopenharmony_ci	struct clk *ext_clk;
17162306a36Sopenharmony_ci	enum adis16480_clock_mode clk_mode;
17262306a36Sopenharmony_ci	unsigned int clk_freq;
17362306a36Sopenharmony_ci	/* Alignment needed for the timestamp */
17462306a36Sopenharmony_ci	__be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8);
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic const char * const adis16480_int_pin_names[4] = {
17862306a36Sopenharmony_ci	[ADIS16480_PIN_DIO1] = "DIO1",
17962306a36Sopenharmony_ci	[ADIS16480_PIN_DIO2] = "DIO2",
18062306a36Sopenharmony_ci	[ADIS16480_PIN_DIO3] = "DIO3",
18162306a36Sopenharmony_ci	[ADIS16480_PIN_DIO4] = "DIO4",
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic bool low_rate_allow;
18562306a36Sopenharmony_cimodule_param(low_rate_allow, bool, 0444);
18662306a36Sopenharmony_ciMODULE_PARM_DESC(low_rate_allow,
18762306a36Sopenharmony_ci		 "Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)");
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic ssize_t adis16480_show_firmware_revision(struct file *file,
19262306a36Sopenharmony_ci		char __user *userbuf, size_t count, loff_t *ppos)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct adis16480 *adis16480 = file->private_data;
19562306a36Sopenharmony_ci	char buf[7];
19662306a36Sopenharmony_ci	size_t len;
19762306a36Sopenharmony_ci	u16 rev;
19862306a36Sopenharmony_ci	int ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
20162306a36Sopenharmony_ci	if (ret)
20262306a36Sopenharmony_ci		return ret;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic const struct file_operations adis16480_firmware_revision_fops = {
21062306a36Sopenharmony_ci	.open = simple_open,
21162306a36Sopenharmony_ci	.read = adis16480_show_firmware_revision,
21262306a36Sopenharmony_ci	.llseek = default_llseek,
21362306a36Sopenharmony_ci	.owner = THIS_MODULE,
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic ssize_t adis16480_show_firmware_date(struct file *file,
21762306a36Sopenharmony_ci		char __user *userbuf, size_t count, loff_t *ppos)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct adis16480 *adis16480 = file->private_data;
22062306a36Sopenharmony_ci	u16 md, year;
22162306a36Sopenharmony_ci	char buf[12];
22262306a36Sopenharmony_ci	size_t len;
22362306a36Sopenharmony_ci	int ret;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
22662306a36Sopenharmony_ci	if (ret)
22762306a36Sopenharmony_ci		return ret;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
23062306a36Sopenharmony_ci	if (ret)
23162306a36Sopenharmony_ci		return ret;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
23462306a36Sopenharmony_ci			md >> 8, md & 0xff, year);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct file_operations adis16480_firmware_date_fops = {
24062306a36Sopenharmony_ci	.open = simple_open,
24162306a36Sopenharmony_ci	.read = adis16480_show_firmware_date,
24262306a36Sopenharmony_ci	.llseek = default_llseek,
24362306a36Sopenharmony_ci	.owner = THIS_MODULE,
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic int adis16480_show_serial_number(void *arg, u64 *val)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct adis16480 *adis16480 = arg;
24962306a36Sopenharmony_ci	u16 serial;
25062306a36Sopenharmony_ci	int ret;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
25362306a36Sopenharmony_ci		&serial);
25462306a36Sopenharmony_ci	if (ret)
25562306a36Sopenharmony_ci		return ret;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	*val = serial;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return 0;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16480_serial_number_fops,
26262306a36Sopenharmony_ci	adis16480_show_serial_number, NULL, "0x%.4llx\n");
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int adis16480_show_product_id(void *arg, u64 *val)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct adis16480 *adis16480 = arg;
26762306a36Sopenharmony_ci	u16 prod_id;
26862306a36Sopenharmony_ci	int ret;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
27162306a36Sopenharmony_ci		&prod_id);
27262306a36Sopenharmony_ci	if (ret)
27362306a36Sopenharmony_ci		return ret;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	*val = prod_id;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16480_product_id_fops,
28062306a36Sopenharmony_ci	adis16480_show_product_id, NULL, "%llu\n");
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int adis16480_show_flash_count(void *arg, u64 *val)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct adis16480 *adis16480 = arg;
28562306a36Sopenharmony_ci	u32 flash_count;
28662306a36Sopenharmony_ci	int ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
28962306a36Sopenharmony_ci		&flash_count);
29062306a36Sopenharmony_ci	if (ret)
29162306a36Sopenharmony_ci		return ret;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	*val = flash_count;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16480_flash_count_fops,
29862306a36Sopenharmony_ci	adis16480_show_flash_count, NULL, "%lld\n");
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int adis16480_debugfs_init(struct iio_dev *indio_dev)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct adis16480 *adis16480 = iio_priv(indio_dev);
30362306a36Sopenharmony_ci	struct dentry *d = iio_get_debugfs_dentry(indio_dev);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	debugfs_create_file_unsafe("firmware_revision", 0400,
30662306a36Sopenharmony_ci		d, adis16480, &adis16480_firmware_revision_fops);
30762306a36Sopenharmony_ci	debugfs_create_file_unsafe("firmware_date", 0400,
30862306a36Sopenharmony_ci		d, adis16480, &adis16480_firmware_date_fops);
30962306a36Sopenharmony_ci	debugfs_create_file_unsafe("serial_number", 0400,
31062306a36Sopenharmony_ci		d, adis16480, &adis16480_serial_number_fops);
31162306a36Sopenharmony_ci	debugfs_create_file_unsafe("product_id", 0400,
31262306a36Sopenharmony_ci		d, adis16480, &adis16480_product_id_fops);
31362306a36Sopenharmony_ci	debugfs_create_file_unsafe("flash_count", 0400,
31462306a36Sopenharmony_ci		d, adis16480, &adis16480_flash_count_fops);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci#else
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int adis16480_debugfs_init(struct iio_dev *indio_dev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci#endif
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
33162306a36Sopenharmony_ci	unsigned int t, sample_rate = st->clk_freq;
33262306a36Sopenharmony_ci	int ret;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (val < 0 || val2 < 0)
33562306a36Sopenharmony_ci		return -EINVAL;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	t =  val * 1000 + val2 / 1000;
33862306a36Sopenharmony_ci	if (t == 0)
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	adis_dev_lock(&st->adis);
34262306a36Sopenharmony_ci	/*
34362306a36Sopenharmony_ci	 * When using PPS mode, the input clock needs to be scaled so that we have an IMU
34462306a36Sopenharmony_ci	 * sample rate between (optimally) 4000 and 4250. After this, we can use the
34562306a36Sopenharmony_ci	 * decimation filter to lower the sampling rate in order to get what the user wants.
34662306a36Sopenharmony_ci	 * Optimally, the user sample rate is a multiple of both the IMU sample rate and
34762306a36Sopenharmony_ci	 * the input clock. Hence, calculating the sync_scale dynamically gives us better
34862306a36Sopenharmony_ci	 * chances of achieving a perfect/integer value for DEC_RATE. The math here is:
34962306a36Sopenharmony_ci	 *	1. lcm of the input clock and the desired output rate.
35062306a36Sopenharmony_ci	 *	2. get the highest multiple of the previous result lower than the adis max rate.
35162306a36Sopenharmony_ci	 *	3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE
35262306a36Sopenharmony_ci	 *	   and DEC_RATE (to get the user output rate)
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	if (st->clk_mode == ADIS16480_CLK_PPS) {
35562306a36Sopenharmony_ci		unsigned long scaled_rate = lcm(st->clk_freq, t);
35662306a36Sopenharmony_ci		int sync_scale;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		/*
35962306a36Sopenharmony_ci		 * If lcm is bigger than the IMU maximum sampling rate there's no perfect
36062306a36Sopenharmony_ci		 * solution. In this case, we get the highest multiple of the input clock
36162306a36Sopenharmony_ci		 * lower than the IMU max sample rate.
36262306a36Sopenharmony_ci		 */
36362306a36Sopenharmony_ci		if (scaled_rate > st->chip_info->int_clk)
36462306a36Sopenharmony_ci			scaled_rate = st->chip_info->int_clk / st->clk_freq * st->clk_freq;
36562306a36Sopenharmony_ci		else
36662306a36Sopenharmony_ci			scaled_rate = st->chip_info->int_clk / scaled_rate * scaled_rate;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		/*
36962306a36Sopenharmony_ci		 * This is not an hard requirement but it's not advised to run the IMU
37062306a36Sopenharmony_ci		 * with a sample rate lower than 4000Hz due to possible undersampling
37162306a36Sopenharmony_ci		 * issues. However, there are users that might really want to take the risk.
37262306a36Sopenharmony_ci		 * Hence, we provide a module parameter for them. If set, we allow sample
37362306a36Sopenharmony_ci		 * rates lower than 4KHz. By default, we won't allow this and we just roundup
37462306a36Sopenharmony_ci		 * the rate to the next multiple of the input clock bigger than 4KHz. This
37562306a36Sopenharmony_ci		 * is done like this as in some cases (when DEC_RATE is 0) might give
37662306a36Sopenharmony_ci		 * us the closest value to the one desired by the user...
37762306a36Sopenharmony_ci		 */
37862306a36Sopenharmony_ci		if (scaled_rate < 4000000 && !low_rate_allow)
37962306a36Sopenharmony_ci			scaled_rate = roundup(4000000, st->clk_freq);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		sync_scale = scaled_rate / st->clk_freq;
38262306a36Sopenharmony_ci		ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
38362306a36Sopenharmony_ci		if (ret)
38462306a36Sopenharmony_ci			goto error;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		sample_rate = scaled_rate;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	t = DIV_ROUND_CLOSEST(sample_rate, t);
39062306a36Sopenharmony_ci	if (t)
39162306a36Sopenharmony_ci		t--;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (t > st->chip_info->max_dec_rate)
39462306a36Sopenharmony_ci		t = st->chip_info->max_dec_rate;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
39762306a36Sopenharmony_cierror:
39862306a36Sopenharmony_ci	adis_dev_unlock(&st->adis);
39962306a36Sopenharmony_ci	return ret;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
40562306a36Sopenharmony_ci	uint16_t t;
40662306a36Sopenharmony_ci	int ret;
40762306a36Sopenharmony_ci	unsigned int freq, sample_rate = st->clk_freq;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	adis_dev_lock(&st->adis);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (st->clk_mode == ADIS16480_CLK_PPS) {
41262306a36Sopenharmony_ci		u16 sync_scale;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale);
41562306a36Sopenharmony_ci		if (ret)
41662306a36Sopenharmony_ci			goto error;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		sample_rate = st->clk_freq * sync_scale;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
42262306a36Sopenharmony_ci	if (ret)
42362306a36Sopenharmony_ci		goto error;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	adis_dev_unlock(&st->adis);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1));
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	*val = freq / 1000;
43062306a36Sopenharmony_ci	*val2 = (freq % 1000) * 1000;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return IIO_VAL_INT_PLUS_MICRO;
43362306a36Sopenharmony_cierror:
43462306a36Sopenharmony_ci	adis_dev_unlock(&st->adis);
43562306a36Sopenharmony_ci	return ret;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cienum {
43962306a36Sopenharmony_ci	ADIS16480_SCAN_GYRO_X,
44062306a36Sopenharmony_ci	ADIS16480_SCAN_GYRO_Y,
44162306a36Sopenharmony_ci	ADIS16480_SCAN_GYRO_Z,
44262306a36Sopenharmony_ci	ADIS16480_SCAN_ACCEL_X,
44362306a36Sopenharmony_ci	ADIS16480_SCAN_ACCEL_Y,
44462306a36Sopenharmony_ci	ADIS16480_SCAN_ACCEL_Z,
44562306a36Sopenharmony_ci	ADIS16480_SCAN_MAGN_X,
44662306a36Sopenharmony_ci	ADIS16480_SCAN_MAGN_Y,
44762306a36Sopenharmony_ci	ADIS16480_SCAN_MAGN_Z,
44862306a36Sopenharmony_ci	ADIS16480_SCAN_BARO,
44962306a36Sopenharmony_ci	ADIS16480_SCAN_TEMP,
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const unsigned int adis16480_calibbias_regs[] = {
45362306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS,
45462306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS,
45562306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS,
45662306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS,
45762306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS,
45862306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS,
45962306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON,
46062306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON,
46162306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON,
46262306a36Sopenharmony_ci	[ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS,
46362306a36Sopenharmony_ci};
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic const unsigned int adis16480_calibscale_regs[] = {
46662306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE,
46762306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE,
46862306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE,
46962306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE,
47062306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE,
47162306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE,
47262306a36Sopenharmony_ci};
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic int adis16480_set_calibbias(struct iio_dev *indio_dev,
47562306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int bias)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
47862306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	switch (chan->type) {
48162306a36Sopenharmony_ci	case IIO_MAGN:
48262306a36Sopenharmony_ci	case IIO_PRESSURE:
48362306a36Sopenharmony_ci		if (bias < -0x8000 || bias >= 0x8000)
48462306a36Sopenharmony_ci			return -EINVAL;
48562306a36Sopenharmony_ci		return adis_write_reg_16(&st->adis, reg, bias);
48662306a36Sopenharmony_ci	case IIO_ANGL_VEL:
48762306a36Sopenharmony_ci	case IIO_ACCEL:
48862306a36Sopenharmony_ci		return adis_write_reg_32(&st->adis, reg, bias);
48962306a36Sopenharmony_ci	default:
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	return -EINVAL;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int adis16480_get_calibbias(struct iio_dev *indio_dev,
49762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *bias)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
50062306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
50162306a36Sopenharmony_ci	uint16_t val16;
50262306a36Sopenharmony_ci	uint32_t val32;
50362306a36Sopenharmony_ci	int ret;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	switch (chan->type) {
50662306a36Sopenharmony_ci	case IIO_MAGN:
50762306a36Sopenharmony_ci	case IIO_PRESSURE:
50862306a36Sopenharmony_ci		ret = adis_read_reg_16(&st->adis, reg, &val16);
50962306a36Sopenharmony_ci		if (ret == 0)
51062306a36Sopenharmony_ci			*bias = sign_extend32(val16, 15);
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci	case IIO_ANGL_VEL:
51362306a36Sopenharmony_ci	case IIO_ACCEL:
51462306a36Sopenharmony_ci		ret = adis_read_reg_32(&st->adis, reg, &val32);
51562306a36Sopenharmony_ci		if (ret == 0)
51662306a36Sopenharmony_ci			*bias = sign_extend32(val32, 31);
51762306a36Sopenharmony_ci		break;
51862306a36Sopenharmony_ci	default:
51962306a36Sopenharmony_ci		ret = -EINVAL;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (ret)
52362306a36Sopenharmony_ci		return ret;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return IIO_VAL_INT;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic int adis16480_set_calibscale(struct iio_dev *indio_dev,
52962306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int scale)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
53262306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (scale < -0x8000 || scale >= 0x8000)
53562306a36Sopenharmony_ci		return -EINVAL;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return adis_write_reg_16(&st->adis, reg, scale);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int adis16480_get_calibscale(struct iio_dev *indio_dev,
54162306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *scale)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
54462306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
54562306a36Sopenharmony_ci	uint16_t val16;
54662306a36Sopenharmony_ci	int ret;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = adis_read_reg_16(&st->adis, reg, &val16);
54962306a36Sopenharmony_ci	if (ret)
55062306a36Sopenharmony_ci		return ret;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	*scale = sign_extend32(val16, 15);
55362306a36Sopenharmony_ci	return IIO_VAL_INT;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic const unsigned int adis16480_def_filter_freqs[] = {
55762306a36Sopenharmony_ci	310,
55862306a36Sopenharmony_ci	55,
55962306a36Sopenharmony_ci	275,
56062306a36Sopenharmony_ci	63,
56162306a36Sopenharmony_ci};
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic const unsigned int adis16495_def_filter_freqs[] = {
56462306a36Sopenharmony_ci	300,
56562306a36Sopenharmony_ci	100,
56662306a36Sopenharmony_ci	300,
56762306a36Sopenharmony_ci	100,
56862306a36Sopenharmony_ci};
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic const unsigned int ad16480_filter_data[][2] = {
57162306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_X]		= { ADIS16480_REG_FILTER_BNK0, 0 },
57262306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Y]		= { ADIS16480_REG_FILTER_BNK0, 3 },
57362306a36Sopenharmony_ci	[ADIS16480_SCAN_GYRO_Z]		= { ADIS16480_REG_FILTER_BNK0, 6 },
57462306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_X]	= { ADIS16480_REG_FILTER_BNK0, 9 },
57562306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Y]	= { ADIS16480_REG_FILTER_BNK0, 12 },
57662306a36Sopenharmony_ci	[ADIS16480_SCAN_ACCEL_Z]	= { ADIS16480_REG_FILTER_BNK1, 0 },
57762306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_X]		= { ADIS16480_REG_FILTER_BNK1, 3 },
57862306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_Y]		= { ADIS16480_REG_FILTER_BNK1, 6 },
57962306a36Sopenharmony_ci	[ADIS16480_SCAN_MAGN_Z]		= { ADIS16480_REG_FILTER_BNK1, 9 },
58062306a36Sopenharmony_ci};
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic int adis16480_get_filter_freq(struct iio_dev *indio_dev,
58362306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *freq)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
58662306a36Sopenharmony_ci	unsigned int enable_mask, offset, reg;
58762306a36Sopenharmony_ci	uint16_t val;
58862306a36Sopenharmony_ci	int ret;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	reg = ad16480_filter_data[chan->scan_index][0];
59162306a36Sopenharmony_ci	offset = ad16480_filter_data[chan->scan_index][1];
59262306a36Sopenharmony_ci	enable_mask = BIT(offset + 2);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	ret = adis_read_reg_16(&st->adis, reg, &val);
59562306a36Sopenharmony_ci	if (ret)
59662306a36Sopenharmony_ci		return ret;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (!(val & enable_mask))
59962306a36Sopenharmony_ci		*freq = 0;
60062306a36Sopenharmony_ci	else
60162306a36Sopenharmony_ci		*freq = st->chip_info->filter_freqs[(val >> offset) & 0x3];
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return IIO_VAL_INT;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic int adis16480_set_filter_freq(struct iio_dev *indio_dev,
60762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, unsigned int freq)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
61062306a36Sopenharmony_ci	unsigned int enable_mask, offset, reg;
61162306a36Sopenharmony_ci	unsigned int diff, best_diff;
61262306a36Sopenharmony_ci	unsigned int i, best_freq;
61362306a36Sopenharmony_ci	uint16_t val;
61462306a36Sopenharmony_ci	int ret;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	reg = ad16480_filter_data[chan->scan_index][0];
61762306a36Sopenharmony_ci	offset = ad16480_filter_data[chan->scan_index][1];
61862306a36Sopenharmony_ci	enable_mask = BIT(offset + 2);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	adis_dev_lock(&st->adis);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	ret = __adis_read_reg_16(&st->adis, reg, &val);
62362306a36Sopenharmony_ci	if (ret)
62462306a36Sopenharmony_ci		goto out_unlock;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (freq == 0) {
62762306a36Sopenharmony_ci		val &= ~enable_mask;
62862306a36Sopenharmony_ci	} else {
62962306a36Sopenharmony_ci		best_freq = 0;
63062306a36Sopenharmony_ci		best_diff = st->chip_info->filter_freqs[0];
63162306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
63262306a36Sopenharmony_ci			if (st->chip_info->filter_freqs[i] >= freq) {
63362306a36Sopenharmony_ci				diff = st->chip_info->filter_freqs[i] - freq;
63462306a36Sopenharmony_ci				if (diff < best_diff) {
63562306a36Sopenharmony_ci					best_diff = diff;
63662306a36Sopenharmony_ci					best_freq = i;
63762306a36Sopenharmony_ci				}
63862306a36Sopenharmony_ci			}
63962306a36Sopenharmony_ci		}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		val &= ~(0x3 << offset);
64262306a36Sopenharmony_ci		val |= best_freq << offset;
64362306a36Sopenharmony_ci		val |= enable_mask;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	ret = __adis_write_reg_16(&st->adis, reg, val);
64762306a36Sopenharmony_ciout_unlock:
64862306a36Sopenharmony_ci	adis_dev_unlock(&st->adis);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return ret;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int adis16480_read_raw(struct iio_dev *indio_dev,
65462306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *val, int *val2, long info)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
65762306a36Sopenharmony_ci	unsigned int temp;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	switch (info) {
66062306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
66162306a36Sopenharmony_ci		return adis_single_conversion(indio_dev, chan, 0, val);
66262306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
66362306a36Sopenharmony_ci		switch (chan->type) {
66462306a36Sopenharmony_ci		case IIO_ANGL_VEL:
66562306a36Sopenharmony_ci			*val = st->chip_info->gyro_max_scale;
66662306a36Sopenharmony_ci			*val2 = st->chip_info->gyro_max_val;
66762306a36Sopenharmony_ci			return IIO_VAL_FRACTIONAL;
66862306a36Sopenharmony_ci		case IIO_ACCEL:
66962306a36Sopenharmony_ci			*val = st->chip_info->accel_max_scale;
67062306a36Sopenharmony_ci			*val2 = st->chip_info->accel_max_val;
67162306a36Sopenharmony_ci			return IIO_VAL_FRACTIONAL;
67262306a36Sopenharmony_ci		case IIO_MAGN:
67362306a36Sopenharmony_ci			*val = 0;
67462306a36Sopenharmony_ci			*val2 = 100; /* 0.0001 gauss */
67562306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
67662306a36Sopenharmony_ci		case IIO_TEMP:
67762306a36Sopenharmony_ci			/*
67862306a36Sopenharmony_ci			 * +85 degrees Celsius = temp_max_scale
67962306a36Sopenharmony_ci			 * +25 degrees Celsius = 0
68062306a36Sopenharmony_ci			 * LSB, 25 degrees Celsius  = 60 / temp_max_scale
68162306a36Sopenharmony_ci			 */
68262306a36Sopenharmony_ci			*val = st->chip_info->temp_scale / 1000;
68362306a36Sopenharmony_ci			*val2 = (st->chip_info->temp_scale % 1000) * 1000;
68462306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
68562306a36Sopenharmony_ci		case IIO_PRESSURE:
68662306a36Sopenharmony_ci			/*
68762306a36Sopenharmony_ci			 * max scale is 1310 mbar
68862306a36Sopenharmony_ci			 * max raw value is 32767 shifted for 32bits
68962306a36Sopenharmony_ci			 */
69062306a36Sopenharmony_ci			*val = 131; /* 1310mbar = 131 kPa */
69162306a36Sopenharmony_ci			*val2 = 32767 << 16;
69262306a36Sopenharmony_ci			return IIO_VAL_FRACTIONAL;
69362306a36Sopenharmony_ci		default:
69462306a36Sopenharmony_ci			return -EINVAL;
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci	case IIO_CHAN_INFO_OFFSET:
69762306a36Sopenharmony_ci		/* Only the temperature channel has a offset */
69862306a36Sopenharmony_ci		temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */
69962306a36Sopenharmony_ci		*val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale);
70062306a36Sopenharmony_ci		return IIO_VAL_INT;
70162306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
70262306a36Sopenharmony_ci		return adis16480_get_calibbias(indio_dev, chan, val);
70362306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
70462306a36Sopenharmony_ci		return adis16480_get_calibscale(indio_dev, chan, val);
70562306a36Sopenharmony_ci	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
70662306a36Sopenharmony_ci		return adis16480_get_filter_freq(indio_dev, chan, val);
70762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
70862306a36Sopenharmony_ci		return adis16480_get_freq(indio_dev, val, val2);
70962306a36Sopenharmony_ci	default:
71062306a36Sopenharmony_ci		return -EINVAL;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic int adis16480_write_raw(struct iio_dev *indio_dev,
71562306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int val, int val2, long info)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	switch (info) {
71862306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
71962306a36Sopenharmony_ci		return adis16480_set_calibbias(indio_dev, chan, val);
72062306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBSCALE:
72162306a36Sopenharmony_ci		return adis16480_set_calibscale(indio_dev, chan, val);
72262306a36Sopenharmony_ci	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
72362306a36Sopenharmony_ci		return adis16480_set_filter_freq(indio_dev, chan, val);
72462306a36Sopenharmony_ci	case IIO_CHAN_INFO_SAMP_FREQ:
72562306a36Sopenharmony_ci		return adis16480_set_freq(indio_dev, val, val2);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	default:
72862306a36Sopenharmony_ci		return -EINVAL;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \
73362306a36Sopenharmony_ci	{ \
73462306a36Sopenharmony_ci		.type = (_type), \
73562306a36Sopenharmony_ci		.modified = 1, \
73662306a36Sopenharmony_ci		.channel2 = (_mod), \
73762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
73862306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS) | \
73962306a36Sopenharmony_ci			_info_sep, \
74062306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
74162306a36Sopenharmony_ci		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
74262306a36Sopenharmony_ci		.address = (_address), \
74362306a36Sopenharmony_ci		.scan_index = (_si), \
74462306a36Sopenharmony_ci		.scan_type = { \
74562306a36Sopenharmony_ci			.sign = 's', \
74662306a36Sopenharmony_ci			.realbits = (_bits), \
74762306a36Sopenharmony_ci			.storagebits = (_bits), \
74862306a36Sopenharmony_ci			.endianness = IIO_BE, \
74962306a36Sopenharmony_ci		}, \
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci#define ADIS16480_GYRO_CHANNEL(_mod) \
75362306a36Sopenharmony_ci	ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
75462306a36Sopenharmony_ci	ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
75562306a36Sopenharmony_ci	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
75662306a36Sopenharmony_ci	BIT(IIO_CHAN_INFO_CALIBSCALE), \
75762306a36Sopenharmony_ci	32)
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci#define ADIS16480_ACCEL_CHANNEL(_mod) \
76062306a36Sopenharmony_ci	ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
76162306a36Sopenharmony_ci	ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
76262306a36Sopenharmony_ci	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
76362306a36Sopenharmony_ci	BIT(IIO_CHAN_INFO_CALIBSCALE), \
76462306a36Sopenharmony_ci	32)
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci#define ADIS16480_MAGN_CHANNEL(_mod) \
76762306a36Sopenharmony_ci	ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
76862306a36Sopenharmony_ci	ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
76962306a36Sopenharmony_ci	BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
77062306a36Sopenharmony_ci	16)
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci#define ADIS16480_PRESSURE_CHANNEL() \
77362306a36Sopenharmony_ci	{ \
77462306a36Sopenharmony_ci		.type = IIO_PRESSURE, \
77562306a36Sopenharmony_ci		.indexed = 1, \
77662306a36Sopenharmony_ci		.channel = 0, \
77762306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
77862306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS) | \
77962306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE), \
78062306a36Sopenharmony_ci		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
78162306a36Sopenharmony_ci		.address = ADIS16480_REG_BAROM_OUT, \
78262306a36Sopenharmony_ci		.scan_index = ADIS16480_SCAN_BARO, \
78362306a36Sopenharmony_ci		.scan_type = { \
78462306a36Sopenharmony_ci			.sign = 's', \
78562306a36Sopenharmony_ci			.realbits = 32, \
78662306a36Sopenharmony_ci			.storagebits = 32, \
78762306a36Sopenharmony_ci			.endianness = IIO_BE, \
78862306a36Sopenharmony_ci		}, \
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci#define ADIS16480_TEMP_CHANNEL() { \
79262306a36Sopenharmony_ci		.type = IIO_TEMP, \
79362306a36Sopenharmony_ci		.indexed = 1, \
79462306a36Sopenharmony_ci		.channel = 0, \
79562306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
79662306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE) | \
79762306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_OFFSET), \
79862306a36Sopenharmony_ci		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
79962306a36Sopenharmony_ci		.address = ADIS16480_REG_TEMP_OUT, \
80062306a36Sopenharmony_ci		.scan_index = ADIS16480_SCAN_TEMP, \
80162306a36Sopenharmony_ci		.scan_type = { \
80262306a36Sopenharmony_ci			.sign = 's', \
80362306a36Sopenharmony_ci			.realbits = 16, \
80462306a36Sopenharmony_ci			.storagebits = 16, \
80562306a36Sopenharmony_ci			.endianness = IIO_BE, \
80662306a36Sopenharmony_ci		}, \
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic const struct iio_chan_spec adis16480_channels[] = {
81062306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(X),
81162306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(Y),
81262306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(Z),
81362306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(X),
81462306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(Y),
81562306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(Z),
81662306a36Sopenharmony_ci	ADIS16480_MAGN_CHANNEL(X),
81762306a36Sopenharmony_ci	ADIS16480_MAGN_CHANNEL(Y),
81862306a36Sopenharmony_ci	ADIS16480_MAGN_CHANNEL(Z),
81962306a36Sopenharmony_ci	ADIS16480_PRESSURE_CHANNEL(),
82062306a36Sopenharmony_ci	ADIS16480_TEMP_CHANNEL(),
82162306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(11)
82262306a36Sopenharmony_ci};
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic const struct iio_chan_spec adis16485_channels[] = {
82562306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(X),
82662306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(Y),
82762306a36Sopenharmony_ci	ADIS16480_GYRO_CHANNEL(Z),
82862306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(X),
82962306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(Y),
83062306a36Sopenharmony_ci	ADIS16480_ACCEL_CHANNEL(Z),
83162306a36Sopenharmony_ci	ADIS16480_TEMP_CHANNEL(),
83262306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(7)
83362306a36Sopenharmony_ci};
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cienum adis16480_variant {
83662306a36Sopenharmony_ci	ADIS16375,
83762306a36Sopenharmony_ci	ADIS16480,
83862306a36Sopenharmony_ci	ADIS16485,
83962306a36Sopenharmony_ci	ADIS16488,
84062306a36Sopenharmony_ci	ADIS16490,
84162306a36Sopenharmony_ci	ADIS16495_1,
84262306a36Sopenharmony_ci	ADIS16495_2,
84362306a36Sopenharmony_ci	ADIS16495_3,
84462306a36Sopenharmony_ci	ADIS16497_1,
84562306a36Sopenharmony_ci	ADIS16497_2,
84662306a36Sopenharmony_ci	ADIS16497_3,
84762306a36Sopenharmony_ci};
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
85062306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
85162306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
85262306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
85362306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
85462306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
85562306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
85662306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
85762306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
85862306a36Sopenharmony_ci#define ADIS16480_DIAG_STAT_BARO_FAIL 11
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic const char * const adis16480_status_error_msgs[] = {
86162306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
86262306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
86362306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
86462306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
86562306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
86662306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
86762306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
86862306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
86962306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
87062306a36Sopenharmony_ci	[ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
87162306a36Sopenharmony_ci};
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic int adis16480_enable_irq(struct adis *adis, bool enable);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci#define ADIS16480_DATA(_prod_id, _timeouts, _burst_len)			\
87662306a36Sopenharmony_ci{									\
87762306a36Sopenharmony_ci	.diag_stat_reg = ADIS16480_REG_DIAG_STS,			\
87862306a36Sopenharmony_ci	.glob_cmd_reg = ADIS16480_REG_GLOB_CMD,				\
87962306a36Sopenharmony_ci	.prod_id_reg = ADIS16480_REG_PROD_ID,				\
88062306a36Sopenharmony_ci	.prod_id = (_prod_id),						\
88162306a36Sopenharmony_ci	.has_paging = true,						\
88262306a36Sopenharmony_ci	.read_delay = 5,						\
88362306a36Sopenharmony_ci	.write_delay = 5,						\
88462306a36Sopenharmony_ci	.self_test_mask = BIT(1),					\
88562306a36Sopenharmony_ci	.self_test_reg = ADIS16480_REG_GLOB_CMD,			\
88662306a36Sopenharmony_ci	.status_error_msgs = adis16480_status_error_msgs,		\
88762306a36Sopenharmony_ci	.status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |	\
88862306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |			\
88962306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |			\
89062306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |			\
89162306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |			\
89262306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |			\
89362306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |			\
89462306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |			\
89562306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |			\
89662306a36Sopenharmony_ci		BIT(ADIS16480_DIAG_STAT_BARO_FAIL),			\
89762306a36Sopenharmony_ci	.enable_irq = adis16480_enable_irq,				\
89862306a36Sopenharmony_ci	.timeouts = (_timeouts),					\
89962306a36Sopenharmony_ci	.burst_reg_cmd = ADIS16495_REG_BURST_CMD,			\
90062306a36Sopenharmony_ci	.burst_len = (_burst_len),					\
90162306a36Sopenharmony_ci	.burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED			\
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic const struct adis_timeout adis16485_timeouts = {
90562306a36Sopenharmony_ci	.reset_ms = 560,
90662306a36Sopenharmony_ci	.sw_reset_ms = 120,
90762306a36Sopenharmony_ci	.self_test_ms = 12,
90862306a36Sopenharmony_ci};
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic const struct adis_timeout adis16480_timeouts = {
91162306a36Sopenharmony_ci	.reset_ms = 560,
91262306a36Sopenharmony_ci	.sw_reset_ms = 560,
91362306a36Sopenharmony_ci	.self_test_ms = 12,
91462306a36Sopenharmony_ci};
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic const struct adis_timeout adis16495_timeouts = {
91762306a36Sopenharmony_ci	.reset_ms = 170,
91862306a36Sopenharmony_ci	.sw_reset_ms = 130,
91962306a36Sopenharmony_ci	.self_test_ms = 40,
92062306a36Sopenharmony_ci};
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic const struct adis_timeout adis16495_1_timeouts = {
92362306a36Sopenharmony_ci	.reset_ms = 250,
92462306a36Sopenharmony_ci	.sw_reset_ms = 210,
92562306a36Sopenharmony_ci	.self_test_ms = 20,
92662306a36Sopenharmony_ci};
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic const struct adis16480_chip_info adis16480_chip_info[] = {
92962306a36Sopenharmony_ci	[ADIS16375] = {
93062306a36Sopenharmony_ci		.channels = adis16485_channels,
93162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
93262306a36Sopenharmony_ci		/*
93362306a36Sopenharmony_ci		 * Typically we do IIO_RAD_TO_DEGREE in the denominator, which
93462306a36Sopenharmony_ci		 * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since
93562306a36Sopenharmony_ci		 * it gives better approximation. However, in this case we
93662306a36Sopenharmony_ci		 * cannot do it since it would not fit in a 32bit variable.
93762306a36Sopenharmony_ci		 */
93862306a36Sopenharmony_ci		.gyro_max_val = 22887 << 16,
93962306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(300),
94062306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
94162306a36Sopenharmony_ci		.accel_max_scale = 18,
94262306a36Sopenharmony_ci		.temp_scale = 5650, /* 5.65 milli degree Celsius */
94362306a36Sopenharmony_ci		.int_clk = 2460000,
94462306a36Sopenharmony_ci		.max_dec_rate = 2048,
94562306a36Sopenharmony_ci		.has_sleep_cnt = true,
94662306a36Sopenharmony_ci		.filter_freqs = adis16480_def_filter_freqs,
94762306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0),
94862306a36Sopenharmony_ci	},
94962306a36Sopenharmony_ci	[ADIS16480] = {
95062306a36Sopenharmony_ci		.channels = adis16480_channels,
95162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16480_channels),
95262306a36Sopenharmony_ci		.gyro_max_val = 22500 << 16,
95362306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
95462306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
95562306a36Sopenharmony_ci		.accel_max_scale = 10,
95662306a36Sopenharmony_ci		.temp_scale = 5650, /* 5.65 milli degree Celsius */
95762306a36Sopenharmony_ci		.int_clk = 2460000,
95862306a36Sopenharmony_ci		.max_dec_rate = 2048,
95962306a36Sopenharmony_ci		.has_sleep_cnt = true,
96062306a36Sopenharmony_ci		.filter_freqs = adis16480_def_filter_freqs,
96162306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0),
96262306a36Sopenharmony_ci	},
96362306a36Sopenharmony_ci	[ADIS16485] = {
96462306a36Sopenharmony_ci		.channels = adis16485_channels,
96562306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
96662306a36Sopenharmony_ci		.gyro_max_val = 22500 << 16,
96762306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
96862306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
96962306a36Sopenharmony_ci		.accel_max_scale = 5,
97062306a36Sopenharmony_ci		.temp_scale = 5650, /* 5.65 milli degree Celsius */
97162306a36Sopenharmony_ci		.int_clk = 2460000,
97262306a36Sopenharmony_ci		.max_dec_rate = 2048,
97362306a36Sopenharmony_ci		.has_sleep_cnt = true,
97462306a36Sopenharmony_ci		.filter_freqs = adis16480_def_filter_freqs,
97562306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0),
97662306a36Sopenharmony_ci	},
97762306a36Sopenharmony_ci	[ADIS16488] = {
97862306a36Sopenharmony_ci		.channels = adis16480_channels,
97962306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16480_channels),
98062306a36Sopenharmony_ci		.gyro_max_val = 22500 << 16,
98162306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
98262306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
98362306a36Sopenharmony_ci		.accel_max_scale = 18,
98462306a36Sopenharmony_ci		.temp_scale = 5650, /* 5.65 milli degree Celsius */
98562306a36Sopenharmony_ci		.int_clk = 2460000,
98662306a36Sopenharmony_ci		.max_dec_rate = 2048,
98762306a36Sopenharmony_ci		.has_sleep_cnt = true,
98862306a36Sopenharmony_ci		.filter_freqs = adis16480_def_filter_freqs,
98962306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0),
99062306a36Sopenharmony_ci	},
99162306a36Sopenharmony_ci	[ADIS16490] = {
99262306a36Sopenharmony_ci		.channels = adis16485_channels,
99362306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
99462306a36Sopenharmony_ci		.gyro_max_val = 20000 << 16,
99562306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(100),
99662306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
99762306a36Sopenharmony_ci		.accel_max_scale = 8,
99862306a36Sopenharmony_ci		.temp_scale = 14285, /* 14.285 milli degree Celsius */
99962306a36Sopenharmony_ci		.int_clk = 4250000,
100062306a36Sopenharmony_ci		.max_dec_rate = 4250,
100162306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
100262306a36Sopenharmony_ci		.has_pps_clk_mode = true,
100362306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0),
100462306a36Sopenharmony_ci	},
100562306a36Sopenharmony_ci	[ADIS16495_1] = {
100662306a36Sopenharmony_ci		.channels = adis16485_channels,
100762306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
100862306a36Sopenharmony_ci		.gyro_max_val = 20000 << 16,
100962306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
101062306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
101162306a36Sopenharmony_ci		.accel_max_scale = 8,
101262306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
101362306a36Sopenharmony_ci		.int_clk = 4250000,
101462306a36Sopenharmony_ci		.max_dec_rate = 4250,
101562306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
101662306a36Sopenharmony_ci		.has_pps_clk_mode = true,
101762306a36Sopenharmony_ci		/* 20 elements of 16bits */
101862306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
101962306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
102062306a36Sopenharmony_ci	},
102162306a36Sopenharmony_ci	[ADIS16495_2] = {
102262306a36Sopenharmony_ci		.channels = adis16485_channels,
102362306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
102462306a36Sopenharmony_ci		.gyro_max_val = 18000 << 16,
102562306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
102662306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
102762306a36Sopenharmony_ci		.accel_max_scale = 8,
102862306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
102962306a36Sopenharmony_ci		.int_clk = 4250000,
103062306a36Sopenharmony_ci		.max_dec_rate = 4250,
103162306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
103262306a36Sopenharmony_ci		.has_pps_clk_mode = true,
103362306a36Sopenharmony_ci		/* 20 elements of 16bits */
103462306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
103562306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
103662306a36Sopenharmony_ci	},
103762306a36Sopenharmony_ci	[ADIS16495_3] = {
103862306a36Sopenharmony_ci		.channels = adis16485_channels,
103962306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
104062306a36Sopenharmony_ci		.gyro_max_val = 20000 << 16,
104162306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
104262306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
104362306a36Sopenharmony_ci		.accel_max_scale = 8,
104462306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
104562306a36Sopenharmony_ci		.int_clk = 4250000,
104662306a36Sopenharmony_ci		.max_dec_rate = 4250,
104762306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
104862306a36Sopenharmony_ci		.has_pps_clk_mode = true,
104962306a36Sopenharmony_ci		/* 20 elements of 16bits */
105062306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts,
105162306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
105262306a36Sopenharmony_ci	},
105362306a36Sopenharmony_ci	[ADIS16497_1] = {
105462306a36Sopenharmony_ci		.channels = adis16485_channels,
105562306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
105662306a36Sopenharmony_ci		.gyro_max_val = 20000 << 16,
105762306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
105862306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
105962306a36Sopenharmony_ci		.accel_max_scale = 40,
106062306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
106162306a36Sopenharmony_ci		.int_clk = 4250000,
106262306a36Sopenharmony_ci		.max_dec_rate = 4250,
106362306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
106462306a36Sopenharmony_ci		.has_pps_clk_mode = true,
106562306a36Sopenharmony_ci		/* 20 elements of 16bits */
106662306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
106762306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
106862306a36Sopenharmony_ci	},
106962306a36Sopenharmony_ci	[ADIS16497_2] = {
107062306a36Sopenharmony_ci		.channels = adis16485_channels,
107162306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
107262306a36Sopenharmony_ci		.gyro_max_val = 18000 << 16,
107362306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
107462306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
107562306a36Sopenharmony_ci		.accel_max_scale = 40,
107662306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
107762306a36Sopenharmony_ci		.int_clk = 4250000,
107862306a36Sopenharmony_ci		.max_dec_rate = 4250,
107962306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
108062306a36Sopenharmony_ci		.has_pps_clk_mode = true,
108162306a36Sopenharmony_ci		/* 20 elements of 16bits */
108262306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
108362306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
108462306a36Sopenharmony_ci	},
108562306a36Sopenharmony_ci	[ADIS16497_3] = {
108662306a36Sopenharmony_ci		.channels = adis16485_channels,
108762306a36Sopenharmony_ci		.num_channels = ARRAY_SIZE(adis16485_channels),
108862306a36Sopenharmony_ci		.gyro_max_val = 20000 << 16,
108962306a36Sopenharmony_ci		.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
109062306a36Sopenharmony_ci		.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
109162306a36Sopenharmony_ci		.accel_max_scale = 40,
109262306a36Sopenharmony_ci		.temp_scale = 12500, /* 12.5 milli degree Celsius */
109362306a36Sopenharmony_ci		.int_clk = 4250000,
109462306a36Sopenharmony_ci		.max_dec_rate = 4250,
109562306a36Sopenharmony_ci		.filter_freqs = adis16495_def_filter_freqs,
109662306a36Sopenharmony_ci		.has_pps_clk_mode = true,
109762306a36Sopenharmony_ci		/* 20 elements of 16bits */
109862306a36Sopenharmony_ci		.adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts,
109962306a36Sopenharmony_ci					    ADIS16495_BURST_MAX_DATA * 2),
110062306a36Sopenharmony_ci	},
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	u32 crc_calc;
110662306a36Sopenharmony_ci	u16 crc_buf[15];
110762306a36Sopenharmony_ci	int j;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	for (j = 0; j < n_elem; j++)
111062306a36Sopenharmony_ci		crc_buf[j] = swab16(buf[j]);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	crc_calc = crc32(~0, crc_buf, n_elem * 2);
111362306a36Sopenharmony_ci	crc_calc ^= ~0;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	return (crc == crc_calc);
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic irqreturn_t adis16480_trigger_handler(int irq, void *p)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
112162306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
112262306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
112362306a36Sopenharmony_ci	struct adis *adis = &st->adis;
112462306a36Sopenharmony_ci	struct device *dev = &adis->spi->dev;
112562306a36Sopenharmony_ci	int ret, bit, offset, i = 0;
112662306a36Sopenharmony_ci	__be16 *buffer;
112762306a36Sopenharmony_ci	u32 crc;
112862306a36Sopenharmony_ci	bool valid;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	adis_dev_lock(adis);
113162306a36Sopenharmony_ci	if (adis->current_page != 0) {
113262306a36Sopenharmony_ci		adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
113362306a36Sopenharmony_ci		adis->tx[1] = 0;
113462306a36Sopenharmony_ci		ret = spi_write(adis->spi, adis->tx, 2);
113562306a36Sopenharmony_ci		if (ret) {
113662306a36Sopenharmony_ci			dev_err(dev, "Failed to change device page: %d\n", ret);
113762306a36Sopenharmony_ci			adis_dev_unlock(adis);
113862306a36Sopenharmony_ci			goto irq_done;
113962306a36Sopenharmony_ci		}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci		adis->current_page = 0;
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ret = spi_sync(adis->spi, &adis->msg);
114562306a36Sopenharmony_ci	if (ret) {
114662306a36Sopenharmony_ci		dev_err(dev, "Failed to read data: %d\n", ret);
114762306a36Sopenharmony_ci		adis_dev_unlock(adis);
114862306a36Sopenharmony_ci		goto irq_done;
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	adis_dev_unlock(adis);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/*
115462306a36Sopenharmony_ci	 * After making the burst request, the response can have one or two
115562306a36Sopenharmony_ci	 * 16-bit responses containing the BURST_ID depending on the sclk. If
115662306a36Sopenharmony_ci	 * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ,
115762306a36Sopenharmony_ci	 * we have only one. To manage that variation, we use the transition from the
115862306a36Sopenharmony_ci	 * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If
115962306a36Sopenharmony_ci	 * we not find this variation in the first 4 segments, then the data should
116062306a36Sopenharmony_ci	 * not be valid.
116162306a36Sopenharmony_ci	 */
116262306a36Sopenharmony_ci	buffer = adis->buffer;
116362306a36Sopenharmony_ci	for (offset = 0; offset < 4; offset++) {
116462306a36Sopenharmony_ci		u16 curr = be16_to_cpu(buffer[offset]);
116562306a36Sopenharmony_ci		u16 next = be16_to_cpu(buffer[offset + 1]);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci		if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) {
116862306a36Sopenharmony_ci			offset++;
116962306a36Sopenharmony_ci			break;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (offset == 4) {
117462306a36Sopenharmony_ci		dev_err(dev, "Invalid burst data\n");
117562306a36Sopenharmony_ci		goto irq_done;
117662306a36Sopenharmony_ci	}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	crc = be16_to_cpu(buffer[offset + 16]) << 16 | be16_to_cpu(buffer[offset + 15]);
117962306a36Sopenharmony_ci	valid = adis16480_validate_crc((u16 *)&buffer[offset], 15, crc);
118062306a36Sopenharmony_ci	if (!valid) {
118162306a36Sopenharmony_ci		dev_err(dev, "Invalid crc\n");
118262306a36Sopenharmony_ci		goto irq_done;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
118662306a36Sopenharmony_ci		/*
118762306a36Sopenharmony_ci		 * When burst mode is used, temperature is the first data
118862306a36Sopenharmony_ci		 * channel in the sequence, but the temperature scan index
118962306a36Sopenharmony_ci		 * is 10.
119062306a36Sopenharmony_ci		 */
119162306a36Sopenharmony_ci		switch (bit) {
119262306a36Sopenharmony_ci		case ADIS16480_SCAN_TEMP:
119362306a36Sopenharmony_ci			st->data[i++] = buffer[offset + 1];
119462306a36Sopenharmony_ci			break;
119562306a36Sopenharmony_ci		case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z:
119662306a36Sopenharmony_ci			/* The lower register data is sequenced first */
119762306a36Sopenharmony_ci			st->data[i++] = buffer[2 * bit + offset + 3];
119862306a36Sopenharmony_ci			st->data[i++] = buffer[2 * bit + offset + 2];
119962306a36Sopenharmony_ci			break;
120062306a36Sopenharmony_ci		}
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp);
120462306a36Sopenharmony_ciirq_done:
120562306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	return IRQ_HANDLED;
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic const struct iio_info adis16480_info = {
121162306a36Sopenharmony_ci	.read_raw = &adis16480_read_raw,
121262306a36Sopenharmony_ci	.write_raw = &adis16480_write_raw,
121362306a36Sopenharmony_ci	.update_scan_mode = adis_update_scan_mode,
121462306a36Sopenharmony_ci	.debugfs_reg_access = adis_debugfs_reg_access,
121562306a36Sopenharmony_ci};
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int adis16480_stop_device(struct iio_dev *indio_dev)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct adis16480 *st = iio_priv(indio_dev);
122062306a36Sopenharmony_ci	struct device *dev = &st->adis.spi->dev;
122162306a36Sopenharmony_ci	int ret;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9));
122462306a36Sopenharmony_ci	if (ret)
122562306a36Sopenharmony_ci		dev_err(dev, "Could not power down device: %d\n", ret);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	return ret;
122862306a36Sopenharmony_ci}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_cistatic int adis16480_enable_irq(struct adis *adis, bool enable)
123162306a36Sopenharmony_ci{
123262306a36Sopenharmony_ci	uint16_t val;
123362306a36Sopenharmony_ci	int ret;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
123662306a36Sopenharmony_ci	if (ret)
123762306a36Sopenharmony_ci		return ret;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	val &= ~ADIS16480_DRDY_EN_MSK;
124062306a36Sopenharmony_ci	val |= ADIS16480_DRDY_EN(enable);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic int adis16480_config_irq_pin(struct adis16480 *st)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	struct device *dev = &st->adis.spi->dev;
124862306a36Sopenharmony_ci	struct fwnode_handle *fwnode = dev_fwnode(dev);
124962306a36Sopenharmony_ci	struct irq_data *desc;
125062306a36Sopenharmony_ci	enum adis16480_int_pin pin;
125162306a36Sopenharmony_ci	unsigned int irq_type;
125262306a36Sopenharmony_ci	uint16_t val;
125362306a36Sopenharmony_ci	int i, irq = 0;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	desc = irq_get_irq_data(st->adis.spi->irq);
125662306a36Sopenharmony_ci	if (!desc) {
125762306a36Sopenharmony_ci		dev_err(dev, "Could not find IRQ %d\n", irq);
125862306a36Sopenharmony_ci		return -EINVAL;
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	/* Disable data ready since the default after reset is on */
126262306a36Sopenharmony_ci	val = ADIS16480_DRDY_EN(0);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/*
126562306a36Sopenharmony_ci	 * Get the interrupt from the devicetre by reading the interrupt-names
126662306a36Sopenharmony_ci	 * property. If it is not specified, use DIO1 pin as default.
126762306a36Sopenharmony_ci	 * According to the datasheet, the factory default assigns DIO2 as data
126862306a36Sopenharmony_ci	 * ready signal. However, in the previous versions of the driver, DIO1
126962306a36Sopenharmony_ci	 * pin was used. So, we should leave it as is since some devices might
127062306a36Sopenharmony_ci	 * be expecting the interrupt on the wrong physical pin.
127162306a36Sopenharmony_ci	 */
127262306a36Sopenharmony_ci	pin = ADIS16480_PIN_DIO1;
127362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
127462306a36Sopenharmony_ci		irq = fwnode_irq_get_byname(fwnode, adis16480_int_pin_names[i]);
127562306a36Sopenharmony_ci		if (irq > 0) {
127662306a36Sopenharmony_ci			pin = i;
127762306a36Sopenharmony_ci			break;
127862306a36Sopenharmony_ci		}
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	val |= ADIS16480_DRDY_SEL(pin);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/*
128462306a36Sopenharmony_ci	 * Get the interrupt line behaviour. The data ready polarity can be
128562306a36Sopenharmony_ci	 * configured as positive or negative, corresponding to
128662306a36Sopenharmony_ci	 * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively.
128762306a36Sopenharmony_ci	 */
128862306a36Sopenharmony_ci	irq_type = irqd_get_trigger_type(desc);
128962306a36Sopenharmony_ci	if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */
129062306a36Sopenharmony_ci		val |= ADIS16480_DRDY_POL(1);
129162306a36Sopenharmony_ci	} else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
129262306a36Sopenharmony_ci		val |= ADIS16480_DRDY_POL(0);
129362306a36Sopenharmony_ci	} else {
129462306a36Sopenharmony_ci		dev_err(dev, "Invalid interrupt type 0x%x specified\n", irq_type);
129562306a36Sopenharmony_ci		return -EINVAL;
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci	/* Write the data ready configuration to the FNCTIO_CTRL register */
129862306a36Sopenharmony_ci	return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic int adis16480_fw_get_ext_clk_pin(struct adis16480 *st)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct device *dev = &st->adis.spi->dev;
130462306a36Sopenharmony_ci	const char *ext_clk_pin;
130562306a36Sopenharmony_ci	enum adis16480_int_pin pin;
130662306a36Sopenharmony_ci	int i;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	pin = ADIS16480_PIN_DIO2;
130962306a36Sopenharmony_ci	if (device_property_read_string(dev, "adi,ext-clk-pin", &ext_clk_pin))
131062306a36Sopenharmony_ci		goto clk_input_not_found;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) {
131362306a36Sopenharmony_ci		if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0)
131462306a36Sopenharmony_ci			return i;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ciclk_input_not_found:
131862306a36Sopenharmony_ci	dev_info(dev, "clk input line not specified, using DIO2\n");
131962306a36Sopenharmony_ci	return pin;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic int adis16480_ext_clk_config(struct adis16480 *st, bool enable)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct device *dev = &st->adis.spi->dev;
132562306a36Sopenharmony_ci	unsigned int mode, mask;
132662306a36Sopenharmony_ci	enum adis16480_int_pin pin;
132762306a36Sopenharmony_ci	uint16_t val;
132862306a36Sopenharmony_ci	int ret;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val);
133162306a36Sopenharmony_ci	if (ret)
133262306a36Sopenharmony_ci		return ret;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	pin = adis16480_fw_get_ext_clk_pin(st);
133562306a36Sopenharmony_ci	/*
133662306a36Sopenharmony_ci	 * Each DIOx pin supports only one function at a time. When a single pin
133762306a36Sopenharmony_ci	 * has two assignments, the enable bit for a lower priority function
133862306a36Sopenharmony_ci	 * automatically resets to zero (disabling the lower priority function).
133962306a36Sopenharmony_ci	 */
134062306a36Sopenharmony_ci	if (pin == ADIS16480_DRDY_SEL(val))
134162306a36Sopenharmony_ci		dev_warn(dev, "DIO%x pin supports only one function at a time\n", pin + 1);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin);
134462306a36Sopenharmony_ci	mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK;
134562306a36Sopenharmony_ci	/* Only ADIS1649x devices support pps ext clock mode */
134662306a36Sopenharmony_ci	if (st->chip_info->has_pps_clk_mode) {
134762306a36Sopenharmony_ci		mode |= ADIS16480_SYNC_MODE(st->clk_mode);
134862306a36Sopenharmony_ci		mask |= ADIS16480_SYNC_MODE_MSK;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	val &= ~mask;
135262306a36Sopenharmony_ci	val |= mode;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
135562306a36Sopenharmony_ci	if (ret)
135662306a36Sopenharmony_ci		return ret;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	return clk_prepare_enable(st->ext_clk);
135962306a36Sopenharmony_ci}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_cistatic int adis16480_get_ext_clocks(struct adis16480 *st)
136262306a36Sopenharmony_ci{
136362306a36Sopenharmony_ci	struct device *dev = &st->adis.spi->dev;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	st->ext_clk = devm_clk_get_optional(dev, "sync");
136662306a36Sopenharmony_ci	if (IS_ERR(st->ext_clk))
136762306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(st->ext_clk), "failed to get ext clk\n");
136862306a36Sopenharmony_ci	if (st->ext_clk) {
136962306a36Sopenharmony_ci		st->clk_mode = ADIS16480_CLK_SYNC;
137062306a36Sopenharmony_ci		return 0;
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (st->chip_info->has_pps_clk_mode) {
137462306a36Sopenharmony_ci		st->ext_clk = devm_clk_get_optional(dev, "pps");
137562306a36Sopenharmony_ci		if (IS_ERR(st->ext_clk))
137662306a36Sopenharmony_ci			return dev_err_probe(dev, PTR_ERR(st->ext_clk), "failed to get ext clk\n");
137762306a36Sopenharmony_ci		if (st->ext_clk) {
137862306a36Sopenharmony_ci			st->clk_mode = ADIS16480_CLK_PPS;
137962306a36Sopenharmony_ci			return 0;
138062306a36Sopenharmony_ci		}
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	st->clk_mode = ADIS16480_CLK_INT;
138462306a36Sopenharmony_ci	return 0;
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic void adis16480_stop(void *data)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	adis16480_stop_device(data);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void adis16480_clk_disable(void *data)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	clk_disable_unprepare(data);
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_cistatic int adis16480_probe(struct spi_device *spi)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	const struct spi_device_id *id = spi_get_device_id(spi);
140062306a36Sopenharmony_ci	const struct adis_data *adis16480_data;
140162306a36Sopenharmony_ci	irq_handler_t trigger_handler = NULL;
140262306a36Sopenharmony_ci	struct device *dev = &spi->dev;
140362306a36Sopenharmony_ci	struct iio_dev *indio_dev;
140462306a36Sopenharmony_ci	struct adis16480 *st;
140562306a36Sopenharmony_ci	int ret;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
140862306a36Sopenharmony_ci	if (indio_dev == NULL)
140962306a36Sopenharmony_ci		return -ENOMEM;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	st = iio_priv(indio_dev);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	st->chip_info = &adis16480_chip_info[id->driver_data];
141462306a36Sopenharmony_ci	indio_dev->name = spi_get_device_id(spi)->name;
141562306a36Sopenharmony_ci	indio_dev->channels = st->chip_info->channels;
141662306a36Sopenharmony_ci	indio_dev->num_channels = st->chip_info->num_channels;
141762306a36Sopenharmony_ci	indio_dev->info = &adis16480_info;
141862306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	adis16480_data = &st->chip_info->adis_data;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	ret = adis_init(&st->adis, indio_dev, spi, adis16480_data);
142362306a36Sopenharmony_ci	if (ret)
142462306a36Sopenharmony_ci		return ret;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	ret = __adis_initial_startup(&st->adis);
142762306a36Sopenharmony_ci	if (ret)
142862306a36Sopenharmony_ci		return ret;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (st->chip_info->has_sleep_cnt) {
143162306a36Sopenharmony_ci		ret = devm_add_action_or_reset(dev, adis16480_stop, indio_dev);
143262306a36Sopenharmony_ci		if (ret)
143362306a36Sopenharmony_ci			return ret;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	ret = adis16480_config_irq_pin(st);
143762306a36Sopenharmony_ci	if (ret)
143862306a36Sopenharmony_ci		return ret;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	ret = adis16480_get_ext_clocks(st);
144162306a36Sopenharmony_ci	if (ret)
144262306a36Sopenharmony_ci		return ret;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (st->ext_clk) {
144562306a36Sopenharmony_ci		ret = adis16480_ext_clk_config(st, true);
144662306a36Sopenharmony_ci		if (ret)
144762306a36Sopenharmony_ci			return ret;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		ret = devm_add_action_or_reset(dev, adis16480_clk_disable, st->ext_clk);
145062306a36Sopenharmony_ci		if (ret)
145162306a36Sopenharmony_ci			return ret;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci		st->clk_freq = clk_get_rate(st->ext_clk);
145462306a36Sopenharmony_ci		st->clk_freq *= 1000; /* micro */
145562306a36Sopenharmony_ci		if (st->clk_mode == ADIS16480_CLK_PPS) {
145662306a36Sopenharmony_ci			u16 sync_scale;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci			/*
145962306a36Sopenharmony_ci			 * In PPS mode, the IMU sample rate is the clk_freq * sync_scale. Hence,
146062306a36Sopenharmony_ci			 * default the IMU sample rate to the highest multiple of the input clock
146162306a36Sopenharmony_ci			 * lower than the IMU max sample rate. The internal sample rate is the
146262306a36Sopenharmony_ci			 * max...
146362306a36Sopenharmony_ci			 */
146462306a36Sopenharmony_ci			sync_scale = st->chip_info->int_clk / st->clk_freq;
146562306a36Sopenharmony_ci			ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale);
146662306a36Sopenharmony_ci			if (ret)
146762306a36Sopenharmony_ci				return ret;
146862306a36Sopenharmony_ci		}
146962306a36Sopenharmony_ci	} else {
147062306a36Sopenharmony_ci		st->clk_freq = st->chip_info->int_clk;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	/* Only use our trigger handler if burst mode is supported */
147462306a36Sopenharmony_ci	if (adis16480_data->burst_len)
147562306a36Sopenharmony_ci		trigger_handler = adis16480_trigger_handler;
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
147862306a36Sopenharmony_ci						 trigger_handler);
147962306a36Sopenharmony_ci	if (ret)
148062306a36Sopenharmony_ci		return ret;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	ret = devm_iio_device_register(dev, indio_dev);
148362306a36Sopenharmony_ci	if (ret)
148462306a36Sopenharmony_ci		return ret;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	adis16480_debugfs_init(indio_dev);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	return 0;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic const struct spi_device_id adis16480_ids[] = {
149262306a36Sopenharmony_ci	{ "adis16375", ADIS16375 },
149362306a36Sopenharmony_ci	{ "adis16480", ADIS16480 },
149462306a36Sopenharmony_ci	{ "adis16485", ADIS16485 },
149562306a36Sopenharmony_ci	{ "adis16488", ADIS16488 },
149662306a36Sopenharmony_ci	{ "adis16490", ADIS16490 },
149762306a36Sopenharmony_ci	{ "adis16495-1", ADIS16495_1 },
149862306a36Sopenharmony_ci	{ "adis16495-2", ADIS16495_2 },
149962306a36Sopenharmony_ci	{ "adis16495-3", ADIS16495_3 },
150062306a36Sopenharmony_ci	{ "adis16497-1", ADIS16497_1 },
150162306a36Sopenharmony_ci	{ "adis16497-2", ADIS16497_2 },
150262306a36Sopenharmony_ci	{ "adis16497-3", ADIS16497_3 },
150362306a36Sopenharmony_ci	{ }
150462306a36Sopenharmony_ci};
150562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adis16480_ids);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_cistatic const struct of_device_id adis16480_of_match[] = {
150862306a36Sopenharmony_ci	{ .compatible = "adi,adis16375" },
150962306a36Sopenharmony_ci	{ .compatible = "adi,adis16480" },
151062306a36Sopenharmony_ci	{ .compatible = "adi,adis16485" },
151162306a36Sopenharmony_ci	{ .compatible = "adi,adis16488" },
151262306a36Sopenharmony_ci	{ .compatible = "adi,adis16490" },
151362306a36Sopenharmony_ci	{ .compatible = "adi,adis16495-1" },
151462306a36Sopenharmony_ci	{ .compatible = "adi,adis16495-2" },
151562306a36Sopenharmony_ci	{ .compatible = "adi,adis16495-3" },
151662306a36Sopenharmony_ci	{ .compatible = "adi,adis16497-1" },
151762306a36Sopenharmony_ci	{ .compatible = "adi,adis16497-2" },
151862306a36Sopenharmony_ci	{ .compatible = "adi,adis16497-3" },
151962306a36Sopenharmony_ci	{ },
152062306a36Sopenharmony_ci};
152162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adis16480_of_match);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_cistatic struct spi_driver adis16480_driver = {
152462306a36Sopenharmony_ci	.driver = {
152562306a36Sopenharmony_ci		.name = "adis16480",
152662306a36Sopenharmony_ci		.of_match_table = adis16480_of_match,
152762306a36Sopenharmony_ci	},
152862306a36Sopenharmony_ci	.id_table = adis16480_ids,
152962306a36Sopenharmony_ci	.probe = adis16480_probe,
153062306a36Sopenharmony_ci};
153162306a36Sopenharmony_cimodule_spi_driver(adis16480_driver);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
153462306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
153562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
153662306a36Sopenharmony_ciMODULE_IMPORT_NS(IIO_ADISLIB);
1537