2010-12-09 23:13:46 +08:00
|
|
|
/*
|
|
|
|
* OMAP SoC specific OPP wrapper function
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/
|
|
|
|
* Nishanth Menon
|
|
|
|
* Kevin Hilman
|
|
|
|
* Copyright (C) 2010 Nokia Corporation.
|
|
|
|
* Eduardo Valentin
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
|
|
* kind, whether express or implied; without even the implied warranty
|
|
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
#include <linux/module.h>
|
2013-10-16 23:39:01 +08:00
|
|
|
#include <linux/of.h>
|
2013-09-20 05:03:52 +08:00
|
|
|
#include <linux/pm_opp.h>
|
ARM: OMAP2+: PM: MPU DVFS: use generic CPU device for MPU-SS
Currently, a dummy omap_device is created for the MPU sub-system so
that a device node exists for MPU DVFS. Specifically, for the
association of MPU OPPs to a device node, and so that a voltage
regulator can be mapped to a device node.
For drivers to get a handle to this device node, an OMAP-specific API
has been used. However, the kernel already has device nodes for the
CPU(s) in the system, so we can use those instead of an OMAP-specific
dummy device and then drivers (like OMAP CPUfreq) can use generic
APIs.
To use the existing CPU device nodes, modify the OPP creation and
regulator registration to use the CPU0 device node for registraion.
NOTE: this patch always uses CPU0 as the device node. On all
OMAPs today, MPU DVFS scales all CPUs together, so this will
not be a problem, but this assumption will need to be changed
if independently scalable CPUs are introduced.
Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
2012-09-07 05:03:08 +08:00
|
|
|
#include <linux/cpu.h>
|
2010-12-09 23:13:46 +08:00
|
|
|
|
2012-10-03 08:25:48 +08:00
|
|
|
#include "omap_device.h"
|
2010-12-09 23:13:46 +08:00
|
|
|
|
|
|
|
#include "omap_opp_data.h"
|
|
|
|
|
|
|
|
/* Temp variable to allow multiple calls */
|
|
|
|
static u8 __initdata omap_table_init;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* omap_init_opp_table() - Initialize opp table as per the CPU type
|
|
|
|
* @opp_def: opp default list for this silicon
|
|
|
|
* @opp_def_size: number of opp entries for this silicon
|
|
|
|
*
|
|
|
|
* Register the initial OPP table with the OPP library based on the CPU
|
|
|
|
* type. This is meant to be used only by SoC specific registration.
|
|
|
|
*/
|
|
|
|
int __init omap_init_opp_table(struct omap_opp_def *opp_def,
|
|
|
|
u32 opp_def_size)
|
|
|
|
{
|
|
|
|
int i, r;
|
|
|
|
|
2013-10-16 23:39:01 +08:00
|
|
|
if (of_have_populated_dt())
|
|
|
|
return -EINVAL;
|
|
|
|
|
2010-12-09 23:13:46 +08:00
|
|
|
if (!opp_def || !opp_def_size) {
|
|
|
|
pr_err("%s: invalid params!\n", __func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize only if not already initialized even if the previous
|
|
|
|
* call failed, because, no reason we'd succeed again.
|
|
|
|
*/
|
|
|
|
if (omap_table_init)
|
|
|
|
return -EEXIST;
|
|
|
|
omap_table_init = 1;
|
|
|
|
|
|
|
|
/* Lets now register with OPP library */
|
2012-05-19 01:26:19 +08:00
|
|
|
for (i = 0; i < opp_def_size; i++, opp_def++) {
|
2010-12-09 23:13:46 +08:00
|
|
|
struct omap_hwmod *oh;
|
|
|
|
struct device *dev;
|
|
|
|
|
|
|
|
if (!opp_def->hwmod_name) {
|
|
|
|
pr_err("%s: NULL name of omap_hwmod, failing [%d].\n",
|
|
|
|
__func__, i);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
ARM: OMAP2+: PM: MPU DVFS: use generic CPU device for MPU-SS
Currently, a dummy omap_device is created for the MPU sub-system so
that a device node exists for MPU DVFS. Specifically, for the
association of MPU OPPs to a device node, and so that a voltage
regulator can be mapped to a device node.
For drivers to get a handle to this device node, an OMAP-specific API
has been used. However, the kernel already has device nodes for the
CPU(s) in the system, so we can use those instead of an OMAP-specific
dummy device and then drivers (like OMAP CPUfreq) can use generic
APIs.
To use the existing CPU device nodes, modify the OPP creation and
regulator registration to use the CPU0 device node for registraion.
NOTE: this patch always uses CPU0 as the device node. On all
OMAPs today, MPU DVFS scales all CPUs together, so this will
not be a problem, but this assumption will need to be changed
if independently scalable CPUs are introduced.
Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
2012-09-07 05:03:08 +08:00
|
|
|
|
|
|
|
if (!strncmp(opp_def->hwmod_name, "mpu", 3)) {
|
|
|
|
/*
|
|
|
|
* All current OMAPs share voltage rail and
|
|
|
|
* clock source, so CPU0 is used to represent
|
|
|
|
* the MPU-SS.
|
|
|
|
*/
|
|
|
|
dev = get_cpu_device(0);
|
|
|
|
} else {
|
|
|
|
oh = omap_hwmod_lookup(opp_def->hwmod_name);
|
|
|
|
if (!oh || !oh->od) {
|
|
|
|
pr_debug("%s: no hwmod or odev for %s, [%d] cannot add OPPs.\n",
|
|
|
|
__func__, opp_def->hwmod_name, i);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
dev = &oh->od->pdev->dev;
|
2010-12-09 23:13:46 +08:00
|
|
|
}
|
|
|
|
|
2013-09-20 05:03:50 +08:00
|
|
|
r = dev_pm_opp_add(dev, opp_def->freq, opp_def->u_volt);
|
2010-12-09 23:13:46 +08:00
|
|
|
if (r) {
|
2012-07-26 14:54:26 +08:00
|
|
|
dev_err(dev, "%s: add OPP %ld failed for %s [%d] result=%d\n",
|
|
|
|
__func__, opp_def->freq,
|
|
|
|
opp_def->hwmod_name, i, r);
|
2010-12-09 23:13:46 +08:00
|
|
|
} else {
|
|
|
|
if (!opp_def->default_available)
|
2013-09-20 05:03:50 +08:00
|
|
|
r = dev_pm_opp_disable(dev, opp_def->freq);
|
2010-12-09 23:13:46 +08:00
|
|
|
if (r)
|
2012-07-26 14:54:26 +08:00
|
|
|
dev_err(dev, "%s: disable %ld failed for %s [%d] result=%d\n",
|
2010-12-09 23:13:46 +08:00
|
|
|
__func__, opp_def->freq,
|
|
|
|
opp_def->hwmod_name, i, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|