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