162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADIS16133/ADIS16135/ADIS16136 gyroscope driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012 Analog Devices Inc.
662306a36Sopenharmony_ci *   Author: Lars-Peter Clausen <lars@metafoo.de>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/spi/spi.h>
1262306a36Sopenharmony_ci#include <linux/sysfs.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/iio/iio.h>
1662306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
1762306a36Sopenharmony_ci#include <linux/iio/imu/adis.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/debugfs.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define ADIS16136_REG_FLASH_CNT		0x00
2262306a36Sopenharmony_ci#define ADIS16136_REG_TEMP_OUT		0x02
2362306a36Sopenharmony_ci#define ADIS16136_REG_GYRO_OUT2		0x04
2462306a36Sopenharmony_ci#define ADIS16136_REG_GYRO_OUT		0x06
2562306a36Sopenharmony_ci#define ADIS16136_REG_GYRO_OFF2		0x08
2662306a36Sopenharmony_ci#define ADIS16136_REG_GYRO_OFF		0x0A
2762306a36Sopenharmony_ci#define ADIS16136_REG_ALM_MAG1		0x10
2862306a36Sopenharmony_ci#define ADIS16136_REG_ALM_MAG2		0x12
2962306a36Sopenharmony_ci#define ADIS16136_REG_ALM_SAMPL1	0x14
3062306a36Sopenharmony_ci#define ADIS16136_REG_ALM_SAMPL2	0x16
3162306a36Sopenharmony_ci#define ADIS16136_REG_ALM_CTRL		0x18
3262306a36Sopenharmony_ci#define ADIS16136_REG_GPIO_CTRL		0x1A
3362306a36Sopenharmony_ci#define ADIS16136_REG_MSC_CTRL		0x1C
3462306a36Sopenharmony_ci#define ADIS16136_REG_SMPL_PRD		0x1E
3562306a36Sopenharmony_ci#define ADIS16136_REG_AVG_CNT		0x20
3662306a36Sopenharmony_ci#define ADIS16136_REG_DEC_RATE		0x22
3762306a36Sopenharmony_ci#define ADIS16136_REG_SLP_CTRL		0x24
3862306a36Sopenharmony_ci#define ADIS16136_REG_DIAG_STAT		0x26
3962306a36Sopenharmony_ci#define ADIS16136_REG_GLOB_CMD		0x28
4062306a36Sopenharmony_ci#define ADIS16136_REG_LOT1		0x32
4162306a36Sopenharmony_ci#define ADIS16136_REG_LOT2		0x34
4262306a36Sopenharmony_ci#define ADIS16136_REG_LOT3		0x36
4362306a36Sopenharmony_ci#define ADIS16136_REG_PROD_ID		0x38
4462306a36Sopenharmony_ci#define ADIS16136_REG_SERIAL_NUM	0x3A
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL	2
4762306a36Sopenharmony_ci#define ADIS16136_DIAG_STAT_SPI_FAIL		3
4862306a36Sopenharmony_ci#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL	5
4962306a36Sopenharmony_ci#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL	6
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11)
5262306a36Sopenharmony_ci#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct adis16136_chip_info {
5562306a36Sopenharmony_ci	unsigned int precision;
5662306a36Sopenharmony_ci	unsigned int fullscale;
5762306a36Sopenharmony_ci	const struct adis_data adis_data;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct adis16136 {
6162306a36Sopenharmony_ci	const struct adis16136_chip_info *chip_info;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	struct adis adis;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic ssize_t adis16136_show_serial(struct file *file,
6962306a36Sopenharmony_ci		char __user *userbuf, size_t count, loff_t *ppos)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct adis16136 *adis16136 = file->private_data;
7262306a36Sopenharmony_ci	uint16_t lot1, lot2, lot3, serial;
7362306a36Sopenharmony_ci	char buf[20];
7462306a36Sopenharmony_ci	size_t len;
7562306a36Sopenharmony_ci	int ret;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
7862306a36Sopenharmony_ci		&serial);
7962306a36Sopenharmony_ci	if (ret)
8062306a36Sopenharmony_ci		return ret;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
8362306a36Sopenharmony_ci	if (ret)
8462306a36Sopenharmony_ci		return ret;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
8762306a36Sopenharmony_ci	if (ret)
8862306a36Sopenharmony_ci		return ret;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
9162306a36Sopenharmony_ci	if (ret)
9262306a36Sopenharmony_ci		return ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
9562306a36Sopenharmony_ci		lot3, serial);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const struct file_operations adis16136_serial_fops = {
10162306a36Sopenharmony_ci	.open = simple_open,
10262306a36Sopenharmony_ci	.read = adis16136_show_serial,
10362306a36Sopenharmony_ci	.llseek = default_llseek,
10462306a36Sopenharmony_ci	.owner = THIS_MODULE,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int adis16136_show_product_id(void *arg, u64 *val)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct adis16136 *adis16136 = arg;
11062306a36Sopenharmony_ci	u16 prod_id;
11162306a36Sopenharmony_ci	int ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
11462306a36Sopenharmony_ci		&prod_id);
11562306a36Sopenharmony_ci	if (ret)
11662306a36Sopenharmony_ci		return ret;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	*val = prod_id;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16136_product_id_fops,
12362306a36Sopenharmony_ci	adis16136_show_product_id, NULL, "%llu\n");
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int adis16136_show_flash_count(void *arg, u64 *val)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct adis16136 *adis16136 = arg;
12862306a36Sopenharmony_ci	uint16_t flash_count;
12962306a36Sopenharmony_ci	int ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
13262306a36Sopenharmony_ci		&flash_count);
13362306a36Sopenharmony_ci	if (ret)
13462306a36Sopenharmony_ci		return ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	*val = flash_count;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16136_flash_count_fops,
14162306a36Sopenharmony_ci	adis16136_show_flash_count, NULL, "%lld\n");
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int adis16136_debugfs_init(struct iio_dev *indio_dev)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
14662306a36Sopenharmony_ci	struct dentry *d = iio_get_debugfs_dentry(indio_dev);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	debugfs_create_file_unsafe("serial_number", 0400,
14962306a36Sopenharmony_ci		d, adis16136, &adis16136_serial_fops);
15062306a36Sopenharmony_ci	debugfs_create_file_unsafe("product_id", 0400,
15162306a36Sopenharmony_ci		d, adis16136, &adis16136_product_id_fops);
15262306a36Sopenharmony_ci	debugfs_create_file_unsafe("flash_count", 0400,
15362306a36Sopenharmony_ci		d, adis16136, &adis16136_flash_count_fops);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return 0;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#else
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int adis16136_debugfs_init(struct iio_dev *indio_dev)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#endif
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	unsigned int t;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	t = 32768 / freq;
17262306a36Sopenharmony_ci	if (t < 0xf)
17362306a36Sopenharmony_ci		t = 0xf;
17462306a36Sopenharmony_ci	else if (t > 0xffff)
17562306a36Sopenharmony_ci		t = 0xffff;
17662306a36Sopenharmony_ci	else
17762306a36Sopenharmony_ci		t--;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	uint16_t t;
18562306a36Sopenharmony_ci	int ret;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
18862306a36Sopenharmony_ci	if (ret)
18962306a36Sopenharmony_ci		return ret;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	*freq = 32768 / (t + 1);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return 0;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic ssize_t adis16136_write_frequency(struct device *dev,
19762306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t len)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
20062306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
20162306a36Sopenharmony_ci	unsigned int val;
20262306a36Sopenharmony_ci	int ret;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret = kstrtouint(buf, 10, &val);
20562306a36Sopenharmony_ci	if (ret)
20662306a36Sopenharmony_ci		return ret;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (val == 0)
20962306a36Sopenharmony_ci		return -EINVAL;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	ret = adis16136_set_freq(adis16136, val);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return ret ? ret : len;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic ssize_t adis16136_read_frequency(struct device *dev,
21762306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
22062306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
22162306a36Sopenharmony_ci	unsigned int freq;
22262306a36Sopenharmony_ci	int ret;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	adis_dev_lock(&adis16136->adis);
22562306a36Sopenharmony_ci	ret = __adis16136_get_freq(adis16136, &freq);
22662306a36Sopenharmony_ci	adis_dev_unlock(&adis16136->adis);
22762306a36Sopenharmony_ci	if (ret)
22862306a36Sopenharmony_ci		return ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return sprintf(buf, "%d\n", freq);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
23462306a36Sopenharmony_ci				  adis16136_read_frequency,
23562306a36Sopenharmony_ci				  adis16136_write_frequency);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const unsigned adis16136_3db_divisors[] = {
23862306a36Sopenharmony_ci	[0] = 2, /* Special case */
23962306a36Sopenharmony_ci	[1] = 6,
24062306a36Sopenharmony_ci	[2] = 12,
24162306a36Sopenharmony_ci	[3] = 25,
24262306a36Sopenharmony_ci	[4] = 50,
24362306a36Sopenharmony_ci	[5] = 100,
24462306a36Sopenharmony_ci	[6] = 200,
24562306a36Sopenharmony_ci	[7] = 200, /* Not a valid setting */
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int adis16136_set_filter(struct iio_dev *indio_dev, int val)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
25162306a36Sopenharmony_ci	unsigned int freq;
25262306a36Sopenharmony_ci	int i, ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	adis_dev_lock(&adis16136->adis);
25562306a36Sopenharmony_ci	ret = __adis16136_get_freq(adis16136, &freq);
25662306a36Sopenharmony_ci	if (ret)
25762306a36Sopenharmony_ci		goto out_unlock;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
26062306a36Sopenharmony_ci		if (freq / adis16136_3db_divisors[i] >= val)
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
26562306a36Sopenharmony_ciout_unlock:
26662306a36Sopenharmony_ci	adis_dev_unlock(&adis16136->adis);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return ret;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
27462306a36Sopenharmony_ci	unsigned int freq;
27562306a36Sopenharmony_ci	uint16_t val16;
27662306a36Sopenharmony_ci	int ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	adis_dev_lock(&adis16136->adis);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
28162306a36Sopenharmony_ci				 &val16);
28262306a36Sopenharmony_ci	if (ret)
28362306a36Sopenharmony_ci		goto err_unlock;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	ret = __adis16136_get_freq(adis16136, &freq);
28662306a36Sopenharmony_ci	if (ret)
28762306a36Sopenharmony_ci		goto err_unlock;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	*val = freq / adis16136_3db_divisors[val16 & 0x07];
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cierr_unlock:
29262306a36Sopenharmony_ci	adis_dev_unlock(&adis16136->adis);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret ? ret : IIO_VAL_INT;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int adis16136_read_raw(struct iio_dev *indio_dev,
29862306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int *val, int *val2, long info)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
30162306a36Sopenharmony_ci	uint32_t val32;
30262306a36Sopenharmony_ci	int ret;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	switch (info) {
30562306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
30662306a36Sopenharmony_ci		return adis_single_conversion(indio_dev, chan, 0, val);
30762306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
30862306a36Sopenharmony_ci		switch (chan->type) {
30962306a36Sopenharmony_ci		case IIO_ANGL_VEL:
31062306a36Sopenharmony_ci			*val = adis16136->chip_info->precision;
31162306a36Sopenharmony_ci			*val2 = (adis16136->chip_info->fullscale << 16);
31262306a36Sopenharmony_ci			return IIO_VAL_FRACTIONAL;
31362306a36Sopenharmony_ci		case IIO_TEMP:
31462306a36Sopenharmony_ci			*val = 10;
31562306a36Sopenharmony_ci			*val2 = 697000; /* 0.010697 degree Celsius */
31662306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_MICRO;
31762306a36Sopenharmony_ci		default:
31862306a36Sopenharmony_ci			return -EINVAL;
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
32162306a36Sopenharmony_ci		ret = adis_read_reg_32(&adis16136->adis,
32262306a36Sopenharmony_ci			ADIS16136_REG_GYRO_OFF2, &val32);
32362306a36Sopenharmony_ci		if (ret)
32462306a36Sopenharmony_ci			return ret;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		*val = sign_extend32(val32, 31);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		return IIO_VAL_INT;
32962306a36Sopenharmony_ci	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
33062306a36Sopenharmony_ci		return adis16136_get_filter(indio_dev, val);
33162306a36Sopenharmony_ci	default:
33262306a36Sopenharmony_ci		return -EINVAL;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int adis16136_write_raw(struct iio_dev *indio_dev,
33762306a36Sopenharmony_ci	const struct iio_chan_spec *chan, int val, int val2, long info)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	switch (info) {
34262306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
34362306a36Sopenharmony_ci		return adis_write_reg_32(&adis16136->adis,
34462306a36Sopenharmony_ci			ADIS16136_REG_GYRO_OFF2, val);
34562306a36Sopenharmony_ci	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
34662306a36Sopenharmony_ci		return adis16136_set_filter(indio_dev, val);
34762306a36Sopenharmony_ci	default:
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return -EINVAL;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cienum {
35562306a36Sopenharmony_ci	ADIS16136_SCAN_GYRO,
35662306a36Sopenharmony_ci	ADIS16136_SCAN_TEMP,
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic const struct iio_chan_spec adis16136_channels[] = {
36062306a36Sopenharmony_ci	{
36162306a36Sopenharmony_ci		.type = IIO_ANGL_VEL,
36262306a36Sopenharmony_ci		.modified = 1,
36362306a36Sopenharmony_ci		.channel2 = IIO_MOD_X,
36462306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
36562306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS) |
36662306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
36762306a36Sopenharmony_ci		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		.address = ADIS16136_REG_GYRO_OUT2,
37062306a36Sopenharmony_ci		.scan_index = ADIS16136_SCAN_GYRO,
37162306a36Sopenharmony_ci		.scan_type = {
37262306a36Sopenharmony_ci			.sign = 's',
37362306a36Sopenharmony_ci			.realbits = 32,
37462306a36Sopenharmony_ci			.storagebits = 32,
37562306a36Sopenharmony_ci			.endianness = IIO_BE,
37662306a36Sopenharmony_ci		},
37762306a36Sopenharmony_ci	}, {
37862306a36Sopenharmony_ci		.type = IIO_TEMP,
37962306a36Sopenharmony_ci		.indexed = 1,
38062306a36Sopenharmony_ci		.channel = 0,
38162306a36Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
38262306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE),
38362306a36Sopenharmony_ci		.address = ADIS16136_REG_TEMP_OUT,
38462306a36Sopenharmony_ci		.scan_index = ADIS16136_SCAN_TEMP,
38562306a36Sopenharmony_ci		.scan_type = {
38662306a36Sopenharmony_ci			.sign = 's',
38762306a36Sopenharmony_ci			.realbits = 16,
38862306a36Sopenharmony_ci			.storagebits = 16,
38962306a36Sopenharmony_ci			.endianness = IIO_BE,
39062306a36Sopenharmony_ci		},
39162306a36Sopenharmony_ci	},
39262306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(2),
39362306a36Sopenharmony_ci};
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic struct attribute *adis16136_attributes[] = {
39662306a36Sopenharmony_ci	&iio_dev_attr_sampling_frequency.dev_attr.attr,
39762306a36Sopenharmony_ci	NULL
39862306a36Sopenharmony_ci};
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic const struct attribute_group adis16136_attribute_group = {
40162306a36Sopenharmony_ci	.attrs = adis16136_attributes,
40262306a36Sopenharmony_ci};
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic const struct iio_info adis16136_info = {
40562306a36Sopenharmony_ci	.attrs = &adis16136_attribute_group,
40662306a36Sopenharmony_ci	.read_raw = &adis16136_read_raw,
40762306a36Sopenharmony_ci	.write_raw = &adis16136_write_raw,
40862306a36Sopenharmony_ci	.update_scan_mode = adis_update_scan_mode,
40962306a36Sopenharmony_ci	.debugfs_reg_access = adis_debugfs_reg_access,
41062306a36Sopenharmony_ci};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic int adis16136_stop_device(struct iio_dev *indio_dev)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
41562306a36Sopenharmony_ci	int ret;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff);
41862306a36Sopenharmony_ci	if (ret)
41962306a36Sopenharmony_ci		dev_err(&indio_dev->dev,
42062306a36Sopenharmony_ci			"Could not power down device: %d\n", ret);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return ret;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int adis16136_initial_setup(struct iio_dev *indio_dev)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct adis16136 *adis16136 = iio_priv(indio_dev);
42862306a36Sopenharmony_ci	unsigned int device_id;
42962306a36Sopenharmony_ci	uint16_t prod_id;
43062306a36Sopenharmony_ci	int ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	ret = __adis_initial_startup(&adis16136->adis);
43362306a36Sopenharmony_ci	if (ret)
43462306a36Sopenharmony_ci		return ret;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
43762306a36Sopenharmony_ci		&prod_id);
43862306a36Sopenharmony_ci	if (ret)
43962306a36Sopenharmony_ci		return ret;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
44262306a36Sopenharmony_ci	if (ret != 1)
44362306a36Sopenharmony_ci		return -EINVAL;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (prod_id != device_id)
44662306a36Sopenharmony_ci		dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
44762306a36Sopenharmony_ci				device_id, prod_id);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return 0;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const char * const adis16136_status_error_msgs[] = {
45362306a36Sopenharmony_ci	[ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed",
45462306a36Sopenharmony_ci	[ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure",
45562306a36Sopenharmony_ci	[ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error",
45662306a36Sopenharmony_ci	[ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
45762306a36Sopenharmony_ci};
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci#define ADIS16136_DATA(_timeouts)					\
46062306a36Sopenharmony_ci{									\
46162306a36Sopenharmony_ci	.diag_stat_reg = ADIS16136_REG_DIAG_STAT,			\
46262306a36Sopenharmony_ci	.glob_cmd_reg = ADIS16136_REG_GLOB_CMD,				\
46362306a36Sopenharmony_ci	.msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,				\
46462306a36Sopenharmony_ci	.self_test_reg = ADIS16136_REG_MSC_CTRL,			\
46562306a36Sopenharmony_ci	.self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,			\
46662306a36Sopenharmony_ci	.read_delay = 10,						\
46762306a36Sopenharmony_ci	.write_delay = 10,						\
46862306a36Sopenharmony_ci	.status_error_msgs = adis16136_status_error_msgs,		\
46962306a36Sopenharmony_ci	.status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |	\
47062306a36Sopenharmony_ci		BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |			\
47162306a36Sopenharmony_ci		BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |		\
47262306a36Sopenharmony_ci		BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),		\
47362306a36Sopenharmony_ci	.timeouts = (_timeouts),					\
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cienum adis16136_id {
47762306a36Sopenharmony_ci	ID_ADIS16133,
47862306a36Sopenharmony_ci	ID_ADIS16135,
47962306a36Sopenharmony_ci	ID_ADIS16136,
48062306a36Sopenharmony_ci	ID_ADIS16137,
48162306a36Sopenharmony_ci};
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic const struct adis_timeout adis16133_timeouts = {
48462306a36Sopenharmony_ci	.reset_ms = 75,
48562306a36Sopenharmony_ci	.sw_reset_ms = 75,
48662306a36Sopenharmony_ci	.self_test_ms = 50,
48762306a36Sopenharmony_ci};
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic const struct adis_timeout adis16136_timeouts = {
49062306a36Sopenharmony_ci	.reset_ms = 128,
49162306a36Sopenharmony_ci	.sw_reset_ms = 75,
49262306a36Sopenharmony_ci	.self_test_ms = 245,
49362306a36Sopenharmony_ci};
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic const struct adis16136_chip_info adis16136_chip_info[] = {
49662306a36Sopenharmony_ci	[ID_ADIS16133] = {
49762306a36Sopenharmony_ci		.precision = IIO_DEGREE_TO_RAD(1200),
49862306a36Sopenharmony_ci		.fullscale = 24000,
49962306a36Sopenharmony_ci		.adis_data = ADIS16136_DATA(&adis16133_timeouts),
50062306a36Sopenharmony_ci	},
50162306a36Sopenharmony_ci	[ID_ADIS16135] = {
50262306a36Sopenharmony_ci		.precision = IIO_DEGREE_TO_RAD(300),
50362306a36Sopenharmony_ci		.fullscale = 24000,
50462306a36Sopenharmony_ci		.adis_data = ADIS16136_DATA(&adis16133_timeouts),
50562306a36Sopenharmony_ci	},
50662306a36Sopenharmony_ci	[ID_ADIS16136] = {
50762306a36Sopenharmony_ci		.precision = IIO_DEGREE_TO_RAD(450),
50862306a36Sopenharmony_ci		.fullscale = 24623,
50962306a36Sopenharmony_ci		.adis_data = ADIS16136_DATA(&adis16136_timeouts),
51062306a36Sopenharmony_ci	},
51162306a36Sopenharmony_ci	[ID_ADIS16137] = {
51262306a36Sopenharmony_ci		.precision = IIO_DEGREE_TO_RAD(1000),
51362306a36Sopenharmony_ci		.fullscale = 24609,
51462306a36Sopenharmony_ci		.adis_data = ADIS16136_DATA(&adis16136_timeouts),
51562306a36Sopenharmony_ci	},
51662306a36Sopenharmony_ci};
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void adis16136_stop(void *data)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	adis16136_stop_device(data);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic int adis16136_probe(struct spi_device *spi)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	const struct spi_device_id *id = spi_get_device_id(spi);
52662306a36Sopenharmony_ci	struct adis16136 *adis16136;
52762306a36Sopenharmony_ci	struct iio_dev *indio_dev;
52862306a36Sopenharmony_ci	const struct adis_data *adis16136_data;
52962306a36Sopenharmony_ci	int ret;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
53262306a36Sopenharmony_ci	if (indio_dev == NULL)
53362306a36Sopenharmony_ci		return -ENOMEM;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	spi_set_drvdata(spi, indio_dev);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	adis16136 = iio_priv(indio_dev);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	adis16136->chip_info = &adis16136_chip_info[id->driver_data];
54062306a36Sopenharmony_ci	indio_dev->name = spi_get_device_id(spi)->name;
54162306a36Sopenharmony_ci	indio_dev->channels = adis16136_channels;
54262306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
54362306a36Sopenharmony_ci	indio_dev->info = &adis16136_info;
54462306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	adis16136_data = &adis16136->chip_info->adis_data;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data);
54962306a36Sopenharmony_ci	if (ret)
55062306a36Sopenharmony_ci		return ret;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	ret = devm_adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
55362306a36Sopenharmony_ci	if (ret)
55462306a36Sopenharmony_ci		return ret;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ret = adis16136_initial_setup(indio_dev);
55762306a36Sopenharmony_ci	if (ret)
55862306a36Sopenharmony_ci		return ret;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&spi->dev, adis16136_stop, indio_dev);
56162306a36Sopenharmony_ci	if (ret)
56262306a36Sopenharmony_ci		return ret;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	ret = devm_iio_device_register(&spi->dev, indio_dev);
56562306a36Sopenharmony_ci	if (ret)
56662306a36Sopenharmony_ci		return ret;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	adis16136_debugfs_init(indio_dev);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	return 0;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic const struct spi_device_id adis16136_ids[] = {
57462306a36Sopenharmony_ci	{ "adis16133", ID_ADIS16133 },
57562306a36Sopenharmony_ci	{ "adis16135", ID_ADIS16135 },
57662306a36Sopenharmony_ci	{ "adis16136", ID_ADIS16136 },
57762306a36Sopenharmony_ci	{ "adis16137", ID_ADIS16137 },
57862306a36Sopenharmony_ci	{ }
57962306a36Sopenharmony_ci};
58062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adis16136_ids);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic struct spi_driver adis16136_driver = {
58362306a36Sopenharmony_ci	.driver = {
58462306a36Sopenharmony_ci		.name = "adis16136",
58562306a36Sopenharmony_ci	},
58662306a36Sopenharmony_ci	.id_table = adis16136_ids,
58762306a36Sopenharmony_ci	.probe = adis16136_probe,
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_cimodule_spi_driver(adis16136_driver);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
59262306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
59362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
59462306a36Sopenharmony_ciMODULE_IMPORT_NS(IIO_ADISLIB);
595