2019-06-04 15:11:33 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-07-11 01:58:20 +07:00
|
|
|
/*
|
2011-05-27 09:39:18 +07:00
|
|
|
* CPU frequency scaling for OMAP using OPP information
|
2005-07-11 01:58:20 +07:00
|
|
|
*
|
|
|
|
* Copyright (C) 2005 Nokia Corporation
|
|
|
|
* Written by Tony Lindgren <tony@atomide.com>
|
|
|
|
*
|
|
|
|
* Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
|
|
|
|
*
|
2010-08-12 07:02:43 +07:00
|
|
|
* Copyright (C) 2007-2011 Texas Instruments, Inc.
|
|
|
|
* - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
|
2005-07-11 01:58:20 +07:00
|
|
|
*/
|
2016-04-06 03:28:25 +07:00
|
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2005-07-11 01:58:20 +07:00
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/cpufreq.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/err.h>
|
2006-01-07 23:15:52 +07:00
|
|
|
#include <linux/clk.h>
|
2008-09-06 18:10:45 +07:00
|
|
|
#include <linux/io.h>
|
2013-09-20 04:03:52 +07:00
|
|
|
#include <linux/pm_opp.h>
|
2011-09-22 06:53:00 +07:00
|
|
|
#include <linux/cpu.h>
|
2011-10-01 00:41:26 +07:00
|
|
|
#include <linux/module.h>
|
cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver
As multi-platform build is being adopted by more and more ARM platforms,
initcall function should be used very carefully. For example, when
CONFIG_ARM_OMAP2PLUS_CPUFREQ is built in the kernel, omap_cpufreq_init()
will be called on all the platforms to initialize omap-cpufreq driver.
Further, on OMAP, we now use Soc generic cpufreq-cpu0 driver using device
tree entries. To allow cpufreq-cpu0 and omap-cpufreq drivers to co-exist
for OMAP in a single image, we need to ensure the following:
1. With device tree boot, we use cpufreq-cpu0
2. With non device tree boot, we use omap-cpufreq
In the case of (1), we will have cpu OPPs and regulator registered
as part of the device tree nodes, to ensure that omap-cpufreq
and cpufreq-cpu0 don't conflict in managing the frequency of the
same CPU, we should not permit omap-cpufreq to be probed.
In the case of (2), we will not have the cpufreq-cpu0 device, hence
only omap-cpufreq will be active.
To eliminate this undesired these effects, we change omap-cpufreq
driver to have it instantiated as a platform_driver and register
"omap-cpufreq" device only when booted without device tree nodes on
OMAP platforms.
This allows the following:
a) Will only run on platforms that create the platform_device
"omap-cpufreq".
b) Since the platform_device is registered only when device tree nodes
are *not* populated, omap-cpufreq driver does not conflict with
the usage of cpufreq-cpu0 driver which is used on OMAP platforms when
device tree nodes are present.
Inspired by commit 5553f9e26f6f49a93ba732fd222eac6973a4cf35
(cpufreq: instantiate cpufreq-cpu0 as a platform_driver)
[robherring2@gmail.com: reported conflict of omap-cpufreq vs other
driver in an non-device tree supported boot]
Reported-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-04-10 06:22:01 +07:00
|
|
|
#include <linux/platform_device.h>
|
2011-07-16 05:05:04 +07:00
|
|
|
#include <linux/regulator/consumer.h>
|
2005-07-11 01:58:20 +07:00
|
|
|
|
2010-08-12 07:02:43 +07:00
|
|
|
#include <asm/smp_plat.h>
|
2011-09-22 06:53:00 +07:00
|
|
|
#include <asm/cpu.h>
|
2005-07-11 01:58:20 +07:00
|
|
|
|
2012-02-23 20:49:24 +07:00
|
|
|
/* OPP tolerance in percentage */
|
|
|
|
#define OPP_TOLERANCE 4
|
|
|
|
|
2010-08-12 07:02:43 +07:00
|
|
|
static struct cpufreq_frequency_table *freq_table;
|
2011-05-27 09:39:20 +07:00
|
|
|
static atomic_t freq_table_users = ATOMIC_INIT(0);
|
2011-05-26 06:38:47 +07:00
|
|
|
static struct device *mpu_dev;
|
2011-07-16 05:05:04 +07:00
|
|
|
static struct regulator *mpu_reg;
|
2007-08-30 16:46:39 +07:00
|
|
|
|
2013-10-25 21:15:48 +07:00
|
|
|
static int omap_target(struct cpufreq_policy *policy, unsigned int index)
|
2005-07-11 01:58:20 +07:00
|
|
|
{
|
2013-11-13 17:09:23 +07:00
|
|
|
int r, ret;
|
2013-09-20 04:03:51 +07:00
|
|
|
struct dev_pm_opp *opp;
|
2012-02-23 20:49:24 +07:00
|
|
|
unsigned long freq, volt = 0, volt_old = 0, tol = 0;
|
2013-08-14 21:08:24 +07:00
|
|
|
unsigned int old_freq, new_freq;
|
2005-07-11 01:58:20 +07:00
|
|
|
|
2014-01-09 22:08:43 +07:00
|
|
|
old_freq = policy->cur;
|
2013-08-14 21:08:24 +07:00
|
|
|
new_freq = freq_table[index].frequency;
|
2009-01-28 09:13:38 +07:00
|
|
|
|
2013-08-14 21:08:24 +07:00
|
|
|
freq = new_freq * 1000;
|
2014-01-09 22:08:43 +07:00
|
|
|
ret = clk_round_rate(policy->clk, freq);
|
remove lots of IS_ERR_VALUE abuses
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.
However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
Andrzej Hajda has already fixed a lot of the worst abusers that
were causing actual bugs, but it would be nice to prevent any
users that are not passing 'unsigned long' arguments.
This patch changes all users of IS_ERR_VALUE() that I could find
on 32-bit ARM randconfig builds and x86 allmodconfig. For the
moment, this doesn't change the definition of IS_ERR_VALUE()
because there are probably still architecture specific users
elsewhere.
Almost all the warnings I got are for files that are better off
using 'if (err)' or 'if (err < 0)'.
The only legitimate user I could find that we get a warning for
is the (32-bit only) freescale fman driver, so I did not remove
the IS_ERR_VALUE() there but changed the type to 'unsigned long'.
For 9pfs, I just worked around one user whose calling conventions
are so obscure that I did not dare change the behavior.
I was using this definition for testing:
#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
which ends up making all 16-bit or wider types work correctly with
the most plausible interpretation of what IS_ERR_VALUE() was supposed
to return according to its users, but also causes a compile-time
warning for any users that do not pass an 'unsigned long' argument.
I suggested this approach earlier this year, but back then we ended
up deciding to just fix the users that are obviously broken. After
the initial warning that caused me to get involved in the discussion
(fs/gfs2/dir.c) showed up again in the mainline kernel, Linus
asked me to send the whole thing again.
[ Updated the 9p parts as per Al Viro - Linus ]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lkml.org/lkml/2016/1/7/363
Link: https://lkml.org/lkml/2016/5/27/486
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> # For nvmem part
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-05-28 04:23:25 +07:00
|
|
|
if (ret < 0) {
|
2012-10-03 05:39:03 +07:00
|
|
|
dev_warn(mpu_dev,
|
|
|
|
"CPUfreq: Cannot find matching frequency for %lu\n",
|
|
|
|
freq);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
freq = ret;
|
2011-07-16 05:05:04 +07:00
|
|
|
|
|
|
|
if (mpu_reg) {
|
2013-09-20 04:03:50 +07:00
|
|
|
opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
|
2011-07-16 05:05:04 +07:00
|
|
|
if (IS_ERR(opp)) {
|
|
|
|
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
|
2013-08-14 21:08:24 +07:00
|
|
|
__func__, new_freq);
|
2011-07-16 05:05:04 +07:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2013-09-20 04:03:50 +07:00
|
|
|
volt = dev_pm_opp_get_voltage(opp);
|
2017-01-23 11:41:47 +07:00
|
|
|
dev_pm_opp_put(opp);
|
2012-02-23 20:49:24 +07:00
|
|
|
tol = volt * OPP_TOLERANCE / 100;
|
2011-07-16 05:05:04 +07:00
|
|
|
volt_old = regulator_get_voltage(mpu_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n",
|
2013-08-14 21:08:24 +07:00
|
|
|
old_freq / 1000, volt_old ? volt_old / 1000 : -1,
|
|
|
|
new_freq / 1000, volt ? volt / 1000 : -1);
|
2013-06-19 12:48:20 +07:00
|
|
|
|
2011-07-16 05:05:04 +07:00
|
|
|
/* scaling up? scale voltage before frequency */
|
2013-08-14 21:08:24 +07:00
|
|
|
if (mpu_reg && (new_freq > old_freq)) {
|
2012-02-23 20:49:24 +07:00
|
|
|
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
|
2011-07-16 05:05:04 +07:00
|
|
|
if (r < 0) {
|
|
|
|
dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
|
|
|
|
__func__);
|
2013-08-14 21:08:24 +07:00
|
|
|
return r;
|
2011-07-16 05:05:04 +07:00
|
|
|
}
|
|
|
|
}
|
2010-08-12 07:02:43 +07:00
|
|
|
|
2014-01-09 22:08:43 +07:00
|
|
|
ret = clk_set_rate(policy->clk, new_freq * 1000);
|
2011-09-22 06:53:00 +07:00
|
|
|
|
2011-07-16 05:05:04 +07:00
|
|
|
/* scaling down? scale voltage after frequency */
|
2013-08-14 21:08:24 +07:00
|
|
|
if (mpu_reg && (new_freq < old_freq)) {
|
2012-02-23 20:49:24 +07:00
|
|
|
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
|
2011-07-16 05:05:04 +07:00
|
|
|
if (r < 0) {
|
|
|
|
dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
|
|
|
|
__func__);
|
2014-01-09 22:08:43 +07:00
|
|
|
clk_set_rate(policy->clk, old_freq * 1000);
|
2013-08-14 21:08:24 +07:00
|
|
|
return r;
|
2011-07-16 05:05:04 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-11 01:58:20 +07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-05-27 09:39:20 +07:00
|
|
|
static inline void freq_table_free(void)
|
|
|
|
{
|
|
|
|
if (atomic_dec_and_test(&freq_table_users))
|
2013-09-20 04:03:50 +07:00
|
|
|
dev_pm_opp_free_cpufreq_table(mpu_dev, &freq_table);
|
2011-05-27 09:39:20 +07:00
|
|
|
}
|
|
|
|
|
2013-06-20 00:54:04 +07:00
|
|
|
static int omap_cpu_init(struct cpufreq_policy *policy)
|
2005-07-11 01:58:20 +07:00
|
|
|
{
|
2013-10-03 21:59:18 +07:00
|
|
|
int result;
|
2010-08-12 07:02:43 +07:00
|
|
|
|
2014-01-09 22:08:43 +07:00
|
|
|
policy->clk = clk_get(NULL, "cpufreq_ck");
|
|
|
|
if (IS_ERR(policy->clk))
|
|
|
|
return PTR_ERR(policy->clk);
|
2005-07-11 01:58:20 +07:00
|
|
|
|
2013-10-03 21:59:18 +07:00
|
|
|
if (!freq_table) {
|
2013-09-20 04:03:50 +07:00
|
|
|
result = dev_pm_opp_init_cpufreq_table(mpu_dev, &freq_table);
|
2013-10-03 21:59:18 +07:00
|
|
|
if (result) {
|
|
|
|
dev_err(mpu_dev,
|
|
|
|
"%s: cpu%d: failed creating freq table[%d]\n",
|
2011-05-27 09:39:17 +07:00
|
|
|
__func__, policy->cpu, result);
|
2013-10-03 21:59:18 +07:00
|
|
|
goto fail;
|
|
|
|
}
|
2009-01-28 09:13:38 +07:00
|
|
|
}
|
|
|
|
|
2012-08-09 14:08:21 +07:00
|
|
|
atomic_inc_return(&freq_table_users);
|
|
|
|
|
2009-01-28 09:13:38 +07:00
|
|
|
/* FIXME: what's the actual transition time? */
|
2013-10-03 21:59:18 +07:00
|
|
|
result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
2019-02-07 11:35:50 +07:00
|
|
|
if (!result) {
|
|
|
|
dev_pm_opp_of_register_em(policy->cpus);
|
2013-10-03 21:59:18 +07:00
|
|
|
return 0;
|
2019-02-07 11:35:50 +07:00
|
|
|
}
|
2011-05-27 09:39:19 +07:00
|
|
|
|
2011-05-27 09:39:20 +07:00
|
|
|
freq_table_free();
|
2013-10-03 21:59:18 +07:00
|
|
|
fail:
|
2014-01-09 22:08:43 +07:00
|
|
|
clk_put(policy->clk);
|
2011-05-27 09:39:19 +07:00
|
|
|
return result;
|
2005-07-11 01:58:20 +07:00
|
|
|
}
|
|
|
|
|
2007-08-30 16:46:39 +07:00
|
|
|
static int omap_cpu_exit(struct cpufreq_policy *policy)
|
|
|
|
{
|
2011-05-27 09:39:20 +07:00
|
|
|
freq_table_free();
|
2014-01-09 22:08:43 +07:00
|
|
|
clk_put(policy->clk);
|
2007-08-30 16:46:39 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-11 01:58:20 +07:00
|
|
|
static struct cpufreq_driver omap_driver = {
|
2013-12-03 12:50:45 +07:00
|
|
|
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
2013-10-03 21:58:13 +07:00
|
|
|
.verify = cpufreq_generic_frequency_table_verify,
|
2013-10-25 21:15:48 +07:00
|
|
|
.target_index = omap_target,
|
2014-01-09 22:08:43 +07:00
|
|
|
.get = cpufreq_generic_get,
|
2005-07-11 01:58:20 +07:00
|
|
|
.init = omap_cpu_init,
|
2007-08-30 16:46:39 +07:00
|
|
|
.exit = omap_cpu_exit,
|
2005-07-11 01:58:20 +07:00
|
|
|
.name = "omap",
|
2013-10-03 21:58:13 +07:00
|
|
|
.attr = cpufreq_generic_attr,
|
2005-07-11 01:58:20 +07:00
|
|
|
};
|
|
|
|
|
cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver
As multi-platform build is being adopted by more and more ARM platforms,
initcall function should be used very carefully. For example, when
CONFIG_ARM_OMAP2PLUS_CPUFREQ is built in the kernel, omap_cpufreq_init()
will be called on all the platforms to initialize omap-cpufreq driver.
Further, on OMAP, we now use Soc generic cpufreq-cpu0 driver using device
tree entries. To allow cpufreq-cpu0 and omap-cpufreq drivers to co-exist
for OMAP in a single image, we need to ensure the following:
1. With device tree boot, we use cpufreq-cpu0
2. With non device tree boot, we use omap-cpufreq
In the case of (1), we will have cpu OPPs and regulator registered
as part of the device tree nodes, to ensure that omap-cpufreq
and cpufreq-cpu0 don't conflict in managing the frequency of the
same CPU, we should not permit omap-cpufreq to be probed.
In the case of (2), we will not have the cpufreq-cpu0 device, hence
only omap-cpufreq will be active.
To eliminate this undesired these effects, we change omap-cpufreq
driver to have it instantiated as a platform_driver and register
"omap-cpufreq" device only when booted without device tree nodes on
OMAP platforms.
This allows the following:
a) Will only run on platforms that create the platform_device
"omap-cpufreq".
b) Since the platform_device is registered only when device tree nodes
are *not* populated, omap-cpufreq driver does not conflict with
the usage of cpufreq-cpu0 driver which is used on OMAP platforms when
device tree nodes are present.
Inspired by commit 5553f9e26f6f49a93ba732fd222eac6973a4cf35
(cpufreq: instantiate cpufreq-cpu0 as a platform_driver)
[robherring2@gmail.com: reported conflict of omap-cpufreq vs other
driver in an non-device tree supported boot]
Reported-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-04-10 06:22:01 +07:00
|
|
|
static int omap_cpufreq_probe(struct platform_device *pdev)
|
2005-07-11 01:58:20 +07:00
|
|
|
{
|
2012-09-07 04:22:44 +07:00
|
|
|
mpu_dev = get_cpu_device(0);
|
|
|
|
if (!mpu_dev) {
|
2016-04-06 03:28:25 +07:00
|
|
|
pr_warn("%s: unable to get the MPU device\n", __func__);
|
2012-09-07 04:22:44 +07:00
|
|
|
return -EINVAL;
|
2011-05-26 06:38:47 +07:00
|
|
|
}
|
|
|
|
|
2011-07-16 05:05:04 +07:00
|
|
|
mpu_reg = regulator_get(mpu_dev, "vcc");
|
|
|
|
if (IS_ERR(mpu_reg)) {
|
2016-04-06 03:28:24 +07:00
|
|
|
pr_warn("%s: unable to get MPU regulator\n", __func__);
|
2011-07-16 05:05:04 +07:00
|
|
|
mpu_reg = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Ensure physical regulator is present.
|
|
|
|
* (e.g. could be dummy regulator.)
|
|
|
|
*/
|
|
|
|
if (regulator_get_voltage(mpu_reg) < 0) {
|
|
|
|
pr_warn("%s: physical regulator not present for MPU\n",
|
|
|
|
__func__);
|
|
|
|
regulator_put(mpu_reg);
|
|
|
|
mpu_reg = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-11 01:58:20 +07:00
|
|
|
return cpufreq_register_driver(&omap_driver);
|
|
|
|
}
|
|
|
|
|
cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver
As multi-platform build is being adopted by more and more ARM platforms,
initcall function should be used very carefully. For example, when
CONFIG_ARM_OMAP2PLUS_CPUFREQ is built in the kernel, omap_cpufreq_init()
will be called on all the platforms to initialize omap-cpufreq driver.
Further, on OMAP, we now use Soc generic cpufreq-cpu0 driver using device
tree entries. To allow cpufreq-cpu0 and omap-cpufreq drivers to co-exist
for OMAP in a single image, we need to ensure the following:
1. With device tree boot, we use cpufreq-cpu0
2. With non device tree boot, we use omap-cpufreq
In the case of (1), we will have cpu OPPs and regulator registered
as part of the device tree nodes, to ensure that omap-cpufreq
and cpufreq-cpu0 don't conflict in managing the frequency of the
same CPU, we should not permit omap-cpufreq to be probed.
In the case of (2), we will not have the cpufreq-cpu0 device, hence
only omap-cpufreq will be active.
To eliminate this undesired these effects, we change omap-cpufreq
driver to have it instantiated as a platform_driver and register
"omap-cpufreq" device only when booted without device tree nodes on
OMAP platforms.
This allows the following:
a) Will only run on platforms that create the platform_device
"omap-cpufreq".
b) Since the platform_device is registered only when device tree nodes
are *not* populated, omap-cpufreq driver does not conflict with
the usage of cpufreq-cpu0 driver which is used on OMAP platforms when
device tree nodes are present.
Inspired by commit 5553f9e26f6f49a93ba732fd222eac6973a4cf35
(cpufreq: instantiate cpufreq-cpu0 as a platform_driver)
[robherring2@gmail.com: reported conflict of omap-cpufreq vs other
driver in an non-device tree supported boot]
Reported-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-04-10 06:22:01 +07:00
|
|
|
static int omap_cpufreq_remove(struct platform_device *pdev)
|
2010-08-12 07:02:43 +07:00
|
|
|
{
|
cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver
As multi-platform build is being adopted by more and more ARM platforms,
initcall function should be used very carefully. For example, when
CONFIG_ARM_OMAP2PLUS_CPUFREQ is built in the kernel, omap_cpufreq_init()
will be called on all the platforms to initialize omap-cpufreq driver.
Further, on OMAP, we now use Soc generic cpufreq-cpu0 driver using device
tree entries. To allow cpufreq-cpu0 and omap-cpufreq drivers to co-exist
for OMAP in a single image, we need to ensure the following:
1. With device tree boot, we use cpufreq-cpu0
2. With non device tree boot, we use omap-cpufreq
In the case of (1), we will have cpu OPPs and regulator registered
as part of the device tree nodes, to ensure that omap-cpufreq
and cpufreq-cpu0 don't conflict in managing the frequency of the
same CPU, we should not permit omap-cpufreq to be probed.
In the case of (2), we will not have the cpufreq-cpu0 device, hence
only omap-cpufreq will be active.
To eliminate this undesired these effects, we change omap-cpufreq
driver to have it instantiated as a platform_driver and register
"omap-cpufreq" device only when booted without device tree nodes on
OMAP platforms.
This allows the following:
a) Will only run on platforms that create the platform_device
"omap-cpufreq".
b) Since the platform_device is registered only when device tree nodes
are *not* populated, omap-cpufreq driver does not conflict with
the usage of cpufreq-cpu0 driver which is used on OMAP platforms when
device tree nodes are present.
Inspired by commit 5553f9e26f6f49a93ba732fd222eac6973a4cf35
(cpufreq: instantiate cpufreq-cpu0 as a platform_driver)
[robherring2@gmail.com: reported conflict of omap-cpufreq vs other
driver in an non-device tree supported boot]
Reported-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-04-10 06:22:01 +07:00
|
|
|
return cpufreq_unregister_driver(&omap_driver);
|
2010-08-12 07:02:43 +07:00
|
|
|
}
|
2009-01-28 09:13:38 +07:00
|
|
|
|
cpufreq: OMAP: instantiate omap-cpufreq as a platform_driver
As multi-platform build is being adopted by more and more ARM platforms,
initcall function should be used very carefully. For example, when
CONFIG_ARM_OMAP2PLUS_CPUFREQ is built in the kernel, omap_cpufreq_init()
will be called on all the platforms to initialize omap-cpufreq driver.
Further, on OMAP, we now use Soc generic cpufreq-cpu0 driver using device
tree entries. To allow cpufreq-cpu0 and omap-cpufreq drivers to co-exist
for OMAP in a single image, we need to ensure the following:
1. With device tree boot, we use cpufreq-cpu0
2. With non device tree boot, we use omap-cpufreq
In the case of (1), we will have cpu OPPs and regulator registered
as part of the device tree nodes, to ensure that omap-cpufreq
and cpufreq-cpu0 don't conflict in managing the frequency of the
same CPU, we should not permit omap-cpufreq to be probed.
In the case of (2), we will not have the cpufreq-cpu0 device, hence
only omap-cpufreq will be active.
To eliminate this undesired these effects, we change omap-cpufreq
driver to have it instantiated as a platform_driver and register
"omap-cpufreq" device only when booted without device tree nodes on
OMAP platforms.
This allows the following:
a) Will only run on platforms that create the platform_device
"omap-cpufreq".
b) Since the platform_device is registered only when device tree nodes
are *not* populated, omap-cpufreq driver does not conflict with
the usage of cpufreq-cpu0 driver which is used on OMAP platforms when
device tree nodes are present.
Inspired by commit 5553f9e26f6f49a93ba732fd222eac6973a4cf35
(cpufreq: instantiate cpufreq-cpu0 as a platform_driver)
[robherring2@gmail.com: reported conflict of omap-cpufreq vs other
driver in an non-device tree supported boot]
Reported-by: Rob Herring <robherring2@gmail.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-04-10 06:22:01 +07:00
|
|
|
static struct platform_driver omap_cpufreq_platdrv = {
|
|
|
|
.driver = {
|
|
|
|
.name = "omap-cpufreq",
|
|
|
|
},
|
|
|
|
.probe = omap_cpufreq_probe,
|
|
|
|
.remove = omap_cpufreq_remove,
|
|
|
|
};
|
|
|
|
module_platform_driver(omap_cpufreq_platdrv);
|
|
|
|
|
2010-08-12 07:02:43 +07:00
|
|
|
MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
|
|
|
|
MODULE_LICENSE("GPL");
|