hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/cpufreq/tegra124-cpufreq.c
....@@ -1,19 +1,12 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Tegra 124 cpufreq driver
3
- *
4
- * This software is licensed under the terms of the GNU General Public
5
- * License version 2, as published by the Free Software Foundation, and
6
- * may be copied, distributed, and modified under those terms.
7
- *
8
- * This program is distributed in the hope that it will be useful,
9
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- * GNU General Public License for more details.
124 */
135
146 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
157
168 #include <linux/clk.h>
9
+#include <linux/cpufreq.h>
1710 #include <linux/err.h>
1811 #include <linux/init.h>
1912 #include <linux/kernel.h>
....@@ -22,11 +15,9 @@
2215 #include <linux/of.h>
2316 #include <linux/platform_device.h>
2417 #include <linux/pm_opp.h>
25
-#include <linux/regulator/consumer.h>
2618 #include <linux/types.h>
2719
2820 struct tegra124_cpufreq_priv {
29
- struct regulator *vdd_cpu_reg;
3021 struct clk *cpu_clk;
3122 struct clk *pllp_clk;
3223 struct clk *pllx_clk;
....@@ -60,14 +51,6 @@
6051 return ret;
6152 }
6253
63
-static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv)
64
-{
65
- clk_set_parent(priv->cpu_clk, priv->pllp_clk);
66
- clk_disable_unprepare(priv->dfll_clk);
67
- regulator_sync_voltage(priv->vdd_cpu_reg);
68
- clk_set_parent(priv->cpu_clk, priv->pllx_clk);
69
-}
70
-
7154 static int tegra124_cpufreq_probe(struct platform_device *pdev)
7255 {
7356 struct tegra124_cpufreq_priv *priv;
....@@ -88,16 +71,10 @@
8871 if (!np)
8972 return -ENODEV;
9073
91
- priv->vdd_cpu_reg = regulator_get(cpu_dev, "vdd-cpu");
92
- if (IS_ERR(priv->vdd_cpu_reg)) {
93
- ret = PTR_ERR(priv->vdd_cpu_reg);
94
- goto out_put_np;
95
- }
96
-
9774 priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
9875 if (IS_ERR(priv->cpu_clk)) {
9976 ret = PTR_ERR(priv->cpu_clk);
100
- goto out_put_vdd_cpu_reg;
77
+ goto out_put_np;
10178 }
10279
10380 priv->dfll_clk = of_clk_get_by_name(np, "dfll");
....@@ -129,7 +106,7 @@
129106 platform_device_register_full(&cpufreq_dt_devinfo);
130107 if (IS_ERR(priv->cpufreq_dt_pdev)) {
131108 ret = PTR_ERR(priv->cpufreq_dt_pdev);
132
- goto out_switch_to_pllx;
109
+ goto out_put_pllp_clk;
133110 }
134111
135112 platform_set_drvdata(pdev, priv);
....@@ -138,8 +115,6 @@
138115
139116 return 0;
140117
141
-out_switch_to_pllx:
142
- tegra124_cpu_switch_to_pllx(priv);
143118 out_put_pllp_clk:
144119 clk_put(priv->pllp_clk);
145120 out_put_pllx_clk:
....@@ -148,34 +123,73 @@
148123 clk_put(priv->dfll_clk);
149124 out_put_cpu_clk:
150125 clk_put(priv->cpu_clk);
151
-out_put_vdd_cpu_reg:
152
- regulator_put(priv->vdd_cpu_reg);
153126 out_put_np:
154127 of_node_put(np);
155128
156129 return ret;
157130 }
158131
159
-static int tegra124_cpufreq_remove(struct platform_device *pdev)
132
+static int __maybe_unused tegra124_cpufreq_suspend(struct device *dev)
160133 {
161
- struct tegra124_cpufreq_priv *priv = platform_get_drvdata(pdev);
134
+ struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
135
+ int err;
162136
163
- platform_device_unregister(priv->cpufreq_dt_pdev);
164
- tegra124_cpu_switch_to_pllx(priv);
137
+ /*
138
+ * PLLP rate 408Mhz is below the CPU Fmax at Vmin and is safe to
139
+ * use during suspend and resume. So, switch the CPU clock source
140
+ * to PLLP and disable DFLL.
141
+ */
142
+ err = clk_set_parent(priv->cpu_clk, priv->pllp_clk);
143
+ if (err < 0) {
144
+ dev_err(dev, "failed to reparent to PLLP: %d\n", err);
145
+ return err;
146
+ }
165147
166
- clk_put(priv->pllp_clk);
167
- clk_put(priv->pllx_clk);
168
- clk_put(priv->dfll_clk);
169
- clk_put(priv->cpu_clk);
170
- regulator_put(priv->vdd_cpu_reg);
148
+ clk_disable_unprepare(priv->dfll_clk);
171149
172150 return 0;
173151 }
174152
153
+static int __maybe_unused tegra124_cpufreq_resume(struct device *dev)
154
+{
155
+ struct tegra124_cpufreq_priv *priv = dev_get_drvdata(dev);
156
+ int err;
157
+
158
+ /*
159
+ * Warmboot code powers up the CPU with PLLP clock source.
160
+ * Enable DFLL clock and switch CPU clock source back to DFLL.
161
+ */
162
+ err = clk_prepare_enable(priv->dfll_clk);
163
+ if (err < 0) {
164
+ dev_err(dev, "failed to enable DFLL clock for CPU: %d\n", err);
165
+ goto disable_cpufreq;
166
+ }
167
+
168
+ err = clk_set_parent(priv->cpu_clk, priv->dfll_clk);
169
+ if (err < 0) {
170
+ dev_err(dev, "failed to reparent to DFLL clock: %d\n", err);
171
+ goto disable_dfll;
172
+ }
173
+
174
+ return 0;
175
+
176
+disable_dfll:
177
+ clk_disable_unprepare(priv->dfll_clk);
178
+disable_cpufreq:
179
+ disable_cpufreq();
180
+
181
+ return err;
182
+}
183
+
184
+static const struct dev_pm_ops tegra124_cpufreq_pm_ops = {
185
+ SET_SYSTEM_SLEEP_PM_OPS(tegra124_cpufreq_suspend,
186
+ tegra124_cpufreq_resume)
187
+};
188
+
175189 static struct platform_driver tegra124_cpufreq_platdrv = {
176190 .driver.name = "cpufreq-tegra124",
191
+ .driver.pm = &tegra124_cpufreq_pm_ops,
177192 .probe = tegra124_cpufreq_probe,
178
- .remove = tegra124_cpufreq_remove,
179193 };
180194
181195 static int __init tegra_cpufreq_init(void)
....@@ -183,7 +197,8 @@
183197 int ret;
184198 struct platform_device *pdev;
185199
186
- if (!of_machine_is_compatible("nvidia,tegra124"))
200
+ if (!(of_machine_is_compatible("nvidia,tegra124") ||
201
+ of_machine_is_compatible("nvidia,tegra210")))
187202 return -ENODEV;
188203
189204 /*