diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-01-16 07:48:00 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2013-01-26 05:07:50 -0500 |
commit | d6b09bd85d57752395c6407bd8a9b32eb7b279ff (patch) | |
tree | 0ad920d6cd805a5e3a357bb678fcd0a1678fc9ea /drivers/iio/imu | |
parent | f4c6d64bcf5b4bd868c53c6943d9b9bdd65eaa48 (diff) |
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>
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r-- | drivers/iio/imu/Kconfig | 11 | ||||
-rw-r--r-- | drivers/iio/imu/Makefile | 3 | ||||
-rw-r--r-- | drivers/iio/imu/adis16400.h | 204 | ||||
-rw-r--r-- | drivers/iio/imu/adis16400_buffer.c | 96 | ||||
-rw-r--r-- | drivers/iio/imu/adis16400_core.c | 812 |
5 files changed, 1126 insertions, 0 deletions
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 3d79a40e916b..47f66ed9c4ef 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig | |||
@@ -3,6 +3,17 @@ | |||
3 | # | 3 | # |
4 | menu "Inertial measurement units" | 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 | config ADIS16480 | 17 | config ADIS16480 |
7 | tristate "Analog Devices ADIS16480 and similar IMU driver" | 18 | tristate "Analog Devices ADIS16480 and similar IMU driver" |
8 | depends on SPI | 19 | depends on SPI |
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index cfe57638f6f9..019b717c5ff1 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile | |||
@@ -2,6 +2,9 @@ | |||
2 | # Makefile for Inertial Measurement Units | 2 | # Makefile for Inertial Measurement Units |
3 | # | 3 | # |
4 | 4 | ||
5 | adis16400-y := adis16400_core.o | ||
6 | adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o | ||
7 | obj-$(CONFIG_ADIS16400) += adis16400.o | ||
5 | obj-$(CONFIG_ADIS16480) += adis16480.o | 8 | obj-$(CONFIG_ADIS16480) += adis16480.o |
6 | 9 | ||
7 | adis_lib-y += adis.o | 10 | adis_lib-y += adis.o |
diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h new file mode 100644 index 000000000000..a3b9e56c5bd1 --- /dev/null +++ b/drivers/iio/imu/adis16400.h | |||
@@ -0,0 +1,204 @@ | |||
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_ */ | ||
diff --git a/drivers/iio/imu/adis16400_buffer.c b/drivers/iio/imu/adis16400_buffer.c new file mode 100644 index 000000000000..054c01d6e73c --- /dev/null +++ b/drivers/iio/imu/adis16400_buffer.c | |||
@@ -0,0 +1,96 @@ | |||
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 | } | ||
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c new file mode 100644 index 000000000000..1bbe5eed0139 --- /dev/null +++ b/drivers/iio/imu/adis16400_core.c | |||
@@ -0,0 +1,812 @@ | |||
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"); | ||