18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADXRS450/ADXRS453 Digital Output Gyroscope Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011 Analog Devices Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/irq.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/mutex.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 178c2ecf20Sopenharmony_ci#include <linux/list.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 218c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define ADXRS450_STARTUP_DELAY 50 /* ms */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* The MSB for the spi commands */ 268c2ecf20Sopenharmony_ci#define ADXRS450_SENSOR_DATA (0x20 << 24) 278c2ecf20Sopenharmony_ci#define ADXRS450_WRITE_DATA (0x40 << 24) 288c2ecf20Sopenharmony_ci#define ADXRS450_READ_DATA (0x80 << 24) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define ADXRS450_RATE1 0x00 /* Rate Registers */ 318c2ecf20Sopenharmony_ci#define ADXRS450_TEMP1 0x02 /* Temperature Registers */ 328c2ecf20Sopenharmony_ci#define ADXRS450_LOCST1 0x04 /* Low CST Memory Registers */ 338c2ecf20Sopenharmony_ci#define ADXRS450_HICST1 0x06 /* High CST Memory Registers */ 348c2ecf20Sopenharmony_ci#define ADXRS450_QUAD1 0x08 /* Quad Memory Registers */ 358c2ecf20Sopenharmony_ci#define ADXRS450_FAULT1 0x0A /* Fault Registers */ 368c2ecf20Sopenharmony_ci#define ADXRS450_PID1 0x0C /* Part ID Register 1 */ 378c2ecf20Sopenharmony_ci#define ADXRS450_SNH 0x0E /* Serial Number Registers, 4 bytes */ 388c2ecf20Sopenharmony_ci#define ADXRS450_SNL 0x10 398c2ecf20Sopenharmony_ci#define ADXRS450_DNC1 0x12 /* Dynamic Null Correction Registers */ 408c2ecf20Sopenharmony_ci/* Check bits */ 418c2ecf20Sopenharmony_ci#define ADXRS450_P 0x01 428c2ecf20Sopenharmony_ci#define ADXRS450_CHK 0x02 438c2ecf20Sopenharmony_ci#define ADXRS450_CST 0x04 448c2ecf20Sopenharmony_ci#define ADXRS450_PWR 0x08 458c2ecf20Sopenharmony_ci#define ADXRS450_POR 0x10 468c2ecf20Sopenharmony_ci#define ADXRS450_NVM 0x20 478c2ecf20Sopenharmony_ci#define ADXRS450_Q 0x40 488c2ecf20Sopenharmony_ci#define ADXRS450_PLL 0x80 498c2ecf20Sopenharmony_ci#define ADXRS450_UV 0x100 508c2ecf20Sopenharmony_ci#define ADXRS450_OV 0x200 518c2ecf20Sopenharmony_ci#define ADXRS450_AMP 0x400 528c2ecf20Sopenharmony_ci#define ADXRS450_FAIL 0x800 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define ADXRS450_WRERR_MASK (0x7 << 29) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define ADXRS450_MAX_RX 4 578c2ecf20Sopenharmony_ci#define ADXRS450_MAX_TX 4 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define ADXRS450_GET_ST(a) ((a >> 26) & 0x3) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cienum { 628c2ecf20Sopenharmony_ci ID_ADXRS450, 638c2ecf20Sopenharmony_ci ID_ADXRS453, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * struct adxrs450_state - device instance specific data 688c2ecf20Sopenharmony_ci * @us: actual spi_device 698c2ecf20Sopenharmony_ci * @buf_lock: mutex to protect tx and rx 708c2ecf20Sopenharmony_ci * @tx: transmit buffer 718c2ecf20Sopenharmony_ci * @rx: receive buffer 728c2ecf20Sopenharmony_ci **/ 738c2ecf20Sopenharmony_cistruct adxrs450_state { 748c2ecf20Sopenharmony_ci struct spi_device *us; 758c2ecf20Sopenharmony_ci struct mutex buf_lock; 768c2ecf20Sopenharmony_ci __be32 tx ____cacheline_aligned; 778c2ecf20Sopenharmony_ci __be32 rx; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * adxrs450_spi_read_reg_16() - read 2 bytes from a register pair 838c2ecf20Sopenharmony_ci * @indio_dev: device associated with child of actual iio_dev 848c2ecf20Sopenharmony_ci * @reg_address: the address of the lower of the two registers, which should be 858c2ecf20Sopenharmony_ci * an even address, the second register's address is reg_address + 1. 868c2ecf20Sopenharmony_ci * @val: somewhere to pass back the value read 878c2ecf20Sopenharmony_ci **/ 888c2ecf20Sopenharmony_cistatic int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, 898c2ecf20Sopenharmony_ci u8 reg_address, 908c2ecf20Sopenharmony_ci u16 *val) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct adxrs450_state *st = iio_priv(indio_dev); 938c2ecf20Sopenharmony_ci u32 tx; 948c2ecf20Sopenharmony_ci int ret; 958c2ecf20Sopenharmony_ci struct spi_transfer xfers[] = { 968c2ecf20Sopenharmony_ci { 978c2ecf20Sopenharmony_ci .tx_buf = &st->tx, 988c2ecf20Sopenharmony_ci .bits_per_word = 8, 998c2ecf20Sopenharmony_ci .len = sizeof(st->tx), 1008c2ecf20Sopenharmony_ci .cs_change = 1, 1018c2ecf20Sopenharmony_ci }, { 1028c2ecf20Sopenharmony_ci .rx_buf = &st->rx, 1038c2ecf20Sopenharmony_ci .bits_per_word = 8, 1048c2ecf20Sopenharmony_ci .len = sizeof(st->rx), 1058c2ecf20Sopenharmony_ci }, 1068c2ecf20Sopenharmony_ci }; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci mutex_lock(&st->buf_lock); 1098c2ecf20Sopenharmony_ci tx = ADXRS450_READ_DATA | (reg_address << 17); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!(hweight32(tx) & 1)) 1128c2ecf20Sopenharmony_ci tx |= ADXRS450_P; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci st->tx = cpu_to_be32(tx); 1158c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); 1168c2ecf20Sopenharmony_ci if (ret) { 1178c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n", 1188c2ecf20Sopenharmony_ci reg_address); 1198c2ecf20Sopenharmony_ci goto error_ret; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci *val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cierror_ret: 1258c2ecf20Sopenharmony_ci mutex_unlock(&st->buf_lock); 1268c2ecf20Sopenharmony_ci return ret; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/** 1308c2ecf20Sopenharmony_ci * adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair 1318c2ecf20Sopenharmony_ci * @indio_dev: device associated with child of actual actual iio_dev 1328c2ecf20Sopenharmony_ci * @reg_address: the address of the lower of the two registers,which should be 1338c2ecf20Sopenharmony_ci * an even address, the second register's address is reg_address + 1. 1348c2ecf20Sopenharmony_ci * @val: value to be written. 1358c2ecf20Sopenharmony_ci **/ 1368c2ecf20Sopenharmony_cistatic int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev, 1378c2ecf20Sopenharmony_ci u8 reg_address, 1388c2ecf20Sopenharmony_ci u16 val) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct adxrs450_state *st = iio_priv(indio_dev); 1418c2ecf20Sopenharmony_ci u32 tx; 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci mutex_lock(&st->buf_lock); 1458c2ecf20Sopenharmony_ci tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!(hweight32(tx) & 1)) 1488c2ecf20Sopenharmony_ci tx |= ADXRS450_P; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci st->tx = cpu_to_be32(tx); 1518c2ecf20Sopenharmony_ci ret = spi_write(st->us, &st->tx, sizeof(st->tx)); 1528c2ecf20Sopenharmony_ci if (ret) 1538c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n", 1548c2ecf20Sopenharmony_ci reg_address); 1558c2ecf20Sopenharmony_ci usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */ 1568c2ecf20Sopenharmony_ci mutex_unlock(&st->buf_lock); 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/** 1618c2ecf20Sopenharmony_ci * adxrs450_spi_sensor_data() - read 2 bytes sensor data 1628c2ecf20Sopenharmony_ci * @indio_dev: device associated with child of actual iio_dev 1638c2ecf20Sopenharmony_ci * @val: somewhere to pass back the value read 1648c2ecf20Sopenharmony_ci **/ 1658c2ecf20Sopenharmony_cistatic int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct adxrs450_state *st = iio_priv(indio_dev); 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci struct spi_transfer xfers[] = { 1708c2ecf20Sopenharmony_ci { 1718c2ecf20Sopenharmony_ci .tx_buf = &st->tx, 1728c2ecf20Sopenharmony_ci .bits_per_word = 8, 1738c2ecf20Sopenharmony_ci .len = sizeof(st->tx), 1748c2ecf20Sopenharmony_ci .cs_change = 1, 1758c2ecf20Sopenharmony_ci }, { 1768c2ecf20Sopenharmony_ci .rx_buf = &st->rx, 1778c2ecf20Sopenharmony_ci .bits_per_word = 8, 1788c2ecf20Sopenharmony_ci .len = sizeof(st->rx), 1798c2ecf20Sopenharmony_ci }, 1808c2ecf20Sopenharmony_ci }; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mutex_lock(&st->buf_lock); 1838c2ecf20Sopenharmony_ci st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); 1868c2ecf20Sopenharmony_ci if (ret) { 1878c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "Problem while reading sensor data\n"); 1888c2ecf20Sopenharmony_ci goto error_ret; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci *val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cierror_ret: 1948c2ecf20Sopenharmony_ci mutex_unlock(&st->buf_lock); 1958c2ecf20Sopenharmony_ci return ret; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * adxrs450_spi_initial() - use for initializing procedure. 2008c2ecf20Sopenharmony_ci * @st: device instance specific data 2018c2ecf20Sopenharmony_ci * @val: somewhere to pass back the value read 2028c2ecf20Sopenharmony_ci * @chk: Whether to perform fault check 2038c2ecf20Sopenharmony_ci **/ 2048c2ecf20Sopenharmony_cistatic int adxrs450_spi_initial(struct adxrs450_state *st, 2058c2ecf20Sopenharmony_ci u32 *val, char chk) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci u32 tx; 2098c2ecf20Sopenharmony_ci struct spi_transfer xfers = { 2108c2ecf20Sopenharmony_ci .tx_buf = &st->tx, 2118c2ecf20Sopenharmony_ci .rx_buf = &st->rx, 2128c2ecf20Sopenharmony_ci .bits_per_word = 8, 2138c2ecf20Sopenharmony_ci .len = sizeof(st->tx), 2148c2ecf20Sopenharmony_ci }; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci mutex_lock(&st->buf_lock); 2178c2ecf20Sopenharmony_ci tx = ADXRS450_SENSOR_DATA; 2188c2ecf20Sopenharmony_ci if (chk) 2198c2ecf20Sopenharmony_ci tx |= (ADXRS450_CHK | ADXRS450_P); 2208c2ecf20Sopenharmony_ci st->tx = cpu_to_be32(tx); 2218c2ecf20Sopenharmony_ci ret = spi_sync_transfer(st->us, &xfers, 1); 2228c2ecf20Sopenharmony_ci if (ret) { 2238c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "Problem while reading initializing data\n"); 2248c2ecf20Sopenharmony_ci goto error_ret; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci *val = be32_to_cpu(st->rx); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cierror_ret: 2308c2ecf20Sopenharmony_ci mutex_unlock(&st->buf_lock); 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* Recommended Startup Sequence by spec */ 2358c2ecf20Sopenharmony_cistatic int adxrs450_initial_setup(struct iio_dev *indio_dev) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci u32 t; 2388c2ecf20Sopenharmony_ci u16 data; 2398c2ecf20Sopenharmony_ci int ret; 2408c2ecf20Sopenharmony_ci struct adxrs450_state *st = iio_priv(indio_dev); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci msleep(ADXRS450_STARTUP_DELAY*2); 2438c2ecf20Sopenharmony_ci ret = adxrs450_spi_initial(st, &t, 1); 2448c2ecf20Sopenharmony_ci if (ret) 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci if (t != 0x01) 2478c2ecf20Sopenharmony_ci dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n"); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci msleep(ADXRS450_STARTUP_DELAY); 2508c2ecf20Sopenharmony_ci ret = adxrs450_spi_initial(st, &t, 0); 2518c2ecf20Sopenharmony_ci if (ret) 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci msleep(ADXRS450_STARTUP_DELAY); 2558c2ecf20Sopenharmony_ci ret = adxrs450_spi_initial(st, &t, 0); 2568c2ecf20Sopenharmony_ci if (ret) 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { 2598c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "The second response is not correct!\n"); 2608c2ecf20Sopenharmony_ci return -EIO; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci ret = adxrs450_spi_initial(st, &t, 0); 2648c2ecf20Sopenharmony_ci if (ret) 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { 2678c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "The third response is not correct!\n"); 2688c2ecf20Sopenharmony_ci return -EIO; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data); 2728c2ecf20Sopenharmony_ci if (ret) 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci if (data & 0x0fff) { 2758c2ecf20Sopenharmony_ci dev_err(&st->us->dev, "The device is not in normal status!\n"); 2768c2ecf20Sopenharmony_ci return -EINVAL; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int adxrs450_write_raw(struct iio_dev *indio_dev, 2838c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2848c2ecf20Sopenharmony_ci int val, 2858c2ecf20Sopenharmony_ci int val2, 2868c2ecf20Sopenharmony_ci long mask) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci int ret; 2898c2ecf20Sopenharmony_ci switch (mask) { 2908c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 2918c2ecf20Sopenharmony_ci if (val < -0x400 || val >= 0x400) 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci ret = adxrs450_spi_write_reg_16(indio_dev, 2948c2ecf20Sopenharmony_ci ADXRS450_DNC1, val); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci default: 2978c2ecf20Sopenharmony_ci ret = -EINVAL; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int adxrs450_read_raw(struct iio_dev *indio_dev, 3048c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3058c2ecf20Sopenharmony_ci int *val, 3068c2ecf20Sopenharmony_ci int *val2, 3078c2ecf20Sopenharmony_ci long mask) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci s16 t; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci switch (mask) { 3138c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3148c2ecf20Sopenharmony_ci switch (chan->type) { 3158c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3168c2ecf20Sopenharmony_ci ret = adxrs450_spi_sensor_data(indio_dev, &t); 3178c2ecf20Sopenharmony_ci if (ret) 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci *val = t; 3208c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case IIO_TEMP: 3238c2ecf20Sopenharmony_ci ret = adxrs450_spi_read_reg_16(indio_dev, 3248c2ecf20Sopenharmony_ci ADXRS450_TEMP1, &t); 3258c2ecf20Sopenharmony_ci if (ret) 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci *val = (t >> 6) + 225; 3288c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci default: 3318c2ecf20Sopenharmony_ci ret = -EINVAL; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3368c2ecf20Sopenharmony_ci switch (chan->type) { 3378c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3388c2ecf20Sopenharmony_ci *val = 0; 3398c2ecf20Sopenharmony_ci *val2 = 218166; 3408c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_NANO; 3418c2ecf20Sopenharmony_ci case IIO_TEMP: 3428c2ecf20Sopenharmony_ci *val = 200; 3438c2ecf20Sopenharmony_ci *val2 = 0; 3448c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3458c2ecf20Sopenharmony_ci default: 3468c2ecf20Sopenharmony_ci return -EINVAL; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: 3498c2ecf20Sopenharmony_ci ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); 3508c2ecf20Sopenharmony_ci if (ret) 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci *val = t; 3538c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 3568c2ecf20Sopenharmony_ci ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t); 3578c2ecf20Sopenharmony_ci if (ret) 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci *val = sign_extend32(t, 9); 3608c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci ret = -EINVAL; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic const struct iio_chan_spec adxrs450_channels[2][2] = { 3718c2ecf20Sopenharmony_ci [ID_ADXRS450] = { 3728c2ecf20Sopenharmony_ci { 3738c2ecf20Sopenharmony_ci .type = IIO_ANGL_VEL, 3748c2ecf20Sopenharmony_ci .modified = 1, 3758c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_Z, 3768c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 3778c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBBIAS) | 3788c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) | 3798c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 3808c2ecf20Sopenharmony_ci }, { 3818c2ecf20Sopenharmony_ci .type = IIO_TEMP, 3828c2ecf20Sopenharmony_ci .indexed = 1, 3838c2ecf20Sopenharmony_ci .channel = 0, 3848c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 3858c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci }, 3888c2ecf20Sopenharmony_ci [ID_ADXRS453] = { 3898c2ecf20Sopenharmony_ci { 3908c2ecf20Sopenharmony_ci .type = IIO_ANGL_VEL, 3918c2ecf20Sopenharmony_ci .modified = 1, 3928c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_Z, 3938c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 3948c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | 3958c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW), 3968c2ecf20Sopenharmony_ci }, { 3978c2ecf20Sopenharmony_ci .type = IIO_TEMP, 3988c2ecf20Sopenharmony_ci .indexed = 1, 3998c2ecf20Sopenharmony_ci .channel = 0, 4008c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 4018c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci }, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic const struct iio_info adxrs450_info = { 4078c2ecf20Sopenharmony_ci .read_raw = &adxrs450_read_raw, 4088c2ecf20Sopenharmony_ci .write_raw = &adxrs450_write_raw, 4098c2ecf20Sopenharmony_ci}; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int adxrs450_probe(struct spi_device *spi) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int ret; 4148c2ecf20Sopenharmony_ci struct adxrs450_state *st; 4158c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* setup the industrialio driver allocated elements */ 4188c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 4198c2ecf20Sopenharmony_ci if (!indio_dev) 4208c2ecf20Sopenharmony_ci return -ENOMEM; 4218c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 4228c2ecf20Sopenharmony_ci st->us = spi; 4238c2ecf20Sopenharmony_ci mutex_init(&st->buf_lock); 4248c2ecf20Sopenharmony_ci /* This is only used for removal purposes */ 4258c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci indio_dev->info = &adxrs450_info; 4288c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 4298c2ecf20Sopenharmony_ci indio_dev->channels = 4308c2ecf20Sopenharmony_ci adxrs450_channels[spi_get_device_id(spi)->driver_data]; 4318c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels); 4328c2ecf20Sopenharmony_ci indio_dev->name = spi->dev.driver->name; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ret = devm_iio_device_register(&spi->dev, indio_dev); 4358c2ecf20Sopenharmony_ci if (ret) 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Get the device into a sane initial state */ 4398c2ecf20Sopenharmony_ci ret = adxrs450_initial_setup(indio_dev); 4408c2ecf20Sopenharmony_ci if (ret) 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const struct spi_device_id adxrs450_id[] = { 4478c2ecf20Sopenharmony_ci {"adxrs450", ID_ADXRS450}, 4488c2ecf20Sopenharmony_ci {"adxrs453", ID_ADXRS453}, 4498c2ecf20Sopenharmony_ci {} 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adxrs450_id); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic struct spi_driver adxrs450_driver = { 4548c2ecf20Sopenharmony_ci .driver = { 4558c2ecf20Sopenharmony_ci .name = "adxrs450", 4568c2ecf20Sopenharmony_ci }, 4578c2ecf20Sopenharmony_ci .probe = adxrs450_probe, 4588c2ecf20Sopenharmony_ci .id_table = adxrs450_id, 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_cimodule_spi_driver(adxrs450_driver); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ciMODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>"); 4638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver"); 4648c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 465