162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ADXRS450/ADXRS453 Digital Output Gyroscope Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2011 Analog Devices Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <linux/irq.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/mutex.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/spi/spi.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/sysfs.h>
1762306a36Sopenharmony_ci#include <linux/list.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/iio/iio.h>
2162306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define ADXRS450_STARTUP_DELAY	50 /* ms */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* The MSB for the spi commands */
2662306a36Sopenharmony_ci#define ADXRS450_SENSOR_DATA    (0x20 << 24)
2762306a36Sopenharmony_ci#define ADXRS450_WRITE_DATA	(0x40 << 24)
2862306a36Sopenharmony_ci#define ADXRS450_READ_DATA	(0x80 << 24)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define ADXRS450_RATE1	0x00	/* Rate Registers */
3162306a36Sopenharmony_ci#define ADXRS450_TEMP1	0x02	/* Temperature Registers */
3262306a36Sopenharmony_ci#define ADXRS450_LOCST1	0x04	/* Low CST Memory Registers */
3362306a36Sopenharmony_ci#define ADXRS450_HICST1	0x06	/* High CST Memory Registers */
3462306a36Sopenharmony_ci#define ADXRS450_QUAD1	0x08	/* Quad Memory Registers */
3562306a36Sopenharmony_ci#define ADXRS450_FAULT1	0x0A	/* Fault Registers */
3662306a36Sopenharmony_ci#define ADXRS450_PID1	0x0C	/* Part ID Register 1 */
3762306a36Sopenharmony_ci#define ADXRS450_SNH	0x0E	/* Serial Number Registers, 4 bytes */
3862306a36Sopenharmony_ci#define ADXRS450_SNL	0x10
3962306a36Sopenharmony_ci#define ADXRS450_DNC1	0x12	/* Dynamic Null Correction Registers */
4062306a36Sopenharmony_ci/* Check bits */
4162306a36Sopenharmony_ci#define ADXRS450_P	0x01
4262306a36Sopenharmony_ci#define ADXRS450_CHK	0x02
4362306a36Sopenharmony_ci#define ADXRS450_CST	0x04
4462306a36Sopenharmony_ci#define ADXRS450_PWR	0x08
4562306a36Sopenharmony_ci#define ADXRS450_POR	0x10
4662306a36Sopenharmony_ci#define ADXRS450_NVM	0x20
4762306a36Sopenharmony_ci#define ADXRS450_Q	0x40
4862306a36Sopenharmony_ci#define ADXRS450_PLL	0x80
4962306a36Sopenharmony_ci#define ADXRS450_UV	0x100
5062306a36Sopenharmony_ci#define ADXRS450_OV	0x200
5162306a36Sopenharmony_ci#define ADXRS450_AMP	0x400
5262306a36Sopenharmony_ci#define ADXRS450_FAIL	0x800
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define ADXRS450_WRERR_MASK	(0x7 << 29)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define ADXRS450_MAX_RX 4
5762306a36Sopenharmony_ci#define ADXRS450_MAX_TX 4
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define ADXRS450_GET_ST(a)	((a >> 26) & 0x3)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cienum {
6262306a36Sopenharmony_ci	ID_ADXRS450,
6362306a36Sopenharmony_ci	ID_ADXRS453,
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/**
6762306a36Sopenharmony_ci * struct adxrs450_state - device instance specific data
6862306a36Sopenharmony_ci * @us:			actual spi_device
6962306a36Sopenharmony_ci * @buf_lock:		mutex to protect tx and rx
7062306a36Sopenharmony_ci * @tx:			transmit buffer
7162306a36Sopenharmony_ci * @rx:			receive buffer
7262306a36Sopenharmony_ci **/
7362306a36Sopenharmony_cistruct adxrs450_state {
7462306a36Sopenharmony_ci	struct spi_device	*us;
7562306a36Sopenharmony_ci	struct mutex		buf_lock;
7662306a36Sopenharmony_ci	__be32			tx __aligned(IIO_DMA_MINALIGN);
7762306a36Sopenharmony_ci	__be32			rx;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/**
8262306a36Sopenharmony_ci * adxrs450_spi_read_reg_16() - read 2 bytes from a register pair
8362306a36Sopenharmony_ci * @indio_dev: device associated with child of actual iio_dev
8462306a36Sopenharmony_ci * @reg_address: the address of the lower of the two registers, which should be
8562306a36Sopenharmony_ci *	an even address, the second register's address is reg_address + 1.
8662306a36Sopenharmony_ci * @val: somewhere to pass back the value read
8762306a36Sopenharmony_ci **/
8862306a36Sopenharmony_cistatic int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev,
8962306a36Sopenharmony_ci				    u8 reg_address,
9062306a36Sopenharmony_ci				    u16 *val)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct adxrs450_state *st = iio_priv(indio_dev);
9362306a36Sopenharmony_ci	u32 tx;
9462306a36Sopenharmony_ci	int ret;
9562306a36Sopenharmony_ci	struct spi_transfer xfers[] = {
9662306a36Sopenharmony_ci		{
9762306a36Sopenharmony_ci			.tx_buf = &st->tx,
9862306a36Sopenharmony_ci			.bits_per_word = 8,
9962306a36Sopenharmony_ci			.len = sizeof(st->tx),
10062306a36Sopenharmony_ci			.cs_change = 1,
10162306a36Sopenharmony_ci		}, {
10262306a36Sopenharmony_ci			.rx_buf = &st->rx,
10362306a36Sopenharmony_ci			.bits_per_word = 8,
10462306a36Sopenharmony_ci			.len = sizeof(st->rx),
10562306a36Sopenharmony_ci		},
10662306a36Sopenharmony_ci	};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	mutex_lock(&st->buf_lock);
10962306a36Sopenharmony_ci	tx = ADXRS450_READ_DATA | (reg_address << 17);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (!(hweight32(tx) & 1))
11262306a36Sopenharmony_ci		tx |= ADXRS450_P;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	st->tx = cpu_to_be32(tx);
11562306a36Sopenharmony_ci	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
11662306a36Sopenharmony_ci	if (ret) {
11762306a36Sopenharmony_ci		dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n",
11862306a36Sopenharmony_ci				reg_address);
11962306a36Sopenharmony_ci		goto error_ret;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	*val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cierror_ret:
12562306a36Sopenharmony_ci	mutex_unlock(&st->buf_lock);
12662306a36Sopenharmony_ci	return ret;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/**
13062306a36Sopenharmony_ci * adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair
13162306a36Sopenharmony_ci * @indio_dev: device associated with child of actual actual iio_dev
13262306a36Sopenharmony_ci * @reg_address: the address of the lower of the two registers,which should be
13362306a36Sopenharmony_ci *	an even address, the second register's address is reg_address + 1.
13462306a36Sopenharmony_ci * @val: value to be written.
13562306a36Sopenharmony_ci **/
13662306a36Sopenharmony_cistatic int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev,
13762306a36Sopenharmony_ci				     u8 reg_address,
13862306a36Sopenharmony_ci				     u16 val)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct adxrs450_state *st = iio_priv(indio_dev);
14162306a36Sopenharmony_ci	u32 tx;
14262306a36Sopenharmony_ci	int ret;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	mutex_lock(&st->buf_lock);
14562306a36Sopenharmony_ci	tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (!(hweight32(tx) & 1))
14862306a36Sopenharmony_ci		tx |= ADXRS450_P;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	st->tx = cpu_to_be32(tx);
15162306a36Sopenharmony_ci	ret = spi_write(st->us, &st->tx, sizeof(st->tx));
15262306a36Sopenharmony_ci	if (ret)
15362306a36Sopenharmony_ci		dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n",
15462306a36Sopenharmony_ci			reg_address);
15562306a36Sopenharmony_ci	usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */
15662306a36Sopenharmony_ci	mutex_unlock(&st->buf_lock);
15762306a36Sopenharmony_ci	return ret;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * adxrs450_spi_sensor_data() - read 2 bytes sensor data
16262306a36Sopenharmony_ci * @indio_dev: device associated with child of actual iio_dev
16362306a36Sopenharmony_ci * @val: somewhere to pass back the value read
16462306a36Sopenharmony_ci **/
16562306a36Sopenharmony_cistatic int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct adxrs450_state *st = iio_priv(indio_dev);
16862306a36Sopenharmony_ci	int ret;
16962306a36Sopenharmony_ci	struct spi_transfer xfers[] = {
17062306a36Sopenharmony_ci		{
17162306a36Sopenharmony_ci			.tx_buf = &st->tx,
17262306a36Sopenharmony_ci			.bits_per_word = 8,
17362306a36Sopenharmony_ci			.len = sizeof(st->tx),
17462306a36Sopenharmony_ci			.cs_change = 1,
17562306a36Sopenharmony_ci		}, {
17662306a36Sopenharmony_ci			.rx_buf = &st->rx,
17762306a36Sopenharmony_ci			.bits_per_word = 8,
17862306a36Sopenharmony_ci			.len = sizeof(st->rx),
17962306a36Sopenharmony_ci		},
18062306a36Sopenharmony_ci	};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	mutex_lock(&st->buf_lock);
18362306a36Sopenharmony_ci	st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
18662306a36Sopenharmony_ci	if (ret) {
18762306a36Sopenharmony_ci		dev_err(&st->us->dev, "Problem while reading sensor data\n");
18862306a36Sopenharmony_ci		goto error_ret;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	*val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cierror_ret:
19462306a36Sopenharmony_ci	mutex_unlock(&st->buf_lock);
19562306a36Sopenharmony_ci	return ret;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/**
19962306a36Sopenharmony_ci * adxrs450_spi_initial() - use for initializing procedure.
20062306a36Sopenharmony_ci * @st: device instance specific data
20162306a36Sopenharmony_ci * @val: somewhere to pass back the value read
20262306a36Sopenharmony_ci * @chk: Whether to perform fault check
20362306a36Sopenharmony_ci **/
20462306a36Sopenharmony_cistatic int adxrs450_spi_initial(struct adxrs450_state *st,
20562306a36Sopenharmony_ci		u32 *val, char chk)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	int ret;
20862306a36Sopenharmony_ci	u32 tx;
20962306a36Sopenharmony_ci	struct spi_transfer xfers = {
21062306a36Sopenharmony_ci		.tx_buf = &st->tx,
21162306a36Sopenharmony_ci		.rx_buf = &st->rx,
21262306a36Sopenharmony_ci		.bits_per_word = 8,
21362306a36Sopenharmony_ci		.len = sizeof(st->tx),
21462306a36Sopenharmony_ci	};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	mutex_lock(&st->buf_lock);
21762306a36Sopenharmony_ci	tx = ADXRS450_SENSOR_DATA;
21862306a36Sopenharmony_ci	if (chk)
21962306a36Sopenharmony_ci		tx |= (ADXRS450_CHK | ADXRS450_P);
22062306a36Sopenharmony_ci	st->tx = cpu_to_be32(tx);
22162306a36Sopenharmony_ci	ret = spi_sync_transfer(st->us, &xfers, 1);
22262306a36Sopenharmony_ci	if (ret) {
22362306a36Sopenharmony_ci		dev_err(&st->us->dev, "Problem while reading initializing data\n");
22462306a36Sopenharmony_ci		goto error_ret;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	*val = be32_to_cpu(st->rx);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cierror_ret:
23062306a36Sopenharmony_ci	mutex_unlock(&st->buf_lock);
23162306a36Sopenharmony_ci	return ret;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/* Recommended Startup Sequence by spec */
23562306a36Sopenharmony_cistatic int adxrs450_initial_setup(struct iio_dev *indio_dev)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	u32 t;
23862306a36Sopenharmony_ci	u16 data;
23962306a36Sopenharmony_ci	int ret;
24062306a36Sopenharmony_ci	struct adxrs450_state *st = iio_priv(indio_dev);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	msleep(ADXRS450_STARTUP_DELAY*2);
24362306a36Sopenharmony_ci	ret = adxrs450_spi_initial(st, &t, 1);
24462306a36Sopenharmony_ci	if (ret)
24562306a36Sopenharmony_ci		return ret;
24662306a36Sopenharmony_ci	if (t != 0x01)
24762306a36Sopenharmony_ci		dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	msleep(ADXRS450_STARTUP_DELAY);
25062306a36Sopenharmony_ci	ret = adxrs450_spi_initial(st, &t, 0);
25162306a36Sopenharmony_ci	if (ret)
25262306a36Sopenharmony_ci		return ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	msleep(ADXRS450_STARTUP_DELAY);
25562306a36Sopenharmony_ci	ret = adxrs450_spi_initial(st, &t, 0);
25662306a36Sopenharmony_ci	if (ret)
25762306a36Sopenharmony_ci		return ret;
25862306a36Sopenharmony_ci	if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
25962306a36Sopenharmony_ci		dev_err(&st->us->dev, "The second response is not correct!\n");
26062306a36Sopenharmony_ci		return -EIO;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci	ret = adxrs450_spi_initial(st, &t, 0);
26462306a36Sopenharmony_ci	if (ret)
26562306a36Sopenharmony_ci		return ret;
26662306a36Sopenharmony_ci	if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) {
26762306a36Sopenharmony_ci		dev_err(&st->us->dev, "The third response is not correct!\n");
26862306a36Sopenharmony_ci		return -EIO;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci	ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data);
27262306a36Sopenharmony_ci	if (ret)
27362306a36Sopenharmony_ci		return ret;
27462306a36Sopenharmony_ci	if (data & 0x0fff) {
27562306a36Sopenharmony_ci		dev_err(&st->us->dev, "The device is not in normal status!\n");
27662306a36Sopenharmony_ci		return -EINVAL;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int adxrs450_write_raw(struct iio_dev *indio_dev,
28362306a36Sopenharmony_ci			      struct iio_chan_spec const *chan,
28462306a36Sopenharmony_ci			      int val,
28562306a36Sopenharmony_ci			      int val2,
28662306a36Sopenharmony_ci			      long mask)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	int ret;
28962306a36Sopenharmony_ci	switch (mask) {
29062306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
29162306a36Sopenharmony_ci		if (val < -0x400 || val >= 0x400)
29262306a36Sopenharmony_ci			return -EINVAL;
29362306a36Sopenharmony_ci		ret = adxrs450_spi_write_reg_16(indio_dev,
29462306a36Sopenharmony_ci						ADXRS450_DNC1, val);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	default:
29762306a36Sopenharmony_ci		ret = -EINVAL;
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	return ret;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int adxrs450_read_raw(struct iio_dev *indio_dev,
30462306a36Sopenharmony_ci			     struct iio_chan_spec const *chan,
30562306a36Sopenharmony_ci			     int *val,
30662306a36Sopenharmony_ci			     int *val2,
30762306a36Sopenharmony_ci			     long mask)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	int ret;
31062306a36Sopenharmony_ci	s16 t;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	switch (mask) {
31362306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
31462306a36Sopenharmony_ci		switch (chan->type) {
31562306a36Sopenharmony_ci		case IIO_ANGL_VEL:
31662306a36Sopenharmony_ci			ret = adxrs450_spi_sensor_data(indio_dev, &t);
31762306a36Sopenharmony_ci			if (ret)
31862306a36Sopenharmony_ci				break;
31962306a36Sopenharmony_ci			*val = t;
32062306a36Sopenharmony_ci			ret = IIO_VAL_INT;
32162306a36Sopenharmony_ci			break;
32262306a36Sopenharmony_ci		case IIO_TEMP:
32362306a36Sopenharmony_ci			ret = adxrs450_spi_read_reg_16(indio_dev,
32462306a36Sopenharmony_ci						       ADXRS450_TEMP1, &t);
32562306a36Sopenharmony_ci			if (ret)
32662306a36Sopenharmony_ci				break;
32762306a36Sopenharmony_ci			*val = (t >> 6) + 225;
32862306a36Sopenharmony_ci			ret = IIO_VAL_INT;
32962306a36Sopenharmony_ci			break;
33062306a36Sopenharmony_ci		default:
33162306a36Sopenharmony_ci			ret = -EINVAL;
33262306a36Sopenharmony_ci			break;
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci		break;
33562306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
33662306a36Sopenharmony_ci		switch (chan->type) {
33762306a36Sopenharmony_ci		case IIO_ANGL_VEL:
33862306a36Sopenharmony_ci			*val = 0;
33962306a36Sopenharmony_ci			*val2 = 218166;
34062306a36Sopenharmony_ci			return IIO_VAL_INT_PLUS_NANO;
34162306a36Sopenharmony_ci		case IIO_TEMP:
34262306a36Sopenharmony_ci			*val = 200;
34362306a36Sopenharmony_ci			*val2 = 0;
34462306a36Sopenharmony_ci			return IIO_VAL_INT;
34562306a36Sopenharmony_ci		default:
34662306a36Sopenharmony_ci			return -EINVAL;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci	case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW:
34962306a36Sopenharmony_ci		ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t);
35062306a36Sopenharmony_ci		if (ret)
35162306a36Sopenharmony_ci			break;
35262306a36Sopenharmony_ci		*val = t;
35362306a36Sopenharmony_ci		ret = IIO_VAL_INT;
35462306a36Sopenharmony_ci		break;
35562306a36Sopenharmony_ci	case IIO_CHAN_INFO_CALIBBIAS:
35662306a36Sopenharmony_ci		ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t);
35762306a36Sopenharmony_ci		if (ret)
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci		*val = sign_extend32(t, 9);
36062306a36Sopenharmony_ci		ret = IIO_VAL_INT;
36162306a36Sopenharmony_ci		break;
36262306a36Sopenharmony_ci	default:
36362306a36Sopenharmony_ci		ret = -EINVAL;
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return ret;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic const struct iio_chan_spec adxrs450_channels[2][2] = {
37162306a36Sopenharmony_ci	[ID_ADXRS450] = {
37262306a36Sopenharmony_ci		{
37362306a36Sopenharmony_ci			.type = IIO_ANGL_VEL,
37462306a36Sopenharmony_ci			.modified = 1,
37562306a36Sopenharmony_ci			.channel2 = IIO_MOD_Z,
37662306a36Sopenharmony_ci			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
37762306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_CALIBBIAS) |
37862306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) |
37962306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE),
38062306a36Sopenharmony_ci		}, {
38162306a36Sopenharmony_ci			.type = IIO_TEMP,
38262306a36Sopenharmony_ci			.indexed = 1,
38362306a36Sopenharmony_ci			.channel = 0,
38462306a36Sopenharmony_ci			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
38562306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE),
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci	},
38862306a36Sopenharmony_ci	[ID_ADXRS453] = {
38962306a36Sopenharmony_ci		{
39062306a36Sopenharmony_ci			.type = IIO_ANGL_VEL,
39162306a36Sopenharmony_ci			.modified = 1,
39262306a36Sopenharmony_ci			.channel2 = IIO_MOD_Z,
39362306a36Sopenharmony_ci			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
39462306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE) |
39562306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW),
39662306a36Sopenharmony_ci		}, {
39762306a36Sopenharmony_ci			.type = IIO_TEMP,
39862306a36Sopenharmony_ci			.indexed = 1,
39962306a36Sopenharmony_ci			.channel = 0,
40062306a36Sopenharmony_ci			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
40162306a36Sopenharmony_ci			BIT(IIO_CHAN_INFO_SCALE),
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci	},
40462306a36Sopenharmony_ci};
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic const struct iio_info adxrs450_info = {
40762306a36Sopenharmony_ci	.read_raw = &adxrs450_read_raw,
40862306a36Sopenharmony_ci	.write_raw = &adxrs450_write_raw,
40962306a36Sopenharmony_ci};
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic int adxrs450_probe(struct spi_device *spi)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	int ret;
41462306a36Sopenharmony_ci	struct adxrs450_state *st;
41562306a36Sopenharmony_ci	struct iio_dev *indio_dev;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* setup the industrialio driver allocated elements */
41862306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
41962306a36Sopenharmony_ci	if (!indio_dev)
42062306a36Sopenharmony_ci		return -ENOMEM;
42162306a36Sopenharmony_ci	st = iio_priv(indio_dev);
42262306a36Sopenharmony_ci	st->us = spi;
42362306a36Sopenharmony_ci	mutex_init(&st->buf_lock);
42462306a36Sopenharmony_ci	/* This is only used for removal purposes */
42562306a36Sopenharmony_ci	spi_set_drvdata(spi, indio_dev);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	indio_dev->info = &adxrs450_info;
42862306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
42962306a36Sopenharmony_ci	indio_dev->channels =
43062306a36Sopenharmony_ci		adxrs450_channels[spi_get_device_id(spi)->driver_data];
43162306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels);
43262306a36Sopenharmony_ci	indio_dev->name = spi->dev.driver->name;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	ret = devm_iio_device_register(&spi->dev, indio_dev);
43562306a36Sopenharmony_ci	if (ret)
43662306a36Sopenharmony_ci		return ret;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Get the device into a sane initial state */
43962306a36Sopenharmony_ci	ret = adxrs450_initial_setup(indio_dev);
44062306a36Sopenharmony_ci	if (ret)
44162306a36Sopenharmony_ci		return ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic const struct spi_device_id adxrs450_id[] = {
44762306a36Sopenharmony_ci	{"adxrs450", ID_ADXRS450},
44862306a36Sopenharmony_ci	{"adxrs453", ID_ADXRS453},
44962306a36Sopenharmony_ci	{}
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adxrs450_id);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic struct spi_driver adxrs450_driver = {
45462306a36Sopenharmony_ci	.driver = {
45562306a36Sopenharmony_ci		.name = "adxrs450",
45662306a36Sopenharmony_ci	},
45762306a36Sopenharmony_ci	.probe = adxrs450_probe,
45862306a36Sopenharmony_ci	.id_table	= adxrs450_id,
45962306a36Sopenharmony_ci};
46062306a36Sopenharmony_cimodule_spi_driver(adxrs450_driver);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ciMODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>");
46362306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver");
46462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
465