diff mbox

[v3,13/15] cpufreq: Add cpufreq driver for Tegra124

Message ID 1408419205-10048-14-git-send-email-tuomas.tynkkynen@iki.fi (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Tuomas Tynkkynen Aug. 19, 2014, 3:33 a.m. UTC
From: Tuomas Tynkkynen <ttynkkynen@nvidia.com>

Add a new cpufreq driver for Tegra124. Instead of using the PLLX as
the CPU clocksource, switch immediately to the DFLL. It allows the use
of higher clock rates, and will automatically scale the CPU voltage as
well. Besides the CPU clocksource switch, we let the cpufreq-cpu0 driver
for all the cpufreq operations.

This driver also relies on the DFLL driver to fill the OPP table for the
CPU0 device, so that the cpufreq-cpu0 driver knows what frequencies to
use.

Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
---
v3:
 - separate Kconfig entry
 - use 'select GENERIC_CPUFREQ_CPU0', not depends
 - support unbinding of the platform device
 - allocate a state structure instead of globals
 - use of_match_machine()
 - various style nits fixed
---
 drivers/cpufreq/Kconfig.arm        |   8 ++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/tegra124-cpufreq.c | 206 +++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/cpufreq/tegra124-cpufreq.c

Comments

Viresh Kumar Aug. 19, 2014, 5:55 a.m. UTC | #1
On 19 August 2014 09:03, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi> wrote:
> From: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
>
> Add a new cpufreq driver for Tegra124. Instead of using the PLLX as
> the CPU clocksource, switch immediately to the DFLL. It allows the use
> of higher clock rates, and will automatically scale the CPU voltage as
> well. Besides the CPU clocksource switch, we let the cpufreq-cpu0 driver
> for all the cpufreq operations.
>
> This driver also relies on the DFLL driver to fill the OPP table for the
> CPU0 device, so that the cpufreq-cpu0 driver knows what frequencies to
> use.
>
> Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
> ---
> v3:
>  - separate Kconfig entry

Gud..

>  - use 'select GENERIC_CPUFREQ_CPU0', not depends

Bad :(

It *has* to be a depends here, its not optional. That was outcome of the
chat we had last time, if I remember it well..

>  - support unbinding of the platform device
>  - allocate a state structure instead of globals
>  - use of_match_machine()
>  - various style nits fixed
> ---

You don't need to add these --- here, just add a blank line and git
will take care of things for you :)

>  drivers/cpufreq/Kconfig.arm        |   8 ++
>  drivers/cpufreq/Makefile           |   1 +
>  drivers/cpufreq/tegra124-cpufreq.c | 206 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 215 insertions(+)
>  create mode 100644 drivers/cpufreq/tegra124-cpufreq.c
>
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 3795a16..07bfed1 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -247,3 +247,11 @@ config ARM_TEGRA20_CPUFREQ
>         default y
>         help
>           This adds the CPUFreq driver support for Tegra20 SOCs.
> +
> +config ARM_TEGRA124_CPUFREQ
> +       bool "Tegra124 CPUFreq support"
> +       depends on ARCH_TEGRA
> +       select GENERIC_CPUFREQ_CPU0

So it will become: depends on ARCH_TEGRA && GENERIC_CPUFREQ_CPU0

> +static int tegra124_cpufreq_probe(struct platform_device *pdev)
> +{

> +       priv->vdd_cpu_reg = regulator_get(get_cpu_device(0), "vdd-cpu");

get_cpu_device() can fail as well, and so you may want to check its return
value as well..

> +static int __init tegra_cpufreq_init(void)
> +{
> +       int ret;
> +       struct platform_device *pdev;
> +
> +       if (!of_match_machine(soc_of_matches))
> +               return -ENODEV;

You may want to add a comment here on why you chose to add another layer
of platform device/driver.. i.e. to catch -EPROBE_DEFER from clk-APIs..

> +       ret = platform_driver_register(&tegra124_cpufreq_platdrv);
> +       if (ret)
> +               return ret;
> +
> +       pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
> +       if (IS_ERR(pdev)) {
> +               platform_driver_unregister(&tegra124_cpufreq_platdrv);
> +               return PTR_ERR(pdev);
> +       }
> +
> +       return 0;
> +}
> +module_init(tegra_cpufreq_init);
> +
> +MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
> +MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124");
> +MODULE_LICENSE("GPL v2");
> --
> 1.8.1.5
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tuomas Tynkkynen Aug. 19, 2014, 7:44 p.m. UTC | #2
On 19/08/14 08:55, Viresh Kumar wrote:
> On 19 August 2014 09:03, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi> wrote:
>>  - use 'select GENERIC_CPUFREQ_CPU0', not depends
> 
> Bad :(
> 
> It *has* to be a depends here, its not optional. That was outcome of the
> chat we had last time, if I remember it well..

Okay, I misread that conversation then.

>> ---
> 
> You don't need to add these --- here, just add a blank line and git
> will take care of things for you :)

There's actually a (mis-?)feature in git format-patch: a literal '---'
line in a commit message won't be escaped, so the patch notes can be
written in the commit message directly so the patch files don't need
to be modified by hand.

>>  drivers/cpufreq/Kconfig.arm        |   8 ++
>>  drivers/cpufreq/Makefile           |   1 +
>>  drivers/cpufreq/tegra124-cpufreq.c | 206 +++++++++++++++++++++++++++++++++++++
>>  3 files changed, 215 insertions(+)
>>  create mode 100644 drivers/cpufreq/tegra124-cpufreq.c
>>
[...]
>> +static int tegra124_cpufreq_probe(struct platform_device *pdev)
>> +{
> 
>> +       priv->vdd_cpu_reg = regulator_get(get_cpu_device(0), "vdd-cpu");
> 
> get_cpu_device() can fail as well, and so you may want to check its return
> value as well..
> 

Oh, right.

>> +static int __init tegra_cpufreq_init(void)
>> +{
>> +       int ret;
>> +       struct platform_device *pdev;
>> +
>> +       if (!of_match_machine(soc_of_matches))
>> +               return -ENODEV;
> 
> You may want to add a comment here on why you chose to add another layer
> of platform device/driver.. i.e. to catch -EPROBE_DEFER from clk-APIs..
>

Yes, a good idea.
Viresh Kumar Aug. 20, 2014, 6:39 a.m. UTC | #3
On 20 August 2014 01:14, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
> There's actually a (mis-?)feature in git format-patch: a literal '---'
> line in a commit message won't be escaped, so the patch notes can be
> written in the commit message directly so the patch files don't need
> to be modified by hand.

How exactly? Can you list the command here please..
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Javier Martinez Canillas Aug. 20, 2014, 3:39 p.m. UTC | #4
Hello Viresh,

On Wed, Aug 20, 2014 at 8:39 AM, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 20 August 2014 01:14, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
>> There's actually a (mis-?)feature in git format-patch: a literal '---'
>> line in a commit message won't be escaped, so the patch notes can be
>> written in the commit message directly so the patch files don't need
>> to be modified by hand.
>
> How exactly? Can you list the command here please..
> --

I rely on the behavior that Tuomas is mentioning as well but is not
about git format-patch but git am.

As you already know when you apply a patch with git am, everything
that is between a line with 3 dashes line (---) and the actual diff is
omitted since that is where the generated diffstat is placed by git
format-patch.

We usually rely on that behavior to put there the history of a patch
or any information that we think that is useful for reviewers but is
not suitable to end in the commit message. Now that means that you
have to generate the patch and then manually edit it to add the
history there.

But since git am omits any text between the first "---" and the diff,
it means that you can add a "---" on your actual commit message and
anything that follows will be discarded by git am, that way you can
maintain your history on your commit message which is way less tedious
than manually editing patches.

So the second "---" from Tuomas patch is actually the one generated by
git format-patch but that gets discarded by git am just like any other
text so it causes no harm when other apply the patches.

If this not the correct workflow and you have a better way to manage
this, I would love to know about it.

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andreas Färber Aug. 20, 2014, 8:02 p.m. UTC | #5
Hi Javier,

Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
> As you already know when you apply a patch with git am, everything
> that is between a line with 3 dashes line (---) and the actual diff is
> omitted since that is where the generated diffstat is placed by git
> format-patch.
> 
> We usually rely on that behavior to put there the history of a patch
> or any information that we think that is useful for reviewers but is
> not suitable to end in the commit message. Now that means that you
> have to generate the patch and then manually edit it to add the
> history there.
> 
> But since git am omits any text between the first "---" and the diff,
> it means that you can add a "---" on your actual commit message and
> anything that follows will be discarded by git am, that way you can
> maintain your history on your commit message which is way less tedious
> than manually editing patches.
> 
> So the second "---" from Tuomas patch is actually the one generated by
> git format-patch but that gets discarded by git am just like any other
> text so it causes no harm when other apply the patches.
> 
> If this not the correct workflow and you have a better way to manage
> this, I would love to know about it.

One drawback of having --- in the commit message is that you can't
cherry-pick but really need to use git-am for it to be stripped.

I resorted to a scripted way of handling change logs: Per patch series I
maintain a shell script that after git-format-patch essentially runs
sed -i "/---/ r /dev/stdin" $OUTDIR/0001-*.patch <<EOCL
...
EOCL
to insert my text after ---. (sed syntax is not POSIX-compliant FWIW.)
Similarly I fill in the blurbs for the cover letter.

Another way I've heard of is git-notes, which lets you associate text
with a given commit id.
But in my tests that data did not survive a git-rebase -i, it stayed
attached to the original commit when editing the commit message or
fixing up a patch. It could still be accessed through the list of
git-notes but not be comfortably extracted from the updated branch via
git-rev-list or the likes.

Cheers,
Andreas
Stephen Warren Aug. 20, 2014, 8:30 p.m. UTC | #6
On 08/20/2014 02:02 PM, Andreas Färber wrote:
> Hi Javier,
>
> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>> As you already know when you apply a patch with git am, everything
>> that is between a line with 3 dashes line (---) and the actual diff is
>> omitted since that is where the generated diffstat is placed by git
>> format-patch.
>>
>> We usually rely on that behavior to put there the history of a patch
>> or any information that we think that is useful for reviewers but is
>> not suitable to end in the commit message. Now that means that you
>> have to generate the patch and then manually edit it to add the
>> history there.
>>
>> But since git am omits any text between the first "---" and the diff,
>> it means that you can add a "---" on your actual commit message and
>> anything that follows will be discarded by git am, that way you can
>> maintain your history on your commit message which is way less tedious
>> than manually editing patches.
>>
>> So the second "---" from Tuomas patch is actually the one generated by
>> git format-patch but that gets discarded by git am just like any other
>> text so it causes no harm when other apply the patches.
>>
>> If this not the correct workflow and you have a better way to manage
>> this, I would love to know about it.
>
> One drawback of having --- in the commit message is that you can't
> cherry-pick but really need to use git-am for it to be stripped.

You can, you just have to either:

* Pass -e to git cherry-pick so you get to edit the patch description,

* Run "git commit --amend" right afterwards,

... and then delete everything starting at ---.

I do this reasonably often on my own patches; I send them to the list, 
get them reviewed, and then cherry-pick them into the Tegra maintainer 
tree rather than saving them from the email client and running git am.
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Viresh Kumar Aug. 21, 2014, 4:26 a.m. UTC | #7
On Thu, Aug 21, 2014 at 2:00 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 08/20/2014 02:02 PM, Andreas Färber wrote:
>> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>>> If this not the correct workflow and you have a better way to manage
>>> this, I would love to know about it.

Oh yes, this was certainly useful. I was missing this (mis)feature :)
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Heiko Schocher Aug. 21, 2014, 6:13 a.m. UTC | #8
Hello Viresh,

Am 21.08.2014 06:26, schrieb Viresh Kumar:
> On Thu, Aug 21, 2014 at 2:00 AM, Stephen Warren<swarren@wwwdotorg.org>  wrote:
>> On 08/20/2014 02:02 PM, Andreas Färber wrote:
>>> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>>>> If this not the correct workflow and you have a better way to manage
>>>> this, I would love to know about it.
>
> Oh yes, this was certainly useful. I was missing this (mis)feature :)

maybe patman from u-boot is also interesting for you, see:

http://git.denx.de/?p=u-boot.git;a=blob;f=tools/patman/README;h=5fb508b80df10d3b11d95eea95a141ce3d0ef578;hb=67ee22b0681305ba1099c508eecade996abc1c65

bye,
Heiko
Javier Martinez Canillas Aug. 21, 2014, 10:34 a.m. UTC | #9
Hello Andreas,

On Wed, Aug 20, 2014 at 10:02 PM, Andreas Färber <afaerber@suse.de> wrote:
>>
>> So the second "---" from Tuomas patch is actually the one generated by
>> git format-patch but that gets discarded by git am just like any other
>> text so it causes no harm when other apply the patches.
>>
>> If this not the correct workflow and you have a better way to manage
>> this, I would love to know about it.
>
> One drawback of having --- in the commit message is that you can't
> cherry-pick but really need to use git-am for it to be stripped.
>

It depends on your workflow really, I don't consider the fact that git
cherry-pick does not omit that part a drawback but a feature ;-)

And as Stephen said you can do a git cherry-pick -e or amend the
commit and remove that part.

> I resorted to a scripted way of handling change logs: Per patch series I
> maintain a shell script that after git-format-patch essentially runs
> sed -i "/---/ r /dev/stdin" $OUTDIR/0001-*.patch <<EOCL
> ...
> EOCL
> to insert my text after ---. (sed syntax is not POSIX-compliant FWIW.)
> Similarly I fill in the blurbs for the cover letter.
>

Yes I used to use sed before indeed. Heiko also suggested patman which
looks quite interesting and may fit my workflow as well.

>
> Cheers,
> Andreas
>
> --

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Javier Martinez Canillas Aug. 21, 2014, 10:35 a.m. UTC | #10
Hello Heiko,

On Thu, Aug 21, 2014 at 8:13 AM, Heiko Schocher <hs@denx.de> wrote:
> Hello Viresh,
>
> Am 21.08.2014 06:26, schrieb Viresh Kumar:
>
>> On Thu, Aug 21, 2014 at 2:00 AM, Stephen Warren<swarren@wwwdotorg.org>
>> wrote:
>>>
>>> On 08/20/2014 02:02 PM, Andreas Färber wrote:
>>>>
>>>> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>>>>>
>>>>> If this not the correct workflow and you have a better way to manage
>>>>> this, I would love to know about it.
>>
>>
>> Oh yes, this was certainly useful. I was missing this (mis)feature :)
>
>
> maybe patman from u-boot is also interesting for you, see:
>
> http://git.denx.de/?p=u-boot.git;a=blob;f=tools/patman/README;h=5fb508b80df10d3b11d95eea95a141ce3d0ef578;hb=67ee22b0681305ba1099c508eecade996abc1c65
>

Very interesting and seems to match my workflow as well so I'll take a
look, thanks for sharing!

> bye,
> Heiko
> --

Best regards,
Javier
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andreas Färber Aug. 21, 2014, 10:43 a.m. UTC | #11
Am 20.08.2014 22:30, schrieb Stephen Warren:
> On 08/20/2014 02:02 PM, Andreas Färber wrote:
>> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>>> As you already know when you apply a patch with git am, everything
>>> that is between a line with 3 dashes line (---) and the actual diff is
>>> omitted since that is where the generated diffstat is placed by git
>>> format-patch.
>>>
>>> We usually rely on that behavior to put there the history of a patch
>>> or any information that we think that is useful for reviewers but is
>>> not suitable to end in the commit message. Now that means that you
>>> have to generate the patch and then manually edit it to add the
>>> history there.
>>>
>>> But since git am omits any text between the first "---" and the diff,
>>> it means that you can add a "---" on your actual commit message and
>>> anything that follows will be discarded by git am, that way you can
>>> maintain your history on your commit message which is way less tedious
>>> than manually editing patches.
>>>
>>> So the second "---" from Tuomas patch is actually the one generated by
>>> git format-patch but that gets discarded by git am just like any other
>>> text so it causes no harm when other apply the patches.
>>>
>>> If this not the correct workflow and you have a better way to manage
>>> this, I would love to know about it.
>>
>> One drawback of having --- in the commit message is that you can't
>> cherry-pick but really need to use git-am for it to be stripped.
> 
> You can, you just have to either:
> 
> * Pass -e to git cherry-pick so you get to edit the patch description,
> 
> * Run "git commit --amend" right afterwards,
> 
> ... and then delete everything starting at ---.
> 
> I do this reasonably often on my own patches; I send them to the list,
> get them reviewed, and then cherry-pick them into the Tegra maintainer
> tree rather than saving them from the email client and running git am.

Sure. My point was more that the person doing the cherry-pick needs to
be aware of and correct such misuse, and in QEMU I did see people
cherry-picking from each other and committing with Signed-off-by *below*
the change log. ;)

Also, keeping commits and change log separate allows me to work on them
concurrently. As with editors, everyone will have their own preferences.

Cheers,
Andreas
Heiko Schocher Aug. 21, 2014, 10:49 a.m. UTC | #12
Hello Javier,

Am 21.08.2014 12:35, schrieb Javier Martinez Canillas:
> Hello Heiko,
>
> On Thu, Aug 21, 2014 at 8:13 AM, Heiko Schocher<hs@denx.de>  wrote:
>> Hello Viresh,
>>
>> Am 21.08.2014 06:26, schrieb Viresh Kumar:
>>
>>> On Thu, Aug 21, 2014 at 2:00 AM, Stephen Warren<swarren@wwwdotorg.org>
>>> wrote:
>>>>
>>>> On 08/20/2014 02:02 PM, Andreas Färber wrote:
>>>>>
>>>>> Am 20.08.2014 17:39, schrieb Javier Martinez Canillas:
>>>>>>
>>>>>> If this not the correct workflow and you have a better way to manage
>>>>>> this, I would love to know about it.
>>>
>>>
>>> Oh yes, this was certainly useful. I was missing this (mis)feature :)
>>
>>
>> maybe patman from u-boot is also interesting for you, see:
>>
>> http://git.denx.de/?p=u-boot.git;a=blob;f=tools/patman/README;h=5fb508b80df10d3b11d95eea95a141ce3d0ef578;hb=67ee22b0681305ba1099c508eecade996abc1c65
>>
>
> Very interesting and seems to match my workflow as well so I'll take a
> look, thanks for sharing!

You are welcome!

bye,
Heiko
diff mbox

Patch

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 3795a16..07bfed1 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -247,3 +247,11 @@  config ARM_TEGRA20_CPUFREQ
 	default y
 	help
 	  This adds the CPUFreq driver support for Tegra20 SOCs.
+
+config ARM_TEGRA124_CPUFREQ
+	bool "Tegra124 CPUFreq support"
+	depends on ARCH_TEGRA
+	select GENERIC_CPUFREQ_CPU0
+	default y
+	help
+	  This adds the CPUFreq driver support for Tegra124 SOCs.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 428451a..25b4f53 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -76,6 +76,7 @@  obj-$(CONFIG_ARM_SA1100_CPUFREQ)	+= sa1100-cpufreq.o
 obj-$(CONFIG_ARM_SA1110_CPUFREQ)	+= sa1110-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)	+= tegra20-cpufreq.o
+obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)	+= tegra124-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)	+= vexpress-spc-cpufreq.o
 
 ##################################################################################
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
new file mode 100644
index 0000000..5748baa
--- /dev/null
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -0,0 +1,206 @@ 
+/*
+ * Tegra 124 cpufreq driver
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+struct tegra124_cpufreq_priv {
+	struct regulator *vdd_cpu_reg;
+	struct clk *cpu_clk;
+	struct clk *pllp_clk;
+	struct clk *pllx_clk;
+	struct clk *dfll_clk;
+	struct platform_device *cpufreq_cpu0_pdev;
+};
+
+static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
+{
+	struct clk *orig_parent;
+	int ret;
+
+	ret = clk_set_rate(priv->dfll_clk, clk_get_rate(priv->cpu_clk));
+	if (ret)
+		return ret;
+
+	orig_parent = clk_get_parent(priv->cpu_clk);
+	clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+
+	ret = clk_prepare_enable(priv->dfll_clk);
+	if (ret)
+		goto out;
+
+	clk_set_parent(priv->cpu_clk, priv->dfll_clk);
+
+	return 0;
+
+out:
+	clk_set_parent(priv->cpu_clk, orig_parent);
+
+	return ret;
+}
+
+static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv)
+{
+	clk_set_parent(priv->cpu_clk, priv->pllp_clk);
+	clk_disable_unprepare(priv->dfll_clk);
+	regulator_sync_voltage(priv->vdd_cpu_reg);
+	clk_set_parent(priv->cpu_clk, priv->pllx_clk);
+}
+
+static int tegra124_cpufreq_probe(struct platform_device *pdev)
+{
+	struct tegra124_cpufreq_priv *priv;
+	struct device_node *np;
+	struct platform_device_info cpufreq_cpu0_devinfo = {};
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	np = of_cpu_device_node_get(0);
+	if (!np)
+		return -ENODEV;
+
+	priv->vdd_cpu_reg = regulator_get(get_cpu_device(0), "vdd-cpu");
+	if (IS_ERR(priv->vdd_cpu_reg)) {
+		ret = PTR_ERR(priv->vdd_cpu_reg);
+		goto out_put_np;
+	}
+
+	priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
+	if (IS_ERR(priv->cpu_clk)) {
+		ret = PTR_ERR(priv->cpu_clk);
+		goto out_put_vdd_cpu_reg;
+	}
+
+	priv->dfll_clk = of_clk_get_by_name(np, "dfll");
+	if (IS_ERR(priv->dfll_clk)) {
+		ret = PTR_ERR(priv->dfll_clk);
+		goto out_put_cpu_clk;
+	}
+
+	priv->pllx_clk = of_clk_get_by_name(np, "pll_x");
+	if (IS_ERR(priv->pllx_clk)) {
+		ret = PTR_ERR(priv->pllx_clk);
+		goto out_put_dfll_clk;
+	}
+
+	priv->pllp_clk = of_clk_get_by_name(np, "pll_p");
+	if (IS_ERR(priv->pllp_clk)) {
+		ret = PTR_ERR(priv->pllp_clk);
+		goto out_put_pllx_clk;
+	}
+
+	ret = tegra124_cpu_switch_to_dfll(priv);
+	if (ret)
+		goto out_put_pllp_clk;
+
+	cpufreq_cpu0_devinfo.name = "cpufreq-cpu0";
+	cpufreq_cpu0_devinfo.parent = &pdev->dev;
+
+	priv->cpufreq_cpu0_pdev =
+		platform_device_register_full(&cpufreq_cpu0_devinfo);
+	if (IS_ERR(priv->cpufreq_cpu0_pdev)) {
+		ret = PTR_ERR(priv->cpufreq_cpu0_pdev);
+		goto out_switch_to_pllx;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+
+out_switch_to_pllx:
+	tegra124_cpu_switch_to_pllx(priv);
+out_put_pllp_clk:
+	clk_put(priv->pllp_clk);
+out_put_pllx_clk:
+	clk_put(priv->pllx_clk);
+out_put_dfll_clk:
+	clk_put(priv->dfll_clk);
+out_put_cpu_clk:
+	clk_put(priv->cpu_clk);
+out_put_vdd_cpu_reg:
+	regulator_put(priv->vdd_cpu_reg);
+out_put_np:
+	of_node_put(np);
+
+	return ret;
+}
+
+static int tegra124_cpufreq_remove(struct platform_device *pdev)
+{
+	struct tegra124_cpufreq_priv *priv = platform_get_drvdata(pdev);
+
+	platform_device_unregister(priv->cpufreq_cpu0_pdev);
+	tegra124_cpu_switch_to_pllx(priv);
+
+	clk_put(priv->pllp_clk);
+	clk_put(priv->pllx_clk);
+	clk_put(priv->dfll_clk);
+	clk_put(priv->cpu_clk);
+	regulator_put(priv->vdd_cpu_reg);
+
+	return 0;
+}
+
+static struct platform_driver tegra124_cpufreq_platdrv = {
+	.driver = {
+		.name	= "cpufreq-tegra124",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tegra124_cpufreq_probe,
+	.remove		= tegra124_cpufreq_remove,
+};
+
+static const struct of_device_id soc_of_matches[] = {
+	{ .compatible = "nvidia,tegra124", },
+	{}
+};
+
+static int __init tegra_cpufreq_init(void)
+{
+	int ret;
+	struct platform_device *pdev;
+
+	if (!of_match_machine(soc_of_matches))
+		return -ENODEV;
+
+	ret = platform_driver_register(&tegra124_cpufreq_platdrv);
+	if (ret)
+		return ret;
+
+	pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		platform_driver_unregister(&tegra124_cpufreq_platdrv);
+		return PTR_ERR(pdev);
+	}
+
+	return 0;
+}
+module_init(tegra_cpufreq_init);
+
+MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
+MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124");
+MODULE_LICENSE("GPL v2");