1 /* 2 * ADIS16080/100 Yaw Rate Gyroscope with SPI driver 3 * 4 * Copyright 2010 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 #include <linux/delay.h> 9 #include <linux/mutex.h> 10 #include <linux/device.h> 11 #include <linux/kernel.h> 12 #include <linux/spi/spi.h> 13 #include <linux/slab.h> 14 #include <linux/sysfs.h> 15 #include <linux/module.h> 16 17 #include <linux/iio/iio.h> 18 #include <linux/iio/sysfs.h> 19 20 #define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */ 21 #define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */ 22 #define ADIS16080_DIN_AIN1 (2 << 10) 23 #define ADIS16080_DIN_AIN2 (3 << 10) 24 25 /* 26 * 1: Write contents on DIN to control register. 27 * 0: No changes to control register. 28 */ 29 30 #define ADIS16080_DIN_WRITE (1 << 15) 31 32 struct adis16080_chip_info { 33 int scale_val; 34 int scale_val2; 35 }; 36 37 /** 38 * struct adis16080_state - device instance specific data 39 * @us: actual spi_device to write data 40 * @info: chip specific parameters 41 * @buf: transmit or receive buffer 42 **/ 43 struct adis16080_state { 44 struct spi_device *us; 45 const struct adis16080_chip_info *info; 46 47 __be16 buf ____cacheline_aligned; 48 }; 49 50 static int adis16080_read_sample(struct iio_dev *indio_dev, 51 u16 addr, int *val) 52 { 53 struct adis16080_state *st = iio_priv(indio_dev); 54 struct spi_message m; 55 int ret; 56 struct spi_transfer t[] = { 57 { 58 .tx_buf = &st->buf, 59 .len = 2, 60 .cs_change = 1, 61 }, { 62 .rx_buf = &st->buf, 63 .len = 2, 64 }, 65 }; 66 67 st->buf = cpu_to_be16(addr | ADIS16080_DIN_WRITE); 68 69 spi_message_init(&m); 70 spi_message_add_tail(&t[0], &m); 71 spi_message_add_tail(&t[1], &m); 72 73 ret = spi_sync(st->us, &m); 74 if (ret == 0) 75 *val = sign_extend32(be16_to_cpu(st->buf), 11); 76 77 return ret; 78 } 79 80 static int adis16080_read_raw(struct iio_dev *indio_dev, 81 struct iio_chan_spec const *chan, 82 int *val, 83 int *val2, 84 long mask) 85 { 86 struct adis16080_state *st = iio_priv(indio_dev); 87 int ret; 88 89 switch (mask) { 90 case IIO_CHAN_INFO_RAW: 91 mutex_lock(&indio_dev->mlock); 92 ret = adis16080_read_sample(indio_dev, chan->address, val); 93 mutex_unlock(&indio_dev->mlock); 94 return ret ? ret : IIO_VAL_INT; 95 case IIO_CHAN_INFO_SCALE: 96 switch (chan->type) { 97 case IIO_ANGL_VEL: 98 *val = st->info->scale_val; 99 *val2 = st->info->scale_val2; 100 return IIO_VAL_FRACTIONAL; 101 case IIO_VOLTAGE: 102 /* VREF = 5V, 12 bits */ 103 *val = 5000; 104 *val2 = 12; 105 return IIO_VAL_FRACTIONAL_LOG2; 106 case IIO_TEMP: 107 /* 85 C = 585, 25 C = 0 */ 108 *val = 85000 - 25000; 109 *val2 = 585; 110 return IIO_VAL_FRACTIONAL; 111 default: 112 return -EINVAL; 113 } 114 case IIO_CHAN_INFO_OFFSET: 115 switch (chan->type) { 116 case IIO_VOLTAGE: 117 /* 2.5 V = 0 */ 118 *val = 2048; 119 return IIO_VAL_INT; 120 case IIO_TEMP: 121 /* 85 C = 585, 25 C = 0 */ 122 *val = DIV_ROUND_CLOSEST(25 * 585, 85 - 25); 123 return IIO_VAL_INT; 124 default: 125 return -EINVAL; 126 } 127 default: 128 break; 129 } 130 131 return -EINVAL; 132 } 133 134 static const struct iio_chan_spec adis16080_channels[] = { 135 { 136 .type = IIO_ANGL_VEL, 137 .modified = 1, 138 .channel2 = IIO_MOD_Z, 139 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 140 BIT(IIO_CHAN_INFO_SCALE), 141 .address = ADIS16080_DIN_GYRO, 142 }, { 143 .type = IIO_VOLTAGE, 144 .indexed = 1, 145 .channel = 0, 146 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 147 BIT(IIO_CHAN_INFO_SCALE) | 148 BIT(IIO_CHAN_INFO_OFFSET), 149 .address = ADIS16080_DIN_AIN1, 150 }, { 151 .type = IIO_VOLTAGE, 152 .indexed = 1, 153 .channel = 1, 154 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 155 BIT(IIO_CHAN_INFO_SCALE) | 156 BIT(IIO_CHAN_INFO_OFFSET), 157 .address = ADIS16080_DIN_AIN2, 158 }, { 159 .type = IIO_TEMP, 160 .indexed = 1, 161 .channel = 0, 162 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 163 BIT(IIO_CHAN_INFO_SCALE) | 164 BIT(IIO_CHAN_INFO_OFFSET), 165 .address = ADIS16080_DIN_TEMP, 166 } 167 }; 168 169 static const struct iio_info adis16080_info = { 170 .read_raw = &adis16080_read_raw, 171 .driver_module = THIS_MODULE, 172 }; 173 174 enum { 175 ID_ADIS16080, 176 ID_ADIS16100, 177 }; 178 179 static const struct adis16080_chip_info adis16080_chip_info[] = { 180 [ID_ADIS16080] = { 181 /* 80 degree = 819, 819 rad = 46925 degree */ 182 .scale_val = 80, 183 .scale_val2 = 46925, 184 }, 185 [ID_ADIS16100] = { 186 /* 300 degree = 1230, 1230 rad = 70474 degree */ 187 .scale_val = 300, 188 .scale_val2 = 70474, 189 }, 190 }; 191 192 static int adis16080_probe(struct spi_device *spi) 193 { 194 const struct spi_device_id *id = spi_get_device_id(spi); 195 struct adis16080_state *st; 196 struct iio_dev *indio_dev; 197 198 /* setup the industrialio driver allocated elements */ 199 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 200 if (!indio_dev) 201 return -ENOMEM; 202 st = iio_priv(indio_dev); 203 /* this is only used for removal purposes */ 204 spi_set_drvdata(spi, indio_dev); 205 206 /* Allocate the comms buffers */ 207 st->us = spi; 208 st->info = &adis16080_chip_info[id->driver_data]; 209 210 indio_dev->name = spi->dev.driver->name; 211 indio_dev->channels = adis16080_channels; 212 indio_dev->num_channels = ARRAY_SIZE(adis16080_channels); 213 indio_dev->dev.parent = &spi->dev; 214 indio_dev->info = &adis16080_info; 215 indio_dev->modes = INDIO_DIRECT_MODE; 216 217 return iio_device_register(indio_dev); 218 } 219 220 static int adis16080_remove(struct spi_device *spi) 221 { 222 iio_device_unregister(spi_get_drvdata(spi)); 223 return 0; 224 } 225 226 static const struct spi_device_id adis16080_ids[] = { 227 { "adis16080", ID_ADIS16080 }, 228 { "adis16100", ID_ADIS16100 }, 229 {}, 230 }; 231 MODULE_DEVICE_TABLE(spi, adis16080_ids); 232 233 static struct spi_driver adis16080_driver = { 234 .driver = { 235 .name = "adis16080", 236 .owner = THIS_MODULE, 237 }, 238 .probe = adis16080_probe, 239 .remove = adis16080_remove, 240 .id_table = adis16080_ids, 241 }; 242 module_spi_driver(adis16080_driver); 243 244 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 245 MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope Driver"); 246 MODULE_LICENSE("GPL v2"); 247