]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2f3abe6c LPC |
2 | /* |
3 | * ADIS16480 and similar IMUs driver | |
4 | * | |
5 | * Copyright 2012 Analog Devices Inc. | |
2f3abe6c LPC |
6 | */ |
7 | ||
326e2357 | 8 | #include <linux/clk.h> |
cede2f89 SP |
9 | #include <linux/bitfield.h> |
10 | #include <linux/of_irq.h> | |
2f3abe6c | 11 | #include <linux/interrupt.h> |
0463e60f | 12 | #include <linux/math.h> |
2f3abe6c LPC |
13 | #include <linux/device.h> |
14 | #include <linux/kernel.h> | |
15 | #include <linux/spi/spi.h> | |
2f3abe6c | 16 | #include <linux/module.h> |
0463e60f | 17 | #include <linux/lcm.h> |
941f1308 NS |
18 | #include <linux/swab.h> |
19 | #include <linux/crc32.h> | |
2f3abe6c LPC |
20 | |
21 | #include <linux/iio/iio.h> | |
2f3abe6c LPC |
22 | #include <linux/iio/buffer.h> |
23 | #include <linux/iio/imu/adis.h> | |
941f1308 | 24 | #include <linux/iio/trigger_consumer.h> |
2f3abe6c | 25 | |
2f3abe6c LPC |
26 | #include <linux/debugfs.h> |
27 | ||
28 | #define ADIS16480_PAGE_SIZE 0x80 | |
29 | ||
30 | #define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg)) | |
31 | ||
32 | #define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */ | |
33 | #define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06) | |
34 | #define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08) | |
35 | #define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A) | |
36 | #define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C) | |
37 | #define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E) | |
38 | #define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10) | |
39 | #define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14) | |
40 | #define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18) | |
41 | #define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C) | |
42 | #define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20) | |
43 | #define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24) | |
44 | #define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28) | |
45 | #define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A) | |
46 | #define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C) | |
47 | #define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E) | |
48 | #define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40) | |
49 | #define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44) | |
50 | #define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48) | |
51 | #define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C) | |
52 | #define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50) | |
53 | #define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54) | |
54 | #define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E) | |
55 | ||
56 | #define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04) | |
57 | #define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06) | |
58 | #define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08) | |
59 | #define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A) | |
60 | #define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C) | |
61 | #define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E) | |
62 | #define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10) | |
63 | #define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14) | |
64 | #define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18) | |
65 | #define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C) | |
66 | #define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20) | |
67 | #define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24) | |
68 | #define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28) | |
69 | #define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A) | |
70 | #define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C) | |
71 | #define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40) | |
72 | #define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C) | |
73 | ||
74 | #define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02) | |
75 | #define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06) | |
76 | #define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08) | |
77 | #define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A) | |
78 | #define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C) | |
79 | #define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10) | |
80 | #define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16) | |
81 | #define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18) | |
82 | #define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20) | |
83 | #define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22) | |
84 | #define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24) | |
85 | #define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28) | |
86 | #define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A) | |
87 | #define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C) | |
88 | #define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E) | |
89 | #define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30) | |
90 | #define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32) | |
91 | #define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34) | |
92 | #define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36) | |
93 | #define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38) | |
94 | #define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A) | |
95 | #define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78) | |
96 | #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) | |
97 | #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) | |
98 | ||
326e2357 SP |
99 | /* |
100 | * External clock scaling in PPS mode. | |
101 | * Available only for ADIS1649x devices | |
102 | */ | |
103 | #define ADIS16495_REG_SYNC_SCALE ADIS16480_REG(0x03, 0x10) | |
941f1308 NS |
104 | #define ADIS16495_REG_BURST_CMD ADIS16480_REG(0x00, 0x7C) |
105 | #define ADIS16495_BURST_ID 0xA5A5 | |
106 | /* total number of segments in burst */ | |
107 | #define ADIS16495_BURST_MAX_DATA 20 | |
108 | /* spi max speed in burst mode */ | |
109 | #define ADIS16495_BURST_MAX_SPEED 6000000 | |
326e2357 | 110 | |
2f3abe6c LPC |
111 | #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) |
112 | ||
113 | /* Each filter coefficent bank spans two pages */ | |
114 | #define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \ | |
115 | ADIS16480_REG((page) + 1, (x) - 60 + 8)) | |
116 | #define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x)) | |
117 | #define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x)) | |
118 | #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) | |
119 | #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) | |
120 | ||
cede2f89 SP |
121 | /* ADIS16480_REG_FNCTIO_CTRL */ |
122 | #define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0) | |
123 | #define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x) | |
124 | #define ADIS16480_DRDY_POL_MSK BIT(2) | |
125 | #define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x) | |
126 | #define ADIS16480_DRDY_EN_MSK BIT(3) | |
127 | #define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x) | |
326e2357 SP |
128 | #define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4) |
129 | #define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x) | |
130 | #define ADIS16480_SYNC_EN_MSK BIT(7) | |
131 | #define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x) | |
132 | #define ADIS16480_SYNC_MODE_MSK BIT(8) | |
133 | #define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) | |
cede2f89 | 134 | |
2f3abe6c LPC |
135 | struct adis16480_chip_info { |
136 | unsigned int num_channels; | |
137 | const struct iio_chan_spec *channels; | |
7abad106 LPC |
138 | unsigned int gyro_max_val; |
139 | unsigned int gyro_max_scale; | |
140 | unsigned int accel_max_val; | |
141 | unsigned int accel_max_scale; | |
6cf7b866 | 142 | unsigned int temp_scale; |
e0e6398e SP |
143 | unsigned int int_clk; |
144 | unsigned int max_dec_rate; | |
83ec2d54 | 145 | const unsigned int *filter_freqs; |
326e2357 | 146 | bool has_pps_clk_mode; |
ea1945c2 | 147 | bool has_sleep_cnt; |
97928677 | 148 | const struct adis_data adis_data; |
2f3abe6c LPC |
149 | }; |
150 | ||
cede2f89 SP |
151 | enum adis16480_int_pin { |
152 | ADIS16480_PIN_DIO1, | |
153 | ADIS16480_PIN_DIO2, | |
154 | ADIS16480_PIN_DIO3, | |
155 | ADIS16480_PIN_DIO4 | |
156 | }; | |
157 | ||
326e2357 SP |
158 | enum adis16480_clock_mode { |
159 | ADIS16480_CLK_SYNC, | |
160 | ADIS16480_CLK_PPS, | |
161 | ADIS16480_CLK_INT | |
162 | }; | |
163 | ||
2f3abe6c LPC |
164 | struct adis16480 { |
165 | const struct adis16480_chip_info *chip_info; | |
166 | ||
167 | struct adis adis; | |
326e2357 SP |
168 | struct clk *ext_clk; |
169 | enum adis16480_clock_mode clk_mode; | |
170 | unsigned int clk_freq; | |
941f1308 NS |
171 | /* Alignment needed for the timestamp */ |
172 | __be16 data[ADIS16495_BURST_MAX_DATA] __aligned(8); | |
2f3abe6c LPC |
173 | }; |
174 | ||
cede2f89 SP |
175 | static const char * const adis16480_int_pin_names[4] = { |
176 | [ADIS16480_PIN_DIO1] = "DIO1", | |
177 | [ADIS16480_PIN_DIO2] = "DIO2", | |
178 | [ADIS16480_PIN_DIO3] = "DIO3", | |
179 | [ADIS16480_PIN_DIO4] = "DIO4", | |
180 | }; | |
181 | ||
0463e60f NS |
182 | static bool low_rate_allow; |
183 | module_param(low_rate_allow, bool, 0444); | |
184 | MODULE_PARM_DESC(low_rate_allow, | |
185 | "Allow IMU rates below the minimum advisable when external clk is used in PPS mode (default: N)"); | |
186 | ||
2f3abe6c LPC |
187 | #ifdef CONFIG_DEBUG_FS |
188 | ||
189 | static ssize_t adis16480_show_firmware_revision(struct file *file, | |
190 | char __user *userbuf, size_t count, loff_t *ppos) | |
191 | { | |
192 | struct adis16480 *adis16480 = file->private_data; | |
afc3a57a | 193 | char buf[7]; |
2f3abe6c LPC |
194 | size_t len; |
195 | u16 rev; | |
196 | int ret; | |
197 | ||
198 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev); | |
92c7529f | 199 | if (ret) |
2f3abe6c LPC |
200 | return ret; |
201 | ||
afc3a57a | 202 | len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff); |
2f3abe6c LPC |
203 | |
204 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | |
205 | } | |
206 | ||
207 | static const struct file_operations adis16480_firmware_revision_fops = { | |
208 | .open = simple_open, | |
209 | .read = adis16480_show_firmware_revision, | |
210 | .llseek = default_llseek, | |
211 | .owner = THIS_MODULE, | |
212 | }; | |
213 | ||
214 | static ssize_t adis16480_show_firmware_date(struct file *file, | |
215 | char __user *userbuf, size_t count, loff_t *ppos) | |
216 | { | |
217 | struct adis16480 *adis16480 = file->private_data; | |
218 | u16 md, year; | |
219 | char buf[12]; | |
220 | size_t len; | |
221 | int ret; | |
222 | ||
223 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year); | |
92c7529f | 224 | if (ret) |
2f3abe6c LPC |
225 | return ret; |
226 | ||
227 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md); | |
92c7529f | 228 | if (ret) |
2f3abe6c LPC |
229 | return ret; |
230 | ||
231 | len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", | |
232 | md >> 8, md & 0xff, year); | |
233 | ||
234 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | |
235 | } | |
236 | ||
237 | static const struct file_operations adis16480_firmware_date_fops = { | |
238 | .open = simple_open, | |
239 | .read = adis16480_show_firmware_date, | |
240 | .llseek = default_llseek, | |
241 | .owner = THIS_MODULE, | |
242 | }; | |
243 | ||
244 | static int adis16480_show_serial_number(void *arg, u64 *val) | |
245 | { | |
246 | struct adis16480 *adis16480 = arg; | |
247 | u16 serial; | |
248 | int ret; | |
249 | ||
250 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM, | |
251 | &serial); | |
92c7529f | 252 | if (ret) |
2f3abe6c LPC |
253 | return ret; |
254 | ||
255 | *val = serial; | |
256 | ||
257 | return 0; | |
258 | } | |
9bf94f83 | 259 | DEFINE_DEBUGFS_ATTRIBUTE(adis16480_serial_number_fops, |
2f3abe6c LPC |
260 | adis16480_show_serial_number, NULL, "0x%.4llx\n"); |
261 | ||
262 | static int adis16480_show_product_id(void *arg, u64 *val) | |
263 | { | |
264 | struct adis16480 *adis16480 = arg; | |
265 | u16 prod_id; | |
266 | int ret; | |
267 | ||
268 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID, | |
269 | &prod_id); | |
92c7529f | 270 | if (ret) |
2f3abe6c LPC |
271 | return ret; |
272 | ||
273 | *val = prod_id; | |
274 | ||
275 | return 0; | |
276 | } | |
9bf94f83 | 277 | DEFINE_DEBUGFS_ATTRIBUTE(adis16480_product_id_fops, |
2f3abe6c LPC |
278 | adis16480_show_product_id, NULL, "%llu\n"); |
279 | ||
280 | static int adis16480_show_flash_count(void *arg, u64 *val) | |
281 | { | |
282 | struct adis16480 *adis16480 = arg; | |
283 | u32 flash_count; | |
284 | int ret; | |
285 | ||
286 | ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT, | |
287 | &flash_count); | |
92c7529f | 288 | if (ret) |
2f3abe6c LPC |
289 | return ret; |
290 | ||
291 | *val = flash_count; | |
292 | ||
293 | return 0; | |
294 | } | |
9bf94f83 | 295 | DEFINE_DEBUGFS_ATTRIBUTE(adis16480_flash_count_fops, |
2f3abe6c LPC |
296 | adis16480_show_flash_count, NULL, "%lld\n"); |
297 | ||
298 | static int adis16480_debugfs_init(struct iio_dev *indio_dev) | |
299 | { | |
300 | struct adis16480 *adis16480 = iio_priv(indio_dev); | |
b7190859 | 301 | struct dentry *d = iio_get_debugfs_dentry(indio_dev); |
2f3abe6c | 302 | |
9bf94f83 | 303 | debugfs_create_file_unsafe("firmware_revision", 0400, |
b7190859 | 304 | d, adis16480, &adis16480_firmware_revision_fops); |
9bf94f83 | 305 | debugfs_create_file_unsafe("firmware_date", 0400, |
b7190859 | 306 | d, adis16480, &adis16480_firmware_date_fops); |
9bf94f83 | 307 | debugfs_create_file_unsafe("serial_number", 0400, |
b7190859 | 308 | d, adis16480, &adis16480_serial_number_fops); |
9bf94f83 | 309 | debugfs_create_file_unsafe("product_id", 0400, |
b7190859 | 310 | d, adis16480, &adis16480_product_id_fops); |
9bf94f83 | 311 | debugfs_create_file_unsafe("flash_count", 0400, |
b7190859 | 312 | d, adis16480, &adis16480_flash_count_fops); |
2f3abe6c LPC |
313 | |
314 | return 0; | |
315 | } | |
316 | ||
317 | #else | |
318 | ||
319 | static int adis16480_debugfs_init(struct iio_dev *indio_dev) | |
320 | { | |
321 | return 0; | |
322 | } | |
323 | ||
324 | #endif | |
325 | ||
e4f95939 | 326 | static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) |
2f3abe6c | 327 | { |
e4f95939 | 328 | struct adis16480 *st = iio_priv(indio_dev); |
0463e60f NS |
329 | unsigned int t, sample_rate = st->clk_freq; |
330 | int ret; | |
2f3abe6c | 331 | |
24e1eb5c AA |
332 | if (val < 0 || val2 < 0) |
333 | return -EINVAL; | |
334 | ||
e4f95939 | 335 | t = val * 1000 + val2 / 1000; |
24e1eb5c | 336 | if (t == 0) |
e4f95939 JC |
337 | return -EINVAL; |
338 | ||
15aacc98 | 339 | adis_dev_lock(&st->adis); |
326e2357 | 340 | /* |
0463e60f NS |
341 | * When using PPS mode, the input clock needs to be scaled so that we have an IMU |
342 | * sample rate between (optimally) 4000 and 4250. After this, we can use the | |
343 | * decimation filter to lower the sampling rate in order to get what the user wants. | |
344 | * Optimally, the user sample rate is a multiple of both the IMU sample rate and | |
345 | * the input clock. Hence, calculating the sync_scale dynamically gives us better | |
346 | * chances of achieving a perfect/integer value for DEC_RATE. The math here is: | |
347 | * 1. lcm of the input clock and the desired output rate. | |
348 | * 2. get the highest multiple of the previous result lower than the adis max rate. | |
349 | * 3. The last result becomes the IMU sample rate. Use that to calculate SYNC_SCALE | |
350 | * and DEC_RATE (to get the user output rate) | |
326e2357 SP |
351 | */ |
352 | if (st->clk_mode == ADIS16480_CLK_PPS) { | |
0463e60f NS |
353 | unsigned long scaled_rate = lcm(st->clk_freq, t); |
354 | int sync_scale; | |
355 | ||
356 | /* | |
357 | * If lcm is bigger than the IMU maximum sampling rate there's no perfect | |
358 | * solution. In this case, we get the highest multiple of the input clock | |
359 | * lower than the IMU max sample rate. | |
360 | */ | |
361 | if (scaled_rate > st->chip_info->int_clk) | |
362 | scaled_rate = st->chip_info->int_clk / st->clk_freq * st->clk_freq; | |
363 | else | |
364 | scaled_rate = st->chip_info->int_clk / scaled_rate * scaled_rate; | |
365 | ||
366 | /* | |
367 | * This is not an hard requirement but it's not advised to run the IMU | |
368 | * with a sample rate lower than 4000Hz due to possible undersampling | |
369 | * issues. However, there are users that might really want to take the risk. | |
370 | * Hence, we provide a module parameter for them. If set, we allow sample | |
371 | * rates lower than 4KHz. By default, we won't allow this and we just roundup | |
372 | * the rate to the next multiple of the input clock bigger than 4KHz. This | |
373 | * is done like this as in some cases (when DEC_RATE is 0) might give | |
374 | * us the closest value to the one desired by the user... | |
375 | */ | |
376 | if (scaled_rate < 4000000 && !low_rate_allow) | |
377 | scaled_rate = roundup(4000000, st->clk_freq); | |
378 | ||
379 | sync_scale = scaled_rate / st->clk_freq; | |
380 | ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); | |
381 | if (ret) | |
382 | goto error; | |
383 | ||
384 | sample_rate = scaled_rate; | |
326e2357 SP |
385 | } |
386 | ||
0463e60f NS |
387 | t = DIV_ROUND_CLOSEST(sample_rate, t); |
388 | if (t) | |
389 | t--; | |
390 | ||
e0e6398e SP |
391 | if (t > st->chip_info->max_dec_rate) |
392 | t = st->chip_info->max_dec_rate; | |
2f3abe6c | 393 | |
0463e60f NS |
394 | ret = __adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); |
395 | error: | |
15aacc98 | 396 | adis_dev_unlock(&st->adis); |
0463e60f | 397 | return ret; |
2f3abe6c LPC |
398 | } |
399 | ||
e4f95939 | 400 | static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) |
2f3abe6c | 401 | { |
e4f95939 | 402 | struct adis16480 *st = iio_priv(indio_dev); |
2f3abe6c LPC |
403 | uint16_t t; |
404 | int ret; | |
0463e60f | 405 | unsigned int freq, sample_rate = st->clk_freq; |
326e2357 | 406 | |
15aacc98 | 407 | adis_dev_lock(&st->adis); |
0463e60f NS |
408 | |
409 | if (st->clk_mode == ADIS16480_CLK_PPS) { | |
410 | u16 sync_scale; | |
411 | ||
412 | ret = __adis_read_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, &sync_scale); | |
413 | if (ret) | |
414 | goto error; | |
2f3abe6c | 415 | |
0463e60f NS |
416 | sample_rate = st->clk_freq * sync_scale; |
417 | } | |
418 | ||
419 | ret = __adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); | |
92c7529f | 420 | if (ret) |
0463e60f | 421 | goto error; |
2f3abe6c | 422 | |
15aacc98 | 423 | adis_dev_unlock(&st->adis); |
0463e60f NS |
424 | |
425 | freq = DIV_ROUND_CLOSEST(sample_rate, (t + 1)); | |
326e2357 | 426 | |
e4f95939 JC |
427 | *val = freq / 1000; |
428 | *val2 = (freq % 1000) * 1000; | |
2f3abe6c | 429 | |
e4f95939 | 430 | return IIO_VAL_INT_PLUS_MICRO; |
0463e60f | 431 | error: |
15aacc98 | 432 | adis_dev_unlock(&st->adis); |
0463e60f | 433 | return ret; |
2f3abe6c LPC |
434 | } |
435 | ||
2f3abe6c LPC |
436 | enum { |
437 | ADIS16480_SCAN_GYRO_X, | |
438 | ADIS16480_SCAN_GYRO_Y, | |
439 | ADIS16480_SCAN_GYRO_Z, | |
440 | ADIS16480_SCAN_ACCEL_X, | |
441 | ADIS16480_SCAN_ACCEL_Y, | |
442 | ADIS16480_SCAN_ACCEL_Z, | |
443 | ADIS16480_SCAN_MAGN_X, | |
444 | ADIS16480_SCAN_MAGN_Y, | |
445 | ADIS16480_SCAN_MAGN_Z, | |
446 | ADIS16480_SCAN_BARO, | |
447 | ADIS16480_SCAN_TEMP, | |
448 | }; | |
449 | ||
450 | static const unsigned int adis16480_calibbias_regs[] = { | |
451 | [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS, | |
452 | [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS, | |
453 | [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS, | |
454 | [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS, | |
455 | [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS, | |
456 | [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS, | |
457 | [ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON, | |
458 | [ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON, | |
459 | [ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON, | |
460 | [ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS, | |
461 | }; | |
462 | ||
463 | static const unsigned int adis16480_calibscale_regs[] = { | |
464 | [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE, | |
465 | [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE, | |
466 | [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE, | |
467 | [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE, | |
468 | [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE, | |
469 | [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE, | |
470 | }; | |
471 | ||
472 | static int adis16480_set_calibbias(struct iio_dev *indio_dev, | |
473 | const struct iio_chan_spec *chan, int bias) | |
474 | { | |
475 | unsigned int reg = adis16480_calibbias_regs[chan->scan_index]; | |
476 | struct adis16480 *st = iio_priv(indio_dev); | |
477 | ||
478 | switch (chan->type) { | |
479 | case IIO_MAGN: | |
480 | case IIO_PRESSURE: | |
481 | if (bias < -0x8000 || bias >= 0x8000) | |
482 | return -EINVAL; | |
483 | return adis_write_reg_16(&st->adis, reg, bias); | |
484 | case IIO_ANGL_VEL: | |
485 | case IIO_ACCEL: | |
486 | return adis_write_reg_32(&st->adis, reg, bias); | |
487 | default: | |
488 | break; | |
489 | } | |
490 | ||
491 | return -EINVAL; | |
492 | } | |
493 | ||
494 | static int adis16480_get_calibbias(struct iio_dev *indio_dev, | |
495 | const struct iio_chan_spec *chan, int *bias) | |
496 | { | |
497 | unsigned int reg = adis16480_calibbias_regs[chan->scan_index]; | |
498 | struct adis16480 *st = iio_priv(indio_dev); | |
499 | uint16_t val16; | |
500 | uint32_t val32; | |
501 | int ret; | |
502 | ||
503 | switch (chan->type) { | |
504 | case IIO_MAGN: | |
505 | case IIO_PRESSURE: | |
506 | ret = adis_read_reg_16(&st->adis, reg, &val16); | |
9b742763 AA |
507 | if (ret == 0) |
508 | *bias = sign_extend32(val16, 15); | |
2f3abe6c LPC |
509 | break; |
510 | case IIO_ANGL_VEL: | |
511 | case IIO_ACCEL: | |
512 | ret = adis_read_reg_32(&st->adis, reg, &val32); | |
9b742763 AA |
513 | if (ret == 0) |
514 | *bias = sign_extend32(val32, 31); | |
2f3abe6c LPC |
515 | break; |
516 | default: | |
d9bbae30 | 517 | ret = -EINVAL; |
2f3abe6c LPC |
518 | } |
519 | ||
92c7529f | 520 | if (ret) |
2f3abe6c LPC |
521 | return ret; |
522 | ||
523 | return IIO_VAL_INT; | |
524 | } | |
525 | ||
526 | static int adis16480_set_calibscale(struct iio_dev *indio_dev, | |
527 | const struct iio_chan_spec *chan, int scale) | |
528 | { | |
529 | unsigned int reg = adis16480_calibscale_regs[chan->scan_index]; | |
530 | struct adis16480 *st = iio_priv(indio_dev); | |
531 | ||
532 | if (scale < -0x8000 || scale >= 0x8000) | |
533 | return -EINVAL; | |
534 | ||
535 | return adis_write_reg_16(&st->adis, reg, scale); | |
536 | } | |
537 | ||
538 | static int adis16480_get_calibscale(struct iio_dev *indio_dev, | |
539 | const struct iio_chan_spec *chan, int *scale) | |
540 | { | |
541 | unsigned int reg = adis16480_calibscale_regs[chan->scan_index]; | |
542 | struct adis16480 *st = iio_priv(indio_dev); | |
543 | uint16_t val16; | |
544 | int ret; | |
545 | ||
546 | ret = adis_read_reg_16(&st->adis, reg, &val16); | |
92c7529f | 547 | if (ret) |
2f3abe6c LPC |
548 | return ret; |
549 | ||
550 | *scale = sign_extend32(val16, 15); | |
551 | return IIO_VAL_INT; | |
552 | } | |
553 | ||
554 | static const unsigned int adis16480_def_filter_freqs[] = { | |
555 | 310, | |
556 | 55, | |
557 | 275, | |
558 | 63, | |
559 | }; | |
560 | ||
82e7a1b2 SP |
561 | static const unsigned int adis16495_def_filter_freqs[] = { |
562 | 300, | |
563 | 100, | |
564 | 300, | |
565 | 100, | |
566 | }; | |
567 | ||
2f3abe6c LPC |
568 | static const unsigned int ad16480_filter_data[][2] = { |
569 | [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 }, | |
570 | [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 }, | |
571 | [ADIS16480_SCAN_GYRO_Z] = { ADIS16480_REG_FILTER_BNK0, 6 }, | |
572 | [ADIS16480_SCAN_ACCEL_X] = { ADIS16480_REG_FILTER_BNK0, 9 }, | |
573 | [ADIS16480_SCAN_ACCEL_Y] = { ADIS16480_REG_FILTER_BNK0, 12 }, | |
574 | [ADIS16480_SCAN_ACCEL_Z] = { ADIS16480_REG_FILTER_BNK1, 0 }, | |
575 | [ADIS16480_SCAN_MAGN_X] = { ADIS16480_REG_FILTER_BNK1, 3 }, | |
576 | [ADIS16480_SCAN_MAGN_Y] = { ADIS16480_REG_FILTER_BNK1, 6 }, | |
577 | [ADIS16480_SCAN_MAGN_Z] = { ADIS16480_REG_FILTER_BNK1, 9 }, | |
578 | }; | |
579 | ||
580 | static int adis16480_get_filter_freq(struct iio_dev *indio_dev, | |
581 | const struct iio_chan_spec *chan, int *freq) | |
582 | { | |
583 | struct adis16480 *st = iio_priv(indio_dev); | |
584 | unsigned int enable_mask, offset, reg; | |
585 | uint16_t val; | |
586 | int ret; | |
587 | ||
588 | reg = ad16480_filter_data[chan->scan_index][0]; | |
589 | offset = ad16480_filter_data[chan->scan_index][1]; | |
590 | enable_mask = BIT(offset + 2); | |
591 | ||
592 | ret = adis_read_reg_16(&st->adis, reg, &val); | |
92c7529f | 593 | if (ret) |
2f3abe6c LPC |
594 | return ret; |
595 | ||
596 | if (!(val & enable_mask)) | |
597 | *freq = 0; | |
598 | else | |
83ec2d54 | 599 | *freq = st->chip_info->filter_freqs[(val >> offset) & 0x3]; |
2f3abe6c LPC |
600 | |
601 | return IIO_VAL_INT; | |
602 | } | |
603 | ||
604 | static int adis16480_set_filter_freq(struct iio_dev *indio_dev, | |
605 | const struct iio_chan_spec *chan, unsigned int freq) | |
606 | { | |
607 | struct adis16480 *st = iio_priv(indio_dev); | |
608 | unsigned int enable_mask, offset, reg; | |
609 | unsigned int diff, best_diff; | |
610 | unsigned int i, best_freq; | |
611 | uint16_t val; | |
612 | int ret; | |
613 | ||
614 | reg = ad16480_filter_data[chan->scan_index][0]; | |
615 | offset = ad16480_filter_data[chan->scan_index][1]; | |
616 | enable_mask = BIT(offset + 2); | |
617 | ||
15aacc98 | 618 | adis_dev_lock(&st->adis); |
d693845d AA |
619 | |
620 | ret = __adis_read_reg_16(&st->adis, reg, &val); | |
92c7529f | 621 | if (ret) |
d693845d | 622 | goto out_unlock; |
2f3abe6c LPC |
623 | |
624 | if (freq == 0) { | |
625 | val &= ~enable_mask; | |
626 | } else { | |
627 | best_freq = 0; | |
83ec2d54 | 628 | best_diff = st->chip_info->filter_freqs[0]; |
2f3abe6c | 629 | for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { |
83ec2d54 SP |
630 | if (st->chip_info->filter_freqs[i] >= freq) { |
631 | diff = st->chip_info->filter_freqs[i] - freq; | |
2f3abe6c LPC |
632 | if (diff < best_diff) { |
633 | best_diff = diff; | |
634 | best_freq = i; | |
635 | } | |
636 | } | |
637 | } | |
638 | ||
639 | val &= ~(0x3 << offset); | |
640 | val |= best_freq << offset; | |
641 | val |= enable_mask; | |
642 | } | |
643 | ||
d693845d AA |
644 | ret = __adis_write_reg_16(&st->adis, reg, val); |
645 | out_unlock: | |
15aacc98 | 646 | adis_dev_unlock(&st->adis); |
d693845d AA |
647 | |
648 | return ret; | |
2f3abe6c LPC |
649 | } |
650 | ||
651 | static int adis16480_read_raw(struct iio_dev *indio_dev, | |
652 | const struct iio_chan_spec *chan, int *val, int *val2, long info) | |
653 | { | |
7abad106 | 654 | struct adis16480 *st = iio_priv(indio_dev); |
6cf7b866 | 655 | unsigned int temp; |
7abad106 | 656 | |
2f3abe6c LPC |
657 | switch (info) { |
658 | case IIO_CHAN_INFO_RAW: | |
659 | return adis_single_conversion(indio_dev, chan, 0, val); | |
660 | case IIO_CHAN_INFO_SCALE: | |
661 | switch (chan->type) { | |
662 | case IIO_ANGL_VEL: | |
7abad106 LPC |
663 | *val = st->chip_info->gyro_max_scale; |
664 | *val2 = st->chip_info->gyro_max_val; | |
665 | return IIO_VAL_FRACTIONAL; | |
2f3abe6c | 666 | case IIO_ACCEL: |
7abad106 LPC |
667 | *val = st->chip_info->accel_max_scale; |
668 | *val2 = st->chip_info->accel_max_val; | |
669 | return IIO_VAL_FRACTIONAL; | |
2f3abe6c LPC |
670 | case IIO_MAGN: |
671 | *val = 0; | |
672 | *val2 = 100; /* 0.0001 gauss */ | |
673 | return IIO_VAL_INT_PLUS_MICRO; | |
674 | case IIO_TEMP: | |
6cf7b866 SP |
675 | /* |
676 | * +85 degrees Celsius = temp_max_scale | |
677 | * +25 degrees Celsius = 0 | |
678 | * LSB, 25 degrees Celsius = 60 / temp_max_scale | |
679 | */ | |
680 | *val = st->chip_info->temp_scale / 1000; | |
681 | *val2 = (st->chip_info->temp_scale % 1000) * 1000; | |
2f3abe6c LPC |
682 | return IIO_VAL_INT_PLUS_MICRO; |
683 | case IIO_PRESSURE: | |
49549cb2 NS |
684 | /* |
685 | * max scale is 1310 mbar | |
686 | * max raw value is 32767 shifted for 32bits | |
687 | */ | |
688 | *val = 131; /* 1310mbar = 131 kPa */ | |
689 | *val2 = 32767 << 16; | |
690 | return IIO_VAL_FRACTIONAL; | |
2f3abe6c LPC |
691 | default: |
692 | return -EINVAL; | |
693 | } | |
694 | case IIO_CHAN_INFO_OFFSET: | |
695 | /* Only the temperature channel has a offset */ | |
6cf7b866 SP |
696 | temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */ |
697 | *val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale); | |
2f3abe6c LPC |
698 | return IIO_VAL_INT; |
699 | case IIO_CHAN_INFO_CALIBBIAS: | |
700 | return adis16480_get_calibbias(indio_dev, chan, val); | |
701 | case IIO_CHAN_INFO_CALIBSCALE: | |
702 | return adis16480_get_calibscale(indio_dev, chan, val); | |
703 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
704 | return adis16480_get_filter_freq(indio_dev, chan, val); | |
e4f95939 JC |
705 | case IIO_CHAN_INFO_SAMP_FREQ: |
706 | return adis16480_get_freq(indio_dev, val, val2); | |
2f3abe6c LPC |
707 | default: |
708 | return -EINVAL; | |
709 | } | |
710 | } | |
711 | ||
712 | static int adis16480_write_raw(struct iio_dev *indio_dev, | |
713 | const struct iio_chan_spec *chan, int val, int val2, long info) | |
714 | { | |
715 | switch (info) { | |
716 | case IIO_CHAN_INFO_CALIBBIAS: | |
717 | return adis16480_set_calibbias(indio_dev, chan, val); | |
718 | case IIO_CHAN_INFO_CALIBSCALE: | |
719 | return adis16480_set_calibscale(indio_dev, chan, val); | |
720 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
721 | return adis16480_set_filter_freq(indio_dev, chan, val); | |
e4f95939 JC |
722 | case IIO_CHAN_INFO_SAMP_FREQ: |
723 | return adis16480_set_freq(indio_dev, val, val2); | |
724 | ||
2f3abe6c LPC |
725 | default: |
726 | return -EINVAL; | |
727 | } | |
728 | } | |
729 | ||
86b64c9d | 730 | #define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \ |
2f3abe6c LPC |
731 | { \ |
732 | .type = (_type), \ | |
733 | .modified = 1, \ | |
734 | .channel2 = (_mod), \ | |
86b64c9d JC |
735 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
736 | BIT(IIO_CHAN_INFO_CALIBBIAS) | \ | |
737 | _info_sep, \ | |
738 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | |
e4f95939 | 739 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
2f3abe6c LPC |
740 | .address = (_address), \ |
741 | .scan_index = (_si), \ | |
742 | .scan_type = { \ | |
743 | .sign = 's', \ | |
744 | .realbits = (_bits), \ | |
745 | .storagebits = (_bits), \ | |
746 | .endianness = IIO_BE, \ | |
747 | }, \ | |
748 | } | |
749 | ||
750 | #define ADIS16480_GYRO_CHANNEL(_mod) \ | |
751 | ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \ | |
752 | ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \ | |
86b64c9d JC |
753 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ |
754 | BIT(IIO_CHAN_INFO_CALIBSCALE), \ | |
2f3abe6c LPC |
755 | 32) |
756 | ||
757 | #define ADIS16480_ACCEL_CHANNEL(_mod) \ | |
758 | ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \ | |
759 | ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \ | |
86b64c9d JC |
760 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ |
761 | BIT(IIO_CHAN_INFO_CALIBSCALE), \ | |
2f3abe6c LPC |
762 | 32) |
763 | ||
764 | #define ADIS16480_MAGN_CHANNEL(_mod) \ | |
765 | ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \ | |
766 | ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \ | |
86b64c9d | 767 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ |
2f3abe6c LPC |
768 | 16) |
769 | ||
770 | #define ADIS16480_PRESSURE_CHANNEL() \ | |
771 | { \ | |
772 | .type = IIO_PRESSURE, \ | |
773 | .indexed = 1, \ | |
774 | .channel = 0, \ | |
86b64c9d JC |
775 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
776 | BIT(IIO_CHAN_INFO_CALIBBIAS) | \ | |
777 | BIT(IIO_CHAN_INFO_SCALE), \ | |
e4f95939 | 778 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
2f3abe6c LPC |
779 | .address = ADIS16480_REG_BAROM_OUT, \ |
780 | .scan_index = ADIS16480_SCAN_BARO, \ | |
781 | .scan_type = { \ | |
782 | .sign = 's', \ | |
783 | .realbits = 32, \ | |
784 | .storagebits = 32, \ | |
785 | .endianness = IIO_BE, \ | |
786 | }, \ | |
787 | } | |
788 | ||
789 | #define ADIS16480_TEMP_CHANNEL() { \ | |
790 | .type = IIO_TEMP, \ | |
791 | .indexed = 1, \ | |
792 | .channel = 0, \ | |
86b64c9d JC |
793 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
794 | BIT(IIO_CHAN_INFO_SCALE) | \ | |
795 | BIT(IIO_CHAN_INFO_OFFSET), \ | |
e4f95939 | 796 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
2f3abe6c LPC |
797 | .address = ADIS16480_REG_TEMP_OUT, \ |
798 | .scan_index = ADIS16480_SCAN_TEMP, \ | |
799 | .scan_type = { \ | |
800 | .sign = 's', \ | |
801 | .realbits = 16, \ | |
802 | .storagebits = 16, \ | |
803 | .endianness = IIO_BE, \ | |
804 | }, \ | |
805 | } | |
806 | ||
807 | static const struct iio_chan_spec adis16480_channels[] = { | |
808 | ADIS16480_GYRO_CHANNEL(X), | |
809 | ADIS16480_GYRO_CHANNEL(Y), | |
810 | ADIS16480_GYRO_CHANNEL(Z), | |
811 | ADIS16480_ACCEL_CHANNEL(X), | |
812 | ADIS16480_ACCEL_CHANNEL(Y), | |
813 | ADIS16480_ACCEL_CHANNEL(Z), | |
814 | ADIS16480_MAGN_CHANNEL(X), | |
815 | ADIS16480_MAGN_CHANNEL(Y), | |
816 | ADIS16480_MAGN_CHANNEL(Z), | |
817 | ADIS16480_PRESSURE_CHANNEL(), | |
818 | ADIS16480_TEMP_CHANNEL(), | |
819 | IIO_CHAN_SOFT_TIMESTAMP(11) | |
820 | }; | |
821 | ||
822 | static const struct iio_chan_spec adis16485_channels[] = { | |
823 | ADIS16480_GYRO_CHANNEL(X), | |
824 | ADIS16480_GYRO_CHANNEL(Y), | |
825 | ADIS16480_GYRO_CHANNEL(Z), | |
826 | ADIS16480_ACCEL_CHANNEL(X), | |
827 | ADIS16480_ACCEL_CHANNEL(Y), | |
828 | ADIS16480_ACCEL_CHANNEL(Z), | |
829 | ADIS16480_TEMP_CHANNEL(), | |
830 | IIO_CHAN_SOFT_TIMESTAMP(7) | |
831 | }; | |
832 | ||
833 | enum adis16480_variant { | |
834 | ADIS16375, | |
835 | ADIS16480, | |
836 | ADIS16485, | |
837 | ADIS16488, | |
80cbc848 | 838 | ADIS16490, |
82e7a1b2 SP |
839 | ADIS16495_1, |
840 | ADIS16495_2, | |
841 | ADIS16495_3, | |
842 | ADIS16497_1, | |
843 | ADIS16497_2, | |
844 | ADIS16497_3, | |
2f3abe6c LPC |
845 | }; |
846 | ||
97928677 AA |
847 | #define ADIS16480_DIAG_STAT_XGYRO_FAIL 0 |
848 | #define ADIS16480_DIAG_STAT_YGYRO_FAIL 1 | |
849 | #define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2 | |
850 | #define ADIS16480_DIAG_STAT_XACCL_FAIL 3 | |
851 | #define ADIS16480_DIAG_STAT_YACCL_FAIL 4 | |
852 | #define ADIS16480_DIAG_STAT_ZACCL_FAIL 5 | |
853 | #define ADIS16480_DIAG_STAT_XMAGN_FAIL 8 | |
854 | #define ADIS16480_DIAG_STAT_YMAGN_FAIL 9 | |
855 | #define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10 | |
856 | #define ADIS16480_DIAG_STAT_BARO_FAIL 11 | |
857 | ||
858 | static const char * const adis16480_status_error_msgs[] = { | |
859 | [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure", | |
860 | [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure", | |
861 | [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure", | |
862 | [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure", | |
863 | [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure", | |
864 | [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure", | |
865 | [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure", | |
866 | [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure", | |
867 | [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure", | |
868 | [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure", | |
869 | }; | |
870 | ||
871 | static int adis16480_enable_irq(struct adis *adis, bool enable); | |
872 | ||
941f1308 | 873 | #define ADIS16480_DATA(_prod_id, _timeouts, _burst_len) \ |
97928677 AA |
874 | { \ |
875 | .diag_stat_reg = ADIS16480_REG_DIAG_STS, \ | |
876 | .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \ | |
366a5434 NS |
877 | .prod_id_reg = ADIS16480_REG_PROD_ID, \ |
878 | .prod_id = (_prod_id), \ | |
97928677 AA |
879 | .has_paging = true, \ |
880 | .read_delay = 5, \ | |
881 | .write_delay = 5, \ | |
882 | .self_test_mask = BIT(1), \ | |
fdcf6bbb | 883 | .self_test_reg = ADIS16480_REG_GLOB_CMD, \ |
97928677 AA |
884 | .status_error_msgs = adis16480_status_error_msgs, \ |
885 | .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \ | |
886 | BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \ | |
887 | BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \ | |
888 | BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \ | |
889 | BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \ | |
890 | BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \ | |
891 | BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \ | |
892 | BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \ | |
893 | BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \ | |
894 | BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \ | |
895 | .enable_irq = adis16480_enable_irq, \ | |
896 | .timeouts = (_timeouts), \ | |
941f1308 NS |
897 | .burst_reg_cmd = ADIS16495_REG_BURST_CMD, \ |
898 | .burst_len = (_burst_len), \ | |
899 | .burst_max_speed_hz = ADIS16495_BURST_MAX_SPEED \ | |
97928677 AA |
900 | } |
901 | ||
380b107b NS |
902 | static const struct adis_timeout adis16485_timeouts = { |
903 | .reset_ms = 560, | |
904 | .sw_reset_ms = 120, | |
905 | .self_test_ms = 12, | |
906 | }; | |
907 | ||
908 | static const struct adis_timeout adis16480_timeouts = { | |
909 | .reset_ms = 560, | |
910 | .sw_reset_ms = 560, | |
911 | .self_test_ms = 12, | |
912 | }; | |
913 | ||
914 | static const struct adis_timeout adis16495_timeouts = { | |
915 | .reset_ms = 170, | |
916 | .sw_reset_ms = 130, | |
917 | .self_test_ms = 40, | |
918 | }; | |
919 | ||
920 | static const struct adis_timeout adis16495_1_timeouts = { | |
921 | .reset_ms = 250, | |
922 | .sw_reset_ms = 210, | |
923 | .self_test_ms = 20, | |
924 | }; | |
925 | ||
2f3abe6c LPC |
926 | static const struct adis16480_chip_info adis16480_chip_info[] = { |
927 | [ADIS16375] = { | |
928 | .channels = adis16485_channels, | |
929 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
7abad106 | 930 | /* |
49549cb2 NS |
931 | * Typically we do IIO_RAD_TO_DEGREE in the denominator, which |
932 | * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since | |
933 | * it gives better approximation. However, in this case we | |
934 | * cannot do it since it would not fit in a 32bit variable. | |
7abad106 | 935 | */ |
49549cb2 NS |
936 | .gyro_max_val = 22887 << 16, |
937 | .gyro_max_scale = IIO_DEGREE_TO_RAD(300), | |
938 | .accel_max_val = IIO_M_S_2_TO_G(21973 << 16), | |
7abad106 | 939 | .accel_max_scale = 18, |
6cf7b866 | 940 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
e0e6398e SP |
941 | .int_clk = 2460000, |
942 | .max_dec_rate = 2048, | |
ea1945c2 | 943 | .has_sleep_cnt = true, |
83ec2d54 | 944 | .filter_freqs = adis16480_def_filter_freqs, |
941f1308 | 945 | .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts, 0), |
2f3abe6c LPC |
946 | }, |
947 | [ADIS16480] = { | |
948 | .channels = adis16480_channels, | |
949 | .num_channels = ARRAY_SIZE(adis16480_channels), | |
49549cb2 NS |
950 | .gyro_max_val = 22500 << 16, |
951 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | |
952 | .accel_max_val = IIO_M_S_2_TO_G(12500 << 16), | |
fdd0d32e | 953 | .accel_max_scale = 10, |
6cf7b866 | 954 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
e0e6398e SP |
955 | .int_clk = 2460000, |
956 | .max_dec_rate = 2048, | |
ea1945c2 | 957 | .has_sleep_cnt = true, |
83ec2d54 | 958 | .filter_freqs = adis16480_def_filter_freqs, |
941f1308 | 959 | .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts, 0), |
2f3abe6c LPC |
960 | }, |
961 | [ADIS16485] = { | |
962 | .channels = adis16485_channels, | |
963 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
964 | .gyro_max_val = 22500 << 16, |
965 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | |
966 | .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), | |
7abad106 | 967 | .accel_max_scale = 5, |
6cf7b866 | 968 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
e0e6398e SP |
969 | .int_clk = 2460000, |
970 | .max_dec_rate = 2048, | |
ea1945c2 | 971 | .has_sleep_cnt = true, |
83ec2d54 | 972 | .filter_freqs = adis16480_def_filter_freqs, |
941f1308 | 973 | .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts, 0), |
2f3abe6c LPC |
974 | }, |
975 | [ADIS16488] = { | |
976 | .channels = adis16480_channels, | |
977 | .num_channels = ARRAY_SIZE(adis16480_channels), | |
49549cb2 NS |
978 | .gyro_max_val = 22500 << 16, |
979 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | |
980 | .accel_max_val = IIO_M_S_2_TO_G(22500 << 16), | |
7abad106 | 981 | .accel_max_scale = 18, |
6cf7b866 | 982 | .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
e0e6398e SP |
983 | .int_clk = 2460000, |
984 | .max_dec_rate = 2048, | |
ea1945c2 | 985 | .has_sleep_cnt = true, |
83ec2d54 | 986 | .filter_freqs = adis16480_def_filter_freqs, |
941f1308 | 987 | .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts, 0), |
2f3abe6c | 988 | }, |
80cbc848 SP |
989 | [ADIS16490] = { |
990 | .channels = adis16485_channels, | |
991 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
992 | .gyro_max_val = 20000 << 16, | |
993 | .gyro_max_scale = IIO_DEGREE_TO_RAD(100), | |
994 | .accel_max_val = IIO_M_S_2_TO_G(16000 << 16), | |
995 | .accel_max_scale = 8, | |
996 | .temp_scale = 14285, /* 14.285 milli degree Celsius */ | |
997 | .int_clk = 4250000, | |
998 | .max_dec_rate = 4250, | |
999 | .filter_freqs = adis16495_def_filter_freqs, | |
1000 | .has_pps_clk_mode = true, | |
941f1308 | 1001 | .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts, 0), |
80cbc848 | 1002 | }, |
82e7a1b2 SP |
1003 | [ADIS16495_1] = { |
1004 | .channels = adis16485_channels, | |
1005 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1006 | .gyro_max_val = 20000 << 16, |
1007 | .gyro_max_scale = IIO_DEGREE_TO_RAD(125), | |
1008 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1009 | .accel_max_scale = 8, |
1010 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1011 | .int_clk = 4250000, | |
1012 | .max_dec_rate = 4250, | |
1013 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1014 | .has_pps_clk_mode = true, |
941f1308 NS |
1015 | /* 20 elements of 16bits */ |
1016 | .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, | |
1017 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 SP |
1018 | }, |
1019 | [ADIS16495_2] = { | |
1020 | .channels = adis16485_channels, | |
1021 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1022 | .gyro_max_val = 18000 << 16, |
1023 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | |
1024 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1025 | .accel_max_scale = 8, |
1026 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1027 | .int_clk = 4250000, | |
1028 | .max_dec_rate = 4250, | |
1029 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1030 | .has_pps_clk_mode = true, |
941f1308 NS |
1031 | /* 20 elements of 16bits */ |
1032 | .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, | |
1033 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 SP |
1034 | }, |
1035 | [ADIS16495_3] = { | |
1036 | .channels = adis16485_channels, | |
1037 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1038 | .gyro_max_val = 20000 << 16, |
1039 | .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), | |
1040 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1041 | .accel_max_scale = 8, |
1042 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1043 | .int_clk = 4250000, | |
1044 | .max_dec_rate = 4250, | |
1045 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1046 | .has_pps_clk_mode = true, |
941f1308 NS |
1047 | /* 20 elements of 16bits */ |
1048 | .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts, | |
1049 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 SP |
1050 | }, |
1051 | [ADIS16497_1] = { | |
1052 | .channels = adis16485_channels, | |
1053 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1054 | .gyro_max_val = 20000 << 16, |
1055 | .gyro_max_scale = IIO_DEGREE_TO_RAD(125), | |
1056 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1057 | .accel_max_scale = 40, |
1058 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1059 | .int_clk = 4250000, | |
1060 | .max_dec_rate = 4250, | |
1061 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1062 | .has_pps_clk_mode = true, |
941f1308 NS |
1063 | /* 20 elements of 16bits */ |
1064 | .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, | |
1065 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 SP |
1066 | }, |
1067 | [ADIS16497_2] = { | |
1068 | .channels = adis16485_channels, | |
1069 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1070 | .gyro_max_val = 18000 << 16, |
1071 | .gyro_max_scale = IIO_DEGREE_TO_RAD(450), | |
1072 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1073 | .accel_max_scale = 40, |
1074 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1075 | .int_clk = 4250000, | |
1076 | .max_dec_rate = 4250, | |
1077 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1078 | .has_pps_clk_mode = true, |
941f1308 NS |
1079 | /* 20 elements of 16bits */ |
1080 | .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, | |
1081 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 SP |
1082 | }, |
1083 | [ADIS16497_3] = { | |
1084 | .channels = adis16485_channels, | |
1085 | .num_channels = ARRAY_SIZE(adis16485_channels), | |
49549cb2 NS |
1086 | .gyro_max_val = 20000 << 16, |
1087 | .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), | |
1088 | .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), | |
82e7a1b2 SP |
1089 | .accel_max_scale = 40, |
1090 | .temp_scale = 12500, /* 12.5 milli degree Celsius */ | |
1091 | .int_clk = 4250000, | |
1092 | .max_dec_rate = 4250, | |
1093 | .filter_freqs = adis16495_def_filter_freqs, | |
326e2357 | 1094 | .has_pps_clk_mode = true, |
941f1308 NS |
1095 | /* 20 elements of 16bits */ |
1096 | .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts, | |
1097 | ADIS16495_BURST_MAX_DATA * 2), | |
82e7a1b2 | 1098 | }, |
2f3abe6c LPC |
1099 | }; |
1100 | ||
941f1308 NS |
1101 | static bool adis16480_validate_crc(const u16 *buf, const u8 n_elem, const u32 crc) |
1102 | { | |
1103 | u32 crc_calc; | |
1104 | u16 crc_buf[15]; | |
1105 | int j; | |
1106 | ||
1107 | for (j = 0; j < n_elem; j++) | |
1108 | crc_buf[j] = swab16(buf[j]); | |
1109 | ||
1110 | crc_calc = crc32(~0, crc_buf, n_elem * 2); | |
1111 | crc_calc ^= ~0; | |
1112 | ||
1113 | return (crc == crc_calc); | |
1114 | } | |
1115 | ||
1116 | static irqreturn_t adis16480_trigger_handler(int irq, void *p) | |
1117 | { | |
1118 | struct iio_poll_func *pf = p; | |
1119 | struct iio_dev *indio_dev = pf->indio_dev; | |
1120 | struct adis16480 *st = iio_priv(indio_dev); | |
1121 | struct adis *adis = &st->adis; | |
1122 | int ret, bit, offset, i = 0; | |
1123 | __be16 *buffer; | |
1124 | u32 crc; | |
1125 | bool valid; | |
1126 | ||
1127 | adis_dev_lock(adis); | |
1128 | if (adis->current_page != 0) { | |
1129 | adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); | |
1130 | adis->tx[1] = 0; | |
1131 | ret = spi_write(adis->spi, adis->tx, 2); | |
1132 | if (ret) { | |
1133 | dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); | |
1134 | adis_dev_unlock(adis); | |
1135 | goto irq_done; | |
1136 | } | |
1137 | ||
1138 | adis->current_page = 0; | |
1139 | } | |
1140 | ||
1141 | ret = spi_sync(adis->spi, &adis->msg); | |
1142 | if (ret) { | |
1143 | dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret); | |
1144 | adis_dev_unlock(adis); | |
1145 | goto irq_done; | |
1146 | } | |
1147 | ||
1148 | adis_dev_unlock(adis); | |
1149 | ||
1150 | /* | |
1151 | * After making the burst request, the response can have one or two | |
1152 | * 16-bit responses containing the BURST_ID depending on the sclk. If | |
1153 | * clk > 3.6MHz, then we will have two BURST_ID in a row. If clk < 3MHZ, | |
1154 | * we have only one. To manage that variation, we use the transition from the | |
1155 | * BURST_ID to the SYS_E_FLAG register, which will not be equal to 0xA5A5. If | |
1156 | * we not find this variation in the first 4 segments, then the data should | |
1157 | * not be valid. | |
1158 | */ | |
1159 | buffer = adis->buffer; | |
1160 | for (offset = 0; offset < 4; offset++) { | |
1161 | u16 curr = be16_to_cpu(buffer[offset]); | |
1162 | u16 next = be16_to_cpu(buffer[offset + 1]); | |
1163 | ||
1164 | if (curr == ADIS16495_BURST_ID && next != ADIS16495_BURST_ID) { | |
1165 | offset++; | |
1166 | break; | |
1167 | } | |
1168 | } | |
1169 | ||
1170 | if (offset == 4) { | |
1171 | dev_err(&adis->spi->dev, "Invalid burst data\n"); | |
1172 | goto irq_done; | |
1173 | } | |
1174 | ||
1175 | crc = be16_to_cpu(buffer[offset + 16]) << 16 | be16_to_cpu(buffer[offset + 15]); | |
1176 | valid = adis16480_validate_crc((u16 *)&buffer[offset], 15, crc); | |
1177 | if (!valid) { | |
1178 | dev_err(&adis->spi->dev, "Invalid crc\n"); | |
1179 | goto irq_done; | |
1180 | } | |
1181 | ||
1182 | for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { | |
1183 | /* | |
1184 | * When burst mode is used, temperature is the first data | |
1185 | * channel in the sequence, but the temperature scan index | |
1186 | * is 10. | |
1187 | */ | |
1188 | switch (bit) { | |
1189 | case ADIS16480_SCAN_TEMP: | |
1190 | st->data[i++] = buffer[offset + 1]; | |
1191 | break; | |
1192 | case ADIS16480_SCAN_GYRO_X ... ADIS16480_SCAN_ACCEL_Z: | |
1193 | /* The lower register data is sequenced first */ | |
1194 | st->data[i++] = buffer[2 * bit + offset + 3]; | |
1195 | st->data[i++] = buffer[2 * bit + offset + 2]; | |
1196 | break; | |
1197 | } | |
1198 | } | |
1199 | ||
1200 | iio_push_to_buffers_with_timestamp(indio_dev, st->data, pf->timestamp); | |
1201 | irq_done: | |
1202 | iio_trigger_notify_done(indio_dev->trig); | |
1203 | ||
1204 | return IRQ_HANDLED; | |
1205 | } | |
1206 | ||
2f3abe6c | 1207 | static const struct iio_info adis16480_info = { |
2f3abe6c LPC |
1208 | .read_raw = &adis16480_read_raw, |
1209 | .write_raw = &adis16480_write_raw, | |
1210 | .update_scan_mode = adis_update_scan_mode, | |
4c35b7a5 | 1211 | .debugfs_reg_access = adis_debugfs_reg_access, |
2f3abe6c LPC |
1212 | }; |
1213 | ||
1214 | static int adis16480_stop_device(struct iio_dev *indio_dev) | |
1215 | { | |
1216 | struct adis16480 *st = iio_priv(indio_dev); | |
1217 | int ret; | |
1218 | ||
1219 | ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9)); | |
1220 | if (ret) | |
1221 | dev_err(&indio_dev->dev, | |
1222 | "Could not power down device: %d\n", ret); | |
1223 | ||
1224 | return ret; | |
1225 | } | |
1226 | ||
1227 | static int adis16480_enable_irq(struct adis *adis, bool enable) | |
1228 | { | |
cede2f89 SP |
1229 | uint16_t val; |
1230 | int ret; | |
1231 | ||
100bfa38 | 1232 | ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); |
92c7529f | 1233 | if (ret) |
cede2f89 SP |
1234 | return ret; |
1235 | ||
1236 | val &= ~ADIS16480_DRDY_EN_MSK; | |
1237 | val |= ADIS16480_DRDY_EN(enable); | |
1238 | ||
100bfa38 | 1239 | return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); |
2f3abe6c LPC |
1240 | } |
1241 | ||
cede2f89 SP |
1242 | static int adis16480_config_irq_pin(struct device_node *of_node, |
1243 | struct adis16480 *st) | |
1244 | { | |
1245 | struct irq_data *desc; | |
1246 | enum adis16480_int_pin pin; | |
1247 | unsigned int irq_type; | |
1248 | uint16_t val; | |
1249 | int i, irq = 0; | |
1250 | ||
1251 | desc = irq_get_irq_data(st->adis.spi->irq); | |
1252 | if (!desc) { | |
1253 | dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq); | |
1254 | return -EINVAL; | |
1255 | } | |
1256 | ||
1257 | /* Disable data ready since the default after reset is on */ | |
1258 | val = ADIS16480_DRDY_EN(0); | |
1259 | ||
1260 | /* | |
1261 | * Get the interrupt from the devicetre by reading the interrupt-names | |
1262 | * property. If it is not specified, use DIO1 pin as default. | |
1263 | * According to the datasheet, the factory default assigns DIO2 as data | |
1264 | * ready signal. However, in the previous versions of the driver, DIO1 | |
1265 | * pin was used. So, we should leave it as is since some devices might | |
1266 | * be expecting the interrupt on the wrong physical pin. | |
1267 | */ | |
1268 | pin = ADIS16480_PIN_DIO1; | |
1269 | for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { | |
1270 | irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]); | |
1271 | if (irq > 0) { | |
1272 | pin = i; | |
1273 | break; | |
1274 | } | |
1275 | } | |
1276 | ||
1277 | val |= ADIS16480_DRDY_SEL(pin); | |
1278 | ||
1279 | /* | |
1280 | * Get the interrupt line behaviour. The data ready polarity can be | |
1281 | * configured as positive or negative, corresponding to | |
471622c9 | 1282 | * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. |
cede2f89 SP |
1283 | */ |
1284 | irq_type = irqd_get_trigger_type(desc); | |
471622c9 | 1285 | if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ |
cede2f89 | 1286 | val |= ADIS16480_DRDY_POL(1); |
471622c9 | 1287 | } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { |
cede2f89 SP |
1288 | val |= ADIS16480_DRDY_POL(0); |
1289 | } else { | |
1290 | dev_err(&st->adis.spi->dev, | |
1291 | "Invalid interrupt type 0x%x specified\n", irq_type); | |
1292 | return -EINVAL; | |
1293 | } | |
1294 | /* Write the data ready configuration to the FNCTIO_CTRL register */ | |
1295 | return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); | |
1296 | } | |
1297 | ||
326e2357 SP |
1298 | static int adis16480_of_get_ext_clk_pin(struct adis16480 *st, |
1299 | struct device_node *of_node) | |
1300 | { | |
1301 | const char *ext_clk_pin; | |
1302 | enum adis16480_int_pin pin; | |
1303 | int i; | |
1304 | ||
1305 | pin = ADIS16480_PIN_DIO2; | |
1306 | if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin)) | |
1307 | goto clk_input_not_found; | |
1308 | ||
1309 | for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { | |
1310 | if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0) | |
1311 | return i; | |
1312 | } | |
1313 | ||
1314 | clk_input_not_found: | |
1315 | dev_info(&st->adis.spi->dev, | |
1316 | "clk input line not specified, using DIO2\n"); | |
1317 | return pin; | |
1318 | } | |
1319 | ||
1320 | static int adis16480_ext_clk_config(struct adis16480 *st, | |
1321 | struct device_node *of_node, | |
1322 | bool enable) | |
1323 | { | |
1324 | unsigned int mode, mask; | |
1325 | enum adis16480_int_pin pin; | |
1326 | uint16_t val; | |
1327 | int ret; | |
1328 | ||
1329 | ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); | |
92c7529f | 1330 | if (ret) |
326e2357 SP |
1331 | return ret; |
1332 | ||
1333 | pin = adis16480_of_get_ext_clk_pin(st, of_node); | |
1334 | /* | |
1335 | * Each DIOx pin supports only one function at a time. When a single pin | |
1336 | * has two assignments, the enable bit for a lower priority function | |
1337 | * automatically resets to zero (disabling the lower priority function). | |
1338 | */ | |
1339 | if (pin == ADIS16480_DRDY_SEL(val)) | |
1340 | dev_warn(&st->adis.spi->dev, | |
1341 | "DIO%x pin supports only one function at a time\n", | |
1342 | pin + 1); | |
1343 | ||
1344 | mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin); | |
1345 | mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK; | |
1346 | /* Only ADIS1649x devices support pps ext clock mode */ | |
1347 | if (st->chip_info->has_pps_clk_mode) { | |
1348 | mode |= ADIS16480_SYNC_MODE(st->clk_mode); | |
1349 | mask |= ADIS16480_SYNC_MODE_MSK; | |
1350 | } | |
1351 | ||
1352 | val &= ~mask; | |
1353 | val |= mode; | |
1354 | ||
1355 | ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); | |
92c7529f | 1356 | if (ret) |
326e2357 SP |
1357 | return ret; |
1358 | ||
1359 | return clk_prepare_enable(st->ext_clk); | |
1360 | } | |
1361 | ||
1362 | static int adis16480_get_ext_clocks(struct adis16480 *st) | |
1363 | { | |
1364 | st->clk_mode = ADIS16480_CLK_INT; | |
1365 | st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync"); | |
1366 | if (!IS_ERR_OR_NULL(st->ext_clk)) { | |
1367 | st->clk_mode = ADIS16480_CLK_SYNC; | |
1368 | return 0; | |
1369 | } | |
1370 | ||
1371 | if (PTR_ERR(st->ext_clk) != -ENOENT) { | |
1372 | dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); | |
1373 | return PTR_ERR(st->ext_clk); | |
1374 | } | |
1375 | ||
1376 | if (st->chip_info->has_pps_clk_mode) { | |
1377 | st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps"); | |
1378 | if (!IS_ERR_OR_NULL(st->ext_clk)) { | |
1379 | st->clk_mode = ADIS16480_CLK_PPS; | |
1380 | return 0; | |
1381 | } | |
1382 | ||
1383 | if (PTR_ERR(st->ext_clk) != -ENOENT) { | |
1384 | dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); | |
1385 | return PTR_ERR(st->ext_clk); | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | return 0; | |
1390 | } | |
1391 | ||
514f641b NS |
1392 | static void adis16480_stop(void *data) |
1393 | { | |
1394 | adis16480_stop_device(data); | |
1395 | } | |
1396 | ||
1397 | static void adis16480_clk_disable(void *data) | |
1398 | { | |
1399 | clk_disable_unprepare(data); | |
1400 | } | |
1401 | ||
2f3abe6c LPC |
1402 | static int adis16480_probe(struct spi_device *spi) |
1403 | { | |
1404 | const struct spi_device_id *id = spi_get_device_id(spi); | |
380b107b | 1405 | const struct adis_data *adis16480_data; |
2f3abe6c LPC |
1406 | struct iio_dev *indio_dev; |
1407 | struct adis16480 *st; | |
1408 | int ret; | |
1409 | ||
297c8876 | 1410 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
2f3abe6c LPC |
1411 | if (indio_dev == NULL) |
1412 | return -ENOMEM; | |
1413 | ||
2f3abe6c LPC |
1414 | st = iio_priv(indio_dev); |
1415 | ||
1416 | st->chip_info = &adis16480_chip_info[id->driver_data]; | |
2f3abe6c LPC |
1417 | indio_dev->name = spi_get_device_id(spi)->name; |
1418 | indio_dev->channels = st->chip_info->channels; | |
1419 | indio_dev->num_channels = st->chip_info->num_channels; | |
1420 | indio_dev->info = &adis16480_info; | |
1421 | indio_dev->modes = INDIO_DIRECT_MODE; | |
1422 | ||
97928677 | 1423 | adis16480_data = &st->chip_info->adis_data; |
380b107b NS |
1424 | |
1425 | ret = adis_init(&st->adis, indio_dev, spi, adis16480_data); | |
2f3abe6c | 1426 | if (ret) |
297c8876 | 1427 | return ret; |
2f3abe6c | 1428 | |
366a5434 | 1429 | ret = __adis_initial_startup(&st->adis); |
cede2f89 SP |
1430 | if (ret) |
1431 | return ret; | |
1432 | ||
ea1945c2 NS |
1433 | if (st->chip_info->has_sleep_cnt) { |
1434 | ret = devm_add_action_or_reset(&spi->dev, adis16480_stop, | |
1435 | indio_dev); | |
1436 | if (ret) | |
1437 | return ret; | |
1438 | } | |
514f641b | 1439 | |
366a5434 NS |
1440 | ret = adis16480_config_irq_pin(spi->dev.of_node, st); |
1441 | if (ret) | |
514f641b | 1442 | return ret; |
366a5434 | 1443 | |
326e2357 | 1444 | ret = adis16480_get_ext_clocks(st); |
2f3abe6c | 1445 | if (ret) |
514f641b | 1446 | return ret; |
2f3abe6c | 1447 | |
326e2357 SP |
1448 | if (!IS_ERR_OR_NULL(st->ext_clk)) { |
1449 | ret = adis16480_ext_clk_config(st, spi->dev.of_node, true); | |
1450 | if (ret) | |
514f641b NS |
1451 | return ret; |
1452 | ||
1453 | ret = devm_add_action_or_reset(&spi->dev, adis16480_clk_disable, st->ext_clk); | |
1454 | if (ret) | |
1455 | return ret; | |
326e2357 SP |
1456 | |
1457 | st->clk_freq = clk_get_rate(st->ext_clk); | |
1458 | st->clk_freq *= 1000; /* micro */ | |
0463e60f NS |
1459 | if (st->clk_mode == ADIS16480_CLK_PPS) { |
1460 | u16 sync_scale; | |
1461 | ||
1462 | /* | |
1463 | * In PPS mode, the IMU sample rate is the clk_freq * sync_scale. Hence, | |
1464 | * default the IMU sample rate to the highest multiple of the input clock | |
1465 | * lower than the IMU max sample rate. The internal sample rate is the | |
1466 | * max... | |
1467 | */ | |
1468 | sync_scale = st->chip_info->int_clk / st->clk_freq; | |
1469 | ret = __adis_write_reg_16(&st->adis, ADIS16495_REG_SYNC_SCALE, sync_scale); | |
1470 | if (ret) | |
1471 | return ret; | |
1472 | } | |
326e2357 SP |
1473 | } else { |
1474 | st->clk_freq = st->chip_info->int_clk; | |
1475 | } | |
1476 | ||
941f1308 NS |
1477 | ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, |
1478 | adis16480_trigger_handler); | |
326e2357 | 1479 | if (ret) |
514f641b | 1480 | return ret; |
326e2357 | 1481 | |
514f641b | 1482 | ret = devm_iio_device_register(&spi->dev, indio_dev); |
2f3abe6c | 1483 | if (ret) |
514f641b | 1484 | return ret; |
2f3abe6c LPC |
1485 | |
1486 | adis16480_debugfs_init(indio_dev); | |
1487 | ||
2f3abe6c LPC |
1488 | return 0; |
1489 | } | |
1490 | ||
1491 | static const struct spi_device_id adis16480_ids[] = { | |
1492 | { "adis16375", ADIS16375 }, | |
1493 | { "adis16480", ADIS16480 }, | |
1494 | { "adis16485", ADIS16485 }, | |
1495 | { "adis16488", ADIS16488 }, | |
80cbc848 | 1496 | { "adis16490", ADIS16490 }, |
82e7a1b2 SP |
1497 | { "adis16495-1", ADIS16495_1 }, |
1498 | { "adis16495-2", ADIS16495_2 }, | |
1499 | { "adis16495-3", ADIS16495_3 }, | |
1500 | { "adis16497-1", ADIS16497_1 }, | |
1501 | { "adis16497-2", ADIS16497_2 }, | |
1502 | { "adis16497-3", ADIS16497_3 }, | |
2f3abe6c LPC |
1503 | { } |
1504 | }; | |
1505 | MODULE_DEVICE_TABLE(spi, adis16480_ids); | |
1506 | ||
304840c4 SP |
1507 | static const struct of_device_id adis16480_of_match[] = { |
1508 | { .compatible = "adi,adis16375" }, | |
1509 | { .compatible = "adi,adis16480" }, | |
1510 | { .compatible = "adi,adis16485" }, | |
1511 | { .compatible = "adi,adis16488" }, | |
80cbc848 | 1512 | { .compatible = "adi,adis16490" }, |
82e7a1b2 SP |
1513 | { .compatible = "adi,adis16495-1" }, |
1514 | { .compatible = "adi,adis16495-2" }, | |
1515 | { .compatible = "adi,adis16495-3" }, | |
1516 | { .compatible = "adi,adis16497-1" }, | |
1517 | { .compatible = "adi,adis16497-2" }, | |
1518 | { .compatible = "adi,adis16497-3" }, | |
304840c4 SP |
1519 | { }, |
1520 | }; | |
1521 | MODULE_DEVICE_TABLE(of, adis16480_of_match); | |
1522 | ||
2f3abe6c LPC |
1523 | static struct spi_driver adis16480_driver = { |
1524 | .driver = { | |
1525 | .name = "adis16480", | |
304840c4 | 1526 | .of_match_table = adis16480_of_match, |
2f3abe6c LPC |
1527 | }, |
1528 | .id_table = adis16480_ids, | |
1529 | .probe = adis16480_probe, | |
2f3abe6c LPC |
1530 | }; |
1531 | module_spi_driver(adis16480_driver); | |
1532 | ||
1533 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | |
1534 | MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver"); | |
1535 | MODULE_LICENSE("GPL v2"); |