1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25447e3f1SAlexandru Ardelean /* 35447e3f1SAlexandru Ardelean * adis16400.c support Analog Devices ADIS16400/5 45447e3f1SAlexandru Ardelean * 3d 2g Linear Accelerometers, 55447e3f1SAlexandru Ardelean * 3d Gyroscopes, 65447e3f1SAlexandru Ardelean * 3d Magnetometers via SPI 75447e3f1SAlexandru Ardelean * 85447e3f1SAlexandru Ardelean * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> 95447e3f1SAlexandru Ardelean * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> 105447e3f1SAlexandru Ardelean * Copyright (c) 2011 Analog Devices Inc. 115447e3f1SAlexandru Ardelean */ 125447e3f1SAlexandru Ardelean 135447e3f1SAlexandru Ardelean #include <linux/interrupt.h> 145447e3f1SAlexandru Ardelean #include <linux/irq.h> 155447e3f1SAlexandru Ardelean #include <linux/delay.h> 165447e3f1SAlexandru Ardelean #include <linux/mutex.h> 175447e3f1SAlexandru Ardelean #include <linux/device.h> 185447e3f1SAlexandru Ardelean #include <linux/kernel.h> 195447e3f1SAlexandru Ardelean #include <linux/spi/spi.h> 205447e3f1SAlexandru Ardelean #include <linux/slab.h> 215447e3f1SAlexandru Ardelean #include <linux/sysfs.h> 225447e3f1SAlexandru Ardelean #include <linux/list.h> 235447e3f1SAlexandru Ardelean #include <linux/module.h> 245447e3f1SAlexandru Ardelean #include <linux/debugfs.h> 255447e3f1SAlexandru Ardelean #include <linux/bitops.h> 265447e3f1SAlexandru Ardelean 275447e3f1SAlexandru Ardelean #include <linux/iio/iio.h> 285447e3f1SAlexandru Ardelean #include <linux/iio/sysfs.h> 295447e3f1SAlexandru Ardelean #include <linux/iio/buffer.h> 305447e3f1SAlexandru Ardelean #include <linux/iio/trigger_consumer.h> 313cb51613SAlexandru Ardelean #include <linux/iio/imu/adis.h> 325447e3f1SAlexandru Ardelean 333cb51613SAlexandru Ardelean #define ADIS16400_STARTUP_DELAY 290 /* ms */ 343cb51613SAlexandru Ardelean #define ADIS16400_MTEST_DELAY 90 /* ms */ 353cb51613SAlexandru Ardelean 363cb51613SAlexandru Ardelean #define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ 373cb51613SAlexandru Ardelean #define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ 383cb51613SAlexandru Ardelean #define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ 393cb51613SAlexandru Ardelean #define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ 403cb51613SAlexandru Ardelean #define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ 413cb51613SAlexandru Ardelean #define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ 423cb51613SAlexandru Ardelean #define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ 433cb51613SAlexandru Ardelean #define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ 443cb51613SAlexandru Ardelean #define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ 453cb51613SAlexandru Ardelean #define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ 463cb51613SAlexandru Ardelean #define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ 473cb51613SAlexandru Ardelean #define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ 483cb51613SAlexandru Ardelean #define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ 493cb51613SAlexandru Ardelean 503cb51613SAlexandru Ardelean #define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ 513cb51613SAlexandru Ardelean #define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ 523cb51613SAlexandru Ardelean #define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ 533cb51613SAlexandru Ardelean 543cb51613SAlexandru Ardelean #define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ 553cb51613SAlexandru Ardelean #define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ 563cb51613SAlexandru Ardelean #define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ 573cb51613SAlexandru Ardelean 583cb51613SAlexandru Ardelean #define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */ 593cb51613SAlexandru Ardelean #define ADIS16448_TEMP_OUT 0x18 /* Temperature output */ 603cb51613SAlexandru Ardelean 613cb51613SAlexandru Ardelean /* Calibration parameters */ 623cb51613SAlexandru Ardelean #define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ 633cb51613SAlexandru Ardelean #define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ 643cb51613SAlexandru Ardelean #define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ 653cb51613SAlexandru Ardelean #define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ 663cb51613SAlexandru Ardelean #define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ 673cb51613SAlexandru Ardelean #define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ 683cb51613SAlexandru Ardelean #define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ 693cb51613SAlexandru Ardelean #define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ 703cb51613SAlexandru Ardelean #define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ 713cb51613SAlexandru Ardelean #define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ 723cb51613SAlexandru Ardelean #define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ 733cb51613SAlexandru Ardelean #define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ 743cb51613SAlexandru Ardelean 753cb51613SAlexandru Ardelean #define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ 763cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ 773cb51613SAlexandru Ardelean #define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ 783cb51613SAlexandru Ardelean #define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ 793cb51613SAlexandru Ardelean #define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ 803cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT 0x3C /* System status */ 813cb51613SAlexandru Ardelean 823cb51613SAlexandru Ardelean /* Alarm functions */ 833cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD 0x3E /* System command */ 843cb51613SAlexandru Ardelean #define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ 853cb51613SAlexandru Ardelean #define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ 863cb51613SAlexandru Ardelean #define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ 873cb51613SAlexandru Ardelean #define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ 883cb51613SAlexandru Ardelean #define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ 893cb51613SAlexandru Ardelean #define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ 903cb51613SAlexandru Ardelean 913cb51613SAlexandru Ardelean #define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */ 923cb51613SAlexandru Ardelean #define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */ 933cb51613SAlexandru Ardelean #define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ 943cb51613SAlexandru Ardelean #define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */ 953cb51613SAlexandru Ardelean 963cb51613SAlexandru Ardelean #define ADIS16400_ERROR_ACTIVE (1<<14) 973cb51613SAlexandru Ardelean #define ADIS16400_NEW_DATA (1<<14) 983cb51613SAlexandru Ardelean 993cb51613SAlexandru Ardelean /* MSC_CTRL */ 1003cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) 1013cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) 1023cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) 1033cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) 1043cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) 1053cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) 1063cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) 1073cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) 1083cb51613SAlexandru Ardelean #define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) 1093cb51613SAlexandru Ardelean 1103cb51613SAlexandru Ardelean /* SMPL_PRD */ 1113cb51613SAlexandru Ardelean #define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) 1123cb51613SAlexandru Ardelean #define ADIS16400_SMPL_PRD_DIV_MASK 0x7F 1133cb51613SAlexandru Ardelean 1143cb51613SAlexandru Ardelean /* DIAG_STAT */ 1153cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 1163cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_YACCL_FAIL 14 1173cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_XACCL_FAIL 13 1183cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 1193cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 1203cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 1213cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_ALARM2 9 1223cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_ALARM1 8 1233cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_FLASH_CHK 6 1243cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_SELF_TEST 5 1253cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_OVERFLOW 4 1263cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_SPI_FAIL 3 1273cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_FLASH_UPT 2 1283cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_POWER_HIGH 1 1293cb51613SAlexandru Ardelean #define ADIS16400_DIAG_STAT_POWER_LOW 0 1303cb51613SAlexandru Ardelean 1313cb51613SAlexandru Ardelean /* GLOB_CMD */ 1323cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_SW_RESET (1<<7) 1333cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) 1343cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) 1353cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) 1363cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) 1373cb51613SAlexandru Ardelean #define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) 1383cb51613SAlexandru Ardelean 1393cb51613SAlexandru Ardelean /* SLP_CNT */ 1403cb51613SAlexandru Ardelean #define ADIS16400_SLP_CNT_POWER_OFF (1<<8) 1413cb51613SAlexandru Ardelean 1423cb51613SAlexandru Ardelean #define ADIS16334_RATE_DIV_SHIFT 8 1433cb51613SAlexandru Ardelean #define ADIS16334_RATE_INT_CLK BIT(0) 1443cb51613SAlexandru Ardelean 1453cb51613SAlexandru Ardelean #define ADIS16400_SPI_SLOW (u32)(300 * 1000) 1463cb51613SAlexandru Ardelean #define ADIS16400_SPI_BURST (u32)(1000 * 1000) 1473cb51613SAlexandru Ardelean #define ADIS16400_SPI_FAST (u32)(2000 * 1000) 1483cb51613SAlexandru Ardelean 1493cb51613SAlexandru Ardelean #define ADIS16400_HAS_PROD_ID BIT(0) 1503cb51613SAlexandru Ardelean #define ADIS16400_NO_BURST BIT(1) 1513cb51613SAlexandru Ardelean #define ADIS16400_HAS_SLOW_MODE BIT(2) 1523cb51613SAlexandru Ardelean #define ADIS16400_HAS_SERIAL_NUMBER BIT(3) 1533cb51613SAlexandru Ardelean #define ADIS16400_BURST_DIAG_STAT BIT(4) 1543cb51613SAlexandru Ardelean 1553cb51613SAlexandru Ardelean struct adis16400_state; 1563cb51613SAlexandru Ardelean 1573cb51613SAlexandru Ardelean struct adis16400_chip_info { 1583cb51613SAlexandru Ardelean const struct iio_chan_spec *channels; 1593cb51613SAlexandru Ardelean const int num_channels; 1603cb51613SAlexandru Ardelean const long flags; 1613cb51613SAlexandru Ardelean unsigned int gyro_scale_micro; 1623cb51613SAlexandru Ardelean unsigned int accel_scale_micro; 1633cb51613SAlexandru Ardelean int temp_scale_nano; 1643cb51613SAlexandru Ardelean int temp_offset; 1653cb51613SAlexandru Ardelean int (*set_freq)(struct adis16400_state *st, unsigned int freq); 1663cb51613SAlexandru Ardelean int (*get_freq)(struct adis16400_state *st); 1673cb51613SAlexandru Ardelean }; 1683cb51613SAlexandru Ardelean 1693cb51613SAlexandru Ardelean /** 1703cb51613SAlexandru Ardelean * struct adis16400_state - device instance specific data 1713cb51613SAlexandru Ardelean * @variant: chip variant info 1723cb51613SAlexandru Ardelean * @filt_int: integer part of requested filter frequency 1733cb51613SAlexandru Ardelean * @adis: adis device 1743cb51613SAlexandru Ardelean **/ 1753cb51613SAlexandru Ardelean struct adis16400_state { 1763cb51613SAlexandru Ardelean struct adis16400_chip_info *variant; 1773cb51613SAlexandru Ardelean int filt_int; 1783cb51613SAlexandru Ardelean 1793cb51613SAlexandru Ardelean struct adis adis; 1803cb51613SAlexandru Ardelean unsigned long avail_scan_mask[2]; 1813cb51613SAlexandru Ardelean }; 1823cb51613SAlexandru Ardelean 1833cb51613SAlexandru Ardelean /* At the moment triggers are only used for ring buffer 1843cb51613SAlexandru Ardelean * filling. This may change! 1853cb51613SAlexandru Ardelean */ 1863cb51613SAlexandru Ardelean 1873cb51613SAlexandru Ardelean enum { 1883cb51613SAlexandru Ardelean ADIS16400_SCAN_SUPPLY, 1893cb51613SAlexandru Ardelean ADIS16400_SCAN_GYRO_X, 1903cb51613SAlexandru Ardelean ADIS16400_SCAN_GYRO_Y, 1913cb51613SAlexandru Ardelean ADIS16400_SCAN_GYRO_Z, 1923cb51613SAlexandru Ardelean ADIS16400_SCAN_ACC_X, 1933cb51613SAlexandru Ardelean ADIS16400_SCAN_ACC_Y, 1943cb51613SAlexandru Ardelean ADIS16400_SCAN_ACC_Z, 1953cb51613SAlexandru Ardelean ADIS16400_SCAN_MAGN_X, 1963cb51613SAlexandru Ardelean ADIS16400_SCAN_MAGN_Y, 1973cb51613SAlexandru Ardelean ADIS16400_SCAN_MAGN_Z, 1983cb51613SAlexandru Ardelean ADIS16400_SCAN_BARO, 1993cb51613SAlexandru Ardelean ADIS16350_SCAN_TEMP_X, 2003cb51613SAlexandru Ardelean ADIS16350_SCAN_TEMP_Y, 2013cb51613SAlexandru Ardelean ADIS16350_SCAN_TEMP_Z, 2023cb51613SAlexandru Ardelean ADIS16300_SCAN_INCLI_X, 2033cb51613SAlexandru Ardelean ADIS16300_SCAN_INCLI_Y, 2043cb51613SAlexandru Ardelean ADIS16400_SCAN_ADC, 2053cb51613SAlexandru Ardelean ADIS16400_SCAN_TIMESTAMP, 2063cb51613SAlexandru Ardelean }; 2075447e3f1SAlexandru Ardelean 2085447e3f1SAlexandru Ardelean #ifdef CONFIG_DEBUG_FS 2095447e3f1SAlexandru Ardelean 2105447e3f1SAlexandru Ardelean static ssize_t adis16400_show_serial_number(struct file *file, 2115447e3f1SAlexandru Ardelean char __user *userbuf, size_t count, loff_t *ppos) 2125447e3f1SAlexandru Ardelean { 2135447e3f1SAlexandru Ardelean struct adis16400_state *st = file->private_data; 2145447e3f1SAlexandru Ardelean u16 lot1, lot2, serial_number; 2155447e3f1SAlexandru Ardelean char buf[16]; 2165447e3f1SAlexandru Ardelean size_t len; 2175447e3f1SAlexandru Ardelean int ret; 2185447e3f1SAlexandru Ardelean 2195447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1); 2205447e3f1SAlexandru Ardelean if (ret < 0) 2215447e3f1SAlexandru Ardelean return ret; 2225447e3f1SAlexandru Ardelean 2235447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2); 2245447e3f1SAlexandru Ardelean if (ret < 0) 2255447e3f1SAlexandru Ardelean return ret; 2265447e3f1SAlexandru Ardelean 2275447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER, 2285447e3f1SAlexandru Ardelean &serial_number); 2295447e3f1SAlexandru Ardelean if (ret < 0) 2305447e3f1SAlexandru Ardelean return ret; 2315447e3f1SAlexandru Ardelean 2325447e3f1SAlexandru Ardelean len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2, 2335447e3f1SAlexandru Ardelean serial_number); 2345447e3f1SAlexandru Ardelean 2355447e3f1SAlexandru Ardelean return simple_read_from_buffer(userbuf, count, ppos, buf, len); 2365447e3f1SAlexandru Ardelean } 2375447e3f1SAlexandru Ardelean 2385447e3f1SAlexandru Ardelean static const struct file_operations adis16400_serial_number_fops = { 2395447e3f1SAlexandru Ardelean .open = simple_open, 2405447e3f1SAlexandru Ardelean .read = adis16400_show_serial_number, 2415447e3f1SAlexandru Ardelean .llseek = default_llseek, 2425447e3f1SAlexandru Ardelean .owner = THIS_MODULE, 2435447e3f1SAlexandru Ardelean }; 2445447e3f1SAlexandru Ardelean 2455447e3f1SAlexandru Ardelean static int adis16400_show_product_id(void *arg, u64 *val) 2465447e3f1SAlexandru Ardelean { 2475447e3f1SAlexandru Ardelean struct adis16400_state *st = arg; 2485447e3f1SAlexandru Ardelean uint16_t prod_id; 2495447e3f1SAlexandru Ardelean int ret; 2505447e3f1SAlexandru Ardelean 2515447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id); 2525447e3f1SAlexandru Ardelean if (ret < 0) 2535447e3f1SAlexandru Ardelean return ret; 2545447e3f1SAlexandru Ardelean 2555447e3f1SAlexandru Ardelean *val = prod_id; 2565447e3f1SAlexandru Ardelean 2575447e3f1SAlexandru Ardelean return 0; 2585447e3f1SAlexandru Ardelean } 2595447e3f1SAlexandru Ardelean DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops, 2605447e3f1SAlexandru Ardelean adis16400_show_product_id, NULL, "%lld\n"); 2615447e3f1SAlexandru Ardelean 2625447e3f1SAlexandru Ardelean static int adis16400_show_flash_count(void *arg, u64 *val) 2635447e3f1SAlexandru Ardelean { 2645447e3f1SAlexandru Ardelean struct adis16400_state *st = arg; 2655447e3f1SAlexandru Ardelean uint16_t flash_count; 2665447e3f1SAlexandru Ardelean int ret; 2675447e3f1SAlexandru Ardelean 2685447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count); 2695447e3f1SAlexandru Ardelean if (ret < 0) 2705447e3f1SAlexandru Ardelean return ret; 2715447e3f1SAlexandru Ardelean 2725447e3f1SAlexandru Ardelean *val = flash_count; 2735447e3f1SAlexandru Ardelean 2745447e3f1SAlexandru Ardelean return 0; 2755447e3f1SAlexandru Ardelean } 2765447e3f1SAlexandru Ardelean DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops, 2775447e3f1SAlexandru Ardelean adis16400_show_flash_count, NULL, "%lld\n"); 2785447e3f1SAlexandru Ardelean 2795447e3f1SAlexandru Ardelean static int adis16400_debugfs_init(struct iio_dev *indio_dev) 2805447e3f1SAlexandru Ardelean { 2815447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 2825447e3f1SAlexandru Ardelean 2835447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER) 2845447e3f1SAlexandru Ardelean debugfs_create_file("serial_number", 0400, 2855447e3f1SAlexandru Ardelean indio_dev->debugfs_dentry, st, 2865447e3f1SAlexandru Ardelean &adis16400_serial_number_fops); 2875447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_HAS_PROD_ID) 2885447e3f1SAlexandru Ardelean debugfs_create_file("product_id", 0400, 2895447e3f1SAlexandru Ardelean indio_dev->debugfs_dentry, st, 2905447e3f1SAlexandru Ardelean &adis16400_product_id_fops); 2915447e3f1SAlexandru Ardelean debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, 2925447e3f1SAlexandru Ardelean st, &adis16400_flash_count_fops); 2935447e3f1SAlexandru Ardelean 2945447e3f1SAlexandru Ardelean return 0; 2955447e3f1SAlexandru Ardelean } 2965447e3f1SAlexandru Ardelean 2975447e3f1SAlexandru Ardelean #else 2985447e3f1SAlexandru Ardelean 2995447e3f1SAlexandru Ardelean static int adis16400_debugfs_init(struct iio_dev *indio_dev) 3005447e3f1SAlexandru Ardelean { 3015447e3f1SAlexandru Ardelean return 0; 3025447e3f1SAlexandru Ardelean } 3035447e3f1SAlexandru Ardelean 3045447e3f1SAlexandru Ardelean #endif 3055447e3f1SAlexandru Ardelean 3065447e3f1SAlexandru Ardelean enum adis16400_chip_variant { 3075447e3f1SAlexandru Ardelean ADIS16300, 3085447e3f1SAlexandru Ardelean ADIS16334, 3095447e3f1SAlexandru Ardelean ADIS16350, 3105447e3f1SAlexandru Ardelean ADIS16360, 3115447e3f1SAlexandru Ardelean ADIS16362, 3125447e3f1SAlexandru Ardelean ADIS16364, 3135447e3f1SAlexandru Ardelean ADIS16367, 3145447e3f1SAlexandru Ardelean ADIS16400, 3155447e3f1SAlexandru Ardelean ADIS16445, 3165447e3f1SAlexandru Ardelean ADIS16448, 3175447e3f1SAlexandru Ardelean }; 3185447e3f1SAlexandru Ardelean 3195447e3f1SAlexandru Ardelean static struct adis_burst adis16400_burst = { 3205447e3f1SAlexandru Ardelean .en = true, 3215447e3f1SAlexandru Ardelean .reg_cmd = ADIS16400_GLOB_CMD, 3225447e3f1SAlexandru Ardelean }; 3235447e3f1SAlexandru Ardelean 3245447e3f1SAlexandru Ardelean static int adis16334_get_freq(struct adis16400_state *st) 3255447e3f1SAlexandru Ardelean { 3265447e3f1SAlexandru Ardelean int ret; 3275447e3f1SAlexandru Ardelean uint16_t t; 3285447e3f1SAlexandru Ardelean 3295447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); 3305447e3f1SAlexandru Ardelean if (ret < 0) 3315447e3f1SAlexandru Ardelean return ret; 3325447e3f1SAlexandru Ardelean 3335447e3f1SAlexandru Ardelean t >>= ADIS16334_RATE_DIV_SHIFT; 3345447e3f1SAlexandru Ardelean 3355447e3f1SAlexandru Ardelean return 819200 >> t; 3365447e3f1SAlexandru Ardelean } 3375447e3f1SAlexandru Ardelean 3385447e3f1SAlexandru Ardelean static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) 3395447e3f1SAlexandru Ardelean { 3405447e3f1SAlexandru Ardelean unsigned int t; 3415447e3f1SAlexandru Ardelean 3425447e3f1SAlexandru Ardelean if (freq < 819200) 3435447e3f1SAlexandru Ardelean t = ilog2(819200 / freq); 3445447e3f1SAlexandru Ardelean else 3455447e3f1SAlexandru Ardelean t = 0; 3465447e3f1SAlexandru Ardelean 3475447e3f1SAlexandru Ardelean if (t > 0x31) 3485447e3f1SAlexandru Ardelean t = 0x31; 3495447e3f1SAlexandru Ardelean 3505447e3f1SAlexandru Ardelean t <<= ADIS16334_RATE_DIV_SHIFT; 3515447e3f1SAlexandru Ardelean t |= ADIS16334_RATE_INT_CLK; 3525447e3f1SAlexandru Ardelean 3535447e3f1SAlexandru Ardelean return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); 3545447e3f1SAlexandru Ardelean } 3555447e3f1SAlexandru Ardelean 3565447e3f1SAlexandru Ardelean static int adis16400_get_freq(struct adis16400_state *st) 3575447e3f1SAlexandru Ardelean { 3585447e3f1SAlexandru Ardelean int sps, ret; 3595447e3f1SAlexandru Ardelean uint16_t t; 3605447e3f1SAlexandru Ardelean 3615447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); 3625447e3f1SAlexandru Ardelean if (ret < 0) 3635447e3f1SAlexandru Ardelean return ret; 3645447e3f1SAlexandru Ardelean 3655447e3f1SAlexandru Ardelean sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404; 3665447e3f1SAlexandru Ardelean sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; 3675447e3f1SAlexandru Ardelean 3685447e3f1SAlexandru Ardelean return sps; 3695447e3f1SAlexandru Ardelean } 3705447e3f1SAlexandru Ardelean 3715447e3f1SAlexandru Ardelean static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) 3725447e3f1SAlexandru Ardelean { 3735447e3f1SAlexandru Ardelean unsigned int t; 3745447e3f1SAlexandru Ardelean uint8_t val = 0; 3755447e3f1SAlexandru Ardelean 3765447e3f1SAlexandru Ardelean t = 1638404 / freq; 3775447e3f1SAlexandru Ardelean if (t >= 128) { 3785447e3f1SAlexandru Ardelean val |= ADIS16400_SMPL_PRD_TIME_BASE; 3795447e3f1SAlexandru Ardelean t = 52851 / freq; 3805447e3f1SAlexandru Ardelean if (t >= 128) 3815447e3f1SAlexandru Ardelean t = 127; 3825447e3f1SAlexandru Ardelean } else if (t != 0) { 3835447e3f1SAlexandru Ardelean t--; 3845447e3f1SAlexandru Ardelean } 3855447e3f1SAlexandru Ardelean 3865447e3f1SAlexandru Ardelean val |= t; 3875447e3f1SAlexandru Ardelean 3885447e3f1SAlexandru Ardelean if (t >= 0x0A || (val & ADIS16400_SMPL_PRD_TIME_BASE)) 3895447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; 3905447e3f1SAlexandru Ardelean else 3915447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; 3925447e3f1SAlexandru Ardelean 3935447e3f1SAlexandru Ardelean return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val); 3945447e3f1SAlexandru Ardelean } 3955447e3f1SAlexandru Ardelean 3965447e3f1SAlexandru Ardelean static const unsigned int adis16400_3db_divisors[] = { 3975447e3f1SAlexandru Ardelean [0] = 2, /* Special case */ 3985447e3f1SAlexandru Ardelean [1] = 6, 3995447e3f1SAlexandru Ardelean [2] = 12, 4005447e3f1SAlexandru Ardelean [3] = 25, 4015447e3f1SAlexandru Ardelean [4] = 50, 4025447e3f1SAlexandru Ardelean [5] = 100, 4035447e3f1SAlexandru Ardelean [6] = 200, 4045447e3f1SAlexandru Ardelean [7] = 200, /* Not a valid setting */ 4055447e3f1SAlexandru Ardelean }; 4065447e3f1SAlexandru Ardelean 4075447e3f1SAlexandru Ardelean static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) 4085447e3f1SAlexandru Ardelean { 4095447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 4105447e3f1SAlexandru Ardelean uint16_t val16; 4115447e3f1SAlexandru Ardelean int i, ret; 4125447e3f1SAlexandru Ardelean 4135447e3f1SAlexandru Ardelean for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { 4145447e3f1SAlexandru Ardelean if (sps / adis16400_3db_divisors[i] >= val) 4155447e3f1SAlexandru Ardelean break; 4165447e3f1SAlexandru Ardelean } 4175447e3f1SAlexandru Ardelean 4185447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); 4195447e3f1SAlexandru Ardelean if (ret < 0) 4205447e3f1SAlexandru Ardelean return ret; 4215447e3f1SAlexandru Ardelean 4225447e3f1SAlexandru Ardelean ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, 4235447e3f1SAlexandru Ardelean (val16 & ~0x07) | i); 4245447e3f1SAlexandru Ardelean return ret; 4255447e3f1SAlexandru Ardelean } 4265447e3f1SAlexandru Ardelean 4275447e3f1SAlexandru Ardelean /* Power down the device */ 4285447e3f1SAlexandru Ardelean static int adis16400_stop_device(struct iio_dev *indio_dev) 4295447e3f1SAlexandru Ardelean { 4305447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 4315447e3f1SAlexandru Ardelean int ret; 4325447e3f1SAlexandru Ardelean 4335447e3f1SAlexandru Ardelean ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, 4345447e3f1SAlexandru Ardelean ADIS16400_SLP_CNT_POWER_OFF); 4355447e3f1SAlexandru Ardelean if (ret) 4365447e3f1SAlexandru Ardelean dev_err(&indio_dev->dev, 4375447e3f1SAlexandru Ardelean "problem with turning device off: SLP_CNT"); 4385447e3f1SAlexandru Ardelean 4395447e3f1SAlexandru Ardelean return ret; 4405447e3f1SAlexandru Ardelean } 4415447e3f1SAlexandru Ardelean 4425447e3f1SAlexandru Ardelean static int adis16400_initial_setup(struct iio_dev *indio_dev) 4435447e3f1SAlexandru Ardelean { 4445447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 4455447e3f1SAlexandru Ardelean uint16_t prod_id, smp_prd; 4465447e3f1SAlexandru Ardelean unsigned int device_id; 4475447e3f1SAlexandru Ardelean int ret; 4485447e3f1SAlexandru Ardelean 4495447e3f1SAlexandru Ardelean /* use low spi speed for init if the device has a slow mode */ 4505447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) 4515447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; 4525447e3f1SAlexandru Ardelean else 4535447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; 4545447e3f1SAlexandru Ardelean st->adis.spi->mode = SPI_MODE_3; 4555447e3f1SAlexandru Ardelean spi_setup(st->adis.spi); 4565447e3f1SAlexandru Ardelean 4575447e3f1SAlexandru Ardelean ret = adis_initial_startup(&st->adis); 4585447e3f1SAlexandru Ardelean if (ret) 4595447e3f1SAlexandru Ardelean return ret; 4605447e3f1SAlexandru Ardelean 4615447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_HAS_PROD_ID) { 4625447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, 4635447e3f1SAlexandru Ardelean ADIS16400_PRODUCT_ID, &prod_id); 4645447e3f1SAlexandru Ardelean if (ret) 4655447e3f1SAlexandru Ardelean goto err_ret; 4665447e3f1SAlexandru Ardelean 4675447e3f1SAlexandru Ardelean ret = sscanf(indio_dev->name, "adis%u\n", &device_id); 4685447e3f1SAlexandru Ardelean if (ret != 1) { 4695447e3f1SAlexandru Ardelean ret = -EINVAL; 4705447e3f1SAlexandru Ardelean goto err_ret; 4715447e3f1SAlexandru Ardelean } 4725447e3f1SAlexandru Ardelean 4735447e3f1SAlexandru Ardelean if (prod_id != device_id) 4745447e3f1SAlexandru Ardelean dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", 4755447e3f1SAlexandru Ardelean device_id, prod_id); 4765447e3f1SAlexandru Ardelean 4775447e3f1SAlexandru Ardelean dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", 4785447e3f1SAlexandru Ardelean indio_dev->name, prod_id, 4795447e3f1SAlexandru Ardelean st->adis.spi->chip_select, st->adis.spi->irq); 4805447e3f1SAlexandru Ardelean } 4815447e3f1SAlexandru Ardelean /* use high spi speed if possible */ 4825447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { 4835447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); 4845447e3f1SAlexandru Ardelean if (ret) 4855447e3f1SAlexandru Ardelean goto err_ret; 4865447e3f1SAlexandru Ardelean 4875447e3f1SAlexandru Ardelean if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { 4885447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; 4895447e3f1SAlexandru Ardelean spi_setup(st->adis.spi); 4905447e3f1SAlexandru Ardelean } 4915447e3f1SAlexandru Ardelean } 4925447e3f1SAlexandru Ardelean 4935447e3f1SAlexandru Ardelean err_ret: 4945447e3f1SAlexandru Ardelean return ret; 4955447e3f1SAlexandru Ardelean } 4965447e3f1SAlexandru Ardelean 4975447e3f1SAlexandru Ardelean static const uint8_t adis16400_addresses[] = { 4985447e3f1SAlexandru Ardelean [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, 4995447e3f1SAlexandru Ardelean [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, 5005447e3f1SAlexandru Ardelean [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, 5015447e3f1SAlexandru Ardelean [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, 5025447e3f1SAlexandru Ardelean [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, 5035447e3f1SAlexandru Ardelean [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, 5045447e3f1SAlexandru Ardelean }; 5055447e3f1SAlexandru Ardelean 5065447e3f1SAlexandru Ardelean static int adis16400_write_raw(struct iio_dev *indio_dev, 5075447e3f1SAlexandru Ardelean struct iio_chan_spec const *chan, int val, int val2, long info) 5085447e3f1SAlexandru Ardelean { 5095447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 5105447e3f1SAlexandru Ardelean int ret, sps; 5115447e3f1SAlexandru Ardelean 5125447e3f1SAlexandru Ardelean switch (info) { 5135447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_CALIBBIAS: 5145447e3f1SAlexandru Ardelean mutex_lock(&indio_dev->mlock); 5155447e3f1SAlexandru Ardelean ret = adis_write_reg_16(&st->adis, 5165447e3f1SAlexandru Ardelean adis16400_addresses[chan->scan_index], val); 5175447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 5185447e3f1SAlexandru Ardelean return ret; 5195447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 5205447e3f1SAlexandru Ardelean /* 5215447e3f1SAlexandru Ardelean * Need to cache values so we can update if the frequency 5225447e3f1SAlexandru Ardelean * changes. 5235447e3f1SAlexandru Ardelean */ 5245447e3f1SAlexandru Ardelean mutex_lock(&indio_dev->mlock); 5255447e3f1SAlexandru Ardelean st->filt_int = val; 5265447e3f1SAlexandru Ardelean /* Work out update to current value */ 5275447e3f1SAlexandru Ardelean sps = st->variant->get_freq(st); 5285447e3f1SAlexandru Ardelean if (sps < 0) { 5295447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 5305447e3f1SAlexandru Ardelean return sps; 5315447e3f1SAlexandru Ardelean } 5325447e3f1SAlexandru Ardelean 5335447e3f1SAlexandru Ardelean ret = adis16400_set_filter(indio_dev, sps, 5345447e3f1SAlexandru Ardelean val * 1000 + val2 / 1000); 5355447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 5365447e3f1SAlexandru Ardelean return ret; 5375447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_SAMP_FREQ: 5385447e3f1SAlexandru Ardelean sps = val * 1000 + val2 / 1000; 5395447e3f1SAlexandru Ardelean 5405447e3f1SAlexandru Ardelean if (sps <= 0) 5415447e3f1SAlexandru Ardelean return -EINVAL; 5425447e3f1SAlexandru Ardelean 5435447e3f1SAlexandru Ardelean mutex_lock(&indio_dev->mlock); 5445447e3f1SAlexandru Ardelean ret = st->variant->set_freq(st, sps); 5455447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 5465447e3f1SAlexandru Ardelean return ret; 5475447e3f1SAlexandru Ardelean default: 5485447e3f1SAlexandru Ardelean return -EINVAL; 5495447e3f1SAlexandru Ardelean } 5505447e3f1SAlexandru Ardelean } 5515447e3f1SAlexandru Ardelean 5525447e3f1SAlexandru Ardelean static int adis16400_read_raw(struct iio_dev *indio_dev, 5535447e3f1SAlexandru Ardelean struct iio_chan_spec const *chan, int *val, int *val2, long info) 5545447e3f1SAlexandru Ardelean { 5555447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 5565447e3f1SAlexandru Ardelean int16_t val16; 5575447e3f1SAlexandru Ardelean int ret; 5585447e3f1SAlexandru Ardelean 5595447e3f1SAlexandru Ardelean switch (info) { 5605447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_RAW: 5615447e3f1SAlexandru Ardelean return adis_single_conversion(indio_dev, chan, 0, val); 5625447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_SCALE: 5635447e3f1SAlexandru Ardelean switch (chan->type) { 5645447e3f1SAlexandru Ardelean case IIO_ANGL_VEL: 5655447e3f1SAlexandru Ardelean *val = 0; 5665447e3f1SAlexandru Ardelean *val2 = st->variant->gyro_scale_micro; 5675447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5685447e3f1SAlexandru Ardelean case IIO_VOLTAGE: 5695447e3f1SAlexandru Ardelean *val = 0; 5705447e3f1SAlexandru Ardelean if (chan->channel == 0) { 5715447e3f1SAlexandru Ardelean *val = 2; 5725447e3f1SAlexandru Ardelean *val2 = 418000; /* 2.418 mV */ 5735447e3f1SAlexandru Ardelean } else { 5745447e3f1SAlexandru Ardelean *val = 0; 5755447e3f1SAlexandru Ardelean *val2 = 805800; /* 805.8 uV */ 5765447e3f1SAlexandru Ardelean } 5775447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5785447e3f1SAlexandru Ardelean case IIO_ACCEL: 5795447e3f1SAlexandru Ardelean *val = 0; 5805447e3f1SAlexandru Ardelean *val2 = st->variant->accel_scale_micro; 5815447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5825447e3f1SAlexandru Ardelean case IIO_MAGN: 5835447e3f1SAlexandru Ardelean *val = 0; 5845447e3f1SAlexandru Ardelean *val2 = 500; /* 0.5 mgauss */ 5855447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5865447e3f1SAlexandru Ardelean case IIO_TEMP: 5875447e3f1SAlexandru Ardelean *val = st->variant->temp_scale_nano / 1000000; 5885447e3f1SAlexandru Ardelean *val2 = (st->variant->temp_scale_nano % 1000000); 5895447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5905447e3f1SAlexandru Ardelean case IIO_PRESSURE: 5915447e3f1SAlexandru Ardelean /* 20 uBar = 0.002kPascal */ 5925447e3f1SAlexandru Ardelean *val = 0; 5935447e3f1SAlexandru Ardelean *val2 = 2000; 5945447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 5955447e3f1SAlexandru Ardelean default: 5965447e3f1SAlexandru Ardelean return -EINVAL; 5975447e3f1SAlexandru Ardelean } 5985447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_CALIBBIAS: 5995447e3f1SAlexandru Ardelean mutex_lock(&indio_dev->mlock); 6005447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, 6015447e3f1SAlexandru Ardelean adis16400_addresses[chan->scan_index], &val16); 6025447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 6035447e3f1SAlexandru Ardelean if (ret) 6045447e3f1SAlexandru Ardelean return ret; 6055447e3f1SAlexandru Ardelean val16 = sign_extend32(val16, 11); 6065447e3f1SAlexandru Ardelean *val = val16; 6075447e3f1SAlexandru Ardelean return IIO_VAL_INT; 6085447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_OFFSET: 6095447e3f1SAlexandru Ardelean /* currently only temperature */ 6105447e3f1SAlexandru Ardelean *val = st->variant->temp_offset; 6115447e3f1SAlexandru Ardelean return IIO_VAL_INT; 6125447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 6135447e3f1SAlexandru Ardelean mutex_lock(&indio_dev->mlock); 6145447e3f1SAlexandru Ardelean /* Need both the number of taps and the sampling frequency */ 6155447e3f1SAlexandru Ardelean ret = adis_read_reg_16(&st->adis, 6165447e3f1SAlexandru Ardelean ADIS16400_SENS_AVG, 6175447e3f1SAlexandru Ardelean &val16); 6185447e3f1SAlexandru Ardelean if (ret < 0) { 6195447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 6205447e3f1SAlexandru Ardelean return ret; 6215447e3f1SAlexandru Ardelean } 6225447e3f1SAlexandru Ardelean ret = st->variant->get_freq(st); 6235447e3f1SAlexandru Ardelean if (ret >= 0) { 6245447e3f1SAlexandru Ardelean ret /= adis16400_3db_divisors[val16 & 0x07]; 6255447e3f1SAlexandru Ardelean *val = ret / 1000; 6265447e3f1SAlexandru Ardelean *val2 = (ret % 1000) * 1000; 6275447e3f1SAlexandru Ardelean } 6285447e3f1SAlexandru Ardelean mutex_unlock(&indio_dev->mlock); 6295447e3f1SAlexandru Ardelean if (ret < 0) 6305447e3f1SAlexandru Ardelean return ret; 6315447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 6325447e3f1SAlexandru Ardelean case IIO_CHAN_INFO_SAMP_FREQ: 6335447e3f1SAlexandru Ardelean ret = st->variant->get_freq(st); 6345447e3f1SAlexandru Ardelean if (ret < 0) 6355447e3f1SAlexandru Ardelean return ret; 6365447e3f1SAlexandru Ardelean *val = ret / 1000; 6375447e3f1SAlexandru Ardelean *val2 = (ret % 1000) * 1000; 6385447e3f1SAlexandru Ardelean return IIO_VAL_INT_PLUS_MICRO; 6395447e3f1SAlexandru Ardelean default: 6405447e3f1SAlexandru Ardelean return -EINVAL; 6415447e3f1SAlexandru Ardelean } 6425447e3f1SAlexandru Ardelean } 6435447e3f1SAlexandru Ardelean 6445447e3f1SAlexandru Ardelean #if IS_ENABLED(CONFIG_IIO_BUFFER) 6455447e3f1SAlexandru Ardelean static irqreturn_t adis16400_trigger_handler(int irq, void *p) 6465447e3f1SAlexandru Ardelean { 6475447e3f1SAlexandru Ardelean struct iio_poll_func *pf = p; 6485447e3f1SAlexandru Ardelean struct iio_dev *indio_dev = pf->indio_dev; 6495447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 6505447e3f1SAlexandru Ardelean struct adis *adis = &st->adis; 6515447e3f1SAlexandru Ardelean u32 old_speed_hz = st->adis.spi->max_speed_hz; 6525447e3f1SAlexandru Ardelean void *buffer; 6535447e3f1SAlexandru Ardelean int ret; 6545447e3f1SAlexandru Ardelean 6555447e3f1SAlexandru Ardelean if (!adis->buffer) 6565447e3f1SAlexandru Ardelean return -ENOMEM; 6575447e3f1SAlexandru Ardelean 6585447e3f1SAlexandru Ardelean if (!(st->variant->flags & ADIS16400_NO_BURST) && 6595447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { 6605447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; 6615447e3f1SAlexandru Ardelean spi_setup(st->adis.spi); 6625447e3f1SAlexandru Ardelean } 6635447e3f1SAlexandru Ardelean 6645447e3f1SAlexandru Ardelean ret = spi_sync(adis->spi, &adis->msg); 6655447e3f1SAlexandru Ardelean if (ret) 6665447e3f1SAlexandru Ardelean dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); 6675447e3f1SAlexandru Ardelean 6685447e3f1SAlexandru Ardelean if (!(st->variant->flags & ADIS16400_NO_BURST)) { 6695447e3f1SAlexandru Ardelean st->adis.spi->max_speed_hz = old_speed_hz; 6705447e3f1SAlexandru Ardelean spi_setup(st->adis.spi); 6715447e3f1SAlexandru Ardelean } 6725447e3f1SAlexandru Ardelean 6735447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) 6745447e3f1SAlexandru Ardelean buffer = adis->buffer + sizeof(u16); 6755447e3f1SAlexandru Ardelean else 6765447e3f1SAlexandru Ardelean buffer = adis->buffer; 6775447e3f1SAlexandru Ardelean 6785447e3f1SAlexandru Ardelean iio_push_to_buffers_with_timestamp(indio_dev, buffer, 6795447e3f1SAlexandru Ardelean pf->timestamp); 6805447e3f1SAlexandru Ardelean 6815447e3f1SAlexandru Ardelean iio_trigger_notify_done(indio_dev->trig); 6825447e3f1SAlexandru Ardelean 6835447e3f1SAlexandru Ardelean return IRQ_HANDLED; 6845447e3f1SAlexandru Ardelean } 6855447e3f1SAlexandru Ardelean #else 6865447e3f1SAlexandru Ardelean #define adis16400_trigger_handler NULL 6875447e3f1SAlexandru Ardelean #endif /* IS_ENABLED(CONFIG_IIO_BUFFER) */ 6885447e3f1SAlexandru Ardelean 6895447e3f1SAlexandru Ardelean #define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ 6905447e3f1SAlexandru Ardelean .type = IIO_VOLTAGE, \ 6915447e3f1SAlexandru Ardelean .indexed = 1, \ 6925447e3f1SAlexandru Ardelean .channel = chn, \ 6935447e3f1SAlexandru Ardelean .extend_name = name, \ 6945447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 6955447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_SCALE), \ 6965447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 6975447e3f1SAlexandru Ardelean .address = (addr), \ 6985447e3f1SAlexandru Ardelean .scan_index = (si), \ 6995447e3f1SAlexandru Ardelean .scan_type = { \ 7005447e3f1SAlexandru Ardelean .sign = 'u', \ 7015447e3f1SAlexandru Ardelean .realbits = (bits), \ 7025447e3f1SAlexandru Ardelean .storagebits = 16, \ 7035447e3f1SAlexandru Ardelean .shift = 0, \ 7045447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 7055447e3f1SAlexandru Ardelean }, \ 7065447e3f1SAlexandru Ardelean } 7075447e3f1SAlexandru Ardelean 7085447e3f1SAlexandru Ardelean #define ADIS16400_SUPPLY_CHAN(addr, bits) \ 7095447e3f1SAlexandru Ardelean ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY, 0) 7105447e3f1SAlexandru Ardelean 7115447e3f1SAlexandru Ardelean #define ADIS16400_AUX_ADC_CHAN(addr, bits) \ 7125447e3f1SAlexandru Ardelean ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC, 1) 7135447e3f1SAlexandru Ardelean 7145447e3f1SAlexandru Ardelean #define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ 7155447e3f1SAlexandru Ardelean .type = IIO_ANGL_VEL, \ 7165447e3f1SAlexandru Ardelean .modified = 1, \ 7175447e3f1SAlexandru Ardelean .channel2 = IIO_MOD_ ## mod, \ 7185447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 7195447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_CALIBBIAS), \ 7205447e3f1SAlexandru Ardelean .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 7215447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 7225447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 7235447e3f1SAlexandru Ardelean .address = addr, \ 7245447e3f1SAlexandru Ardelean .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ 7255447e3f1SAlexandru Ardelean .scan_type = { \ 7265447e3f1SAlexandru Ardelean .sign = 's', \ 7275447e3f1SAlexandru Ardelean .realbits = (bits), \ 7285447e3f1SAlexandru Ardelean .storagebits = 16, \ 7295447e3f1SAlexandru Ardelean .shift = 0, \ 7305447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 7315447e3f1SAlexandru Ardelean }, \ 7325447e3f1SAlexandru Ardelean } 7335447e3f1SAlexandru Ardelean 7345447e3f1SAlexandru Ardelean #define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ 7355447e3f1SAlexandru Ardelean .type = IIO_ACCEL, \ 7365447e3f1SAlexandru Ardelean .modified = 1, \ 7375447e3f1SAlexandru Ardelean .channel2 = IIO_MOD_ ## mod, \ 7385447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 7395447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_CALIBBIAS), \ 7405447e3f1SAlexandru Ardelean .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 7415447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 7425447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 7435447e3f1SAlexandru Ardelean .address = (addr), \ 7445447e3f1SAlexandru Ardelean .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ 7455447e3f1SAlexandru Ardelean .scan_type = { \ 7465447e3f1SAlexandru Ardelean .sign = 's', \ 7475447e3f1SAlexandru Ardelean .realbits = (bits), \ 7485447e3f1SAlexandru Ardelean .storagebits = 16, \ 7495447e3f1SAlexandru Ardelean .shift = 0, \ 7505447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 7515447e3f1SAlexandru Ardelean }, \ 7525447e3f1SAlexandru Ardelean } 7535447e3f1SAlexandru Ardelean 7545447e3f1SAlexandru Ardelean #define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ 7555447e3f1SAlexandru Ardelean .type = IIO_MAGN, \ 7565447e3f1SAlexandru Ardelean .modified = 1, \ 7575447e3f1SAlexandru Ardelean .channel2 = IIO_MOD_ ## mod, \ 7585447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 7595447e3f1SAlexandru Ardelean .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 7605447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 7615447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 7625447e3f1SAlexandru Ardelean .address = (addr), \ 7635447e3f1SAlexandru Ardelean .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ 7645447e3f1SAlexandru Ardelean .scan_type = { \ 7655447e3f1SAlexandru Ardelean .sign = 's', \ 7665447e3f1SAlexandru Ardelean .realbits = (bits), \ 7675447e3f1SAlexandru Ardelean .storagebits = 16, \ 7685447e3f1SAlexandru Ardelean .shift = 0, \ 7695447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 7705447e3f1SAlexandru Ardelean }, \ 7715447e3f1SAlexandru Ardelean } 7725447e3f1SAlexandru Ardelean 7735447e3f1SAlexandru Ardelean #define ADIS16400_MOD_TEMP_NAME_X "x" 7745447e3f1SAlexandru Ardelean #define ADIS16400_MOD_TEMP_NAME_Y "y" 7755447e3f1SAlexandru Ardelean #define ADIS16400_MOD_TEMP_NAME_Z "z" 7765447e3f1SAlexandru Ardelean 7775447e3f1SAlexandru Ardelean #define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ 7785447e3f1SAlexandru Ardelean .type = IIO_TEMP, \ 7795447e3f1SAlexandru Ardelean .indexed = 1, \ 7805447e3f1SAlexandru Ardelean .channel = 0, \ 7815447e3f1SAlexandru Ardelean .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ 7825447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 7835447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_OFFSET) | \ 7845447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_SCALE), \ 7855447e3f1SAlexandru Ardelean .info_mask_shared_by_type = \ 7865447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 7875447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 7885447e3f1SAlexandru Ardelean .address = (addr), \ 7895447e3f1SAlexandru Ardelean .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ 7905447e3f1SAlexandru Ardelean .scan_type = { \ 7915447e3f1SAlexandru Ardelean .sign = 's', \ 7925447e3f1SAlexandru Ardelean .realbits = (bits), \ 7935447e3f1SAlexandru Ardelean .storagebits = 16, \ 7945447e3f1SAlexandru Ardelean .shift = 0, \ 7955447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 7965447e3f1SAlexandru Ardelean }, \ 7975447e3f1SAlexandru Ardelean } 7985447e3f1SAlexandru Ardelean 7995447e3f1SAlexandru Ardelean #define ADIS16400_TEMP_CHAN(addr, bits) { \ 8005447e3f1SAlexandru Ardelean .type = IIO_TEMP, \ 8015447e3f1SAlexandru Ardelean .indexed = 1, \ 8025447e3f1SAlexandru Ardelean .channel = 0, \ 8035447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 8045447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_OFFSET) | \ 8055447e3f1SAlexandru Ardelean BIT(IIO_CHAN_INFO_SCALE), \ 8065447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 8075447e3f1SAlexandru Ardelean .address = (addr), \ 8085447e3f1SAlexandru Ardelean .scan_index = ADIS16350_SCAN_TEMP_X, \ 8095447e3f1SAlexandru Ardelean .scan_type = { \ 8105447e3f1SAlexandru Ardelean .sign = 's', \ 8115447e3f1SAlexandru Ardelean .realbits = (bits), \ 8125447e3f1SAlexandru Ardelean .storagebits = 16, \ 8135447e3f1SAlexandru Ardelean .shift = 0, \ 8145447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 8155447e3f1SAlexandru Ardelean }, \ 8165447e3f1SAlexandru Ardelean } 8175447e3f1SAlexandru Ardelean 8185447e3f1SAlexandru Ardelean #define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ 8195447e3f1SAlexandru Ardelean .type = IIO_INCLI, \ 8205447e3f1SAlexandru Ardelean .modified = 1, \ 8215447e3f1SAlexandru Ardelean .channel2 = IIO_MOD_ ## mod, \ 8225447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 8235447e3f1SAlexandru Ardelean .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 8245447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 8255447e3f1SAlexandru Ardelean .address = (addr), \ 8265447e3f1SAlexandru Ardelean .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ 8275447e3f1SAlexandru Ardelean .scan_type = { \ 8285447e3f1SAlexandru Ardelean .sign = 's', \ 8295447e3f1SAlexandru Ardelean .realbits = (bits), \ 8305447e3f1SAlexandru Ardelean .storagebits = 16, \ 8315447e3f1SAlexandru Ardelean .shift = 0, \ 8325447e3f1SAlexandru Ardelean .endianness = IIO_BE, \ 8335447e3f1SAlexandru Ardelean }, \ 8345447e3f1SAlexandru Ardelean } 8355447e3f1SAlexandru Ardelean 8365447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16400_channels[] = { 8375447e3f1SAlexandru Ardelean ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), 8385447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), 8395447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), 8405447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), 8415447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), 8425447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), 8435447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), 8445447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), 8455447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), 8465447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), 8475447e3f1SAlexandru Ardelean ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), 8485447e3f1SAlexandru Ardelean ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), 8495447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 8505447e3f1SAlexandru Ardelean }; 8515447e3f1SAlexandru Ardelean 8525447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16445_channels[] = { 8535447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), 8545447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), 8555447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), 8565447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), 8575447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), 8585447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), 8595447e3f1SAlexandru Ardelean ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), 8605447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 8615447e3f1SAlexandru Ardelean }; 8625447e3f1SAlexandru Ardelean 8635447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16448_channels[] = { 8645447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), 8655447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), 8665447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), 8675447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), 8685447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), 8695447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), 8705447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 16), 8715447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 16), 8725447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16), 8735447e3f1SAlexandru Ardelean { 8745447e3f1SAlexandru Ardelean .type = IIO_PRESSURE, 8755447e3f1SAlexandru Ardelean .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 8765447e3f1SAlexandru Ardelean .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 8775447e3f1SAlexandru Ardelean .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 8785447e3f1SAlexandru Ardelean .address = ADIS16448_BARO_OUT, 8795447e3f1SAlexandru Ardelean .scan_index = ADIS16400_SCAN_BARO, 8805447e3f1SAlexandru Ardelean .scan_type = { 8815447e3f1SAlexandru Ardelean .sign = 's', 8825447e3f1SAlexandru Ardelean .realbits = 16, 8835447e3f1SAlexandru Ardelean .storagebits = 16, 8845447e3f1SAlexandru Ardelean .endianness = IIO_BE, 8855447e3f1SAlexandru Ardelean }, 8865447e3f1SAlexandru Ardelean }, 8875447e3f1SAlexandru Ardelean ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), 8885447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 8895447e3f1SAlexandru Ardelean }; 8905447e3f1SAlexandru Ardelean 8915447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16350_channels[] = { 8925447e3f1SAlexandru Ardelean ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), 8935447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), 8945447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), 8955447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), 8965447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), 8975447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), 8985447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), 8995447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), 9005447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), 9015447e3f1SAlexandru Ardelean ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), 9025447e3f1SAlexandru Ardelean ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), 9035447e3f1SAlexandru Ardelean ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), 9045447e3f1SAlexandru Ardelean ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), 9055447e3f1SAlexandru Ardelean ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), 9065447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 9075447e3f1SAlexandru Ardelean }; 9085447e3f1SAlexandru Ardelean 9095447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16300_channels[] = { 9105447e3f1SAlexandru Ardelean ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), 9115447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), 9125447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), 9135447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), 9145447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), 9155447e3f1SAlexandru Ardelean ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), 9165447e3f1SAlexandru Ardelean ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), 9175447e3f1SAlexandru Ardelean ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), 9185447e3f1SAlexandru Ardelean ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), 9195447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 9205447e3f1SAlexandru Ardelean }; 9215447e3f1SAlexandru Ardelean 9225447e3f1SAlexandru Ardelean static const struct iio_chan_spec adis16334_channels[] = { 9235447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), 9245447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), 9255447e3f1SAlexandru Ardelean ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), 9265447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), 9275447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), 9285447e3f1SAlexandru Ardelean ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), 9295447e3f1SAlexandru Ardelean ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), 9305447e3f1SAlexandru Ardelean IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), 9315447e3f1SAlexandru Ardelean }; 9325447e3f1SAlexandru Ardelean 9335447e3f1SAlexandru Ardelean static struct adis16400_chip_info adis16400_chips[] = { 9345447e3f1SAlexandru Ardelean [ADIS16300] = { 9355447e3f1SAlexandru Ardelean .channels = adis16300_channels, 9365447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16300_channels), 9375447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | 9385447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 9395447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 9405447e3f1SAlexandru Ardelean .accel_scale_micro = 5884, 9415447e3f1SAlexandru Ardelean .temp_scale_nano = 140000000, /* 0.14 C */ 9425447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ 9435447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 9445447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 9455447e3f1SAlexandru Ardelean }, 9465447e3f1SAlexandru Ardelean [ADIS16334] = { 9475447e3f1SAlexandru Ardelean .channels = adis16334_channels, 9485447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16334_channels), 9495447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_NO_BURST | 9505447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 9515447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 9525447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ 9535447e3f1SAlexandru Ardelean .temp_scale_nano = 67850000, /* 0.06785 C */ 9545447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ 9555447e3f1SAlexandru Ardelean .set_freq = adis16334_set_freq, 9565447e3f1SAlexandru Ardelean .get_freq = adis16334_get_freq, 9575447e3f1SAlexandru Ardelean }, 9585447e3f1SAlexandru Ardelean [ADIS16350] = { 9595447e3f1SAlexandru Ardelean .channels = adis16350_channels, 9605447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16350_channels), 9615447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ 9625447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ 9635447e3f1SAlexandru Ardelean .temp_scale_nano = 145300000, /* 0.1453 C */ 9645447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ 9655447e3f1SAlexandru Ardelean .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, 9665447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 9675447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 9685447e3f1SAlexandru Ardelean }, 9695447e3f1SAlexandru Ardelean [ADIS16360] = { 9705447e3f1SAlexandru Ardelean .channels = adis16350_channels, 9715447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16350_channels), 9725447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | 9735447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 9745447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 9755447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ 9765447e3f1SAlexandru Ardelean .temp_scale_nano = 136000000, /* 0.136 C */ 9775447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ 9785447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 9795447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 9805447e3f1SAlexandru Ardelean }, 9815447e3f1SAlexandru Ardelean [ADIS16362] = { 9825447e3f1SAlexandru Ardelean .channels = adis16350_channels, 9835447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16350_channels), 9845447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | 9855447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 9865447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 9875447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ 9885447e3f1SAlexandru Ardelean .temp_scale_nano = 136000000, /* 0.136 C */ 9895447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ 9905447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 9915447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 9925447e3f1SAlexandru Ardelean }, 9935447e3f1SAlexandru Ardelean [ADIS16364] = { 9945447e3f1SAlexandru Ardelean .channels = adis16350_channels, 9955447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16350_channels), 9965447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | 9975447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 9985447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 9995447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ 10005447e3f1SAlexandru Ardelean .temp_scale_nano = 136000000, /* 0.136 C */ 10015447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ 10025447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 10035447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 10045447e3f1SAlexandru Ardelean }, 10055447e3f1SAlexandru Ardelean [ADIS16367] = { 10065447e3f1SAlexandru Ardelean .channels = adis16350_channels, 10075447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16350_channels), 10085447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | 10095447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER, 10105447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ 10115447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ 10125447e3f1SAlexandru Ardelean .temp_scale_nano = 136000000, /* 0.136 C */ 10135447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ 10145447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 10155447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 10165447e3f1SAlexandru Ardelean }, 10175447e3f1SAlexandru Ardelean [ADIS16400] = { 10185447e3f1SAlexandru Ardelean .channels = adis16400_channels, 10195447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16400_channels), 10205447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, 10215447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ 10225447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ 10235447e3f1SAlexandru Ardelean .temp_scale_nano = 140000000, /* 0.14 C */ 10245447e3f1SAlexandru Ardelean .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ 10255447e3f1SAlexandru Ardelean .set_freq = adis16400_set_freq, 10265447e3f1SAlexandru Ardelean .get_freq = adis16400_get_freq, 10275447e3f1SAlexandru Ardelean }, 10285447e3f1SAlexandru Ardelean [ADIS16445] = { 10295447e3f1SAlexandru Ardelean .channels = adis16445_channels, 10305447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16445_channels), 10315447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | 10325447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER | 10335447e3f1SAlexandru Ardelean ADIS16400_BURST_DIAG_STAT, 10345447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ 10355447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ 10365447e3f1SAlexandru Ardelean .temp_scale_nano = 73860000, /* 0.07386 C */ 10375447e3f1SAlexandru Ardelean .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ 10385447e3f1SAlexandru Ardelean .set_freq = adis16334_set_freq, 10395447e3f1SAlexandru Ardelean .get_freq = adis16334_get_freq, 10405447e3f1SAlexandru Ardelean }, 10415447e3f1SAlexandru Ardelean [ADIS16448] = { 10425447e3f1SAlexandru Ardelean .channels = adis16448_channels, 10435447e3f1SAlexandru Ardelean .num_channels = ARRAY_SIZE(adis16448_channels), 10445447e3f1SAlexandru Ardelean .flags = ADIS16400_HAS_PROD_ID | 10455447e3f1SAlexandru Ardelean ADIS16400_HAS_SERIAL_NUMBER | 10465447e3f1SAlexandru Ardelean ADIS16400_BURST_DIAG_STAT, 10475447e3f1SAlexandru Ardelean .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ 10485447e3f1SAlexandru Ardelean .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ 10495447e3f1SAlexandru Ardelean .temp_scale_nano = 73860000, /* 0.07386 C */ 10505447e3f1SAlexandru Ardelean .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ 10515447e3f1SAlexandru Ardelean .set_freq = adis16334_set_freq, 10525447e3f1SAlexandru Ardelean .get_freq = adis16334_get_freq, 10535447e3f1SAlexandru Ardelean } 10545447e3f1SAlexandru Ardelean }; 10555447e3f1SAlexandru Ardelean 10565447e3f1SAlexandru Ardelean static const struct iio_info adis16400_info = { 10575447e3f1SAlexandru Ardelean .read_raw = &adis16400_read_raw, 10585447e3f1SAlexandru Ardelean .write_raw = &adis16400_write_raw, 10595447e3f1SAlexandru Ardelean .update_scan_mode = adis_update_scan_mode, 10605447e3f1SAlexandru Ardelean .debugfs_reg_access = adis_debugfs_reg_access, 10615447e3f1SAlexandru Ardelean }; 10625447e3f1SAlexandru Ardelean 10635447e3f1SAlexandru Ardelean static const char * const adis16400_status_error_msgs[] = { 10645447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", 10655447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", 10665447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", 10675447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", 10685447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", 10695447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", 10705447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", 10715447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", 10725447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", 10735447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", 10745447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", 10755447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", 10765447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", 10775447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", 10785447e3f1SAlexandru Ardelean [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", 10795447e3f1SAlexandru Ardelean }; 10805447e3f1SAlexandru Ardelean 10815447e3f1SAlexandru Ardelean static const struct adis_data adis16400_data = { 10825447e3f1SAlexandru Ardelean .msc_ctrl_reg = ADIS16400_MSC_CTRL, 10835447e3f1SAlexandru Ardelean .glob_cmd_reg = ADIS16400_GLOB_CMD, 10845447e3f1SAlexandru Ardelean .diag_stat_reg = ADIS16400_DIAG_STAT, 10855447e3f1SAlexandru Ardelean 10865447e3f1SAlexandru Ardelean .read_delay = 50, 10875447e3f1SAlexandru Ardelean .write_delay = 50, 10885447e3f1SAlexandru Ardelean 10895447e3f1SAlexandru Ardelean .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, 10905447e3f1SAlexandru Ardelean .startup_delay = ADIS16400_STARTUP_DELAY, 10915447e3f1SAlexandru Ardelean 10925447e3f1SAlexandru Ardelean .status_error_msgs = adis16400_status_error_msgs, 10935447e3f1SAlexandru Ardelean .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | 10945447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | 10955447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | 10965447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | 10975447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | 10985447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | 10995447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_ALARM2) | 11005447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_ALARM1) | 11015447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | 11025447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_SELF_TEST) | 11035447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_OVERFLOW) | 11045447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | 11055447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | 11065447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | 11075447e3f1SAlexandru Ardelean BIT(ADIS16400_DIAG_STAT_POWER_LOW), 11085447e3f1SAlexandru Ardelean }; 11095447e3f1SAlexandru Ardelean 11105447e3f1SAlexandru Ardelean static void adis16400_setup_chan_mask(struct adis16400_state *st) 11115447e3f1SAlexandru Ardelean { 11125447e3f1SAlexandru Ardelean const struct adis16400_chip_info *chip_info = st->variant; 11135447e3f1SAlexandru Ardelean unsigned int i; 11145447e3f1SAlexandru Ardelean 11155447e3f1SAlexandru Ardelean for (i = 0; i < chip_info->num_channels; i++) { 11165447e3f1SAlexandru Ardelean const struct iio_chan_spec *ch = &chip_info->channels[i]; 11175447e3f1SAlexandru Ardelean 11185447e3f1SAlexandru Ardelean if (ch->scan_index >= 0 && 11195447e3f1SAlexandru Ardelean ch->scan_index != ADIS16400_SCAN_TIMESTAMP) 11205447e3f1SAlexandru Ardelean st->avail_scan_mask[0] |= BIT(ch->scan_index); 11215447e3f1SAlexandru Ardelean } 11225447e3f1SAlexandru Ardelean } 11235447e3f1SAlexandru Ardelean 11245447e3f1SAlexandru Ardelean static int adis16400_probe(struct spi_device *spi) 11255447e3f1SAlexandru Ardelean { 11265447e3f1SAlexandru Ardelean struct adis16400_state *st; 11275447e3f1SAlexandru Ardelean struct iio_dev *indio_dev; 11285447e3f1SAlexandru Ardelean int ret; 11295447e3f1SAlexandru Ardelean 11305447e3f1SAlexandru Ardelean indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 11315447e3f1SAlexandru Ardelean if (indio_dev == NULL) 11325447e3f1SAlexandru Ardelean return -ENOMEM; 11335447e3f1SAlexandru Ardelean 11345447e3f1SAlexandru Ardelean st = iio_priv(indio_dev); 11355447e3f1SAlexandru Ardelean /* this is only used for removal purposes */ 11365447e3f1SAlexandru Ardelean spi_set_drvdata(spi, indio_dev); 11375447e3f1SAlexandru Ardelean 11385447e3f1SAlexandru Ardelean /* setup the industrialio driver allocated elements */ 11395447e3f1SAlexandru Ardelean st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; 11405447e3f1SAlexandru Ardelean indio_dev->dev.parent = &spi->dev; 11415447e3f1SAlexandru Ardelean indio_dev->name = spi_get_device_id(spi)->name; 11425447e3f1SAlexandru Ardelean indio_dev->channels = st->variant->channels; 11435447e3f1SAlexandru Ardelean indio_dev->num_channels = st->variant->num_channels; 11445447e3f1SAlexandru Ardelean indio_dev->info = &adis16400_info; 11455447e3f1SAlexandru Ardelean indio_dev->modes = INDIO_DIRECT_MODE; 11465447e3f1SAlexandru Ardelean 11475447e3f1SAlexandru Ardelean if (!(st->variant->flags & ADIS16400_NO_BURST)) { 11485447e3f1SAlexandru Ardelean adis16400_setup_chan_mask(st); 11495447e3f1SAlexandru Ardelean indio_dev->available_scan_masks = st->avail_scan_mask; 11505447e3f1SAlexandru Ardelean st->adis.burst = &adis16400_burst; 11515447e3f1SAlexandru Ardelean if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) 11525447e3f1SAlexandru Ardelean st->adis.burst->extra_len = sizeof(u16); 11535447e3f1SAlexandru Ardelean } 11545447e3f1SAlexandru Ardelean 11555447e3f1SAlexandru Ardelean ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); 11565447e3f1SAlexandru Ardelean if (ret) 11575447e3f1SAlexandru Ardelean return ret; 11585447e3f1SAlexandru Ardelean 11595447e3f1SAlexandru Ardelean ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, 11605447e3f1SAlexandru Ardelean adis16400_trigger_handler); 11615447e3f1SAlexandru Ardelean if (ret) 11625447e3f1SAlexandru Ardelean return ret; 11635447e3f1SAlexandru Ardelean 11645447e3f1SAlexandru Ardelean /* Get the device into a sane initial state */ 11655447e3f1SAlexandru Ardelean ret = adis16400_initial_setup(indio_dev); 11665447e3f1SAlexandru Ardelean if (ret) 11675447e3f1SAlexandru Ardelean goto error_cleanup_buffer; 11685447e3f1SAlexandru Ardelean ret = iio_device_register(indio_dev); 11695447e3f1SAlexandru Ardelean if (ret) 11705447e3f1SAlexandru Ardelean goto error_cleanup_buffer; 11715447e3f1SAlexandru Ardelean 11725447e3f1SAlexandru Ardelean adis16400_debugfs_init(indio_dev); 11735447e3f1SAlexandru Ardelean return 0; 11745447e3f1SAlexandru Ardelean 11755447e3f1SAlexandru Ardelean error_cleanup_buffer: 11765447e3f1SAlexandru Ardelean adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); 11775447e3f1SAlexandru Ardelean return ret; 11785447e3f1SAlexandru Ardelean } 11795447e3f1SAlexandru Ardelean 11805447e3f1SAlexandru Ardelean static int adis16400_remove(struct spi_device *spi) 11815447e3f1SAlexandru Ardelean { 11825447e3f1SAlexandru Ardelean struct iio_dev *indio_dev = spi_get_drvdata(spi); 11835447e3f1SAlexandru Ardelean struct adis16400_state *st = iio_priv(indio_dev); 11845447e3f1SAlexandru Ardelean 11855447e3f1SAlexandru Ardelean iio_device_unregister(indio_dev); 11865447e3f1SAlexandru Ardelean adis16400_stop_device(indio_dev); 11875447e3f1SAlexandru Ardelean 11885447e3f1SAlexandru Ardelean adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); 11895447e3f1SAlexandru Ardelean 11905447e3f1SAlexandru Ardelean return 0; 11915447e3f1SAlexandru Ardelean } 11925447e3f1SAlexandru Ardelean 11935447e3f1SAlexandru Ardelean static const struct spi_device_id adis16400_id[] = { 11945447e3f1SAlexandru Ardelean {"adis16300", ADIS16300}, 11955447e3f1SAlexandru Ardelean {"adis16305", ADIS16300}, 11965447e3f1SAlexandru Ardelean {"adis16334", ADIS16334}, 11975447e3f1SAlexandru Ardelean {"adis16350", ADIS16350}, 11985447e3f1SAlexandru Ardelean {"adis16354", ADIS16350}, 11995447e3f1SAlexandru Ardelean {"adis16355", ADIS16350}, 12005447e3f1SAlexandru Ardelean {"adis16360", ADIS16360}, 12015447e3f1SAlexandru Ardelean {"adis16362", ADIS16362}, 12025447e3f1SAlexandru Ardelean {"adis16364", ADIS16364}, 12035447e3f1SAlexandru Ardelean {"adis16365", ADIS16360}, 12045447e3f1SAlexandru Ardelean {"adis16367", ADIS16367}, 12055447e3f1SAlexandru Ardelean {"adis16400", ADIS16400}, 12065447e3f1SAlexandru Ardelean {"adis16405", ADIS16400}, 12075447e3f1SAlexandru Ardelean {"adis16445", ADIS16445}, 12085447e3f1SAlexandru Ardelean {"adis16448", ADIS16448}, 12095447e3f1SAlexandru Ardelean {} 12105447e3f1SAlexandru Ardelean }; 12115447e3f1SAlexandru Ardelean MODULE_DEVICE_TABLE(spi, adis16400_id); 12125447e3f1SAlexandru Ardelean 12135447e3f1SAlexandru Ardelean static struct spi_driver adis16400_driver = { 12145447e3f1SAlexandru Ardelean .driver = { 12155447e3f1SAlexandru Ardelean .name = "adis16400", 12165447e3f1SAlexandru Ardelean }, 12175447e3f1SAlexandru Ardelean .id_table = adis16400_id, 12185447e3f1SAlexandru Ardelean .probe = adis16400_probe, 12195447e3f1SAlexandru Ardelean .remove = adis16400_remove, 12205447e3f1SAlexandru Ardelean }; 12215447e3f1SAlexandru Ardelean module_spi_driver(adis16400_driver); 12225447e3f1SAlexandru Ardelean 12235447e3f1SAlexandru Ardelean MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>"); 12245447e3f1SAlexandru Ardelean MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); 12255447e3f1SAlexandru Ardelean MODULE_LICENSE("GPL v2"); 1226