2 * Tegra 124 cpufreq driver
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.
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.
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/clk.h>
17 #include <linux/err.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/of_device.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_opp.h>
25 #include <linux/types.h>
27 struct tegra124_cpufreq_priv {
32 struct platform_device *cpufreq_dt_pdev;
35 static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
37 struct clk *orig_parent;
40 ret = clk_set_rate(priv->dfll_clk, clk_get_rate(priv->cpu_clk));
44 orig_parent = clk_get_parent(priv->cpu_clk);
45 clk_set_parent(priv->cpu_clk, priv->pllp_clk);
47 ret = clk_prepare_enable(priv->dfll_clk);
51 clk_set_parent(priv->cpu_clk, priv->dfll_clk);
56 clk_set_parent(priv->cpu_clk, orig_parent);
61 static int tegra124_cpufreq_probe(struct platform_device *pdev)
63 struct tegra124_cpufreq_priv *priv;
64 struct device_node *np;
65 struct device *cpu_dev;
66 struct platform_device_info cpufreq_dt_devinfo = {};
69 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
73 cpu_dev = get_cpu_device(0);
77 np = of_cpu_device_node_get(0);
81 priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
82 if (IS_ERR(priv->cpu_clk)) {
83 ret = PTR_ERR(priv->cpu_clk);
87 priv->dfll_clk = of_clk_get_by_name(np, "dfll");
88 if (IS_ERR(priv->dfll_clk)) {
89 ret = PTR_ERR(priv->dfll_clk);
93 priv->pllx_clk = of_clk_get_by_name(np, "pll_x");
94 if (IS_ERR(priv->pllx_clk)) {
95 ret = PTR_ERR(priv->pllx_clk);
96 goto out_put_dfll_clk;
99 priv->pllp_clk = of_clk_get_by_name(np, "pll_p");
100 if (IS_ERR(priv->pllp_clk)) {
101 ret = PTR_ERR(priv->pllp_clk);
102 goto out_put_pllx_clk;
105 ret = tegra124_cpu_switch_to_dfll(priv);
107 goto out_put_pllp_clk;
109 cpufreq_dt_devinfo.name = "cpufreq-dt";
110 cpufreq_dt_devinfo.parent = &pdev->dev;
112 priv->cpufreq_dt_pdev =
113 platform_device_register_full(&cpufreq_dt_devinfo);
114 if (IS_ERR(priv->cpufreq_dt_pdev)) {
115 ret = PTR_ERR(priv->cpufreq_dt_pdev);
116 goto out_put_pllp_clk;
119 platform_set_drvdata(pdev, priv);
126 clk_put(priv->pllp_clk);
128 clk_put(priv->pllx_clk);
130 clk_put(priv->dfll_clk);
132 clk_put(priv->cpu_clk);
139 static struct platform_driver tegra124_cpufreq_platdrv = {
140 .driver.name = "cpufreq-tegra124",
141 .probe = tegra124_cpufreq_probe,
144 static int __init tegra_cpufreq_init(void)
147 struct platform_device *pdev;
149 if (!(of_machine_is_compatible("nvidia,tegra124") ||
150 of_machine_is_compatible("nvidia,tegra210")))
154 * Platform driver+device required for handling EPROBE_DEFER with
155 * the regulator and the DFLL clock
157 ret = platform_driver_register(&tegra124_cpufreq_platdrv);
161 pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
163 platform_driver_unregister(&tegra124_cpufreq_platdrv);
164 return PTR_ERR(pdev);
169 module_init(tegra_cpufreq_init);
171 MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
172 MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124");
173 MODULE_LICENSE("GPL v2");