Commit | Line | Data |
---|---|---|
24742ac6 | 1 | /* |
617156fb | 2 | * ADXRS450/ADXRS453 Digital Output Gyroscope Driver |
24742ac6 MH |
3 | * |
4 | * Copyright 2011 Analog Devices Inc. | |
5 | * | |
caca8c89 | 6 | * Licensed under the GPL-2. |
24742ac6 MH |
7 | */ |
8 | ||
9 | #include <linux/interrupt.h> | |
10 | #include <linux/irq.h> | |
24742ac6 MH |
11 | #include <linux/delay.h> |
12 | #include <linux/mutex.h> | |
13 | #include <linux/device.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/spi/spi.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/sysfs.h> | |
18 | #include <linux/list.h> | |
99c97852 | 19 | #include <linux/module.h> |
24742ac6 | 20 | |
06458e27 JC |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> | |
24742ac6 | 23 | |
53ac8500 LPC |
24 | #define ADXRS450_STARTUP_DELAY 50 /* ms */ |
25 | ||
26 | /* The MSB for the spi commands */ | |
27 | #define ADXRS450_SENSOR_DATA (0x20 << 24) | |
28 | #define ADXRS450_WRITE_DATA (0x40 << 24) | |
29 | #define ADXRS450_READ_DATA (0x80 << 24) | |
30 | ||
31 | #define ADXRS450_RATE1 0x00 /* Rate Registers */ | |
32 | #define ADXRS450_TEMP1 0x02 /* Temperature Registers */ | |
33 | #define ADXRS450_LOCST1 0x04 /* Low CST Memory Registers */ | |
34 | #define ADXRS450_HICST1 0x06 /* High CST Memory Registers */ | |
35 | #define ADXRS450_QUAD1 0x08 /* Quad Memory Registers */ | |
36 | #define ADXRS450_FAULT1 0x0A /* Fault Registers */ | |
37 | #define ADXRS450_PID1 0x0C /* Part ID Register 1 */ | |
38 | #define ADXRS450_SNH 0x0E /* Serial Number Registers, 4 bytes */ | |
39 | #define ADXRS450_SNL 0x10 | |
40 | #define ADXRS450_DNC1 0x12 /* Dynamic Null Correction Registers */ | |
41 | /* Check bits */ | |
42 | #define ADXRS450_P 0x01 | |
43 | #define ADXRS450_CHK 0x02 | |
44 | #define ADXRS450_CST 0x04 | |
45 | #define ADXRS450_PWR 0x08 | |
46 | #define ADXRS450_POR 0x10 | |
47 | #define ADXRS450_NVM 0x20 | |
48 | #define ADXRS450_Q 0x40 | |
49 | #define ADXRS450_PLL 0x80 | |
50 | #define ADXRS450_UV 0x100 | |
51 | #define ADXRS450_OV 0x200 | |
52 | #define ADXRS450_AMP 0x400 | |
53 | #define ADXRS450_FAIL 0x800 | |
54 | ||
55 | #define ADXRS450_WRERR_MASK (0x7 << 29) | |
56 | ||
57 | #define ADXRS450_MAX_RX 4 | |
58 | #define ADXRS450_MAX_TX 4 | |
59 | ||
60 | #define ADXRS450_GET_ST(a) ((a >> 26) & 0x3) | |
61 | ||
62 | enum { | |
63 | ID_ADXRS450, | |
64 | ID_ADXRS453, | |
65 | }; | |
66 | ||
67 | /** | |
68 | * struct adxrs450_state - device instance specific data | |
69 | * @us: actual spi_device | |
70 | * @buf_lock: mutex to protect tx and rx | |
71 | * @tx: transmit buffer | |
72 | * @rx: receive buffer | |
73 | **/ | |
74 | struct adxrs450_state { | |
75 | struct spi_device *us; | |
76 | struct mutex buf_lock; | |
77 | __be32 tx ____cacheline_aligned; | |
78 | __be32 rx; | |
79 | ||
80 | }; | |
24742ac6 MH |
81 | |
82 | /** | |
83 | * adxrs450_spi_read_reg_16() - read 2 bytes from a register pair | |
d5e69c83 | 84 | * @indio_dev: device associated with child of actual iio_dev |
1439b6e8 LPC |
85 | * @reg_address: the address of the lower of the two registers, which should be |
86 | * an even address, the second register's address is reg_address + 1. | |
24742ac6 MH |
87 | * @val: somewhere to pass back the value read |
88 | **/ | |
58ea7784 JC |
89 | static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev, |
90 | u8 reg_address, | |
91 | u16 *val) | |
24742ac6 | 92 | { |
6a6df2d9 | 93 | struct spi_message msg; |
ba61bb18 | 94 | struct adxrs450_state *st = iio_priv(indio_dev); |
1a87e4fb | 95 | u32 tx; |
24742ac6 | 96 | int ret; |
6a6df2d9 LPC |
97 | struct spi_transfer xfers[] = { |
98 | { | |
1a87e4fb | 99 | .tx_buf = &st->tx, |
6a6df2d9 | 100 | .bits_per_word = 8, |
1a87e4fb | 101 | .len = sizeof(st->tx), |
6a6df2d9 LPC |
102 | .cs_change = 1, |
103 | }, { | |
1a87e4fb | 104 | .rx_buf = &st->rx, |
6a6df2d9 | 105 | .bits_per_word = 8, |
1a87e4fb | 106 | .len = sizeof(st->rx), |
6a6df2d9 LPC |
107 | }, |
108 | }; | |
31f6a29a | 109 | |
24742ac6 | 110 | mutex_lock(&st->buf_lock); |
1a87e4fb | 111 | tx = ADXRS450_READ_DATA | (reg_address << 17); |
24742ac6 | 112 | |
1a87e4fb LPC |
113 | if (!(hweight32(tx) & 1)) |
114 | tx |= ADXRS450_P; | |
232b1648 | 115 | |
1a87e4fb | 116 | st->tx = cpu_to_be32(tx); |
6a6df2d9 LPC |
117 | spi_message_init(&msg); |
118 | spi_message_add_tail(&xfers[0], &msg); | |
119 | spi_message_add_tail(&xfers[1], &msg); | |
120 | ret = spi_sync(st->us, &msg); | |
24742ac6 MH |
121 | if (ret) { |
122 | dev_err(&st->us->dev, "problem while reading 16 bit register 0x%02x\n", | |
123 | reg_address); | |
124 | goto error_ret; | |
125 | } | |
126 | ||
1a87e4fb | 127 | *val = (be32_to_cpu(st->rx) >> 5) & 0xFFFF; |
24742ac6 MH |
128 | |
129 | error_ret: | |
130 | mutex_unlock(&st->buf_lock); | |
131 | return ret; | |
132 | } | |
133 | ||
134 | /** | |
135 | * adxrs450_spi_write_reg_16() - write 2 bytes data to a register pair | |
d5e69c83 | 136 | * @indio_dev: device associated with child of actual actual iio_dev |
1439b6e8 LPC |
137 | * @reg_address: the address of the lower of the two registers,which should be |
138 | * an even address, the second register's address is reg_address + 1. | |
24742ac6 MH |
139 | * @val: value to be written. |
140 | **/ | |
58ea7784 JC |
141 | static int adxrs450_spi_write_reg_16(struct iio_dev *indio_dev, |
142 | u8 reg_address, | |
143 | u16 val) | |
24742ac6 | 144 | { |
ba61bb18 | 145 | struct adxrs450_state *st = iio_priv(indio_dev); |
1a87e4fb | 146 | u32 tx; |
24742ac6 | 147 | int ret; |
24742ac6 MH |
148 | |
149 | mutex_lock(&st->buf_lock); | |
1a87e4fb | 150 | tx = ADXRS450_WRITE_DATA | (reg_address << 17) | (val << 1); |
232b1648 | 151 | |
1a87e4fb LPC |
152 | if (!(hweight32(tx) & 1)) |
153 | tx |= ADXRS450_P; | |
232b1648 | 154 | |
1a87e4fb LPC |
155 | st->tx = cpu_to_be32(tx); |
156 | ret = spi_write(st->us, &st->tx, sizeof(st->tx)); | |
24742ac6 MH |
157 | if (ret) |
158 | dev_err(&st->us->dev, "problem while writing 16 bit register 0x%02x\n", | |
cb449687 | 159 | reg_address); |
619036e2 | 160 | usleep_range(100, 1000); /* enforce sequential transfer delay 0.1ms */ |
24742ac6 MH |
161 | mutex_unlock(&st->buf_lock); |
162 | return ret; | |
163 | } | |
164 | ||
165 | /** | |
166 | * adxrs450_spi_sensor_data() - read 2 bytes sensor data | |
d5e69c83 | 167 | * @indio_dev: device associated with child of actual iio_dev |
24742ac6 MH |
168 | * @val: somewhere to pass back the value read |
169 | **/ | |
58ea7784 | 170 | static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val) |
24742ac6 | 171 | { |
6a6df2d9 | 172 | struct spi_message msg; |
ba61bb18 | 173 | struct adxrs450_state *st = iio_priv(indio_dev); |
24742ac6 | 174 | int ret; |
6a6df2d9 LPC |
175 | struct spi_transfer xfers[] = { |
176 | { | |
1a87e4fb | 177 | .tx_buf = &st->tx, |
6a6df2d9 | 178 | .bits_per_word = 8, |
1a87e4fb | 179 | .len = sizeof(st->tx), |
6a6df2d9 LPC |
180 | .cs_change = 1, |
181 | }, { | |
1a87e4fb | 182 | .rx_buf = &st->rx, |
6a6df2d9 | 183 | .bits_per_word = 8, |
1a87e4fb | 184 | .len = sizeof(st->rx), |
6a6df2d9 LPC |
185 | }, |
186 | }; | |
24742ac6 MH |
187 | |
188 | mutex_lock(&st->buf_lock); | |
1a87e4fb | 189 | st->tx = cpu_to_be32(ADXRS450_SENSOR_DATA); |
24742ac6 | 190 | |
6a6df2d9 LPC |
191 | spi_message_init(&msg); |
192 | spi_message_add_tail(&xfers[0], &msg); | |
193 | spi_message_add_tail(&xfers[1], &msg); | |
194 | ret = spi_sync(st->us, &msg); | |
24742ac6 MH |
195 | if (ret) { |
196 | dev_err(&st->us->dev, "Problem while reading sensor data\n"); | |
197 | goto error_ret; | |
198 | } | |
199 | ||
1a87e4fb | 200 | *val = (be32_to_cpu(st->rx) >> 10) & 0xFFFF; |
caca8c89 | 201 | |
24742ac6 MH |
202 | error_ret: |
203 | mutex_unlock(&st->buf_lock); | |
204 | return ret; | |
205 | } | |
206 | ||
207 | /** | |
208 | * adxrs450_spi_initial() - use for initializing procedure. | |
209 | * @st: device instance specific data | |
210 | * @val: somewhere to pass back the value read | |
d5e69c83 | 211 | * @chk: Whether to perform fault check |
24742ac6 MH |
212 | **/ |
213 | static int adxrs450_spi_initial(struct adxrs450_state *st, | |
214 | u32 *val, char chk) | |
215 | { | |
24742ac6 | 216 | int ret; |
1a87e4fb | 217 | u32 tx; |
24742ac6 | 218 | struct spi_transfer xfers = { |
1a87e4fb LPC |
219 | .tx_buf = &st->tx, |
220 | .rx_buf = &st->rx, | |
24742ac6 | 221 | .bits_per_word = 8, |
1a87e4fb | 222 | .len = sizeof(st->tx), |
24742ac6 MH |
223 | }; |
224 | ||
225 | mutex_lock(&st->buf_lock); | |
1a87e4fb | 226 | tx = ADXRS450_SENSOR_DATA; |
24742ac6 | 227 | if (chk) |
1a87e4fb LPC |
228 | tx |= (ADXRS450_CHK | ADXRS450_P); |
229 | st->tx = cpu_to_be32(tx); | |
14543a00 | 230 | ret = spi_sync_transfer(st->us, &xfers, 1); |
24742ac6 MH |
231 | if (ret) { |
232 | dev_err(&st->us->dev, "Problem while reading initializing data\n"); | |
233 | goto error_ret; | |
234 | } | |
235 | ||
1a87e4fb | 236 | *val = be32_to_cpu(st->rx); |
24742ac6 MH |
237 | |
238 | error_ret: | |
239 | mutex_unlock(&st->buf_lock); | |
240 | return ret; | |
241 | } | |
242 | ||
24742ac6 | 243 | /* Recommended Startup Sequence by spec */ |
ba61bb18 | 244 | static int adxrs450_initial_setup(struct iio_dev *indio_dev) |
24742ac6 MH |
245 | { |
246 | u32 t; | |
247 | u16 data; | |
248 | int ret; | |
ba61bb18 | 249 | struct adxrs450_state *st = iio_priv(indio_dev); |
24742ac6 MH |
250 | |
251 | msleep(ADXRS450_STARTUP_DELAY*2); | |
252 | ret = adxrs450_spi_initial(st, &t, 1); | |
253 | if (ret) | |
254 | return ret; | |
1810b3bb | 255 | if (t != 0x01) |
457b71df | 256 | dev_warn(&st->us->dev, "The initial power on response is not correct! Restart without reset?\n"); |
24742ac6 MH |
257 | |
258 | msleep(ADXRS450_STARTUP_DELAY); | |
259 | ret = adxrs450_spi_initial(st, &t, 0); | |
260 | if (ret) | |
261 | return ret; | |
262 | ||
263 | msleep(ADXRS450_STARTUP_DELAY); | |
264 | ret = adxrs450_spi_initial(st, &t, 0); | |
265 | if (ret) | |
266 | return ret; | |
267 | if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { | |
268 | dev_err(&st->us->dev, "The second response is not correct!\n"); | |
269 | return -EIO; | |
270 | ||
271 | } | |
272 | ret = adxrs450_spi_initial(st, &t, 0); | |
273 | if (ret) | |
274 | return ret; | |
275 | if (((t & 0xff) | 0x01) != 0xff || ADXRS450_GET_ST(t) != 2) { | |
276 | dev_err(&st->us->dev, "The third response is not correct!\n"); | |
277 | return -EIO; | |
278 | ||
279 | } | |
58ea7784 | 280 | ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_FAULT1, &data); |
24742ac6 MH |
281 | if (ret) |
282 | return ret; | |
283 | if (data & 0x0fff) { | |
284 | dev_err(&st->us->dev, "The device is not in normal status!\n"); | |
285 | return -EINVAL; | |
286 | } | |
24742ac6 MH |
287 | |
288 | return 0; | |
289 | } | |
290 | ||
58ea7784 JC |
291 | static int adxrs450_write_raw(struct iio_dev *indio_dev, |
292 | struct iio_chan_spec const *chan, | |
293 | int val, | |
294 | int val2, | |
295 | long mask) | |
296 | { | |
297 | int ret; | |
298 | switch (mask) { | |
c8a9f805 | 299 | case IIO_CHAN_INFO_CALIBBIAS: |
9a26578c LPC |
300 | if (val < -0x400 || val >= 0x400) |
301 | return -EINVAL; | |
58ea7784 | 302 | ret = adxrs450_spi_write_reg_16(indio_dev, |
9a26578c | 303 | ADXRS450_DNC1, val); |
58ea7784 JC |
304 | break; |
305 | default: | |
306 | ret = -EINVAL; | |
307 | break; | |
308 | } | |
309 | return ret; | |
310 | } | |
311 | ||
312 | static int adxrs450_read_raw(struct iio_dev *indio_dev, | |
313 | struct iio_chan_spec const *chan, | |
314 | int *val, | |
315 | int *val2, | |
316 | long mask) | |
317 | { | |
318 | int ret; | |
037bad9a | 319 | s16 t; |
90b9b227 | 320 | |
58ea7784 | 321 | switch (mask) { |
fbaff213 | 322 | case IIO_CHAN_INFO_RAW: |
58ea7784 | 323 | switch (chan->type) { |
41ea040c | 324 | case IIO_ANGL_VEL: |
037bad9a JC |
325 | ret = adxrs450_spi_sensor_data(indio_dev, &t); |
326 | if (ret) | |
58ea7784 | 327 | break; |
037bad9a | 328 | *val = t; |
58ea7784 JC |
329 | ret = IIO_VAL_INT; |
330 | break; | |
331 | case IIO_TEMP: | |
037bad9a | 332 | ret = adxrs450_spi_read_reg_16(indio_dev, |
90b9b227 | 333 | ADXRS450_TEMP1, &t); |
037bad9a | 334 | if (ret) |
58ea7784 | 335 | break; |
90b9b227 | 336 | *val = (t >> 6) + 225; |
58ea7784 JC |
337 | ret = IIO_VAL_INT; |
338 | break; | |
339 | default: | |
340 | ret = -EINVAL; | |
341 | break; | |
342 | } | |
343 | break; | |
90b9b227 MH |
344 | case IIO_CHAN_INFO_SCALE: |
345 | switch (chan->type) { | |
346 | case IIO_ANGL_VEL: | |
347 | *val = 0; | |
348 | *val2 = 218166; | |
349 | return IIO_VAL_INT_PLUS_NANO; | |
350 | case IIO_TEMP: | |
351 | *val = 200; | |
352 | *val2 = 0; | |
353 | return IIO_VAL_INT; | |
354 | default: | |
355 | return -EINVAL; | |
356 | } | |
357 | break; | |
c8a9f805 | 358 | case IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW: |
037bad9a JC |
359 | ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_QUAD1, &t); |
360 | if (ret) | |
58ea7784 | 361 | break; |
037bad9a | 362 | *val = t; |
58ea7784 JC |
363 | ret = IIO_VAL_INT; |
364 | break; | |
9631135d MH |
365 | case IIO_CHAN_INFO_CALIBBIAS: |
366 | ret = adxrs450_spi_read_reg_16(indio_dev, ADXRS450_DNC1, &t); | |
367 | if (ret) | |
368 | break; | |
c62b89c7 | 369 | *val = sign_extend32(t, 9); |
9631135d MH |
370 | ret = IIO_VAL_INT; |
371 | break; | |
58ea7784 JC |
372 | default: |
373 | ret = -EINVAL; | |
374 | break; | |
375 | } | |
376 | ||
377 | return ret; | |
378 | } | |
24742ac6 | 379 | |
617156fb MH |
380 | static const struct iio_chan_spec adxrs450_channels[2][2] = { |
381 | [ID_ADXRS450] = { | |
382 | { | |
383 | .type = IIO_ANGL_VEL, | |
384 | .modified = 1, | |
385 | .channel2 = IIO_MOD_Z, | |
98bfb6e3 JC |
386 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
387 | BIT(IIO_CHAN_INFO_CALIBBIAS) | | |
388 | BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) | | |
389 | BIT(IIO_CHAN_INFO_SCALE), | |
617156fb MH |
390 | }, { |
391 | .type = IIO_TEMP, | |
392 | .indexed = 1, | |
393 | .channel = 0, | |
98bfb6e3 JC |
394 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
395 | BIT(IIO_CHAN_INFO_SCALE), | |
617156fb MH |
396 | } |
397 | }, | |
398 | [ID_ADXRS453] = { | |
399 | { | |
400 | .type = IIO_ANGL_VEL, | |
401 | .modified = 1, | |
402 | .channel2 = IIO_MOD_Z, | |
98bfb6e3 JC |
403 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
404 | BIT(IIO_CHAN_INFO_SCALE) | | |
405 | BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW), | |
617156fb MH |
406 | }, { |
407 | .type = IIO_TEMP, | |
408 | .indexed = 1, | |
409 | .channel = 0, | |
98bfb6e3 JC |
410 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
411 | BIT(IIO_CHAN_INFO_SCALE), | |
617156fb MH |
412 | } |
413 | }, | |
24742ac6 MH |
414 | }; |
415 | ||
6fe8135f | 416 | static const struct iio_info adxrs450_info = { |
6fe8135f | 417 | .driver_module = THIS_MODULE, |
58ea7784 JC |
418 | .read_raw = &adxrs450_read_raw, |
419 | .write_raw = &adxrs450_write_raw, | |
6fe8135f JC |
420 | }; |
421 | ||
4ae1c61f | 422 | static int adxrs450_probe(struct spi_device *spi) |
24742ac6 | 423 | { |
d2fffd6c | 424 | int ret; |
ba61bb18 JC |
425 | struct adxrs450_state *st; |
426 | struct iio_dev *indio_dev; | |
24742ac6 | 427 | |
ba61bb18 | 428 | /* setup the industrialio driver allocated elements */ |
7cbb7537 | 429 | indio_dev = iio_device_alloc(sizeof(*st)); |
ba61bb18 | 430 | if (indio_dev == NULL) { |
24742ac6 | 431 | ret = -ENOMEM; |
ba61bb18 | 432 | goto error_ret; |
24742ac6 | 433 | } |
ba61bb18 | 434 | st = iio_priv(indio_dev); |
24742ac6 MH |
435 | st->us = spi; |
436 | mutex_init(&st->buf_lock); | |
ba61bb18 JC |
437 | /* This is only used for removal purposes */ |
438 | spi_set_drvdata(spi, indio_dev); | |
24742ac6 | 439 | |
ba61bb18 JC |
440 | indio_dev->dev.parent = &spi->dev; |
441 | indio_dev->info = &adxrs450_info; | |
442 | indio_dev->modes = INDIO_DIRECT_MODE; | |
617156fb MH |
443 | indio_dev->channels = |
444 | adxrs450_channels[spi_get_device_id(spi)->driver_data]; | |
58ea7784 JC |
445 | indio_dev->num_channels = ARRAY_SIZE(adxrs450_channels); |
446 | indio_dev->name = spi->dev.driver->name; | |
24742ac6 | 447 | |
ba61bb18 | 448 | ret = iio_device_register(indio_dev); |
24742ac6 MH |
449 | if (ret) |
450 | goto error_free_dev; | |
24742ac6 MH |
451 | |
452 | /* Get the device into a sane initial state */ | |
ba61bb18 | 453 | ret = adxrs450_initial_setup(indio_dev); |
24742ac6 MH |
454 | if (ret) |
455 | goto error_initial; | |
456 | return 0; | |
24742ac6 | 457 | error_initial: |
d2fffd6c | 458 | iio_device_unregister(indio_dev); |
24742ac6 | 459 | error_free_dev: |
7cbb7537 | 460 | iio_device_free(indio_dev); |
ba61bb18 | 461 | |
24742ac6 MH |
462 | error_ret: |
463 | return ret; | |
464 | } | |
465 | ||
447d4f29 | 466 | static int adxrs450_remove(struct spi_device *spi) |
24742ac6 | 467 | { |
ba61bb18 | 468 | iio_device_unregister(spi_get_drvdata(spi)); |
7cbb7537 | 469 | iio_device_free(spi_get_drvdata(spi)); |
24742ac6 MH |
470 | |
471 | return 0; | |
472 | } | |
473 | ||
617156fb MH |
474 | static const struct spi_device_id adxrs450_id[] = { |
475 | {"adxrs450", ID_ADXRS450}, | |
476 | {"adxrs453", ID_ADXRS453}, | |
477 | {} | |
478 | }; | |
479 | MODULE_DEVICE_TABLE(spi, adxrs450_id); | |
480 | ||
24742ac6 MH |
481 | static struct spi_driver adxrs450_driver = { |
482 | .driver = { | |
483 | .name = "adxrs450", | |
484 | .owner = THIS_MODULE, | |
485 | }, | |
486 | .probe = adxrs450_probe, | |
e543acf0 | 487 | .remove = adxrs450_remove, |
617156fb | 488 | .id_table = adxrs450_id, |
24742ac6 | 489 | }; |
ae6ae6fe | 490 | module_spi_driver(adxrs450_driver); |
24742ac6 MH |
491 | |
492 | MODULE_AUTHOR("Cliff Cai <cliff.cai@xxxxxxxxxx>"); | |
617156fb | 493 | MODULE_DESCRIPTION("Analog Devices ADXRS450/ADXRS453 Gyroscope SPI driver"); |
24742ac6 | 494 | MODULE_LICENSE("GPL v2"); |