Commit d6b09bd85d57752395c6407bd8a9b32eb7b279ff
Committed by
Jonathan Cameron
1 parent
f4c6d64bcf
Exists in
master
and in
20 other branches
staging:iio: Move adis16400 out of staging
This adis16400 driver is in pretty good shape now, so move it out of staging. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Showing 12 changed files with 1126 additions and 1138 deletions Side-by-side Diff
- drivers/iio/imu/Kconfig
- drivers/iio/imu/Makefile
- drivers/iio/imu/adis16400.h
- drivers/iio/imu/adis16400_buffer.c
- drivers/iio/imu/adis16400_core.c
- drivers/staging/iio/Kconfig
- drivers/staging/iio/Makefile
- drivers/staging/iio/imu/Kconfig
- drivers/staging/iio/imu/Makefile
- drivers/staging/iio/imu/adis16400.h
- drivers/staging/iio/imu/adis16400_core.c
- drivers/staging/iio/imu/adis16400_ring.c
drivers/iio/imu/Kconfig
... | ... | @@ -3,6 +3,17 @@ |
3 | 3 | # |
4 | 4 | menu "Inertial measurement units" |
5 | 5 | |
6 | +config ADIS16400 | |
7 | + tristate "Analog Devices ADIS16400 and similar IMU SPI driver" | |
8 | + depends on SPI | |
9 | + select IIO_ADIS_LIB | |
10 | + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER | |
11 | + help | |
12 | + Say yes here to build support for Analog Devices adis16300, adis16344, | |
13 | + adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, | |
14 | + adis16365, adis16400 and adis16405 triaxial inertial sensors | |
15 | + (adis16400 series also have magnetometers). | |
16 | + | |
6 | 17 | config ADIS16480 |
7 | 18 | tristate "Analog Devices ADIS16480 and similar IMU driver" |
8 | 19 | depends on SPI |
drivers/iio/imu/Makefile
drivers/iio/imu/adis16400.h
1 | +/* | |
2 | + * adis16400.h support Analog Devices ADIS16400 | |
3 | + * 3d 18g accelerometers, | |
4 | + * 3d gyroscopes, | |
5 | + * 3d 2.5gauss magnetometers via SPI | |
6 | + * | |
7 | + * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | |
8 | + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> | |
9 | + * | |
10 | + * Loosely based upon lis3l02dq.h | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify | |
13 | + * it under the terms of the GNU General Public License version 2 as | |
14 | + * published by the Free Software Foundation. | |
15 | + */ | |
16 | + | |
17 | +#ifndef SPI_ADIS16400_H_ | |
18 | +#define SPI_ADIS16400_H_ | |
19 | + | |
20 | +#include <linux/iio/imu/adis.h> | |
21 | + | |
22 | +#define ADIS16400_STARTUP_DELAY 290 /* ms */ | |
23 | +#define ADIS16400_MTEST_DELAY 90 /* ms */ | |
24 | + | |
25 | +#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ | |
26 | +#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ | |
27 | +#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ | |
28 | +#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ | |
29 | +#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ | |
30 | +#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ | |
31 | +#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ | |
32 | +#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ | |
33 | +#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ | |
34 | +#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ | |
35 | +#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ | |
36 | +#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ | |
37 | +#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ | |
38 | + | |
39 | +#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ | |
40 | +#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ | |
41 | +#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ | |
42 | + | |
43 | +#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ | |
44 | +#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ | |
45 | +#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ | |
46 | + | |
47 | +/* Calibration parameters */ | |
48 | +#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ | |
49 | +#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ | |
50 | +#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ | |
51 | +#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ | |
52 | +#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ | |
53 | +#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ | |
54 | +#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ | |
55 | +#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ | |
56 | +#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ | |
57 | +#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ | |
58 | +#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ | |
59 | +#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ | |
60 | + | |
61 | +#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ | |
62 | +#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ | |
63 | +#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ | |
64 | +#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ | |
65 | +#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ | |
66 | +#define ADIS16400_DIAG_STAT 0x3C /* System status */ | |
67 | + | |
68 | +/* Alarm functions */ | |
69 | +#define ADIS16400_GLOB_CMD 0x3E /* System command */ | |
70 | +#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ | |
71 | +#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ | |
72 | +#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ | |
73 | +#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ | |
74 | +#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ | |
75 | +#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ | |
76 | + | |
77 | +#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ | |
78 | + | |
79 | +#define ADIS16400_ERROR_ACTIVE (1<<14) | |
80 | +#define ADIS16400_NEW_DATA (1<<14) | |
81 | + | |
82 | +/* MSC_CTRL */ | |
83 | +#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) | |
84 | +#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) | |
85 | +#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) | |
86 | +#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) | |
87 | +#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) | |
88 | +#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) | |
89 | +#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) | |
90 | +#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) | |
91 | +#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) | |
92 | + | |
93 | +/* SMPL_PRD */ | |
94 | +#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) | |
95 | +#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F | |
96 | + | |
97 | +/* DIAG_STAT */ | |
98 | +#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 | |
99 | +#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 | |
100 | +#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 | |
101 | +#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 | |
102 | +#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 | |
103 | +#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 | |
104 | +#define ADIS16400_DIAG_STAT_ALARM2 9 | |
105 | +#define ADIS16400_DIAG_STAT_ALARM1 8 | |
106 | +#define ADIS16400_DIAG_STAT_FLASH_CHK 6 | |
107 | +#define ADIS16400_DIAG_STAT_SELF_TEST 5 | |
108 | +#define ADIS16400_DIAG_STAT_OVERFLOW 4 | |
109 | +#define ADIS16400_DIAG_STAT_SPI_FAIL 3 | |
110 | +#define ADIS16400_DIAG_STAT_FLASH_UPT 2 | |
111 | +#define ADIS16400_DIAG_STAT_POWER_HIGH 1 | |
112 | +#define ADIS16400_DIAG_STAT_POWER_LOW 0 | |
113 | + | |
114 | +/* GLOB_CMD */ | |
115 | +#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) | |
116 | +#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) | |
117 | +#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) | |
118 | +#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) | |
119 | +#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) | |
120 | +#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) | |
121 | + | |
122 | +/* SLP_CNT */ | |
123 | +#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) | |
124 | + | |
125 | +#define ADIS16334_RATE_DIV_SHIFT 8 | |
126 | +#define ADIS16334_RATE_INT_CLK BIT(0) | |
127 | + | |
128 | +#define ADIS16400_SPI_SLOW (u32)(300 * 1000) | |
129 | +#define ADIS16400_SPI_BURST (u32)(1000 * 1000) | |
130 | +#define ADIS16400_SPI_FAST (u32)(2000 * 1000) | |
131 | + | |
132 | +#define ADIS16400_HAS_PROD_ID BIT(0) | |
133 | +#define ADIS16400_NO_BURST BIT(1) | |
134 | +#define ADIS16400_HAS_SLOW_MODE BIT(2) | |
135 | + | |
136 | +struct adis16400_state; | |
137 | + | |
138 | +struct adis16400_chip_info { | |
139 | + const struct iio_chan_spec *channels; | |
140 | + const int num_channels; | |
141 | + const long flags; | |
142 | + unsigned int gyro_scale_micro; | |
143 | + unsigned int accel_scale_micro; | |
144 | + int temp_scale_nano; | |
145 | + int temp_offset; | |
146 | + int (*set_freq)(struct adis16400_state *st, unsigned int freq); | |
147 | + int (*get_freq)(struct adis16400_state *st); | |
148 | +}; | |
149 | + | |
150 | +/** | |
151 | + * struct adis16400_state - device instance specific data | |
152 | + * @variant: chip variant info | |
153 | + * @filt_int: integer part of requested filter frequency | |
154 | + * @adis: adis device | |
155 | + **/ | |
156 | +struct adis16400_state { | |
157 | + struct adis16400_chip_info *variant; | |
158 | + int filt_int; | |
159 | + | |
160 | + struct adis adis; | |
161 | +}; | |
162 | + | |
163 | +/* At the moment triggers are only used for ring buffer | |
164 | + * filling. This may change! | |
165 | + */ | |
166 | + | |
167 | +enum { | |
168 | + ADIS16400_SCAN_SUPPLY, | |
169 | + ADIS16400_SCAN_GYRO_X, | |
170 | + ADIS16400_SCAN_GYRO_Y, | |
171 | + ADIS16400_SCAN_GYRO_Z, | |
172 | + ADIS16400_SCAN_ACC_X, | |
173 | + ADIS16400_SCAN_ACC_Y, | |
174 | + ADIS16400_SCAN_ACC_Z, | |
175 | + ADIS16400_SCAN_MAGN_X, | |
176 | + ADIS16400_SCAN_MAGN_Y, | |
177 | + ADIS16400_SCAN_MAGN_Z, | |
178 | + ADIS16350_SCAN_TEMP_X, | |
179 | + ADIS16350_SCAN_TEMP_Y, | |
180 | + ADIS16350_SCAN_TEMP_Z, | |
181 | + ADIS16300_SCAN_INCLI_X, | |
182 | + ADIS16300_SCAN_INCLI_Y, | |
183 | + ADIS16400_SCAN_ADC, | |
184 | +}; | |
185 | + | |
186 | +#ifdef CONFIG_IIO_BUFFER | |
187 | + | |
188 | +ssize_t adis16400_read_data_from_ring(struct device *dev, | |
189 | + struct device_attribute *attr, | |
190 | + char *buf); | |
191 | + | |
192 | + | |
193 | +int adis16400_update_scan_mode(struct iio_dev *indio_dev, | |
194 | + const unsigned long *scan_mask); | |
195 | +irqreturn_t adis16400_trigger_handler(int irq, void *p); | |
196 | + | |
197 | +#else /* CONFIG_IIO_BUFFER */ | |
198 | + | |
199 | +#define adis16400_update_scan_mode NULL | |
200 | +#define adis16400_trigger_handler NULL | |
201 | + | |
202 | +#endif /* CONFIG_IIO_BUFFER */ | |
203 | + | |
204 | +#endif /* SPI_ADIS16400_H_ */ |
drivers/iio/imu/adis16400_buffer.c
1 | +#include <linux/interrupt.h> | |
2 | +#include <linux/mutex.h> | |
3 | +#include <linux/kernel.h> | |
4 | +#include <linux/spi/spi.h> | |
5 | +#include <linux/slab.h> | |
6 | +#include <linux/bitops.h> | |
7 | +#include <linux/export.h> | |
8 | + | |
9 | +#include <linux/iio/iio.h> | |
10 | +#include <linux/iio/buffer.h> | |
11 | +#include <linux/iio/triggered_buffer.h> | |
12 | +#include <linux/iio/trigger_consumer.h> | |
13 | + | |
14 | +#include "adis16400.h" | |
15 | + | |
16 | +int adis16400_update_scan_mode(struct iio_dev *indio_dev, | |
17 | + const unsigned long *scan_mask) | |
18 | +{ | |
19 | + struct adis16400_state *st = iio_priv(indio_dev); | |
20 | + struct adis *adis = &st->adis; | |
21 | + uint16_t *tx, *rx; | |
22 | + | |
23 | + if (st->variant->flags & ADIS16400_NO_BURST) | |
24 | + return adis_update_scan_mode(indio_dev, scan_mask); | |
25 | + | |
26 | + kfree(adis->xfer); | |
27 | + kfree(adis->buffer); | |
28 | + | |
29 | + adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); | |
30 | + if (!adis->xfer) | |
31 | + return -ENOMEM; | |
32 | + | |
33 | + adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), | |
34 | + GFP_KERNEL); | |
35 | + if (!adis->buffer) | |
36 | + return -ENOMEM; | |
37 | + | |
38 | + rx = adis->buffer; | |
39 | + tx = adis->buffer + indio_dev->scan_bytes; | |
40 | + | |
41 | + tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); | |
42 | + tx[1] = 0; | |
43 | + | |
44 | + adis->xfer[0].tx_buf = tx; | |
45 | + adis->xfer[0].bits_per_word = 8; | |
46 | + adis->xfer[0].len = 2; | |
47 | + adis->xfer[1].tx_buf = tx; | |
48 | + adis->xfer[1].bits_per_word = 8; | |
49 | + adis->xfer[1].len = indio_dev->scan_bytes; | |
50 | + | |
51 | + spi_message_init(&adis->msg); | |
52 | + spi_message_add_tail(&adis->xfer[0], &adis->msg); | |
53 | + spi_message_add_tail(&adis->xfer[1], &adis->msg); | |
54 | + | |
55 | + return 0; | |
56 | +} | |
57 | + | |
58 | +irqreturn_t adis16400_trigger_handler(int irq, void *p) | |
59 | +{ | |
60 | + struct iio_poll_func *pf = p; | |
61 | + struct iio_dev *indio_dev = pf->indio_dev; | |
62 | + struct adis16400_state *st = iio_priv(indio_dev); | |
63 | + struct adis *adis = &st->adis; | |
64 | + u32 old_speed_hz = st->adis.spi->max_speed_hz; | |
65 | + int ret; | |
66 | + | |
67 | + if (!adis->buffer) | |
68 | + return -ENOMEM; | |
69 | + | |
70 | + if (!(st->variant->flags & ADIS16400_NO_BURST) && | |
71 | + st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { | |
72 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; | |
73 | + spi_setup(st->adis.spi); | |
74 | + } | |
75 | + | |
76 | + ret = spi_sync(adis->spi, &adis->msg); | |
77 | + if (ret) | |
78 | + dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); | |
79 | + | |
80 | + if (!(st->variant->flags & ADIS16400_NO_BURST)) { | |
81 | + st->adis.spi->max_speed_hz = old_speed_hz; | |
82 | + spi_setup(st->adis.spi); | |
83 | + } | |
84 | + | |
85 | + /* Guaranteed to be aligned with 8 byte boundary */ | |
86 | + if (indio_dev->scan_timestamp) { | |
87 | + void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); | |
88 | + *(s64 *)b = pf->timestamp; | |
89 | + } | |
90 | + | |
91 | + iio_push_to_buffers(indio_dev, adis->buffer); | |
92 | + | |
93 | + iio_trigger_notify_done(indio_dev->trig); | |
94 | + | |
95 | + return IRQ_HANDLED; | |
96 | +} |
drivers/iio/imu/adis16400_core.c
1 | +/* | |
2 | + * adis16400.c support Analog Devices ADIS16400/5 | |
3 | + * 3d 2g Linear Accelerometers, | |
4 | + * 3d Gyroscopes, | |
5 | + * 3d Magnetometers via SPI | |
6 | + * | |
7 | + * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | |
8 | + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> | |
9 | + * Copyright (c) 2011 Analog Devices Inc. | |
10 | + * | |
11 | + * This program is free software; you can redistribute it and/or modify | |
12 | + * it under the terms of the GNU General Public License version 2 as | |
13 | + * published by the Free Software Foundation. | |
14 | + * | |
15 | + */ | |
16 | + | |
17 | +#include <linux/interrupt.h> | |
18 | +#include <linux/irq.h> | |
19 | +#include <linux/delay.h> | |
20 | +#include <linux/mutex.h> | |
21 | +#include <linux/device.h> | |
22 | +#include <linux/kernel.h> | |
23 | +#include <linux/spi/spi.h> | |
24 | +#include <linux/slab.h> | |
25 | +#include <linux/sysfs.h> | |
26 | +#include <linux/list.h> | |
27 | +#include <linux/module.h> | |
28 | + | |
29 | +#include <linux/iio/iio.h> | |
30 | +#include <linux/iio/sysfs.h> | |
31 | +#include <linux/iio/buffer.h> | |
32 | + | |
33 | +#include "adis16400.h" | |
34 | + | |
35 | +enum adis16400_chip_variant { | |
36 | + ADIS16300, | |
37 | + ADIS16334, | |
38 | + ADIS16350, | |
39 | + ADIS16360, | |
40 | + ADIS16362, | |
41 | + ADIS16364, | |
42 | + ADIS16400, | |
43 | +}; | |
44 | + | |
45 | +static int adis16334_get_freq(struct adis16400_state *st) | |
46 | +{ | |
47 | + int ret; | |
48 | + uint16_t t; | |
49 | + | |
50 | + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); | |
51 | + if (ret < 0) | |
52 | + return ret; | |
53 | + | |
54 | + t >>= ADIS16334_RATE_DIV_SHIFT; | |
55 | + | |
56 | + return (8192 >> t) / 10; | |
57 | +} | |
58 | + | |
59 | +static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) | |
60 | +{ | |
61 | + unsigned int t; | |
62 | + | |
63 | + freq *= 10; | |
64 | + if (freq < 8192) | |
65 | + t = ilog2(8192 / freq); | |
66 | + else | |
67 | + t = 0; | |
68 | + | |
69 | + if (t > 0x31) | |
70 | + t = 0x31; | |
71 | + | |
72 | + t <<= ADIS16334_RATE_DIV_SHIFT; | |
73 | + t |= ADIS16334_RATE_INT_CLK; | |
74 | + | |
75 | + return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); | |
76 | +} | |
77 | + | |
78 | +static int adis16400_get_freq(struct adis16400_state *st) | |
79 | +{ | |
80 | + int sps, ret; | |
81 | + uint16_t t; | |
82 | + | |
83 | + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); | |
84 | + if (ret < 0) | |
85 | + return ret; | |
86 | + | |
87 | + sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; | |
88 | + sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; | |
89 | + | |
90 | + return sps; | |
91 | +} | |
92 | + | |
93 | +static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) | |
94 | +{ | |
95 | + unsigned int t; | |
96 | + | |
97 | + t = 1638 / freq; | |
98 | + if (t > 0) | |
99 | + t--; | |
100 | + t &= ADIS16400_SMPL_PRD_DIV_MASK; | |
101 | + | |
102 | + if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) | |
103 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; | |
104 | + else | |
105 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
106 | + | |
107 | + return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); | |
108 | +} | |
109 | + | |
110 | +static ssize_t adis16400_read_frequency(struct device *dev, | |
111 | + struct device_attribute *attr, | |
112 | + char *buf) | |
113 | +{ | |
114 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
115 | + struct adis16400_state *st = iio_priv(indio_dev); | |
116 | + int ret; | |
117 | + | |
118 | + ret = st->variant->get_freq(st); | |
119 | + if (ret < 0) | |
120 | + return ret; | |
121 | + | |
122 | + return sprintf(buf, "%d\n", ret); | |
123 | +} | |
124 | + | |
125 | +static const unsigned adis16400_3db_divisors[] = { | |
126 | + [0] = 2, /* Special case */ | |
127 | + [1] = 6, | |
128 | + [2] = 12, | |
129 | + [3] = 25, | |
130 | + [4] = 50, | |
131 | + [5] = 100, | |
132 | + [6] = 200, | |
133 | + [7] = 200, /* Not a valid setting */ | |
134 | +}; | |
135 | + | |
136 | +static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) | |
137 | +{ | |
138 | + struct adis16400_state *st = iio_priv(indio_dev); | |
139 | + uint16_t val16; | |
140 | + int i, ret; | |
141 | + | |
142 | + for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { | |
143 | + if (sps / adis16400_3db_divisors[i] >= val) | |
144 | + break; | |
145 | + } | |
146 | + | |
147 | + ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); | |
148 | + if (ret < 0) | |
149 | + return ret; | |
150 | + | |
151 | + ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, | |
152 | + (val16 & ~0x07) | i); | |
153 | + return ret; | |
154 | +} | |
155 | + | |
156 | +static ssize_t adis16400_write_frequency(struct device *dev, | |
157 | + struct device_attribute *attr, const char *buf, size_t len) | |
158 | +{ | |
159 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
160 | + struct adis16400_state *st = iio_priv(indio_dev); | |
161 | + long val; | |
162 | + int ret; | |
163 | + | |
164 | + ret = kstrtol(buf, 10, &val); | |
165 | + if (ret) | |
166 | + return ret; | |
167 | + | |
168 | + if (val == 0) | |
169 | + return -EINVAL; | |
170 | + | |
171 | + mutex_lock(&indio_dev->mlock); | |
172 | + st->variant->set_freq(st, val); | |
173 | + mutex_unlock(&indio_dev->mlock); | |
174 | + | |
175 | + return ret ? ret : len; | |
176 | +} | |
177 | + | |
178 | +/* Power down the device */ | |
179 | +static int adis16400_stop_device(struct iio_dev *indio_dev) | |
180 | +{ | |
181 | + struct adis16400_state *st = iio_priv(indio_dev); | |
182 | + int ret; | |
183 | + | |
184 | + ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, | |
185 | + ADIS16400_SLP_CNT_POWER_OFF); | |
186 | + if (ret) | |
187 | + dev_err(&indio_dev->dev, | |
188 | + "problem with turning device off: SLP_CNT"); | |
189 | + | |
190 | + return ret; | |
191 | +} | |
192 | + | |
193 | +static int adis16400_initial_setup(struct iio_dev *indio_dev) | |
194 | +{ | |
195 | + struct adis16400_state *st = iio_priv(indio_dev); | |
196 | + uint16_t prod_id, smp_prd; | |
197 | + unsigned int device_id; | |
198 | + int ret; | |
199 | + | |
200 | + /* use low spi speed for init if the device has a slow mode */ | |
201 | + if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) | |
202 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; | |
203 | + else | |
204 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
205 | + st->adis.spi->mode = SPI_MODE_3; | |
206 | + spi_setup(st->adis.spi); | |
207 | + | |
208 | + ret = adis_initial_startup(&st->adis); | |
209 | + if (ret) | |
210 | + return ret; | |
211 | + | |
212 | + if (st->variant->flags & ADIS16400_HAS_PROD_ID) { | |
213 | + ret = adis_read_reg_16(&st->adis, | |
214 | + ADIS16400_PRODUCT_ID, &prod_id); | |
215 | + if (ret) | |
216 | + goto err_ret; | |
217 | + | |
218 | + sscanf(indio_dev->name, "adis%u\n", &device_id); | |
219 | + | |
220 | + if (prod_id != device_id) | |
221 | + dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", | |
222 | + device_id, prod_id); | |
223 | + | |
224 | + dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", | |
225 | + indio_dev->name, prod_id, | |
226 | + st->adis.spi->chip_select, st->adis.spi->irq); | |
227 | + } | |
228 | + /* use high spi speed if possible */ | |
229 | + if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { | |
230 | + ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); | |
231 | + if (ret) | |
232 | + goto err_ret; | |
233 | + | |
234 | + if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { | |
235 | + st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
236 | + spi_setup(st->adis.spi); | |
237 | + } | |
238 | + } | |
239 | + | |
240 | +err_ret: | |
241 | + return ret; | |
242 | +} | |
243 | + | |
244 | +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | |
245 | + adis16400_read_frequency, | |
246 | + adis16400_write_frequency); | |
247 | + | |
248 | +static const uint8_t adis16400_addresses[] = { | |
249 | + [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, | |
250 | + [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, | |
251 | + [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, | |
252 | + [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, | |
253 | + [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, | |
254 | + [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, | |
255 | +}; | |
256 | + | |
257 | +static int adis16400_write_raw(struct iio_dev *indio_dev, | |
258 | + struct iio_chan_spec const *chan, int val, int val2, long info) | |
259 | +{ | |
260 | + struct adis16400_state *st = iio_priv(indio_dev); | |
261 | + int ret, sps; | |
262 | + | |
263 | + switch (info) { | |
264 | + case IIO_CHAN_INFO_CALIBBIAS: | |
265 | + mutex_lock(&indio_dev->mlock); | |
266 | + ret = adis_write_reg_16(&st->adis, | |
267 | + adis16400_addresses[chan->scan_index], val); | |
268 | + mutex_unlock(&indio_dev->mlock); | |
269 | + return ret; | |
270 | + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
271 | + /* | |
272 | + * Need to cache values so we can update if the frequency | |
273 | + * changes. | |
274 | + */ | |
275 | + mutex_lock(&indio_dev->mlock); | |
276 | + st->filt_int = val; | |
277 | + /* Work out update to current value */ | |
278 | + sps = st->variant->get_freq(st); | |
279 | + if (sps < 0) { | |
280 | + mutex_unlock(&indio_dev->mlock); | |
281 | + return sps; | |
282 | + } | |
283 | + | |
284 | + ret = adis16400_set_filter(indio_dev, sps, val); | |
285 | + mutex_unlock(&indio_dev->mlock); | |
286 | + return ret; | |
287 | + default: | |
288 | + return -EINVAL; | |
289 | + } | |
290 | +} | |
291 | + | |
292 | +static int adis16400_read_raw(struct iio_dev *indio_dev, | |
293 | + struct iio_chan_spec const *chan, int *val, int *val2, long info) | |
294 | +{ | |
295 | + struct adis16400_state *st = iio_priv(indio_dev); | |
296 | + int16_t val16; | |
297 | + int ret; | |
298 | + | |
299 | + switch (info) { | |
300 | + case IIO_CHAN_INFO_RAW: | |
301 | + return adis_single_conversion(indio_dev, chan, 0, val); | |
302 | + case IIO_CHAN_INFO_SCALE: | |
303 | + switch (chan->type) { | |
304 | + case IIO_ANGL_VEL: | |
305 | + *val = 0; | |
306 | + *val2 = st->variant->gyro_scale_micro; | |
307 | + return IIO_VAL_INT_PLUS_MICRO; | |
308 | + case IIO_VOLTAGE: | |
309 | + *val = 0; | |
310 | + if (chan->channel == 0) { | |
311 | + *val = 2; | |
312 | + *val2 = 418000; /* 2.418 mV */ | |
313 | + } else { | |
314 | + *val = 0; | |
315 | + *val2 = 805800; /* 805.8 uV */ | |
316 | + } | |
317 | + return IIO_VAL_INT_PLUS_MICRO; | |
318 | + case IIO_ACCEL: | |
319 | + *val = 0; | |
320 | + *val2 = st->variant->accel_scale_micro; | |
321 | + return IIO_VAL_INT_PLUS_MICRO; | |
322 | + case IIO_MAGN: | |
323 | + *val = 0; | |
324 | + *val2 = 500; /* 0.5 mgauss */ | |
325 | + return IIO_VAL_INT_PLUS_MICRO; | |
326 | + case IIO_TEMP: | |
327 | + *val = st->variant->temp_scale_nano / 1000000; | |
328 | + *val2 = (st->variant->temp_scale_nano % 1000000); | |
329 | + return IIO_VAL_INT_PLUS_MICRO; | |
330 | + default: | |
331 | + return -EINVAL; | |
332 | + } | |
333 | + case IIO_CHAN_INFO_CALIBBIAS: | |
334 | + mutex_lock(&indio_dev->mlock); | |
335 | + ret = adis_read_reg_16(&st->adis, | |
336 | + adis16400_addresses[chan->scan_index], &val16); | |
337 | + mutex_unlock(&indio_dev->mlock); | |
338 | + if (ret) | |
339 | + return ret; | |
340 | + val16 = ((val16 & 0xFFF) << 4) >> 4; | |
341 | + *val = val16; | |
342 | + return IIO_VAL_INT; | |
343 | + case IIO_CHAN_INFO_OFFSET: | |
344 | + /* currently only temperature */ | |
345 | + *val = st->variant->temp_offset; | |
346 | + return IIO_VAL_INT; | |
347 | + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
348 | + mutex_lock(&indio_dev->mlock); | |
349 | + /* Need both the number of taps and the sampling frequency */ | |
350 | + ret = adis_read_reg_16(&st->adis, | |
351 | + ADIS16400_SENS_AVG, | |
352 | + &val16); | |
353 | + if (ret < 0) { | |
354 | + mutex_unlock(&indio_dev->mlock); | |
355 | + return ret; | |
356 | + } | |
357 | + ret = st->variant->get_freq(st); | |
358 | + if (ret >= 0) | |
359 | + *val = ret / adis16400_3db_divisors[val16 & 0x07]; | |
360 | + *val2 = 0; | |
361 | + mutex_unlock(&indio_dev->mlock); | |
362 | + if (ret < 0) | |
363 | + return ret; | |
364 | + return IIO_VAL_INT_PLUS_MICRO; | |
365 | + default: | |
366 | + return -EINVAL; | |
367 | + } | |
368 | +} | |
369 | + | |
370 | +#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ | |
371 | + .type = IIO_VOLTAGE, \ | |
372 | + .indexed = 1, \ | |
373 | + .channel = 0, \ | |
374 | + .extend_name = name, \ | |
375 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
376 | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | |
377 | + .address = (addr), \ | |
378 | + .scan_index = (si), \ | |
379 | + .scan_type = { \ | |
380 | + .sign = 'u', \ | |
381 | + .realbits = (bits), \ | |
382 | + .storagebits = 16, \ | |
383 | + .shift = 0, \ | |
384 | + .endianness = IIO_BE, \ | |
385 | + }, \ | |
386 | +} | |
387 | + | |
388 | +#define ADIS16400_SUPPLY_CHAN(addr, bits) \ | |
389 | + ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) | |
390 | + | |
391 | +#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ | |
392 | + ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) | |
393 | + | |
394 | +#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ | |
395 | + .type = IIO_ANGL_VEL, \ | |
396 | + .modified = 1, \ | |
397 | + .channel2 = IIO_MOD_ ## mod, \ | |
398 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
399 | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ | |
400 | + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
401 | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
402 | + .address = addr, \ | |
403 | + .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ | |
404 | + .scan_type = { \ | |
405 | + .sign = 's', \ | |
406 | + .realbits = (bits), \ | |
407 | + .storagebits = 16, \ | |
408 | + .shift = 0, \ | |
409 | + .endianness = IIO_BE, \ | |
410 | + }, \ | |
411 | +} | |
412 | + | |
413 | +#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ | |
414 | + .type = IIO_ACCEL, \ | |
415 | + .modified = 1, \ | |
416 | + .channel2 = IIO_MOD_ ## mod, \ | |
417 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
418 | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ | |
419 | + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
420 | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
421 | + .address = (addr), \ | |
422 | + .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ | |
423 | + .scan_type = { \ | |
424 | + .sign = 's', \ | |
425 | + .realbits = (bits), \ | |
426 | + .storagebits = 16, \ | |
427 | + .shift = 0, \ | |
428 | + .endianness = IIO_BE, \ | |
429 | + }, \ | |
430 | +} | |
431 | + | |
432 | +#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ | |
433 | + .type = IIO_MAGN, \ | |
434 | + .modified = 1, \ | |
435 | + .channel2 = IIO_MOD_ ## mod, \ | |
436 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
437 | + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
438 | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
439 | + .address = (addr), \ | |
440 | + .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ | |
441 | + .scan_type = { \ | |
442 | + .sign = 's', \ | |
443 | + .realbits = (bits), \ | |
444 | + .storagebits = 16, \ | |
445 | + .shift = 0, \ | |
446 | + .endianness = IIO_BE, \ | |
447 | + }, \ | |
448 | +} | |
449 | + | |
450 | +#define ADIS16400_MOD_TEMP_NAME_X "x" | |
451 | +#define ADIS16400_MOD_TEMP_NAME_Y "y" | |
452 | +#define ADIS16400_MOD_TEMP_NAME_Z "z" | |
453 | + | |
454 | +#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ | |
455 | + .type = IIO_TEMP, \ | |
456 | + .indexed = 1, \ | |
457 | + .channel = 0, \ | |
458 | + .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ | |
459 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
460 | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ | |
461 | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ | |
462 | + IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
463 | + .address = (addr), \ | |
464 | + .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ | |
465 | + .scan_type = { \ | |
466 | + .sign = 's', \ | |
467 | + .realbits = (bits), \ | |
468 | + .storagebits = 16, \ | |
469 | + .shift = 0, \ | |
470 | + .endianness = IIO_BE, \ | |
471 | + }, \ | |
472 | +} | |
473 | + | |
474 | +#define ADIS16400_TEMP_CHAN(addr, bits) { \ | |
475 | + .type = IIO_TEMP, \ | |
476 | + .indexed = 1, \ | |
477 | + .channel = 0, \ | |
478 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
479 | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ | |
480 | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | |
481 | + .address = (addr), \ | |
482 | + .scan_index = ADIS16350_SCAN_TEMP_X, \ | |
483 | + .scan_type = { \ | |
484 | + .sign = 's', \ | |
485 | + .realbits = (bits), \ | |
486 | + .storagebits = 16, \ | |
487 | + .shift = 0, \ | |
488 | + .endianness = IIO_BE, \ | |
489 | + }, \ | |
490 | +} | |
491 | + | |
492 | +#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ | |
493 | + .type = IIO_INCLI, \ | |
494 | + .modified = 1, \ | |
495 | + .channel2 = IIO_MOD_ ## mod, \ | |
496 | + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
497 | + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ | |
498 | + .address = (addr), \ | |
499 | + .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ | |
500 | + .scan_type = { \ | |
501 | + .sign = 's', \ | |
502 | + .realbits = (bits), \ | |
503 | + .storagebits = 16, \ | |
504 | + .shift = 0, \ | |
505 | + .endianness = IIO_BE, \ | |
506 | + }, \ | |
507 | +} | |
508 | + | |
509 | +static const struct iio_chan_spec adis16400_channels[] = { | |
510 | + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), | |
511 | + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
512 | + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
513 | + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
514 | + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
515 | + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
516 | + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
517 | + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), | |
518 | + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), | |
519 | + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), | |
520 | + ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), | |
521 | + ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), | |
522 | + IIO_CHAN_SOFT_TIMESTAMP(12) | |
523 | +}; | |
524 | + | |
525 | +static const struct iio_chan_spec adis16350_channels[] = { | |
526 | + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), | |
527 | + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
528 | + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
529 | + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
530 | + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
531 | + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
532 | + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
533 | + ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), | |
534 | + ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), | |
535 | + ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), | |
536 | + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), | |
537 | + ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), | |
538 | + ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), | |
539 | + ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), | |
540 | + IIO_CHAN_SOFT_TIMESTAMP(11) | |
541 | +}; | |
542 | + | |
543 | +static const struct iio_chan_spec adis16300_channels[] = { | |
544 | + ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), | |
545 | + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
546 | + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
547 | + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
548 | + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
549 | + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), | |
550 | + ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), | |
551 | + ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), | |
552 | + ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), | |
553 | + IIO_CHAN_SOFT_TIMESTAMP(14) | |
554 | +}; | |
555 | + | |
556 | +static const struct iio_chan_spec adis16334_channels[] = { | |
557 | + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
558 | + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
559 | + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
560 | + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
561 | + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
562 | + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
563 | + ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), | |
564 | + IIO_CHAN_SOFT_TIMESTAMP(8) | |
565 | +}; | |
566 | + | |
567 | +static struct attribute *adis16400_attributes[] = { | |
568 | + &iio_dev_attr_sampling_frequency.dev_attr.attr, | |
569 | + NULL | |
570 | +}; | |
571 | + | |
572 | +static const struct attribute_group adis16400_attribute_group = { | |
573 | + .attrs = adis16400_attributes, | |
574 | +}; | |
575 | + | |
576 | +static struct adis16400_chip_info adis16400_chips[] = { | |
577 | + [ADIS16300] = { | |
578 | + .channels = adis16300_channels, | |
579 | + .num_channels = ARRAY_SIZE(adis16300_channels), | |
580 | + .flags = ADIS16400_HAS_SLOW_MODE, | |
581 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
582 | + .accel_scale_micro = 5884, | |
583 | + .temp_scale_nano = 140000000, /* 0.14 C */ | |
584 | + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ | |
585 | + .set_freq = adis16400_set_freq, | |
586 | + .get_freq = adis16400_get_freq, | |
587 | + }, | |
588 | + [ADIS16334] = { | |
589 | + .channels = adis16334_channels, | |
590 | + .num_channels = ARRAY_SIZE(adis16334_channels), | |
591 | + .flags = ADIS16400_HAS_PROD_ID, | |
592 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
593 | + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ | |
594 | + .temp_scale_nano = 67850000, /* 0.06785 C */ | |
595 | + .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ | |
596 | + .set_freq = adis16334_set_freq, | |
597 | + .get_freq = adis16334_get_freq, | |
598 | + }, | |
599 | + [ADIS16350] = { | |
600 | + .channels = adis16350_channels, | |
601 | + .num_channels = ARRAY_SIZE(adis16350_channels), | |
602 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ | |
603 | + .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ | |
604 | + .temp_scale_nano = 145300000, /* 0.1453 C */ | |
605 | + .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ | |
606 | + .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, | |
607 | + .set_freq = adis16400_set_freq, | |
608 | + .get_freq = adis16400_get_freq, | |
609 | + }, | |
610 | + [ADIS16360] = { | |
611 | + .channels = adis16350_channels, | |
612 | + .num_channels = ARRAY_SIZE(adis16350_channels), | |
613 | + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
614 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
615 | + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ | |
616 | + .temp_scale_nano = 136000000, /* 0.136 C */ | |
617 | + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
618 | + .set_freq = adis16400_set_freq, | |
619 | + .get_freq = adis16400_get_freq, | |
620 | + }, | |
621 | + [ADIS16362] = { | |
622 | + .channels = adis16350_channels, | |
623 | + .num_channels = ARRAY_SIZE(adis16350_channels), | |
624 | + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
625 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
626 | + .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ | |
627 | + .temp_scale_nano = 136000000, /* 0.136 C */ | |
628 | + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
629 | + .set_freq = adis16400_set_freq, | |
630 | + .get_freq = adis16400_get_freq, | |
631 | + }, | |
632 | + [ADIS16364] = { | |
633 | + .channels = adis16350_channels, | |
634 | + .num_channels = ARRAY_SIZE(adis16350_channels), | |
635 | + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
636 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
637 | + .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ | |
638 | + .temp_scale_nano = 136000000, /* 0.136 C */ | |
639 | + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
640 | + .set_freq = adis16400_set_freq, | |
641 | + .get_freq = adis16400_get_freq, | |
642 | + }, | |
643 | + [ADIS16400] = { | |
644 | + .channels = adis16400_channels, | |
645 | + .num_channels = ARRAY_SIZE(adis16400_channels), | |
646 | + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
647 | + .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
648 | + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ | |
649 | + .temp_scale_nano = 140000000, /* 0.14 C */ | |
650 | + .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ | |
651 | + .set_freq = adis16400_set_freq, | |
652 | + .get_freq = adis16400_get_freq, | |
653 | + } | |
654 | +}; | |
655 | + | |
656 | +static const struct iio_info adis16400_info = { | |
657 | + .driver_module = THIS_MODULE, | |
658 | + .read_raw = &adis16400_read_raw, | |
659 | + .write_raw = &adis16400_write_raw, | |
660 | + .attrs = &adis16400_attribute_group, | |
661 | + .update_scan_mode = adis16400_update_scan_mode, | |
662 | +}; | |
663 | + | |
664 | +static const unsigned long adis16400_burst_scan_mask[] = { | |
665 | + ~0UL, | |
666 | + 0, | |
667 | +}; | |
668 | + | |
669 | +static const char * const adis16400_status_error_msgs[] = { | |
670 | + [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", | |
671 | + [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", | |
672 | + [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", | |
673 | + [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", | |
674 | + [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", | |
675 | + [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", | |
676 | + [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", | |
677 | + [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", | |
678 | + [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", | |
679 | + [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", | |
680 | + [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", | |
681 | + [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", | |
682 | + [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", | |
683 | + [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", | |
684 | + [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", | |
685 | +}; | |
686 | + | |
687 | +static const struct adis_data adis16400_data = { | |
688 | + .msc_ctrl_reg = ADIS16400_MSC_CTRL, | |
689 | + .glob_cmd_reg = ADIS16400_GLOB_CMD, | |
690 | + .diag_stat_reg = ADIS16400_DIAG_STAT, | |
691 | + | |
692 | + .read_delay = 50, | |
693 | + .write_delay = 50, | |
694 | + | |
695 | + .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, | |
696 | + .startup_delay = ADIS16400_STARTUP_DELAY, | |
697 | + | |
698 | + .status_error_msgs = adis16400_status_error_msgs, | |
699 | + .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | | |
700 | + BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | | |
701 | + BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | | |
702 | + BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | | |
703 | + BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | | |
704 | + BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | | |
705 | + BIT(ADIS16400_DIAG_STAT_ALARM2) | | |
706 | + BIT(ADIS16400_DIAG_STAT_ALARM1) | | |
707 | + BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | | |
708 | + BIT(ADIS16400_DIAG_STAT_SELF_TEST) | | |
709 | + BIT(ADIS16400_DIAG_STAT_OVERFLOW) | | |
710 | + BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | | |
711 | + BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | | |
712 | + BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | | |
713 | + BIT(ADIS16400_DIAG_STAT_POWER_LOW), | |
714 | +}; | |
715 | + | |
716 | +static int adis16400_probe(struct spi_device *spi) | |
717 | +{ | |
718 | + struct adis16400_state *st; | |
719 | + struct iio_dev *indio_dev; | |
720 | + int ret; | |
721 | + | |
722 | + indio_dev = iio_device_alloc(sizeof(*st)); | |
723 | + if (indio_dev == NULL) | |
724 | + return -ENOMEM; | |
725 | + | |
726 | + st = iio_priv(indio_dev); | |
727 | + /* this is only used for removal purposes */ | |
728 | + spi_set_drvdata(spi, indio_dev); | |
729 | + | |
730 | + /* setup the industrialio driver allocated elements */ | |
731 | + st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; | |
732 | + indio_dev->dev.parent = &spi->dev; | |
733 | + indio_dev->name = spi_get_device_id(spi)->name; | |
734 | + indio_dev->channels = st->variant->channels; | |
735 | + indio_dev->num_channels = st->variant->num_channels; | |
736 | + indio_dev->info = &adis16400_info; | |
737 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
738 | + | |
739 | + if (!(st->variant->flags & ADIS16400_NO_BURST)) | |
740 | + indio_dev->available_scan_masks = adis16400_burst_scan_mask; | |
741 | + | |
742 | + ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); | |
743 | + if (ret) | |
744 | + goto error_free_dev; | |
745 | + | |
746 | + ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, | |
747 | + adis16400_trigger_handler); | |
748 | + if (ret) | |
749 | + goto error_free_dev; | |
750 | + | |
751 | + /* Get the device into a sane initial state */ | |
752 | + ret = adis16400_initial_setup(indio_dev); | |
753 | + if (ret) | |
754 | + goto error_cleanup_buffer; | |
755 | + ret = iio_device_register(indio_dev); | |
756 | + if (ret) | |
757 | + goto error_cleanup_buffer; | |
758 | + | |
759 | + return 0; | |
760 | + | |
761 | +error_cleanup_buffer: | |
762 | + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | |
763 | +error_free_dev: | |
764 | + iio_device_free(indio_dev); | |
765 | + return ret; | |
766 | +} | |
767 | + | |
768 | +static int adis16400_remove(struct spi_device *spi) | |
769 | +{ | |
770 | + struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
771 | + struct adis16400_state *st = iio_priv(indio_dev); | |
772 | + | |
773 | + iio_device_unregister(indio_dev); | |
774 | + adis16400_stop_device(indio_dev); | |
775 | + | |
776 | + adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | |
777 | + | |
778 | + iio_device_free(indio_dev); | |
779 | + | |
780 | + return 0; | |
781 | +} | |
782 | + | |
783 | +static const struct spi_device_id adis16400_id[] = { | |
784 | + {"adis16300", ADIS16300}, | |
785 | + {"adis16334", ADIS16334}, | |
786 | + {"adis16350", ADIS16350}, | |
787 | + {"adis16354", ADIS16350}, | |
788 | + {"adis16355", ADIS16350}, | |
789 | + {"adis16360", ADIS16360}, | |
790 | + {"adis16362", ADIS16362}, | |
791 | + {"adis16364", ADIS16364}, | |
792 | + {"adis16365", ADIS16360}, | |
793 | + {"adis16400", ADIS16400}, | |
794 | + {"adis16405", ADIS16400}, | |
795 | + {} | |
796 | +}; | |
797 | +MODULE_DEVICE_TABLE(spi, adis16400_id); | |
798 | + | |
799 | +static struct spi_driver adis16400_driver = { | |
800 | + .driver = { | |
801 | + .name = "adis16400", | |
802 | + .owner = THIS_MODULE, | |
803 | + }, | |
804 | + .id_table = adis16400_id, | |
805 | + .probe = adis16400_probe, | |
806 | + .remove = adis16400_remove, | |
807 | +}; | |
808 | +module_spi_driver(adis16400_driver); | |
809 | + | |
810 | +MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>"); | |
811 | +MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); | |
812 | +MODULE_LICENSE("GPL v2"); |
drivers/staging/iio/Kconfig
... | ... | @@ -32,7 +32,6 @@ |
32 | 32 | source "drivers/staging/iio/frequency/Kconfig" |
33 | 33 | source "drivers/staging/iio/gyro/Kconfig" |
34 | 34 | source "drivers/staging/iio/impedance-analyzer/Kconfig" |
35 | -source "drivers/staging/iio/imu/Kconfig" | |
36 | 35 | source "drivers/staging/iio/light/Kconfig" |
37 | 36 | source "drivers/staging/iio/magnetometer/Kconfig" |
38 | 37 | source "drivers/staging/iio/meter/Kconfig" |
drivers/staging/iio/Makefile
drivers/staging/iio/imu/Kconfig
1 | -# | |
2 | -# IIO imu drivers configuration | |
3 | -# | |
4 | -menu "Inertial measurement units" | |
5 | - | |
6 | -config ADIS16400 | |
7 | - tristate "Analog Devices ADIS16400 and similar IMU SPI driver" | |
8 | - depends on SPI | |
9 | - select IIO_ADIS_LIB | |
10 | - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER | |
11 | - help | |
12 | - Say yes here to build support for Analog Devices adis16300, adis16344, | |
13 | - adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, | |
14 | - adis16365, adis16400 and adis16405 triaxial inertial sensors | |
15 | - (adis16400 series also have magnetometers). | |
16 | - | |
17 | -endmenu |
drivers/staging/iio/imu/Makefile
drivers/staging/iio/imu/adis16400.h
1 | -/* | |
2 | - * adis16400.h support Analog Devices ADIS16400 | |
3 | - * 3d 18g accelerometers, | |
4 | - * 3d gyroscopes, | |
5 | - * 3d 2.5gauss magnetometers via SPI | |
6 | - * | |
7 | - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | |
8 | - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> | |
9 | - * | |
10 | - * Loosely based upon lis3l02dq.h | |
11 | - * | |
12 | - * This program is free software; you can redistribute it and/or modify | |
13 | - * it under the terms of the GNU General Public License version 2 as | |
14 | - * published by the Free Software Foundation. | |
15 | - */ | |
16 | - | |
17 | -#ifndef SPI_ADIS16400_H_ | |
18 | -#define SPI_ADIS16400_H_ | |
19 | - | |
20 | -#include <linux/iio/imu/adis.h> | |
21 | - | |
22 | -#define ADIS16400_STARTUP_DELAY 290 /* ms */ | |
23 | -#define ADIS16400_MTEST_DELAY 90 /* ms */ | |
24 | - | |
25 | -#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */ | |
26 | -#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */ | |
27 | -#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */ | |
28 | -#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */ | |
29 | -#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */ | |
30 | -#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */ | |
31 | -#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */ | |
32 | -#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */ | |
33 | -#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */ | |
34 | -#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */ | |
35 | -#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */ | |
36 | -#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */ | |
37 | -#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */ | |
38 | - | |
39 | -#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */ | |
40 | -#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */ | |
41 | -#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */ | |
42 | - | |
43 | -#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */ | |
44 | -#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */ | |
45 | -#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */ | |
46 | - | |
47 | -/* Calibration parameters */ | |
48 | -#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */ | |
49 | -#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */ | |
50 | -#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */ | |
51 | -#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */ | |
52 | -#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */ | |
53 | -#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */ | |
54 | -#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */ | |
55 | -#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */ | |
56 | -#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */ | |
57 | -#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */ | |
58 | -#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */ | |
59 | -#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */ | |
60 | - | |
61 | -#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */ | |
62 | -#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */ | |
63 | -#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */ | |
64 | -#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */ | |
65 | -#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */ | |
66 | -#define ADIS16400_DIAG_STAT 0x3C /* System status */ | |
67 | - | |
68 | -/* Alarm functions */ | |
69 | -#define ADIS16400_GLOB_CMD 0x3E /* System command */ | |
70 | -#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */ | |
71 | -#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */ | |
72 | -#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */ | |
73 | -#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */ | |
74 | -#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */ | |
75 | -#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */ | |
76 | - | |
77 | -#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */ | |
78 | - | |
79 | -#define ADIS16400_ERROR_ACTIVE (1<<14) | |
80 | -#define ADIS16400_NEW_DATA (1<<14) | |
81 | - | |
82 | -/* MSC_CTRL */ | |
83 | -#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11) | |
84 | -#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10) | |
85 | -#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9) | |
86 | -#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8) | |
87 | -#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7) | |
88 | -#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6) | |
89 | -#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2) | |
90 | -#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) | |
91 | -#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0) | |
92 | - | |
93 | -/* SMPL_PRD */ | |
94 | -#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7) | |
95 | -#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F | |
96 | - | |
97 | -/* DIAG_STAT */ | |
98 | -#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15 | |
99 | -#define ADIS16400_DIAG_STAT_YACCL_FAIL 14 | |
100 | -#define ADIS16400_DIAG_STAT_XACCL_FAIL 13 | |
101 | -#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12 | |
102 | -#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11 | |
103 | -#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10 | |
104 | -#define ADIS16400_DIAG_STAT_ALARM2 9 | |
105 | -#define ADIS16400_DIAG_STAT_ALARM1 8 | |
106 | -#define ADIS16400_DIAG_STAT_FLASH_CHK 6 | |
107 | -#define ADIS16400_DIAG_STAT_SELF_TEST 5 | |
108 | -#define ADIS16400_DIAG_STAT_OVERFLOW 4 | |
109 | -#define ADIS16400_DIAG_STAT_SPI_FAIL 3 | |
110 | -#define ADIS16400_DIAG_STAT_FLASH_UPT 2 | |
111 | -#define ADIS16400_DIAG_STAT_POWER_HIGH 1 | |
112 | -#define ADIS16400_DIAG_STAT_POWER_LOW 0 | |
113 | - | |
114 | -/* GLOB_CMD */ | |
115 | -#define ADIS16400_GLOB_CMD_SW_RESET (1<<7) | |
116 | -#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4) | |
117 | -#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3) | |
118 | -#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2) | |
119 | -#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1) | |
120 | -#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0) | |
121 | - | |
122 | -/* SLP_CNT */ | |
123 | -#define ADIS16400_SLP_CNT_POWER_OFF (1<<8) | |
124 | - | |
125 | -#define ADIS16334_RATE_DIV_SHIFT 8 | |
126 | -#define ADIS16334_RATE_INT_CLK BIT(0) | |
127 | - | |
128 | -#define ADIS16400_SPI_SLOW (u32)(300 * 1000) | |
129 | -#define ADIS16400_SPI_BURST (u32)(1000 * 1000) | |
130 | -#define ADIS16400_SPI_FAST (u32)(2000 * 1000) | |
131 | - | |
132 | -#define ADIS16400_HAS_PROD_ID BIT(0) | |
133 | -#define ADIS16400_NO_BURST BIT(1) | |
134 | -#define ADIS16400_HAS_SLOW_MODE BIT(2) | |
135 | - | |
136 | -struct adis16400_state; | |
137 | - | |
138 | -struct adis16400_chip_info { | |
139 | - const struct iio_chan_spec *channels; | |
140 | - const int num_channels; | |
141 | - const long flags; | |
142 | - unsigned int gyro_scale_micro; | |
143 | - unsigned int accel_scale_micro; | |
144 | - int temp_scale_nano; | |
145 | - int temp_offset; | |
146 | - int (*set_freq)(struct adis16400_state *st, unsigned int freq); | |
147 | - int (*get_freq)(struct adis16400_state *st); | |
148 | -}; | |
149 | - | |
150 | -/** | |
151 | - * struct adis16400_state - device instance specific data | |
152 | - * @variant: chip variant info | |
153 | - * @filt_int: integer part of requested filter frequency | |
154 | - * @adis: adis device | |
155 | - **/ | |
156 | -struct adis16400_state { | |
157 | - struct adis16400_chip_info *variant; | |
158 | - int filt_int; | |
159 | - | |
160 | - struct adis adis; | |
161 | -}; | |
162 | - | |
163 | -/* At the moment triggers are only used for ring buffer | |
164 | - * filling. This may change! | |
165 | - */ | |
166 | - | |
167 | -enum { | |
168 | - ADIS16400_SCAN_SUPPLY, | |
169 | - ADIS16400_SCAN_GYRO_X, | |
170 | - ADIS16400_SCAN_GYRO_Y, | |
171 | - ADIS16400_SCAN_GYRO_Z, | |
172 | - ADIS16400_SCAN_ACC_X, | |
173 | - ADIS16400_SCAN_ACC_Y, | |
174 | - ADIS16400_SCAN_ACC_Z, | |
175 | - ADIS16400_SCAN_MAGN_X, | |
176 | - ADIS16400_SCAN_MAGN_Y, | |
177 | - ADIS16400_SCAN_MAGN_Z, | |
178 | - ADIS16350_SCAN_TEMP_X, | |
179 | - ADIS16350_SCAN_TEMP_Y, | |
180 | - ADIS16350_SCAN_TEMP_Z, | |
181 | - ADIS16300_SCAN_INCLI_X, | |
182 | - ADIS16300_SCAN_INCLI_Y, | |
183 | - ADIS16400_SCAN_ADC, | |
184 | -}; | |
185 | - | |
186 | -#ifdef CONFIG_IIO_BUFFER | |
187 | - | |
188 | -ssize_t adis16400_read_data_from_ring(struct device *dev, | |
189 | - struct device_attribute *attr, | |
190 | - char *buf); | |
191 | - | |
192 | - | |
193 | -int adis16400_update_scan_mode(struct iio_dev *indio_dev, | |
194 | - const unsigned long *scan_mask); | |
195 | -irqreturn_t adis16400_trigger_handler(int irq, void *p); | |
196 | - | |
197 | -#else /* CONFIG_IIO_BUFFER */ | |
198 | - | |
199 | -#define adis16400_update_scan_mode NULL | |
200 | -#define adis16400_trigger_handler NULL | |
201 | - | |
202 | -#endif /* CONFIG_IIO_BUFFER */ | |
203 | - | |
204 | -#endif /* SPI_ADIS16400_H_ */ |
drivers/staging/iio/imu/adis16400_core.c
1 | -/* | |
2 | - * adis16400.c support Analog Devices ADIS16400/5 | |
3 | - * 3d 2g Linear Accelerometers, | |
4 | - * 3d Gyroscopes, | |
5 | - * 3d Magnetometers via SPI | |
6 | - * | |
7 | - * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | |
8 | - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> | |
9 | - * Copyright (c) 2011 Analog Devices Inc. | |
10 | - * | |
11 | - * This program is free software; you can redistribute it and/or modify | |
12 | - * it under the terms of the GNU General Public License version 2 as | |
13 | - * published by the Free Software Foundation. | |
14 | - * | |
15 | - */ | |
16 | - | |
17 | -#include <linux/interrupt.h> | |
18 | -#include <linux/irq.h> | |
19 | -#include <linux/delay.h> | |
20 | -#include <linux/mutex.h> | |
21 | -#include <linux/device.h> | |
22 | -#include <linux/kernel.h> | |
23 | -#include <linux/spi/spi.h> | |
24 | -#include <linux/slab.h> | |
25 | -#include <linux/sysfs.h> | |
26 | -#include <linux/list.h> | |
27 | -#include <linux/module.h> | |
28 | - | |
29 | -#include <linux/iio/iio.h> | |
30 | -#include <linux/iio/sysfs.h> | |
31 | -#include <linux/iio/buffer.h> | |
32 | - | |
33 | -#include "adis16400.h" | |
34 | - | |
35 | -enum adis16400_chip_variant { | |
36 | - ADIS16300, | |
37 | - ADIS16334, | |
38 | - ADIS16350, | |
39 | - ADIS16360, | |
40 | - ADIS16362, | |
41 | - ADIS16364, | |
42 | - ADIS16400, | |
43 | -}; | |
44 | - | |
45 | -static int adis16334_get_freq(struct adis16400_state *st) | |
46 | -{ | |
47 | - int ret; | |
48 | - uint16_t t; | |
49 | - | |
50 | - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); | |
51 | - if (ret < 0) | |
52 | - return ret; | |
53 | - | |
54 | - t >>= ADIS16334_RATE_DIV_SHIFT; | |
55 | - | |
56 | - return (8192 >> t) / 10; | |
57 | -} | |
58 | - | |
59 | -static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq) | |
60 | -{ | |
61 | - unsigned int t; | |
62 | - | |
63 | - freq *= 10; | |
64 | - if (freq < 8192) | |
65 | - t = ilog2(8192 / freq); | |
66 | - else | |
67 | - t = 0; | |
68 | - | |
69 | - if (t > 0x31) | |
70 | - t = 0x31; | |
71 | - | |
72 | - t <<= ADIS16334_RATE_DIV_SHIFT; | |
73 | - t |= ADIS16334_RATE_INT_CLK; | |
74 | - | |
75 | - return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t); | |
76 | -} | |
77 | - | |
78 | -static int adis16400_get_freq(struct adis16400_state *st) | |
79 | -{ | |
80 | - int sps, ret; | |
81 | - uint16_t t; | |
82 | - | |
83 | - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t); | |
84 | - if (ret < 0) | |
85 | - return ret; | |
86 | - | |
87 | - sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; | |
88 | - sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; | |
89 | - | |
90 | - return sps; | |
91 | -} | |
92 | - | |
93 | -static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq) | |
94 | -{ | |
95 | - unsigned int t; | |
96 | - | |
97 | - t = 1638 / freq; | |
98 | - if (t > 0) | |
99 | - t--; | |
100 | - t &= ADIS16400_SMPL_PRD_DIV_MASK; | |
101 | - | |
102 | - if ((t & ADIS16400_SMPL_PRD_DIV_MASK) >= 0x0A) | |
103 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; | |
104 | - else | |
105 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
106 | - | |
107 | - return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, t); | |
108 | -} | |
109 | - | |
110 | -static ssize_t adis16400_read_frequency(struct device *dev, | |
111 | - struct device_attribute *attr, | |
112 | - char *buf) | |
113 | -{ | |
114 | - struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
115 | - struct adis16400_state *st = iio_priv(indio_dev); | |
116 | - int ret; | |
117 | - | |
118 | - ret = st->variant->get_freq(st); | |
119 | - if (ret < 0) | |
120 | - return ret; | |
121 | - | |
122 | - return sprintf(buf, "%d\n", ret); | |
123 | -} | |
124 | - | |
125 | -static const unsigned adis16400_3db_divisors[] = { | |
126 | - [0] = 2, /* Special case */ | |
127 | - [1] = 6, | |
128 | - [2] = 12, | |
129 | - [3] = 25, | |
130 | - [4] = 50, | |
131 | - [5] = 100, | |
132 | - [6] = 200, | |
133 | - [7] = 200, /* Not a valid setting */ | |
134 | -}; | |
135 | - | |
136 | -static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val) | |
137 | -{ | |
138 | - struct adis16400_state *st = iio_priv(indio_dev); | |
139 | - uint16_t val16; | |
140 | - int i, ret; | |
141 | - | |
142 | - for (i = ARRAY_SIZE(adis16400_3db_divisors) - 1; i >= 1; i--) { | |
143 | - if (sps / adis16400_3db_divisors[i] >= val) | |
144 | - break; | |
145 | - } | |
146 | - | |
147 | - ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16); | |
148 | - if (ret < 0) | |
149 | - return ret; | |
150 | - | |
151 | - ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG, | |
152 | - (val16 & ~0x07) | i); | |
153 | - return ret; | |
154 | -} | |
155 | - | |
156 | -static ssize_t adis16400_write_frequency(struct device *dev, | |
157 | - struct device_attribute *attr, const char *buf, size_t len) | |
158 | -{ | |
159 | - struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
160 | - struct adis16400_state *st = iio_priv(indio_dev); | |
161 | - long val; | |
162 | - int ret; | |
163 | - | |
164 | - ret = kstrtol(buf, 10, &val); | |
165 | - if (ret) | |
166 | - return ret; | |
167 | - | |
168 | - if (val == 0) | |
169 | - return -EINVAL; | |
170 | - | |
171 | - mutex_lock(&indio_dev->mlock); | |
172 | - st->variant->set_freq(st, val); | |
173 | - mutex_unlock(&indio_dev->mlock); | |
174 | - | |
175 | - return ret ? ret : len; | |
176 | -} | |
177 | - | |
178 | -/* Power down the device */ | |
179 | -static int adis16400_stop_device(struct iio_dev *indio_dev) | |
180 | -{ | |
181 | - struct adis16400_state *st = iio_priv(indio_dev); | |
182 | - int ret; | |
183 | - | |
184 | - ret = adis_write_reg_16(&st->adis, ADIS16400_SLP_CNT, | |
185 | - ADIS16400_SLP_CNT_POWER_OFF); | |
186 | - if (ret) | |
187 | - dev_err(&indio_dev->dev, | |
188 | - "problem with turning device off: SLP_CNT"); | |
189 | - | |
190 | - return ret; | |
191 | -} | |
192 | - | |
193 | -static int adis16400_initial_setup(struct iio_dev *indio_dev) | |
194 | -{ | |
195 | - struct adis16400_state *st = iio_priv(indio_dev); | |
196 | - uint16_t prod_id, smp_prd; | |
197 | - unsigned int device_id; | |
198 | - int ret; | |
199 | - | |
200 | - /* use low spi speed for init if the device has a slow mode */ | |
201 | - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) | |
202 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_SLOW; | |
203 | - else | |
204 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
205 | - st->adis.spi->mode = SPI_MODE_3; | |
206 | - spi_setup(st->adis.spi); | |
207 | - | |
208 | - ret = adis_initial_startup(&st->adis); | |
209 | - if (ret) | |
210 | - return ret; | |
211 | - | |
212 | - if (st->variant->flags & ADIS16400_HAS_PROD_ID) { | |
213 | - ret = adis_read_reg_16(&st->adis, | |
214 | - ADIS16400_PRODUCT_ID, &prod_id); | |
215 | - if (ret) | |
216 | - goto err_ret; | |
217 | - | |
218 | - sscanf(indio_dev->name, "adis%u\n", &device_id); | |
219 | - | |
220 | - if (prod_id != device_id) | |
221 | - dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", | |
222 | - device_id, prod_id); | |
223 | - | |
224 | - dev_info(&indio_dev->dev, "%s: prod_id 0x%04x at CS%d (irq %d)\n", | |
225 | - indio_dev->name, prod_id, | |
226 | - st->adis.spi->chip_select, st->adis.spi->irq); | |
227 | - } | |
228 | - /* use high spi speed if possible */ | |
229 | - if (st->variant->flags & ADIS16400_HAS_SLOW_MODE) { | |
230 | - ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &smp_prd); | |
231 | - if (ret) | |
232 | - goto err_ret; | |
233 | - | |
234 | - if ((smp_prd & ADIS16400_SMPL_PRD_DIV_MASK) < 0x0A) { | |
235 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST; | |
236 | - spi_setup(st->adis.spi); | |
237 | - } | |
238 | - } | |
239 | - | |
240 | -err_ret: | |
241 | - return ret; | |
242 | -} | |
243 | - | |
244 | -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | |
245 | - adis16400_read_frequency, | |
246 | - adis16400_write_frequency); | |
247 | - | |
248 | -static const uint8_t adis16400_addresses[] = { | |
249 | - [ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF, | |
250 | - [ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF, | |
251 | - [ADIS16400_SCAN_GYRO_Z] = ADIS16400_ZGYRO_OFF, | |
252 | - [ADIS16400_SCAN_ACC_X] = ADIS16400_XACCL_OFF, | |
253 | - [ADIS16400_SCAN_ACC_Y] = ADIS16400_YACCL_OFF, | |
254 | - [ADIS16400_SCAN_ACC_Z] = ADIS16400_ZACCL_OFF, | |
255 | -}; | |
256 | - | |
257 | -static int adis16400_write_raw(struct iio_dev *indio_dev, | |
258 | - struct iio_chan_spec const *chan, int val, int val2, long info) | |
259 | -{ | |
260 | - struct adis16400_state *st = iio_priv(indio_dev); | |
261 | - int ret, sps; | |
262 | - | |
263 | - switch (info) { | |
264 | - case IIO_CHAN_INFO_CALIBBIAS: | |
265 | - mutex_lock(&indio_dev->mlock); | |
266 | - ret = adis_write_reg_16(&st->adis, | |
267 | - adis16400_addresses[chan->scan_index], val); | |
268 | - mutex_unlock(&indio_dev->mlock); | |
269 | - return ret; | |
270 | - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
271 | - /* | |
272 | - * Need to cache values so we can update if the frequency | |
273 | - * changes. | |
274 | - */ | |
275 | - mutex_lock(&indio_dev->mlock); | |
276 | - st->filt_int = val; | |
277 | - /* Work out update to current value */ | |
278 | - sps = st->variant->get_freq(st); | |
279 | - if (sps < 0) { | |
280 | - mutex_unlock(&indio_dev->mlock); | |
281 | - return sps; | |
282 | - } | |
283 | - | |
284 | - ret = adis16400_set_filter(indio_dev, sps, val); | |
285 | - mutex_unlock(&indio_dev->mlock); | |
286 | - return ret; | |
287 | - default: | |
288 | - return -EINVAL; | |
289 | - } | |
290 | -} | |
291 | - | |
292 | -static int adis16400_read_raw(struct iio_dev *indio_dev, | |
293 | - struct iio_chan_spec const *chan, int *val, int *val2, long info) | |
294 | -{ | |
295 | - struct adis16400_state *st = iio_priv(indio_dev); | |
296 | - int16_t val16; | |
297 | - int ret; | |
298 | - | |
299 | - switch (info) { | |
300 | - case IIO_CHAN_INFO_RAW: | |
301 | - return adis_single_conversion(indio_dev, chan, 0, val); | |
302 | - case IIO_CHAN_INFO_SCALE: | |
303 | - switch (chan->type) { | |
304 | - case IIO_ANGL_VEL: | |
305 | - *val = 0; | |
306 | - *val2 = st->variant->gyro_scale_micro; | |
307 | - return IIO_VAL_INT_PLUS_MICRO; | |
308 | - case IIO_VOLTAGE: | |
309 | - *val = 0; | |
310 | - if (chan->channel == 0) { | |
311 | - *val = 2; | |
312 | - *val2 = 418000; /* 2.418 mV */ | |
313 | - } else { | |
314 | - *val = 0; | |
315 | - *val2 = 805800; /* 805.8 uV */ | |
316 | - } | |
317 | - return IIO_VAL_INT_PLUS_MICRO; | |
318 | - case IIO_ACCEL: | |
319 | - *val = 0; | |
320 | - *val2 = st->variant->accel_scale_micro; | |
321 | - return IIO_VAL_INT_PLUS_MICRO; | |
322 | - case IIO_MAGN: | |
323 | - *val = 0; | |
324 | - *val2 = 500; /* 0.5 mgauss */ | |
325 | - return IIO_VAL_INT_PLUS_MICRO; | |
326 | - case IIO_TEMP: | |
327 | - *val = st->variant->temp_scale_nano / 1000000; | |
328 | - *val2 = (st->variant->temp_scale_nano % 1000000); | |
329 | - return IIO_VAL_INT_PLUS_MICRO; | |
330 | - default: | |
331 | - return -EINVAL; | |
332 | - } | |
333 | - case IIO_CHAN_INFO_CALIBBIAS: | |
334 | - mutex_lock(&indio_dev->mlock); | |
335 | - ret = adis_read_reg_16(&st->adis, | |
336 | - adis16400_addresses[chan->scan_index], &val16); | |
337 | - mutex_unlock(&indio_dev->mlock); | |
338 | - if (ret) | |
339 | - return ret; | |
340 | - val16 = ((val16 & 0xFFF) << 4) >> 4; | |
341 | - *val = val16; | |
342 | - return IIO_VAL_INT; | |
343 | - case IIO_CHAN_INFO_OFFSET: | |
344 | - /* currently only temperature */ | |
345 | - *val = st->variant->temp_offset; | |
346 | - return IIO_VAL_INT; | |
347 | - case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
348 | - mutex_lock(&indio_dev->mlock); | |
349 | - /* Need both the number of taps and the sampling frequency */ | |
350 | - ret = adis_read_reg_16(&st->adis, | |
351 | - ADIS16400_SENS_AVG, | |
352 | - &val16); | |
353 | - if (ret < 0) { | |
354 | - mutex_unlock(&indio_dev->mlock); | |
355 | - return ret; | |
356 | - } | |
357 | - ret = st->variant->get_freq(st); | |
358 | - if (ret >= 0) | |
359 | - *val = ret / adis16400_3db_divisors[val16 & 0x07]; | |
360 | - *val2 = 0; | |
361 | - mutex_unlock(&indio_dev->mlock); | |
362 | - if (ret < 0) | |
363 | - return ret; | |
364 | - return IIO_VAL_INT_PLUS_MICRO; | |
365 | - default: | |
366 | - return -EINVAL; | |
367 | - } | |
368 | -} | |
369 | - | |
370 | -#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si) { \ | |
371 | - .type = IIO_VOLTAGE, \ | |
372 | - .indexed = 1, \ | |
373 | - .channel = 0, \ | |
374 | - .extend_name = name, \ | |
375 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
376 | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | |
377 | - .address = (addr), \ | |
378 | - .scan_index = (si), \ | |
379 | - .scan_type = { \ | |
380 | - .sign = 'u', \ | |
381 | - .realbits = (bits), \ | |
382 | - .storagebits = 16, \ | |
383 | - .shift = 0, \ | |
384 | - .endianness = IIO_BE, \ | |
385 | - }, \ | |
386 | -} | |
387 | - | |
388 | -#define ADIS16400_SUPPLY_CHAN(addr, bits) \ | |
389 | - ADIS16400_VOLTAGE_CHAN(addr, bits, "supply", ADIS16400_SCAN_SUPPLY) | |
390 | - | |
391 | -#define ADIS16400_AUX_ADC_CHAN(addr, bits) \ | |
392 | - ADIS16400_VOLTAGE_CHAN(addr, bits, NULL, ADIS16400_SCAN_ADC) | |
393 | - | |
394 | -#define ADIS16400_GYRO_CHAN(mod, addr, bits) { \ | |
395 | - .type = IIO_ANGL_VEL, \ | |
396 | - .modified = 1, \ | |
397 | - .channel2 = IIO_MOD_ ## mod, \ | |
398 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
399 | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ | |
400 | - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
401 | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
402 | - .address = addr, \ | |
403 | - .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ | |
404 | - .scan_type = { \ | |
405 | - .sign = 's', \ | |
406 | - .realbits = (bits), \ | |
407 | - .storagebits = 16, \ | |
408 | - .shift = 0, \ | |
409 | - .endianness = IIO_BE, \ | |
410 | - }, \ | |
411 | -} | |
412 | - | |
413 | -#define ADIS16400_ACCEL_CHAN(mod, addr, bits) { \ | |
414 | - .type = IIO_ACCEL, \ | |
415 | - .modified = 1, \ | |
416 | - .channel2 = IIO_MOD_ ## mod, \ | |
417 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
418 | - IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ | |
419 | - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
420 | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
421 | - .address = (addr), \ | |
422 | - .scan_index = ADIS16400_SCAN_ACC_ ## mod, \ | |
423 | - .scan_type = { \ | |
424 | - .sign = 's', \ | |
425 | - .realbits = (bits), \ | |
426 | - .storagebits = 16, \ | |
427 | - .shift = 0, \ | |
428 | - .endianness = IIO_BE, \ | |
429 | - }, \ | |
430 | -} | |
431 | - | |
432 | -#define ADIS16400_MAGN_CHAN(mod, addr, bits) { \ | |
433 | - .type = IIO_MAGN, \ | |
434 | - .modified = 1, \ | |
435 | - .channel2 = IIO_MOD_ ## mod, \ | |
436 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
437 | - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | |
438 | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
439 | - .address = (addr), \ | |
440 | - .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ | |
441 | - .scan_type = { \ | |
442 | - .sign = 's', \ | |
443 | - .realbits = (bits), \ | |
444 | - .storagebits = 16, \ | |
445 | - .shift = 0, \ | |
446 | - .endianness = IIO_BE, \ | |
447 | - }, \ | |
448 | -} | |
449 | - | |
450 | -#define ADIS16400_MOD_TEMP_NAME_X "x" | |
451 | -#define ADIS16400_MOD_TEMP_NAME_Y "y" | |
452 | -#define ADIS16400_MOD_TEMP_NAME_Z "z" | |
453 | - | |
454 | -#define ADIS16400_MOD_TEMP_CHAN(mod, addr, bits) { \ | |
455 | - .type = IIO_TEMP, \ | |
456 | - .indexed = 1, \ | |
457 | - .channel = 0, \ | |
458 | - .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ | |
459 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
460 | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ | |
461 | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ | |
462 | - IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ | |
463 | - .address = (addr), \ | |
464 | - .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ | |
465 | - .scan_type = { \ | |
466 | - .sign = 's', \ | |
467 | - .realbits = (bits), \ | |
468 | - .storagebits = 16, \ | |
469 | - .shift = 0, \ | |
470 | - .endianness = IIO_BE, \ | |
471 | - }, \ | |
472 | -} | |
473 | - | |
474 | -#define ADIS16400_TEMP_CHAN(addr, bits) { \ | |
475 | - .type = IIO_TEMP, \ | |
476 | - .indexed = 1, \ | |
477 | - .channel = 0, \ | |
478 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
479 | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ | |
480 | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ | |
481 | - .address = (addr), \ | |
482 | - .scan_index = ADIS16350_SCAN_TEMP_X, \ | |
483 | - .scan_type = { \ | |
484 | - .sign = 's', \ | |
485 | - .realbits = (bits), \ | |
486 | - .storagebits = 16, \ | |
487 | - .shift = 0, \ | |
488 | - .endianness = IIO_BE, \ | |
489 | - }, \ | |
490 | -} | |
491 | - | |
492 | -#define ADIS16400_INCLI_CHAN(mod, addr, bits) { \ | |
493 | - .type = IIO_INCLI, \ | |
494 | - .modified = 1, \ | |
495 | - .channel2 = IIO_MOD_ ## mod, \ | |
496 | - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | |
497 | - IIO_CHAN_INFO_SCALE_SHARED_BIT, \ | |
498 | - .address = (addr), \ | |
499 | - .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ | |
500 | - .scan_type = { \ | |
501 | - .sign = 's', \ | |
502 | - .realbits = (bits), \ | |
503 | - .storagebits = 16, \ | |
504 | - .shift = 0, \ | |
505 | - .endianness = IIO_BE, \ | |
506 | - }, \ | |
507 | -} | |
508 | - | |
509 | -static const struct iio_chan_spec adis16400_channels[] = { | |
510 | - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 14), | |
511 | - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
512 | - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
513 | - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
514 | - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
515 | - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
516 | - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
517 | - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), | |
518 | - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), | |
519 | - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), | |
520 | - ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), | |
521 | - ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), | |
522 | - IIO_CHAN_SOFT_TIMESTAMP(12) | |
523 | -}; | |
524 | - | |
525 | -static const struct iio_chan_spec adis16350_channels[] = { | |
526 | - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), | |
527 | - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
528 | - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
529 | - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
530 | - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
531 | - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
532 | - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
533 | - ADIS16400_MAGN_CHAN(X, ADIS16400_XMAGN_OUT, 14), | |
534 | - ADIS16400_MAGN_CHAN(Y, ADIS16400_YMAGN_OUT, 14), | |
535 | - ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), | |
536 | - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), | |
537 | - ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), | |
538 | - ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), | |
539 | - ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), | |
540 | - IIO_CHAN_SOFT_TIMESTAMP(11) | |
541 | -}; | |
542 | - | |
543 | -static const struct iio_chan_spec adis16300_channels[] = { | |
544 | - ADIS16400_SUPPLY_CHAN(ADIS16400_SUPPLY_OUT, 12), | |
545 | - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
546 | - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
547 | - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
548 | - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
549 | - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), | |
550 | - ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), | |
551 | - ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), | |
552 | - ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), | |
553 | - IIO_CHAN_SOFT_TIMESTAMP(14) | |
554 | -}; | |
555 | - | |
556 | -static const struct iio_chan_spec adis16334_channels[] = { | |
557 | - ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 14), | |
558 | - ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 14), | |
559 | - ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 14), | |
560 | - ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 14), | |
561 | - ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), | |
562 | - ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), | |
563 | - ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), | |
564 | - IIO_CHAN_SOFT_TIMESTAMP(8) | |
565 | -}; | |
566 | - | |
567 | -static struct attribute *adis16400_attributes[] = { | |
568 | - &iio_dev_attr_sampling_frequency.dev_attr.attr, | |
569 | - NULL | |
570 | -}; | |
571 | - | |
572 | -static const struct attribute_group adis16400_attribute_group = { | |
573 | - .attrs = adis16400_attributes, | |
574 | -}; | |
575 | - | |
576 | -static struct adis16400_chip_info adis16400_chips[] = { | |
577 | - [ADIS16300] = { | |
578 | - .channels = adis16300_channels, | |
579 | - .num_channels = ARRAY_SIZE(adis16300_channels), | |
580 | - .flags = ADIS16400_HAS_SLOW_MODE, | |
581 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
582 | - .accel_scale_micro = 5884, | |
583 | - .temp_scale_nano = 140000000, /* 0.14 C */ | |
584 | - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ | |
585 | - .set_freq = adis16400_set_freq, | |
586 | - .get_freq = adis16400_get_freq, | |
587 | - }, | |
588 | - [ADIS16334] = { | |
589 | - .channels = adis16334_channels, | |
590 | - .num_channels = ARRAY_SIZE(adis16334_channels), | |
591 | - .flags = ADIS16400_HAS_PROD_ID, | |
592 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
593 | - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ | |
594 | - .temp_scale_nano = 67850000, /* 0.06785 C */ | |
595 | - .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */ | |
596 | - .set_freq = adis16334_set_freq, | |
597 | - .get_freq = adis16334_get_freq, | |
598 | - }, | |
599 | - [ADIS16350] = { | |
600 | - .channels = adis16350_channels, | |
601 | - .num_channels = ARRAY_SIZE(adis16350_channels), | |
602 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */ | |
603 | - .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */ | |
604 | - .temp_scale_nano = 145300000, /* 0.1453 C */ | |
605 | - .temp_offset = 25000000 / 145300, /* 25 C = 0x00 */ | |
606 | - .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE, | |
607 | - .set_freq = adis16400_set_freq, | |
608 | - .get_freq = adis16400_get_freq, | |
609 | - }, | |
610 | - [ADIS16360] = { | |
611 | - .channels = adis16350_channels, | |
612 | - .num_channels = ARRAY_SIZE(adis16350_channels), | |
613 | - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
614 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
615 | - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ | |
616 | - .temp_scale_nano = 136000000, /* 0.136 C */ | |
617 | - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
618 | - .set_freq = adis16400_set_freq, | |
619 | - .get_freq = adis16400_get_freq, | |
620 | - }, | |
621 | - [ADIS16362] = { | |
622 | - .channels = adis16350_channels, | |
623 | - .num_channels = ARRAY_SIZE(adis16350_channels), | |
624 | - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
625 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
626 | - .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */ | |
627 | - .temp_scale_nano = 136000000, /* 0.136 C */ | |
628 | - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
629 | - .set_freq = adis16400_set_freq, | |
630 | - .get_freq = adis16400_get_freq, | |
631 | - }, | |
632 | - [ADIS16364] = { | |
633 | - .channels = adis16350_channels, | |
634 | - .num_channels = ARRAY_SIZE(adis16350_channels), | |
635 | - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
636 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
637 | - .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */ | |
638 | - .temp_scale_nano = 136000000, /* 0.136 C */ | |
639 | - .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ | |
640 | - .set_freq = adis16400_set_freq, | |
641 | - .get_freq = adis16400_get_freq, | |
642 | - }, | |
643 | - [ADIS16400] = { | |
644 | - .channels = adis16400_channels, | |
645 | - .num_channels = ARRAY_SIZE(adis16400_channels), | |
646 | - .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE, | |
647 | - .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ | |
648 | - .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ | |
649 | - .temp_scale_nano = 140000000, /* 0.14 C */ | |
650 | - .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */ | |
651 | - .set_freq = adis16400_set_freq, | |
652 | - .get_freq = adis16400_get_freq, | |
653 | - } | |
654 | -}; | |
655 | - | |
656 | -static const struct iio_info adis16400_info = { | |
657 | - .driver_module = THIS_MODULE, | |
658 | - .read_raw = &adis16400_read_raw, | |
659 | - .write_raw = &adis16400_write_raw, | |
660 | - .attrs = &adis16400_attribute_group, | |
661 | - .update_scan_mode = adis16400_update_scan_mode, | |
662 | -}; | |
663 | - | |
664 | -static const unsigned long adis16400_burst_scan_mask[] = { | |
665 | - ~0UL, | |
666 | - 0, | |
667 | -}; | |
668 | - | |
669 | -static const char * const adis16400_status_error_msgs[] = { | |
670 | - [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", | |
671 | - [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", | |
672 | - [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", | |
673 | - [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", | |
674 | - [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", | |
675 | - [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", | |
676 | - [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active", | |
677 | - [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active", | |
678 | - [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error", | |
679 | - [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error", | |
680 | - [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange", | |
681 | - [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure", | |
682 | - [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed", | |
683 | - [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V", | |
684 | - [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V", | |
685 | -}; | |
686 | - | |
687 | -static const struct adis_data adis16400_data = { | |
688 | - .msc_ctrl_reg = ADIS16400_MSC_CTRL, | |
689 | - .glob_cmd_reg = ADIS16400_GLOB_CMD, | |
690 | - .diag_stat_reg = ADIS16400_DIAG_STAT, | |
691 | - | |
692 | - .read_delay = 50, | |
693 | - .write_delay = 50, | |
694 | - | |
695 | - .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST, | |
696 | - .startup_delay = ADIS16400_STARTUP_DELAY, | |
697 | - | |
698 | - .status_error_msgs = adis16400_status_error_msgs, | |
699 | - .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) | | |
700 | - BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) | | |
701 | - BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) | | |
702 | - BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) | | |
703 | - BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) | | |
704 | - BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) | | |
705 | - BIT(ADIS16400_DIAG_STAT_ALARM2) | | |
706 | - BIT(ADIS16400_DIAG_STAT_ALARM1) | | |
707 | - BIT(ADIS16400_DIAG_STAT_FLASH_CHK) | | |
708 | - BIT(ADIS16400_DIAG_STAT_SELF_TEST) | | |
709 | - BIT(ADIS16400_DIAG_STAT_OVERFLOW) | | |
710 | - BIT(ADIS16400_DIAG_STAT_SPI_FAIL) | | |
711 | - BIT(ADIS16400_DIAG_STAT_FLASH_UPT) | | |
712 | - BIT(ADIS16400_DIAG_STAT_POWER_HIGH) | | |
713 | - BIT(ADIS16400_DIAG_STAT_POWER_LOW), | |
714 | -}; | |
715 | - | |
716 | -static int adis16400_probe(struct spi_device *spi) | |
717 | -{ | |
718 | - struct adis16400_state *st; | |
719 | - struct iio_dev *indio_dev; | |
720 | - int ret; | |
721 | - | |
722 | - indio_dev = iio_device_alloc(sizeof(*st)); | |
723 | - if (indio_dev == NULL) | |
724 | - return -ENOMEM; | |
725 | - | |
726 | - st = iio_priv(indio_dev); | |
727 | - /* this is only used for removal purposes */ | |
728 | - spi_set_drvdata(spi, indio_dev); | |
729 | - | |
730 | - /* setup the industrialio driver allocated elements */ | |
731 | - st->variant = &adis16400_chips[spi_get_device_id(spi)->driver_data]; | |
732 | - indio_dev->dev.parent = &spi->dev; | |
733 | - indio_dev->name = spi_get_device_id(spi)->name; | |
734 | - indio_dev->channels = st->variant->channels; | |
735 | - indio_dev->num_channels = st->variant->num_channels; | |
736 | - indio_dev->info = &adis16400_info; | |
737 | - indio_dev->modes = INDIO_DIRECT_MODE; | |
738 | - | |
739 | - if (!(st->variant->flags & ADIS16400_NO_BURST)) | |
740 | - indio_dev->available_scan_masks = adis16400_burst_scan_mask; | |
741 | - | |
742 | - ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); | |
743 | - if (ret) | |
744 | - goto error_free_dev; | |
745 | - | |
746 | - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, | |
747 | - adis16400_trigger_handler); | |
748 | - if (ret) | |
749 | - goto error_free_dev; | |
750 | - | |
751 | - /* Get the device into a sane initial state */ | |
752 | - ret = adis16400_initial_setup(indio_dev); | |
753 | - if (ret) | |
754 | - goto error_cleanup_buffer; | |
755 | - ret = iio_device_register(indio_dev); | |
756 | - if (ret) | |
757 | - goto error_cleanup_buffer; | |
758 | - | |
759 | - return 0; | |
760 | - | |
761 | -error_cleanup_buffer: | |
762 | - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | |
763 | -error_free_dev: | |
764 | - iio_device_free(indio_dev); | |
765 | - return ret; | |
766 | -} | |
767 | - | |
768 | -static int adis16400_remove(struct spi_device *spi) | |
769 | -{ | |
770 | - struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
771 | - struct adis16400_state *st = iio_priv(indio_dev); | |
772 | - | |
773 | - iio_device_unregister(indio_dev); | |
774 | - adis16400_stop_device(indio_dev); | |
775 | - | |
776 | - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); | |
777 | - | |
778 | - iio_device_free(indio_dev); | |
779 | - | |
780 | - return 0; | |
781 | -} | |
782 | - | |
783 | -static const struct spi_device_id adis16400_id[] = { | |
784 | - {"adis16300", ADIS16300}, | |
785 | - {"adis16334", ADIS16334}, | |
786 | - {"adis16350", ADIS16350}, | |
787 | - {"adis16354", ADIS16350}, | |
788 | - {"adis16355", ADIS16350}, | |
789 | - {"adis16360", ADIS16360}, | |
790 | - {"adis16362", ADIS16362}, | |
791 | - {"adis16364", ADIS16364}, | |
792 | - {"adis16365", ADIS16360}, | |
793 | - {"adis16400", ADIS16400}, | |
794 | - {"adis16405", ADIS16400}, | |
795 | - {} | |
796 | -}; | |
797 | -MODULE_DEVICE_TABLE(spi, adis16400_id); | |
798 | - | |
799 | -static struct spi_driver adis16400_driver = { | |
800 | - .driver = { | |
801 | - .name = "adis16400", | |
802 | - .owner = THIS_MODULE, | |
803 | - }, | |
804 | - .id_table = adis16400_id, | |
805 | - .probe = adis16400_probe, | |
806 | - .remove = adis16400_remove, | |
807 | -}; | |
808 | -module_spi_driver(adis16400_driver); | |
809 | - | |
810 | -MODULE_AUTHOR("Manuel Stahl <manuel.stahl@iis.fraunhofer.de>"); | |
811 | -MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); | |
812 | -MODULE_LICENSE("GPL v2"); |
drivers/staging/iio/imu/adis16400_ring.c
1 | -#include <linux/interrupt.h> | |
2 | -#include <linux/mutex.h> | |
3 | -#include <linux/kernel.h> | |
4 | -#include <linux/spi/spi.h> | |
5 | -#include <linux/slab.h> | |
6 | -#include <linux/bitops.h> | |
7 | -#include <linux/export.h> | |
8 | - | |
9 | -#include <linux/iio/iio.h> | |
10 | -#include <linux/iio/buffer.h> | |
11 | -#include <linux/iio/triggered_buffer.h> | |
12 | -#include <linux/iio/trigger_consumer.h> | |
13 | - | |
14 | -#include "adis16400.h" | |
15 | - | |
16 | -int adis16400_update_scan_mode(struct iio_dev *indio_dev, | |
17 | - const unsigned long *scan_mask) | |
18 | -{ | |
19 | - struct adis16400_state *st = iio_priv(indio_dev); | |
20 | - struct adis *adis = &st->adis; | |
21 | - uint16_t *tx, *rx; | |
22 | - | |
23 | - if (st->variant->flags & ADIS16400_NO_BURST) | |
24 | - return adis_update_scan_mode(indio_dev, scan_mask); | |
25 | - | |
26 | - kfree(adis->xfer); | |
27 | - kfree(adis->buffer); | |
28 | - | |
29 | - adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL); | |
30 | - if (!adis->xfer) | |
31 | - return -ENOMEM; | |
32 | - | |
33 | - adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16), | |
34 | - GFP_KERNEL); | |
35 | - if (!adis->buffer) | |
36 | - return -ENOMEM; | |
37 | - | |
38 | - rx = adis->buffer; | |
39 | - tx = adis->buffer + indio_dev->scan_bytes; | |
40 | - | |
41 | - tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD); | |
42 | - tx[1] = 0; | |
43 | - | |
44 | - adis->xfer[0].tx_buf = tx; | |
45 | - adis->xfer[0].bits_per_word = 8; | |
46 | - adis->xfer[0].len = 2; | |
47 | - adis->xfer[1].tx_buf = tx; | |
48 | - adis->xfer[1].bits_per_word = 8; | |
49 | - adis->xfer[1].len = indio_dev->scan_bytes; | |
50 | - | |
51 | - spi_message_init(&adis->msg); | |
52 | - spi_message_add_tail(&adis->xfer[0], &adis->msg); | |
53 | - spi_message_add_tail(&adis->xfer[1], &adis->msg); | |
54 | - | |
55 | - return 0; | |
56 | -} | |
57 | - | |
58 | -irqreturn_t adis16400_trigger_handler(int irq, void *p) | |
59 | -{ | |
60 | - struct iio_poll_func *pf = p; | |
61 | - struct iio_dev *indio_dev = pf->indio_dev; | |
62 | - struct adis16400_state *st = iio_priv(indio_dev); | |
63 | - struct adis *adis = &st->adis; | |
64 | - u32 old_speed_hz = st->adis.spi->max_speed_hz; | |
65 | - int ret; | |
66 | - | |
67 | - if (!adis->buffer) | |
68 | - return -ENOMEM; | |
69 | - | |
70 | - if (!(st->variant->flags & ADIS16400_NO_BURST) && | |
71 | - st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) { | |
72 | - st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST; | |
73 | - spi_setup(st->adis.spi); | |
74 | - } | |
75 | - | |
76 | - ret = spi_sync(adis->spi, &adis->msg); | |
77 | - if (ret) | |
78 | - dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); | |
79 | - | |
80 | - if (!(st->variant->flags & ADIS16400_NO_BURST)) { | |
81 | - st->adis.spi->max_speed_hz = old_speed_hz; | |
82 | - spi_setup(st->adis.spi); | |
83 | - } | |
84 | - | |
85 | - /* Guaranteed to be aligned with 8 byte boundary */ | |
86 | - if (indio_dev->scan_timestamp) { | |
87 | - void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); | |
88 | - *(s64 *)b = pf->timestamp; | |
89 | - } | |
90 | - | |
91 | - iio_push_to_buffers(indio_dev, adis->buffer); | |
92 | - | |
93 | - iio_trigger_notify_done(indio_dev->trig); | |
94 | - | |
95 | - return IRQ_HANDLED; | |
96 | -} |