18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADXRS290 SPI Gyroscope Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Nishant Malpani <nish.malpani25@gmail.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2020 Analog Devices, Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 108c2ecf20Sopenharmony_ci#include <linux/bitops.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 188c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 198c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 208c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 218c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ADXRS290_ADI_ID 0xAD 258c2ecf20Sopenharmony_ci#define ADXRS290_MEMS_ID 0x1D 268c2ecf20Sopenharmony_ci#define ADXRS290_DEV_ID 0x92 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define ADXRS290_REG_ADI_ID 0x00 298c2ecf20Sopenharmony_ci#define ADXRS290_REG_MEMS_ID 0x01 308c2ecf20Sopenharmony_ci#define ADXRS290_REG_DEV_ID 0x02 318c2ecf20Sopenharmony_ci#define ADXRS290_REG_REV_ID 0x03 328c2ecf20Sopenharmony_ci#define ADXRS290_REG_SN0 0x04 /* Serial Number Registers, 4 bytes */ 338c2ecf20Sopenharmony_ci#define ADXRS290_REG_DATAX0 0x08 /* Roll Rate o/p Data Regs, 2 bytes */ 348c2ecf20Sopenharmony_ci#define ADXRS290_REG_DATAY0 0x0A /* Pitch Rate o/p Data Regs, 2 bytes */ 358c2ecf20Sopenharmony_ci#define ADXRS290_REG_TEMP0 0x0C 368c2ecf20Sopenharmony_ci#define ADXRS290_REG_POWER_CTL 0x10 378c2ecf20Sopenharmony_ci#define ADXRS290_REG_FILTER 0x11 388c2ecf20Sopenharmony_ci#define ADXRS290_REG_DATA_RDY 0x12 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define ADXRS290_READ BIT(7) 418c2ecf20Sopenharmony_ci#define ADXRS290_TSM BIT(0) 428c2ecf20Sopenharmony_ci#define ADXRS290_MEASUREMENT BIT(1) 438c2ecf20Sopenharmony_ci#define ADXRS290_DATA_RDY_OUT BIT(0) 448c2ecf20Sopenharmony_ci#define ADXRS290_SYNC_MASK GENMASK(1, 0) 458c2ecf20Sopenharmony_ci#define ADXRS290_SYNC(x) FIELD_PREP(ADXRS290_SYNC_MASK, x) 468c2ecf20Sopenharmony_ci#define ADXRS290_LPF_MASK GENMASK(2, 0) 478c2ecf20Sopenharmony_ci#define ADXRS290_LPF(x) FIELD_PREP(ADXRS290_LPF_MASK, x) 488c2ecf20Sopenharmony_ci#define ADXRS290_HPF_MASK GENMASK(7, 4) 498c2ecf20Sopenharmony_ci#define ADXRS290_HPF(x) FIELD_PREP(ADXRS290_HPF_MASK, x) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define ADXRS290_READ_REG(reg) (ADXRS290_READ | (reg)) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define ADXRS290_MAX_TRANSITION_TIME_MS 100 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cienum adxrs290_mode { 568c2ecf20Sopenharmony_ci ADXRS290_MODE_STANDBY, 578c2ecf20Sopenharmony_ci ADXRS290_MODE_MEASUREMENT, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cienum adxrs290_scan_index { 618c2ecf20Sopenharmony_ci ADXRS290_IDX_X, 628c2ecf20Sopenharmony_ci ADXRS290_IDX_Y, 638c2ecf20Sopenharmony_ci ADXRS290_IDX_TEMP, 648c2ecf20Sopenharmony_ci ADXRS290_IDX_TS, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistruct adxrs290_state { 688c2ecf20Sopenharmony_ci struct spi_device *spi; 698c2ecf20Sopenharmony_ci /* Serialize reads and their subsequent processing */ 708c2ecf20Sopenharmony_ci struct mutex lock; 718c2ecf20Sopenharmony_ci enum adxrs290_mode mode; 728c2ecf20Sopenharmony_ci unsigned int lpf_3db_freq_idx; 738c2ecf20Sopenharmony_ci unsigned int hpf_3db_freq_idx; 748c2ecf20Sopenharmony_ci struct iio_trigger *dready_trig; 758c2ecf20Sopenharmony_ci /* Ensure correct alignment of timestamp when present */ 768c2ecf20Sopenharmony_ci struct { 778c2ecf20Sopenharmony_ci s16 channels[3]; 788c2ecf20Sopenharmony_ci s64 ts __aligned(8); 798c2ecf20Sopenharmony_ci } buffer; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * Available cut-off frequencies of the low pass filter in Hz. 848c2ecf20Sopenharmony_ci * The integer part and fractional part are represented separately. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic const int adxrs290_lpf_3db_freq_hz_table[][2] = { 878c2ecf20Sopenharmony_ci [0] = {480, 0}, 888c2ecf20Sopenharmony_ci [1] = {320, 0}, 898c2ecf20Sopenharmony_ci [2] = {160, 0}, 908c2ecf20Sopenharmony_ci [3] = {80, 0}, 918c2ecf20Sopenharmony_ci [4] = {56, 600000}, 928c2ecf20Sopenharmony_ci [5] = {40, 0}, 938c2ecf20Sopenharmony_ci [6] = {28, 300000}, 948c2ecf20Sopenharmony_ci [7] = {20, 0}, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Available cut-off frequencies of the high pass filter in Hz. 998c2ecf20Sopenharmony_ci * The integer part and fractional part are represented separately. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic const int adxrs290_hpf_3db_freq_hz_table[][2] = { 1028c2ecf20Sopenharmony_ci [0] = {0, 0}, 1038c2ecf20Sopenharmony_ci [1] = {0, 11000}, 1048c2ecf20Sopenharmony_ci [2] = {0, 22000}, 1058c2ecf20Sopenharmony_ci [3] = {0, 44000}, 1068c2ecf20Sopenharmony_ci [4] = {0, 87000}, 1078c2ecf20Sopenharmony_ci [5] = {0, 175000}, 1088c2ecf20Sopenharmony_ci [6] = {0, 350000}, 1098c2ecf20Sopenharmony_ci [7] = {0, 700000}, 1108c2ecf20Sopenharmony_ci [8] = {1, 400000}, 1118c2ecf20Sopenharmony_ci [9] = {2, 800000}, 1128c2ecf20Sopenharmony_ci [10] = {11, 300000}, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 1188c2ecf20Sopenharmony_ci int ret = 0; 1198c2ecf20Sopenharmony_ci int temp; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1228c2ecf20Sopenharmony_ci temp = spi_w8r16(st->spi, cmd); 1238c2ecf20Sopenharmony_ci if (temp < 0) { 1248c2ecf20Sopenharmony_ci ret = temp; 1258c2ecf20Sopenharmony_ci goto err_unlock; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci *val = sign_extend32(temp, 15); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cierr_unlock: 1318c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1328c2ecf20Sopenharmony_ci return ret; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0); 1388c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 1398c2ecf20Sopenharmony_ci int ret = 0; 1408c2ecf20Sopenharmony_ci int temp; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1438c2ecf20Sopenharmony_ci temp = spi_w8r16(st->spi, cmd); 1448c2ecf20Sopenharmony_ci if (temp < 0) { 1458c2ecf20Sopenharmony_ci ret = temp; 1468c2ecf20Sopenharmony_ci goto err_unlock; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* extract lower 12 bits temperature reading */ 1508c2ecf20Sopenharmony_ci *val = sign_extend32(temp, 11); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cierr_unlock: 1538c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER); 1608c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 1618c2ecf20Sopenharmony_ci int ret = 0; 1628c2ecf20Sopenharmony_ci short temp; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1658c2ecf20Sopenharmony_ci temp = spi_w8r8(st->spi, cmd); 1668c2ecf20Sopenharmony_ci if (temp < 0) { 1678c2ecf20Sopenharmony_ci ret = temp; 1688c2ecf20Sopenharmony_ci goto err_unlock; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci *val = FIELD_GET(ADXRS290_LPF_MASK, temp); 1728c2ecf20Sopenharmony_ci *val2 = FIELD_GET(ADXRS290_HPF_MASK, temp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cierr_unlock: 1758c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg, 1808c2ecf20Sopenharmony_ci const u8 val) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u8 buf[2]; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci buf[0] = reg; 1858c2ecf20Sopenharmony_ci buf[1] = val; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return spi_write_then_read(spi, buf, ARRAY_SIZE(buf), NULL, 0); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int adxrs290_find_match(const int (*freq_tbl)[2], const int n, 1918c2ecf20Sopenharmony_ci const int val, const int val2) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int i; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 1968c2ecf20Sopenharmony_ci if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2) 1978c2ecf20Sopenharmony_ci return i; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return -EINVAL; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int adxrs290_set_filter_freq(struct iio_dev *indio_dev, 2048c2ecf20Sopenharmony_ci const unsigned int lpf_idx, 2058c2ecf20Sopenharmony_ci const unsigned int hpf_idx) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 2088c2ecf20Sopenharmony_ci u8 val; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci val = ADXRS290_HPF(hpf_idx) | ADXRS290_LPF(lpf_idx); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return adxrs290_spi_write_reg(st->spi, ADXRS290_REG_FILTER, val); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int adxrs290_set_mode(struct iio_dev *indio_dev, enum adxrs290_mode mode) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 2188c2ecf20Sopenharmony_ci int val, ret; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (st->mode == mode) 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = spi_w8r8(st->spi, ADXRS290_READ_REG(ADXRS290_REG_POWER_CTL)); 2268c2ecf20Sopenharmony_ci if (ret < 0) 2278c2ecf20Sopenharmony_ci goto out_unlock; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci val = ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci switch (mode) { 2328c2ecf20Sopenharmony_ci case ADXRS290_MODE_STANDBY: 2338c2ecf20Sopenharmony_ci val &= ~ADXRS290_MEASUREMENT; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case ADXRS290_MODE_MEASUREMENT: 2368c2ecf20Sopenharmony_ci val |= ADXRS290_MEASUREMENT; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci default: 2398c2ecf20Sopenharmony_ci ret = -EINVAL; 2408c2ecf20Sopenharmony_ci goto out_unlock; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_POWER_CTL, val); 2448c2ecf20Sopenharmony_ci if (ret < 0) { 2458c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, "unable to set mode: %d\n", ret); 2468c2ecf20Sopenharmony_ci goto out_unlock; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* update cached mode */ 2508c2ecf20Sopenharmony_ci st->mode = mode; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciout_unlock: 2538c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void adxrs290_chip_off_action(void *data) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = data; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci adxrs290_set_mode(indio_dev, ADXRS290_MODE_STANDBY); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int adxrs290_initial_setup(struct iio_dev *indio_dev) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 2678c2ecf20Sopenharmony_ci struct spi_device *spi = st->spi; 2688c2ecf20Sopenharmony_ci int ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = adxrs290_spi_write_reg(spi, ADXRS290_REG_POWER_CTL, 2718c2ecf20Sopenharmony_ci ADXRS290_MEASUREMENT | ADXRS290_TSM); 2728c2ecf20Sopenharmony_ci if (ret < 0) 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci st->mode = ADXRS290_MODE_MEASUREMENT; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return devm_add_action_or_reset(&spi->dev, adxrs290_chip_off_action, 2788c2ecf20Sopenharmony_ci indio_dev); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int adxrs290_read_raw(struct iio_dev *indio_dev, 2828c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 2838c2ecf20Sopenharmony_ci int *val, 2848c2ecf20Sopenharmony_ci int *val2, 2858c2ecf20Sopenharmony_ci long mask) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 2888c2ecf20Sopenharmony_ci unsigned int t; 2898c2ecf20Sopenharmony_ci int ret; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (mask) { 2928c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2938c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 2948c2ecf20Sopenharmony_ci if (ret) 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci switch (chan->type) { 2988c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 2998c2ecf20Sopenharmony_ci ret = adxrs290_get_rate_data(indio_dev, 3008c2ecf20Sopenharmony_ci ADXRS290_READ_REG(chan->address), 3018c2ecf20Sopenharmony_ci val); 3028c2ecf20Sopenharmony_ci if (ret < 0) 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case IIO_TEMP: 3088c2ecf20Sopenharmony_ci ret = adxrs290_get_temp_data(indio_dev, val); 3098c2ecf20Sopenharmony_ci if (ret < 0) 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ret = IIO_VAL_INT; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci default: 3158c2ecf20Sopenharmony_ci ret = -EINVAL; 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 3208c2ecf20Sopenharmony_ci return ret; 3218c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3228c2ecf20Sopenharmony_ci switch (chan->type) { 3238c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3248c2ecf20Sopenharmony_ci /* 1 LSB = 0.005 degrees/sec */ 3258c2ecf20Sopenharmony_ci *val = 0; 3268c2ecf20Sopenharmony_ci *val2 = 87266; 3278c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_NANO; 3288c2ecf20Sopenharmony_ci case IIO_TEMP: 3298c2ecf20Sopenharmony_ci /* 1 LSB = 0.1 degrees Celsius */ 3308c2ecf20Sopenharmony_ci *val = 100; 3318c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3328c2ecf20Sopenharmony_ci default: 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 3368c2ecf20Sopenharmony_ci switch (chan->type) { 3378c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3388c2ecf20Sopenharmony_ci t = st->lpf_3db_freq_idx; 3398c2ecf20Sopenharmony_ci *val = adxrs290_lpf_3db_freq_hz_table[t][0]; 3408c2ecf20Sopenharmony_ci *val2 = adxrs290_lpf_3db_freq_hz_table[t][1]; 3418c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 3468c2ecf20Sopenharmony_ci switch (chan->type) { 3478c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3488c2ecf20Sopenharmony_ci t = st->hpf_3db_freq_idx; 3498c2ecf20Sopenharmony_ci *val = adxrs290_hpf_3db_freq_hz_table[t][0]; 3508c2ecf20Sopenharmony_ci *val2 = adxrs290_hpf_3db_freq_hz_table[t][1]; 3518c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3528c2ecf20Sopenharmony_ci default: 3538c2ecf20Sopenharmony_ci return -EINVAL; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int adxrs290_write_raw(struct iio_dev *indio_dev, 3618c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3628c2ecf20Sopenharmony_ci int val, 3638c2ecf20Sopenharmony_ci int val2, 3648c2ecf20Sopenharmony_ci long mask) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 3678c2ecf20Sopenharmony_ci int ret, lpf_idx, hpf_idx; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 3708c2ecf20Sopenharmony_ci if (ret) 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci switch (mask) { 3748c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 3758c2ecf20Sopenharmony_ci lpf_idx = adxrs290_find_match(adxrs290_lpf_3db_freq_hz_table, 3768c2ecf20Sopenharmony_ci ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table), 3778c2ecf20Sopenharmony_ci val, val2); 3788c2ecf20Sopenharmony_ci if (lpf_idx < 0) { 3798c2ecf20Sopenharmony_ci ret = -EINVAL; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* caching the updated state of the low-pass filter */ 3848c2ecf20Sopenharmony_ci st->lpf_3db_freq_idx = lpf_idx; 3858c2ecf20Sopenharmony_ci /* retrieving the current state of the high-pass filter */ 3868c2ecf20Sopenharmony_ci hpf_idx = st->hpf_3db_freq_idx; 3878c2ecf20Sopenharmony_ci ret = adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 3918c2ecf20Sopenharmony_ci hpf_idx = adxrs290_find_match(adxrs290_hpf_3db_freq_hz_table, 3928c2ecf20Sopenharmony_ci ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table), 3938c2ecf20Sopenharmony_ci val, val2); 3948c2ecf20Sopenharmony_ci if (hpf_idx < 0) { 3958c2ecf20Sopenharmony_ci ret = -EINVAL; 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* caching the updated state of the high-pass filter */ 4008c2ecf20Sopenharmony_ci st->hpf_3db_freq_idx = hpf_idx; 4018c2ecf20Sopenharmony_ci /* retrieving the current state of the low-pass filter */ 4028c2ecf20Sopenharmony_ci lpf_idx = st->lpf_3db_freq_idx; 4038c2ecf20Sopenharmony_ci ret = adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci default: 4078c2ecf20Sopenharmony_ci ret = -EINVAL; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 4128c2ecf20Sopenharmony_ci return ret; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int adxrs290_read_avail(struct iio_dev *indio_dev, 4168c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 4178c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 4188c2ecf20Sopenharmony_ci long mask) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci switch (mask) { 4218c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 4228c2ecf20Sopenharmony_ci *vals = (const int *)adxrs290_lpf_3db_freq_hz_table; 4238c2ecf20Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 4248c2ecf20Sopenharmony_ci /* Values are stored in a 2D matrix */ 4258c2ecf20Sopenharmony_ci *length = ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table) * 2; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return IIO_AVAIL_LIST; 4288c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: 4298c2ecf20Sopenharmony_ci *vals = (const int *)adxrs290_hpf_3db_freq_hz_table; 4308c2ecf20Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 4318c2ecf20Sopenharmony_ci /* Values are stored in a 2D matrix */ 4328c2ecf20Sopenharmony_ci *length = ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table) * 2; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return IIO_AVAIL_LIST; 4358c2ecf20Sopenharmony_ci default: 4368c2ecf20Sopenharmony_ci return -EINVAL; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int adxrs290_reg_access_rw(struct spi_device *spi, unsigned int reg, 4418c2ecf20Sopenharmony_ci unsigned int *readval) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci int ret; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ret = spi_w8r8(spi, ADXRS290_READ_REG(reg)); 4468c2ecf20Sopenharmony_ci if (ret < 0) 4478c2ecf20Sopenharmony_ci return ret; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci *readval = ret; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int adxrs290_reg_access(struct iio_dev *indio_dev, unsigned int reg, 4558c2ecf20Sopenharmony_ci unsigned int writeval, unsigned int *readval) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (readval) 4608c2ecf20Sopenharmony_ci return adxrs290_reg_access_rw(st->spi, reg, readval); 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci return adxrs290_spi_write_reg(st->spi, reg, writeval); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int adxrs290_data_rdy_trigger_set_state(struct iio_trigger *trig, 4668c2ecf20Sopenharmony_ci bool state) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 4698c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci u8 val; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci val = state ? ADXRS290_SYNC(ADXRS290_DATA_RDY_OUT) : 0; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_DATA_RDY, val); 4768c2ecf20Sopenharmony_ci if (ret < 0) 4778c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, "failed to start data rdy interrupt\n"); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int adxrs290_reset_trig(struct iio_trigger *trig) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 4858c2ecf20Sopenharmony_ci int val; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * Data ready interrupt is reset after a read of the data registers. 4898c2ecf20Sopenharmony_ci * Here, we only read the 16b DATAY registers as that marks the end of 4908c2ecf20Sopenharmony_ci * a read of the data registers and initiates a reset for the interrupt 4918c2ecf20Sopenharmony_ci * line. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci adxrs290_get_rate_data(indio_dev, 4948c2ecf20Sopenharmony_ci ADXRS290_READ_REG(ADXRS290_REG_DATAY0), &val); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return 0; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic const struct iio_trigger_ops adxrs290_trigger_ops = { 5008c2ecf20Sopenharmony_ci .set_trigger_state = &adxrs290_data_rdy_trigger_set_state, 5018c2ecf20Sopenharmony_ci .validate_device = &iio_trigger_validate_own_device, 5028c2ecf20Sopenharmony_ci .try_reenable = &adxrs290_reset_trig, 5038c2ecf20Sopenharmony_ci}; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic irqreturn_t adxrs290_trigger_handler(int irq, void *p) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct iio_poll_func *pf = p; 5088c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 5098c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 5108c2ecf20Sopenharmony_ci u8 tx = ADXRS290_READ_REG(ADXRS290_REG_DATAX0); 5118c2ecf20Sopenharmony_ci int ret; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* exercise a bulk data capture starting from reg DATAX0... */ 5168c2ecf20Sopenharmony_ci ret = spi_write_then_read(st->spi, &tx, sizeof(tx), st->buffer.channels, 5178c2ecf20Sopenharmony_ci sizeof(st->buffer.channels)); 5188c2ecf20Sopenharmony_ci if (ret < 0) 5198c2ecf20Sopenharmony_ci goto out_unlock_notify; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, 5228c2ecf20Sopenharmony_ci pf->timestamp); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciout_unlock_notify: 5258c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 5268c2ecf20Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci#define ADXRS290_ANGL_VEL_CHANNEL(reg, axis) { \ 5328c2ecf20Sopenharmony_ci .type = IIO_ANGL_VEL, \ 5338c2ecf20Sopenharmony_ci .address = reg, \ 5348c2ecf20Sopenharmony_ci .modified = 1, \ 5358c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_##axis, \ 5368c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 5378c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 5388c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ 5398c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 5408c2ecf20Sopenharmony_ci .info_mask_shared_by_type_available = \ 5418c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ 5428c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 5438c2ecf20Sopenharmony_ci .scan_index = ADXRS290_IDX_##axis, \ 5448c2ecf20Sopenharmony_ci .scan_type = { \ 5458c2ecf20Sopenharmony_ci .sign = 's', \ 5468c2ecf20Sopenharmony_ci .realbits = 16, \ 5478c2ecf20Sopenharmony_ci .storagebits = 16, \ 5488c2ecf20Sopenharmony_ci .endianness = IIO_LE, \ 5498c2ecf20Sopenharmony_ci }, \ 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic const struct iio_chan_spec adxrs290_channels[] = { 5538c2ecf20Sopenharmony_ci ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAX0, X), 5548c2ecf20Sopenharmony_ci ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAY0, Y), 5558c2ecf20Sopenharmony_ci { 5568c2ecf20Sopenharmony_ci .type = IIO_TEMP, 5578c2ecf20Sopenharmony_ci .address = ADXRS290_REG_TEMP0, 5588c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 5598c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 5608c2ecf20Sopenharmony_ci .scan_index = ADXRS290_IDX_TEMP, 5618c2ecf20Sopenharmony_ci .scan_type = { 5628c2ecf20Sopenharmony_ci .sign = 's', 5638c2ecf20Sopenharmony_ci .realbits = 12, 5648c2ecf20Sopenharmony_ci .storagebits = 16, 5658c2ecf20Sopenharmony_ci .endianness = IIO_LE, 5668c2ecf20Sopenharmony_ci }, 5678c2ecf20Sopenharmony_ci }, 5688c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(ADXRS290_IDX_TS), 5698c2ecf20Sopenharmony_ci}; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic const unsigned long adxrs290_avail_scan_masks[] = { 5728c2ecf20Sopenharmony_ci BIT(ADXRS290_IDX_X) | BIT(ADXRS290_IDX_Y) | BIT(ADXRS290_IDX_TEMP), 5738c2ecf20Sopenharmony_ci 0 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic const struct iio_info adxrs290_info = { 5778c2ecf20Sopenharmony_ci .read_raw = &adxrs290_read_raw, 5788c2ecf20Sopenharmony_ci .write_raw = &adxrs290_write_raw, 5798c2ecf20Sopenharmony_ci .read_avail = &adxrs290_read_avail, 5808c2ecf20Sopenharmony_ci .debugfs_reg_access = &adxrs290_reg_access, 5818c2ecf20Sopenharmony_ci}; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int adxrs290_probe_trigger(struct iio_dev *indio_dev) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct adxrs290_state *st = iio_priv(indio_dev); 5868c2ecf20Sopenharmony_ci int ret; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (!st->spi->irq) { 5898c2ecf20Sopenharmony_ci dev_info(&st->spi->dev, "no irq, using polling\n"); 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci st->dready_trig = devm_iio_trigger_alloc(&st->spi->dev, "%s-dev%d", 5948c2ecf20Sopenharmony_ci indio_dev->name, 5958c2ecf20Sopenharmony_ci indio_dev->id); 5968c2ecf20Sopenharmony_ci if (!st->dready_trig) 5978c2ecf20Sopenharmony_ci return -ENOMEM; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci st->dready_trig->dev.parent = &st->spi->dev; 6008c2ecf20Sopenharmony_ci st->dready_trig->ops = &adxrs290_trigger_ops; 6018c2ecf20Sopenharmony_ci iio_trigger_set_drvdata(st->dready_trig, indio_dev); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ret = devm_request_irq(&st->spi->dev, st->spi->irq, 6048c2ecf20Sopenharmony_ci &iio_trigger_generic_data_rdy_poll, 6058c2ecf20Sopenharmony_ci IRQF_ONESHOT, "adxrs290_irq", st->dready_trig); 6068c2ecf20Sopenharmony_ci if (ret < 0) 6078c2ecf20Sopenharmony_ci return dev_err_probe(&st->spi->dev, ret, 6088c2ecf20Sopenharmony_ci "request irq %d failed\n", st->spi->irq); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ret = devm_iio_trigger_register(&st->spi->dev, st->dready_trig); 6118c2ecf20Sopenharmony_ci if (ret) { 6128c2ecf20Sopenharmony_ci dev_err(&st->spi->dev, "iio trigger register failed\n"); 6138c2ecf20Sopenharmony_ci return ret; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci indio_dev->trig = iio_trigger_get(st->dready_trig); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int adxrs290_probe(struct spi_device *spi) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 6248c2ecf20Sopenharmony_ci struct adxrs290_state *st; 6258c2ecf20Sopenharmony_ci u8 val, val2; 6268c2ecf20Sopenharmony_ci int ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 6298c2ecf20Sopenharmony_ci if (!indio_dev) 6308c2ecf20Sopenharmony_ci return -ENOMEM; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci st = iio_priv(indio_dev); 6338c2ecf20Sopenharmony_ci st->spi = spi; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci indio_dev->name = "adxrs290"; 6368c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 6378c2ecf20Sopenharmony_ci indio_dev->channels = adxrs290_channels; 6388c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(adxrs290_channels); 6398c2ecf20Sopenharmony_ci indio_dev->info = &adxrs290_info; 6408c2ecf20Sopenharmony_ci indio_dev->available_scan_masks = adxrs290_avail_scan_masks; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci mutex_init(&st->lock); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_ADI_ID)); 6458c2ecf20Sopenharmony_ci if (val != ADXRS290_ADI_ID) { 6468c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Wrong ADI ID 0x%02x\n", val); 6478c2ecf20Sopenharmony_ci return -ENODEV; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_MEMS_ID)); 6518c2ecf20Sopenharmony_ci if (val != ADXRS290_MEMS_ID) { 6528c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Wrong MEMS ID 0x%02x\n", val); 6538c2ecf20Sopenharmony_ci return -ENODEV; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_DEV_ID)); 6578c2ecf20Sopenharmony_ci if (val != ADXRS290_DEV_ID) { 6588c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Wrong DEV ID 0x%02x\n", val); 6598c2ecf20Sopenharmony_ci return -ENODEV; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* default mode the gyroscope starts in */ 6638c2ecf20Sopenharmony_ci st->mode = ADXRS290_MODE_STANDBY; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* switch to measurement mode and switch on the temperature sensor */ 6668c2ecf20Sopenharmony_ci ret = adxrs290_initial_setup(indio_dev); 6678c2ecf20Sopenharmony_ci if (ret < 0) 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* max transition time to measurement mode */ 6718c2ecf20Sopenharmony_ci msleep(ADXRS290_MAX_TRANSITION_TIME_MS); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci ret = adxrs290_get_3db_freq(indio_dev, &val, &val2); 6748c2ecf20Sopenharmony_ci if (ret < 0) 6758c2ecf20Sopenharmony_ci return ret; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci st->lpf_3db_freq_idx = val; 6788c2ecf20Sopenharmony_ci st->hpf_3db_freq_idx = val2; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, 6818c2ecf20Sopenharmony_ci &iio_pollfunc_store_time, 6828c2ecf20Sopenharmony_ci &adxrs290_trigger_handler, NULL); 6838c2ecf20Sopenharmony_ci if (ret < 0) 6848c2ecf20Sopenharmony_ci return dev_err_probe(&spi->dev, ret, 6858c2ecf20Sopenharmony_ci "iio triggered buffer setup failed\n"); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci ret = adxrs290_probe_trigger(indio_dev); 6888c2ecf20Sopenharmony_ci if (ret < 0) 6898c2ecf20Sopenharmony_ci return ret; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return devm_iio_device_register(&spi->dev, indio_dev); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic const struct of_device_id adxrs290_of_match[] = { 6958c2ecf20Sopenharmony_ci { .compatible = "adi,adxrs290" }, 6968c2ecf20Sopenharmony_ci { } 6978c2ecf20Sopenharmony_ci}; 6988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adxrs290_of_match); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic struct spi_driver adxrs290_driver = { 7018c2ecf20Sopenharmony_ci .driver = { 7028c2ecf20Sopenharmony_ci .name = "adxrs290", 7038c2ecf20Sopenharmony_ci .of_match_table = adxrs290_of_match, 7048c2ecf20Sopenharmony_ci }, 7058c2ecf20Sopenharmony_ci .probe = adxrs290_probe, 7068c2ecf20Sopenharmony_ci}; 7078c2ecf20Sopenharmony_cimodule_spi_driver(adxrs290_driver); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nishant Malpani <nish.malpani25@gmail.com>"); 7108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADXRS290 Gyroscope SPI driver"); 7118c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 712