| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * clk-dfll.c - Tegra DFLL clock source common code |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. |
|---|
| 5 | + * Copyright (C) 2012-2019 NVIDIA Corporation. All rights reserved. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Aleksandr Frid <afrid@nvidia.com> |
|---|
| 7 | 8 | * Paul Walmsley <pwalmsley@nvidia.com> |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 11 | | - * published by the Free Software Foundation. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 14 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 15 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 16 | | - * more details. |
|---|
| 17 | 9 | * |
|---|
| 18 | 10 | * This library is for the DVCO and DFLL IP blocks on the Tegra124 |
|---|
| 19 | 11 | * SoC. These IP blocks together are also known at NVIDIA as |
|---|
| .. | .. |
|---|
| 34 | 26 | * CPU cycle time will vary. This has implications for |
|---|
| 35 | 27 | * performance-measurement code and any code that relies on the CPU |
|---|
| 36 | 28 | * cycle time to delay for a certain length of time. |
|---|
| 37 | | - * |
|---|
| 38 | 29 | */ |
|---|
| 39 | 30 | |
|---|
| 40 | 31 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 47 | 38 | #include <linux/kernel.h> |
|---|
| 48 | 39 | #include <linux/module.h> |
|---|
| 49 | 40 | #include <linux/of.h> |
|---|
| 41 | +#include <linux/pinctrl/consumer.h> |
|---|
| 50 | 42 | #include <linux/pm_opp.h> |
|---|
| 51 | 43 | #include <linux/pm_runtime.h> |
|---|
| 52 | 44 | #include <linux/regmap.h> |
|---|
| .. | .. |
|---|
| 243 | 235 | DFLL_TUNE_LOW = 1, |
|---|
| 244 | 236 | }; |
|---|
| 245 | 237 | |
|---|
| 238 | + |
|---|
| 239 | +enum tegra_dfll_pmu_if { |
|---|
| 240 | + TEGRA_DFLL_PMU_I2C = 0, |
|---|
| 241 | + TEGRA_DFLL_PMU_PWM = 1, |
|---|
| 242 | +}; |
|---|
| 243 | + |
|---|
| 246 | 244 | /** |
|---|
| 247 | 245 | * struct dfll_rate_req - target DFLL rate request data |
|---|
| 248 | 246 | * @rate: target frequency, after the postscaling |
|---|
| .. | .. |
|---|
| 300 | 298 | u32 i2c_reg; |
|---|
| 301 | 299 | u32 i2c_slave_addr; |
|---|
| 302 | 300 | |
|---|
| 303 | | - /* i2c_lut array entries are regulator framework selectors */ |
|---|
| 304 | | - unsigned i2c_lut[MAX_DFLL_VOLTAGES]; |
|---|
| 305 | | - int i2c_lut_size; |
|---|
| 306 | | - u8 lut_min, lut_max, lut_safe; |
|---|
| 301 | + /* lut array entries are regulator framework selectors or PWM values*/ |
|---|
| 302 | + unsigned lut[MAX_DFLL_VOLTAGES]; |
|---|
| 303 | + unsigned long lut_uv[MAX_DFLL_VOLTAGES]; |
|---|
| 304 | + int lut_size; |
|---|
| 305 | + u8 lut_bottom, lut_min, lut_max, lut_safe; |
|---|
| 306 | + |
|---|
| 307 | + /* PWM interface */ |
|---|
| 308 | + enum tegra_dfll_pmu_if pmu_if; |
|---|
| 309 | + unsigned long pwm_rate; |
|---|
| 310 | + struct pinctrl *pwm_pin; |
|---|
| 311 | + struct pinctrl_state *pwm_enable_state; |
|---|
| 312 | + struct pinctrl_state *pwm_disable_state; |
|---|
| 313 | + u32 reg_init_uV; |
|---|
| 307 | 314 | }; |
|---|
| 308 | 315 | |
|---|
| 309 | 316 | #define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw) |
|---|
| .. | .. |
|---|
| 490 | 497 | } |
|---|
| 491 | 498 | |
|---|
| 492 | 499 | /* |
|---|
| 500 | + * DVCO rate control |
|---|
| 501 | + */ |
|---|
| 502 | + |
|---|
| 503 | +static unsigned long get_dvco_rate_below(struct tegra_dfll *td, u8 out_min) |
|---|
| 504 | +{ |
|---|
| 505 | + struct dev_pm_opp *opp; |
|---|
| 506 | + unsigned long rate, prev_rate; |
|---|
| 507 | + unsigned long uv, min_uv; |
|---|
| 508 | + |
|---|
| 509 | + min_uv = td->lut_uv[out_min]; |
|---|
| 510 | + for (rate = 0, prev_rate = 0; ; rate++) { |
|---|
| 511 | + opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
|---|
| 512 | + if (IS_ERR(opp)) |
|---|
| 513 | + break; |
|---|
| 514 | + |
|---|
| 515 | + uv = dev_pm_opp_get_voltage(opp); |
|---|
| 516 | + dev_pm_opp_put(opp); |
|---|
| 517 | + |
|---|
| 518 | + if (uv && uv > min_uv) |
|---|
| 519 | + return prev_rate; |
|---|
| 520 | + |
|---|
| 521 | + prev_rate = rate; |
|---|
| 522 | + } |
|---|
| 523 | + |
|---|
| 524 | + return prev_rate; |
|---|
| 525 | +} |
|---|
| 526 | + |
|---|
| 527 | +/* |
|---|
| 493 | 528 | * DFLL-to-I2C controller interface |
|---|
| 494 | 529 | */ |
|---|
| 495 | 530 | |
|---|
| .. | .. |
|---|
| 518 | 553 | return 0; |
|---|
| 519 | 554 | } |
|---|
| 520 | 555 | |
|---|
| 556 | + |
|---|
| 557 | +/* |
|---|
| 558 | + * DFLL-to-PWM controller interface |
|---|
| 559 | + */ |
|---|
| 560 | + |
|---|
| 561 | +/** |
|---|
| 562 | + * dfll_pwm_set_output_enabled - enable/disable PWM voltage requests |
|---|
| 563 | + * @td: DFLL instance |
|---|
| 564 | + * @enable: whether to enable or disable the PWM voltage requests |
|---|
| 565 | + * |
|---|
| 566 | + * Set the master enable control for PWM control value updates. If disabled, |
|---|
| 567 | + * then the PWM signal is not driven. Also configure the PWM output pad |
|---|
| 568 | + * to the appropriate state. |
|---|
| 569 | + */ |
|---|
| 570 | +static int dfll_pwm_set_output_enabled(struct tegra_dfll *td, bool enable) |
|---|
| 571 | +{ |
|---|
| 572 | + int ret; |
|---|
| 573 | + u32 val, div; |
|---|
| 574 | + |
|---|
| 575 | + if (enable) { |
|---|
| 576 | + ret = pinctrl_select_state(td->pwm_pin, td->pwm_enable_state); |
|---|
| 577 | + if (ret < 0) { |
|---|
| 578 | + dev_err(td->dev, "setting enable state failed\n"); |
|---|
| 579 | + return -EINVAL; |
|---|
| 580 | + } |
|---|
| 581 | + val = dfll_readl(td, DFLL_OUTPUT_CFG); |
|---|
| 582 | + val &= ~DFLL_OUTPUT_CFG_PWM_DIV_MASK; |
|---|
| 583 | + div = DIV_ROUND_UP(td->ref_rate, td->pwm_rate); |
|---|
| 584 | + val |= (div << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT) |
|---|
| 585 | + & DFLL_OUTPUT_CFG_PWM_DIV_MASK; |
|---|
| 586 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
|---|
| 587 | + dfll_wmb(td); |
|---|
| 588 | + |
|---|
| 589 | + val |= DFLL_OUTPUT_CFG_PWM_ENABLE; |
|---|
| 590 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
|---|
| 591 | + dfll_wmb(td); |
|---|
| 592 | + } else { |
|---|
| 593 | + ret = pinctrl_select_state(td->pwm_pin, td->pwm_disable_state); |
|---|
| 594 | + if (ret < 0) |
|---|
| 595 | + dev_warn(td->dev, "setting disable state failed\n"); |
|---|
| 596 | + |
|---|
| 597 | + val = dfll_readl(td, DFLL_OUTPUT_CFG); |
|---|
| 598 | + val &= ~DFLL_OUTPUT_CFG_PWM_ENABLE; |
|---|
| 599 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
|---|
| 600 | + dfll_wmb(td); |
|---|
| 601 | + } |
|---|
| 602 | + |
|---|
| 603 | + return 0; |
|---|
| 604 | +} |
|---|
| 605 | + |
|---|
| 606 | +/** |
|---|
| 607 | + * dfll_set_force_output_value - set fixed value for force output |
|---|
| 608 | + * @td: DFLL instance |
|---|
| 609 | + * @out_val: value to force output |
|---|
| 610 | + * |
|---|
| 611 | + * Set the fixed value for force output, DFLL will output this value when |
|---|
| 612 | + * force output is enabled. |
|---|
| 613 | + */ |
|---|
| 614 | +static u32 dfll_set_force_output_value(struct tegra_dfll *td, u8 out_val) |
|---|
| 615 | +{ |
|---|
| 616 | + u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE); |
|---|
| 617 | + |
|---|
| 618 | + val = (val & DFLL_OUTPUT_FORCE_ENABLE) | (out_val & OUT_MASK); |
|---|
| 619 | + dfll_writel(td, val, DFLL_OUTPUT_FORCE); |
|---|
| 620 | + dfll_wmb(td); |
|---|
| 621 | + |
|---|
| 622 | + return dfll_readl(td, DFLL_OUTPUT_FORCE); |
|---|
| 623 | +} |
|---|
| 624 | + |
|---|
| 625 | +/** |
|---|
| 626 | + * dfll_set_force_output_enabled - enable/disable force output |
|---|
| 627 | + * @td: DFLL instance |
|---|
| 628 | + * @enable: whether to enable or disable the force output |
|---|
| 629 | + * |
|---|
| 630 | + * Set the enable control for fouce output with fixed value. |
|---|
| 631 | + */ |
|---|
| 632 | +static void dfll_set_force_output_enabled(struct tegra_dfll *td, bool enable) |
|---|
| 633 | +{ |
|---|
| 634 | + u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE); |
|---|
| 635 | + |
|---|
| 636 | + if (enable) |
|---|
| 637 | + val |= DFLL_OUTPUT_FORCE_ENABLE; |
|---|
| 638 | + else |
|---|
| 639 | + val &= ~DFLL_OUTPUT_FORCE_ENABLE; |
|---|
| 640 | + |
|---|
| 641 | + dfll_writel(td, val, DFLL_OUTPUT_FORCE); |
|---|
| 642 | + dfll_wmb(td); |
|---|
| 643 | +} |
|---|
| 644 | + |
|---|
| 645 | +/** |
|---|
| 646 | + * dfll_force_output - force output a fixed value |
|---|
| 647 | + * @td: DFLL instance |
|---|
| 648 | + * @out_sel: value to force output |
|---|
| 649 | + * |
|---|
| 650 | + * Set the fixed value for force output, DFLL will output this value. |
|---|
| 651 | + */ |
|---|
| 652 | +static int dfll_force_output(struct tegra_dfll *td, unsigned int out_sel) |
|---|
| 653 | +{ |
|---|
| 654 | + u32 val; |
|---|
| 655 | + |
|---|
| 656 | + if (out_sel > OUT_MASK) |
|---|
| 657 | + return -EINVAL; |
|---|
| 658 | + |
|---|
| 659 | + val = dfll_set_force_output_value(td, out_sel); |
|---|
| 660 | + if ((td->mode < DFLL_CLOSED_LOOP) && |
|---|
| 661 | + !(val & DFLL_OUTPUT_FORCE_ENABLE)) { |
|---|
| 662 | + dfll_set_force_output_enabled(td, true); |
|---|
| 663 | + } |
|---|
| 664 | + |
|---|
| 665 | + return 0; |
|---|
| 666 | +} |
|---|
| 667 | + |
|---|
| 521 | 668 | /** |
|---|
| 522 | 669 | * dfll_load_lut - load the voltage lookup table |
|---|
| 523 | 670 | * @td: struct tegra_dfll * |
|---|
| .. | .. |
|---|
| 539 | 686 | lut_index = i; |
|---|
| 540 | 687 | |
|---|
| 541 | 688 | val = regulator_list_hardware_vsel(td->vdd_reg, |
|---|
| 542 | | - td->i2c_lut[lut_index]); |
|---|
| 689 | + td->lut[lut_index]); |
|---|
| 543 | 690 | __raw_writel(val, td->lut_base + i * 4); |
|---|
| 544 | 691 | } |
|---|
| 545 | 692 | |
|---|
| .. | .. |
|---|
| 594 | 741 | { |
|---|
| 595 | 742 | u32 val; |
|---|
| 596 | 743 | |
|---|
| 597 | | - td->lut_min = 0; |
|---|
| 598 | | - td->lut_max = td->i2c_lut_size - 1; |
|---|
| 599 | | - td->lut_safe = td->lut_min + 1; |
|---|
| 744 | + td->lut_min = td->lut_bottom; |
|---|
| 745 | + td->lut_max = td->lut_size - 1; |
|---|
| 746 | + td->lut_safe = td->lut_min + (td->lut_min < td->lut_max ? 1 : 0); |
|---|
| 600 | 747 | |
|---|
| 601 | | - dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG); |
|---|
| 748 | + /* clear DFLL_OUTPUT_CFG before setting new value */ |
|---|
| 749 | + dfll_writel(td, 0, DFLL_OUTPUT_CFG); |
|---|
| 750 | + dfll_wmb(td); |
|---|
| 751 | + |
|---|
| 602 | 752 | val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) | |
|---|
| 603 | | - (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) | |
|---|
| 604 | | - (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT); |
|---|
| 605 | | - dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG); |
|---|
| 606 | | - dfll_i2c_wmb(td); |
|---|
| 753 | + (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) | |
|---|
| 754 | + (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT); |
|---|
| 755 | + dfll_writel(td, val, DFLL_OUTPUT_CFG); |
|---|
| 756 | + dfll_wmb(td); |
|---|
| 607 | 757 | |
|---|
| 608 | 758 | dfll_writel(td, 0, DFLL_OUTPUT_FORCE); |
|---|
| 609 | 759 | dfll_i2c_writel(td, 0, DFLL_INTR_EN); |
|---|
| 610 | 760 | dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK, |
|---|
| 611 | 761 | DFLL_INTR_STS); |
|---|
| 612 | 762 | |
|---|
| 613 | | - dfll_load_i2c_lut(td); |
|---|
| 614 | | - dfll_init_i2c_if(td); |
|---|
| 763 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) { |
|---|
| 764 | + u32 vinit = td->reg_init_uV; |
|---|
| 765 | + int vstep = td->soc->alignment.step_uv; |
|---|
| 766 | + unsigned long vmin = td->lut_uv[0]; |
|---|
| 767 | + |
|---|
| 768 | + /* set initial voltage */ |
|---|
| 769 | + if ((vinit >= vmin) && vstep) { |
|---|
| 770 | + unsigned int vsel; |
|---|
| 771 | + |
|---|
| 772 | + vsel = DIV_ROUND_UP((vinit - vmin), vstep); |
|---|
| 773 | + dfll_force_output(td, vsel); |
|---|
| 774 | + } |
|---|
| 775 | + } else { |
|---|
| 776 | + dfll_load_i2c_lut(td); |
|---|
| 777 | + dfll_init_i2c_if(td); |
|---|
| 778 | + } |
|---|
| 615 | 779 | } |
|---|
| 616 | 780 | |
|---|
| 617 | 781 | /* |
|---|
| .. | .. |
|---|
| 631 | 795 | static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) |
|---|
| 632 | 796 | { |
|---|
| 633 | 797 | struct dev_pm_opp *opp; |
|---|
| 634 | | - int i, uv; |
|---|
| 798 | + int i, align_step; |
|---|
| 635 | 799 | |
|---|
| 636 | 800 | opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
|---|
| 637 | 801 | if (IS_ERR(opp)) |
|---|
| 638 | 802 | return PTR_ERR(opp); |
|---|
| 639 | 803 | |
|---|
| 640 | | - uv = dev_pm_opp_get_voltage(opp); |
|---|
| 804 | + align_step = dev_pm_opp_get_voltage(opp) / td->soc->alignment.step_uv; |
|---|
| 641 | 805 | dev_pm_opp_put(opp); |
|---|
| 642 | 806 | |
|---|
| 643 | | - for (i = 0; i < td->i2c_lut_size; i++) { |
|---|
| 644 | | - if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv) |
|---|
| 807 | + for (i = td->lut_bottom; i < td->lut_size; i++) { |
|---|
| 808 | + if ((td->lut_uv[i] / td->soc->alignment.step_uv) >= align_step) |
|---|
| 645 | 809 | return i; |
|---|
| 646 | 810 | } |
|---|
| 647 | 811 | |
|---|
| .. | .. |
|---|
| 863 | 1027 | return -EINVAL; |
|---|
| 864 | 1028 | } |
|---|
| 865 | 1029 | |
|---|
| 866 | | - dfll_i2c_set_output_enabled(td, true); |
|---|
| 1030 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
|---|
| 1031 | + dfll_pwm_set_output_enabled(td, true); |
|---|
| 1032 | + else |
|---|
| 1033 | + dfll_i2c_set_output_enabled(td, true); |
|---|
| 1034 | + |
|---|
| 867 | 1035 | dfll_set_mode(td, DFLL_CLOSED_LOOP); |
|---|
| 868 | 1036 | dfll_set_frequency_request(td, req); |
|---|
| 1037 | + dfll_set_force_output_enabled(td, false); |
|---|
| 869 | 1038 | return 0; |
|---|
| 870 | 1039 | |
|---|
| 871 | 1040 | default: |
|---|
| .. | .. |
|---|
| 889 | 1058 | case DFLL_CLOSED_LOOP: |
|---|
| 890 | 1059 | dfll_set_open_loop_config(td); |
|---|
| 891 | 1060 | dfll_set_mode(td, DFLL_OPEN_LOOP); |
|---|
| 892 | | - dfll_i2c_set_output_enabled(td, false); |
|---|
| 1061 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
|---|
| 1062 | + dfll_pwm_set_output_enabled(td, false); |
|---|
| 1063 | + else |
|---|
| 1064 | + dfll_i2c_set_output_enabled(td, false); |
|---|
| 893 | 1065 | return 0; |
|---|
| 894 | 1066 | |
|---|
| 895 | 1067 | case DFLL_OPEN_LOOP: |
|---|
| .. | .. |
|---|
| 1112 | 1284 | |
|---|
| 1113 | 1285 | return val ? dfll_enable(td) : dfll_disable(td); |
|---|
| 1114 | 1286 | } |
|---|
| 1115 | | -DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, |
|---|
| 1116 | | - "%llu\n"); |
|---|
| 1287 | +DEFINE_DEBUGFS_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, |
|---|
| 1288 | + "%llu\n"); |
|---|
| 1117 | 1289 | |
|---|
| 1118 | 1290 | static int attr_lock_get(void *data, u64 *val) |
|---|
| 1119 | 1291 | { |
|---|
| .. | .. |
|---|
| 1129 | 1301 | |
|---|
| 1130 | 1302 | return val ? dfll_lock(td) : dfll_unlock(td); |
|---|
| 1131 | 1303 | } |
|---|
| 1132 | | -DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, |
|---|
| 1133 | | - "%llu\n"); |
|---|
| 1304 | +DEFINE_DEBUGFS_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, "%llu\n"); |
|---|
| 1134 | 1305 | |
|---|
| 1135 | 1306 | static int attr_rate_get(void *data, u64 *val) |
|---|
| 1136 | 1307 | { |
|---|
| .. | .. |
|---|
| 1147 | 1318 | |
|---|
| 1148 | 1319 | return dfll_request_rate(td, val); |
|---|
| 1149 | 1320 | } |
|---|
| 1150 | | -DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); |
|---|
| 1321 | +DEFINE_DEBUGFS_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); |
|---|
| 1151 | 1322 | |
|---|
| 1152 | 1323 | static int attr_registers_show(struct seq_file *s, void *data) |
|---|
| 1153 | 1324 | { |
|---|
| .. | .. |
|---|
| 1171 | 1342 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
|---|
| 1172 | 1343 | dfll_i2c_readl(td, offs)); |
|---|
| 1173 | 1344 | |
|---|
| 1174 | | - seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); |
|---|
| 1175 | | - offs = DFLL_I2C_CLK_DIVISOR; |
|---|
| 1176 | | - seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
|---|
| 1177 | | - __raw_readl(td->i2c_controller_base + offs)); |
|---|
| 1178 | | - |
|---|
| 1179 | | - seq_puts(s, "\nLUT:\n"); |
|---|
| 1180 | | - for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) |
|---|
| 1345 | + if (td->pmu_if == TEGRA_DFLL_PMU_I2C) { |
|---|
| 1346 | + seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); |
|---|
| 1347 | + offs = DFLL_I2C_CLK_DIVISOR; |
|---|
| 1181 | 1348 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
|---|
| 1182 | | - __raw_readl(td->lut_base + offs)); |
|---|
| 1349 | + __raw_readl(td->i2c_controller_base + offs)); |
|---|
| 1350 | + |
|---|
| 1351 | + seq_puts(s, "\nLUT:\n"); |
|---|
| 1352 | + for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) |
|---|
| 1353 | + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, |
|---|
| 1354 | + __raw_readl(td->lut_base + offs)); |
|---|
| 1355 | + } |
|---|
| 1183 | 1356 | |
|---|
| 1184 | 1357 | return 0; |
|---|
| 1185 | 1358 | } |
|---|
| 1186 | 1359 | |
|---|
| 1187 | | -static int attr_registers_open(struct inode *inode, struct file *file) |
|---|
| 1188 | | -{ |
|---|
| 1189 | | - return single_open(file, attr_registers_show, inode->i_private); |
|---|
| 1190 | | -} |
|---|
| 1191 | | - |
|---|
| 1192 | | -static const struct file_operations attr_registers_fops = { |
|---|
| 1193 | | - .open = attr_registers_open, |
|---|
| 1194 | | - .read = seq_read, |
|---|
| 1195 | | - .llseek = seq_lseek, |
|---|
| 1196 | | - .release = single_release, |
|---|
| 1197 | | -}; |
|---|
| 1360 | +DEFINE_SHOW_ATTRIBUTE(attr_registers); |
|---|
| 1198 | 1361 | |
|---|
| 1199 | 1362 | static void dfll_debug_init(struct tegra_dfll *td) |
|---|
| 1200 | 1363 | { |
|---|
| .. | .. |
|---|
| 1206 | 1369 | root = debugfs_create_dir("tegra_dfll_fcpu", NULL); |
|---|
| 1207 | 1370 | td->debugfs_dir = root; |
|---|
| 1208 | 1371 | |
|---|
| 1209 | | - debugfs_create_file("enable", S_IRUGO | S_IWUSR, root, td, &enable_fops); |
|---|
| 1210 | | - debugfs_create_file("lock", S_IRUGO, root, td, &lock_fops); |
|---|
| 1211 | | - debugfs_create_file("rate", S_IRUGO, root, td, &rate_fops); |
|---|
| 1212 | | - debugfs_create_file("registers", S_IRUGO, root, td, &attr_registers_fops); |
|---|
| 1372 | + debugfs_create_file_unsafe("enable", 0644, root, td, |
|---|
| 1373 | + &enable_fops); |
|---|
| 1374 | + debugfs_create_file_unsafe("lock", 0444, root, td, &lock_fops); |
|---|
| 1375 | + debugfs_create_file_unsafe("rate", 0444, root, td, &rate_fops); |
|---|
| 1376 | + debugfs_create_file("registers", 0444, root, td, &attr_registers_fops); |
|---|
| 1213 | 1377 | } |
|---|
| 1214 | 1378 | |
|---|
| 1215 | 1379 | #else |
|---|
| .. | .. |
|---|
| 1349 | 1513 | return ret; |
|---|
| 1350 | 1514 | } |
|---|
| 1351 | 1515 | |
|---|
| 1516 | +/** |
|---|
| 1517 | + * tegra_dfll_suspend - check DFLL is disabled |
|---|
| 1518 | + * @dev: DFLL instance |
|---|
| 1519 | + * |
|---|
| 1520 | + * DFLL clock should be disabled by the CPUFreq driver. So, make |
|---|
| 1521 | + * sure it is disabled and disable all clocks needed by the DFLL. |
|---|
| 1522 | + */ |
|---|
| 1523 | +int tegra_dfll_suspend(struct device *dev) |
|---|
| 1524 | +{ |
|---|
| 1525 | + struct tegra_dfll *td = dev_get_drvdata(dev); |
|---|
| 1526 | + |
|---|
| 1527 | + if (dfll_is_running(td)) { |
|---|
| 1528 | + dev_err(td->dev, "DFLL still enabled while suspending\n"); |
|---|
| 1529 | + return -EBUSY; |
|---|
| 1530 | + } |
|---|
| 1531 | + |
|---|
| 1532 | + reset_control_assert(td->dvco_rst); |
|---|
| 1533 | + |
|---|
| 1534 | + return 0; |
|---|
| 1535 | +} |
|---|
| 1536 | +EXPORT_SYMBOL(tegra_dfll_suspend); |
|---|
| 1537 | + |
|---|
| 1538 | +/** |
|---|
| 1539 | + * tegra_dfll_resume - reinitialize DFLL on resume |
|---|
| 1540 | + * @dev: DFLL instance |
|---|
| 1541 | + * |
|---|
| 1542 | + * DFLL is disabled and reset during suspend and resume. |
|---|
| 1543 | + * So, reinitialize the DFLL IP block back for use. |
|---|
| 1544 | + * DFLL clock is enabled later in closed loop mode by CPUFreq |
|---|
| 1545 | + * driver before switching its clock source to DFLL output. |
|---|
| 1546 | + */ |
|---|
| 1547 | +int tegra_dfll_resume(struct device *dev) |
|---|
| 1548 | +{ |
|---|
| 1549 | + struct tegra_dfll *td = dev_get_drvdata(dev); |
|---|
| 1550 | + |
|---|
| 1551 | + reset_control_deassert(td->dvco_rst); |
|---|
| 1552 | + |
|---|
| 1553 | + pm_runtime_get_sync(td->dev); |
|---|
| 1554 | + |
|---|
| 1555 | + dfll_set_mode(td, DFLL_DISABLED); |
|---|
| 1556 | + dfll_set_default_params(td); |
|---|
| 1557 | + |
|---|
| 1558 | + if (td->soc->init_clock_trimmers) |
|---|
| 1559 | + td->soc->init_clock_trimmers(); |
|---|
| 1560 | + |
|---|
| 1561 | + dfll_set_open_loop_config(td); |
|---|
| 1562 | + |
|---|
| 1563 | + dfll_init_out_if(td); |
|---|
| 1564 | + |
|---|
| 1565 | + pm_runtime_put_sync(td->dev); |
|---|
| 1566 | + |
|---|
| 1567 | + return 0; |
|---|
| 1568 | +} |
|---|
| 1569 | +EXPORT_SYMBOL(tegra_dfll_resume); |
|---|
| 1570 | + |
|---|
| 1352 | 1571 | /* |
|---|
| 1353 | 1572 | * DT data fetch |
|---|
| 1354 | 1573 | */ |
|---|
| .. | .. |
|---|
| 1359 | 1578 | */ |
|---|
| 1360 | 1579 | static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV) |
|---|
| 1361 | 1580 | { |
|---|
| 1362 | | - int i, n_voltages, reg_uV; |
|---|
| 1581 | + int i, n_voltages, reg_uV,reg_volt_id, align_step; |
|---|
| 1363 | 1582 | |
|---|
| 1583 | + if (WARN_ON(td->pmu_if == TEGRA_DFLL_PMU_PWM)) |
|---|
| 1584 | + return -EINVAL; |
|---|
| 1585 | + |
|---|
| 1586 | + align_step = uV / td->soc->alignment.step_uv; |
|---|
| 1364 | 1587 | n_voltages = regulator_count_voltages(td->vdd_reg); |
|---|
| 1365 | 1588 | for (i = 0; i < n_voltages; i++) { |
|---|
| 1366 | 1589 | reg_uV = regulator_list_voltage(td->vdd_reg, i); |
|---|
| 1367 | 1590 | if (reg_uV < 0) |
|---|
| 1368 | 1591 | break; |
|---|
| 1369 | 1592 | |
|---|
| 1370 | | - if (uV == reg_uV) |
|---|
| 1593 | + reg_volt_id = reg_uV / td->soc->alignment.step_uv; |
|---|
| 1594 | + |
|---|
| 1595 | + if (align_step == reg_volt_id) |
|---|
| 1371 | 1596 | return i; |
|---|
| 1372 | 1597 | } |
|---|
| 1373 | 1598 | |
|---|
| .. | .. |
|---|
| 1381 | 1606 | * */ |
|---|
| 1382 | 1607 | static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV) |
|---|
| 1383 | 1608 | { |
|---|
| 1384 | | - int i, n_voltages, reg_uV; |
|---|
| 1609 | + int i, n_voltages, reg_uV, reg_volt_id, align_step; |
|---|
| 1385 | 1610 | |
|---|
| 1611 | + if (WARN_ON(td->pmu_if == TEGRA_DFLL_PMU_PWM)) |
|---|
| 1612 | + return -EINVAL; |
|---|
| 1613 | + |
|---|
| 1614 | + align_step = uV / td->soc->alignment.step_uv; |
|---|
| 1386 | 1615 | n_voltages = regulator_count_voltages(td->vdd_reg); |
|---|
| 1387 | 1616 | for (i = 0; i < n_voltages; i++) { |
|---|
| 1388 | 1617 | reg_uV = regulator_list_voltage(td->vdd_reg, i); |
|---|
| 1389 | 1618 | if (reg_uV < 0) |
|---|
| 1390 | 1619 | break; |
|---|
| 1391 | 1620 | |
|---|
| 1392 | | - if (uV <= reg_uV) |
|---|
| 1621 | + reg_volt_id = reg_uV / td->soc->alignment.step_uv; |
|---|
| 1622 | + |
|---|
| 1623 | + if (align_step <= reg_volt_id) |
|---|
| 1393 | 1624 | return i; |
|---|
| 1394 | 1625 | } |
|---|
| 1395 | 1626 | |
|---|
| .. | .. |
|---|
| 1397 | 1628 | return -EINVAL; |
|---|
| 1398 | 1629 | } |
|---|
| 1399 | 1630 | |
|---|
| 1631 | +/* |
|---|
| 1632 | + * dfll_build_pwm_lut - build the PWM regulator lookup table |
|---|
| 1633 | + * @td: DFLL instance |
|---|
| 1634 | + * @v_max: Vmax from OPP table |
|---|
| 1635 | + * |
|---|
| 1636 | + * Look-up table in h/w is ignored when PWM is used as DFLL interface to PMIC. |
|---|
| 1637 | + * In this case closed loop output is controlling duty cycle directly. The s/w |
|---|
| 1638 | + * look-up that maps PWM duty cycle to voltage is still built by this function. |
|---|
| 1639 | + */ |
|---|
| 1640 | +static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max) |
|---|
| 1641 | +{ |
|---|
| 1642 | + int i; |
|---|
| 1643 | + unsigned long rate, reg_volt; |
|---|
| 1644 | + u8 lut_bottom = MAX_DFLL_VOLTAGES; |
|---|
| 1645 | + int v_min = td->soc->cvb->min_millivolts * 1000; |
|---|
| 1646 | + |
|---|
| 1647 | + for (i = 0; i < MAX_DFLL_VOLTAGES; i++) { |
|---|
| 1648 | + reg_volt = td->lut_uv[i]; |
|---|
| 1649 | + |
|---|
| 1650 | + /* since opp voltage is exact mv */ |
|---|
| 1651 | + reg_volt = (reg_volt / 1000) * 1000; |
|---|
| 1652 | + if (reg_volt > v_max) |
|---|
| 1653 | + break; |
|---|
| 1654 | + |
|---|
| 1655 | + td->lut[i] = i; |
|---|
| 1656 | + if ((lut_bottom == MAX_DFLL_VOLTAGES) && (reg_volt >= v_min)) |
|---|
| 1657 | + lut_bottom = i; |
|---|
| 1658 | + } |
|---|
| 1659 | + |
|---|
| 1660 | + /* determine voltage boundaries */ |
|---|
| 1661 | + td->lut_size = i; |
|---|
| 1662 | + if ((lut_bottom == MAX_DFLL_VOLTAGES) || |
|---|
| 1663 | + (lut_bottom + 1 >= td->lut_size)) { |
|---|
| 1664 | + dev_err(td->dev, "no voltage above DFLL minimum %d mV\n", |
|---|
| 1665 | + td->soc->cvb->min_millivolts); |
|---|
| 1666 | + return -EINVAL; |
|---|
| 1667 | + } |
|---|
| 1668 | + td->lut_bottom = lut_bottom; |
|---|
| 1669 | + |
|---|
| 1670 | + /* determine rate boundaries */ |
|---|
| 1671 | + rate = get_dvco_rate_below(td, td->lut_bottom); |
|---|
| 1672 | + if (!rate) { |
|---|
| 1673 | + dev_err(td->dev, "no opp below DFLL minimum voltage %d mV\n", |
|---|
| 1674 | + td->soc->cvb->min_millivolts); |
|---|
| 1675 | + return -EINVAL; |
|---|
| 1676 | + } |
|---|
| 1677 | + td->dvco_rate_min = rate; |
|---|
| 1678 | + |
|---|
| 1679 | + return 0; |
|---|
| 1680 | +} |
|---|
| 1681 | + |
|---|
| 1400 | 1682 | /** |
|---|
| 1401 | 1683 | * dfll_build_i2c_lut - build the I2C voltage register lookup table |
|---|
| 1402 | 1684 | * @td: DFLL instance |
|---|
| 1685 | + * @v_max: Vmax from OPP table |
|---|
| 1403 | 1686 | * |
|---|
| 1404 | 1687 | * The DFLL hardware has 33 bytes of look-up table RAM that must be filled with |
|---|
| 1405 | 1688 | * PMIC voltage register values that span the entire DFLL operating range. |
|---|
| .. | .. |
|---|
| 1407 | 1690 | * the soc-specific platform driver (td->soc->opp_dev) and the PMIC |
|---|
| 1408 | 1691 | * register-to-voltage mapping queried from the regulator framework. |
|---|
| 1409 | 1692 | * |
|---|
| 1410 | | - * On success, fills in td->i2c_lut and returns 0, or -err on failure. |
|---|
| 1693 | + * On success, fills in td->lut and returns 0, or -err on failure. |
|---|
| 1411 | 1694 | */ |
|---|
| 1412 | | -static int dfll_build_i2c_lut(struct tegra_dfll *td) |
|---|
| 1695 | +static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max) |
|---|
| 1413 | 1696 | { |
|---|
| 1697 | + unsigned long rate, v, v_opp; |
|---|
| 1414 | 1698 | int ret = -EINVAL; |
|---|
| 1415 | | - int j, v, v_max, v_opp; |
|---|
| 1416 | | - int selector; |
|---|
| 1417 | | - unsigned long rate; |
|---|
| 1418 | | - struct dev_pm_opp *opp; |
|---|
| 1419 | | - int lut; |
|---|
| 1420 | | - |
|---|
| 1421 | | - rate = ULONG_MAX; |
|---|
| 1422 | | - opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); |
|---|
| 1423 | | - if (IS_ERR(opp)) { |
|---|
| 1424 | | - dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); |
|---|
| 1425 | | - goto out; |
|---|
| 1426 | | - } |
|---|
| 1427 | | - v_max = dev_pm_opp_get_voltage(opp); |
|---|
| 1428 | | - dev_pm_opp_put(opp); |
|---|
| 1699 | + int j, selector, lut; |
|---|
| 1429 | 1700 | |
|---|
| 1430 | 1701 | v = td->soc->cvb->min_millivolts * 1000; |
|---|
| 1431 | 1702 | lut = find_vdd_map_entry_exact(td, v); |
|---|
| 1432 | 1703 | if (lut < 0) |
|---|
| 1433 | 1704 | goto out; |
|---|
| 1434 | | - td->i2c_lut[0] = lut; |
|---|
| 1705 | + td->lut[0] = lut; |
|---|
| 1706 | + td->lut_bottom = 0; |
|---|
| 1435 | 1707 | |
|---|
| 1436 | 1708 | for (j = 1, rate = 0; ; rate++) { |
|---|
| 1709 | + struct dev_pm_opp *opp; |
|---|
| 1710 | + |
|---|
| 1437 | 1711 | opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); |
|---|
| 1438 | 1712 | if (IS_ERR(opp)) |
|---|
| 1439 | 1713 | break; |
|---|
| .. | .. |
|---|
| 1445 | 1719 | dev_pm_opp_put(opp); |
|---|
| 1446 | 1720 | |
|---|
| 1447 | 1721 | for (;;) { |
|---|
| 1448 | | - v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); |
|---|
| 1722 | + v += max(1UL, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); |
|---|
| 1449 | 1723 | if (v >= v_opp) |
|---|
| 1450 | 1724 | break; |
|---|
| 1451 | 1725 | |
|---|
| 1452 | 1726 | selector = find_vdd_map_entry_min(td, v); |
|---|
| 1453 | 1727 | if (selector < 0) |
|---|
| 1454 | 1728 | goto out; |
|---|
| 1455 | | - if (selector != td->i2c_lut[j - 1]) |
|---|
| 1456 | | - td->i2c_lut[j++] = selector; |
|---|
| 1729 | + if (selector != td->lut[j - 1]) |
|---|
| 1730 | + td->lut[j++] = selector; |
|---|
| 1457 | 1731 | } |
|---|
| 1458 | 1732 | |
|---|
| 1459 | 1733 | v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp; |
|---|
| 1460 | 1734 | selector = find_vdd_map_entry_exact(td, v); |
|---|
| 1461 | 1735 | if (selector < 0) |
|---|
| 1462 | 1736 | goto out; |
|---|
| 1463 | | - if (selector != td->i2c_lut[j - 1]) |
|---|
| 1464 | | - td->i2c_lut[j++] = selector; |
|---|
| 1737 | + if (selector != td->lut[j - 1]) |
|---|
| 1738 | + td->lut[j++] = selector; |
|---|
| 1465 | 1739 | |
|---|
| 1466 | 1740 | if (v >= v_max) |
|---|
| 1467 | 1741 | break; |
|---|
| 1468 | 1742 | } |
|---|
| 1469 | | - td->i2c_lut_size = j; |
|---|
| 1743 | + td->lut_size = j; |
|---|
| 1470 | 1744 | |
|---|
| 1471 | 1745 | if (!td->dvco_rate_min) |
|---|
| 1472 | 1746 | dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", |
|---|
| 1473 | 1747 | td->soc->cvb->min_millivolts); |
|---|
| 1474 | | - else |
|---|
| 1748 | + else { |
|---|
| 1475 | 1749 | ret = 0; |
|---|
| 1750 | + for (j = 0; j < td->lut_size; j++) |
|---|
| 1751 | + td->lut_uv[j] = |
|---|
| 1752 | + regulator_list_voltage(td->vdd_reg, |
|---|
| 1753 | + td->lut[j]); |
|---|
| 1754 | + } |
|---|
| 1476 | 1755 | |
|---|
| 1477 | 1756 | out: |
|---|
| 1478 | 1757 | return ret; |
|---|
| 1758 | +} |
|---|
| 1759 | + |
|---|
| 1760 | +static int dfll_build_lut(struct tegra_dfll *td) |
|---|
| 1761 | +{ |
|---|
| 1762 | + unsigned long rate, v_max; |
|---|
| 1763 | + struct dev_pm_opp *opp; |
|---|
| 1764 | + |
|---|
| 1765 | + rate = ULONG_MAX; |
|---|
| 1766 | + opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); |
|---|
| 1767 | + if (IS_ERR(opp)) { |
|---|
| 1768 | + dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); |
|---|
| 1769 | + return -EINVAL; |
|---|
| 1770 | + } |
|---|
| 1771 | + v_max = dev_pm_opp_get_voltage(opp); |
|---|
| 1772 | + dev_pm_opp_put(opp); |
|---|
| 1773 | + |
|---|
| 1774 | + if (td->pmu_if == TEGRA_DFLL_PMU_PWM) |
|---|
| 1775 | + return dfll_build_pwm_lut(td, v_max); |
|---|
| 1776 | + else |
|---|
| 1777 | + return dfll_build_i2c_lut(td, v_max); |
|---|
| 1479 | 1778 | } |
|---|
| 1480 | 1779 | |
|---|
| 1481 | 1780 | /** |
|---|
| .. | .. |
|---|
| 1536 | 1835 | } |
|---|
| 1537 | 1836 | td->i2c_reg = vsel_reg; |
|---|
| 1538 | 1837 | |
|---|
| 1539 | | - ret = dfll_build_i2c_lut(td); |
|---|
| 1540 | | - if (ret) { |
|---|
| 1541 | | - dev_err(td->dev, "couldn't build I2C LUT\n"); |
|---|
| 1542 | | - return ret; |
|---|
| 1838 | + return 0; |
|---|
| 1839 | +} |
|---|
| 1840 | + |
|---|
| 1841 | +static int dfll_fetch_pwm_params(struct tegra_dfll *td) |
|---|
| 1842 | +{ |
|---|
| 1843 | + int ret, i; |
|---|
| 1844 | + u32 pwm_period; |
|---|
| 1845 | + |
|---|
| 1846 | + if (!td->soc->alignment.step_uv || !td->soc->alignment.offset_uv) { |
|---|
| 1847 | + dev_err(td->dev, |
|---|
| 1848 | + "Missing step or alignment info for PWM regulator"); |
|---|
| 1849 | + return -EINVAL; |
|---|
| 1850 | + } |
|---|
| 1851 | + for (i = 0; i < MAX_DFLL_VOLTAGES; i++) |
|---|
| 1852 | + td->lut_uv[i] = td->soc->alignment.offset_uv + |
|---|
| 1853 | + i * td->soc->alignment.step_uv; |
|---|
| 1854 | + |
|---|
| 1855 | + ret = read_dt_param(td, "nvidia,pwm-tristate-microvolts", |
|---|
| 1856 | + &td->reg_init_uV); |
|---|
| 1857 | + if (!ret) { |
|---|
| 1858 | + dev_err(td->dev, "couldn't get initialized voltage\n"); |
|---|
| 1859 | + return -EINVAL; |
|---|
| 1860 | + } |
|---|
| 1861 | + |
|---|
| 1862 | + ret = read_dt_param(td, "nvidia,pwm-period-nanoseconds", &pwm_period); |
|---|
| 1863 | + if (!ret) { |
|---|
| 1864 | + dev_err(td->dev, "couldn't get PWM period\n"); |
|---|
| 1865 | + return -EINVAL; |
|---|
| 1866 | + } |
|---|
| 1867 | + td->pwm_rate = (NSEC_PER_SEC / pwm_period) * (MAX_DFLL_VOLTAGES - 1); |
|---|
| 1868 | + |
|---|
| 1869 | + td->pwm_pin = devm_pinctrl_get(td->dev); |
|---|
| 1870 | + if (IS_ERR(td->pwm_pin)) { |
|---|
| 1871 | + dev_err(td->dev, "DT: missing pinctrl device\n"); |
|---|
| 1872 | + return PTR_ERR(td->pwm_pin); |
|---|
| 1873 | + } |
|---|
| 1874 | + |
|---|
| 1875 | + td->pwm_enable_state = pinctrl_lookup_state(td->pwm_pin, |
|---|
| 1876 | + "dvfs_pwm_enable"); |
|---|
| 1877 | + if (IS_ERR(td->pwm_enable_state)) { |
|---|
| 1878 | + dev_err(td->dev, "DT: missing pwm enabled state\n"); |
|---|
| 1879 | + return PTR_ERR(td->pwm_enable_state); |
|---|
| 1880 | + } |
|---|
| 1881 | + |
|---|
| 1882 | + td->pwm_disable_state = pinctrl_lookup_state(td->pwm_pin, |
|---|
| 1883 | + "dvfs_pwm_disable"); |
|---|
| 1884 | + if (IS_ERR(td->pwm_disable_state)) { |
|---|
| 1885 | + dev_err(td->dev, "DT: missing pwm disabled state\n"); |
|---|
| 1886 | + return PTR_ERR(td->pwm_disable_state); |
|---|
| 1543 | 1887 | } |
|---|
| 1544 | 1888 | |
|---|
| 1545 | 1889 | return 0; |
|---|
| .. | .. |
|---|
| 1607 | 1951 | |
|---|
| 1608 | 1952 | td->soc = soc; |
|---|
| 1609 | 1953 | |
|---|
| 1610 | | - td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); |
|---|
| 1611 | | - if (IS_ERR(td->vdd_reg)) { |
|---|
| 1612 | | - dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); |
|---|
| 1613 | | - return PTR_ERR(td->vdd_reg); |
|---|
| 1614 | | - } |
|---|
| 1615 | | - |
|---|
| 1616 | 1954 | td->dvco_rst = devm_reset_control_get(td->dev, "dvco"); |
|---|
| 1617 | 1955 | if (IS_ERR(td->dvco_rst)) { |
|---|
| 1618 | 1956 | dev_err(td->dev, "couldn't get dvco reset\n"); |
|---|
| .. | .. |
|---|
| 1625 | 1963 | return ret; |
|---|
| 1626 | 1964 | } |
|---|
| 1627 | 1965 | |
|---|
| 1628 | | - ret = dfll_fetch_i2c_params(td); |
|---|
| 1966 | + if (of_property_read_bool(td->dev->of_node, "nvidia,pwm-to-pmic")) { |
|---|
| 1967 | + td->pmu_if = TEGRA_DFLL_PMU_PWM; |
|---|
| 1968 | + ret = dfll_fetch_pwm_params(td); |
|---|
| 1969 | + } else { |
|---|
| 1970 | + td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); |
|---|
| 1971 | + if (IS_ERR(td->vdd_reg)) { |
|---|
| 1972 | + dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); |
|---|
| 1973 | + return PTR_ERR(td->vdd_reg); |
|---|
| 1974 | + } |
|---|
| 1975 | + td->pmu_if = TEGRA_DFLL_PMU_I2C; |
|---|
| 1976 | + ret = dfll_fetch_i2c_params(td); |
|---|
| 1977 | + } |
|---|
| 1629 | 1978 | if (ret) |
|---|
| 1630 | 1979 | return ret; |
|---|
| 1631 | 1980 | |
|---|
| 1981 | + ret = dfll_build_lut(td); |
|---|
| 1982 | + if (ret) { |
|---|
| 1983 | + dev_err(td->dev, "couldn't build LUT\n"); |
|---|
| 1984 | + return ret; |
|---|
| 1985 | + } |
|---|
| 1986 | + |
|---|
| 1632 | 1987 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1633 | 1988 | if (!mem) { |
|---|
| 1634 | 1989 | dev_err(td->dev, "no control register resource\n"); |
|---|