xref: /openbmc/linux/drivers/iio/gyro/adxrs450.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2420b0fcbSLars-Peter Clausen /*
3420b0fcbSLars-Peter Clausen  * ADXRS450/ADXRS453 Digital Output Gyroscope Driver
4420b0fcbSLars-Peter Clausen  *
5420b0fcbSLars-Peter Clausen  * Copyright 2011 Analog Devices Inc.
6420b0fcbSLars-Peter Clausen  */
7420b0fcbSLars-Peter Clausen 
8420b0fcbSLars-Peter Clausen #include <linux/interrupt.h>
9420b0fcbSLars-Peter Clausen #include <linux/irq.h>
10420b0fcbSLars-Peter Clausen #include <linux/delay.h>
11420b0fcbSLars-Peter Clausen #include <linux/mutex.h>
12420b0fcbSLars-Peter Clausen #include <linux/device.h>
13420b0fcbSLars-Peter Clausen #include <linux/kernel.h>
14420b0fcbSLars-Peter Clausen #include <linux/spi/spi.h>
15420b0fcbSLars-Peter Clausen #include <linux/slab.h>
16420b0fcbSLars-Peter Clausen #include <linux/sysfs.h>
17420b0fcbSLars-Peter Clausen #include <linux/list.h>
18420b0fcbSLars-Peter Clausen #include <linux/module.h>
19420b0fcbSLars-Peter Clausen 
20420b0fcbSLars-Peter Clausen #include <linux/iio/iio.h>
21420b0fcbSLars-Peter Clausen #include <linux/iio/sysfs.h>
22420b0fcbSLars-Peter Clausen 
23420b0fcbSLars-Peter Clausen #define ADXRS450_STARTUP_DELAY	50 /* ms */
24420b0fcbSLars-Peter Clausen 
25420b0fcbSLars-Peter Clausen /* The MSB for the spi commands */
26420b0fcbSLars-Peter Clausen #define ADXRS450_SENSOR_DATA    (0x20 << 24)
27420b0fcbSLars-Peter Clausen #define ADXRS450_WRITE_DATA	(0x40 << 24)
28420b0fcbSLars-Peter Clausen #define ADXRS450_READ_DATA	(0x80 << 24)
29420b0fcbSLars-Peter Clausen 
30420b0fcbSLars-Peter Clausen #define ADXRS450_RATE1	0x00	/* Rate Registers */
31420b0fcbSLars-Peter Clausen #define ADXRS450_TEMP1	0x02	/* Temperature Registers */
32420b0fcbSLars-Peter Clausen #define ADXRS450_LOCST1	0x04	/* Low CST Memory Registers */
33420b0fcbSLars-Peter Clausen #define ADXRS450_HICST1	0x06	/* High CST Memory Registers */
34420b0fcbSLars-Peter Clausen #define ADXRS450_QUAD1	0x08	/* Quad Memory Registers */
35420b0fcbSLars-Peter Clausen #define ADXRS450_FAULT1	0x0A	/* Fault Registers */
36420b0fcbSLars-Peter Clausen #define ADXRS450_PID1	0x0C	/* Part ID Register 1 */
37420b0fcbSLars-Peter Clausen #define ADXRS450_SNH	0x0E	/* Serial Number Registers, 4 bytes */
38420b0fcbSLars-Peter Clausen #define ADXRS450_SNL	0x10
39420b0fcbSLars-Peter Clausen #define ADXRS450_DNC1	0x12	/* Dynamic Null Correction Registers */
40420b0fcbSLars-Peter Clausen /* Check bits */
41420b0fcbSLars-Peter Clausen #define ADXRS450_P	0x01
42420b0fcbSLars-Peter Clausen #define ADXRS450_CHK	0x02
43420b0fcbSLars-Peter Clausen #define ADXRS450_CST	0x04
44420b0fcbSLars-Peter Clausen #define ADXRS450_PWR	0x08
45420b0fcbSLars-Peter Clausen #define ADXRS450_POR	0x10
46420b0fcbSLars-Peter Clausen #define ADXRS450_NVM	0x20
47420b0fcbSLars-Peter Clausen #define ADXRS450_Q	0x40
48420b0fcbSLars-Peter Clausen #define ADXRS450_PLL	0x80
49420b0fcbSLars-Peter Clausen #define ADXRS450_UV	0x100
50420b0fcbSLars-Peter Clausen #define ADXRS450_OV	0x200
51420b0fcbSLars-Peter Clausen #define ADXRS450_AMP	0x400
52420b0fcbSLars-Peter Clausen #define ADXRS450_FAIL	0x800
53420b0fcbSLars-Peter Clausen 
54420b0fcbSLars-Peter Clausen #define ADXRS450_WRERR_MASK	(0x7 << 29)
55420b0fcbSLars-Peter Clausen 
56420b0fcbSLars-Peter Clausen #define ADXRS450_MAX_RX 4
57420b0fcbSLars-Peter Clausen #define ADXRS450_MAX_TX 4
58420b0fcbSLars-Peter Clausen 
59420b0fcbSLars-Peter Clausen #define ADXRS450_GET_ST(a)	((a >> 26) & 0x3)
60420b0fcbSLars-Peter Clausen 
61420b0fcbSLars-Peter Clausen enum {
62420b0fcbSLars-Peter Clausen 	ID_ADXRS450,
63420b0fcbSLars-Peter Clausen 	ID_ADXRS453,
64420b0fcbSLars-Peter Clausen };
65420b0fcbSLars-Peter Clausen 
66420b0fcbSLars-Peter Clausen /**
67420b0fcbSLars-Peter Clausen  * struct adxrs450_state - device instance specific data
68420b0fcbSLars-Peter Clausen  * @us:			actual spi_device
69420b0fcbSLars-Peter Clausen  * @buf_lock:		mutex to protect tx and rx
70420b0fcbSLars-Peter Clausen  * @tx:			transmit buffer
71420b0fcbSLars-Peter Clausen  * @rx:			receive buffer
72420b0fcbSLars-Peter Clausen  **/
73420b0fcbSLars-Peter Clausen struct adxrs450_state {
74420b0fcbSLars-Peter Clausen 	struct spi_device	*us;
75420b0fcbSLars-Peter Clausen 	struct mutex		buf_lock;
76*966d2f4eSJonathan Cameron 	__be32			tx __aligned(IIO_DMA_MINALIGN);
77420b0fcbSLars-Peter Clausen 	__be32			rx;
78420b0fcbSLars-Peter Clausen 
79420b0fcbSLars-Peter Clausen };
80420b0fcbSLars-Peter Clausen 
81420b0fcbSLars-Peter Clausen /**
82420b0fcbSLars-Peter Clausen  * adxrs450_spi_read_reg_16() - read 2 bytes from a register pair
83420b0fcbSLars-Peter Clausen  * @indio_dev: device associated with child of actual iio_dev
84420b0fcbSLars-Peter Clausen  * @reg_address: the address of the lower of the two registers, which should be
85420b0fcbSLars-Peter Clausen  *	an even address, the second register's address is reg_address + 1.
86420b0fcbSLars-Peter Clausen  * @val: somewhere to pass back the value read
87420b0fcbSLars-Peter Clausen  **/
adxrs450_spi_read_reg_16(struct iio_dev * indio_dev,u8 reg_address,u16 * val)88420b0fcbSLars-Peter Clausen static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev,
89420b0fcbSLars-Peter Clausen 				    u8 reg_address,
90420b0fcbSLars-Peter Clausen 				    u16 *val)
91420b0fcbSLars-Peter Clausen {
92420b0fcbSLars-Peter Clausen 	struct adxrs450_state *st = iio_priv(indio_dev);
93420b0fcbSLars-Peter Clausen 	u32 tx;
94420b0fcbSLars-Peter Clausen 	int ret;
95420b0fcbSLars-Peter Clausen 	struct spi_transfer xfers[] = {
96420b0fcbSLars-Peter Clausen 		{
97420b0fcbSLars-Peter Clausen 			.tx_buf = &st->tx,
98420b0fcbSLars-Peter Clausen 			.bits_per_word = 8,
99420b0fcbSLars-Peter Clausen 			.len = sizeof(st->tx),
100420b0fcbSLars-Peter Clausen 			.cs_change = 1,
101420b0fcbSLars-Peter Clausen 		}, {
102420b0fcbSLars-Peter Clausen 			.rx_buf = &st->rx,
103420b0fcbSLars-Peter Clausen 			.bits_per_word = 8,
104420b0fcbSLars-Peter Clausen 			.len = sizeof(st->rx),
105420b0fcbSLars-Peter Clausen 		},
106420b0fcbSLars-Peter Clausen 	};
107420b0fcbSLars-Peter Clausen 
108420b0fcbSLars-Peter Clausen 	mutex_lock(&st->buf_lock);
109420b0fcbSLars-Peter Clausen 	tx = ADXRS450_READ_DATA | (reg_address << 17);
110420b0fcbSLars-Peter Clausen 
111420b0fcbSLars-Peter Clausen 	if (!(hweight32(tx) & 1))
112420b0fcbSLars-Peter Clausen 		tx |= ADXRS450_P;
113420b0fcbSLars-Peter Clausen 
114420b0fcbSLars-Peter Clausen 	st->tx = cpu_to_be32(tx);
11535734fbdSLars-Peter Clausen 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
116420b0fcbSLars-Peter Clausen 	if (ret) {
117420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n",
118420b0fcbSLars-Peter Clausen 				reg_address);
119420b0fcbSLars-Peter Clausen 		goto error_ret;
120420b0fcbSLars-Peter Clausen 	}
121420b0fcbSLars-Peter Clausen 
122420b0fcbSLars-Peter Clausen 	*val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF;
123420b0fcbSLars-Peter Clausen 
124420b0fcbSLars-Peter Clausen error_ret:
125420b0fcbSLars-Peter Clausen 	mutex_unlock(&st->buf_lock);
126420b0fcbSLars-Peter Clausen 	return ret;
127420b0fcbSLars-Peter Clausen }
128420b0fcbSLars-Peter Clausen 
129420b0fcbSLars-Peter Clausen /**
130420b0fcbSLars-Peter Clausen  * adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair
131420b0fcbSLars-Peter Clausen  * @indio_dev: device associated with child of actual actual iio_dev
132420b0fcbSLars-Peter Clausen  * @reg_address: the address of the lower of the two registers,which should be
133420b0fcbSLars-Peter Clausen  *	an even address, the second register's address is reg_address + 1.
134420b0fcbSLars-Peter Clausen  * @val: value to be written.
135420b0fcbSLars-Peter Clausen  **/
adxrs450_spi_write_reg_16(struct iio_dev * indio_dev,u8 reg_address,u16 val)136420b0fcbSLars-Peter Clausen static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev,
137420b0fcbSLars-Peter Clausen 				     u8 reg_address,
138420b0fcbSLars-Peter Clausen 				     u16 val)
139420b0fcbSLars-Peter Clausen {
140420b0fcbSLars-Peter Clausen 	struct adxrs450_state *st = iio_priv(indio_dev);
141420b0fcbSLars-Peter Clausen 	u32 tx;
142420b0fcbSLars-Peter Clausen 	int ret;
143420b0fcbSLars-Peter Clausen 
144420b0fcbSLars-Peter Clausen 	mutex_lock(&st->buf_lock);
145420b0fcbSLars-Peter Clausen 	tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1);
146420b0fcbSLars-Peter Clausen 
147420b0fcbSLars-Peter Clausen 	if (!(hweight32(tx) & 1))
148420b0fcbSLars-Peter Clausen 		tx |= ADXRS450_P;
149420b0fcbSLars-Peter Clausen 
150420b0fcbSLars-Peter Clausen 	st->tx = cpu_to_be32(tx);
151420b0fcbSLars-Peter Clausen 	ret = spi_write(st->us, &st->tx, sizeof(st->tx));
152420b0fcbSLars-Peter Clausen 	if (ret)
153420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n",
154420b0fcbSLars-Peter Clausen 			reg_address);
155420b0fcbSLars-Peter Clausen 	usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */
156420b0fcbSLars-Peter Clausen 	mutex_unlock(&st->buf_lock);
157420b0fcbSLars-Peter Clausen 	return ret;
158420b0fcbSLars-Peter Clausen }
159420b0fcbSLars-Peter Clausen 
160420b0fcbSLars-Peter Clausen /**
161420b0fcbSLars-Peter Clausen  * adxrs450_spi_sensor_data() - read 2 bytes sensor data
162420b0fcbSLars-Peter Clausen  * @indio_dev: device associated with child of actual iio_dev
163420b0fcbSLars-Peter Clausen  * @val: somewhere to pass back the value read
164420b0fcbSLars-Peter Clausen  **/
adxrs450_spi_sensor_data(struct iio_dev * indio_dev,s16 * val)165420b0fcbSLars-Peter Clausen static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val)
166420b0fcbSLars-Peter Clausen {
167420b0fcbSLars-Peter Clausen 	struct adxrs450_state *st = iio_priv(indio_dev);
168420b0fcbSLars-Peter Clausen 	int ret;
169420b0fcbSLars-Peter Clausen 	struct spi_transfer xfers[] = {
170420b0fcbSLars-Peter Clausen 		{
171420b0fcbSLars-Peter Clausen 			.tx_buf = &st->tx,
172420b0fcbSLars-Peter Clausen 			.bits_per_word = 8,
173420b0fcbSLars-Peter Clausen 			.len = sizeof(st->tx),
174420b0fcbSLars-Peter Clausen 			.cs_change = 1,
175420b0fcbSLars-Peter Clausen 		}, {
176420b0fcbSLars-Peter Clausen 			.rx_buf = &st->rx,
177420b0fcbSLars-Peter Clausen 			.bits_per_word = 8,
178420b0fcbSLars-Peter Clausen 			.len = sizeof(st->rx),
179420b0fcbSLars-Peter Clausen 		},
180420b0fcbSLars-Peter Clausen 	};
181420b0fcbSLars-Peter Clausen 
182420b0fcbSLars-Peter Clausen 	mutex_lock(&st->buf_lock);
183420b0fcbSLars-Peter Clausen 	st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA);
184420b0fcbSLars-Peter Clausen 
18535734fbdSLars-Peter Clausen 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
186420b0fcbSLars-Peter Clausen 	if (ret) {
187420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "Problem while reading sensor data\n");
188420b0fcbSLars-Peter Clausen 		goto error_ret;
189420b0fcbSLars-Peter Clausen 	}
190420b0fcbSLars-Peter Clausen 
191420b0fcbSLars-Peter Clausen 	*val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF;
192420b0fcbSLars-Peter Clausen 
193420b0fcbSLars-Peter Clausen error_ret:
194420b0fcbSLars-Peter Clausen 	mutex_unlock(&st->buf_lock);
195420b0fcbSLars-Peter Clausen 	return ret;
196420b0fcbSLars-Peter Clausen }
197420b0fcbSLars-Peter Clausen 
198420b0fcbSLars-Peter Clausen /**
199420b0fcbSLars-Peter Clausen  * adxrs450_spi_initial() - use for initializing procedure.
200420b0fcbSLars-Peter Clausen  * @st: device instance specific data
201420b0fcbSLars-Peter Clausen  * @val: somewhere to pass back the value read
202420b0fcbSLars-Peter Clausen  * @chk: Whether to perform fault check
203420b0fcbSLars-Peter Clausen  **/
adxrs450_spi_initial(struct adxrs450_state * st,u32 * val,char chk)204420b0fcbSLars-Peter Clausen static int adxrs450_spi_initial(struct adxrs450_state *st,
205420b0fcbSLars-Peter Clausen 		u32 *val, char chk)
206420b0fcbSLars-Peter Clausen {
207420b0fcbSLars-Peter Clausen 	int ret;
208420b0fcbSLars-Peter Clausen 	u32 tx;
209420b0fcbSLars-Peter Clausen 	struct spi_transfer xfers = {
210420b0fcbSLars-Peter Clausen 		.tx_buf = &st->tx,
211420b0fcbSLars-Peter Clausen 		.rx_buf = &st->rx,
212420b0fcbSLars-Peter Clausen 		.bits_per_word = 8,
213420b0fcbSLars-Peter Clausen 		.len = sizeof(st->tx),
214420b0fcbSLars-Peter Clausen 	};
215420b0fcbSLars-Peter Clausen 
216420b0fcbSLars-Peter Clausen 	mutex_lock(&st->buf_lock);
217420b0fcbSLars-Peter Clausen 	tx = ADXRS450_SENSOR_DATA;
218420b0fcbSLars-Peter Clausen 	if (chk)
219420b0fcbSLars-Peter Clausen 		tx |= (ADXRS450_CHK | ADXRS450_P);
220420b0fcbSLars-Peter Clausen 	st->tx = cpu_to_be32(tx);
22114543a00SLars-Peter Clausen 	ret = spi_sync_transfer(st->us, &xfers, 1);
222420b0fcbSLars-Peter Clausen 	if (ret) {
223420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "Problem while reading initializing data\n");
224420b0fcbSLars-Peter Clausen 		goto error_ret;
225420b0fcbSLars-Peter Clausen 	}
226420b0fcbSLars-Peter Clausen 
227420b0fcbSLars-Peter Clausen 	*val = be32_to_cpu(st->rx);
228420b0fcbSLars-Peter Clausen 
229420b0fcbSLars-Peter Clausen error_ret:
230420b0fcbSLars-Peter Clausen 	mutex_unlock(&st->buf_lock);
231420b0fcbSLars-Peter Clausen 	return ret;
232420b0fcbSLars-Peter Clausen }
233420b0fcbSLars-Peter Clausen 
234420b0fcbSLars-Peter Clausen /* Recommended Startup Sequence by spec */
adxrs450_initial_setup(struct iio_dev * indio_dev)235420b0fcbSLars-Peter Clausen static int adxrs450_initial_setup(struct iio_dev *indio_dev)
236420b0fcbSLars-Peter Clausen {
237420b0fcbSLars-Peter Clausen 	u32 t;
238420b0fcbSLars-Peter Clausen 	u16 data;
239420b0fcbSLars-Peter Clausen 	int ret;
240420b0fcbSLars-Peter Clausen 	struct adxrs450_state *st = iio_priv(indio_dev);
241420b0fcbSLars-Peter Clausen 
242420b0fcbSLars-Peter Clausen 	msleep(ADXRS450_STARTUP_DELAY*2);
243420b0fcbSLars-Peter Clausen 	ret = adxrs450_spi_initial(st, &t, 1);
244420b0fcbSLars-Peter Clausen 	if (ret)
245420b0fcbSLars-Peter Clausen 		return ret;
246420b0fcbSLars-Peter Clausen 	if (t != 0x01)
247420b0fcbSLars-Peter Clausen 		dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n");
248420b0fcbSLars-Peter Clausen 
249420b0fcbSLars-Peter Clausen 	msleep(ADXRS450_STARTUP_DELAY);
250420b0fcbSLars-Peter Clausen 	ret = adxrs450_spi_initial(st, &t, 0);
251420b0fcbSLars-Peter Clausen 	if (ret)
252420b0fcbSLars-Peter Clausen 		return ret;
253420b0fcbSLars-Peter Clausen 
254420b0fcbSLars-Peter Clausen 	msleep(ADXRS450_STARTUP_DELAY);
255420b0fcbSLars-Peter Clausen 	ret = adxrs450_spi_initial(st, &t, 0);
256420b0fcbSLars-Peter Clausen 	if (ret)
257420b0fcbSLars-Peter Clausen 		return ret;
258420b0fcbSLars-Peter Clausen 	if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
259420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "The second response is not correct!\n");
260420b0fcbSLars-Peter Clausen 		return -EIO;
261420b0fcbSLars-Peter Clausen 
262420b0fcbSLars-Peter Clausen 	}
263420b0fcbSLars-Peter Clausen 	ret = adxrs450_spi_initial(st, &t, 0);
264420b0fcbSLars-Peter Clausen 	if (ret)
265420b0fcbSLars-Peter Clausen 		return ret;
266420b0fcbSLars-Peter Clausen 	if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
267420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "The third response is not correct!\n");
268420b0fcbSLars-Peter Clausen 		return -EIO;
269420b0fcbSLars-Peter Clausen 
270420b0fcbSLars-Peter Clausen 	}
271420b0fcbSLars-Peter Clausen 	ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data);
272420b0fcbSLars-Peter Clausen 	if (ret)
273420b0fcbSLars-Peter Clausen 		return ret;
274420b0fcbSLars-Peter Clausen 	if (data & 0x0fff) {
275420b0fcbSLars-Peter Clausen 		dev_err(&st->us->dev, "The device is not in normal status!\n");
276420b0fcbSLars-Peter Clausen 		return -EINVAL;
277420b0fcbSLars-Peter Clausen 	}
278420b0fcbSLars-Peter Clausen 
279420b0fcbSLars-Peter Clausen 	return 0;
280420b0fcbSLars-Peter Clausen }
281420b0fcbSLars-Peter Clausen 
adxrs450_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)282420b0fcbSLars-Peter Clausen static int adxrs450_write_raw(struct iio_dev *indio_dev,
283420b0fcbSLars-Peter Clausen 			      struct iio_chan_spec const *chan,
284420b0fcbSLars-Peter Clausen 			      int val,
285420b0fcbSLars-Peter Clausen 			      int val2,
286420b0fcbSLars-Peter Clausen 			      long mask)
287420b0fcbSLars-Peter Clausen {
288420b0fcbSLars-Peter Clausen 	int ret;
289420b0fcbSLars-Peter Clausen 	switch (mask) {
290420b0fcbSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
291420b0fcbSLars-Peter Clausen 		if (val < -0x400 || val >= 0x400)
292420b0fcbSLars-Peter Clausen 			return -EINVAL;
293420b0fcbSLars-Peter Clausen 		ret = adxrs450_spi_write_reg_16(indio_dev,
294420b0fcbSLars-Peter Clausen 						ADXRS450_DNC1, val);
295420b0fcbSLars-Peter Clausen 		break;
296420b0fcbSLars-Peter Clausen 	default:
297420b0fcbSLars-Peter Clausen 		ret = -EINVAL;
298420b0fcbSLars-Peter Clausen 		break;
299420b0fcbSLars-Peter Clausen 	}
300420b0fcbSLars-Peter Clausen 	return ret;
301420b0fcbSLars-Peter Clausen }
302420b0fcbSLars-Peter Clausen 
adxrs450_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)303420b0fcbSLars-Peter Clausen static int adxrs450_read_raw(struct iio_dev *indio_dev,
304420b0fcbSLars-Peter Clausen 			     struct iio_chan_spec const *chan,
305420b0fcbSLars-Peter Clausen 			     int *val,
306420b0fcbSLars-Peter Clausen 			     int *val2,
307420b0fcbSLars-Peter Clausen 			     long mask)
308420b0fcbSLars-Peter Clausen {
309420b0fcbSLars-Peter Clausen 	int ret;
310420b0fcbSLars-Peter Clausen 	s16 t;
311420b0fcbSLars-Peter Clausen 
312420b0fcbSLars-Peter Clausen 	switch (mask) {
313420b0fcbSLars-Peter Clausen 	case IIO_CHAN_INFO_RAW:
314420b0fcbSLars-Peter Clausen 		switch (chan->type) {
315420b0fcbSLars-Peter Clausen 		case IIO_ANGL_VEL:
316420b0fcbSLars-Peter Clausen 			ret = adxrs450_spi_sensor_data(indio_dev, &t);
317420b0fcbSLars-Peter Clausen 			if (ret)
318420b0fcbSLars-Peter Clausen 				break;
319420b0fcbSLars-Peter Clausen 			*val = t;
320420b0fcbSLars-Peter Clausen 			ret = IIO_VAL_INT;
321420b0fcbSLars-Peter Clausen 			break;
322420b0fcbSLars-Peter Clausen 		case IIO_TEMP:
323420b0fcbSLars-Peter Clausen 			ret = adxrs450_spi_read_reg_16(indio_dev,
324420b0fcbSLars-Peter Clausen 						       ADXRS450_TEMP1, &t);
325420b0fcbSLars-Peter Clausen 			if (ret)
326420b0fcbSLars-Peter Clausen 				break;
327420b0fcbSLars-Peter Clausen 			*val = (t >> 6) + 225;
328420b0fcbSLars-Peter Clausen 			ret = IIO_VAL_INT;
329420b0fcbSLars-Peter Clausen 			break;
330420b0fcbSLars-Peter Clausen 		default:
331420b0fcbSLars-Peter Clausen 			ret = -EINVAL;
332420b0fcbSLars-Peter Clausen 			break;
333420b0fcbSLars-Peter Clausen 		}
334420b0fcbSLars-Peter Clausen 		break;
335420b0fcbSLars-Peter Clausen 	case IIO_CHAN_INFO_SCALE:
336420b0fcbSLars-Peter Clausen 		switch (chan->type) {
337420b0fcbSLars-Peter Clausen 		case IIO_ANGL_VEL:
338420b0fcbSLars-Peter Clausen 			*val = 0;
339420b0fcbSLars-Peter Clausen 			*val2 = 218166;
340420b0fcbSLars-Peter Clausen 			return IIO_VAL_INT_PLUS_NANO;
341420b0fcbSLars-Peter Clausen 		case IIO_TEMP:
342420b0fcbSLars-Peter Clausen 			*val = 200;
343420b0fcbSLars-Peter Clausen 			*val2 = 0;
344420b0fcbSLars-Peter Clausen 			return IIO_VAL_INT;
345420b0fcbSLars-Peter Clausen 		default:
346420b0fcbSLars-Peter Clausen 			return -EINVAL;
347420b0fcbSLars-Peter Clausen 		}
348420b0fcbSLars-Peter Clausen 	case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW:
349420b0fcbSLars-Peter Clausen 		ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t);
350420b0fcbSLars-Peter Clausen 		if (ret)
351420b0fcbSLars-Peter Clausen 			break;
352420b0fcbSLars-Peter Clausen 		*val = t;
353420b0fcbSLars-Peter Clausen 		ret = IIO_VAL_INT;
354420b0fcbSLars-Peter Clausen 		break;
355420b0fcbSLars-Peter Clausen 	case IIO_CHAN_INFO_CALIBBIAS:
356420b0fcbSLars-Peter Clausen 		ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t);
357420b0fcbSLars-Peter Clausen 		if (ret)
358420b0fcbSLars-Peter Clausen 			break;
359420b0fcbSLars-Peter Clausen 		*val = sign_extend32(t, 9);
360420b0fcbSLars-Peter Clausen 		ret = IIO_VAL_INT;
361420b0fcbSLars-Peter Clausen 		break;
362420b0fcbSLars-Peter Clausen 	default:
363420b0fcbSLars-Peter Clausen 		ret = -EINVAL;
364420b0fcbSLars-Peter Clausen 		break;
365420b0fcbSLars-Peter Clausen 	}
366420b0fcbSLars-Peter Clausen 
367420b0fcbSLars-Peter Clausen 	return ret;
368420b0fcbSLars-Peter Clausen }
369420b0fcbSLars-Peter Clausen 
370420b0fcbSLars-Peter Clausen static const struct iio_chan_spec adxrs450_channels[2][2] = {
371420b0fcbSLars-Peter Clausen 	[ID_ADXRS450] = {
372420b0fcbSLars-Peter Clausen 		{
373420b0fcbSLars-Peter Clausen 			.type = IIO_ANGL_VEL,
374420b0fcbSLars-Peter Clausen 			.modified = 1,
375420b0fcbSLars-Peter Clausen 			.channel2 = IIO_MOD_Z,
37698bfb6e3SJonathan Cameron 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
37798bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_CALIBBIAS) |
37898bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) |
37998bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE),
380420b0fcbSLars-Peter Clausen 		}, {
381420b0fcbSLars-Peter Clausen 			.type = IIO_TEMP,
382420b0fcbSLars-Peter Clausen 			.indexed = 1,
383420b0fcbSLars-Peter Clausen 			.channel = 0,
38498bfb6e3SJonathan Cameron 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
38598bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE),
386420b0fcbSLars-Peter Clausen 		}
387420b0fcbSLars-Peter Clausen 	},
388420b0fcbSLars-Peter Clausen 	[ID_ADXRS453] = {
389420b0fcbSLars-Peter Clausen 		{
390420b0fcbSLars-Peter Clausen 			.type = IIO_ANGL_VEL,
391420b0fcbSLars-Peter Clausen 			.modified = 1,
392420b0fcbSLars-Peter Clausen 			.channel2 = IIO_MOD_Z,
39398bfb6e3SJonathan Cameron 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
39498bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE) |
39598bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW),
396420b0fcbSLars-Peter Clausen 		}, {
397420b0fcbSLars-Peter Clausen 			.type = IIO_TEMP,
398420b0fcbSLars-Peter Clausen 			.indexed = 1,
399420b0fcbSLars-Peter Clausen 			.channel = 0,
40098bfb6e3SJonathan Cameron 			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
40198bfb6e3SJonathan Cameron 			BIT(IIO_CHAN_INFO_SCALE),
402420b0fcbSLars-Peter Clausen 		}
403420b0fcbSLars-Peter Clausen 	},
404420b0fcbSLars-Peter Clausen };
405420b0fcbSLars-Peter Clausen 
406420b0fcbSLars-Peter Clausen static const struct iio_info adxrs450_info = {
407420b0fcbSLars-Peter Clausen 	.read_raw = &adxrs450_read_raw,
408420b0fcbSLars-Peter Clausen 	.write_raw = &adxrs450_write_raw,
409420b0fcbSLars-Peter Clausen };
410420b0fcbSLars-Peter Clausen 
adxrs450_probe(struct spi_device * spi)411420b0fcbSLars-Peter Clausen static int adxrs450_probe(struct spi_device *spi)
412420b0fcbSLars-Peter Clausen {
413420b0fcbSLars-Peter Clausen 	int ret;
414420b0fcbSLars-Peter Clausen 	struct adxrs450_state *st;
415420b0fcbSLars-Peter Clausen 	struct iio_dev *indio_dev;
416420b0fcbSLars-Peter Clausen 
417420b0fcbSLars-Peter Clausen 	/* setup the industrialio driver allocated elements */
4186694cf96SSachin Kamat 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
4196694cf96SSachin Kamat 	if (!indio_dev)
4206694cf96SSachin Kamat 		return -ENOMEM;
421420b0fcbSLars-Peter Clausen 	st = iio_priv(indio_dev);
422420b0fcbSLars-Peter Clausen 	st->us = spi;
423420b0fcbSLars-Peter Clausen 	mutex_init(&st->buf_lock);
424420b0fcbSLars-Peter Clausen 	/* This is only used for removal purposes */
425420b0fcbSLars-Peter Clausen 	spi_set_drvdata(spi, indio_dev);
426420b0fcbSLars-Peter Clausen 
427420b0fcbSLars-Peter Clausen 	indio_dev->info = &adxrs450_info;
428420b0fcbSLars-Peter Clausen 	indio_dev->modes = INDIO_DIRECT_MODE;
429420b0fcbSLars-Peter Clausen 	indio_dev->channels =
430420b0fcbSLars-Peter Clausen 		adxrs450_channels[spi_get_device_id(spi)->driver_data];
431420b0fcbSLars-Peter Clausen 	indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels);
432420b0fcbSLars-Peter Clausen 	indio_dev->name = spi->dev.driver->name;
433420b0fcbSLars-Peter Clausen 
4349bcbf02aSSachin Kamat 	ret = devm_iio_device_register(&spi->dev, indio_dev);
435420b0fcbSLars-Peter Clausen 	if (ret)
4366694cf96SSachin Kamat 		return ret;
437420b0fcbSLars-Peter Clausen 
438420b0fcbSLars-Peter Clausen 	/* Get the device into a sane initial state */
439420b0fcbSLars-Peter Clausen 	ret = adxrs450_initial_setup(indio_dev);
440420b0fcbSLars-Peter Clausen 	if (ret)
441420b0fcbSLars-Peter Clausen 		return ret;
442420b0fcbSLars-Peter Clausen 
443420b0fcbSLars-Peter Clausen 	return 0;
444420b0fcbSLars-Peter Clausen }
445420b0fcbSLars-Peter Clausen 
446420b0fcbSLars-Peter Clausen static const struct spi_device_id adxrs450_id[] = {
447420b0fcbSLars-Peter Clausen 	{"adxrs450", ID_ADXRS450},
448420b0fcbSLars-Peter Clausen 	{"adxrs453", ID_ADXRS453},
449420b0fcbSLars-Peter Clausen 	{}
450420b0fcbSLars-Peter Clausen };
451420b0fcbSLars-Peter Clausen MODULE_DEVICE_TABLE(spi, adxrs450_id);
452420b0fcbSLars-Peter Clausen 
453420b0fcbSLars-Peter Clausen static struct spi_driver adxrs450_driver = {
454420b0fcbSLars-Peter Clausen 	.driver = {
455420b0fcbSLars-Peter Clausen 		.name = "adxrs450",
456420b0fcbSLars-Peter Clausen 	},
457420b0fcbSLars-Peter Clausen 	.probe = adxrs450_probe,
458420b0fcbSLars-Peter Clausen 	.id_table	= adxrs450_id,
459420b0fcbSLars-Peter Clausen };
460420b0fcbSLars-Peter Clausen module_spi_driver(adxrs450_driver);
461420b0fcbSLars-Peter Clausen 
462420b0fcbSLars-Peter Clausen MODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>");
463420b0fcbSLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver");
464420b0fcbSLars-Peter Clausen MODULE_LICENSE("GPL v2");
465