| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Rockchip Successive Approximation Register (SAR) A/D Converter |
|---|
| 3 | 4 | * Copyright (C) 2014 ROCKCHIP, Inc. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 7 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | | - * (at your option) any later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/module.h> |
|---|
| 8 | +#include <linux/mutex.h> |
|---|
| 17 | 9 | #include <linux/platform_device.h> |
|---|
| 18 | 10 | #include <linux/interrupt.h> |
|---|
| 19 | 11 | #include <linux/io.h> |
|---|
| .. | .. |
|---|
| 77 | 69 | struct clk *clk; |
|---|
| 78 | 70 | struct completion completion; |
|---|
| 79 | 71 | struct regulator *vref; |
|---|
| 72 | + /* lock to protect against multiple access to the device */ |
|---|
| 73 | + struct mutex lock; |
|---|
| 80 | 74 | int uv_vref; |
|---|
| 81 | 75 | struct reset_control *reset; |
|---|
| 82 | 76 | const struct rockchip_saradc_data *data; |
|---|
| 83 | 77 | u16 last_val; |
|---|
| 84 | 78 | const struct iio_chan_spec *last_chan; |
|---|
| 79 | + struct notifier_block nb; |
|---|
| 85 | 80 | bool suspended; |
|---|
| 86 | 81 | #ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN |
|---|
| 87 | 82 | bool test; |
|---|
| .. | .. |
|---|
| 197 | 192 | #endif |
|---|
| 198 | 193 | switch (mask) { |
|---|
| 199 | 194 | case IIO_CHAN_INFO_RAW: |
|---|
| 200 | | - mutex_lock(&indio_dev->mlock); |
|---|
| 195 | + mutex_lock(&info->lock); |
|---|
| 201 | 196 | |
|---|
| 202 | 197 | if (info->suspended) { |
|---|
| 203 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 198 | + mutex_unlock(&info->lock); |
|---|
| 204 | 199 | return -EBUSY; |
|---|
| 205 | 200 | } |
|---|
| 206 | 201 | |
|---|
| 207 | 202 | ret = rockchip_saradc_conversion(info, chan); |
|---|
| 208 | 203 | if (ret) { |
|---|
| 209 | 204 | rockchip_saradc_power_down(info); |
|---|
| 210 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 205 | + mutex_unlock(&info->lock); |
|---|
| 211 | 206 | return ret; |
|---|
| 212 | 207 | } |
|---|
| 213 | 208 | |
|---|
| 214 | 209 | *val = info->last_val; |
|---|
| 215 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 210 | + mutex_unlock(&info->lock); |
|---|
| 216 | 211 | return IIO_VAL_INT; |
|---|
| 217 | 212 | case IIO_CHAN_INFO_SCALE: |
|---|
| 218 | 213 | /* It is a dummy regulator */ |
|---|
| .. | .. |
|---|
| 321 | 316 | .power_down = rockchip_saradc_power_down_v1, |
|---|
| 322 | 317 | }; |
|---|
| 323 | 318 | |
|---|
| 319 | +static const struct iio_chan_spec rockchip_rk3528_saradc_iio_channels[] = { |
|---|
| 320 | + SARADC_CHANNEL(0, "adc0", 10), |
|---|
| 321 | + SARADC_CHANNEL(1, "adc1", 10), |
|---|
| 322 | + SARADC_CHANNEL(2, "adc2", 10), |
|---|
| 323 | + SARADC_CHANNEL(3, "adc3", 10), |
|---|
| 324 | +}; |
|---|
| 325 | + |
|---|
| 326 | +static const struct rockchip_saradc_data rk3528_saradc_data = { |
|---|
| 327 | + .channels = rockchip_rk3528_saradc_iio_channels, |
|---|
| 328 | + .num_channels = ARRAY_SIZE(rockchip_rk3528_saradc_iio_channels), |
|---|
| 329 | + .clk_rate = 1000000, |
|---|
| 330 | + .start = rockchip_saradc_start_v2, |
|---|
| 331 | + .read = rockchip_saradc_read_v2, |
|---|
| 332 | +}; |
|---|
| 333 | + |
|---|
| 334 | +static const struct iio_chan_spec rockchip_rk3562_saradc_iio_channels[] = { |
|---|
| 335 | + SARADC_CHANNEL(0, "adc0", 10), |
|---|
| 336 | + SARADC_CHANNEL(1, "adc1", 10), |
|---|
| 337 | + SARADC_CHANNEL(2, "adc2", 10), |
|---|
| 338 | + SARADC_CHANNEL(3, "adc3", 10), |
|---|
| 339 | + SARADC_CHANNEL(4, "adc4", 10), |
|---|
| 340 | + SARADC_CHANNEL(5, "adc5", 10), |
|---|
| 341 | + SARADC_CHANNEL(6, "adc6", 10), |
|---|
| 342 | + SARADC_CHANNEL(7, "adc7", 10), |
|---|
| 343 | +}; |
|---|
| 344 | + |
|---|
| 345 | +static const struct rockchip_saradc_data rk3562_saradc_data = { |
|---|
| 346 | + .channels = rockchip_rk3562_saradc_iio_channels, |
|---|
| 347 | + .num_channels = ARRAY_SIZE(rockchip_rk3562_saradc_iio_channels), |
|---|
| 348 | + .clk_rate = 1000000, |
|---|
| 349 | + .start = rockchip_saradc_start_v2, |
|---|
| 350 | + .read = rockchip_saradc_read_v2, |
|---|
| 351 | +}; |
|---|
| 352 | + |
|---|
| 324 | 353 | static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = { |
|---|
| 325 | 354 | SARADC_CHANNEL(0, "adc0", 10), |
|---|
| 326 | 355 | SARADC_CHANNEL(1, "adc1", 10), |
|---|
| .. | .. |
|---|
| 384 | 413 | .compatible = "rockchip,rk3399-saradc", |
|---|
| 385 | 414 | .data = &rk3399_saradc_data, |
|---|
| 386 | 415 | }, { |
|---|
| 416 | + .compatible = "rockchip,rk3528-saradc", |
|---|
| 417 | + .data = &rk3528_saradc_data, |
|---|
| 418 | + }, { |
|---|
| 419 | + .compatible = "rockchip,rk3562-saradc", |
|---|
| 420 | + .data = &rk3562_saradc_data, |
|---|
| 421 | + }, { |
|---|
| 387 | 422 | .compatible = "rockchip,rk3568-saradc", |
|---|
| 388 | 423 | .data = &rk3568_saradc_data, |
|---|
| 389 | 424 | }, { |
|---|
| .. | .. |
|---|
| 397 | 432 | }; |
|---|
| 398 | 433 | MODULE_DEVICE_TABLE(of, rockchip_saradc_match); |
|---|
| 399 | 434 | |
|---|
| 400 | | -/** |
|---|
| 435 | +/* |
|---|
| 401 | 436 | * Reset SARADC Controller. |
|---|
| 402 | 437 | */ |
|---|
| 403 | 438 | static void rockchip_saradc_reset_controller(struct reset_control *reset) |
|---|
| .. | .. |
|---|
| 444 | 479 | int ret; |
|---|
| 445 | 480 | int i, j = 0; |
|---|
| 446 | 481 | |
|---|
| 447 | | - mutex_lock(&i_dev->mlock); |
|---|
| 482 | + mutex_lock(&info->lock); |
|---|
| 448 | 483 | |
|---|
| 449 | 484 | for_each_set_bit(i, i_dev->active_scan_mask, i_dev->masklength) { |
|---|
| 450 | 485 | const struct iio_chan_spec *chan = &i_dev->channels[i]; |
|---|
| .. | .. |
|---|
| 461 | 496 | |
|---|
| 462 | 497 | iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev)); |
|---|
| 463 | 498 | out: |
|---|
| 464 | | - mutex_unlock(&i_dev->mlock); |
|---|
| 499 | + mutex_unlock(&info->lock); |
|---|
| 465 | 500 | |
|---|
| 466 | 501 | iio_trigger_notify_done(i_dev->trig); |
|---|
| 467 | 502 | |
|---|
| 468 | 503 | return IRQ_HANDLED; |
|---|
| 504 | +} |
|---|
| 505 | + |
|---|
| 506 | +static int rockchip_saradc_volt_notify(struct notifier_block *nb, |
|---|
| 507 | + unsigned long event, |
|---|
| 508 | + void *data) |
|---|
| 509 | +{ |
|---|
| 510 | + struct rockchip_saradc *info = |
|---|
| 511 | + container_of(nb, struct rockchip_saradc, nb); |
|---|
| 512 | + |
|---|
| 513 | + if (event & REGULATOR_EVENT_VOLTAGE_CHANGE) |
|---|
| 514 | + info->uv_vref = (unsigned long)data; |
|---|
| 515 | + |
|---|
| 516 | + return NOTIFY_OK; |
|---|
| 517 | +} |
|---|
| 518 | + |
|---|
| 519 | +static void rockchip_saradc_regulator_unreg_notifier(void *data) |
|---|
| 520 | +{ |
|---|
| 521 | + struct rockchip_saradc *info = data; |
|---|
| 522 | + |
|---|
| 523 | + regulator_unregister_notifier(info->vref, &info->nb); |
|---|
| 469 | 524 | } |
|---|
| 470 | 525 | |
|---|
| 471 | 526 | #ifdef CONFIG_ROCKCHIP_SARADC_TEST_CHN |
|---|
| .. | .. |
|---|
| 492 | 547 | return size; |
|---|
| 493 | 548 | } |
|---|
| 494 | 549 | |
|---|
| 495 | | - if (!info->test && val < SARADC_CTRL_CHN_MASK) { |
|---|
| 550 | + if (!info->test && val <= SARADC_CTRL_CHN_MASK) { |
|---|
| 496 | 551 | info->test = true; |
|---|
| 497 | 552 | info->chn = val; |
|---|
| 498 | 553 | mod_delayed_work(info->wq, &info->work, msecs_to_jiffies(100)); |
|---|
| .. | .. |
|---|
| 594 | 649 | init_completion(&info->completion); |
|---|
| 595 | 650 | |
|---|
| 596 | 651 | irq = platform_get_irq(pdev, 0); |
|---|
| 597 | | - if (irq < 0) { |
|---|
| 598 | | - dev_err(&pdev->dev, "no irq resource?\n"); |
|---|
| 652 | + if (irq < 0) |
|---|
| 599 | 653 | return irq; |
|---|
| 600 | | - } |
|---|
| 601 | 654 | |
|---|
| 602 | 655 | ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, |
|---|
| 603 | 656 | 0, dev_name(&pdev->dev), info); |
|---|
| .. | .. |
|---|
| 651 | 704 | return ret; |
|---|
| 652 | 705 | } |
|---|
| 653 | 706 | |
|---|
| 654 | | - info->uv_vref = regulator_get_voltage(info->vref); |
|---|
| 655 | | - if (info->uv_vref < 0) { |
|---|
| 707 | + ret = regulator_get_voltage(info->vref); |
|---|
| 708 | + if (ret < 0) { |
|---|
| 656 | 709 | dev_err(&pdev->dev, "failed to get voltage\n"); |
|---|
| 657 | | - ret = info->uv_vref; |
|---|
| 658 | 710 | return ret; |
|---|
| 659 | 711 | } |
|---|
| 712 | + |
|---|
| 713 | + info->uv_vref = ret; |
|---|
| 660 | 714 | |
|---|
| 661 | 715 | ret = clk_prepare_enable(info->pclk); |
|---|
| 662 | 716 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 687 | 741 | platform_set_drvdata(pdev, indio_dev); |
|---|
| 688 | 742 | |
|---|
| 689 | 743 | indio_dev->name = dev_name(&pdev->dev); |
|---|
| 690 | | - indio_dev->dev.parent = &pdev->dev; |
|---|
| 691 | | - indio_dev->dev.of_node = pdev->dev.of_node; |
|---|
| 692 | 744 | indio_dev->info = &rockchip_saradc_iio_info; |
|---|
| 693 | 745 | indio_dev->modes = INDIO_DIRECT_MODE; |
|---|
| 694 | 746 | |
|---|
| .. | .. |
|---|
| 697 | 749 | ret = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL, |
|---|
| 698 | 750 | rockchip_saradc_trigger_handler, |
|---|
| 699 | 751 | NULL); |
|---|
| 752 | + if (ret) |
|---|
| 753 | + return ret; |
|---|
| 754 | + |
|---|
| 755 | + info->nb.notifier_call = rockchip_saradc_volt_notify; |
|---|
| 756 | + ret = regulator_register_notifier(info->vref, &info->nb); |
|---|
| 757 | + if (ret) |
|---|
| 758 | + return ret; |
|---|
| 759 | + |
|---|
| 760 | + ret = devm_add_action_or_reset(&pdev->dev, |
|---|
| 761 | + rockchip_saradc_regulator_unreg_notifier, |
|---|
| 762 | + info); |
|---|
| 700 | 763 | if (ret) |
|---|
| 701 | 764 | return ret; |
|---|
| 702 | 765 | |
|---|
| .. | .. |
|---|
| 724 | 787 | return ret; |
|---|
| 725 | 788 | } |
|---|
| 726 | 789 | #endif |
|---|
| 790 | + mutex_init(&info->lock); |
|---|
| 791 | + |
|---|
| 727 | 792 | return devm_iio_device_register(&pdev->dev, indio_dev); |
|---|
| 728 | 793 | } |
|---|
| 729 | 794 | |
|---|
| .. | .. |
|---|
| 734 | 799 | struct rockchip_saradc *info = iio_priv(indio_dev); |
|---|
| 735 | 800 | |
|---|
| 736 | 801 | /* Avoid reading saradc when suspending */ |
|---|
| 737 | | - mutex_lock(&indio_dev->mlock); |
|---|
| 802 | + mutex_lock(&info->lock); |
|---|
| 738 | 803 | |
|---|
| 739 | 804 | clk_disable_unprepare(info->clk); |
|---|
| 740 | 805 | clk_disable_unprepare(info->pclk); |
|---|
| 741 | 806 | regulator_disable(info->vref); |
|---|
| 742 | 807 | |
|---|
| 743 | 808 | info->suspended = true; |
|---|
| 744 | | - mutex_unlock(&indio_dev->mlock); |
|---|
| 809 | + mutex_unlock(&info->lock); |
|---|
| 745 | 810 | |
|---|
| 746 | 811 | return 0; |
|---|
| 747 | 812 | } |
|---|
| .. | .. |
|---|
| 782 | 847 | }, |
|---|
| 783 | 848 | }; |
|---|
| 784 | 849 | |
|---|
| 785 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
|---|
| 786 | | -static int __init rockchip_saradc_driver_init(void) |
|---|
| 787 | | -{ |
|---|
| 788 | | - return platform_driver_register(&rockchip_saradc_driver); |
|---|
| 789 | | -} |
|---|
| 790 | | -fs_initcall(rockchip_saradc_driver_init); |
|---|
| 791 | | - |
|---|
| 792 | | -static void __exit rockchip_saradc_driver_exit(void) |
|---|
| 793 | | -{ |
|---|
| 794 | | - platform_driver_unregister(&rockchip_saradc_driver); |
|---|
| 795 | | -} |
|---|
| 796 | | -module_exit(rockchip_saradc_driver_exit); |
|---|
| 797 | | -#else |
|---|
| 798 | 850 | module_platform_driver(rockchip_saradc_driver); |
|---|
| 799 | | -#endif |
|---|
| 800 | 851 | |
|---|
| 801 | 852 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); |
|---|
| 802 | 853 | MODULE_DESCRIPTION("Rockchip SARADC driver"); |
|---|