xref: /openbmc/linux/drivers/iio/gyro/adis16136.c (revision 9caed0d9d6db12cb6d81ba68d5bc98432d6b4711)
1*9caed0d9SLars-Peter Clausen /*
2*9caed0d9SLars-Peter Clausen  * ADIS16133/ADIS16135/ADIS16136 gyroscope driver
3*9caed0d9SLars-Peter Clausen  *
4*9caed0d9SLars-Peter Clausen  * Copyright 2012 Analog Devices Inc.
5*9caed0d9SLars-Peter Clausen  *   Author: Lars-Peter Clausen <lars@metafoo.de>
6*9caed0d9SLars-Peter Clausen  *
7*9caed0d9SLars-Peter Clausen  * Licensed under the GPL-2.
8*9caed0d9SLars-Peter Clausen  */
9*9caed0d9SLars-Peter Clausen 
10*9caed0d9SLars-Peter Clausen #include <linux/interrupt.h>
11*9caed0d9SLars-Peter Clausen #include <linux/delay.h>
12*9caed0d9SLars-Peter Clausen #include <linux/mutex.h>
13*9caed0d9SLars-Peter Clausen #include <linux/device.h>
14*9caed0d9SLars-Peter Clausen #include <linux/kernel.h>
15*9caed0d9SLars-Peter Clausen #include <linux/spi/spi.h>
16*9caed0d9SLars-Peter Clausen #include <linux/slab.h>
17*9caed0d9SLars-Peter Clausen #include <linux/sysfs.h>
18*9caed0d9SLars-Peter Clausen #include <linux/module.h>
19*9caed0d9SLars-Peter Clausen 
20*9caed0d9SLars-Peter Clausen #include <linux/iio/iio.h>
21*9caed0d9SLars-Peter Clausen #include <linux/iio/sysfs.h>
22*9caed0d9SLars-Peter Clausen #include <linux/iio/buffer.h>
23*9caed0d9SLars-Peter Clausen #include <linux/iio/imu/adis.h>
24*9caed0d9SLars-Peter Clausen 
25*9caed0d9SLars-Peter Clausen #include <linux/iio/iio.h>
26*9caed0d9SLars-Peter Clausen #include <linux/debugfs.h>
27*9caed0d9SLars-Peter Clausen 
28*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_FLASH_CNT		0x00
29*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_TEMP_OUT		0x02
30*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OUT2		0x04
31*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OUT		0x06
32*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OFF2		0x08
33*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OFF		0x0A
34*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_MAG1		0x10
35*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_MAG2		0x12
36*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_SAMPL1	0x14
37*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_SAMPL2	0x16
38*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_CTRL		0x18
39*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GPIO_CTRL		0x1A
40*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_MSC_CTRL		0x1C
41*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SMPL_PRD		0x1E
42*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_AVG_CNT		0x20
43*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_DEC_RATE		0x22
44*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SLP_CTRL		0x24
45*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_DIAG_STAT		0x26
46*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GLOB_CMD		0x28
47*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT1		0x32
48*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT2		0x34
49*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT3		0x36
50*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_PROD_ID		0x38
51*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SERIAL_NUM	0x3A
52*9caed0d9SLars-Peter Clausen 
53*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL	2
54*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_SPI_FAIL		3
55*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_SELF_TEST_FAIL	5
56*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL	6
57*9caed0d9SLars-Peter Clausen 
58*9caed0d9SLars-Peter Clausen #define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11)
59*9caed0d9SLars-Peter Clausen #define ADIS16136_MSC_CTRL_SELF_TEST BIT(10)
60*9caed0d9SLars-Peter Clausen 
61*9caed0d9SLars-Peter Clausen struct adis16136_chip_info {
62*9caed0d9SLars-Peter Clausen 	unsigned int precision;
63*9caed0d9SLars-Peter Clausen 	unsigned int fullscale;
64*9caed0d9SLars-Peter Clausen };
65*9caed0d9SLars-Peter Clausen 
66*9caed0d9SLars-Peter Clausen struct adis16136 {
67*9caed0d9SLars-Peter Clausen 	const struct adis16136_chip_info *chip_info;
68*9caed0d9SLars-Peter Clausen 
69*9caed0d9SLars-Peter Clausen 	struct adis adis;
70*9caed0d9SLars-Peter Clausen };
71*9caed0d9SLars-Peter Clausen 
72*9caed0d9SLars-Peter Clausen #ifdef CONFIG_DEBUG_FS
73*9caed0d9SLars-Peter Clausen 
74*9caed0d9SLars-Peter Clausen static ssize_t adis16136_show_serial(struct file *file,
75*9caed0d9SLars-Peter Clausen 		char __user *userbuf, size_t count, loff_t *ppos)
76*9caed0d9SLars-Peter Clausen {
77*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = file->private_data;
78*9caed0d9SLars-Peter Clausen 	uint16_t lot1, lot2, lot3, serial;
79*9caed0d9SLars-Peter Clausen 	char buf[20];
80*9caed0d9SLars-Peter Clausen 	size_t len;
81*9caed0d9SLars-Peter Clausen 	int ret;
82*9caed0d9SLars-Peter Clausen 
83*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
84*9caed0d9SLars-Peter Clausen 		&serial);
85*9caed0d9SLars-Peter Clausen 	if (ret < 0)
86*9caed0d9SLars-Peter Clausen 		return ret;
87*9caed0d9SLars-Peter Clausen 
88*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
89*9caed0d9SLars-Peter Clausen 	if (ret < 0)
90*9caed0d9SLars-Peter Clausen 		return ret;
91*9caed0d9SLars-Peter Clausen 
92*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
93*9caed0d9SLars-Peter Clausen 	if (ret < 0)
94*9caed0d9SLars-Peter Clausen 		return ret;
95*9caed0d9SLars-Peter Clausen 
96*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
97*9caed0d9SLars-Peter Clausen 	if (ret < 0)
98*9caed0d9SLars-Peter Clausen 		return ret;
99*9caed0d9SLars-Peter Clausen 
100*9caed0d9SLars-Peter Clausen 	len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
101*9caed0d9SLars-Peter Clausen 		lot3, serial);
102*9caed0d9SLars-Peter Clausen 
103*9caed0d9SLars-Peter Clausen 	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
104*9caed0d9SLars-Peter Clausen }
105*9caed0d9SLars-Peter Clausen 
106*9caed0d9SLars-Peter Clausen static const struct file_operations adis16136_serial_fops = {
107*9caed0d9SLars-Peter Clausen 	.open = simple_open,
108*9caed0d9SLars-Peter Clausen 	.read = adis16136_show_serial,
109*9caed0d9SLars-Peter Clausen 	.llseek = default_llseek,
110*9caed0d9SLars-Peter Clausen 	.owner = THIS_MODULE,
111*9caed0d9SLars-Peter Clausen };
112*9caed0d9SLars-Peter Clausen 
113*9caed0d9SLars-Peter Clausen static int adis16136_show_product_id(void *arg, u64 *val)
114*9caed0d9SLars-Peter Clausen {
115*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = arg;
116*9caed0d9SLars-Peter Clausen 	u16 prod_id;
117*9caed0d9SLars-Peter Clausen 	int ret;
118*9caed0d9SLars-Peter Clausen 
119*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
120*9caed0d9SLars-Peter Clausen 		&prod_id);
121*9caed0d9SLars-Peter Clausen 	if (ret < 0)
122*9caed0d9SLars-Peter Clausen 		return ret;
123*9caed0d9SLars-Peter Clausen 
124*9caed0d9SLars-Peter Clausen 	*val = prod_id;
125*9caed0d9SLars-Peter Clausen 
126*9caed0d9SLars-Peter Clausen 	return 0;
127*9caed0d9SLars-Peter Clausen }
128*9caed0d9SLars-Peter Clausen DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops,
129*9caed0d9SLars-Peter Clausen 	adis16136_show_product_id, NULL, "%llu\n");
130*9caed0d9SLars-Peter Clausen 
131*9caed0d9SLars-Peter Clausen static int adis16136_show_flash_count(void *arg, u64 *val)
132*9caed0d9SLars-Peter Clausen {
133*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = arg;
134*9caed0d9SLars-Peter Clausen 	uint16_t flash_count;
135*9caed0d9SLars-Peter Clausen 	int ret;
136*9caed0d9SLars-Peter Clausen 
137*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
138*9caed0d9SLars-Peter Clausen 		&flash_count);
139*9caed0d9SLars-Peter Clausen 	if (ret < 0)
140*9caed0d9SLars-Peter Clausen 		return ret;
141*9caed0d9SLars-Peter Clausen 
142*9caed0d9SLars-Peter Clausen 	*val = flash_count;
143*9caed0d9SLars-Peter Clausen 
144*9caed0d9SLars-Peter Clausen 	return 0;
145*9caed0d9SLars-Peter Clausen }
146*9caed0d9SLars-Peter Clausen DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops,
147*9caed0d9SLars-Peter Clausen 	adis16136_show_flash_count, NULL, "%lld\n");
148*9caed0d9SLars-Peter Clausen 
149*9caed0d9SLars-Peter Clausen static int adis16136_debugfs_init(struct iio_dev *indio_dev)
150*9caed0d9SLars-Peter Clausen {
151*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
152*9caed0d9SLars-Peter Clausen 
153*9caed0d9SLars-Peter Clausen 	debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
154*9caed0d9SLars-Peter Clausen 		adis16136, &adis16136_serial_fops);
155*9caed0d9SLars-Peter Clausen 	debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
156*9caed0d9SLars-Peter Clausen 		adis16136, &adis16136_product_id_fops);
157*9caed0d9SLars-Peter Clausen 	debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
158*9caed0d9SLars-Peter Clausen 		adis16136, &adis16136_flash_count_fops);
159*9caed0d9SLars-Peter Clausen 
160*9caed0d9SLars-Peter Clausen 	return 0;
161*9caed0d9SLars-Peter Clausen }
162*9caed0d9SLars-Peter Clausen 
163*9caed0d9SLars-Peter Clausen #else
164*9caed0d9SLars-Peter Clausen 
165*9caed0d9SLars-Peter Clausen static int adis16136_debugfs_init(struct iio_dev *indio_dev)
166*9caed0d9SLars-Peter Clausen {
167*9caed0d9SLars-Peter Clausen 	return 0;
168*9caed0d9SLars-Peter Clausen }
169*9caed0d9SLars-Peter Clausen 
170*9caed0d9SLars-Peter Clausen #endif
171*9caed0d9SLars-Peter Clausen 
172*9caed0d9SLars-Peter Clausen static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
173*9caed0d9SLars-Peter Clausen {
174*9caed0d9SLars-Peter Clausen 	unsigned int t;
175*9caed0d9SLars-Peter Clausen 
176*9caed0d9SLars-Peter Clausen 	t = 32768 / freq;
177*9caed0d9SLars-Peter Clausen 	if (t < 0xf)
178*9caed0d9SLars-Peter Clausen 		t = 0xf;
179*9caed0d9SLars-Peter Clausen 	else if (t > 0xffff)
180*9caed0d9SLars-Peter Clausen 		t = 0xffff;
181*9caed0d9SLars-Peter Clausen 	else
182*9caed0d9SLars-Peter Clausen 		t--;
183*9caed0d9SLars-Peter Clausen 
184*9caed0d9SLars-Peter Clausen 	return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
185*9caed0d9SLars-Peter Clausen }
186*9caed0d9SLars-Peter Clausen 
187*9caed0d9SLars-Peter Clausen static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
188*9caed0d9SLars-Peter Clausen {
189*9caed0d9SLars-Peter Clausen 	uint16_t t;
190*9caed0d9SLars-Peter Clausen 	int ret;
191*9caed0d9SLars-Peter Clausen 
192*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
193*9caed0d9SLars-Peter Clausen 	if (ret < 0)
194*9caed0d9SLars-Peter Clausen 		return ret;
195*9caed0d9SLars-Peter Clausen 
196*9caed0d9SLars-Peter Clausen 	*freq = 32768 / (t + 1);
197*9caed0d9SLars-Peter Clausen 
198*9caed0d9SLars-Peter Clausen 	return 0;
199*9caed0d9SLars-Peter Clausen }
200*9caed0d9SLars-Peter Clausen 
201*9caed0d9SLars-Peter Clausen static ssize_t adis16136_write_frequency(struct device *dev,
202*9caed0d9SLars-Peter Clausen 	struct device_attribute *attr, const char *buf, size_t len)
203*9caed0d9SLars-Peter Clausen {
204*9caed0d9SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
205*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
206*9caed0d9SLars-Peter Clausen 	long val;
207*9caed0d9SLars-Peter Clausen 	int ret;
208*9caed0d9SLars-Peter Clausen 
209*9caed0d9SLars-Peter Clausen 	ret = kstrtol(buf, 10, &val);
210*9caed0d9SLars-Peter Clausen 	if (ret)
211*9caed0d9SLars-Peter Clausen 		return ret;
212*9caed0d9SLars-Peter Clausen 
213*9caed0d9SLars-Peter Clausen 	if (val == 0)
214*9caed0d9SLars-Peter Clausen 		return -EINVAL;
215*9caed0d9SLars-Peter Clausen 
216*9caed0d9SLars-Peter Clausen 	ret = adis16136_set_freq(adis16136, val);
217*9caed0d9SLars-Peter Clausen 
218*9caed0d9SLars-Peter Clausen 	return ret ? ret : len;
219*9caed0d9SLars-Peter Clausen }
220*9caed0d9SLars-Peter Clausen 
221*9caed0d9SLars-Peter Clausen static ssize_t adis16136_read_frequency(struct device *dev,
222*9caed0d9SLars-Peter Clausen 	struct device_attribute *attr, char *buf)
223*9caed0d9SLars-Peter Clausen {
224*9caed0d9SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
225*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
226*9caed0d9SLars-Peter Clausen 	unsigned int freq;
227*9caed0d9SLars-Peter Clausen 	int ret;
228*9caed0d9SLars-Peter Clausen 
229*9caed0d9SLars-Peter Clausen 	ret = adis16136_get_freq(adis16136, &freq);
230*9caed0d9SLars-Peter Clausen 	if (ret < 0)
231*9caed0d9SLars-Peter Clausen 		return ret;
232*9caed0d9SLars-Peter Clausen 
233*9caed0d9SLars-Peter Clausen 	return sprintf(buf, "%d\n", freq);
234*9caed0d9SLars-Peter Clausen }
235*9caed0d9SLars-Peter Clausen 
236*9caed0d9SLars-Peter Clausen static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
237*9caed0d9SLars-Peter Clausen 				  adis16136_read_frequency,
238*9caed0d9SLars-Peter Clausen 				  adis16136_write_frequency);
239*9caed0d9SLars-Peter Clausen 
240*9caed0d9SLars-Peter Clausen static const unsigned adis16136_3db_divisors[] = {
241*9caed0d9SLars-Peter Clausen 	[0] = 2, /* Special case */
242*9caed0d9SLars-Peter Clausen 	[1] = 6,
243*9caed0d9SLars-Peter Clausen 	[2] = 12,
244*9caed0d9SLars-Peter Clausen 	[3] = 25,
245*9caed0d9SLars-Peter Clausen 	[4] = 50,
246*9caed0d9SLars-Peter Clausen 	[5] = 100,
247*9caed0d9SLars-Peter Clausen 	[6] = 200,
248*9caed0d9SLars-Peter Clausen 	[7] = 200, /* Not a valid setting */
249*9caed0d9SLars-Peter Clausen };
250*9caed0d9SLars-Peter Clausen 
251*9caed0d9SLars-Peter Clausen static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
252*9caed0d9SLars-Peter Clausen {
253*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
254*9caed0d9SLars-Peter Clausen 	unsigned int freq;
255*9caed0d9SLars-Peter Clausen 	int i, ret;
256*9caed0d9SLars-Peter Clausen 
257*9caed0d9SLars-Peter Clausen 	ret = adis16136_get_freq(adis16136, &freq);
258*9caed0d9SLars-Peter Clausen 	if (ret < 0)
259*9caed0d9SLars-Peter Clausen 		return ret;
260*9caed0d9SLars-Peter Clausen 
261*9caed0d9SLars-Peter Clausen 	for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
262*9caed0d9SLars-Peter Clausen 		if (freq / adis16136_3db_divisors[i] >= val)
263*9caed0d9SLars-Peter Clausen 			break;
264*9caed0d9SLars-Peter Clausen 	}
265*9caed0d9SLars-Peter Clausen 
266*9caed0d9SLars-Peter Clausen 	return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
267*9caed0d9SLars-Peter Clausen }
268*9caed0d9SLars-Peter Clausen 
269*9caed0d9SLars-Peter Clausen static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
270*9caed0d9SLars-Peter Clausen {
271*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
272*9caed0d9SLars-Peter Clausen 	unsigned int freq;
273*9caed0d9SLars-Peter Clausen 	uint16_t val16;
274*9caed0d9SLars-Peter Clausen 	int ret;
275*9caed0d9SLars-Peter Clausen 
276*9caed0d9SLars-Peter Clausen 	mutex_lock(&indio_dev->mlock);
277*9caed0d9SLars-Peter Clausen 
278*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
279*9caed0d9SLars-Peter Clausen 	if (ret < 0)
280*9caed0d9SLars-Peter Clausen 		goto err_unlock;
281*9caed0d9SLars-Peter Clausen 
282*9caed0d9SLars-Peter Clausen 	ret = adis16136_get_freq(adis16136, &freq);
283*9caed0d9SLars-Peter Clausen 	if (ret < 0)
284*9caed0d9SLars-Peter Clausen 		goto err_unlock;
285*9caed0d9SLars-Peter Clausen 
286*9caed0d9SLars-Peter Clausen 	*val = freq / adis16136_3db_divisors[val16 & 0x07];
287*9caed0d9SLars-Peter Clausen 
288*9caed0d9SLars-Peter Clausen err_unlock:
289*9caed0d9SLars-Peter Clausen 	mutex_unlock(&indio_dev->mlock);
290*9caed0d9SLars-Peter Clausen 
291*9caed0d9SLars-Peter Clausen 	return ret ? ret : IIO_VAL_INT;
292*9caed0d9SLars-Peter Clausen }
293*9caed0d9SLars-Peter Clausen 
294*9caed0d9SLars-Peter Clausen static int adis16136_read_raw(struct iio_dev *indio_dev,
295*9caed0d9SLars-Peter Clausen 	const struct iio_chan_spec *chan, int *val, int *val2, long info)
296*9caed0d9SLars-Peter Clausen {
297*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
298*9caed0d9SLars-Peter Clausen 	uint32_t val32;
299*9caed0d9SLars-Peter Clausen 	int ret;
300*9caed0d9SLars-Peter Clausen 
301*9caed0d9SLars-Peter Clausen 	switch (info) {
302*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_RAW:
303*9caed0d9SLars-Peter Clausen 		return adis_single_conversion(indio_dev, chan, 0, val);
304*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_SCALE:
305*9caed0d9SLars-Peter Clausen 		switch (chan->type) {
306*9caed0d9SLars-Peter Clausen 		case IIO_ANGL_VEL:
307*9caed0d9SLars-Peter Clausen 			*val = adis16136->chip_info->precision;
308*9caed0d9SLars-Peter Clausen 			*val2 = (adis16136->chip_info->fullscale << 16);
309*9caed0d9SLars-Peter Clausen 			return IIO_VAL_FRACTIONAL;
310*9caed0d9SLars-Peter Clausen 		case IIO_TEMP:
311*9caed0d9SLars-Peter Clausen 			*val = 10;
312*9caed0d9SLars-Peter Clausen 			*val2 = 697000; /* 0.010697 degree Celsius */
313*9caed0d9SLars-Peter Clausen 			return IIO_VAL_INT_PLUS_MICRO;
314*9caed0d9SLars-Peter Clausen 		default:
315*9caed0d9SLars-Peter Clausen 			return -EINVAL;
316*9caed0d9SLars-Peter Clausen 		}
317*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
318*9caed0d9SLars-Peter Clausen 		ret = adis_read_reg_32(&adis16136->adis,
319*9caed0d9SLars-Peter Clausen 			ADIS16136_REG_GYRO_OFF2, &val32);
320*9caed0d9SLars-Peter Clausen 		if (ret < 0)
321*9caed0d9SLars-Peter Clausen 			return ret;
322*9caed0d9SLars-Peter Clausen 
323*9caed0d9SLars-Peter Clausen 		*val = sign_extend32(val32, 31);
324*9caed0d9SLars-Peter Clausen 
325*9caed0d9SLars-Peter Clausen 		return IIO_VAL_INT;
326*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
327*9caed0d9SLars-Peter Clausen 		return adis16136_get_filter(indio_dev, val);
328*9caed0d9SLars-Peter Clausen 	default:
329*9caed0d9SLars-Peter Clausen 		return -EINVAL;
330*9caed0d9SLars-Peter Clausen 	}
331*9caed0d9SLars-Peter Clausen }
332*9caed0d9SLars-Peter Clausen 
333*9caed0d9SLars-Peter Clausen static int adis16136_write_raw(struct iio_dev *indio_dev,
334*9caed0d9SLars-Peter Clausen 	const struct iio_chan_spec *chan, int val, int val2, long info)
335*9caed0d9SLars-Peter Clausen {
336*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
337*9caed0d9SLars-Peter Clausen 
338*9caed0d9SLars-Peter Clausen 	switch (info) {
339*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
340*9caed0d9SLars-Peter Clausen 		return adis_write_reg_32(&adis16136->adis,
341*9caed0d9SLars-Peter Clausen 			ADIS16136_REG_GYRO_OFF2, val);
342*9caed0d9SLars-Peter Clausen 	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
343*9caed0d9SLars-Peter Clausen 		return adis16136_set_filter(indio_dev, val);
344*9caed0d9SLars-Peter Clausen 	default:
345*9caed0d9SLars-Peter Clausen 		break;
346*9caed0d9SLars-Peter Clausen 	}
347*9caed0d9SLars-Peter Clausen 
348*9caed0d9SLars-Peter Clausen 	return -EINVAL;
349*9caed0d9SLars-Peter Clausen }
350*9caed0d9SLars-Peter Clausen 
351*9caed0d9SLars-Peter Clausen enum {
352*9caed0d9SLars-Peter Clausen 	ADIS16136_SCAN_GYRO,
353*9caed0d9SLars-Peter Clausen 	ADIS16136_SCAN_TEMP,
354*9caed0d9SLars-Peter Clausen };
355*9caed0d9SLars-Peter Clausen 
356*9caed0d9SLars-Peter Clausen static const struct iio_chan_spec adis16136_channels[] = {
357*9caed0d9SLars-Peter Clausen 	{
358*9caed0d9SLars-Peter Clausen 		.type = IIO_ANGL_VEL,
359*9caed0d9SLars-Peter Clausen 		.modified = 1,
360*9caed0d9SLars-Peter Clausen 		.channel2 = IIO_MOD_X,
361*9caed0d9SLars-Peter Clausen 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
362*9caed0d9SLars-Peter Clausen 			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
363*9caed0d9SLars-Peter Clausen 			IIO_CHAN_INFO_SCALE_SHARED_BIT |
364*9caed0d9SLars-Peter Clausen 			IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT,
365*9caed0d9SLars-Peter Clausen 		.address = ADIS16136_REG_GYRO_OUT2,
366*9caed0d9SLars-Peter Clausen 		.scan_index = ADIS16136_SCAN_GYRO,
367*9caed0d9SLars-Peter Clausen 		.scan_type = {
368*9caed0d9SLars-Peter Clausen 			.sign = 's',
369*9caed0d9SLars-Peter Clausen 			.realbits = 32,
370*9caed0d9SLars-Peter Clausen 			.storagebits = 32,
371*9caed0d9SLars-Peter Clausen 			.endianness = IIO_BE,
372*9caed0d9SLars-Peter Clausen 		},
373*9caed0d9SLars-Peter Clausen 	}, {
374*9caed0d9SLars-Peter Clausen 		.type = IIO_TEMP,
375*9caed0d9SLars-Peter Clausen 		.indexed = 1,
376*9caed0d9SLars-Peter Clausen 		.channel = 0,
377*9caed0d9SLars-Peter Clausen 		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
378*9caed0d9SLars-Peter Clausen 			IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
379*9caed0d9SLars-Peter Clausen 		.address = ADIS16136_REG_TEMP_OUT,
380*9caed0d9SLars-Peter Clausen 		.scan_index = ADIS16136_SCAN_TEMP,
381*9caed0d9SLars-Peter Clausen 		.scan_type = {
382*9caed0d9SLars-Peter Clausen 			.sign = 's',
383*9caed0d9SLars-Peter Clausen 			.realbits = 16,
384*9caed0d9SLars-Peter Clausen 			.storagebits = 16,
385*9caed0d9SLars-Peter Clausen 			.endianness = IIO_BE,
386*9caed0d9SLars-Peter Clausen 		},
387*9caed0d9SLars-Peter Clausen 	},
388*9caed0d9SLars-Peter Clausen 	IIO_CHAN_SOFT_TIMESTAMP(2),
389*9caed0d9SLars-Peter Clausen };
390*9caed0d9SLars-Peter Clausen 
391*9caed0d9SLars-Peter Clausen static struct attribute *adis16136_attributes[] = {
392*9caed0d9SLars-Peter Clausen 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
393*9caed0d9SLars-Peter Clausen 	NULL
394*9caed0d9SLars-Peter Clausen };
395*9caed0d9SLars-Peter Clausen 
396*9caed0d9SLars-Peter Clausen static const struct attribute_group adis16136_attribute_group = {
397*9caed0d9SLars-Peter Clausen 	.attrs = adis16136_attributes,
398*9caed0d9SLars-Peter Clausen };
399*9caed0d9SLars-Peter Clausen 
400*9caed0d9SLars-Peter Clausen static const struct iio_info adis16136_info = {
401*9caed0d9SLars-Peter Clausen 	.driver_module = THIS_MODULE,
402*9caed0d9SLars-Peter Clausen 	.attrs = &adis16136_attribute_group,
403*9caed0d9SLars-Peter Clausen 	.read_raw = &adis16136_read_raw,
404*9caed0d9SLars-Peter Clausen 	.write_raw = &adis16136_write_raw,
405*9caed0d9SLars-Peter Clausen 	.update_scan_mode = adis_update_scan_mode,
406*9caed0d9SLars-Peter Clausen 	.debugfs_reg_access = adis_debugfs_reg_access,
407*9caed0d9SLars-Peter Clausen };
408*9caed0d9SLars-Peter Clausen 
409*9caed0d9SLars-Peter Clausen static int adis16136_stop_device(struct iio_dev *indio_dev)
410*9caed0d9SLars-Peter Clausen {
411*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
412*9caed0d9SLars-Peter Clausen 	int ret;
413*9caed0d9SLars-Peter Clausen 
414*9caed0d9SLars-Peter Clausen 	ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff);
415*9caed0d9SLars-Peter Clausen 	if (ret)
416*9caed0d9SLars-Peter Clausen 		dev_err(&indio_dev->dev,
417*9caed0d9SLars-Peter Clausen 			"Could not power down device: %d\n", ret);
418*9caed0d9SLars-Peter Clausen 
419*9caed0d9SLars-Peter Clausen 	return ret;
420*9caed0d9SLars-Peter Clausen }
421*9caed0d9SLars-Peter Clausen 
422*9caed0d9SLars-Peter Clausen static int adis16136_initial_setup(struct iio_dev *indio_dev)
423*9caed0d9SLars-Peter Clausen {
424*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
425*9caed0d9SLars-Peter Clausen 	unsigned int device_id;
426*9caed0d9SLars-Peter Clausen 	uint16_t prod_id;
427*9caed0d9SLars-Peter Clausen 	int ret;
428*9caed0d9SLars-Peter Clausen 
429*9caed0d9SLars-Peter Clausen 	ret = adis_initial_startup(&adis16136->adis);
430*9caed0d9SLars-Peter Clausen 	if (ret)
431*9caed0d9SLars-Peter Clausen 		return ret;
432*9caed0d9SLars-Peter Clausen 
433*9caed0d9SLars-Peter Clausen 	ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
434*9caed0d9SLars-Peter Clausen 		&prod_id);
435*9caed0d9SLars-Peter Clausen 	if (ret)
436*9caed0d9SLars-Peter Clausen 		return ret;
437*9caed0d9SLars-Peter Clausen 
438*9caed0d9SLars-Peter Clausen 	sscanf(indio_dev->name, "adis%u\n", &device_id);
439*9caed0d9SLars-Peter Clausen 
440*9caed0d9SLars-Peter Clausen 	if (prod_id != device_id)
441*9caed0d9SLars-Peter Clausen 		dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
442*9caed0d9SLars-Peter Clausen 				device_id, prod_id);
443*9caed0d9SLars-Peter Clausen 
444*9caed0d9SLars-Peter Clausen 	return 0;
445*9caed0d9SLars-Peter Clausen }
446*9caed0d9SLars-Peter Clausen 
447*9caed0d9SLars-Peter Clausen static const char * const adis16136_status_error_msgs[] = {
448*9caed0d9SLars-Peter Clausen 	[ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed",
449*9caed0d9SLars-Peter Clausen 	[ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure",
450*9caed0d9SLars-Peter Clausen 	[ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error",
451*9caed0d9SLars-Peter Clausen 	[ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
452*9caed0d9SLars-Peter Clausen };
453*9caed0d9SLars-Peter Clausen 
454*9caed0d9SLars-Peter Clausen static const struct adis_data adis16136_data = {
455*9caed0d9SLars-Peter Clausen 	.diag_stat_reg = ADIS16136_REG_DIAG_STAT,
456*9caed0d9SLars-Peter Clausen 	.glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
457*9caed0d9SLars-Peter Clausen 	.msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
458*9caed0d9SLars-Peter Clausen 
459*9caed0d9SLars-Peter Clausen 	.self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
460*9caed0d9SLars-Peter Clausen 	.startup_delay = 80,
461*9caed0d9SLars-Peter Clausen 
462*9caed0d9SLars-Peter Clausen 	.read_delay = 10,
463*9caed0d9SLars-Peter Clausen 	.write_delay = 10,
464*9caed0d9SLars-Peter Clausen 
465*9caed0d9SLars-Peter Clausen 	.status_error_msgs = adis16136_status_error_msgs,
466*9caed0d9SLars-Peter Clausen 	.status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
467*9caed0d9SLars-Peter Clausen 		BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
468*9caed0d9SLars-Peter Clausen 		BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
469*9caed0d9SLars-Peter Clausen 		BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
470*9caed0d9SLars-Peter Clausen };
471*9caed0d9SLars-Peter Clausen 
472*9caed0d9SLars-Peter Clausen enum adis16136_id {
473*9caed0d9SLars-Peter Clausen 	ID_ADIS16133,
474*9caed0d9SLars-Peter Clausen 	ID_ADIS16135,
475*9caed0d9SLars-Peter Clausen 	ID_ADIS16136,
476*9caed0d9SLars-Peter Clausen };
477*9caed0d9SLars-Peter Clausen 
478*9caed0d9SLars-Peter Clausen static const struct adis16136_chip_info adis16136_chip_info[] = {
479*9caed0d9SLars-Peter Clausen 	[ID_ADIS16133] = {
480*9caed0d9SLars-Peter Clausen 		.precision = IIO_DEGREE_TO_RAD(1200),
481*9caed0d9SLars-Peter Clausen 		.fullscale = 24000,
482*9caed0d9SLars-Peter Clausen 	},
483*9caed0d9SLars-Peter Clausen 	[ID_ADIS16135] = {
484*9caed0d9SLars-Peter Clausen 		.precision = IIO_DEGREE_TO_RAD(300),
485*9caed0d9SLars-Peter Clausen 		.fullscale = 24000,
486*9caed0d9SLars-Peter Clausen 	},
487*9caed0d9SLars-Peter Clausen 	[ID_ADIS16136] = {
488*9caed0d9SLars-Peter Clausen 		.precision = IIO_DEGREE_TO_RAD(450),
489*9caed0d9SLars-Peter Clausen 		.fullscale = 24623,
490*9caed0d9SLars-Peter Clausen 	},
491*9caed0d9SLars-Peter Clausen };
492*9caed0d9SLars-Peter Clausen 
493*9caed0d9SLars-Peter Clausen static int adis16136_probe(struct spi_device *spi)
494*9caed0d9SLars-Peter Clausen {
495*9caed0d9SLars-Peter Clausen 	const struct spi_device_id *id = spi_get_device_id(spi);
496*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136;
497*9caed0d9SLars-Peter Clausen 	struct iio_dev *indio_dev;
498*9caed0d9SLars-Peter Clausen 	int ret;
499*9caed0d9SLars-Peter Clausen 
500*9caed0d9SLars-Peter Clausen 	indio_dev = iio_device_alloc(sizeof(*adis16136));
501*9caed0d9SLars-Peter Clausen 	if (indio_dev == NULL)
502*9caed0d9SLars-Peter Clausen 		return -ENOMEM;
503*9caed0d9SLars-Peter Clausen 
504*9caed0d9SLars-Peter Clausen 	spi_set_drvdata(spi, indio_dev);
505*9caed0d9SLars-Peter Clausen 
506*9caed0d9SLars-Peter Clausen 	adis16136 = iio_priv(indio_dev);
507*9caed0d9SLars-Peter Clausen 
508*9caed0d9SLars-Peter Clausen 	adis16136->chip_info = &adis16136_chip_info[id->driver_data];
509*9caed0d9SLars-Peter Clausen 	indio_dev->dev.parent = &spi->dev;
510*9caed0d9SLars-Peter Clausen 	indio_dev->name = spi_get_device_id(spi)->name;
511*9caed0d9SLars-Peter Clausen 	indio_dev->channels = adis16136_channels;
512*9caed0d9SLars-Peter Clausen 	indio_dev->num_channels = ARRAY_SIZE(adis16136_channels);
513*9caed0d9SLars-Peter Clausen 	indio_dev->info = &adis16136_info;
514*9caed0d9SLars-Peter Clausen 	indio_dev->modes = INDIO_DIRECT_MODE;
515*9caed0d9SLars-Peter Clausen 
516*9caed0d9SLars-Peter Clausen 	ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
517*9caed0d9SLars-Peter Clausen 	if (ret)
518*9caed0d9SLars-Peter Clausen 		goto error_free_dev;
519*9caed0d9SLars-Peter Clausen 
520*9caed0d9SLars-Peter Clausen 	ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
521*9caed0d9SLars-Peter Clausen 	if (ret)
522*9caed0d9SLars-Peter Clausen 		goto error_free_dev;
523*9caed0d9SLars-Peter Clausen 
524*9caed0d9SLars-Peter Clausen 	ret = adis16136_initial_setup(indio_dev);
525*9caed0d9SLars-Peter Clausen 	if (ret)
526*9caed0d9SLars-Peter Clausen 		goto error_cleanup_buffer;
527*9caed0d9SLars-Peter Clausen 
528*9caed0d9SLars-Peter Clausen 	ret = iio_device_register(indio_dev);
529*9caed0d9SLars-Peter Clausen 	if (ret)
530*9caed0d9SLars-Peter Clausen 		goto error_stop_device;
531*9caed0d9SLars-Peter Clausen 
532*9caed0d9SLars-Peter Clausen 	adis16136_debugfs_init(indio_dev);
533*9caed0d9SLars-Peter Clausen 
534*9caed0d9SLars-Peter Clausen 	return 0;
535*9caed0d9SLars-Peter Clausen 
536*9caed0d9SLars-Peter Clausen error_stop_device:
537*9caed0d9SLars-Peter Clausen 	adis16136_stop_device(indio_dev);
538*9caed0d9SLars-Peter Clausen error_cleanup_buffer:
539*9caed0d9SLars-Peter Clausen 	adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
540*9caed0d9SLars-Peter Clausen error_free_dev:
541*9caed0d9SLars-Peter Clausen 	iio_device_free(indio_dev);
542*9caed0d9SLars-Peter Clausen 	return ret;
543*9caed0d9SLars-Peter Clausen }
544*9caed0d9SLars-Peter Clausen 
545*9caed0d9SLars-Peter Clausen static int adis16136_remove(struct spi_device *spi)
546*9caed0d9SLars-Peter Clausen {
547*9caed0d9SLars-Peter Clausen 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
548*9caed0d9SLars-Peter Clausen 	struct adis16136 *adis16136 = iio_priv(indio_dev);
549*9caed0d9SLars-Peter Clausen 
550*9caed0d9SLars-Peter Clausen 	iio_device_unregister(indio_dev);
551*9caed0d9SLars-Peter Clausen 	adis16136_stop_device(indio_dev);
552*9caed0d9SLars-Peter Clausen 
553*9caed0d9SLars-Peter Clausen 	adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
554*9caed0d9SLars-Peter Clausen 
555*9caed0d9SLars-Peter Clausen 	iio_device_free(indio_dev);
556*9caed0d9SLars-Peter Clausen 
557*9caed0d9SLars-Peter Clausen 	return 0;
558*9caed0d9SLars-Peter Clausen }
559*9caed0d9SLars-Peter Clausen 
560*9caed0d9SLars-Peter Clausen static const struct spi_device_id adis16136_ids[] = {
561*9caed0d9SLars-Peter Clausen 	{ "adis16133", ID_ADIS16133 },
562*9caed0d9SLars-Peter Clausen 	{ "adis16135", ID_ADIS16135 },
563*9caed0d9SLars-Peter Clausen 	{ "adis16136", ID_ADIS16136 },
564*9caed0d9SLars-Peter Clausen 	{ }
565*9caed0d9SLars-Peter Clausen };
566*9caed0d9SLars-Peter Clausen MODULE_DEVICE_TABLE(spi, adis16136_ids);
567*9caed0d9SLars-Peter Clausen 
568*9caed0d9SLars-Peter Clausen static struct spi_driver adis16136_driver = {
569*9caed0d9SLars-Peter Clausen 	.driver = {
570*9caed0d9SLars-Peter Clausen 		.name = "adis16136",
571*9caed0d9SLars-Peter Clausen 		.owner = THIS_MODULE,
572*9caed0d9SLars-Peter Clausen 	},
573*9caed0d9SLars-Peter Clausen 	.id_table = adis16136_ids,
574*9caed0d9SLars-Peter Clausen 	.probe = adis16136_probe,
575*9caed0d9SLars-Peter Clausen 	.remove = adis16136_remove,
576*9caed0d9SLars-Peter Clausen };
577*9caed0d9SLars-Peter Clausen module_spi_driver(adis16136_driver);
578*9caed0d9SLars-Peter Clausen 
579*9caed0d9SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
580*9caed0d9SLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver");
581*9caed0d9SLars-Peter Clausen MODULE_LICENSE("GPL v2");
582