// SPDX-License-Identifier: GPL-2.0-only
/*
* ADIS16480 and similar IMUs driver
*
* Copyright 2012 Analog Devices Inc.
*/
#include <linux/clk.h>
#include <linux/bitfield.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/imu/adis.h>
#include <linux/debugfs.h>
#define ADIS16480_PAGE_SIZE 0x80
#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
#define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06)
#define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08)
#define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A)
#define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C)
#define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E)
#define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10)
#define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14)
#define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18)
#define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C)
#define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20)
#define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24)
#define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28)
#define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A)
#define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C)
#define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E)
#define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40)
#define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44)
#define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48)
#define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C)
#define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50)
#define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54)
#define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E)
#define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04)
#define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06)
#define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08)
#define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A)
#define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C)
#define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E)
#define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10)
#define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14)
#define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18)
#define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C)
#define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20)
#define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24)
#define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28)
#define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A)
#define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C)
#define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40)
#define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C)
#define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02)
#define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06)
#define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08)
#define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A)
#define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C)
#define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10)
#define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16)
#define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18)
#define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20)
#define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22)
#define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24)
#define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28)
#define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A)
#define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C)
#define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E)
#define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30)
#define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32)
#define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34)
#define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36)
#define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38)
#define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A)
#define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78)
#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A)
#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C)
/*
* External clock scaling in PPS mode.
* Available only for ADIS1649x devices
*/
#define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10)
#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
/* Each filter coefficent bank spans two pages */
#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
ADIS16480_REG((page) + 1, (x) - 60 + 8))
#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
#define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x))
#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x))
#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x))
/* ADIS16480_REG_FNCTIO_CTRL */
#define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0)
#define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x)
#define ADIS16480_DRDY_POL_MSK BIT(2)
#define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x)
#define ADIS16480_DRDY_EN_MSK BIT(3)
#define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x)
#define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4)
#define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x)
#define ADIS16480_SYNC_EN_MSK BIT(7)
#define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x)
#define ADIS16480_SYNC_MODE_MSK BIT(8)
#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x)
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int gyro_max_val;
unsigned int gyro_max_scale;
unsigned int accel_max_val;
unsigned int accel_max_scale;
unsigned int temp_scale;
unsigned int int_clk;
unsigned int max_dec_rate;
const unsigned int *filter_freqs;
bool has_pps_clk_mode;
};
enum adis16480_int_pin {