1*9caed0d9SLars-Peter Clausen /* 2*9caed0d9SLars-Peter Clausen * ADIS16133/ADIS16135/ADIS16136 gyroscope driver 3*9caed0d9SLars-Peter Clausen * 4*9caed0d9SLars-Peter Clausen * Copyright 2012 Analog Devices Inc. 5*9caed0d9SLars-Peter Clausen * Author: Lars-Peter Clausen <lars@metafoo.de> 6*9caed0d9SLars-Peter Clausen * 7*9caed0d9SLars-Peter Clausen * Licensed under the GPL-2. 8*9caed0d9SLars-Peter Clausen */ 9*9caed0d9SLars-Peter Clausen 10*9caed0d9SLars-Peter Clausen #include <linux/interrupt.h> 11*9caed0d9SLars-Peter Clausen #include <linux/delay.h> 12*9caed0d9SLars-Peter Clausen #include <linux/mutex.h> 13*9caed0d9SLars-Peter Clausen #include <linux/device.h> 14*9caed0d9SLars-Peter Clausen #include <linux/kernel.h> 15*9caed0d9SLars-Peter Clausen #include <linux/spi/spi.h> 16*9caed0d9SLars-Peter Clausen #include <linux/slab.h> 17*9caed0d9SLars-Peter Clausen #include <linux/sysfs.h> 18*9caed0d9SLars-Peter Clausen #include <linux/module.h> 19*9caed0d9SLars-Peter Clausen 20*9caed0d9SLars-Peter Clausen #include <linux/iio/iio.h> 21*9caed0d9SLars-Peter Clausen #include <linux/iio/sysfs.h> 22*9caed0d9SLars-Peter Clausen #include <linux/iio/buffer.h> 23*9caed0d9SLars-Peter Clausen #include <linux/iio/imu/adis.h> 24*9caed0d9SLars-Peter Clausen 25*9caed0d9SLars-Peter Clausen #include <linux/iio/iio.h> 26*9caed0d9SLars-Peter Clausen #include <linux/debugfs.h> 27*9caed0d9SLars-Peter Clausen 28*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_FLASH_CNT 0x00 29*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_TEMP_OUT 0x02 30*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OUT2 0x04 31*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OUT 0x06 32*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OFF2 0x08 33*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GYRO_OFF 0x0A 34*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_MAG1 0x10 35*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_MAG2 0x12 36*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_SAMPL1 0x14 37*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_SAMPL2 0x16 38*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_ALM_CTRL 0x18 39*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GPIO_CTRL 0x1A 40*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_MSC_CTRL 0x1C 41*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SMPL_PRD 0x1E 42*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_AVG_CNT 0x20 43*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_DEC_RATE 0x22 44*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SLP_CTRL 0x24 45*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_DIAG_STAT 0x26 46*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_GLOB_CMD 0x28 47*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT1 0x32 48*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT2 0x34 49*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_LOT3 0x36 50*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_PROD_ID 0x38 51*9caed0d9SLars-Peter Clausen #define ADIS16136_REG_SERIAL_NUM 0x3A 52*9caed0d9SLars-Peter Clausen 53*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2 54*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_SPI_FAIL 3 55*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5 56*9caed0d9SLars-Peter Clausen #define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6 57*9caed0d9SLars-Peter Clausen 58*9caed0d9SLars-Peter Clausen #define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11) 59*9caed0d9SLars-Peter Clausen #define ADIS16136_MSC_CTRL_SELF_TEST BIT(10) 60*9caed0d9SLars-Peter Clausen 61*9caed0d9SLars-Peter Clausen struct adis16136_chip_info { 62*9caed0d9SLars-Peter Clausen unsigned int precision; 63*9caed0d9SLars-Peter Clausen unsigned int fullscale; 64*9caed0d9SLars-Peter Clausen }; 65*9caed0d9SLars-Peter Clausen 66*9caed0d9SLars-Peter Clausen struct adis16136 { 67*9caed0d9SLars-Peter Clausen const struct adis16136_chip_info *chip_info; 68*9caed0d9SLars-Peter Clausen 69*9caed0d9SLars-Peter Clausen struct adis adis; 70*9caed0d9SLars-Peter Clausen }; 71*9caed0d9SLars-Peter Clausen 72*9caed0d9SLars-Peter Clausen #ifdef CONFIG_DEBUG_FS 73*9caed0d9SLars-Peter Clausen 74*9caed0d9SLars-Peter Clausen static ssize_t adis16136_show_serial(struct file *file, 75*9caed0d9SLars-Peter Clausen char __user *userbuf, size_t count, loff_t *ppos) 76*9caed0d9SLars-Peter Clausen { 77*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = file->private_data; 78*9caed0d9SLars-Peter Clausen uint16_t lot1, lot2, lot3, serial; 79*9caed0d9SLars-Peter Clausen char buf[20]; 80*9caed0d9SLars-Peter Clausen size_t len; 81*9caed0d9SLars-Peter Clausen int ret; 82*9caed0d9SLars-Peter Clausen 83*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, 84*9caed0d9SLars-Peter Clausen &serial); 85*9caed0d9SLars-Peter Clausen if (ret < 0) 86*9caed0d9SLars-Peter Clausen return ret; 87*9caed0d9SLars-Peter Clausen 88*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); 89*9caed0d9SLars-Peter Clausen if (ret < 0) 90*9caed0d9SLars-Peter Clausen return ret; 91*9caed0d9SLars-Peter Clausen 92*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); 93*9caed0d9SLars-Peter Clausen if (ret < 0) 94*9caed0d9SLars-Peter Clausen return ret; 95*9caed0d9SLars-Peter Clausen 96*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); 97*9caed0d9SLars-Peter Clausen if (ret < 0) 98*9caed0d9SLars-Peter Clausen return ret; 99*9caed0d9SLars-Peter Clausen 100*9caed0d9SLars-Peter Clausen len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, 101*9caed0d9SLars-Peter Clausen lot3, serial); 102*9caed0d9SLars-Peter Clausen 103*9caed0d9SLars-Peter Clausen return simple_read_from_buffer(userbuf, count, ppos, buf, len); 104*9caed0d9SLars-Peter Clausen } 105*9caed0d9SLars-Peter Clausen 106*9caed0d9SLars-Peter Clausen static const struct file_operations adis16136_serial_fops = { 107*9caed0d9SLars-Peter Clausen .open = simple_open, 108*9caed0d9SLars-Peter Clausen .read = adis16136_show_serial, 109*9caed0d9SLars-Peter Clausen .llseek = default_llseek, 110*9caed0d9SLars-Peter Clausen .owner = THIS_MODULE, 111*9caed0d9SLars-Peter Clausen }; 112*9caed0d9SLars-Peter Clausen 113*9caed0d9SLars-Peter Clausen static int adis16136_show_product_id(void *arg, u64 *val) 114*9caed0d9SLars-Peter Clausen { 115*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = arg; 116*9caed0d9SLars-Peter Clausen u16 prod_id; 117*9caed0d9SLars-Peter Clausen int ret; 118*9caed0d9SLars-Peter Clausen 119*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, 120*9caed0d9SLars-Peter Clausen &prod_id); 121*9caed0d9SLars-Peter Clausen if (ret < 0) 122*9caed0d9SLars-Peter Clausen return ret; 123*9caed0d9SLars-Peter Clausen 124*9caed0d9SLars-Peter Clausen *val = prod_id; 125*9caed0d9SLars-Peter Clausen 126*9caed0d9SLars-Peter Clausen return 0; 127*9caed0d9SLars-Peter Clausen } 128*9caed0d9SLars-Peter Clausen DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops, 129*9caed0d9SLars-Peter Clausen adis16136_show_product_id, NULL, "%llu\n"); 130*9caed0d9SLars-Peter Clausen 131*9caed0d9SLars-Peter Clausen static int adis16136_show_flash_count(void *arg, u64 *val) 132*9caed0d9SLars-Peter Clausen { 133*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = arg; 134*9caed0d9SLars-Peter Clausen uint16_t flash_count; 135*9caed0d9SLars-Peter Clausen int ret; 136*9caed0d9SLars-Peter Clausen 137*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, 138*9caed0d9SLars-Peter Clausen &flash_count); 139*9caed0d9SLars-Peter Clausen if (ret < 0) 140*9caed0d9SLars-Peter Clausen return ret; 141*9caed0d9SLars-Peter Clausen 142*9caed0d9SLars-Peter Clausen *val = flash_count; 143*9caed0d9SLars-Peter Clausen 144*9caed0d9SLars-Peter Clausen return 0; 145*9caed0d9SLars-Peter Clausen } 146*9caed0d9SLars-Peter Clausen DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops, 147*9caed0d9SLars-Peter Clausen adis16136_show_flash_count, NULL, "%lld\n"); 148*9caed0d9SLars-Peter Clausen 149*9caed0d9SLars-Peter Clausen static int adis16136_debugfs_init(struct iio_dev *indio_dev) 150*9caed0d9SLars-Peter Clausen { 151*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 152*9caed0d9SLars-Peter Clausen 153*9caed0d9SLars-Peter Clausen debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, 154*9caed0d9SLars-Peter Clausen adis16136, &adis16136_serial_fops); 155*9caed0d9SLars-Peter Clausen debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, 156*9caed0d9SLars-Peter Clausen adis16136, &adis16136_product_id_fops); 157*9caed0d9SLars-Peter Clausen debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, 158*9caed0d9SLars-Peter Clausen adis16136, &adis16136_flash_count_fops); 159*9caed0d9SLars-Peter Clausen 160*9caed0d9SLars-Peter Clausen return 0; 161*9caed0d9SLars-Peter Clausen } 162*9caed0d9SLars-Peter Clausen 163*9caed0d9SLars-Peter Clausen #else 164*9caed0d9SLars-Peter Clausen 165*9caed0d9SLars-Peter Clausen static int adis16136_debugfs_init(struct iio_dev *indio_dev) 166*9caed0d9SLars-Peter Clausen { 167*9caed0d9SLars-Peter Clausen return 0; 168*9caed0d9SLars-Peter Clausen } 169*9caed0d9SLars-Peter Clausen 170*9caed0d9SLars-Peter Clausen #endif 171*9caed0d9SLars-Peter Clausen 172*9caed0d9SLars-Peter Clausen static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) 173*9caed0d9SLars-Peter Clausen { 174*9caed0d9SLars-Peter Clausen unsigned int t; 175*9caed0d9SLars-Peter Clausen 176*9caed0d9SLars-Peter Clausen t = 32768 / freq; 177*9caed0d9SLars-Peter Clausen if (t < 0xf) 178*9caed0d9SLars-Peter Clausen t = 0xf; 179*9caed0d9SLars-Peter Clausen else if (t > 0xffff) 180*9caed0d9SLars-Peter Clausen t = 0xffff; 181*9caed0d9SLars-Peter Clausen else 182*9caed0d9SLars-Peter Clausen t--; 183*9caed0d9SLars-Peter Clausen 184*9caed0d9SLars-Peter Clausen return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); 185*9caed0d9SLars-Peter Clausen } 186*9caed0d9SLars-Peter Clausen 187*9caed0d9SLars-Peter Clausen static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) 188*9caed0d9SLars-Peter Clausen { 189*9caed0d9SLars-Peter Clausen uint16_t t; 190*9caed0d9SLars-Peter Clausen int ret; 191*9caed0d9SLars-Peter Clausen 192*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); 193*9caed0d9SLars-Peter Clausen if (ret < 0) 194*9caed0d9SLars-Peter Clausen return ret; 195*9caed0d9SLars-Peter Clausen 196*9caed0d9SLars-Peter Clausen *freq = 32768 / (t + 1); 197*9caed0d9SLars-Peter Clausen 198*9caed0d9SLars-Peter Clausen return 0; 199*9caed0d9SLars-Peter Clausen } 200*9caed0d9SLars-Peter Clausen 201*9caed0d9SLars-Peter Clausen static ssize_t adis16136_write_frequency(struct device *dev, 202*9caed0d9SLars-Peter Clausen struct device_attribute *attr, const char *buf, size_t len) 203*9caed0d9SLars-Peter Clausen { 204*9caed0d9SLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev); 205*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 206*9caed0d9SLars-Peter Clausen long val; 207*9caed0d9SLars-Peter Clausen int ret; 208*9caed0d9SLars-Peter Clausen 209*9caed0d9SLars-Peter Clausen ret = kstrtol(buf, 10, &val); 210*9caed0d9SLars-Peter Clausen if (ret) 211*9caed0d9SLars-Peter Clausen return ret; 212*9caed0d9SLars-Peter Clausen 213*9caed0d9SLars-Peter Clausen if (val == 0) 214*9caed0d9SLars-Peter Clausen return -EINVAL; 215*9caed0d9SLars-Peter Clausen 216*9caed0d9SLars-Peter Clausen ret = adis16136_set_freq(adis16136, val); 217*9caed0d9SLars-Peter Clausen 218*9caed0d9SLars-Peter Clausen return ret ? ret : len; 219*9caed0d9SLars-Peter Clausen } 220*9caed0d9SLars-Peter Clausen 221*9caed0d9SLars-Peter Clausen static ssize_t adis16136_read_frequency(struct device *dev, 222*9caed0d9SLars-Peter Clausen struct device_attribute *attr, char *buf) 223*9caed0d9SLars-Peter Clausen { 224*9caed0d9SLars-Peter Clausen struct iio_dev *indio_dev = dev_to_iio_dev(dev); 225*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 226*9caed0d9SLars-Peter Clausen unsigned int freq; 227*9caed0d9SLars-Peter Clausen int ret; 228*9caed0d9SLars-Peter Clausen 229*9caed0d9SLars-Peter Clausen ret = adis16136_get_freq(adis16136, &freq); 230*9caed0d9SLars-Peter Clausen if (ret < 0) 231*9caed0d9SLars-Peter Clausen return ret; 232*9caed0d9SLars-Peter Clausen 233*9caed0d9SLars-Peter Clausen return sprintf(buf, "%d\n", freq); 234*9caed0d9SLars-Peter Clausen } 235*9caed0d9SLars-Peter Clausen 236*9caed0d9SLars-Peter Clausen static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, 237*9caed0d9SLars-Peter Clausen adis16136_read_frequency, 238*9caed0d9SLars-Peter Clausen adis16136_write_frequency); 239*9caed0d9SLars-Peter Clausen 240*9caed0d9SLars-Peter Clausen static const unsigned adis16136_3db_divisors[] = { 241*9caed0d9SLars-Peter Clausen [0] = 2, /* Special case */ 242*9caed0d9SLars-Peter Clausen [1] = 6, 243*9caed0d9SLars-Peter Clausen [2] = 12, 244*9caed0d9SLars-Peter Clausen [3] = 25, 245*9caed0d9SLars-Peter Clausen [4] = 50, 246*9caed0d9SLars-Peter Clausen [5] = 100, 247*9caed0d9SLars-Peter Clausen [6] = 200, 248*9caed0d9SLars-Peter Clausen [7] = 200, /* Not a valid setting */ 249*9caed0d9SLars-Peter Clausen }; 250*9caed0d9SLars-Peter Clausen 251*9caed0d9SLars-Peter Clausen static int adis16136_set_filter(struct iio_dev *indio_dev, int val) 252*9caed0d9SLars-Peter Clausen { 253*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 254*9caed0d9SLars-Peter Clausen unsigned int freq; 255*9caed0d9SLars-Peter Clausen int i, ret; 256*9caed0d9SLars-Peter Clausen 257*9caed0d9SLars-Peter Clausen ret = adis16136_get_freq(adis16136, &freq); 258*9caed0d9SLars-Peter Clausen if (ret < 0) 259*9caed0d9SLars-Peter Clausen return ret; 260*9caed0d9SLars-Peter Clausen 261*9caed0d9SLars-Peter Clausen for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { 262*9caed0d9SLars-Peter Clausen if (freq / adis16136_3db_divisors[i] >= val) 263*9caed0d9SLars-Peter Clausen break; 264*9caed0d9SLars-Peter Clausen } 265*9caed0d9SLars-Peter Clausen 266*9caed0d9SLars-Peter Clausen return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); 267*9caed0d9SLars-Peter Clausen } 268*9caed0d9SLars-Peter Clausen 269*9caed0d9SLars-Peter Clausen static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) 270*9caed0d9SLars-Peter Clausen { 271*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 272*9caed0d9SLars-Peter Clausen unsigned int freq; 273*9caed0d9SLars-Peter Clausen uint16_t val16; 274*9caed0d9SLars-Peter Clausen int ret; 275*9caed0d9SLars-Peter Clausen 276*9caed0d9SLars-Peter Clausen mutex_lock(&indio_dev->mlock); 277*9caed0d9SLars-Peter Clausen 278*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); 279*9caed0d9SLars-Peter Clausen if (ret < 0) 280*9caed0d9SLars-Peter Clausen goto err_unlock; 281*9caed0d9SLars-Peter Clausen 282*9caed0d9SLars-Peter Clausen ret = adis16136_get_freq(adis16136, &freq); 283*9caed0d9SLars-Peter Clausen if (ret < 0) 284*9caed0d9SLars-Peter Clausen goto err_unlock; 285*9caed0d9SLars-Peter Clausen 286*9caed0d9SLars-Peter Clausen *val = freq / adis16136_3db_divisors[val16 & 0x07]; 287*9caed0d9SLars-Peter Clausen 288*9caed0d9SLars-Peter Clausen err_unlock: 289*9caed0d9SLars-Peter Clausen mutex_unlock(&indio_dev->mlock); 290*9caed0d9SLars-Peter Clausen 291*9caed0d9SLars-Peter Clausen return ret ? ret : IIO_VAL_INT; 292*9caed0d9SLars-Peter Clausen } 293*9caed0d9SLars-Peter Clausen 294*9caed0d9SLars-Peter Clausen static int adis16136_read_raw(struct iio_dev *indio_dev, 295*9caed0d9SLars-Peter Clausen const struct iio_chan_spec *chan, int *val, int *val2, long info) 296*9caed0d9SLars-Peter Clausen { 297*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 298*9caed0d9SLars-Peter Clausen uint32_t val32; 299*9caed0d9SLars-Peter Clausen int ret; 300*9caed0d9SLars-Peter Clausen 301*9caed0d9SLars-Peter Clausen switch (info) { 302*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_RAW: 303*9caed0d9SLars-Peter Clausen return adis_single_conversion(indio_dev, chan, 0, val); 304*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_SCALE: 305*9caed0d9SLars-Peter Clausen switch (chan->type) { 306*9caed0d9SLars-Peter Clausen case IIO_ANGL_VEL: 307*9caed0d9SLars-Peter Clausen *val = adis16136->chip_info->precision; 308*9caed0d9SLars-Peter Clausen *val2 = (adis16136->chip_info->fullscale << 16); 309*9caed0d9SLars-Peter Clausen return IIO_VAL_FRACTIONAL; 310*9caed0d9SLars-Peter Clausen case IIO_TEMP: 311*9caed0d9SLars-Peter Clausen *val = 10; 312*9caed0d9SLars-Peter Clausen *val2 = 697000; /* 0.010697 degree Celsius */ 313*9caed0d9SLars-Peter Clausen return IIO_VAL_INT_PLUS_MICRO; 314*9caed0d9SLars-Peter Clausen default: 315*9caed0d9SLars-Peter Clausen return -EINVAL; 316*9caed0d9SLars-Peter Clausen } 317*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_CALIBBIAS: 318*9caed0d9SLars-Peter Clausen ret = adis_read_reg_32(&adis16136->adis, 319*9caed0d9SLars-Peter Clausen ADIS16136_REG_GYRO_OFF2, &val32); 320*9caed0d9SLars-Peter Clausen if (ret < 0) 321*9caed0d9SLars-Peter Clausen return ret; 322*9caed0d9SLars-Peter Clausen 323*9caed0d9SLars-Peter Clausen *val = sign_extend32(val32, 31); 324*9caed0d9SLars-Peter Clausen 325*9caed0d9SLars-Peter Clausen return IIO_VAL_INT; 326*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 327*9caed0d9SLars-Peter Clausen return adis16136_get_filter(indio_dev, val); 328*9caed0d9SLars-Peter Clausen default: 329*9caed0d9SLars-Peter Clausen return -EINVAL; 330*9caed0d9SLars-Peter Clausen } 331*9caed0d9SLars-Peter Clausen } 332*9caed0d9SLars-Peter Clausen 333*9caed0d9SLars-Peter Clausen static int adis16136_write_raw(struct iio_dev *indio_dev, 334*9caed0d9SLars-Peter Clausen const struct iio_chan_spec *chan, int val, int val2, long info) 335*9caed0d9SLars-Peter Clausen { 336*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 337*9caed0d9SLars-Peter Clausen 338*9caed0d9SLars-Peter Clausen switch (info) { 339*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_CALIBBIAS: 340*9caed0d9SLars-Peter Clausen return adis_write_reg_32(&adis16136->adis, 341*9caed0d9SLars-Peter Clausen ADIS16136_REG_GYRO_OFF2, val); 342*9caed0d9SLars-Peter Clausen case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 343*9caed0d9SLars-Peter Clausen return adis16136_set_filter(indio_dev, val); 344*9caed0d9SLars-Peter Clausen default: 345*9caed0d9SLars-Peter Clausen break; 346*9caed0d9SLars-Peter Clausen } 347*9caed0d9SLars-Peter Clausen 348*9caed0d9SLars-Peter Clausen return -EINVAL; 349*9caed0d9SLars-Peter Clausen } 350*9caed0d9SLars-Peter Clausen 351*9caed0d9SLars-Peter Clausen enum { 352*9caed0d9SLars-Peter Clausen ADIS16136_SCAN_GYRO, 353*9caed0d9SLars-Peter Clausen ADIS16136_SCAN_TEMP, 354*9caed0d9SLars-Peter Clausen }; 355*9caed0d9SLars-Peter Clausen 356*9caed0d9SLars-Peter Clausen static const struct iio_chan_spec adis16136_channels[] = { 357*9caed0d9SLars-Peter Clausen { 358*9caed0d9SLars-Peter Clausen .type = IIO_ANGL_VEL, 359*9caed0d9SLars-Peter Clausen .modified = 1, 360*9caed0d9SLars-Peter Clausen .channel2 = IIO_MOD_X, 361*9caed0d9SLars-Peter Clausen .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | 362*9caed0d9SLars-Peter Clausen IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | 363*9caed0d9SLars-Peter Clausen IIO_CHAN_INFO_SCALE_SHARED_BIT | 364*9caed0d9SLars-Peter Clausen IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, 365*9caed0d9SLars-Peter Clausen .address = ADIS16136_REG_GYRO_OUT2, 366*9caed0d9SLars-Peter Clausen .scan_index = ADIS16136_SCAN_GYRO, 367*9caed0d9SLars-Peter Clausen .scan_type = { 368*9caed0d9SLars-Peter Clausen .sign = 's', 369*9caed0d9SLars-Peter Clausen .realbits = 32, 370*9caed0d9SLars-Peter Clausen .storagebits = 32, 371*9caed0d9SLars-Peter Clausen .endianness = IIO_BE, 372*9caed0d9SLars-Peter Clausen }, 373*9caed0d9SLars-Peter Clausen }, { 374*9caed0d9SLars-Peter Clausen .type = IIO_TEMP, 375*9caed0d9SLars-Peter Clausen .indexed = 1, 376*9caed0d9SLars-Peter Clausen .channel = 0, 377*9caed0d9SLars-Peter Clausen .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | 378*9caed0d9SLars-Peter Clausen IIO_CHAN_INFO_SCALE_SEPARATE_BIT, 379*9caed0d9SLars-Peter Clausen .address = ADIS16136_REG_TEMP_OUT, 380*9caed0d9SLars-Peter Clausen .scan_index = ADIS16136_SCAN_TEMP, 381*9caed0d9SLars-Peter Clausen .scan_type = { 382*9caed0d9SLars-Peter Clausen .sign = 's', 383*9caed0d9SLars-Peter Clausen .realbits = 16, 384*9caed0d9SLars-Peter Clausen .storagebits = 16, 385*9caed0d9SLars-Peter Clausen .endianness = IIO_BE, 386*9caed0d9SLars-Peter Clausen }, 387*9caed0d9SLars-Peter Clausen }, 388*9caed0d9SLars-Peter Clausen IIO_CHAN_SOFT_TIMESTAMP(2), 389*9caed0d9SLars-Peter Clausen }; 390*9caed0d9SLars-Peter Clausen 391*9caed0d9SLars-Peter Clausen static struct attribute *adis16136_attributes[] = { 392*9caed0d9SLars-Peter Clausen &iio_dev_attr_sampling_frequency.dev_attr.attr, 393*9caed0d9SLars-Peter Clausen NULL 394*9caed0d9SLars-Peter Clausen }; 395*9caed0d9SLars-Peter Clausen 396*9caed0d9SLars-Peter Clausen static const struct attribute_group adis16136_attribute_group = { 397*9caed0d9SLars-Peter Clausen .attrs = adis16136_attributes, 398*9caed0d9SLars-Peter Clausen }; 399*9caed0d9SLars-Peter Clausen 400*9caed0d9SLars-Peter Clausen static const struct iio_info adis16136_info = { 401*9caed0d9SLars-Peter Clausen .driver_module = THIS_MODULE, 402*9caed0d9SLars-Peter Clausen .attrs = &adis16136_attribute_group, 403*9caed0d9SLars-Peter Clausen .read_raw = &adis16136_read_raw, 404*9caed0d9SLars-Peter Clausen .write_raw = &adis16136_write_raw, 405*9caed0d9SLars-Peter Clausen .update_scan_mode = adis_update_scan_mode, 406*9caed0d9SLars-Peter Clausen .debugfs_reg_access = adis_debugfs_reg_access, 407*9caed0d9SLars-Peter Clausen }; 408*9caed0d9SLars-Peter Clausen 409*9caed0d9SLars-Peter Clausen static int adis16136_stop_device(struct iio_dev *indio_dev) 410*9caed0d9SLars-Peter Clausen { 411*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 412*9caed0d9SLars-Peter Clausen int ret; 413*9caed0d9SLars-Peter Clausen 414*9caed0d9SLars-Peter Clausen ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff); 415*9caed0d9SLars-Peter Clausen if (ret) 416*9caed0d9SLars-Peter Clausen dev_err(&indio_dev->dev, 417*9caed0d9SLars-Peter Clausen "Could not power down device: %d\n", ret); 418*9caed0d9SLars-Peter Clausen 419*9caed0d9SLars-Peter Clausen return ret; 420*9caed0d9SLars-Peter Clausen } 421*9caed0d9SLars-Peter Clausen 422*9caed0d9SLars-Peter Clausen static int adis16136_initial_setup(struct iio_dev *indio_dev) 423*9caed0d9SLars-Peter Clausen { 424*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 425*9caed0d9SLars-Peter Clausen unsigned int device_id; 426*9caed0d9SLars-Peter Clausen uint16_t prod_id; 427*9caed0d9SLars-Peter Clausen int ret; 428*9caed0d9SLars-Peter Clausen 429*9caed0d9SLars-Peter Clausen ret = adis_initial_startup(&adis16136->adis); 430*9caed0d9SLars-Peter Clausen if (ret) 431*9caed0d9SLars-Peter Clausen return ret; 432*9caed0d9SLars-Peter Clausen 433*9caed0d9SLars-Peter Clausen ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, 434*9caed0d9SLars-Peter Clausen &prod_id); 435*9caed0d9SLars-Peter Clausen if (ret) 436*9caed0d9SLars-Peter Clausen return ret; 437*9caed0d9SLars-Peter Clausen 438*9caed0d9SLars-Peter Clausen sscanf(indio_dev->name, "adis%u\n", &device_id); 439*9caed0d9SLars-Peter Clausen 440*9caed0d9SLars-Peter Clausen if (prod_id != device_id) 441*9caed0d9SLars-Peter Clausen dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", 442*9caed0d9SLars-Peter Clausen device_id, prod_id); 443*9caed0d9SLars-Peter Clausen 444*9caed0d9SLars-Peter Clausen return 0; 445*9caed0d9SLars-Peter Clausen } 446*9caed0d9SLars-Peter Clausen 447*9caed0d9SLars-Peter Clausen static const char * const adis16136_status_error_msgs[] = { 448*9caed0d9SLars-Peter Clausen [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", 449*9caed0d9SLars-Peter Clausen [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", 450*9caed0d9SLars-Peter Clausen [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", 451*9caed0d9SLars-Peter Clausen [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", 452*9caed0d9SLars-Peter Clausen }; 453*9caed0d9SLars-Peter Clausen 454*9caed0d9SLars-Peter Clausen static const struct adis_data adis16136_data = { 455*9caed0d9SLars-Peter Clausen .diag_stat_reg = ADIS16136_REG_DIAG_STAT, 456*9caed0d9SLars-Peter Clausen .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, 457*9caed0d9SLars-Peter Clausen .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, 458*9caed0d9SLars-Peter Clausen 459*9caed0d9SLars-Peter Clausen .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, 460*9caed0d9SLars-Peter Clausen .startup_delay = 80, 461*9caed0d9SLars-Peter Clausen 462*9caed0d9SLars-Peter Clausen .read_delay = 10, 463*9caed0d9SLars-Peter Clausen .write_delay = 10, 464*9caed0d9SLars-Peter Clausen 465*9caed0d9SLars-Peter Clausen .status_error_msgs = adis16136_status_error_msgs, 466*9caed0d9SLars-Peter Clausen .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | 467*9caed0d9SLars-Peter Clausen BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | 468*9caed0d9SLars-Peter Clausen BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | 469*9caed0d9SLars-Peter Clausen BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), 470*9caed0d9SLars-Peter Clausen }; 471*9caed0d9SLars-Peter Clausen 472*9caed0d9SLars-Peter Clausen enum adis16136_id { 473*9caed0d9SLars-Peter Clausen ID_ADIS16133, 474*9caed0d9SLars-Peter Clausen ID_ADIS16135, 475*9caed0d9SLars-Peter Clausen ID_ADIS16136, 476*9caed0d9SLars-Peter Clausen }; 477*9caed0d9SLars-Peter Clausen 478*9caed0d9SLars-Peter Clausen static const struct adis16136_chip_info adis16136_chip_info[] = { 479*9caed0d9SLars-Peter Clausen [ID_ADIS16133] = { 480*9caed0d9SLars-Peter Clausen .precision = IIO_DEGREE_TO_RAD(1200), 481*9caed0d9SLars-Peter Clausen .fullscale = 24000, 482*9caed0d9SLars-Peter Clausen }, 483*9caed0d9SLars-Peter Clausen [ID_ADIS16135] = { 484*9caed0d9SLars-Peter Clausen .precision = IIO_DEGREE_TO_RAD(300), 485*9caed0d9SLars-Peter Clausen .fullscale = 24000, 486*9caed0d9SLars-Peter Clausen }, 487*9caed0d9SLars-Peter Clausen [ID_ADIS16136] = { 488*9caed0d9SLars-Peter Clausen .precision = IIO_DEGREE_TO_RAD(450), 489*9caed0d9SLars-Peter Clausen .fullscale = 24623, 490*9caed0d9SLars-Peter Clausen }, 491*9caed0d9SLars-Peter Clausen }; 492*9caed0d9SLars-Peter Clausen 493*9caed0d9SLars-Peter Clausen static int adis16136_probe(struct spi_device *spi) 494*9caed0d9SLars-Peter Clausen { 495*9caed0d9SLars-Peter Clausen const struct spi_device_id *id = spi_get_device_id(spi); 496*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136; 497*9caed0d9SLars-Peter Clausen struct iio_dev *indio_dev; 498*9caed0d9SLars-Peter Clausen int ret; 499*9caed0d9SLars-Peter Clausen 500*9caed0d9SLars-Peter Clausen indio_dev = iio_device_alloc(sizeof(*adis16136)); 501*9caed0d9SLars-Peter Clausen if (indio_dev == NULL) 502*9caed0d9SLars-Peter Clausen return -ENOMEM; 503*9caed0d9SLars-Peter Clausen 504*9caed0d9SLars-Peter Clausen spi_set_drvdata(spi, indio_dev); 505*9caed0d9SLars-Peter Clausen 506*9caed0d9SLars-Peter Clausen adis16136 = iio_priv(indio_dev); 507*9caed0d9SLars-Peter Clausen 508*9caed0d9SLars-Peter Clausen adis16136->chip_info = &adis16136_chip_info[id->driver_data]; 509*9caed0d9SLars-Peter Clausen indio_dev->dev.parent = &spi->dev; 510*9caed0d9SLars-Peter Clausen indio_dev->name = spi_get_device_id(spi)->name; 511*9caed0d9SLars-Peter Clausen indio_dev->channels = adis16136_channels; 512*9caed0d9SLars-Peter Clausen indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); 513*9caed0d9SLars-Peter Clausen indio_dev->info = &adis16136_info; 514*9caed0d9SLars-Peter Clausen indio_dev->modes = INDIO_DIRECT_MODE; 515*9caed0d9SLars-Peter Clausen 516*9caed0d9SLars-Peter Clausen ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); 517*9caed0d9SLars-Peter Clausen if (ret) 518*9caed0d9SLars-Peter Clausen goto error_free_dev; 519*9caed0d9SLars-Peter Clausen 520*9caed0d9SLars-Peter Clausen ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); 521*9caed0d9SLars-Peter Clausen if (ret) 522*9caed0d9SLars-Peter Clausen goto error_free_dev; 523*9caed0d9SLars-Peter Clausen 524*9caed0d9SLars-Peter Clausen ret = adis16136_initial_setup(indio_dev); 525*9caed0d9SLars-Peter Clausen if (ret) 526*9caed0d9SLars-Peter Clausen goto error_cleanup_buffer; 527*9caed0d9SLars-Peter Clausen 528*9caed0d9SLars-Peter Clausen ret = iio_device_register(indio_dev); 529*9caed0d9SLars-Peter Clausen if (ret) 530*9caed0d9SLars-Peter Clausen goto error_stop_device; 531*9caed0d9SLars-Peter Clausen 532*9caed0d9SLars-Peter Clausen adis16136_debugfs_init(indio_dev); 533*9caed0d9SLars-Peter Clausen 534*9caed0d9SLars-Peter Clausen return 0; 535*9caed0d9SLars-Peter Clausen 536*9caed0d9SLars-Peter Clausen error_stop_device: 537*9caed0d9SLars-Peter Clausen adis16136_stop_device(indio_dev); 538*9caed0d9SLars-Peter Clausen error_cleanup_buffer: 539*9caed0d9SLars-Peter Clausen adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); 540*9caed0d9SLars-Peter Clausen error_free_dev: 541*9caed0d9SLars-Peter Clausen iio_device_free(indio_dev); 542*9caed0d9SLars-Peter Clausen return ret; 543*9caed0d9SLars-Peter Clausen } 544*9caed0d9SLars-Peter Clausen 545*9caed0d9SLars-Peter Clausen static int adis16136_remove(struct spi_device *spi) 546*9caed0d9SLars-Peter Clausen { 547*9caed0d9SLars-Peter Clausen struct iio_dev *indio_dev = spi_get_drvdata(spi); 548*9caed0d9SLars-Peter Clausen struct adis16136 *adis16136 = iio_priv(indio_dev); 549*9caed0d9SLars-Peter Clausen 550*9caed0d9SLars-Peter Clausen iio_device_unregister(indio_dev); 551*9caed0d9SLars-Peter Clausen adis16136_stop_device(indio_dev); 552*9caed0d9SLars-Peter Clausen 553*9caed0d9SLars-Peter Clausen adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); 554*9caed0d9SLars-Peter Clausen 555*9caed0d9SLars-Peter Clausen iio_device_free(indio_dev); 556*9caed0d9SLars-Peter Clausen 557*9caed0d9SLars-Peter Clausen return 0; 558*9caed0d9SLars-Peter Clausen } 559*9caed0d9SLars-Peter Clausen 560*9caed0d9SLars-Peter Clausen static const struct spi_device_id adis16136_ids[] = { 561*9caed0d9SLars-Peter Clausen { "adis16133", ID_ADIS16133 }, 562*9caed0d9SLars-Peter Clausen { "adis16135", ID_ADIS16135 }, 563*9caed0d9SLars-Peter Clausen { "adis16136", ID_ADIS16136 }, 564*9caed0d9SLars-Peter Clausen { } 565*9caed0d9SLars-Peter Clausen }; 566*9caed0d9SLars-Peter Clausen MODULE_DEVICE_TABLE(spi, adis16136_ids); 567*9caed0d9SLars-Peter Clausen 568*9caed0d9SLars-Peter Clausen static struct spi_driver adis16136_driver = { 569*9caed0d9SLars-Peter Clausen .driver = { 570*9caed0d9SLars-Peter Clausen .name = "adis16136", 571*9caed0d9SLars-Peter Clausen .owner = THIS_MODULE, 572*9caed0d9SLars-Peter Clausen }, 573*9caed0d9SLars-Peter Clausen .id_table = adis16136_ids, 574*9caed0d9SLars-Peter Clausen .probe = adis16136_probe, 575*9caed0d9SLars-Peter Clausen .remove = adis16136_remove, 576*9caed0d9SLars-Peter Clausen }; 577*9caed0d9SLars-Peter Clausen module_spi_driver(adis16136_driver); 578*9caed0d9SLars-Peter Clausen 579*9caed0d9SLars-Peter Clausen MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 580*9caed0d9SLars-Peter Clausen MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); 581*9caed0d9SLars-Peter Clausen MODULE_LICENSE("GPL v2"); 582