1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver |
4 | * |
5 | * Copyright 2010 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/device.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/spi/spi.h> |
11 | #include <linux/module.h> |
12 | |
13 | #include <linux/iio/iio.h> |
14 | #include <linux/iio/imu/adis.h> |
15 | |
16 | #define ADIS16260_STARTUP_DELAY 220 /* ms */ |
17 | |
18 | #define ADIS16260_FLASH_CNT 0x00 /* Flash memory write count */ |
19 | #define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */ |
20 | #define ADIS16260_GYRO_OUT 0x04 /* X-axis gyroscope output */ |
21 | #define ADIS16260_AUX_ADC 0x0A /* analog input channel measurement */ |
22 | #define ADIS16260_TEMP_OUT 0x0C /* internal temperature measurement */ |
23 | #define ADIS16260_ANGL_OUT 0x0E /* angle displacement */ |
24 | #define ADIS16260_GYRO_OFF 0x14 /* Calibration, offset/bias adjustment */ |
25 | #define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */ |
26 | #define ADIS16260_ALM_MAG1 0x20 /* Alarm 1 magnitude/polarity setting */ |
27 | #define ADIS16260_ALM_MAG2 0x22 /* Alarm 2 magnitude/polarity setting */ |
28 | #define ADIS16260_ALM_SMPL1 0x24 /* Alarm 1 dynamic rate of change setting */ |
29 | #define ADIS16260_ALM_SMPL2 0x26 /* Alarm 2 dynamic rate of change setting */ |
30 | #define ADIS16260_ALM_CTRL 0x28 /* Alarm control */ |
31 | #define ADIS16260_AUX_DAC 0x30 /* Auxiliary DAC data */ |
32 | #define ADIS16260_GPIO_CTRL 0x32 /* Control, digital I/O line */ |
33 | #define ADIS16260_MSC_CTRL 0x34 /* Control, data ready, self-test settings */ |
34 | #define ADIS16260_SMPL_PRD 0x36 /* Control, internal sample rate */ |
35 | #define ADIS16260_SENS_AVG 0x38 /* Control, dynamic range, filtering */ |
36 | #define ADIS16260_SLP_CNT 0x3A /* Control, sleep mode initiation */ |
37 | #define ADIS16260_DIAG_STAT 0x3C /* Diagnostic, error flags */ |
38 | #define ADIS16260_GLOB_CMD 0x3E /* Control, global commands */ |
39 | #define ADIS16260_LOT_ID1 0x52 /* Lot Identification Code 1 */ |
40 | #define ADIS16260_LOT_ID2 0x54 /* Lot Identification Code 2 */ |
41 | #define ADIS16260_PROD_ID 0x56 /* Product identifier; |
42 | * convert to decimal = 16,265/16,260 */ |
43 | #define ADIS16260_SERIAL_NUM 0x58 /* Serial number */ |
44 | |
45 | #define ADIS16260_ERROR_ACTIVE (1<<14) |
46 | #define ADIS16260_NEW_DATA (1<<15) |
47 | |
48 | /* MSC_CTRL */ |
49 | #define ADIS16260_MSC_CTRL_MEM_TEST (1<<11) |
50 | /* Internal self-test enable */ |
51 | #define ADIS16260_MSC_CTRL_INT_SELF_TEST (1<<10) |
52 | #define ADIS16260_MSC_CTRL_NEG_SELF_TEST (1<<9) |
53 | #define ADIS16260_MSC_CTRL_POS_SELF_TEST (1<<8) |
54 | #define ADIS16260_MSC_CTRL_DATA_RDY_EN (1<<2) |
55 | #define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1) |
56 | #define ADIS16260_MSC_CTRL_DATA_RDY_DIO2 (1<<0) |
57 | |
58 | /* SMPL_PRD */ |
59 | /* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */ |
60 | #define ADIS16260_SMPL_PRD_TIME_BASE (1<<7) |
61 | #define ADIS16260_SMPL_PRD_DIV_MASK 0x7F |
62 | |
63 | /* SLP_CNT */ |
64 | #define ADIS16260_SLP_CNT_POWER_OFF 0x80 |
65 | |
66 | /* DIAG_STAT */ |
67 | #define ADIS16260_DIAG_STAT_ALARM2 (1<<9) |
68 | #define ADIS16260_DIAG_STAT_ALARM1 (1<<8) |
69 | #define ADIS16260_DIAG_STAT_FLASH_CHK_BIT 6 |
70 | #define ADIS16260_DIAG_STAT_SELF_TEST_BIT 5 |
71 | #define ADIS16260_DIAG_STAT_OVERFLOW_BIT 4 |
72 | #define ADIS16260_DIAG_STAT_SPI_FAIL_BIT 3 |
73 | #define ADIS16260_DIAG_STAT_FLASH_UPT_BIT 2 |
74 | #define ADIS16260_DIAG_STAT_POWER_HIGH_BIT 1 |
75 | #define ADIS16260_DIAG_STAT_POWER_LOW_BIT 0 |
76 | |
77 | /* GLOB_CMD */ |
78 | #define ADIS16260_GLOB_CMD_SW_RESET (1<<7) |
79 | #define ADIS16260_GLOB_CMD_FLASH_UPD (1<<3) |
80 | #define ADIS16260_GLOB_CMD_DAC_LATCH (1<<2) |
81 | #define ADIS16260_GLOB_CMD_FAC_CALIB (1<<1) |
82 | #define ADIS16260_GLOB_CMD_AUTO_NULL (1<<0) |
83 | |
84 | #define ADIS16260_SPI_SLOW (u32)(300 * 1000) |
85 | #define ADIS16260_SPI_BURST (u32)(1000 * 1000) |
86 | #define ADIS16260_SPI_FAST (u32)(2000 * 1000) |
87 | |
88 | /* At the moment triggers are only used for ring buffer |
89 | * filling. This may change! |
90 | */ |
91 | |
92 | #define ADIS16260_SCAN_GYRO 0 |
93 | #define ADIS16260_SCAN_SUPPLY 1 |
94 | #define ADIS16260_SCAN_AUX_ADC 2 |
95 | #define ADIS16260_SCAN_TEMP 3 |
96 | #define ADIS16260_SCAN_ANGL 4 |
97 | |
98 | struct adis16260_chip_info { |
99 | unsigned int gyro_max_val; |
100 | unsigned int gyro_max_scale; |
101 | const struct iio_chan_spec *channels; |
102 | unsigned int num_channels; |
103 | }; |
104 | |
105 | struct adis16260 { |
106 | const struct adis16260_chip_info *info; |
107 | |
108 | struct adis adis; |
109 | }; |
110 | |
111 | enum adis16260_type { |
112 | ADIS16251, |
113 | ADIS16260, |
114 | ADIS16266, |
115 | }; |
116 | |
117 | static const struct iio_chan_spec adis16260_channels[] = { |
118 | ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, |
119 | BIT(IIO_CHAN_INFO_CALIBBIAS) | |
120 | BIT(IIO_CHAN_INFO_CALIBSCALE), |
121 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), |
122 | ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, |
123 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), |
124 | ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, |
125 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
126 | ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, |
127 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
128 | ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, |
129 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
130 | IIO_CHAN_SOFT_TIMESTAMP(5), |
131 | }; |
132 | |
133 | static const struct iio_chan_spec adis16266_channels[] = { |
134 | ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, |
135 | BIT(IIO_CHAN_INFO_CALIBBIAS) | |
136 | BIT(IIO_CHAN_INFO_CALIBSCALE), |
137 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), |
138 | ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, |
139 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
140 | ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, |
141 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
142 | ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, |
143 | BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), |
144 | IIO_CHAN_SOFT_TIMESTAMP(4), |
145 | }; |
146 | |
147 | static const struct adis16260_chip_info adis16260_chip_info_table[] = { |
148 | [ADIS16251] = { |
149 | .gyro_max_scale = 80, |
150 | .gyro_max_val = IIO_RAD_TO_DEGREE(4368), |
151 | .channels = adis16260_channels, |
152 | .num_channels = ARRAY_SIZE(adis16260_channels), |
153 | }, |
154 | [ADIS16260] = { |
155 | .gyro_max_scale = 320, |
156 | .gyro_max_val = IIO_RAD_TO_DEGREE(4368), |
157 | .channels = adis16260_channels, |
158 | .num_channels = ARRAY_SIZE(adis16260_channels), |
159 | }, |
160 | [ADIS16266] = { |
161 | .gyro_max_scale = 14000, |
162 | .gyro_max_val = IIO_RAD_TO_DEGREE(3357), |
163 | .channels = adis16266_channels, |
164 | .num_channels = ARRAY_SIZE(adis16266_channels), |
165 | }, |
166 | }; |
167 | |
168 | /* Power down the device */ |
169 | static int adis16260_stop_device(struct iio_dev *indio_dev) |
170 | { |
171 | struct adis16260 *adis16260 = iio_priv(indio_dev); |
172 | int ret; |
173 | u16 val = ADIS16260_SLP_CNT_POWER_OFF; |
174 | |
175 | ret = adis_write_reg_16(adis: &adis16260->adis, ADIS16260_SLP_CNT, val); |
176 | if (ret) |
177 | dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT" ); |
178 | |
179 | return ret; |
180 | } |
181 | |
182 | static const u8 adis16260_addresses[][2] = { |
183 | [ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE }, |
184 | }; |
185 | |
186 | static int adis16260_read_raw(struct iio_dev *indio_dev, |
187 | struct iio_chan_spec const *chan, |
188 | int *val, int *val2, |
189 | long mask) |
190 | { |
191 | struct adis16260 *adis16260 = iio_priv(indio_dev); |
192 | const struct adis16260_chip_info *info = adis16260->info; |
193 | struct adis *adis = &adis16260->adis; |
194 | int ret; |
195 | u8 addr; |
196 | s16 val16; |
197 | |
198 | switch (mask) { |
199 | case IIO_CHAN_INFO_RAW: |
200 | return adis_single_conversion(indio_dev, chan, |
201 | ADIS16260_ERROR_ACTIVE, val); |
202 | case IIO_CHAN_INFO_SCALE: |
203 | switch (chan->type) { |
204 | case IIO_ANGL_VEL: |
205 | *val = info->gyro_max_scale; |
206 | *val2 = info->gyro_max_val; |
207 | return IIO_VAL_FRACTIONAL; |
208 | case IIO_INCLI: |
209 | *val = 0; |
210 | *val2 = IIO_DEGREE_TO_RAD(36630); |
211 | return IIO_VAL_INT_PLUS_MICRO; |
212 | case IIO_VOLTAGE: |
213 | if (chan->channel == 0) { |
214 | *val = 1; |
215 | *val2 = 831500; /* 1.8315 mV */ |
216 | } else { |
217 | *val = 0; |
218 | *val2 = 610500; /* 610.5 uV */ |
219 | } |
220 | return IIO_VAL_INT_PLUS_MICRO; |
221 | case IIO_TEMP: |
222 | *val = 145; |
223 | *val2 = 300000; /* 0.1453 C */ |
224 | return IIO_VAL_INT_PLUS_MICRO; |
225 | default: |
226 | return -EINVAL; |
227 | } |
228 | case IIO_CHAN_INFO_OFFSET: |
229 | *val = 250000 / 1453; /* 25 C = 0x00 */ |
230 | return IIO_VAL_INT; |
231 | case IIO_CHAN_INFO_CALIBBIAS: |
232 | addr = adis16260_addresses[chan->scan_index][0]; |
233 | ret = adis_read_reg_16(adis, reg: addr, val: &val16); |
234 | if (ret) |
235 | return ret; |
236 | |
237 | *val = sign_extend32(value: val16, index: 11); |
238 | return IIO_VAL_INT; |
239 | case IIO_CHAN_INFO_CALIBSCALE: |
240 | addr = adis16260_addresses[chan->scan_index][1]; |
241 | ret = adis_read_reg_16(adis, reg: addr, val: &val16); |
242 | if (ret) |
243 | return ret; |
244 | |
245 | *val = val16; |
246 | return IIO_VAL_INT; |
247 | case IIO_CHAN_INFO_SAMP_FREQ: |
248 | ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, val: &val16); |
249 | if (ret) |
250 | return ret; |
251 | |
252 | if (spi_get_device_id(sdev: adis->spi)->driver_data) |
253 | /* If an adis16251 */ |
254 | *val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ? |
255 | 8 : 256; |
256 | else |
257 | *val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ? |
258 | 66 : 2048; |
259 | *val /= (val16 & ADIS16260_SMPL_PRD_DIV_MASK) + 1; |
260 | return IIO_VAL_INT; |
261 | } |
262 | return -EINVAL; |
263 | } |
264 | |
265 | static int adis16260_write_raw(struct iio_dev *indio_dev, |
266 | struct iio_chan_spec const *chan, |
267 | int val, |
268 | int val2, |
269 | long mask) |
270 | { |
271 | struct adis16260 *adis16260 = iio_priv(indio_dev); |
272 | struct adis *adis = &adis16260->adis; |
273 | int ret; |
274 | u8 addr; |
275 | u8 t; |
276 | |
277 | switch (mask) { |
278 | case IIO_CHAN_INFO_CALIBBIAS: |
279 | if (val < -2048 || val >= 2048) |
280 | return -EINVAL; |
281 | |
282 | addr = adis16260_addresses[chan->scan_index][0]; |
283 | return adis_write_reg_16(adis, reg: addr, val); |
284 | case IIO_CHAN_INFO_CALIBSCALE: |
285 | if (val < 0 || val >= 4096) |
286 | return -EINVAL; |
287 | |
288 | addr = adis16260_addresses[chan->scan_index][1]; |
289 | return adis_write_reg_16(adis, reg: addr, val); |
290 | case IIO_CHAN_INFO_SAMP_FREQ: |
291 | adis_dev_lock(adis); |
292 | if (spi_get_device_id(sdev: adis->spi)->driver_data) |
293 | t = 256 / val; |
294 | else |
295 | t = 2048 / val; |
296 | |
297 | if (t > ADIS16260_SMPL_PRD_DIV_MASK) |
298 | t = ADIS16260_SMPL_PRD_DIV_MASK; |
299 | else if (t > 0) |
300 | t--; |
301 | |
302 | if (t >= 0x0A) |
303 | adis->spi->max_speed_hz = ADIS16260_SPI_SLOW; |
304 | else |
305 | adis->spi->max_speed_hz = ADIS16260_SPI_FAST; |
306 | ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, val: t); |
307 | |
308 | adis_dev_unlock(adis); |
309 | return ret; |
310 | } |
311 | return -EINVAL; |
312 | } |
313 | |
314 | static const struct iio_info adis16260_info = { |
315 | .read_raw = &adis16260_read_raw, |
316 | .write_raw = &adis16260_write_raw, |
317 | .update_scan_mode = adis_update_scan_mode, |
318 | }; |
319 | |
320 | static const char * const adis1620_status_error_msgs[] = { |
321 | [ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error" , |
322 | [ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error" , |
323 | [ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange" , |
324 | [ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure" , |
325 | [ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed" , |
326 | [ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25" , |
327 | [ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75" , |
328 | }; |
329 | |
330 | static const struct adis_timeout adis16260_timeouts = { |
331 | .reset_ms = ADIS16260_STARTUP_DELAY, |
332 | .sw_reset_ms = ADIS16260_STARTUP_DELAY, |
333 | .self_test_ms = ADIS16260_STARTUP_DELAY, |
334 | }; |
335 | |
336 | static const struct adis_data adis16260_data = { |
337 | .write_delay = 30, |
338 | .read_delay = 30, |
339 | .msc_ctrl_reg = ADIS16260_MSC_CTRL, |
340 | .glob_cmd_reg = ADIS16260_GLOB_CMD, |
341 | .diag_stat_reg = ADIS16260_DIAG_STAT, |
342 | |
343 | .self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST, |
344 | .self_test_reg = ADIS16260_MSC_CTRL, |
345 | .timeouts = &adis16260_timeouts, |
346 | |
347 | .status_error_msgs = adis1620_status_error_msgs, |
348 | .status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) | |
349 | BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) | |
350 | BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) | |
351 | BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) | |
352 | BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) | |
353 | BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) | |
354 | BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT), |
355 | }; |
356 | |
357 | static void adis16260_stop(void *data) |
358 | { |
359 | adis16260_stop_device(indio_dev: data); |
360 | } |
361 | |
362 | static int adis16260_probe(struct spi_device *spi) |
363 | { |
364 | const struct spi_device_id *id; |
365 | struct adis16260 *adis16260; |
366 | struct iio_dev *indio_dev; |
367 | int ret; |
368 | |
369 | id = spi_get_device_id(sdev: spi); |
370 | if (!id) |
371 | return -ENODEV; |
372 | |
373 | /* setup the industrialio driver allocated elements */ |
374 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*adis16260)); |
375 | if (!indio_dev) |
376 | return -ENOMEM; |
377 | adis16260 = iio_priv(indio_dev); |
378 | /* this is only used for removal purposes */ |
379 | spi_set_drvdata(spi, data: indio_dev); |
380 | |
381 | adis16260->info = &adis16260_chip_info_table[id->driver_data]; |
382 | |
383 | indio_dev->name = id->name; |
384 | indio_dev->info = &adis16260_info; |
385 | indio_dev->channels = adis16260->info->channels; |
386 | indio_dev->num_channels = adis16260->info->num_channels; |
387 | indio_dev->modes = INDIO_DIRECT_MODE; |
388 | |
389 | ret = adis_init(adis: &adis16260->adis, indio_dev, spi, data: &adis16260_data); |
390 | if (ret) |
391 | return ret; |
392 | |
393 | ret = devm_adis_setup_buffer_and_trigger(adis: &adis16260->adis, indio_dev, NULL); |
394 | if (ret) |
395 | return ret; |
396 | |
397 | /* Get the device into a sane initial state */ |
398 | ret = __adis_initial_startup(adis: &adis16260->adis); |
399 | if (ret) |
400 | return ret; |
401 | |
402 | ret = devm_add_action_or_reset(&spi->dev, adis16260_stop, indio_dev); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | return devm_iio_device_register(&spi->dev, indio_dev); |
407 | } |
408 | |
409 | /* |
410 | * These parts do not need to be differentiated until someone adds |
411 | * support for the on chip filtering. |
412 | */ |
413 | static const struct spi_device_id adis16260_id[] = { |
414 | {"adis16260" , ADIS16260}, |
415 | {"adis16265" , ADIS16260}, |
416 | {"adis16266" , ADIS16266}, |
417 | {"adis16250" , ADIS16260}, |
418 | {"adis16255" , ADIS16260}, |
419 | {"adis16251" , ADIS16251}, |
420 | {} |
421 | }; |
422 | MODULE_DEVICE_TABLE(spi, adis16260_id); |
423 | |
424 | static struct spi_driver adis16260_driver = { |
425 | .driver = { |
426 | .name = "adis16260" , |
427 | }, |
428 | .probe = adis16260_probe, |
429 | .id_table = adis16260_id, |
430 | }; |
431 | module_spi_driver(adis16260_driver); |
432 | |
433 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>" ); |
434 | MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor" ); |
435 | MODULE_LICENSE("GPL v2" ); |
436 | MODULE_IMPORT_NS(IIO_ADISLIB); |
437 | |