18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ADIS16133/ADIS16135/ADIS16136 gyroscope driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2012 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * Author: Lars-Peter Clausen <lars@metafoo.de> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/mutex.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 208c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 218c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/imu/adis.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define ADIS16136_REG_FLASH_CNT 0x00 278c2ecf20Sopenharmony_ci#define ADIS16136_REG_TEMP_OUT 0x02 288c2ecf20Sopenharmony_ci#define ADIS16136_REG_GYRO_OUT2 0x04 298c2ecf20Sopenharmony_ci#define ADIS16136_REG_GYRO_OUT 0x06 308c2ecf20Sopenharmony_ci#define ADIS16136_REG_GYRO_OFF2 0x08 318c2ecf20Sopenharmony_ci#define ADIS16136_REG_GYRO_OFF 0x0A 328c2ecf20Sopenharmony_ci#define ADIS16136_REG_ALM_MAG1 0x10 338c2ecf20Sopenharmony_ci#define ADIS16136_REG_ALM_MAG2 0x12 348c2ecf20Sopenharmony_ci#define ADIS16136_REG_ALM_SAMPL1 0x14 358c2ecf20Sopenharmony_ci#define ADIS16136_REG_ALM_SAMPL2 0x16 368c2ecf20Sopenharmony_ci#define ADIS16136_REG_ALM_CTRL 0x18 378c2ecf20Sopenharmony_ci#define ADIS16136_REG_GPIO_CTRL 0x1A 388c2ecf20Sopenharmony_ci#define ADIS16136_REG_MSC_CTRL 0x1C 398c2ecf20Sopenharmony_ci#define ADIS16136_REG_SMPL_PRD 0x1E 408c2ecf20Sopenharmony_ci#define ADIS16136_REG_AVG_CNT 0x20 418c2ecf20Sopenharmony_ci#define ADIS16136_REG_DEC_RATE 0x22 428c2ecf20Sopenharmony_ci#define ADIS16136_REG_SLP_CTRL 0x24 438c2ecf20Sopenharmony_ci#define ADIS16136_REG_DIAG_STAT 0x26 448c2ecf20Sopenharmony_ci#define ADIS16136_REG_GLOB_CMD 0x28 458c2ecf20Sopenharmony_ci#define ADIS16136_REG_LOT1 0x32 468c2ecf20Sopenharmony_ci#define ADIS16136_REG_LOT2 0x34 478c2ecf20Sopenharmony_ci#define ADIS16136_REG_LOT3 0x36 488c2ecf20Sopenharmony_ci#define ADIS16136_REG_PROD_ID 0x38 498c2ecf20Sopenharmony_ci#define ADIS16136_REG_SERIAL_NUM 0x3A 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2 528c2ecf20Sopenharmony_ci#define ADIS16136_DIAG_STAT_SPI_FAIL 3 538c2ecf20Sopenharmony_ci#define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5 548c2ecf20Sopenharmony_ci#define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11) 578c2ecf20Sopenharmony_ci#define ADIS16136_MSC_CTRL_SELF_TEST BIT(10) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct adis16136_chip_info { 608c2ecf20Sopenharmony_ci unsigned int precision; 618c2ecf20Sopenharmony_ci unsigned int fullscale; 628c2ecf20Sopenharmony_ci const struct adis_data adis_data; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct adis16136 { 668c2ecf20Sopenharmony_ci const struct adis16136_chip_info *chip_info; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci struct adis adis; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic ssize_t adis16136_show_serial(struct file *file, 748c2ecf20Sopenharmony_ci char __user *userbuf, size_t count, loff_t *ppos) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = file->private_data; 778c2ecf20Sopenharmony_ci uint16_t lot1, lot2, lot3, serial; 788c2ecf20Sopenharmony_ci char buf[20]; 798c2ecf20Sopenharmony_ci size_t len; 808c2ecf20Sopenharmony_ci int ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, 838c2ecf20Sopenharmony_ci &serial); 848c2ecf20Sopenharmony_ci if (ret) 858c2ecf20Sopenharmony_ci return ret; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); 888c2ecf20Sopenharmony_ci if (ret) 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); 928c2ecf20Sopenharmony_ci if (ret) 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); 968c2ecf20Sopenharmony_ci if (ret) 978c2ecf20Sopenharmony_ci return ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, 1008c2ecf20Sopenharmony_ci lot3, serial); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return simple_read_from_buffer(userbuf, count, ppos, buf, len); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const struct file_operations adis16136_serial_fops = { 1068c2ecf20Sopenharmony_ci .open = simple_open, 1078c2ecf20Sopenharmony_ci .read = adis16136_show_serial, 1088c2ecf20Sopenharmony_ci .llseek = default_llseek, 1098c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int adis16136_show_product_id(void *arg, u64 *val) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = arg; 1158c2ecf20Sopenharmony_ci u16 prod_id; 1168c2ecf20Sopenharmony_ci int ret; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, 1198c2ecf20Sopenharmony_ci &prod_id); 1208c2ecf20Sopenharmony_ci if (ret) 1218c2ecf20Sopenharmony_ci return ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci *val = prod_id; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16136_product_id_fops, 1288c2ecf20Sopenharmony_ci adis16136_show_product_id, NULL, "%llu\n"); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int adis16136_show_flash_count(void *arg, u64 *val) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = arg; 1338c2ecf20Sopenharmony_ci uint16_t flash_count; 1348c2ecf20Sopenharmony_ci int ret; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, 1378c2ecf20Sopenharmony_ci &flash_count); 1388c2ecf20Sopenharmony_ci if (ret) 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci *val = flash_count; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(adis16136_flash_count_fops, 1468c2ecf20Sopenharmony_ci adis16136_show_flash_count, NULL, "%lld\n"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int adis16136_debugfs_init(struct iio_dev *indio_dev) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 1518c2ecf20Sopenharmony_ci struct dentry *d = iio_get_debugfs_dentry(indio_dev); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci debugfs_create_file_unsafe("serial_number", 0400, 1548c2ecf20Sopenharmony_ci d, adis16136, &adis16136_serial_fops); 1558c2ecf20Sopenharmony_ci debugfs_create_file_unsafe("product_id", 0400, 1568c2ecf20Sopenharmony_ci d, adis16136, &adis16136_product_id_fops); 1578c2ecf20Sopenharmony_ci debugfs_create_file_unsafe("flash_count", 0400, 1588c2ecf20Sopenharmony_ci d, adis16136, &adis16136_flash_count_fops); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#else 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int adis16136_debugfs_init(struct iio_dev *indio_dev) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#endif 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned int t; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci t = 32768 / freq; 1778c2ecf20Sopenharmony_ci if (t < 0xf) 1788c2ecf20Sopenharmony_ci t = 0xf; 1798c2ecf20Sopenharmony_ci else if (t > 0xffff) 1808c2ecf20Sopenharmony_ci t = 0xffff; 1818c2ecf20Sopenharmony_ci else 1828c2ecf20Sopenharmony_ci t--; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci uint16_t t; 1908c2ecf20Sopenharmony_ci int ret; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); 1938c2ecf20Sopenharmony_ci if (ret) 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci *freq = 32768 / (t + 1); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic ssize_t adis16136_write_frequency(struct device *dev, 2028c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t len) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2058c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 2068c2ecf20Sopenharmony_ci unsigned int val; 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 10, &val); 2108c2ecf20Sopenharmony_ci if (ret) 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (val == 0) 2148c2ecf20Sopenharmony_ci return -EINVAL; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci ret = adis16136_set_freq(adis16136, val); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return ret ? ret : len; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t adis16136_read_frequency(struct device *dev, 2228c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2258c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 2268c2ecf20Sopenharmony_ci struct mutex *slock = &adis16136->adis.state_lock; 2278c2ecf20Sopenharmony_ci unsigned int freq; 2288c2ecf20Sopenharmony_ci int ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci mutex_lock(slock); 2318c2ecf20Sopenharmony_ci ret = __adis16136_get_freq(adis16136, &freq); 2328c2ecf20Sopenharmony_ci mutex_unlock(slock); 2338c2ecf20Sopenharmony_ci if (ret) 2348c2ecf20Sopenharmony_ci return ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", freq); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, 2408c2ecf20Sopenharmony_ci adis16136_read_frequency, 2418c2ecf20Sopenharmony_ci adis16136_write_frequency); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic const unsigned adis16136_3db_divisors[] = { 2448c2ecf20Sopenharmony_ci [0] = 2, /* Special case */ 2458c2ecf20Sopenharmony_ci [1] = 6, 2468c2ecf20Sopenharmony_ci [2] = 12, 2478c2ecf20Sopenharmony_ci [3] = 25, 2488c2ecf20Sopenharmony_ci [4] = 50, 2498c2ecf20Sopenharmony_ci [5] = 100, 2508c2ecf20Sopenharmony_ci [6] = 200, 2518c2ecf20Sopenharmony_ci [7] = 200, /* Not a valid setting */ 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int adis16136_set_filter(struct iio_dev *indio_dev, int val) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 2578c2ecf20Sopenharmony_ci struct mutex *slock = &adis16136->adis.state_lock; 2588c2ecf20Sopenharmony_ci unsigned int freq; 2598c2ecf20Sopenharmony_ci int i, ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci mutex_lock(slock); 2628c2ecf20Sopenharmony_ci ret = __adis16136_get_freq(adis16136, &freq); 2638c2ecf20Sopenharmony_ci if (ret) 2648c2ecf20Sopenharmony_ci goto out_unlock; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { 2678c2ecf20Sopenharmony_ci if (freq / adis16136_3db_divisors[i] >= val) 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); 2728c2ecf20Sopenharmony_ciout_unlock: 2738c2ecf20Sopenharmony_ci mutex_unlock(slock); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return ret; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int adis16136_get_filter(struct iio_dev *indio_dev, int *val) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 2818c2ecf20Sopenharmony_ci struct mutex *slock = &adis16136->adis.state_lock; 2828c2ecf20Sopenharmony_ci unsigned int freq; 2838c2ecf20Sopenharmony_ci uint16_t val16; 2848c2ecf20Sopenharmony_ci int ret; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci mutex_lock(slock); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, 2898c2ecf20Sopenharmony_ci &val16); 2908c2ecf20Sopenharmony_ci if (ret) 2918c2ecf20Sopenharmony_ci goto err_unlock; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci ret = __adis16136_get_freq(adis16136, &freq); 2948c2ecf20Sopenharmony_ci if (ret) 2958c2ecf20Sopenharmony_ci goto err_unlock; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci *val = freq / adis16136_3db_divisors[val16 & 0x07]; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cierr_unlock: 3008c2ecf20Sopenharmony_ci mutex_unlock(slock); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return ret ? ret : IIO_VAL_INT; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int adis16136_read_raw(struct iio_dev *indio_dev, 3068c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, int *val, int *val2, long info) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 3098c2ecf20Sopenharmony_ci uint32_t val32; 3108c2ecf20Sopenharmony_ci int ret; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci switch (info) { 3138c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3148c2ecf20Sopenharmony_ci return adis_single_conversion(indio_dev, chan, 0, val); 3158c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3168c2ecf20Sopenharmony_ci switch (chan->type) { 3178c2ecf20Sopenharmony_ci case IIO_ANGL_VEL: 3188c2ecf20Sopenharmony_ci *val = adis16136->chip_info->precision; 3198c2ecf20Sopenharmony_ci *val2 = (adis16136->chip_info->fullscale << 16); 3208c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL; 3218c2ecf20Sopenharmony_ci case IIO_TEMP: 3228c2ecf20Sopenharmony_ci *val = 10; 3238c2ecf20Sopenharmony_ci *val2 = 697000; /* 0.010697 degree Celsius */ 3248c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 3258c2ecf20Sopenharmony_ci default: 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 3298c2ecf20Sopenharmony_ci ret = adis_read_reg_32(&adis16136->adis, 3308c2ecf20Sopenharmony_ci ADIS16136_REG_GYRO_OFF2, &val32); 3318c2ecf20Sopenharmony_ci if (ret) 3328c2ecf20Sopenharmony_ci return ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci *val = sign_extend32(val32, 31); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return IIO_VAL_INT; 3378c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 3388c2ecf20Sopenharmony_ci return adis16136_get_filter(indio_dev, val); 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int adis16136_write_raw(struct iio_dev *indio_dev, 3458c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, int val, int val2, long info) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci switch (info) { 3508c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_CALIBBIAS: 3518c2ecf20Sopenharmony_ci return adis_write_reg_32(&adis16136->adis, 3528c2ecf20Sopenharmony_ci ADIS16136_REG_GYRO_OFF2, val); 3538c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 3548c2ecf20Sopenharmony_ci return adis16136_set_filter(indio_dev, val); 3558c2ecf20Sopenharmony_ci default: 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cienum { 3638c2ecf20Sopenharmony_ci ADIS16136_SCAN_GYRO, 3648c2ecf20Sopenharmony_ci ADIS16136_SCAN_TEMP, 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct iio_chan_spec adis16136_channels[] = { 3688c2ecf20Sopenharmony_ci { 3698c2ecf20Sopenharmony_ci .type = IIO_ANGL_VEL, 3708c2ecf20Sopenharmony_ci .modified = 1, 3718c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_X, 3728c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 3738c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_CALIBBIAS) | 3748c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), 3758c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci .address = ADIS16136_REG_GYRO_OUT2, 3788c2ecf20Sopenharmony_ci .scan_index = ADIS16136_SCAN_GYRO, 3798c2ecf20Sopenharmony_ci .scan_type = { 3808c2ecf20Sopenharmony_ci .sign = 's', 3818c2ecf20Sopenharmony_ci .realbits = 32, 3828c2ecf20Sopenharmony_ci .storagebits = 32, 3838c2ecf20Sopenharmony_ci .endianness = IIO_BE, 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci }, { 3868c2ecf20Sopenharmony_ci .type = IIO_TEMP, 3878c2ecf20Sopenharmony_ci .indexed = 1, 3888c2ecf20Sopenharmony_ci .channel = 0, 3898c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 3908c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), 3918c2ecf20Sopenharmony_ci .address = ADIS16136_REG_TEMP_OUT, 3928c2ecf20Sopenharmony_ci .scan_index = ADIS16136_SCAN_TEMP, 3938c2ecf20Sopenharmony_ci .scan_type = { 3948c2ecf20Sopenharmony_ci .sign = 's', 3958c2ecf20Sopenharmony_ci .realbits = 16, 3968c2ecf20Sopenharmony_ci .storagebits = 16, 3978c2ecf20Sopenharmony_ci .endianness = IIO_BE, 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci }, 4008c2ecf20Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(2), 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic struct attribute *adis16136_attributes[] = { 4048c2ecf20Sopenharmony_ci &iio_dev_attr_sampling_frequency.dev_attr.attr, 4058c2ecf20Sopenharmony_ci NULL 4068c2ecf20Sopenharmony_ci}; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic const struct attribute_group adis16136_attribute_group = { 4098c2ecf20Sopenharmony_ci .attrs = adis16136_attributes, 4108c2ecf20Sopenharmony_ci}; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic const struct iio_info adis16136_info = { 4138c2ecf20Sopenharmony_ci .attrs = &adis16136_attribute_group, 4148c2ecf20Sopenharmony_ci .read_raw = &adis16136_read_raw, 4158c2ecf20Sopenharmony_ci .write_raw = &adis16136_write_raw, 4168c2ecf20Sopenharmony_ci .update_scan_mode = adis_update_scan_mode, 4178c2ecf20Sopenharmony_ci .debugfs_reg_access = adis_debugfs_reg_access, 4188c2ecf20Sopenharmony_ci}; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int adis16136_stop_device(struct iio_dev *indio_dev) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 4238c2ecf20Sopenharmony_ci int ret; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci dev_err(&indio_dev->dev, 4288c2ecf20Sopenharmony_ci "Could not power down device: %d\n", ret); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int adis16136_initial_setup(struct iio_dev *indio_dev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct adis16136 *adis16136 = iio_priv(indio_dev); 4368c2ecf20Sopenharmony_ci unsigned int device_id; 4378c2ecf20Sopenharmony_ci uint16_t prod_id; 4388c2ecf20Sopenharmony_ci int ret; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ret = adis_initial_startup(&adis16136->adis); 4418c2ecf20Sopenharmony_ci if (ret) 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, 4458c2ecf20Sopenharmony_ci &prod_id); 4468c2ecf20Sopenharmony_ci if (ret) 4478c2ecf20Sopenharmony_ci return ret; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret = sscanf(indio_dev->name, "adis%u\n", &device_id); 4508c2ecf20Sopenharmony_ci if (ret != 1) 4518c2ecf20Sopenharmony_ci return -EINVAL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (prod_id != device_id) 4548c2ecf20Sopenharmony_ci dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", 4558c2ecf20Sopenharmony_ci device_id, prod_id); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic const char * const adis16136_status_error_msgs[] = { 4618c2ecf20Sopenharmony_ci [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", 4628c2ecf20Sopenharmony_ci [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", 4638c2ecf20Sopenharmony_ci [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", 4648c2ecf20Sopenharmony_ci [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", 4658c2ecf20Sopenharmony_ci}; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci#define ADIS16136_DATA(_timeouts) \ 4688c2ecf20Sopenharmony_ci{ \ 4698c2ecf20Sopenharmony_ci .diag_stat_reg = ADIS16136_REG_DIAG_STAT, \ 4708c2ecf20Sopenharmony_ci .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, \ 4718c2ecf20Sopenharmony_ci .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, \ 4728c2ecf20Sopenharmony_ci .self_test_reg = ADIS16136_REG_MSC_CTRL, \ 4738c2ecf20Sopenharmony_ci .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, \ 4748c2ecf20Sopenharmony_ci .read_delay = 10, \ 4758c2ecf20Sopenharmony_ci .write_delay = 10, \ 4768c2ecf20Sopenharmony_ci .status_error_msgs = adis16136_status_error_msgs, \ 4778c2ecf20Sopenharmony_ci .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | \ 4788c2ecf20Sopenharmony_ci BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | \ 4798c2ecf20Sopenharmony_ci BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | \ 4808c2ecf20Sopenharmony_ci BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), \ 4818c2ecf20Sopenharmony_ci .timeouts = (_timeouts), \ 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cienum adis16136_id { 4858c2ecf20Sopenharmony_ci ID_ADIS16133, 4868c2ecf20Sopenharmony_ci ID_ADIS16135, 4878c2ecf20Sopenharmony_ci ID_ADIS16136, 4888c2ecf20Sopenharmony_ci ID_ADIS16137, 4898c2ecf20Sopenharmony_ci}; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic const struct adis_timeout adis16133_timeouts = { 4928c2ecf20Sopenharmony_ci .reset_ms = 75, 4938c2ecf20Sopenharmony_ci .sw_reset_ms = 75, 4948c2ecf20Sopenharmony_ci .self_test_ms = 50, 4958c2ecf20Sopenharmony_ci}; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic const struct adis_timeout adis16136_timeouts = { 4988c2ecf20Sopenharmony_ci .reset_ms = 128, 4998c2ecf20Sopenharmony_ci .sw_reset_ms = 75, 5008c2ecf20Sopenharmony_ci .self_test_ms = 245, 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic const struct adis16136_chip_info adis16136_chip_info[] = { 5048c2ecf20Sopenharmony_ci [ID_ADIS16133] = { 5058c2ecf20Sopenharmony_ci .precision = IIO_DEGREE_TO_RAD(1200), 5068c2ecf20Sopenharmony_ci .fullscale = 24000, 5078c2ecf20Sopenharmony_ci .adis_data = ADIS16136_DATA(&adis16133_timeouts), 5088c2ecf20Sopenharmony_ci }, 5098c2ecf20Sopenharmony_ci [ID_ADIS16135] = { 5108c2ecf20Sopenharmony_ci .precision = IIO_DEGREE_TO_RAD(300), 5118c2ecf20Sopenharmony_ci .fullscale = 24000, 5128c2ecf20Sopenharmony_ci .adis_data = ADIS16136_DATA(&adis16133_timeouts), 5138c2ecf20Sopenharmony_ci }, 5148c2ecf20Sopenharmony_ci [ID_ADIS16136] = { 5158c2ecf20Sopenharmony_ci .precision = IIO_DEGREE_TO_RAD(450), 5168c2ecf20Sopenharmony_ci .fullscale = 24623, 5178c2ecf20Sopenharmony_ci .adis_data = ADIS16136_DATA(&adis16136_timeouts), 5188c2ecf20Sopenharmony_ci }, 5198c2ecf20Sopenharmony_ci [ID_ADIS16137] = { 5208c2ecf20Sopenharmony_ci .precision = IIO_DEGREE_TO_RAD(1000), 5218c2ecf20Sopenharmony_ci .fullscale = 24609, 5228c2ecf20Sopenharmony_ci .adis_data = ADIS16136_DATA(&adis16136_timeouts), 5238c2ecf20Sopenharmony_ci }, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void adis16136_stop(void *data) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci adis16136_stop_device(data); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int adis16136_probe(struct spi_device *spi) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 5348c2ecf20Sopenharmony_ci struct adis16136 *adis16136; 5358c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 5368c2ecf20Sopenharmony_ci const struct adis_data *adis16136_data; 5378c2ecf20Sopenharmony_ci int ret; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136)); 5408c2ecf20Sopenharmony_ci if (indio_dev == NULL) 5418c2ecf20Sopenharmony_ci return -ENOMEM; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci spi_set_drvdata(spi, indio_dev); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci adis16136 = iio_priv(indio_dev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci adis16136->chip_info = &adis16136_chip_info[id->driver_data]; 5488c2ecf20Sopenharmony_ci indio_dev->name = spi_get_device_id(spi)->name; 5498c2ecf20Sopenharmony_ci indio_dev->channels = adis16136_channels; 5508c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); 5518c2ecf20Sopenharmony_ci indio_dev->info = &adis16136_info; 5528c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci adis16136_data = &adis16136->chip_info->adis_data; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data); 5578c2ecf20Sopenharmony_ci if (ret) 5588c2ecf20Sopenharmony_ci return ret; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci ret = devm_adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); 5618c2ecf20Sopenharmony_ci if (ret) 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = adis16136_initial_setup(indio_dev); 5658c2ecf20Sopenharmony_ci if (ret) 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(&spi->dev, adis16136_stop, indio_dev); 5698c2ecf20Sopenharmony_ci if (ret) 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci ret = devm_iio_device_register(&spi->dev, indio_dev); 5738c2ecf20Sopenharmony_ci if (ret) 5748c2ecf20Sopenharmony_ci return ret; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci adis16136_debugfs_init(indio_dev); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic const struct spi_device_id adis16136_ids[] = { 5828c2ecf20Sopenharmony_ci { "adis16133", ID_ADIS16133 }, 5838c2ecf20Sopenharmony_ci { "adis16135", ID_ADIS16135 }, 5848c2ecf20Sopenharmony_ci { "adis16136", ID_ADIS16136 }, 5858c2ecf20Sopenharmony_ci { "adis16137", ID_ADIS16137 }, 5868c2ecf20Sopenharmony_ci { } 5878c2ecf20Sopenharmony_ci}; 5888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adis16136_ids); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic struct spi_driver adis16136_driver = { 5918c2ecf20Sopenharmony_ci .driver = { 5928c2ecf20Sopenharmony_ci .name = "adis16136", 5938c2ecf20Sopenharmony_ci }, 5948c2ecf20Sopenharmony_ci .id_table = adis16136_ids, 5958c2ecf20Sopenharmony_ci .probe = adis16136_probe, 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_cimodule_spi_driver(adis16136_driver); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 6008c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); 6018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6028c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(IIO_ADISLIB); 603