| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ADIS16133/ADIS16135/ADIS16136 gyroscope driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2012 Analog Devices Inc. |
|---|
| 5 | 6 | * Author: Lars-Peter Clausen <lars@metafoo.de> |
|---|
| 6 | | - * |
|---|
| 7 | | - * Licensed under the GPL-2. |
|---|
| 8 | 7 | */ |
|---|
| 9 | 8 | |
|---|
| 10 | 9 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 60 | 59 | struct adis16136_chip_info { |
|---|
| 61 | 60 | unsigned int precision; |
|---|
| 62 | 61 | unsigned int fullscale; |
|---|
| 62 | + const struct adis_data adis_data; |
|---|
| 63 | 63 | }; |
|---|
| 64 | 64 | |
|---|
| 65 | 65 | struct adis16136 { |
|---|
| .. | .. |
|---|
| 81 | 81 | |
|---|
| 82 | 82 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, |
|---|
| 83 | 83 | &serial); |
|---|
| 84 | | - if (ret < 0) |
|---|
| 84 | + if (ret) |
|---|
| 85 | 85 | return ret; |
|---|
| 86 | 86 | |
|---|
| 87 | 87 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); |
|---|
| 88 | | - if (ret < 0) |
|---|
| 88 | + if (ret) |
|---|
| 89 | 89 | return ret; |
|---|
| 90 | 90 | |
|---|
| 91 | 91 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); |
|---|
| 92 | | - if (ret < 0) |
|---|
| 92 | + if (ret) |
|---|
| 93 | 93 | return ret; |
|---|
| 94 | 94 | |
|---|
| 95 | 95 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); |
|---|
| 96 | | - if (ret < 0) |
|---|
| 96 | + if (ret) |
|---|
| 97 | 97 | return ret; |
|---|
| 98 | 98 | |
|---|
| 99 | 99 | len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, |
|---|
| .. | .. |
|---|
| 117 | 117 | |
|---|
| 118 | 118 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, |
|---|
| 119 | 119 | &prod_id); |
|---|
| 120 | | - if (ret < 0) |
|---|
| 120 | + if (ret) |
|---|
| 121 | 121 | return ret; |
|---|
| 122 | 122 | |
|---|
| 123 | 123 | *val = prod_id; |
|---|
| .. | .. |
|---|
| 135 | 135 | |
|---|
| 136 | 136 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, |
|---|
| 137 | 137 | &flash_count); |
|---|
| 138 | | - if (ret < 0) |
|---|
| 138 | + if (ret) |
|---|
| 139 | 139 | return ret; |
|---|
| 140 | 140 | |
|---|
| 141 | 141 | *val = flash_count; |
|---|
| .. | .. |
|---|
| 148 | 148 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) |
|---|
| 149 | 149 | { |
|---|
| 150 | 150 | struct adis16136 *adis16136 = iio_priv(indio_dev); |
|---|
| 151 | + struct dentry *d = iio_get_debugfs_dentry(indio_dev); |
|---|
| 151 | 152 | |
|---|
| 152 | 153 | debugfs_create_file_unsafe("serial_number", 0400, |
|---|
| 153 | | - indio_dev->debugfs_dentry, adis16136, |
|---|
| 154 | | - &adis16136_serial_fops); |
|---|
| 154 | + d, adis16136, &adis16136_serial_fops); |
|---|
| 155 | 155 | debugfs_create_file_unsafe("product_id", 0400, |
|---|
| 156 | | - indio_dev->debugfs_dentry, |
|---|
| 157 | | - adis16136, &adis16136_product_id_fops); |
|---|
| 156 | + d, adis16136, &adis16136_product_id_fops); |
|---|
| 158 | 157 | debugfs_create_file_unsafe("flash_count", 0400, |
|---|
| 159 | | - indio_dev->debugfs_dentry, |
|---|
| 160 | | - adis16136, &adis16136_flash_count_fops); |
|---|
| 158 | + d, adis16136, &adis16136_flash_count_fops); |
|---|
| 161 | 159 | |
|---|
| 162 | 160 | return 0; |
|---|
| 163 | 161 | } |
|---|
| .. | .. |
|---|
| 186 | 184 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); |
|---|
| 187 | 185 | } |
|---|
| 188 | 186 | |
|---|
| 189 | | -static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) |
|---|
| 187 | +static int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) |
|---|
| 190 | 188 | { |
|---|
| 191 | 189 | uint16_t t; |
|---|
| 192 | 190 | int ret; |
|---|
| 193 | 191 | |
|---|
| 194 | | - ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); |
|---|
| 195 | | - if (ret < 0) |
|---|
| 192 | + ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); |
|---|
| 193 | + if (ret) |
|---|
| 196 | 194 | return ret; |
|---|
| 197 | 195 | |
|---|
| 198 | 196 | *freq = 32768 / (t + 1); |
|---|
| .. | .. |
|---|
| 225 | 223 | { |
|---|
| 226 | 224 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
|---|
| 227 | 225 | struct adis16136 *adis16136 = iio_priv(indio_dev); |
|---|
| 226 | + struct mutex *slock = &adis16136->adis.state_lock; |
|---|
| 228 | 227 | unsigned int freq; |
|---|
| 229 | 228 | int ret; |
|---|
| 230 | 229 | |
|---|
| 231 | | - ret = adis16136_get_freq(adis16136, &freq); |
|---|
| 232 | | - if (ret < 0) |
|---|
| 230 | + mutex_lock(slock); |
|---|
| 231 | + ret = __adis16136_get_freq(adis16136, &freq); |
|---|
| 232 | + mutex_unlock(slock); |
|---|
| 233 | + if (ret) |
|---|
| 233 | 234 | return ret; |
|---|
| 234 | 235 | |
|---|
| 235 | 236 | return sprintf(buf, "%d\n", freq); |
|---|
| .. | .. |
|---|
| 253 | 254 | static int adis16136_set_filter(struct iio_dev *indio_dev, int val) |
|---|
| 254 | 255 | { |
|---|
| 255 | 256 | struct adis16136 *adis16136 = iio_priv(indio_dev); |
|---|
| 257 | + struct mutex *slock = &adis16136->adis.state_lock; |
|---|
| 256 | 258 | unsigned int freq; |
|---|
| 257 | 259 | int i, ret; |
|---|
| 258 | 260 | |
|---|
| 259 | | - ret = adis16136_get_freq(adis16136, &freq); |
|---|
| 260 | | - if (ret < 0) |
|---|
| 261 | | - return ret; |
|---|
| 261 | + mutex_lock(slock); |
|---|
| 262 | + ret = __adis16136_get_freq(adis16136, &freq); |
|---|
| 263 | + if (ret) |
|---|
| 264 | + goto out_unlock; |
|---|
| 262 | 265 | |
|---|
| 263 | 266 | for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { |
|---|
| 264 | 267 | if (freq / adis16136_3db_divisors[i] >= val) |
|---|
| 265 | 268 | break; |
|---|
| 266 | 269 | } |
|---|
| 267 | 270 | |
|---|
| 268 | | - return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); |
|---|
| 271 | + ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); |
|---|
| 272 | +out_unlock: |
|---|
| 273 | + mutex_unlock(slock); |
|---|
| 274 | + |
|---|
| 275 | + return ret; |
|---|
| 269 | 276 | } |
|---|
| 270 | 277 | |
|---|
| 271 | 278 | static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) |
|---|
| 272 | 279 | { |
|---|
| 273 | 280 | struct adis16136 *adis16136 = iio_priv(indio_dev); |
|---|
| 281 | + struct mutex *slock = &adis16136->adis.state_lock; |
|---|
| 274 | 282 | unsigned int freq; |
|---|
| 275 | 283 | uint16_t val16; |
|---|
| 276 | 284 | int ret; |
|---|
| 277 | 285 | |
|---|
| 278 | | - mutex_lock(&indio_dev->mlock); |
|---|
| 286 | + mutex_lock(slock); |
|---|
| 279 | 287 | |
|---|
| 280 | | - ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); |
|---|
| 281 | | - if (ret < 0) |
|---|
| 288 | + ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, |
|---|
| 289 | + &val16); |
|---|
| 290 | + if (ret) |
|---|
| 282 | 291 | goto err_unlock; |
|---|
| 283 | 292 | |
|---|
| 284 | | - ret = adis16136_get_freq(adis16136, &freq); |
|---|
| 285 | | - if (ret < 0) |
|---|
| 293 | + ret = __adis16136_get_freq(adis16136, &freq); |
|---|
| 294 | + if (ret) |
|---|
| 286 | 295 | goto err_unlock; |
|---|
| 287 | 296 | |
|---|
| 288 | 297 | *val = freq / adis16136_3db_divisors[val16 & 0x07]; |
|---|
| 289 | 298 | |
|---|
| 290 | 299 | err_unlock: |
|---|
| 291 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 300 | + mutex_unlock(slock); |
|---|
| 292 | 301 | |
|---|
| 293 | 302 | return ret ? ret : IIO_VAL_INT; |
|---|
| 294 | 303 | } |
|---|
| .. | .. |
|---|
| 319 | 328 | case IIO_CHAN_INFO_CALIBBIAS: |
|---|
| 320 | 329 | ret = adis_read_reg_32(&adis16136->adis, |
|---|
| 321 | 330 | ADIS16136_REG_GYRO_OFF2, &val32); |
|---|
| 322 | | - if (ret < 0) |
|---|
| 331 | + if (ret) |
|---|
| 323 | 332 | return ret; |
|---|
| 324 | 333 | |
|---|
| 325 | 334 | *val = sign_extend32(val32, 31); |
|---|
| .. | .. |
|---|
| 455 | 464 | [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", |
|---|
| 456 | 465 | }; |
|---|
| 457 | 466 | |
|---|
| 458 | | -static const struct adis_data adis16136_data = { |
|---|
| 459 | | - .diag_stat_reg = ADIS16136_REG_DIAG_STAT, |
|---|
| 460 | | - .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, |
|---|
| 461 | | - .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, |
|---|
| 462 | | - |
|---|
| 463 | | - .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, |
|---|
| 464 | | - .startup_delay = 80, |
|---|
| 465 | | - |
|---|
| 466 | | - .read_delay = 10, |
|---|
| 467 | | - .write_delay = 10, |
|---|
| 468 | | - |
|---|
| 469 | | - .status_error_msgs = adis16136_status_error_msgs, |
|---|
| 470 | | - .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | |
|---|
| 471 | | - BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | |
|---|
| 472 | | - BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | |
|---|
| 473 | | - BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), |
|---|
| 474 | | -}; |
|---|
| 467 | +#define ADIS16136_DATA(_timeouts) \ |
|---|
| 468 | +{ \ |
|---|
| 469 | + .diag_stat_reg = ADIS16136_REG_DIAG_STAT, \ |
|---|
| 470 | + .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, \ |
|---|
| 471 | + .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, \ |
|---|
| 472 | + .self_test_reg = ADIS16136_REG_MSC_CTRL, \ |
|---|
| 473 | + .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, \ |
|---|
| 474 | + .read_delay = 10, \ |
|---|
| 475 | + .write_delay = 10, \ |
|---|
| 476 | + .status_error_msgs = adis16136_status_error_msgs, \ |
|---|
| 477 | + .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | \ |
|---|
| 478 | + BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | \ |
|---|
| 479 | + BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | \ |
|---|
| 480 | + BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), \ |
|---|
| 481 | + .timeouts = (_timeouts), \ |
|---|
| 482 | +} |
|---|
| 475 | 483 | |
|---|
| 476 | 484 | enum adis16136_id { |
|---|
| 477 | 485 | ID_ADIS16133, |
|---|
| .. | .. |
|---|
| 480 | 488 | ID_ADIS16137, |
|---|
| 481 | 489 | }; |
|---|
| 482 | 490 | |
|---|
| 491 | +static const struct adis_timeout adis16133_timeouts = { |
|---|
| 492 | + .reset_ms = 75, |
|---|
| 493 | + .sw_reset_ms = 75, |
|---|
| 494 | + .self_test_ms = 50, |
|---|
| 495 | +}; |
|---|
| 496 | + |
|---|
| 497 | +static const struct adis_timeout adis16136_timeouts = { |
|---|
| 498 | + .reset_ms = 128, |
|---|
| 499 | + .sw_reset_ms = 75, |
|---|
| 500 | + .self_test_ms = 245, |
|---|
| 501 | +}; |
|---|
| 502 | + |
|---|
| 483 | 503 | static const struct adis16136_chip_info adis16136_chip_info[] = { |
|---|
| 484 | 504 | [ID_ADIS16133] = { |
|---|
| 485 | 505 | .precision = IIO_DEGREE_TO_RAD(1200), |
|---|
| 486 | 506 | .fullscale = 24000, |
|---|
| 507 | + .adis_data = ADIS16136_DATA(&adis16133_timeouts), |
|---|
| 487 | 508 | }, |
|---|
| 488 | 509 | [ID_ADIS16135] = { |
|---|
| 489 | 510 | .precision = IIO_DEGREE_TO_RAD(300), |
|---|
| 490 | 511 | .fullscale = 24000, |
|---|
| 512 | + .adis_data = ADIS16136_DATA(&adis16133_timeouts), |
|---|
| 491 | 513 | }, |
|---|
| 492 | 514 | [ID_ADIS16136] = { |
|---|
| 493 | 515 | .precision = IIO_DEGREE_TO_RAD(450), |
|---|
| 494 | 516 | .fullscale = 24623, |
|---|
| 517 | + .adis_data = ADIS16136_DATA(&adis16136_timeouts), |
|---|
| 495 | 518 | }, |
|---|
| 496 | 519 | [ID_ADIS16137] = { |
|---|
| 497 | 520 | .precision = IIO_DEGREE_TO_RAD(1000), |
|---|
| 498 | 521 | .fullscale = 24609, |
|---|
| 522 | + .adis_data = ADIS16136_DATA(&adis16136_timeouts), |
|---|
| 499 | 523 | }, |
|---|
| 500 | 524 | }; |
|---|
| 525 | + |
|---|
| 526 | +static void adis16136_stop(void *data) |
|---|
| 527 | +{ |
|---|
| 528 | + adis16136_stop_device(data); |
|---|
| 529 | +} |
|---|
| 501 | 530 | |
|---|
| 502 | 531 | static int adis16136_probe(struct spi_device *spi) |
|---|
| 503 | 532 | { |
|---|
| 504 | 533 | const struct spi_device_id *id = spi_get_device_id(spi); |
|---|
| 505 | 534 | struct adis16136 *adis16136; |
|---|
| 506 | 535 | struct iio_dev *indio_dev; |
|---|
| 536 | + const struct adis_data *adis16136_data; |
|---|
| 507 | 537 | int ret; |
|---|
| 508 | 538 | |
|---|
| 509 | 539 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136)); |
|---|
| .. | .. |
|---|
| 515 | 545 | adis16136 = iio_priv(indio_dev); |
|---|
| 516 | 546 | |
|---|
| 517 | 547 | adis16136->chip_info = &adis16136_chip_info[id->driver_data]; |
|---|
| 518 | | - indio_dev->dev.parent = &spi->dev; |
|---|
| 519 | 548 | indio_dev->name = spi_get_device_id(spi)->name; |
|---|
| 520 | 549 | indio_dev->channels = adis16136_channels; |
|---|
| 521 | 550 | indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); |
|---|
| 522 | 551 | indio_dev->info = &adis16136_info; |
|---|
| 523 | 552 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 524 | 553 | |
|---|
| 525 | | - ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); |
|---|
| 554 | + adis16136_data = &adis16136->chip_info->adis_data; |
|---|
| 555 | + |
|---|
| 556 | + ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data); |
|---|
| 526 | 557 | if (ret) |
|---|
| 527 | 558 | return ret; |
|---|
| 528 | 559 | |
|---|
| 529 | | - ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); |
|---|
| 560 | + ret = devm_adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); |
|---|
| 530 | 561 | if (ret) |
|---|
| 531 | 562 | return ret; |
|---|
| 532 | 563 | |
|---|
| 533 | 564 | ret = adis16136_initial_setup(indio_dev); |
|---|
| 534 | 565 | if (ret) |
|---|
| 535 | | - goto error_cleanup_buffer; |
|---|
| 566 | + return ret; |
|---|
| 536 | 567 | |
|---|
| 537 | | - ret = iio_device_register(indio_dev); |
|---|
| 568 | + ret = devm_add_action_or_reset(&spi->dev, adis16136_stop, indio_dev); |
|---|
| 538 | 569 | if (ret) |
|---|
| 539 | | - goto error_stop_device; |
|---|
| 570 | + return ret; |
|---|
| 571 | + |
|---|
| 572 | + ret = devm_iio_device_register(&spi->dev, indio_dev); |
|---|
| 573 | + if (ret) |
|---|
| 574 | + return ret; |
|---|
| 540 | 575 | |
|---|
| 541 | 576 | adis16136_debugfs_init(indio_dev); |
|---|
| 542 | | - |
|---|
| 543 | | - return 0; |
|---|
| 544 | | - |
|---|
| 545 | | -error_stop_device: |
|---|
| 546 | | - adis16136_stop_device(indio_dev); |
|---|
| 547 | | -error_cleanup_buffer: |
|---|
| 548 | | - adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); |
|---|
| 549 | | - return ret; |
|---|
| 550 | | -} |
|---|
| 551 | | - |
|---|
| 552 | | -static int adis16136_remove(struct spi_device *spi) |
|---|
| 553 | | -{ |
|---|
| 554 | | - struct iio_dev *indio_dev = spi_get_drvdata(spi); |
|---|
| 555 | | - struct adis16136 *adis16136 = iio_priv(indio_dev); |
|---|
| 556 | | - |
|---|
| 557 | | - iio_device_unregister(indio_dev); |
|---|
| 558 | | - adis16136_stop_device(indio_dev); |
|---|
| 559 | | - |
|---|
| 560 | | - adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); |
|---|
| 561 | 577 | |
|---|
| 562 | 578 | return 0; |
|---|
| 563 | 579 | } |
|---|
| .. | .. |
|---|
| 577 | 593 | }, |
|---|
| 578 | 594 | .id_table = adis16136_ids, |
|---|
| 579 | 595 | .probe = adis16136_probe, |
|---|
| 580 | | - .remove = adis16136_remove, |
|---|
| 581 | 596 | }; |
|---|
| 582 | 597 | module_spi_driver(adis16136_driver); |
|---|
| 583 | 598 | |
|---|