| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ADIS16480 and similar IMUs driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2012 Analog Devices Inc. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 8 | +#include <linux/clk.h> |
|---|
| 9 | +#include <linux/bitfield.h> |
|---|
| 10 | +#include <linux/of_irq.h> |
|---|
| 12 | 11 | #include <linux/interrupt.h> |
|---|
| 13 | 12 | #include <linux/delay.h> |
|---|
| 14 | 13 | #include <linux/mutex.h> |
|---|
| .. | .. |
|---|
| 97 | 96 | #define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A) |
|---|
| 98 | 97 | #define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C) |
|---|
| 99 | 98 | |
|---|
| 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) |
|---|
| 104 | + |
|---|
| 100 | 105 | #define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20) |
|---|
| 101 | 106 | |
|---|
| 102 | 107 | /* Each filter coefficent bank spans two pages */ |
|---|
| .. | .. |
|---|
| 107 | 112 | #define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x)) |
|---|
| 108 | 113 | #define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x)) |
|---|
| 109 | 114 | |
|---|
| 115 | +/* ADIS16480_REG_FNCTIO_CTRL */ |
|---|
| 116 | +#define ADIS16480_DRDY_SEL_MSK GENMASK(1, 0) |
|---|
| 117 | +#define ADIS16480_DRDY_SEL(x) FIELD_PREP(ADIS16480_DRDY_SEL_MSK, x) |
|---|
| 118 | +#define ADIS16480_DRDY_POL_MSK BIT(2) |
|---|
| 119 | +#define ADIS16480_DRDY_POL(x) FIELD_PREP(ADIS16480_DRDY_POL_MSK, x) |
|---|
| 120 | +#define ADIS16480_DRDY_EN_MSK BIT(3) |
|---|
| 121 | +#define ADIS16480_DRDY_EN(x) FIELD_PREP(ADIS16480_DRDY_EN_MSK, x) |
|---|
| 122 | +#define ADIS16480_SYNC_SEL_MSK GENMASK(5, 4) |
|---|
| 123 | +#define ADIS16480_SYNC_SEL(x) FIELD_PREP(ADIS16480_SYNC_SEL_MSK, x) |
|---|
| 124 | +#define ADIS16480_SYNC_EN_MSK BIT(7) |
|---|
| 125 | +#define ADIS16480_SYNC_EN(x) FIELD_PREP(ADIS16480_SYNC_EN_MSK, x) |
|---|
| 126 | +#define ADIS16480_SYNC_MODE_MSK BIT(8) |
|---|
| 127 | +#define ADIS16480_SYNC_MODE(x) FIELD_PREP(ADIS16480_SYNC_MODE_MSK, x) |
|---|
| 128 | + |
|---|
| 110 | 129 | struct adis16480_chip_info { |
|---|
| 111 | 130 | unsigned int num_channels; |
|---|
| 112 | 131 | const struct iio_chan_spec *channels; |
|---|
| .. | .. |
|---|
| 114 | 133 | unsigned int gyro_max_scale; |
|---|
| 115 | 134 | unsigned int accel_max_val; |
|---|
| 116 | 135 | unsigned int accel_max_scale; |
|---|
| 136 | + unsigned int temp_scale; |
|---|
| 137 | + unsigned int int_clk; |
|---|
| 138 | + unsigned int max_dec_rate; |
|---|
| 139 | + const unsigned int *filter_freqs; |
|---|
| 140 | + bool has_pps_clk_mode; |
|---|
| 141 | + const struct adis_data adis_data; |
|---|
| 142 | +}; |
|---|
| 143 | + |
|---|
| 144 | +enum adis16480_int_pin { |
|---|
| 145 | + ADIS16480_PIN_DIO1, |
|---|
| 146 | + ADIS16480_PIN_DIO2, |
|---|
| 147 | + ADIS16480_PIN_DIO3, |
|---|
| 148 | + ADIS16480_PIN_DIO4 |
|---|
| 149 | +}; |
|---|
| 150 | + |
|---|
| 151 | +enum adis16480_clock_mode { |
|---|
| 152 | + ADIS16480_CLK_SYNC, |
|---|
| 153 | + ADIS16480_CLK_PPS, |
|---|
| 154 | + ADIS16480_CLK_INT |
|---|
| 117 | 155 | }; |
|---|
| 118 | 156 | |
|---|
| 119 | 157 | struct adis16480 { |
|---|
| 120 | 158 | const struct adis16480_chip_info *chip_info; |
|---|
| 121 | 159 | |
|---|
| 122 | 160 | struct adis adis; |
|---|
| 161 | + struct clk *ext_clk; |
|---|
| 162 | + enum adis16480_clock_mode clk_mode; |
|---|
| 163 | + unsigned int clk_freq; |
|---|
| 164 | +}; |
|---|
| 165 | + |
|---|
| 166 | +static const char * const adis16480_int_pin_names[4] = { |
|---|
| 167 | + [ADIS16480_PIN_DIO1] = "DIO1", |
|---|
| 168 | + [ADIS16480_PIN_DIO2] = "DIO2", |
|---|
| 169 | + [ADIS16480_PIN_DIO3] = "DIO3", |
|---|
| 170 | + [ADIS16480_PIN_DIO4] = "DIO4", |
|---|
| 123 | 171 | }; |
|---|
| 124 | 172 | |
|---|
| 125 | 173 | #ifdef CONFIG_DEBUG_FS |
|---|
| .. | .. |
|---|
| 134 | 182 | int ret; |
|---|
| 135 | 183 | |
|---|
| 136 | 184 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev); |
|---|
| 137 | | - if (ret < 0) |
|---|
| 185 | + if (ret) |
|---|
| 138 | 186 | return ret; |
|---|
| 139 | 187 | |
|---|
| 140 | 188 | len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff); |
|---|
| .. | .. |
|---|
| 159 | 207 | int ret; |
|---|
| 160 | 208 | |
|---|
| 161 | 209 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year); |
|---|
| 162 | | - if (ret < 0) |
|---|
| 210 | + if (ret) |
|---|
| 163 | 211 | return ret; |
|---|
| 164 | 212 | |
|---|
| 165 | 213 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md); |
|---|
| 166 | | - if (ret < 0) |
|---|
| 214 | + if (ret) |
|---|
| 167 | 215 | return ret; |
|---|
| 168 | 216 | |
|---|
| 169 | 217 | len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n", |
|---|
| .. | .. |
|---|
| 187 | 235 | |
|---|
| 188 | 236 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM, |
|---|
| 189 | 237 | &serial); |
|---|
| 190 | | - if (ret < 0) |
|---|
| 238 | + if (ret) |
|---|
| 191 | 239 | return ret; |
|---|
| 192 | 240 | |
|---|
| 193 | 241 | *val = serial; |
|---|
| .. | .. |
|---|
| 205 | 253 | |
|---|
| 206 | 254 | ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID, |
|---|
| 207 | 255 | &prod_id); |
|---|
| 208 | | - if (ret < 0) |
|---|
| 256 | + if (ret) |
|---|
| 209 | 257 | return ret; |
|---|
| 210 | 258 | |
|---|
| 211 | 259 | *val = prod_id; |
|---|
| .. | .. |
|---|
| 223 | 271 | |
|---|
| 224 | 272 | ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT, |
|---|
| 225 | 273 | &flash_count); |
|---|
| 226 | | - if (ret < 0) |
|---|
| 274 | + if (ret) |
|---|
| 227 | 275 | return ret; |
|---|
| 228 | 276 | |
|---|
| 229 | 277 | *val = flash_count; |
|---|
| .. | .. |
|---|
| 236 | 284 | static int adis16480_debugfs_init(struct iio_dev *indio_dev) |
|---|
| 237 | 285 | { |
|---|
| 238 | 286 | struct adis16480 *adis16480 = iio_priv(indio_dev); |
|---|
| 287 | + struct dentry *d = iio_get_debugfs_dentry(indio_dev); |
|---|
| 239 | 288 | |
|---|
| 240 | 289 | debugfs_create_file_unsafe("firmware_revision", 0400, |
|---|
| 241 | | - indio_dev->debugfs_dentry, adis16480, |
|---|
| 242 | | - &adis16480_firmware_revision_fops); |
|---|
| 290 | + d, adis16480, &adis16480_firmware_revision_fops); |
|---|
| 243 | 291 | debugfs_create_file_unsafe("firmware_date", 0400, |
|---|
| 244 | | - indio_dev->debugfs_dentry, adis16480, |
|---|
| 245 | | - &adis16480_firmware_date_fops); |
|---|
| 292 | + d, adis16480, &adis16480_firmware_date_fops); |
|---|
| 246 | 293 | debugfs_create_file_unsafe("serial_number", 0400, |
|---|
| 247 | | - indio_dev->debugfs_dentry, adis16480, |
|---|
| 248 | | - &adis16480_serial_number_fops); |
|---|
| 294 | + d, adis16480, &adis16480_serial_number_fops); |
|---|
| 249 | 295 | debugfs_create_file_unsafe("product_id", 0400, |
|---|
| 250 | | - indio_dev->debugfs_dentry, adis16480, |
|---|
| 251 | | - &adis16480_product_id_fops); |
|---|
| 296 | + d, adis16480, &adis16480_product_id_fops); |
|---|
| 252 | 297 | debugfs_create_file_unsafe("flash_count", 0400, |
|---|
| 253 | | - indio_dev->debugfs_dentry, adis16480, |
|---|
| 254 | | - &adis16480_flash_count_fops); |
|---|
| 298 | + d, adis16480, &adis16480_flash_count_fops); |
|---|
| 255 | 299 | |
|---|
| 256 | 300 | return 0; |
|---|
| 257 | 301 | } |
|---|
| .. | .. |
|---|
| 268 | 312 | static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2) |
|---|
| 269 | 313 | { |
|---|
| 270 | 314 | struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 271 | | - unsigned int t; |
|---|
| 315 | + unsigned int t, reg; |
|---|
| 272 | 316 | |
|---|
| 273 | 317 | if (val < 0 || val2 < 0) |
|---|
| 274 | 318 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 277 | 321 | if (t == 0) |
|---|
| 278 | 322 | return -EINVAL; |
|---|
| 279 | 323 | |
|---|
| 280 | | - t = 2460000 / t; |
|---|
| 281 | | - if (t > 2048) |
|---|
| 282 | | - t = 2048; |
|---|
| 324 | + /* |
|---|
| 325 | + * When using PPS mode, the rate of data collection is equal to the |
|---|
| 326 | + * product of the external clock frequency and the scale factor in the |
|---|
| 327 | + * SYNC_SCALE register. |
|---|
| 328 | + * When using sync mode, or internal clock, the output data rate is |
|---|
| 329 | + * equal with the clock frequency divided by DEC_RATE + 1. |
|---|
| 330 | + */ |
|---|
| 331 | + if (st->clk_mode == ADIS16480_CLK_PPS) { |
|---|
| 332 | + t = t / st->clk_freq; |
|---|
| 333 | + reg = ADIS16495_REG_SYNC_SCALE; |
|---|
| 334 | + } else { |
|---|
| 335 | + t = st->clk_freq / t; |
|---|
| 336 | + reg = ADIS16480_REG_DEC_RATE; |
|---|
| 337 | + } |
|---|
| 283 | 338 | |
|---|
| 284 | | - if (t != 0) |
|---|
| 339 | + if (t > st->chip_info->max_dec_rate) |
|---|
| 340 | + t = st->chip_info->max_dec_rate; |
|---|
| 341 | + |
|---|
| 342 | + if ((t != 0) && (st->clk_mode != ADIS16480_CLK_PPS)) |
|---|
| 285 | 343 | t--; |
|---|
| 286 | 344 | |
|---|
| 287 | | - return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t); |
|---|
| 345 | + return adis_write_reg_16(&st->adis, reg, t); |
|---|
| 288 | 346 | } |
|---|
| 289 | 347 | |
|---|
| 290 | 348 | static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2) |
|---|
| .. | .. |
|---|
| 292 | 350 | struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 293 | 351 | uint16_t t; |
|---|
| 294 | 352 | int ret; |
|---|
| 295 | | - unsigned freq; |
|---|
| 353 | + unsigned int freq; |
|---|
| 354 | + unsigned int reg; |
|---|
| 296 | 355 | |
|---|
| 297 | | - ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t); |
|---|
| 298 | | - if (ret < 0) |
|---|
| 356 | + if (st->clk_mode == ADIS16480_CLK_PPS) |
|---|
| 357 | + reg = ADIS16495_REG_SYNC_SCALE; |
|---|
| 358 | + else |
|---|
| 359 | + reg = ADIS16480_REG_DEC_RATE; |
|---|
| 360 | + |
|---|
| 361 | + ret = adis_read_reg_16(&st->adis, reg, &t); |
|---|
| 362 | + if (ret) |
|---|
| 299 | 363 | return ret; |
|---|
| 300 | 364 | |
|---|
| 301 | | - freq = 2460000 / (t + 1); |
|---|
| 365 | + /* |
|---|
| 366 | + * When using PPS mode, the rate of data collection is equal to the |
|---|
| 367 | + * product of the external clock frequency and the scale factor in the |
|---|
| 368 | + * SYNC_SCALE register. |
|---|
| 369 | + * When using sync mode, or internal clock, the output data rate is |
|---|
| 370 | + * equal with the clock frequency divided by DEC_RATE + 1. |
|---|
| 371 | + */ |
|---|
| 372 | + if (st->clk_mode == ADIS16480_CLK_PPS) |
|---|
| 373 | + freq = st->clk_freq * t; |
|---|
| 374 | + else |
|---|
| 375 | + freq = st->clk_freq / (t + 1); |
|---|
| 376 | + |
|---|
| 302 | 377 | *val = freq / 1000; |
|---|
| 303 | 378 | *val2 = (freq % 1000) * 1000; |
|---|
| 304 | 379 | |
|---|
| .. | .. |
|---|
| 386 | 461 | *bias = sign_extend32(val32, 31); |
|---|
| 387 | 462 | break; |
|---|
| 388 | 463 | default: |
|---|
| 389 | | - ret = -EINVAL; |
|---|
| 464 | + ret = -EINVAL; |
|---|
| 390 | 465 | } |
|---|
| 391 | 466 | |
|---|
| 392 | | - if (ret < 0) |
|---|
| 467 | + if (ret) |
|---|
| 393 | 468 | return ret; |
|---|
| 394 | 469 | |
|---|
| 395 | 470 | return IIO_VAL_INT; |
|---|
| .. | .. |
|---|
| 416 | 491 | int ret; |
|---|
| 417 | 492 | |
|---|
| 418 | 493 | ret = adis_read_reg_16(&st->adis, reg, &val16); |
|---|
| 419 | | - if (ret < 0) |
|---|
| 494 | + if (ret) |
|---|
| 420 | 495 | return ret; |
|---|
| 421 | 496 | |
|---|
| 422 | 497 | *scale = sign_extend32(val16, 15); |
|---|
| .. | .. |
|---|
| 428 | 503 | 55, |
|---|
| 429 | 504 | 275, |
|---|
| 430 | 505 | 63, |
|---|
| 506 | +}; |
|---|
| 507 | + |
|---|
| 508 | +static const unsigned int adis16495_def_filter_freqs[] = { |
|---|
| 509 | + 300, |
|---|
| 510 | + 100, |
|---|
| 511 | + 300, |
|---|
| 512 | + 100, |
|---|
| 431 | 513 | }; |
|---|
| 432 | 514 | |
|---|
| 433 | 515 | static const unsigned int ad16480_filter_data[][2] = { |
|---|
| .. | .. |
|---|
| 455 | 537 | enable_mask = BIT(offset + 2); |
|---|
| 456 | 538 | |
|---|
| 457 | 539 | ret = adis_read_reg_16(&st->adis, reg, &val); |
|---|
| 458 | | - if (ret < 0) |
|---|
| 540 | + if (ret) |
|---|
| 459 | 541 | return ret; |
|---|
| 460 | 542 | |
|---|
| 461 | 543 | if (!(val & enable_mask)) |
|---|
| 462 | 544 | *freq = 0; |
|---|
| 463 | 545 | else |
|---|
| 464 | | - *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3]; |
|---|
| 546 | + *freq = st->chip_info->filter_freqs[(val >> offset) & 0x3]; |
|---|
| 465 | 547 | |
|---|
| 466 | 548 | return IIO_VAL_INT; |
|---|
| 467 | 549 | } |
|---|
| .. | .. |
|---|
| 470 | 552 | const struct iio_chan_spec *chan, unsigned int freq) |
|---|
| 471 | 553 | { |
|---|
| 472 | 554 | struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 555 | + struct mutex *slock = &st->adis.state_lock; |
|---|
| 473 | 556 | unsigned int enable_mask, offset, reg; |
|---|
| 474 | 557 | unsigned int diff, best_diff; |
|---|
| 475 | 558 | unsigned int i, best_freq; |
|---|
| .. | .. |
|---|
| 480 | 563 | offset = ad16480_filter_data[chan->scan_index][1]; |
|---|
| 481 | 564 | enable_mask = BIT(offset + 2); |
|---|
| 482 | 565 | |
|---|
| 483 | | - ret = adis_read_reg_16(&st->adis, reg, &val); |
|---|
| 484 | | - if (ret < 0) |
|---|
| 485 | | - return ret; |
|---|
| 566 | + mutex_lock(slock); |
|---|
| 567 | + |
|---|
| 568 | + ret = __adis_read_reg_16(&st->adis, reg, &val); |
|---|
| 569 | + if (ret) |
|---|
| 570 | + goto out_unlock; |
|---|
| 486 | 571 | |
|---|
| 487 | 572 | if (freq == 0) { |
|---|
| 488 | 573 | val &= ~enable_mask; |
|---|
| 489 | 574 | } else { |
|---|
| 490 | 575 | best_freq = 0; |
|---|
| 491 | | - best_diff = 310; |
|---|
| 576 | + best_diff = st->chip_info->filter_freqs[0]; |
|---|
| 492 | 577 | for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) { |
|---|
| 493 | | - if (adis16480_def_filter_freqs[i] >= freq) { |
|---|
| 494 | | - diff = adis16480_def_filter_freqs[i] - freq; |
|---|
| 578 | + if (st->chip_info->filter_freqs[i] >= freq) { |
|---|
| 579 | + diff = st->chip_info->filter_freqs[i] - freq; |
|---|
| 495 | 580 | if (diff < best_diff) { |
|---|
| 496 | 581 | best_diff = diff; |
|---|
| 497 | 582 | best_freq = i; |
|---|
| .. | .. |
|---|
| 504 | 589 | val |= enable_mask; |
|---|
| 505 | 590 | } |
|---|
| 506 | 591 | |
|---|
| 507 | | - return adis_write_reg_16(&st->adis, reg, val); |
|---|
| 592 | + ret = __adis_write_reg_16(&st->adis, reg, val); |
|---|
| 593 | +out_unlock: |
|---|
| 594 | + mutex_unlock(slock); |
|---|
| 595 | + |
|---|
| 596 | + return ret; |
|---|
| 508 | 597 | } |
|---|
| 509 | 598 | |
|---|
| 510 | 599 | static int adis16480_read_raw(struct iio_dev *indio_dev, |
|---|
| 511 | 600 | const struct iio_chan_spec *chan, int *val, int *val2, long info) |
|---|
| 512 | 601 | { |
|---|
| 513 | 602 | struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 603 | + unsigned int temp; |
|---|
| 514 | 604 | |
|---|
| 515 | 605 | switch (info) { |
|---|
| 516 | 606 | case IIO_CHAN_INFO_RAW: |
|---|
| .. | .. |
|---|
| 530 | 620 | *val2 = 100; /* 0.0001 gauss */ |
|---|
| 531 | 621 | return IIO_VAL_INT_PLUS_MICRO; |
|---|
| 532 | 622 | case IIO_TEMP: |
|---|
| 533 | | - *val = 5; |
|---|
| 534 | | - *val2 = 650000; /* 5.65 milli degree Celsius */ |
|---|
| 623 | + /* |
|---|
| 624 | + * +85 degrees Celsius = temp_max_scale |
|---|
| 625 | + * +25 degrees Celsius = 0 |
|---|
| 626 | + * LSB, 25 degrees Celsius = 60 / temp_max_scale |
|---|
| 627 | + */ |
|---|
| 628 | + *val = st->chip_info->temp_scale / 1000; |
|---|
| 629 | + *val2 = (st->chip_info->temp_scale % 1000) * 1000; |
|---|
| 535 | 630 | return IIO_VAL_INT_PLUS_MICRO; |
|---|
| 536 | 631 | case IIO_PRESSURE: |
|---|
| 537 | | - *val = 0; |
|---|
| 538 | | - *val2 = 4000; /* 40ubar = 0.004 kPa */ |
|---|
| 539 | | - return IIO_VAL_INT_PLUS_MICRO; |
|---|
| 632 | + /* |
|---|
| 633 | + * max scale is 1310 mbar |
|---|
| 634 | + * max raw value is 32767 shifted for 32bits |
|---|
| 635 | + */ |
|---|
| 636 | + *val = 131; /* 1310mbar = 131 kPa */ |
|---|
| 637 | + *val2 = 32767 << 16; |
|---|
| 638 | + return IIO_VAL_FRACTIONAL; |
|---|
| 540 | 639 | default: |
|---|
| 541 | 640 | return -EINVAL; |
|---|
| 542 | 641 | } |
|---|
| 543 | 642 | case IIO_CHAN_INFO_OFFSET: |
|---|
| 544 | 643 | /* Only the temperature channel has a offset */ |
|---|
| 545 | | - *val = 4425; /* 25 degree Celsius = 0x0000 */ |
|---|
| 644 | + temp = 25 * 1000000LL; /* 25 degree Celsius = 0x0000 */ |
|---|
| 645 | + *val = DIV_ROUND_CLOSEST_ULL(temp, st->chip_info->temp_scale); |
|---|
| 546 | 646 | return IIO_VAL_INT; |
|---|
| 547 | 647 | case IIO_CHAN_INFO_CALIBBIAS: |
|---|
| 548 | 648 | return adis16480_get_calibbias(indio_dev, chan, val); |
|---|
| .. | .. |
|---|
| 683 | 783 | ADIS16480, |
|---|
| 684 | 784 | ADIS16485, |
|---|
| 685 | 785 | ADIS16488, |
|---|
| 786 | + ADIS16490, |
|---|
| 787 | + ADIS16495_1, |
|---|
| 788 | + ADIS16495_2, |
|---|
| 789 | + ADIS16495_3, |
|---|
| 790 | + ADIS16497_1, |
|---|
| 791 | + ADIS16497_2, |
|---|
| 792 | + ADIS16497_3, |
|---|
| 686 | 793 | }; |
|---|
| 687 | | - |
|---|
| 688 | | -static const struct adis16480_chip_info adis16480_chip_info[] = { |
|---|
| 689 | | - [ADIS16375] = { |
|---|
| 690 | | - .channels = adis16485_channels, |
|---|
| 691 | | - .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 692 | | - /* |
|---|
| 693 | | - * storing the value in rad/degree and the scale in degree |
|---|
| 694 | | - * gives us the result in rad and better precession than |
|---|
| 695 | | - * storing the scale directly in rad. |
|---|
| 696 | | - */ |
|---|
| 697 | | - .gyro_max_val = IIO_RAD_TO_DEGREE(22887), |
|---|
| 698 | | - .gyro_max_scale = 300, |
|---|
| 699 | | - .accel_max_val = IIO_M_S_2_TO_G(21973), |
|---|
| 700 | | - .accel_max_scale = 18, |
|---|
| 701 | | - }, |
|---|
| 702 | | - [ADIS16480] = { |
|---|
| 703 | | - .channels = adis16480_channels, |
|---|
| 704 | | - .num_channels = ARRAY_SIZE(adis16480_channels), |
|---|
| 705 | | - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), |
|---|
| 706 | | - .gyro_max_scale = 450, |
|---|
| 707 | | - .accel_max_val = IIO_M_S_2_TO_G(12500), |
|---|
| 708 | | - .accel_max_scale = 10, |
|---|
| 709 | | - }, |
|---|
| 710 | | - [ADIS16485] = { |
|---|
| 711 | | - .channels = adis16485_channels, |
|---|
| 712 | | - .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 713 | | - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), |
|---|
| 714 | | - .gyro_max_scale = 450, |
|---|
| 715 | | - .accel_max_val = IIO_M_S_2_TO_G(20000), |
|---|
| 716 | | - .accel_max_scale = 5, |
|---|
| 717 | | - }, |
|---|
| 718 | | - [ADIS16488] = { |
|---|
| 719 | | - .channels = adis16480_channels, |
|---|
| 720 | | - .num_channels = ARRAY_SIZE(adis16480_channels), |
|---|
| 721 | | - .gyro_max_val = IIO_RAD_TO_DEGREE(22500), |
|---|
| 722 | | - .gyro_max_scale = 450, |
|---|
| 723 | | - .accel_max_val = IIO_M_S_2_TO_G(22500), |
|---|
| 724 | | - .accel_max_scale = 18, |
|---|
| 725 | | - }, |
|---|
| 726 | | -}; |
|---|
| 727 | | - |
|---|
| 728 | | -static const struct iio_info adis16480_info = { |
|---|
| 729 | | - .read_raw = &adis16480_read_raw, |
|---|
| 730 | | - .write_raw = &adis16480_write_raw, |
|---|
| 731 | | - .update_scan_mode = adis_update_scan_mode, |
|---|
| 732 | | - .debugfs_reg_access = adis_debugfs_reg_access, |
|---|
| 733 | | -}; |
|---|
| 734 | | - |
|---|
| 735 | | -static int adis16480_stop_device(struct iio_dev *indio_dev) |
|---|
| 736 | | -{ |
|---|
| 737 | | - struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 738 | | - int ret; |
|---|
| 739 | | - |
|---|
| 740 | | - ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9)); |
|---|
| 741 | | - if (ret) |
|---|
| 742 | | - dev_err(&indio_dev->dev, |
|---|
| 743 | | - "Could not power down device: %d\n", ret); |
|---|
| 744 | | - |
|---|
| 745 | | - return ret; |
|---|
| 746 | | -} |
|---|
| 747 | | - |
|---|
| 748 | | -static int adis16480_enable_irq(struct adis *adis, bool enable) |
|---|
| 749 | | -{ |
|---|
| 750 | | - return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, |
|---|
| 751 | | - enable ? BIT(3) : 0); |
|---|
| 752 | | -} |
|---|
| 753 | | - |
|---|
| 754 | | -static int adis16480_initial_setup(struct iio_dev *indio_dev) |
|---|
| 755 | | -{ |
|---|
| 756 | | - struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 757 | | - uint16_t prod_id; |
|---|
| 758 | | - unsigned int device_id; |
|---|
| 759 | | - int ret; |
|---|
| 760 | | - |
|---|
| 761 | | - adis_reset(&st->adis); |
|---|
| 762 | | - msleep(70); |
|---|
| 763 | | - |
|---|
| 764 | | - ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1)); |
|---|
| 765 | | - if (ret) |
|---|
| 766 | | - return ret; |
|---|
| 767 | | - msleep(30); |
|---|
| 768 | | - |
|---|
| 769 | | - ret = adis_check_status(&st->adis); |
|---|
| 770 | | - if (ret) |
|---|
| 771 | | - return ret; |
|---|
| 772 | | - |
|---|
| 773 | | - ret = adis_read_reg_16(&st->adis, ADIS16480_REG_PROD_ID, &prod_id); |
|---|
| 774 | | - if (ret) |
|---|
| 775 | | - return ret; |
|---|
| 776 | | - |
|---|
| 777 | | - ret = sscanf(indio_dev->name, "adis%u\n", &device_id); |
|---|
| 778 | | - if (ret != 1) |
|---|
| 779 | | - return -EINVAL; |
|---|
| 780 | | - |
|---|
| 781 | | - if (prod_id != device_id) |
|---|
| 782 | | - dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", |
|---|
| 783 | | - device_id, prod_id); |
|---|
| 784 | | - |
|---|
| 785 | | - return 0; |
|---|
| 786 | | -} |
|---|
| 787 | 794 | |
|---|
| 788 | 795 | #define ADIS16480_DIAG_STAT_XGYRO_FAIL 0 |
|---|
| 789 | 796 | #define ADIS16480_DIAG_STAT_YGYRO_FAIL 1 |
|---|
| .. | .. |
|---|
| 809 | 816 | [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure", |
|---|
| 810 | 817 | }; |
|---|
| 811 | 818 | |
|---|
| 812 | | -static const struct adis_data adis16480_data = { |
|---|
| 813 | | - .diag_stat_reg = ADIS16480_REG_DIAG_STS, |
|---|
| 814 | | - .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, |
|---|
| 815 | | - .has_paging = true, |
|---|
| 819 | +static int adis16480_enable_irq(struct adis *adis, bool enable); |
|---|
| 816 | 820 | |
|---|
| 817 | | - .read_delay = 5, |
|---|
| 818 | | - .write_delay = 5, |
|---|
| 821 | +#define ADIS16480_DATA(_prod_id, _timeouts) \ |
|---|
| 822 | +{ \ |
|---|
| 823 | + .diag_stat_reg = ADIS16480_REG_DIAG_STS, \ |
|---|
| 824 | + .glob_cmd_reg = ADIS16480_REG_GLOB_CMD, \ |
|---|
| 825 | + .prod_id_reg = ADIS16480_REG_PROD_ID, \ |
|---|
| 826 | + .prod_id = (_prod_id), \ |
|---|
| 827 | + .has_paging = true, \ |
|---|
| 828 | + .read_delay = 5, \ |
|---|
| 829 | + .write_delay = 5, \ |
|---|
| 830 | + .self_test_mask = BIT(1), \ |
|---|
| 831 | + .self_test_reg = ADIS16480_REG_GLOB_CMD, \ |
|---|
| 832 | + .status_error_msgs = adis16480_status_error_msgs, \ |
|---|
| 833 | + .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | \ |
|---|
| 834 | + BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | \ |
|---|
| 835 | + BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | \ |
|---|
| 836 | + BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | \ |
|---|
| 837 | + BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | \ |
|---|
| 838 | + BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | \ |
|---|
| 839 | + BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | \ |
|---|
| 840 | + BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | \ |
|---|
| 841 | + BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | \ |
|---|
| 842 | + BIT(ADIS16480_DIAG_STAT_BARO_FAIL), \ |
|---|
| 843 | + .enable_irq = adis16480_enable_irq, \ |
|---|
| 844 | + .timeouts = (_timeouts), \ |
|---|
| 845 | +} |
|---|
| 819 | 846 | |
|---|
| 820 | | - .status_error_msgs = adis16480_status_error_msgs, |
|---|
| 821 | | - .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) | |
|---|
| 822 | | - BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) | |
|---|
| 823 | | - BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) | |
|---|
| 824 | | - BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) | |
|---|
| 825 | | - BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) | |
|---|
| 826 | | - BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) | |
|---|
| 827 | | - BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) | |
|---|
| 828 | | - BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) | |
|---|
| 829 | | - BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) | |
|---|
| 830 | | - BIT(ADIS16480_DIAG_STAT_BARO_FAIL), |
|---|
| 831 | | - |
|---|
| 832 | | - .enable_irq = adis16480_enable_irq, |
|---|
| 847 | +static const struct adis_timeout adis16485_timeouts = { |
|---|
| 848 | + .reset_ms = 560, |
|---|
| 849 | + .sw_reset_ms = 120, |
|---|
| 850 | + .self_test_ms = 12, |
|---|
| 833 | 851 | }; |
|---|
| 852 | + |
|---|
| 853 | +static const struct adis_timeout adis16480_timeouts = { |
|---|
| 854 | + .reset_ms = 560, |
|---|
| 855 | + .sw_reset_ms = 560, |
|---|
| 856 | + .self_test_ms = 12, |
|---|
| 857 | +}; |
|---|
| 858 | + |
|---|
| 859 | +static const struct adis_timeout adis16495_timeouts = { |
|---|
| 860 | + .reset_ms = 170, |
|---|
| 861 | + .sw_reset_ms = 130, |
|---|
| 862 | + .self_test_ms = 40, |
|---|
| 863 | +}; |
|---|
| 864 | + |
|---|
| 865 | +static const struct adis_timeout adis16495_1_timeouts = { |
|---|
| 866 | + .reset_ms = 250, |
|---|
| 867 | + .sw_reset_ms = 210, |
|---|
| 868 | + .self_test_ms = 20, |
|---|
| 869 | +}; |
|---|
| 870 | + |
|---|
| 871 | +static const struct adis16480_chip_info adis16480_chip_info[] = { |
|---|
| 872 | + [ADIS16375] = { |
|---|
| 873 | + .channels = adis16485_channels, |
|---|
| 874 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 875 | + /* |
|---|
| 876 | + * Typically we do IIO_RAD_TO_DEGREE in the denominator, which |
|---|
| 877 | + * is exactly the same as IIO_DEGREE_TO_RAD in numerator, since |
|---|
| 878 | + * it gives better approximation. However, in this case we |
|---|
| 879 | + * cannot do it since it would not fit in a 32bit variable. |
|---|
| 880 | + */ |
|---|
| 881 | + .gyro_max_val = 22887 << 16, |
|---|
| 882 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(300), |
|---|
| 883 | + .accel_max_val = IIO_M_S_2_TO_G(21973 << 16), |
|---|
| 884 | + .accel_max_scale = 18, |
|---|
| 885 | + .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
|---|
| 886 | + .int_clk = 2460000, |
|---|
| 887 | + .max_dec_rate = 2048, |
|---|
| 888 | + .filter_freqs = adis16480_def_filter_freqs, |
|---|
| 889 | + .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts), |
|---|
| 890 | + }, |
|---|
| 891 | + [ADIS16480] = { |
|---|
| 892 | + .channels = adis16480_channels, |
|---|
| 893 | + .num_channels = ARRAY_SIZE(adis16480_channels), |
|---|
| 894 | + .gyro_max_val = 22500 << 16, |
|---|
| 895 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), |
|---|
| 896 | + .accel_max_val = IIO_M_S_2_TO_G(12500 << 16), |
|---|
| 897 | + .accel_max_scale = 10, |
|---|
| 898 | + .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
|---|
| 899 | + .int_clk = 2460000, |
|---|
| 900 | + .max_dec_rate = 2048, |
|---|
| 901 | + .filter_freqs = adis16480_def_filter_freqs, |
|---|
| 902 | + .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts), |
|---|
| 903 | + }, |
|---|
| 904 | + [ADIS16485] = { |
|---|
| 905 | + .channels = adis16485_channels, |
|---|
| 906 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 907 | + .gyro_max_val = 22500 << 16, |
|---|
| 908 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), |
|---|
| 909 | + .accel_max_val = IIO_M_S_2_TO_G(20000 << 16), |
|---|
| 910 | + .accel_max_scale = 5, |
|---|
| 911 | + .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
|---|
| 912 | + .int_clk = 2460000, |
|---|
| 913 | + .max_dec_rate = 2048, |
|---|
| 914 | + .filter_freqs = adis16480_def_filter_freqs, |
|---|
| 915 | + .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts), |
|---|
| 916 | + }, |
|---|
| 917 | + [ADIS16488] = { |
|---|
| 918 | + .channels = adis16480_channels, |
|---|
| 919 | + .num_channels = ARRAY_SIZE(adis16480_channels), |
|---|
| 920 | + .gyro_max_val = 22500 << 16, |
|---|
| 921 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), |
|---|
| 922 | + .accel_max_val = IIO_M_S_2_TO_G(22500 << 16), |
|---|
| 923 | + .accel_max_scale = 18, |
|---|
| 924 | + .temp_scale = 5650, /* 5.65 milli degree Celsius */ |
|---|
| 925 | + .int_clk = 2460000, |
|---|
| 926 | + .max_dec_rate = 2048, |
|---|
| 927 | + .filter_freqs = adis16480_def_filter_freqs, |
|---|
| 928 | + .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts), |
|---|
| 929 | + }, |
|---|
| 930 | + [ADIS16490] = { |
|---|
| 931 | + .channels = adis16485_channels, |
|---|
| 932 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 933 | + .gyro_max_val = 20000 << 16, |
|---|
| 934 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(100), |
|---|
| 935 | + .accel_max_val = IIO_M_S_2_TO_G(16000 << 16), |
|---|
| 936 | + .accel_max_scale = 8, |
|---|
| 937 | + .temp_scale = 14285, /* 14.285 milli degree Celsius */ |
|---|
| 938 | + .int_clk = 4250000, |
|---|
| 939 | + .max_dec_rate = 4250, |
|---|
| 940 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 941 | + .has_pps_clk_mode = true, |
|---|
| 942 | + .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts), |
|---|
| 943 | + }, |
|---|
| 944 | + [ADIS16495_1] = { |
|---|
| 945 | + .channels = adis16485_channels, |
|---|
| 946 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 947 | + .gyro_max_val = 20000 << 16, |
|---|
| 948 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(125), |
|---|
| 949 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 950 | + .accel_max_scale = 8, |
|---|
| 951 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 952 | + .int_clk = 4250000, |
|---|
| 953 | + .max_dec_rate = 4250, |
|---|
| 954 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 955 | + .has_pps_clk_mode = true, |
|---|
| 956 | + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), |
|---|
| 957 | + }, |
|---|
| 958 | + [ADIS16495_2] = { |
|---|
| 959 | + .channels = adis16485_channels, |
|---|
| 960 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 961 | + .gyro_max_val = 18000 << 16, |
|---|
| 962 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), |
|---|
| 963 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 964 | + .accel_max_scale = 8, |
|---|
| 965 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 966 | + .int_clk = 4250000, |
|---|
| 967 | + .max_dec_rate = 4250, |
|---|
| 968 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 969 | + .has_pps_clk_mode = true, |
|---|
| 970 | + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), |
|---|
| 971 | + }, |
|---|
| 972 | + [ADIS16495_3] = { |
|---|
| 973 | + .channels = adis16485_channels, |
|---|
| 974 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 975 | + .gyro_max_val = 20000 << 16, |
|---|
| 976 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), |
|---|
| 977 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 978 | + .accel_max_scale = 8, |
|---|
| 979 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 980 | + .int_clk = 4250000, |
|---|
| 981 | + .max_dec_rate = 4250, |
|---|
| 982 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 983 | + .has_pps_clk_mode = true, |
|---|
| 984 | + .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts), |
|---|
| 985 | + }, |
|---|
| 986 | + [ADIS16497_1] = { |
|---|
| 987 | + .channels = adis16485_channels, |
|---|
| 988 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 989 | + .gyro_max_val = 20000 << 16, |
|---|
| 990 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(125), |
|---|
| 991 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 992 | + .accel_max_scale = 40, |
|---|
| 993 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 994 | + .int_clk = 4250000, |
|---|
| 995 | + .max_dec_rate = 4250, |
|---|
| 996 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 997 | + .has_pps_clk_mode = true, |
|---|
| 998 | + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), |
|---|
| 999 | + }, |
|---|
| 1000 | + [ADIS16497_2] = { |
|---|
| 1001 | + .channels = adis16485_channels, |
|---|
| 1002 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 1003 | + .gyro_max_val = 18000 << 16, |
|---|
| 1004 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(450), |
|---|
| 1005 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 1006 | + .accel_max_scale = 40, |
|---|
| 1007 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 1008 | + .int_clk = 4250000, |
|---|
| 1009 | + .max_dec_rate = 4250, |
|---|
| 1010 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 1011 | + .has_pps_clk_mode = true, |
|---|
| 1012 | + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), |
|---|
| 1013 | + }, |
|---|
| 1014 | + [ADIS16497_3] = { |
|---|
| 1015 | + .channels = adis16485_channels, |
|---|
| 1016 | + .num_channels = ARRAY_SIZE(adis16485_channels), |
|---|
| 1017 | + .gyro_max_val = 20000 << 16, |
|---|
| 1018 | + .gyro_max_scale = IIO_DEGREE_TO_RAD(2000), |
|---|
| 1019 | + .accel_max_val = IIO_M_S_2_TO_G(32000 << 16), |
|---|
| 1020 | + .accel_max_scale = 40, |
|---|
| 1021 | + .temp_scale = 12500, /* 12.5 milli degree Celsius */ |
|---|
| 1022 | + .int_clk = 4250000, |
|---|
| 1023 | + .max_dec_rate = 4250, |
|---|
| 1024 | + .filter_freqs = adis16495_def_filter_freqs, |
|---|
| 1025 | + .has_pps_clk_mode = true, |
|---|
| 1026 | + .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts), |
|---|
| 1027 | + }, |
|---|
| 1028 | +}; |
|---|
| 1029 | + |
|---|
| 1030 | +static const struct iio_info adis16480_info = { |
|---|
| 1031 | + .read_raw = &adis16480_read_raw, |
|---|
| 1032 | + .write_raw = &adis16480_write_raw, |
|---|
| 1033 | + .update_scan_mode = adis_update_scan_mode, |
|---|
| 1034 | + .debugfs_reg_access = adis_debugfs_reg_access, |
|---|
| 1035 | +}; |
|---|
| 1036 | + |
|---|
| 1037 | +static int adis16480_stop_device(struct iio_dev *indio_dev) |
|---|
| 1038 | +{ |
|---|
| 1039 | + struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 1040 | + int ret; |
|---|
| 1041 | + |
|---|
| 1042 | + ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9)); |
|---|
| 1043 | + if (ret) |
|---|
| 1044 | + dev_err(&indio_dev->dev, |
|---|
| 1045 | + "Could not power down device: %d\n", ret); |
|---|
| 1046 | + |
|---|
| 1047 | + return ret; |
|---|
| 1048 | +} |
|---|
| 1049 | + |
|---|
| 1050 | +static int adis16480_enable_irq(struct adis *adis, bool enable) |
|---|
| 1051 | +{ |
|---|
| 1052 | + uint16_t val; |
|---|
| 1053 | + int ret; |
|---|
| 1054 | + |
|---|
| 1055 | + ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val); |
|---|
| 1056 | + if (ret) |
|---|
| 1057 | + return ret; |
|---|
| 1058 | + |
|---|
| 1059 | + val &= ~ADIS16480_DRDY_EN_MSK; |
|---|
| 1060 | + val |= ADIS16480_DRDY_EN(enable); |
|---|
| 1061 | + |
|---|
| 1062 | + return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val); |
|---|
| 1063 | +} |
|---|
| 1064 | + |
|---|
| 1065 | +static int adis16480_config_irq_pin(struct device_node *of_node, |
|---|
| 1066 | + struct adis16480 *st) |
|---|
| 1067 | +{ |
|---|
| 1068 | + struct irq_data *desc; |
|---|
| 1069 | + enum adis16480_int_pin pin; |
|---|
| 1070 | + unsigned int irq_type; |
|---|
| 1071 | + uint16_t val; |
|---|
| 1072 | + int i, irq = 0; |
|---|
| 1073 | + |
|---|
| 1074 | + desc = irq_get_irq_data(st->adis.spi->irq); |
|---|
| 1075 | + if (!desc) { |
|---|
| 1076 | + dev_err(&st->adis.spi->dev, "Could not find IRQ %d\n", irq); |
|---|
| 1077 | + return -EINVAL; |
|---|
| 1078 | + } |
|---|
| 1079 | + |
|---|
| 1080 | + /* Disable data ready since the default after reset is on */ |
|---|
| 1081 | + val = ADIS16480_DRDY_EN(0); |
|---|
| 1082 | + |
|---|
| 1083 | + /* |
|---|
| 1084 | + * Get the interrupt from the devicetre by reading the interrupt-names |
|---|
| 1085 | + * property. If it is not specified, use DIO1 pin as default. |
|---|
| 1086 | + * According to the datasheet, the factory default assigns DIO2 as data |
|---|
| 1087 | + * ready signal. However, in the previous versions of the driver, DIO1 |
|---|
| 1088 | + * pin was used. So, we should leave it as is since some devices might |
|---|
| 1089 | + * be expecting the interrupt on the wrong physical pin. |
|---|
| 1090 | + */ |
|---|
| 1091 | + pin = ADIS16480_PIN_DIO1; |
|---|
| 1092 | + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { |
|---|
| 1093 | + irq = of_irq_get_byname(of_node, adis16480_int_pin_names[i]); |
|---|
| 1094 | + if (irq > 0) { |
|---|
| 1095 | + pin = i; |
|---|
| 1096 | + break; |
|---|
| 1097 | + } |
|---|
| 1098 | + } |
|---|
| 1099 | + |
|---|
| 1100 | + val |= ADIS16480_DRDY_SEL(pin); |
|---|
| 1101 | + |
|---|
| 1102 | + /* |
|---|
| 1103 | + * Get the interrupt line behaviour. The data ready polarity can be |
|---|
| 1104 | + * configured as positive or negative, corresponding to |
|---|
| 1105 | + * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively. |
|---|
| 1106 | + */ |
|---|
| 1107 | + irq_type = irqd_get_trigger_type(desc); |
|---|
| 1108 | + if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */ |
|---|
| 1109 | + val |= ADIS16480_DRDY_POL(1); |
|---|
| 1110 | + } else if (irq_type == IRQ_TYPE_EDGE_FALLING) { |
|---|
| 1111 | + val |= ADIS16480_DRDY_POL(0); |
|---|
| 1112 | + } else { |
|---|
| 1113 | + dev_err(&st->adis.spi->dev, |
|---|
| 1114 | + "Invalid interrupt type 0x%x specified\n", irq_type); |
|---|
| 1115 | + return -EINVAL; |
|---|
| 1116 | + } |
|---|
| 1117 | + /* Write the data ready configuration to the FNCTIO_CTRL register */ |
|---|
| 1118 | + return adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); |
|---|
| 1119 | +} |
|---|
| 1120 | + |
|---|
| 1121 | +static int adis16480_of_get_ext_clk_pin(struct adis16480 *st, |
|---|
| 1122 | + struct device_node *of_node) |
|---|
| 1123 | +{ |
|---|
| 1124 | + const char *ext_clk_pin; |
|---|
| 1125 | + enum adis16480_int_pin pin; |
|---|
| 1126 | + int i; |
|---|
| 1127 | + |
|---|
| 1128 | + pin = ADIS16480_PIN_DIO2; |
|---|
| 1129 | + if (of_property_read_string(of_node, "adi,ext-clk-pin", &ext_clk_pin)) |
|---|
| 1130 | + goto clk_input_not_found; |
|---|
| 1131 | + |
|---|
| 1132 | + for (i = 0; i < ARRAY_SIZE(adis16480_int_pin_names); i++) { |
|---|
| 1133 | + if (strcasecmp(ext_clk_pin, adis16480_int_pin_names[i]) == 0) |
|---|
| 1134 | + return i; |
|---|
| 1135 | + } |
|---|
| 1136 | + |
|---|
| 1137 | +clk_input_not_found: |
|---|
| 1138 | + dev_info(&st->adis.spi->dev, |
|---|
| 1139 | + "clk input line not specified, using DIO2\n"); |
|---|
| 1140 | + return pin; |
|---|
| 1141 | +} |
|---|
| 1142 | + |
|---|
| 1143 | +static int adis16480_ext_clk_config(struct adis16480 *st, |
|---|
| 1144 | + struct device_node *of_node, |
|---|
| 1145 | + bool enable) |
|---|
| 1146 | +{ |
|---|
| 1147 | + unsigned int mode, mask; |
|---|
| 1148 | + enum adis16480_int_pin pin; |
|---|
| 1149 | + uint16_t val; |
|---|
| 1150 | + int ret; |
|---|
| 1151 | + |
|---|
| 1152 | + ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val); |
|---|
| 1153 | + if (ret) |
|---|
| 1154 | + return ret; |
|---|
| 1155 | + |
|---|
| 1156 | + pin = adis16480_of_get_ext_clk_pin(st, of_node); |
|---|
| 1157 | + /* |
|---|
| 1158 | + * Each DIOx pin supports only one function at a time. When a single pin |
|---|
| 1159 | + * has two assignments, the enable bit for a lower priority function |
|---|
| 1160 | + * automatically resets to zero (disabling the lower priority function). |
|---|
| 1161 | + */ |
|---|
| 1162 | + if (pin == ADIS16480_DRDY_SEL(val)) |
|---|
| 1163 | + dev_warn(&st->adis.spi->dev, |
|---|
| 1164 | + "DIO%x pin supports only one function at a time\n", |
|---|
| 1165 | + pin + 1); |
|---|
| 1166 | + |
|---|
| 1167 | + mode = ADIS16480_SYNC_EN(enable) | ADIS16480_SYNC_SEL(pin); |
|---|
| 1168 | + mask = ADIS16480_SYNC_EN_MSK | ADIS16480_SYNC_SEL_MSK; |
|---|
| 1169 | + /* Only ADIS1649x devices support pps ext clock mode */ |
|---|
| 1170 | + if (st->chip_info->has_pps_clk_mode) { |
|---|
| 1171 | + mode |= ADIS16480_SYNC_MODE(st->clk_mode); |
|---|
| 1172 | + mask |= ADIS16480_SYNC_MODE_MSK; |
|---|
| 1173 | + } |
|---|
| 1174 | + |
|---|
| 1175 | + val &= ~mask; |
|---|
| 1176 | + val |= mode; |
|---|
| 1177 | + |
|---|
| 1178 | + ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val); |
|---|
| 1179 | + if (ret) |
|---|
| 1180 | + return ret; |
|---|
| 1181 | + |
|---|
| 1182 | + return clk_prepare_enable(st->ext_clk); |
|---|
| 1183 | +} |
|---|
| 1184 | + |
|---|
| 1185 | +static int adis16480_get_ext_clocks(struct adis16480 *st) |
|---|
| 1186 | +{ |
|---|
| 1187 | + st->clk_mode = ADIS16480_CLK_INT; |
|---|
| 1188 | + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "sync"); |
|---|
| 1189 | + if (!IS_ERR_OR_NULL(st->ext_clk)) { |
|---|
| 1190 | + st->clk_mode = ADIS16480_CLK_SYNC; |
|---|
| 1191 | + return 0; |
|---|
| 1192 | + } |
|---|
| 1193 | + |
|---|
| 1194 | + if (PTR_ERR(st->ext_clk) != -ENOENT) { |
|---|
| 1195 | + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); |
|---|
| 1196 | + return PTR_ERR(st->ext_clk); |
|---|
| 1197 | + } |
|---|
| 1198 | + |
|---|
| 1199 | + if (st->chip_info->has_pps_clk_mode) { |
|---|
| 1200 | + st->ext_clk = devm_clk_get(&st->adis.spi->dev, "pps"); |
|---|
| 1201 | + if (!IS_ERR_OR_NULL(st->ext_clk)) { |
|---|
| 1202 | + st->clk_mode = ADIS16480_CLK_PPS; |
|---|
| 1203 | + return 0; |
|---|
| 1204 | + } |
|---|
| 1205 | + |
|---|
| 1206 | + if (PTR_ERR(st->ext_clk) != -ENOENT) { |
|---|
| 1207 | + dev_err(&st->adis.spi->dev, "failed to get ext clk\n"); |
|---|
| 1208 | + return PTR_ERR(st->ext_clk); |
|---|
| 1209 | + } |
|---|
| 1210 | + } |
|---|
| 1211 | + |
|---|
| 1212 | + return 0; |
|---|
| 1213 | +} |
|---|
| 1214 | + |
|---|
| 1215 | +static void adis16480_stop(void *data) |
|---|
| 1216 | +{ |
|---|
| 1217 | + adis16480_stop_device(data); |
|---|
| 1218 | +} |
|---|
| 1219 | + |
|---|
| 1220 | +static void adis16480_clk_disable(void *data) |
|---|
| 1221 | +{ |
|---|
| 1222 | + clk_disable_unprepare(data); |
|---|
| 1223 | +} |
|---|
| 834 | 1224 | |
|---|
| 835 | 1225 | static int adis16480_probe(struct spi_device *spi) |
|---|
| 836 | 1226 | { |
|---|
| 837 | 1227 | const struct spi_device_id *id = spi_get_device_id(spi); |
|---|
| 1228 | + const struct adis_data *adis16480_data; |
|---|
| 838 | 1229 | struct iio_dev *indio_dev; |
|---|
| 839 | 1230 | struct adis16480 *st; |
|---|
| 840 | 1231 | int ret; |
|---|
| .. | .. |
|---|
| 848 | 1239 | st = iio_priv(indio_dev); |
|---|
| 849 | 1240 | |
|---|
| 850 | 1241 | st->chip_info = &adis16480_chip_info[id->driver_data]; |
|---|
| 851 | | - indio_dev->dev.parent = &spi->dev; |
|---|
| 852 | 1242 | indio_dev->name = spi_get_device_id(spi)->name; |
|---|
| 853 | 1243 | indio_dev->channels = st->chip_info->channels; |
|---|
| 854 | 1244 | indio_dev->num_channels = st->chip_info->num_channels; |
|---|
| 855 | 1245 | indio_dev->info = &adis16480_info; |
|---|
| 856 | 1246 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 857 | 1247 | |
|---|
| 858 | | - ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data); |
|---|
| 1248 | + adis16480_data = &st->chip_info->adis_data; |
|---|
| 1249 | + |
|---|
| 1250 | + ret = adis_init(&st->adis, indio_dev, spi, adis16480_data); |
|---|
| 859 | 1251 | if (ret) |
|---|
| 860 | 1252 | return ret; |
|---|
| 861 | 1253 | |
|---|
| 862 | | - ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); |
|---|
| 1254 | + ret = __adis_initial_startup(&st->adis); |
|---|
| 863 | 1255 | if (ret) |
|---|
| 864 | 1256 | return ret; |
|---|
| 865 | 1257 | |
|---|
| 866 | | - ret = adis16480_initial_setup(indio_dev); |
|---|
| 1258 | + ret = devm_add_action_or_reset(&spi->dev, adis16480_stop, indio_dev); |
|---|
| 867 | 1259 | if (ret) |
|---|
| 868 | | - goto error_cleanup_buffer; |
|---|
| 1260 | + return ret; |
|---|
| 869 | 1261 | |
|---|
| 870 | | - ret = iio_device_register(indio_dev); |
|---|
| 1262 | + ret = adis16480_config_irq_pin(spi->dev.of_node, st); |
|---|
| 871 | 1263 | if (ret) |
|---|
| 872 | | - goto error_stop_device; |
|---|
| 1264 | + return ret; |
|---|
| 1265 | + |
|---|
| 1266 | + ret = adis16480_get_ext_clocks(st); |
|---|
| 1267 | + if (ret) |
|---|
| 1268 | + return ret; |
|---|
| 1269 | + |
|---|
| 1270 | + if (!IS_ERR_OR_NULL(st->ext_clk)) { |
|---|
| 1271 | + ret = adis16480_ext_clk_config(st, spi->dev.of_node, true); |
|---|
| 1272 | + if (ret) |
|---|
| 1273 | + return ret; |
|---|
| 1274 | + |
|---|
| 1275 | + ret = devm_add_action_or_reset(&spi->dev, adis16480_clk_disable, st->ext_clk); |
|---|
| 1276 | + if (ret) |
|---|
| 1277 | + return ret; |
|---|
| 1278 | + |
|---|
| 1279 | + st->clk_freq = clk_get_rate(st->ext_clk); |
|---|
| 1280 | + st->clk_freq *= 1000; /* micro */ |
|---|
| 1281 | + } else { |
|---|
| 1282 | + st->clk_freq = st->chip_info->int_clk; |
|---|
| 1283 | + } |
|---|
| 1284 | + |
|---|
| 1285 | + ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL); |
|---|
| 1286 | + if (ret) |
|---|
| 1287 | + return ret; |
|---|
| 1288 | + |
|---|
| 1289 | + ret = devm_iio_device_register(&spi->dev, indio_dev); |
|---|
| 1290 | + if (ret) |
|---|
| 1291 | + return ret; |
|---|
| 873 | 1292 | |
|---|
| 874 | 1293 | adis16480_debugfs_init(indio_dev); |
|---|
| 875 | | - |
|---|
| 876 | | - return 0; |
|---|
| 877 | | - |
|---|
| 878 | | -error_stop_device: |
|---|
| 879 | | - adis16480_stop_device(indio_dev); |
|---|
| 880 | | -error_cleanup_buffer: |
|---|
| 881 | | - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); |
|---|
| 882 | | - return ret; |
|---|
| 883 | | -} |
|---|
| 884 | | - |
|---|
| 885 | | -static int adis16480_remove(struct spi_device *spi) |
|---|
| 886 | | -{ |
|---|
| 887 | | - struct iio_dev *indio_dev = spi_get_drvdata(spi); |
|---|
| 888 | | - struct adis16480 *st = iio_priv(indio_dev); |
|---|
| 889 | | - |
|---|
| 890 | | - iio_device_unregister(indio_dev); |
|---|
| 891 | | - adis16480_stop_device(indio_dev); |
|---|
| 892 | | - |
|---|
| 893 | | - adis_cleanup_buffer_and_trigger(&st->adis, indio_dev); |
|---|
| 894 | 1294 | |
|---|
| 895 | 1295 | return 0; |
|---|
| 896 | 1296 | } |
|---|
| .. | .. |
|---|
| 900 | 1300 | { "adis16480", ADIS16480 }, |
|---|
| 901 | 1301 | { "adis16485", ADIS16485 }, |
|---|
| 902 | 1302 | { "adis16488", ADIS16488 }, |
|---|
| 1303 | + { "adis16490", ADIS16490 }, |
|---|
| 1304 | + { "adis16495-1", ADIS16495_1 }, |
|---|
| 1305 | + { "adis16495-2", ADIS16495_2 }, |
|---|
| 1306 | + { "adis16495-3", ADIS16495_3 }, |
|---|
| 1307 | + { "adis16497-1", ADIS16497_1 }, |
|---|
| 1308 | + { "adis16497-2", ADIS16497_2 }, |
|---|
| 1309 | + { "adis16497-3", ADIS16497_3 }, |
|---|
| 903 | 1310 | { } |
|---|
| 904 | 1311 | }; |
|---|
| 905 | 1312 | MODULE_DEVICE_TABLE(spi, adis16480_ids); |
|---|
| 906 | 1313 | |
|---|
| 1314 | +static const struct of_device_id adis16480_of_match[] = { |
|---|
| 1315 | + { .compatible = "adi,adis16375" }, |
|---|
| 1316 | + { .compatible = "adi,adis16480" }, |
|---|
| 1317 | + { .compatible = "adi,adis16485" }, |
|---|
| 1318 | + { .compatible = "adi,adis16488" }, |
|---|
| 1319 | + { .compatible = "adi,adis16490" }, |
|---|
| 1320 | + { .compatible = "adi,adis16495-1" }, |
|---|
| 1321 | + { .compatible = "adi,adis16495-2" }, |
|---|
| 1322 | + { .compatible = "adi,adis16495-3" }, |
|---|
| 1323 | + { .compatible = "adi,adis16497-1" }, |
|---|
| 1324 | + { .compatible = "adi,adis16497-2" }, |
|---|
| 1325 | + { .compatible = "adi,adis16497-3" }, |
|---|
| 1326 | + { }, |
|---|
| 1327 | +}; |
|---|
| 1328 | +MODULE_DEVICE_TABLE(of, adis16480_of_match); |
|---|
| 1329 | + |
|---|
| 907 | 1330 | static struct spi_driver adis16480_driver = { |
|---|
| 908 | 1331 | .driver = { |
|---|
| 909 | 1332 | .name = "adis16480", |
|---|
| 1333 | + .of_match_table = adis16480_of_match, |
|---|
| 910 | 1334 | }, |
|---|
| 911 | 1335 | .id_table = adis16480_ids, |
|---|
| 912 | 1336 | .probe = adis16480_probe, |
|---|
| 913 | | - .remove = adis16480_remove, |
|---|
| 914 | 1337 | }; |
|---|
| 915 | 1338 | module_spi_driver(adis16480_driver); |
|---|
| 916 | 1339 | |
|---|
| 917 | 1340 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
|---|
| 918 | 1341 | MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver"); |
|---|
| 919 | 1342 | MODULE_LICENSE("GPL v2"); |
|---|
| 1343 | +MODULE_IMPORT_NS(IIO_ADISLIB); |
|---|