root/drivers/cpufreq/tegra124-cpufreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tegra124_cpu_switch_to_dfll
  2. tegra124_cpufreq_probe
  3. tegra_cpufreq_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Tegra 124 cpufreq driver
   4  */
   5 
   6 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   7 
   8 #include <linux/clk.h>
   9 #include <linux/err.h>
  10 #include <linux/init.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/of_device.h>
  14 #include <linux/of.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/pm_opp.h>
  17 #include <linux/types.h>
  18 
  19 struct tegra124_cpufreq_priv {
  20         struct clk *cpu_clk;
  21         struct clk *pllp_clk;
  22         struct clk *pllx_clk;
  23         struct clk *dfll_clk;
  24         struct platform_device *cpufreq_dt_pdev;
  25 };
  26 
  27 static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
  28 {
  29         struct clk *orig_parent;
  30         int ret;
  31 
  32         ret = clk_set_rate(priv->dfll_clk, clk_get_rate(priv->cpu_clk));
  33         if (ret)
  34                 return ret;
  35 
  36         orig_parent = clk_get_parent(priv->cpu_clk);
  37         clk_set_parent(priv->cpu_clk, priv->pllp_clk);
  38 
  39         ret = clk_prepare_enable(priv->dfll_clk);
  40         if (ret)
  41                 goto out;
  42 
  43         clk_set_parent(priv->cpu_clk, priv->dfll_clk);
  44 
  45         return 0;
  46 
  47 out:
  48         clk_set_parent(priv->cpu_clk, orig_parent);
  49 
  50         return ret;
  51 }
  52 
  53 static int tegra124_cpufreq_probe(struct platform_device *pdev)
  54 {
  55         struct tegra124_cpufreq_priv *priv;
  56         struct device_node *np;
  57         struct device *cpu_dev;
  58         struct platform_device_info cpufreq_dt_devinfo = {};
  59         int ret;
  60 
  61         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  62         if (!priv)
  63                 return -ENOMEM;
  64 
  65         cpu_dev = get_cpu_device(0);
  66         if (!cpu_dev)
  67                 return -ENODEV;
  68 
  69         np = of_cpu_device_node_get(0);
  70         if (!np)
  71                 return -ENODEV;
  72 
  73         priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
  74         if (IS_ERR(priv->cpu_clk)) {
  75                 ret = PTR_ERR(priv->cpu_clk);
  76                 goto out_put_np;
  77         }
  78 
  79         priv->dfll_clk = of_clk_get_by_name(np, "dfll");
  80         if (IS_ERR(priv->dfll_clk)) {
  81                 ret = PTR_ERR(priv->dfll_clk);
  82                 goto out_put_cpu_clk;
  83         }
  84 
  85         priv->pllx_clk = of_clk_get_by_name(np, "pll_x");
  86         if (IS_ERR(priv->pllx_clk)) {
  87                 ret = PTR_ERR(priv->pllx_clk);
  88                 goto out_put_dfll_clk;
  89         }
  90 
  91         priv->pllp_clk = of_clk_get_by_name(np, "pll_p");
  92         if (IS_ERR(priv->pllp_clk)) {
  93                 ret = PTR_ERR(priv->pllp_clk);
  94                 goto out_put_pllx_clk;
  95         }
  96 
  97         ret = tegra124_cpu_switch_to_dfll(priv);
  98         if (ret)
  99                 goto out_put_pllp_clk;
 100 
 101         cpufreq_dt_devinfo.name = "cpufreq-dt";
 102         cpufreq_dt_devinfo.parent = &pdev->dev;
 103 
 104         priv->cpufreq_dt_pdev =
 105                 platform_device_register_full(&cpufreq_dt_devinfo);
 106         if (IS_ERR(priv->cpufreq_dt_pdev)) {
 107                 ret = PTR_ERR(priv->cpufreq_dt_pdev);
 108                 goto out_put_pllp_clk;
 109         }
 110 
 111         platform_set_drvdata(pdev, priv);
 112 
 113         of_node_put(np);
 114 
 115         return 0;
 116 
 117 out_put_pllp_clk:
 118         clk_put(priv->pllp_clk);
 119 out_put_pllx_clk:
 120         clk_put(priv->pllx_clk);
 121 out_put_dfll_clk:
 122         clk_put(priv->dfll_clk);
 123 out_put_cpu_clk:
 124         clk_put(priv->cpu_clk);
 125 out_put_np:
 126         of_node_put(np);
 127 
 128         return ret;
 129 }
 130 
 131 static struct platform_driver tegra124_cpufreq_platdrv = {
 132         .driver.name    = "cpufreq-tegra124",
 133         .probe          = tegra124_cpufreq_probe,
 134 };
 135 
 136 static int __init tegra_cpufreq_init(void)
 137 {
 138         int ret;
 139         struct platform_device *pdev;
 140 
 141         if (!(of_machine_is_compatible("nvidia,tegra124") ||
 142                 of_machine_is_compatible("nvidia,tegra210")))
 143                 return -ENODEV;
 144 
 145         /*
 146          * Platform driver+device required for handling EPROBE_DEFER with
 147          * the regulator and the DFLL clock
 148          */
 149         ret = platform_driver_register(&tegra124_cpufreq_platdrv);
 150         if (ret)
 151                 return ret;
 152 
 153         pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
 154         if (IS_ERR(pdev)) {
 155                 platform_driver_unregister(&tegra124_cpufreq_platdrv);
 156                 return PTR_ERR(pdev);
 157         }
 158 
 159         return 0;
 160 }
 161 module_init(tegra_cpufreq_init);
 162 
 163 MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
 164 MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124");
 165 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */