forked from Minki/linux
Merge branch 'for_3.6/pm/sr-move' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm into devel-driver
This commit is contained in:
commit
9e74f218ab
@ -70,8 +70,9 @@ obj-$(CONFIG_ARCH_OMAP3) += cpuidle34xx.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += cpuidle44xx.o
|
||||
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
|
||||
obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o
|
||||
obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
|
||||
|
||||
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
|
||||
obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o
|
||||
|
||||
AFLAGS_sleep24xx.o :=-Wa,-march=armv6
|
||||
AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec)
|
||||
|
@ -14,6 +14,8 @@
|
||||
*
|
||||
* XXX these should be marked initdata for multi-OMAP kernels
|
||||
*/
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <plat/cpu.h>
|
||||
@ -29,8 +31,6 @@
|
||||
#include <plat/dmtimer.h>
|
||||
|
||||
#include "omap_hwmod_common_data.h"
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "prm-regbits-34xx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
#include "wd_timer.h"
|
||||
@ -1325,7 +1325,7 @@ static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
|
||||
};
|
||||
|
||||
static struct omap_hwmod omap34xx_sr1_hwmod = {
|
||||
.name = "sr1",
|
||||
.name = "smartreflex_mpu_iva",
|
||||
.class = &omap34xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr1_fck",
|
||||
.prcm = {
|
||||
@ -1343,7 +1343,7 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
|
||||
};
|
||||
|
||||
static struct omap_hwmod omap36xx_sr1_hwmod = {
|
||||
.name = "sr1",
|
||||
.name = "smartreflex_mpu_iva",
|
||||
.class = &omap36xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr1_fck",
|
||||
.prcm = {
|
||||
@ -1370,7 +1370,7 @@ static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
|
||||
};
|
||||
|
||||
static struct omap_hwmod omap34xx_sr2_hwmod = {
|
||||
.name = "sr2",
|
||||
.name = "smartreflex_core",
|
||||
.class = &omap34xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr2_fck",
|
||||
.prcm = {
|
||||
@ -1388,7 +1388,7 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
|
||||
};
|
||||
|
||||
static struct omap_hwmod omap36xx_sr2_hwmod = {
|
||||
.name = "sr2",
|
||||
.name = "smartreflex_core",
|
||||
.class = &omap36xx_smartreflex_hwmod_class,
|
||||
.main_clk = "sr2_fck",
|
||||
.prcm = {
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/cpu.h>
|
||||
@ -32,8 +33,6 @@
|
||||
#include <plat/common.h>
|
||||
|
||||
#include "omap_hwmod_common_data.h"
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "cm1_44xx.h"
|
||||
#include "cm2_44xx.h"
|
||||
#include "prm44xx.h"
|
||||
|
@ -88,7 +88,7 @@ extern void enable_omap3630_toggle_l2_on_restore(void);
|
||||
static inline void enable_omap3630_toggle_l2_on_restore(void) { }
|
||||
#endif /* defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) */
|
||||
|
||||
#ifdef CONFIG_OMAP_SMARTREFLEX
|
||||
#ifdef CONFIG_POWER_AVS_OMAP
|
||||
extern int omap_devinit_smartreflex(void);
|
||||
extern void omap_enable_smartreflex_on_init(void);
|
||||
#else
|
||||
|
@ -11,36 +11,37 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include <linux/power/smartreflex.h>
|
||||
#include "voltage.h"
|
||||
|
||||
static int sr_class3_enable(struct voltagedomain *voltdm)
|
||||
static int sr_class3_enable(struct omap_sr *sr)
|
||||
{
|
||||
unsigned long volt = voltdm_get_voltage(voltdm);
|
||||
unsigned long volt = voltdm_get_voltage(sr->voltdm);
|
||||
|
||||
if (!volt) {
|
||||
pr_warning("%s: Curr voltage unknown. Cannot enable sr_%s\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: Curr voltage unknown. Cannot enable %s\n",
|
||||
__func__, sr->name);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
omap_vp_enable(voltdm);
|
||||
return sr_enable(voltdm, volt);
|
||||
omap_vp_enable(sr->voltdm);
|
||||
return sr_enable(sr->voltdm, volt);
|
||||
}
|
||||
|
||||
static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
|
||||
static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
|
||||
{
|
||||
sr_disable_errgen(voltdm);
|
||||
omap_vp_disable(voltdm);
|
||||
sr_disable(voltdm);
|
||||
sr_disable_errgen(sr->voltdm);
|
||||
omap_vp_disable(sr->voltdm);
|
||||
sr_disable(sr->voltdm);
|
||||
if (is_volt_reset)
|
||||
voltdm_reset(voltdm);
|
||||
voltdm_reset(sr->voltdm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_class3_configure(struct voltagedomain *voltdm)
|
||||
static int sr_class3_configure(struct omap_sr *sr)
|
||||
{
|
||||
return sr_configure_errgen(voltdm);
|
||||
return sr_configure_errgen(sr->voltdm);
|
||||
}
|
||||
|
||||
/* SR class3 structure */
|
||||
|
@ -17,6 +17,7 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
@ -24,7 +25,6 @@
|
||||
|
||||
#include <plat/omap_device.h>
|
||||
|
||||
#include "smartreflex.h"
|
||||
#include "voltage.h"
|
||||
#include "control.h"
|
||||
#include "pm.h"
|
||||
@ -36,7 +36,10 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
||||
struct omap_sr_data *sr_data)
|
||||
{
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
int i, count = 0;
|
||||
int i, j, count = 0;
|
||||
|
||||
sr_data->nvalue_count = 0;
|
||||
sr_data->nvalue_table = NULL;
|
||||
|
||||
while (volt_data[count].volt_nominal)
|
||||
count++;
|
||||
@ -44,8 +47,14 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
||||
nvalue_table = kzalloc(sizeof(struct omap_sr_nvalue_table)*count,
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!nvalue_table) {
|
||||
pr_err("OMAP: SmartReflex: cannot allocate memory for n-value table\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < count; i++) {
|
||||
u32 v;
|
||||
|
||||
/*
|
||||
* In OMAP4 the efuse registers are 24 bit aligned.
|
||||
* A __raw_readl will fail for non-32 bit aligned address
|
||||
@ -58,15 +67,30 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
|
||||
omap_ctrl_readb(offset + 1) << 8 |
|
||||
omap_ctrl_readb(offset + 2) << 16;
|
||||
} else {
|
||||
v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
|
||||
v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
|
||||
}
|
||||
|
||||
nvalue_table[i].efuse_offs = volt_data[i].sr_efuse_offs;
|
||||
nvalue_table[i].nvalue = v;
|
||||
/*
|
||||
* Many OMAP SoCs don't have the eFuse values set.
|
||||
* For example, pretty much all OMAP3xxx before
|
||||
* ES3.something.
|
||||
*
|
||||
* XXX There needs to be some way for board files or
|
||||
* userspace to add these in.
|
||||
*/
|
||||
if (v == 0)
|
||||
continue;
|
||||
|
||||
nvalue_table[j].nvalue = v;
|
||||
nvalue_table[j].efuse_offs = volt_data[i].sr_efuse_offs;
|
||||
nvalue_table[j].errminlimit = volt_data[i].sr_errminlimit;
|
||||
nvalue_table[j].volt_nominal = volt_data[i].volt_nominal;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
sr_data->nvalue_table = nvalue_table;
|
||||
sr_data->nvalue_count = count;
|
||||
sr_data->nvalue_count = j;
|
||||
}
|
||||
|
||||
static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
|
||||
@ -93,6 +117,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sr_data->name = oh->name;
|
||||
sr_data->ip_type = oh->class->rev;
|
||||
sr_data->senn_mod = 0x1;
|
||||
sr_data->senp_mod = 0x1;
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/voltage.h>
|
||||
|
||||
#include "vc.h"
|
||||
#include "vp.h"
|
||||
|
||||
@ -90,25 +92,6 @@ struct voltagedomain {
|
||||
struct omap_volt_data *volt_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_volt_data - Omap voltage specific data.
|
||||
* @voltage_nominal: The possible voltage value in uV
|
||||
* @sr_efuse_offs: The offset of the efuse register(from system
|
||||
* control module base address) from where to read
|
||||
* the n-target value for the smartreflex module.
|
||||
* @sr_errminlimit: Error min limit value for smartreflex. This value
|
||||
* differs at differnet opp and thus is linked
|
||||
* with voltage.
|
||||
* @vp_errorgain: Error gain value for the voltage processor. This
|
||||
* field also differs according to the voltage/opp.
|
||||
*/
|
||||
struct omap_volt_data {
|
||||
u32 volt_nominal;
|
||||
u32 sr_efuse_offs;
|
||||
u8 sr_errminlimit;
|
||||
u8 vp_errgain;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_voltdm_pmic - PMIC specific data required by voltage driver.
|
||||
* @slew_rate: PMIC slew rate (in uv/us)
|
||||
|
@ -45,31 +45,30 @@ config OMAP_DEBUG_LEDS
|
||||
depends on OMAP_DEBUG_DEVICES
|
||||
default y if LEDS_CLASS
|
||||
|
||||
config OMAP_SMARTREFLEX
|
||||
bool "SmartReflex support"
|
||||
depends on (ARCH_OMAP3 || ARCH_OMAP4) && PM
|
||||
config POWER_AVS_OMAP
|
||||
bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
|
||||
depends on POWER_AVS && (ARCH_OMAP3 || ARCH_OMAP4) && PM
|
||||
help
|
||||
Say Y if you want to enable SmartReflex.
|
||||
|
||||
SmartReflex can perform continuous dynamic voltage
|
||||
scaling around the nominal operating point voltage
|
||||
according to silicon characteristics and operating
|
||||
conditions. Enabling SmartReflex reduces power
|
||||
consumption.
|
||||
Say Y to enable AVS(Adaptive Voltage Scaling)
|
||||
support on OMAP containing the version 1 or
|
||||
version 2 of the SmartReflex IP.
|
||||
V1 is the 65nm version used in OMAP3430.
|
||||
V2 is the update for the 45nm version of the IP used in OMAP3630
|
||||
and OMAP4430
|
||||
|
||||
Please note, that by default SmartReflex is only
|
||||
initialized. To enable the automatic voltage
|
||||
compensation for vdd mpu and vdd core from user space,
|
||||
initialized and not enabled. To enable the automatic voltage
|
||||
compensation for vdd mpu and vdd core from user space,
|
||||
user must write 1 to
|
||||
/debug/voltage/vdd_<X>/smartreflex/autocomp,
|
||||
where X is mpu or core for OMAP3.
|
||||
/debug/smartreflex/sr_<X>/autocomp,
|
||||
where X is mpu_iva or core for OMAP3.
|
||||
Optionally autocompensation can be enabled in the kernel
|
||||
by default during system init via the enable_on_init flag
|
||||
which an be passed as platform data to the smartreflex driver.
|
||||
|
||||
config OMAP_SMARTREFLEX_CLASS3
|
||||
config POWER_AVS_OMAP_CLASS3
|
||||
bool "Class 3 mode of Smartreflex Implementation"
|
||||
depends on OMAP_SMARTREFLEX && TWL4030_CORE
|
||||
depends on POWER_AVS_OMAP && TWL4030_CORE
|
||||
help
|
||||
Say Y to enable Class 3 implementation of Smartreflex
|
||||
|
||||
|
@ -11,10 +11,29 @@
|
||||
#ifndef __ARCH_ARM_OMAP_VOLTAGE_H
|
||||
#define __ARCH_ARM_OMAP_VOLTAGE_H
|
||||
|
||||
/**
|
||||
* struct omap_volt_data - Omap voltage specific data.
|
||||
* @voltage_nominal: The possible voltage value in uV
|
||||
* @sr_efuse_offs: The offset of the efuse register(from system
|
||||
* control module base address) from where to read
|
||||
* the n-target value for the smartreflex module.
|
||||
* @sr_errminlimit: Error min limit value for smartreflex. This value
|
||||
* differs at differnet opp and thus is linked
|
||||
* with voltage.
|
||||
* @vp_errorgain: Error gain value for the voltage processor. This
|
||||
* field also differs according to the voltage/opp.
|
||||
*/
|
||||
struct omap_volt_data {
|
||||
u32 volt_nominal;
|
||||
u32 sr_efuse_offs;
|
||||
u8 sr_errminlimit;
|
||||
u8 vp_errgain;
|
||||
};
|
||||
struct voltagedomain;
|
||||
|
||||
struct voltagedomain *voltdm_lookup(const char *name);
|
||||
int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt);
|
||||
unsigned long voltdm_get_voltage(struct voltagedomain *voltdm);
|
||||
|
||||
struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
|
||||
unsigned long volt);
|
||||
#endif
|
||||
|
@ -310,3 +310,5 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
|
||||
Say Y to enable battery temperature measurements using
|
||||
thermistor connected on BATCTRL ADC.
|
||||
endif # POWER_SUPPLY
|
||||
|
||||
source "drivers/power/avs/Kconfig"
|
||||
|
@ -43,4 +43,5 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
|
||||
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
|
||||
|
12
drivers/power/avs/Kconfig
Normal file
12
drivers/power/avs/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
menuconfig POWER_AVS
|
||||
tristate "Adaptive Voltage Scaling class support"
|
||||
help
|
||||
AVS is a power management technique which finely controls the
|
||||
operating voltage of a device in order to optimize (i.e. reduce)
|
||||
its power consumption.
|
||||
At a given operating point the voltage is adapted depending on
|
||||
static factors (chip manufacturing process) and dynamic factors
|
||||
(temperature depending performance).
|
||||
AVS is also called SmartReflex on OMAP devices.
|
||||
|
||||
Say Y here to enable Adaptive Voltage Scaling class support.
|
1
drivers/power/avs/Makefile
Normal file
1
drivers/power/avs/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Author: Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||
* Thara Gopinath <thara@ti.com>
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
@ -25,39 +25,12 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "pm.h"
|
||||
#include "smartreflex.h"
|
||||
#include <linux/power/smartreflex.h>
|
||||
|
||||
#define SMARTREFLEX_NAME_LEN 16
|
||||
#define NVALUE_NAME_LEN 40
|
||||
#define SR_DISABLE_TIMEOUT 200
|
||||
|
||||
struct omap_sr {
|
||||
struct list_head node;
|
||||
struct platform_device *pdev;
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
struct voltagedomain *voltdm;
|
||||
struct dentry *dbg_dir;
|
||||
unsigned int irq;
|
||||
int srid;
|
||||
int ip_type;
|
||||
int nvalue_count;
|
||||
bool autocomp_active;
|
||||
u32 clk_length;
|
||||
u32 err_weight;
|
||||
u32 err_minlimit;
|
||||
u32 err_maxlimit;
|
||||
u32 accum_data;
|
||||
u32 senn_avgweight;
|
||||
u32 senp_avgweight;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/* sr_list contains all the instances of smartreflex module */
|
||||
static LIST_HEAD(sr_list);
|
||||
|
||||
@ -148,7 +121,7 @@ static irqreturn_t sr_interrupt(int irq, void *data)
|
||||
}
|
||||
|
||||
if (sr_class->notify)
|
||||
sr_class->notify(sr_info->voltdm, status);
|
||||
sr_class->notify(sr_info, status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -207,7 +180,7 @@ static void sr_set_regfields(struct omap_sr *sr)
|
||||
sr->err_weight = OMAP3430_SR_ERRWEIGHT;
|
||||
sr->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
|
||||
sr->accum_data = OMAP3430_SR_ACCUMDATA;
|
||||
if (!(strcmp(sr->voltdm->name, "mpu"))) {
|
||||
if (!(strcmp(sr->name, "smartreflex_mpu_iva"))) {
|
||||
sr->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
|
||||
sr->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
|
||||
} else {
|
||||
@ -226,7 +199,7 @@ static void sr_start_vddautocomp(struct omap_sr *sr)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sr_class->enable(sr->voltdm))
|
||||
if (!sr_class->enable(sr))
|
||||
sr->autocomp_active = true;
|
||||
}
|
||||
|
||||
@ -240,7 +213,7 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
|
||||
}
|
||||
|
||||
if (sr->autocomp_active) {
|
||||
sr_class->disable(sr->voltdm, 1);
|
||||
sr_class->disable(sr, 1);
|
||||
sr->autocomp_active = false;
|
||||
}
|
||||
}
|
||||
@ -258,19 +231,13 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
|
||||
*/
|
||||
static int sr_late_init(struct omap_sr *sr_info)
|
||||
{
|
||||
char *name;
|
||||
struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
|
||||
struct resource *mem;
|
||||
int ret = 0;
|
||||
|
||||
if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
|
||||
name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
|
||||
if (name == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
ret = request_irq(sr_info->irq, sr_interrupt,
|
||||
0, name, sr_info);
|
||||
0, sr_info->name, sr_info);
|
||||
if (ret)
|
||||
goto error;
|
||||
disable_irq(sr_info->irq);
|
||||
@ -289,7 +256,6 @@ error:
|
||||
dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
|
||||
"interrupt handler. Smartreflex will"
|
||||
"not function as desired\n", __func__);
|
||||
kfree(name);
|
||||
kfree(sr_info);
|
||||
|
||||
return ret;
|
||||
@ -320,9 +286,9 @@ static void sr_v1_disable(struct omap_sr *sr)
|
||||
* Wait for SR to be disabled.
|
||||
* wait until ERRCONFIG.MCUDISACKINTST = 1. Typical latency is 1us.
|
||||
*/
|
||||
omap_test_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
|
||||
ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
sr_test_cond_timeout((sr_read_reg(sr, ERRCONFIG_V1) &
|
||||
ERRCONFIG_MCUDISACKINTST), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
|
||||
if (timeout >= SR_DISABLE_TIMEOUT)
|
||||
dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
|
||||
@ -365,9 +331,9 @@ static void sr_v2_disable(struct omap_sr *sr)
|
||||
* Wait for SR to be disabled.
|
||||
* wait until IRQSTATUS.MCUDISACKINTST = 1. Typical latency is 1us.
|
||||
*/
|
||||
omap_test_timeout((sr_read_reg(sr, IRQSTATUS) &
|
||||
IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
sr_test_cond_timeout((sr_read_reg(sr, IRQSTATUS) &
|
||||
IRQSTATUS_MCUDISABLEACKINT), SR_DISABLE_TIMEOUT,
|
||||
timeout);
|
||||
|
||||
if (timeout >= SR_DISABLE_TIMEOUT)
|
||||
dev_warn(&sr->pdev->dev, "%s: Smartreflex disable timedout\n",
|
||||
@ -378,22 +344,23 @@ static void sr_v2_disable(struct omap_sr *sr)
|
||||
sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUDISABLEACKINT);
|
||||
}
|
||||
|
||||
static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
|
||||
static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
|
||||
struct omap_sr *sr, u32 efuse_offs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!sr->nvalue_table) {
|
||||
dev_warn(&sr->pdev->dev, "%s: Missing ntarget value table\n",
|
||||
__func__);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < sr->nvalue_count; i++) {
|
||||
if (sr->nvalue_table[i].efuse_offs == efuse_offs)
|
||||
return sr->nvalue_table[i].nvalue;
|
||||
return &sr->nvalue_table[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Public Functions */
|
||||
@ -419,8 +386,7 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
@ -487,8 +453,7 @@ int sr_disable_errgen(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
@ -538,8 +503,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
@ -620,12 +584,11 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
||||
{
|
||||
struct omap_volt_data *volt_data;
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
u32 nvalue_reciprocal;
|
||||
struct omap_sr_nvalue_table *nvalue_row;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return PTR_ERR(sr);
|
||||
}
|
||||
|
||||
@ -637,16 +600,16 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
||||
return PTR_ERR(volt_data);
|
||||
}
|
||||
|
||||
nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
|
||||
nvalue_row = sr_retrieve_nvalue_row(sr, volt_data->sr_efuse_offs);
|
||||
|
||||
if (!nvalue_reciprocal) {
|
||||
dev_warn(&sr->pdev->dev, "%s: NVALUE = 0 at voltage %ld\n",
|
||||
__func__, volt);
|
||||
if (!nvalue_row) {
|
||||
dev_warn(&sr->pdev->dev, "%s: failure getting SR data for this voltage %ld\n",
|
||||
__func__, volt);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* errminlimit is opp dependent and hence linked to voltage */
|
||||
sr->err_minlimit = volt_data->sr_errminlimit;
|
||||
sr->err_minlimit = nvalue_row->errminlimit;
|
||||
|
||||
pm_runtime_get_sync(&sr->pdev->dev);
|
||||
|
||||
@ -655,11 +618,11 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
|
||||
return 0;
|
||||
|
||||
/* Configure SR */
|
||||
ret = sr_class->configure(voltdm);
|
||||
ret = sr_class->configure(sr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
|
||||
sr_write_reg(sr, NVALUERECIPROCAL, nvalue_row->nvalue);
|
||||
|
||||
/* SRCONFIG - enable SR */
|
||||
sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
|
||||
@ -678,8 +641,7 @@ void sr_disable(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -759,8 +721,7 @@ void omap_sr_enable(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -773,7 +734,7 @@ void omap_sr_enable(struct voltagedomain *voltdm)
|
||||
return;
|
||||
}
|
||||
|
||||
sr_class->enable(voltdm);
|
||||
sr_class->enable(sr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -792,8 +753,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -806,7 +766,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
|
||||
return;
|
||||
}
|
||||
|
||||
sr_class->disable(voltdm, 0);
|
||||
sr_class->disable(sr, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -825,8 +785,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
|
||||
struct omap_sr *sr = _sr_lookup(voltdm);
|
||||
|
||||
if (IS_ERR(sr)) {
|
||||
pr_warning("%s: omap_sr struct for sr_%s not found\n",
|
||||
__func__, voltdm->name);
|
||||
pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -839,7 +798,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
|
||||
return;
|
||||
}
|
||||
|
||||
sr_class->disable(voltdm, 1);
|
||||
sr_class->disable(sr, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -911,9 +870,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
struct omap_sr_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *mem, *irq;
|
||||
struct dentry *nvalue_dir;
|
||||
struct omap_volt_data *volt_data;
|
||||
int i, ret = 0;
|
||||
char *name;
|
||||
|
||||
sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
|
||||
if (!sr_info) {
|
||||
@ -950,6 +907,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
|
||||
sr_info->name = kasprintf(GFP_KERNEL, "%s", pdata->name);
|
||||
if (!sr_info->name) {
|
||||
dev_err(&pdev->dev, "%s: Unable to alloc SR instance name\n",
|
||||
__func__);
|
||||
ret = -ENOMEM;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
sr_info->pdev = pdev;
|
||||
sr_info->srid = pdev->id;
|
||||
sr_info->voltdm = pdata->voltdm;
|
||||
@ -997,20 +962,12 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
|
||||
if (!name) {
|
||||
dev_err(&pdev->dev, "%s: Unable to alloc debugfs name\n",
|
||||
__func__);
|
||||
ret = -ENOMEM;
|
||||
goto err_iounmap;
|
||||
}
|
||||
sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
|
||||
kfree(name);
|
||||
sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir);
|
||||
if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
|
||||
dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
|
||||
__func__);
|
||||
ret = PTR_ERR(sr_info->dbg_dir);
|
||||
goto err_iounmap;
|
||||
goto err_free_name;
|
||||
}
|
||||
|
||||
(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
|
||||
@ -1019,8 +976,6 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
&sr_info->err_weight);
|
||||
(void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
|
||||
&sr_info->err_maxlimit);
|
||||
(void) debugfs_create_x32("errminlimit", S_IRUGO, sr_info->dbg_dir,
|
||||
&sr_info->err_minlimit);
|
||||
|
||||
nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
|
||||
if (IS_ERR_OR_NULL(nvalue_dir)) {
|
||||
@ -1030,12 +985,10 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
goto err_debugfs;
|
||||
}
|
||||
|
||||
omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
|
||||
if (!volt_data) {
|
||||
dev_warn(&pdev->dev, "%s: No Voltage table for the"
|
||||
" corresponding vdd vdd_%s. Cannot create debugfs"
|
||||
"entries for n-values\n",
|
||||
__func__, sr_info->voltdm->name);
|
||||
if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) {
|
||||
dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n",
|
||||
__func__, sr_info->name);
|
||||
|
||||
ret = -ENODATA;
|
||||
goto err_debugfs;
|
||||
}
|
||||
@ -1043,16 +996,23 @@ static int __init omap_sr_probe(struct platform_device *pdev)
|
||||
for (i = 0; i < sr_info->nvalue_count; i++) {
|
||||
char name[NVALUE_NAME_LEN + 1];
|
||||
|
||||
snprintf(name, sizeof(name), "volt_%d",
|
||||
volt_data[i].volt_nominal);
|
||||
snprintf(name, sizeof(name), "volt_%lu",
|
||||
sr_info->nvalue_table[i].volt_nominal);
|
||||
(void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
|
||||
&(sr_info->nvalue_table[i].nvalue));
|
||||
snprintf(name, sizeof(name), "errminlimit_%lu",
|
||||
sr_info->nvalue_table[i].volt_nominal);
|
||||
(void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
|
||||
&(sr_info->nvalue_table[i].errminlimit));
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_debugfs:
|
||||
debugfs_remove_recursive(sr_info->dbg_dir);
|
||||
err_free_name:
|
||||
kfree(sr_info->name);
|
||||
err_iounmap:
|
||||
list_del(&sr_info->node);
|
||||
iounmap(sr_info->base);
|
||||
@ -1089,6 +1049,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
|
||||
|
||||
list_del(&sr_info->node);
|
||||
iounmap(sr_info->base);
|
||||
kfree(sr_info->name);
|
||||
kfree(sr_info);
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
@ -17,12 +17,13 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H
|
||||
#define __ASM_ARM_OMAP_SMARTREFLEX_H
|
||||
#ifndef __POWER_SMARTREFLEX_H
|
||||
#define __POWER_SMARTREFLEX_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "voltage.h"
|
||||
#include <linux/delay.h>
|
||||
#include <plat/voltage.h>
|
||||
|
||||
/*
|
||||
* Different Smartreflex IPs version. The v1 is the 65nm version used in
|
||||
@ -142,6 +143,51 @@
|
||||
#define OMAP3430_SR_ERRWEIGHT 0x04
|
||||
#define OMAP3430_SR_ERRMAXLIMIT 0x02
|
||||
|
||||
struct omap_sr {
|
||||
char *name;
|
||||
struct list_head node;
|
||||
struct platform_device *pdev;
|
||||
struct omap_sr_nvalue_table *nvalue_table;
|
||||
struct voltagedomain *voltdm;
|
||||
struct dentry *dbg_dir;
|
||||
unsigned int irq;
|
||||
int srid;
|
||||
int ip_type;
|
||||
int nvalue_count;
|
||||
bool autocomp_active;
|
||||
u32 clk_length;
|
||||
u32 err_weight;
|
||||
u32 err_minlimit;
|
||||
u32 err_maxlimit;
|
||||
u32 accum_data;
|
||||
u32 senn_avgweight;
|
||||
u32 senp_avgweight;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/**
|
||||
* test_cond_timeout - busy-loop, testing a condition
|
||||
* @cond: condition to test until it evaluates to true
|
||||
* @timeout: maximum number of microseconds in the timeout
|
||||
* @index: loop index (integer)
|
||||
*
|
||||
* Loop waiting for @cond to become true or until at least @timeout
|
||||
* microseconds have passed. To use, define some integer @index in the
|
||||
* calling code. After running, if @index == @timeout, then the loop has
|
||||
* timed out.
|
||||
*
|
||||
* Copied from omap_test_timeout */
|
||||
#define sr_test_cond_timeout(cond, timeout, index) \
|
||||
({ \
|
||||
for (index = 0; index < timeout; index++) { \
|
||||
if (cond) \
|
||||
break; \
|
||||
udelay(1); \
|
||||
} \
|
||||
})
|
||||
|
||||
/**
|
||||
* struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
|
||||
* pmic specific info to smartreflex driver
|
||||
@ -161,7 +207,7 @@ struct omap_smartreflex_dev_attr {
|
||||
const char *sensor_voltdm_name;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OMAP_SMARTREFLEX
|
||||
#ifdef CONFIG_POWER_AVS_OMAP
|
||||
/*
|
||||
* The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
|
||||
* The smartreflex class driver should pass the class type.
|
||||
@ -186,10 +232,10 @@ struct omap_smartreflex_dev_attr {
|
||||
* based decisions.
|
||||
*/
|
||||
struct omap_sr_class_data {
|
||||
int (*enable)(struct voltagedomain *voltdm);
|
||||
int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
|
||||
int (*configure)(struct voltagedomain *voltdm);
|
||||
int (*notify)(struct voltagedomain *voltdm, u32 status);
|
||||
int (*enable)(struct omap_sr *sr);
|
||||
int (*disable)(struct omap_sr *sr, int is_volt_reset);
|
||||
int (*configure)(struct omap_sr *sr);
|
||||
int (*notify)(struct omap_sr *sr, u32 status);
|
||||
u8 notify_flags;
|
||||
u8 class_type;
|
||||
};
|
||||
@ -197,17 +243,22 @@ struct omap_sr_class_data {
|
||||
/**
|
||||
* struct omap_sr_nvalue_table - Smartreflex n-target value info
|
||||
*
|
||||
* @efuse_offs: The offset of the efuse where n-target values are stored.
|
||||
* @nvalue: The n-target value.
|
||||
* @efuse_offs: The offset of the efuse where n-target values are stored.
|
||||
* @nvalue: The n-target value.
|
||||
* @errminlimit: The value of the ERRMINLIMIT bitfield for this n-target
|
||||
* @volt_nominal: microvolts DC that the VDD is initially programmed to
|
||||
*/
|
||||
struct omap_sr_nvalue_table {
|
||||
u32 efuse_offs;
|
||||
u32 nvalue;
|
||||
u32 errminlimit;
|
||||
unsigned long volt_nominal;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct omap_sr_data - Smartreflex platform data.
|
||||
*
|
||||
* @name: instance name
|
||||
* @ip_type: Smartreflex IP type.
|
||||
* @senp_mod: SENPENABLE value for the sr
|
||||
* @senn_mod: SENNENABLE value for sr
|
||||
@ -219,6 +270,7 @@ struct omap_sr_nvalue_table {
|
||||
* @voltdm: Pointer to the voltage domain associated with the SR
|
||||
*/
|
||||
struct omap_sr_data {
|
||||
const char *name;
|
||||
int ip_type;
|
||||
u32 senp_mod;
|
||||
u32 senn_mod;
|
Loading…
Reference in New Issue
Block a user