From patchwork Thu Mar 31 00:16:19 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Hilman X-Patchwork-Id: 678231 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p2V0Gf3V032632 for ; Thu, 31 Mar 2011 00:16:42 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933345Ab1CaAQk (ORCPT ); Wed, 30 Mar 2011 20:16:40 -0400 Received: from na3sys009aog113.obsmtp.com ([74.125.149.209]:39146 "EHLO na3sys009aog113.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933303Ab1CaAQj (ORCPT ); Wed, 30 Mar 2011 20:16:39 -0400 Received: from source ([209.85.214.182]) (using TLSv1) by na3sys009aob113.postini.com ([74.125.148.12]) with SMTP ID DSNKTZPH5m2tBra8QdtYRYG+qLcwGuMCIA63@postini.com; Wed, 30 Mar 2011 17:16:39 PDT Received: by mail-iw0-f182.google.com with SMTP id 33so3147810iwn.27 for ; Wed, 30 Mar 2011 17:16:38 -0700 (PDT) Received: by 10.43.70.138 with SMTP id yg10mr2136710icb.495.1301530598712; Wed, 30 Mar 2011 17:16:38 -0700 (PDT) Received: from localhost (c-24-18-179-55.hsd1.wa.comcast.net [24.18.179.55]) by mx.google.com with ESMTPS id g16sm344370ibb.37.2011.03.30.17.16.37 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 30 Mar 2011 17:16:38 -0700 (PDT) From: Kevin Hilman To: linux-omap@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Subject: [PATCH 16/17] OMAP2+: voltage: split out voltage processor (VP) code into new layer Date: Wed, 30 Mar 2011 17:16:19 -0700 Message-Id: <1301530580-12046-17-git-send-email-khilman@ti.com> X-Mailer: git-send-email 1.7.4 In-Reply-To: <1301530580-12046-1-git-send-email-khilman@ti.com> References: <1301530580-12046-1-git-send-email-khilman@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 31 Mar 2011 00:16:42 +0000 (UTC) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 1301cce..0a797ec 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -90,7 +90,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \ # OMAP voltage domains ifeq ($(CONFIG_PM),y) -voltagedomain-common := voltage.o vc.o +voltagedomain-common := voltage.o vc.o vp.o obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ voltagedomains2xxx_data.o obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index afe3356..fe13784 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -46,10 +46,6 @@ static LIST_HEAD(voltdm_list); #define VOLTAGE_DIR_SIZE 16 static struct dentry *voltage_dir; -/* Init function pointers */ -static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, - unsigned long target_volt); - static u32 omap3_voltage_read_reg(u16 mod, u8 offset) { return omap2_prm_read_mod_reg(mod, offset); @@ -105,7 +101,7 @@ static int __init _config_common_vdd_data(struct voltagedomain *voltdm) sys_clk_speed /= 1000; /* Generic voltage parameters */ - vdd->volt_scale = vp_forceupdate_scale_voltage; + vdd->volt_scale = omap_vp_forceupdate_scale; vdd->vp_enabled = false; vdd->vp_rt_data.vpconfig_erroroffset = @@ -127,30 +123,6 @@ static int __init _config_common_vdd_data(struct voltagedomain *voltdm) return 0; } -/* Voltage debugfs support */ -static int vp_volt_debug_get(void *data, u64 *val) -{ - struct voltagedomain *voltdm = (struct voltagedomain *)data; - struct omap_vdd_info *vdd = voltdm->vdd; - u8 vsel; - - if (!vdd) { - pr_warning("Wrong paramater passed\n"); - return -EINVAL; - } - - vsel = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->voltage); - - if (!vdd->pmic_info->vsel_to_uv) { - pr_warning("PMIC function to convert vsel to voltage" - "in uV not registerd\n"); - return -EINVAL; - } - - *val = vdd->pmic_info->vsel_to_uv(vsel); - return 0; -} - static int nom_volt_debug_get(void *data, u64 *val) { struct voltagedomain *voltdm = (struct voltagedomain *)data; @@ -165,85 +137,8 @@ static int nom_volt_debug_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n"); DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL, "%llu\n"); -static void vp_latch_vsel(struct voltagedomain *voltdm) -{ - u32 vpconfig; - unsigned long uvdc; - char vsel; - struct omap_vdd_info *vdd = voltdm->vdd; - - uvdc = omap_voltage_get_nom_volt(voltdm); - if (!uvdc) { - pr_warning("%s: unable to find current voltage for vdd_%s\n", - __func__, voltdm->name); - return; - } - - if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { - pr_warning("%s: PMIC function to convert voltage in uV to" - " vsel not registered\n", __func__); - return; - } - - vsel = vdd->pmic_info->uv_to_vsel(uvdc); - - vpconfig = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvoltage_mask | - vdd->vp_data->vp_common->vpconfig_initvdd); - vpconfig |= vsel << vdd->vp_data->vp_common->vpconfig_initvoltage_shift; - - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* Trigger initVDD value copy to voltage processor */ - vdd->write_reg((vpconfig | vdd->vp_data->vp_common->vpconfig_initvdd), - vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* Clear initVDD copy trigger bit */ - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); -} - -/* Generic voltage init functions */ -static void __init vp_init(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd = voltdm->vdd; - u32 vp_val; - - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, voltdm->name); - return; - } - - vp_val = vdd->vp_rt_data.vpconfig_erroroffset | - (vdd->vp_rt_data.vpconfig_errorgain << - vdd->vp_data->vp_common->vpconfig_errorgain_shift) | - vdd->vp_data->vp_common->vpconfig_timeouten; - vdd->write_reg(vp_val, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin << - vdd->vp_data->vp_common->vstepmin_smpswaittimemin_shift) | - (vdd->vp_rt_data.vstepmin_stepmin << - vdd->vp_data->vp_common->vstepmin_stepmin_shift)); - vdd->write_reg(vp_val, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vstepmin); - - vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax << - vdd->vp_data->vp_common->vstepmax_smpswaittimemax_shift) | - (vdd->vp_rt_data.vstepmax_stepmax << - vdd->vp_data->vp_common->vstepmax_stepmax_shift)); - vdd->write_reg(vp_val, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vstepmax); - - vp_val = ((vdd->vp_rt_data.vlimitto_vddmax << - vdd->vp_data->vp_common->vlimitto_vddmax_shift) | - (vdd->vp_rt_data.vlimitto_vddmin << - vdd->vp_data->vp_common->vlimitto_vddmin_shift) | - (vdd->vp_rt_data.vlimitto_timeout << - vdd->vp_data->vp_common->vlimitto_timeout_shift)); - vdd->write_reg(vp_val, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vlimitto); -} - static void __init vdd_debugfs_init(struct voltagedomain *voltdm) { char *name; @@ -268,125 +163,11 @@ static void __init vdd_debugfs_init(struct voltagedomain *voltdm) return; } - (void) debugfs_create_x16("vp_errorgain", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vpconfig_errorgain)); - (void) debugfs_create_x16("vp_smpswaittimemin", S_IRUGO, - vdd->debug_dir, - &(vdd->vp_rt_data.vstepmin_smpswaittimemin)); - (void) debugfs_create_x8("vp_stepmin", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vstepmin_stepmin)); - (void) debugfs_create_x16("vp_smpswaittimemax", S_IRUGO, - vdd->debug_dir, - &(vdd->vp_rt_data.vstepmax_smpswaittimemax)); - (void) debugfs_create_x8("vp_stepmax", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vstepmax_stepmax)); - (void) debugfs_create_x8("vp_vddmax", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_vddmax)); - (void) debugfs_create_x8("vp_vddmin", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_vddmin)); - (void) debugfs_create_x16("vp_timeout", S_IRUGO, vdd->debug_dir, - &(vdd->vp_rt_data.vlimitto_timeout)); - (void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd->debug_dir, - (void *) voltdm, &vp_volt_debug_fops); (void) debugfs_create_file("curr_nominal_volt", S_IRUGO, vdd->debug_dir, (void *) voltdm, &nom_volt_debug_fops); } -/* VP force update method of voltage scaling */ -static int vp_forceupdate_scale_voltage(struct voltagedomain *voltdm, - unsigned long target_volt) -{ - struct omap_vdd_info *vdd = voltdm->vdd; - u32 vpconfig; - u8 target_vsel, current_vsel; - int ret, timeout = 0; - - ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); - if (ret) - return ret; - - /* - * Clear all pending TransactionDone interrupt/status. Typical latency - * is <3us - */ - while (timeout++ < VP_TRANXDONE_TIMEOUT) { - vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status, - vdd->prm_irqst_mod, vdd->prm_irqst_reg); - if (!(vdd->read_reg(vdd->prm_irqst_mod, vdd->prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status)) - break; - udelay(1); - } - if (timeout >= VP_TRANXDONE_TIMEOUT) { - pr_warning("%s: vdd_%s TRANXDONE timeout exceeded." - "Voltage change aborted", __func__, voltdm->name); - return -ETIMEDOUT; - } - - /* Configure for VP-Force Update */ - vpconfig = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvdd | - vdd->vp_data->vp_common->vpconfig_forceupdate | - vdd->vp_data->vp_common->vpconfig_initvoltage_mask); - vpconfig |= ((target_vsel << - vdd->vp_data->vp_common->vpconfig_initvoltage_shift)); - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* Trigger initVDD value copy to voltage processor */ - vpconfig |= vdd->vp_data->vp_common->vpconfig_initvdd; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* Force update of voltage */ - vpconfig |= vdd->vp_data->vp_common->vpconfig_forceupdate; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* - * Wait for TransactionDone. Typical latency is <200us. - * Depends on SMPSWAITTIMEMIN/MAX and voltage change - */ - timeout = 0; - omap_test_timeout((vdd->read_reg(vdd->prm_irqst_mod, - vdd->prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status), - VP_TRANXDONE_TIMEOUT, timeout); - if (timeout >= VP_TRANXDONE_TIMEOUT) - pr_err("%s: vdd_%s TRANXDONE timeout exceeded." - "TRANXDONE never got set after the voltage update\n", - __func__, voltdm->name); - - omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); - - /* - * Disable TransactionDone interrupt , clear all status, clear - * control registers - */ - timeout = 0; - while (timeout++ < VP_TRANXDONE_TIMEOUT) { - vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status, - vdd->prm_irqst_mod, vdd->prm_irqst_reg); - if (!(vdd->read_reg(vdd->prm_irqst_mod, vdd->prm_irqst_reg) & - vdd->vp_data->prm_irqst_data->tranxdone_status)) - break; - udelay(1); - } - - if (timeout >= VP_TRANXDONE_TIMEOUT) - pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying" - "to clear the TRANXDONE status\n", - __func__, voltdm->name); - - vpconfig = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - /* Clear initVDD copy trigger bit */ - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_initvdd; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - /* Clear force bit */ - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_forceupdate; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - return 0; -} - static int __init omap_vdd_data_configure(struct voltagedomain *voltdm) { struct omap_vdd_info *vdd = voltdm->vdd; @@ -439,129 +220,6 @@ unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm) } /** - * omap_vp_get_curr_volt() - API to get the current vp voltage. - * @voltdm: pointer to the VDD. - * - * This API returns the current voltage for the specified voltage processor - */ -unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - u8 curr_vsel; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return 0; - } - - vdd = voltdm->vdd; - if (!vdd->read_reg) { - pr_err("%s: No read API for reading vdd_%s regs\n", - __func__, voltdm->name); - return 0; - } - - curr_vsel = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->voltage); - - if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) { - pr_warning("%s: PMIC function to convert vsel to voltage" - "in uV not registerd\n", __func__); - return 0; - } - - return vdd->pmic_info->vsel_to_uv(curr_vsel); -} - -/** - * omap_vp_enable() - API to enable a particular VP - * @voltdm: pointer to the VDD whose VP is to be enabled. - * - * This API enables a particular voltage processor. Needed by the smartreflex - * class drivers. - */ -void omap_vp_enable(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - u32 vpconfig; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return; - } - - vdd = voltdm->vdd; - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, voltdm->name); - return; - } - - /* If VP is already enabled, do nothing. Return */ - if (vdd->vp_enabled) - return; - - vp_latch_vsel(voltdm); - - /* Enable VP */ - vpconfig = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - vpconfig |= vdd->vp_data->vp_common->vpconfig_vpenable; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - vdd->vp_enabled = true; -} - -/** - * omap_vp_disable() - API to disable a particular VP - * @voltdm: pointer to the VDD whose VP is to be disabled. - * - * This API disables a particular voltage processor. Needed by the smartreflex - * class drivers. - */ -void omap_vp_disable(struct voltagedomain *voltdm) -{ - struct omap_vdd_info *vdd; - u32 vpconfig; - int timeout; - - if (!voltdm || IS_ERR(voltdm)) { - pr_warning("%s: VDD specified does not exist!\n", __func__); - return; - } - - vdd = voltdm->vdd; - if (!vdd->read_reg || !vdd->write_reg) { - pr_err("%s: No read/write API for accessing vdd_%s regs\n", - __func__, voltdm->name); - return; - } - - /* If VP is already disabled, do nothing. Return */ - if (!vdd->vp_enabled) { - pr_warning("%s: Trying to disable VP for vdd_%s when" - "it is already disabled\n", __func__, voltdm->name); - return; - } - - /* Disable VP */ - vpconfig = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - vpconfig &= ~vdd->vp_data->vp_common->vpconfig_vpenable; - vdd->write_reg(vpconfig, vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vpconfig); - - /* - * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us - */ - omap_test_timeout((vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->vstatus)), - VP_IDLE_TIMEOUT, timeout); - - if (timeout >= VP_IDLE_TIMEOUT) - pr_warning("%s: vdd_%s idle timedout\n", - __func__, voltdm->name); - - vdd->vp_enabled = false; - - return; -} - -/** * omap_voltage_scale_vdd() - API to scale voltage of a particular * voltage domain. * @voltdm: pointer to the VDD which is to be scaled. @@ -766,7 +424,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm, switch (voltscale_method) { case VOLTSCALE_VPFORCEUPDATE: - vdd->volt_scale = vp_forceupdate_scale_voltage; + vdd->volt_scale = omap_vp_forceupdate_scale; return; case VOLTSCALE_VCBYPASS: vdd->volt_scale = omap_vc_bypass_scale_voltage; @@ -805,8 +463,8 @@ int __init omap_voltage_late_init(void) if (voltdm->vdd) { if (omap_vdd_data_configure(voltdm)) continue; - vp_init(voltdm); vdd_debugfs_init(voltdm); + omap_vp_init(voltdm); } if (voltdm->vc) diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index bef870a..71694fe 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -154,9 +154,6 @@ struct omap_vdd_info { unsigned long target_volt); }; -unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm); -void omap_vp_enable(struct voltagedomain *voltdm); -void omap_vp_disable(struct voltagedomain *voltdm); int omap_voltage_scale_vdd(struct voltagedomain *voltdm, unsigned long target_volt); void omap_voltage_reset(struct voltagedomain *voltdm); diff --git a/arch/arm/mach-omap2/vp.c b/arch/arm/mach-omap2/vp.c new file mode 100644 index 0000000..f3503de --- /dev/null +++ b/arch/arm/mach-omap2/vp.c @@ -0,0 +1,374 @@ +#include +#include +#include + +#include + +#include "voltage.h" +#include "vp.h" +#include "prm-regbits-34xx.h" +#include "prm-regbits-44xx.h" +#include "prm44xx.h" + +static void __init vp_debugfs_init(struct voltagedomain *voltdm); + +static void vp_latch_vsel(struct voltagedomain *voltdm) +{ + struct omap_vp_instance_data *vp = voltdm->vdd->vp_data; + u32 vpconfig; + unsigned long uvdc; + char vsel; + struct omap_vdd_info *vdd = voltdm->vdd; + + uvdc = omap_voltage_get_nom_volt(voltdm); + if (!uvdc) { + pr_warning("%s: unable to find current voltage for vdd_%s\n", + __func__, voltdm->name); + return; + } + + if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) { + pr_warning("%s: PMIC function to convert voltage in uV to" + " vsel not registered\n", __func__); + return; + } + + vsel = vdd->pmic_info->uv_to_vsel(uvdc); + + vpconfig = vdd->read_reg(vp->vp_common->prm_mod, vp->vpconfig); + vpconfig &= ~(vp->vp_common->vpconfig_initvoltage_mask | + vp->vp_common->vpconfig_initvdd); + vpconfig |= vsel << vp->vp_common->vpconfig_initvoltage_shift; + + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + /* Trigger initVDD value copy to voltage processor */ + vdd->write_reg((vpconfig | vp->vp_common->vpconfig_initvdd), + vp->vp_common->prm_mod, vp->vpconfig); + + /* Clear initVDD copy trigger bit */ + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); +} + +/* Generic voltage init functions */ +void __init omap_vp_init(struct voltagedomain *voltdm) +{ + struct omap_vp_instance_data *vp = voltdm->vdd->vp_data; + struct omap_vdd_info *vdd = voltdm->vdd; + u32 vp_val; + + if (!vdd->read_reg || !vdd->write_reg) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + vp_val = vdd->vp_rt_data.vpconfig_erroroffset | + (vdd->vp_rt_data.vpconfig_errorgain << + vp->vp_common->vpconfig_errorgain_shift) | + vp->vp_common->vpconfig_timeouten; + vdd->write_reg(vp_val, vp->vp_common->prm_mod, vp->vpconfig); + + vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin << + vp->vp_common->vstepmin_smpswaittimemin_shift) | + (vdd->vp_rt_data.vstepmin_stepmin << + vp->vp_common->vstepmin_stepmin_shift)); + vdd->write_reg(vp_val, vp->vp_common->prm_mod, vp->vstepmin); + + vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax << + vp->vp_common->vstepmax_smpswaittimemax_shift) | + (vdd->vp_rt_data.vstepmax_stepmax << + vp->vp_common->vstepmax_stepmax_shift)); + vdd->write_reg(vp_val, vp->vp_common->prm_mod, vp->vstepmax); + + vp_val = ((vdd->vp_rt_data.vlimitto_vddmax << + vp->vp_common->vlimitto_vddmax_shift) | + (vdd->vp_rt_data.vlimitto_vddmin << + vp->vp_common->vlimitto_vddmin_shift) | + (vdd->vp_rt_data.vlimitto_timeout << + vp->vp_common->vlimitto_timeout_shift)); + vdd->write_reg(vp_val, vp->vp_common->prm_mod, vp->vlimitto); + + vp_debugfs_init(voltdm); +} + +/* VP force update method of voltage scaling */ +int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, + unsigned long target_volt) +{ + struct omap_vp_instance_data *vp = voltdm->vdd->vp_data; + struct omap_vdd_info *vdd = voltdm->vdd; + u32 vpconfig; + u8 target_vsel, current_vsel; + int ret, timeout = 0; + + ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); + if (ret) + return ret; + + /* + * Clear all pending TransactionDone interrupt/status. Typical latency + * is <3us + */ + while (timeout++ < VP_TRANXDONE_TIMEOUT) { + vdd->write_reg(vp->prm_irqst_data->tranxdone_status, + vdd->prm_irqst_mod, vdd->prm_irqst_reg); + if (!(vdd->read_reg(vdd->prm_irqst_mod, vdd->prm_irqst_reg) & + vp->prm_irqst_data->tranxdone_status)) + break; + udelay(1); + } + if (timeout >= VP_TRANXDONE_TIMEOUT) { + pr_warning("%s: vdd_%s TRANXDONE timeout exceeded." + "Voltage change aborted", __func__, voltdm->name); + return -ETIMEDOUT; + } + + /* Configure for VP-Force Update */ + vpconfig = vdd->read_reg(vp->vp_common->prm_mod, vp->vpconfig); + vpconfig &= ~(vp->vp_common->vpconfig_initvdd | + vp->vp_common->vpconfig_forceupdate | + vp->vp_common->vpconfig_initvoltage_mask); + vpconfig |= ((target_vsel << + vp->vp_common->vpconfig_initvoltage_shift)); + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + /* Trigger initVDD value copy to voltage processor */ + vpconfig |= vp->vp_common->vpconfig_initvdd; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + /* Force update of voltage */ + vpconfig |= vp->vp_common->vpconfig_forceupdate; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + /* + * Wait for TransactionDone. Typical latency is <200us. + * Depends on SMPSWAITTIMEMIN/MAX and voltage change + */ + timeout = 0; + omap_test_timeout((vdd->read_reg(vdd->prm_irqst_mod, + vdd->prm_irqst_reg) & + vp->prm_irqst_data->tranxdone_status), + VP_TRANXDONE_TIMEOUT, timeout); + if (timeout >= VP_TRANXDONE_TIMEOUT) + pr_err("%s: vdd_%s TRANXDONE timeout exceeded." + "TRANXDONE never got set after the voltage update\n", + __func__, voltdm->name); + + omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); + + /* + * Disable TransactionDone interrupt , clear all status, clear + * control registers + */ + timeout = 0; + while (timeout++ < VP_TRANXDONE_TIMEOUT) { + vdd->write_reg(vp->prm_irqst_data->tranxdone_status, + vdd->prm_irqst_mod, vdd->prm_irqst_reg); + if (!(vdd->read_reg(vdd->prm_irqst_mod, vdd->prm_irqst_reg) & + vp->prm_irqst_data->tranxdone_status)) + break; + udelay(1); + } + + if (timeout >= VP_TRANXDONE_TIMEOUT) + pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying" + "to clear the TRANXDONE status\n", + __func__, voltdm->name); + + vpconfig = vdd->read_reg(vp->vp_common->prm_mod, vp->vpconfig); + /* Clear initVDD copy trigger bit */ + vpconfig &= ~vp->vp_common->vpconfig_initvdd; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + /* Clear force bit */ + vpconfig &= ~vp->vp_common->vpconfig_forceupdate; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + return 0; +} + +/** + * omap_vp_get_curr_volt() - API to get the current vp voltage. + * @voltdm: pointer to the VDD. + * + * This API returns the current voltage for the specified voltage processor + */ +unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm) +{ + struct omap_vp_instance_data *vp = voltdm->vdd->vp_data; + struct omap_vdd_info *vdd; + u8 curr_vsel; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return 0; + } + + vdd = voltdm->vdd; + if (!vdd->read_reg) { + pr_err("%s: No read API for reading vdd_%s regs\n", + __func__, voltdm->name); + return 0; + } + + curr_vsel = vdd->read_reg(vp->vp_common->prm_mod, vp->voltage); + + if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) { + pr_warning("%s: PMIC function to convert vsel to voltage" + "in uV not registerd\n", __func__); + return 0; + } + + return vdd->pmic_info->vsel_to_uv(curr_vsel); +} + +/** + * omap_vp_enable() - API to enable a particular VP + * @voltdm: pointer to the VDD whose VP is to be enabled. + * + * This API enables a particular voltage processor. Needed by the smartreflex + * class drivers. + */ +void omap_vp_enable(struct voltagedomain *voltdm) +{ + struct omap_vp_instance_data *vp; + struct omap_vdd_info *vdd; + u32 vpconfig; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return; + } + + vdd = voltdm->vdd; + vp = voltdm->vdd->vp_data; + if (!vdd->read_reg || !vdd->write_reg) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + /* If VP is already enabled, do nothing. Return */ + if (vdd->vp_enabled) + return; + + vp_latch_vsel(voltdm); + + /* Enable VP */ + vpconfig = vdd->read_reg(vp->vp_common->prm_mod, vp->vpconfig); + vpconfig |= vp->vp_common->vpconfig_vpenable; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + vdd->vp_enabled = true; +} + +/** + * omap_vp_disable() - API to disable a particular VP + * @voltdm: pointer to the VDD whose VP is to be disabled. + * + * This API disables a particular voltage processor. Needed by the smartreflex + * class drivers. + */ +void omap_vp_disable(struct voltagedomain *voltdm) +{ + struct omap_vp_instance_data *vp; + struct omap_vdd_info *vdd; + u32 vpconfig; + int timeout; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); + return; + } + + vdd = voltdm->vdd; + vp = voltdm->vdd->vp_data; + if (!vdd->read_reg || !vdd->write_reg) { + pr_err("%s: No read/write API for accessing vdd_%s regs\n", + __func__, voltdm->name); + return; + } + + /* If VP is already disabled, do nothing. Return */ + if (!vdd->vp_enabled) { + pr_warning("%s: Trying to disable VP for vdd_%s when" + "it is already disabled\n", __func__, voltdm->name); + return; + } + + /* Disable VP */ + vpconfig = vdd->read_reg(vp->vp_common->prm_mod, vp->vpconfig); + vpconfig &= ~vp->vp_common->vpconfig_vpenable; + vdd->write_reg(vpconfig, vp->vp_common->prm_mod, vp->vpconfig); + + /* + * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us + */ + omap_test_timeout((vdd->read_reg(vp->vp_common->prm_mod, vp->vstatus)), + VP_IDLE_TIMEOUT, timeout); + + if (timeout >= VP_IDLE_TIMEOUT) + pr_warning("%s: vdd_%s idle timedout\n", + __func__, voltdm->name); + + vdd->vp_enabled = false; + + return; +} + +/* Voltage debugfs support */ +static int vp_volt_debug_get(void *data, u64 *val) +{ + struct voltagedomain *voltdm = (struct voltagedomain *)data; + struct omap_vp_instance_data *vp = voltdm->vdd->vp_data; + struct omap_vdd_info *vdd = voltdm->vdd; + u8 vsel; + + if (!vdd) { + pr_warning("Wrong paramater passed\n"); + return -EINVAL; + } + + vsel = vdd->read_reg(vp->vp_common->prm_mod, vp->voltage); + + if (!vdd->pmic_info->vsel_to_uv) { + pr_warning("PMIC function to convert vsel to voltage" + "in uV not registerd\n"); + return -EINVAL; + } + + *val = vdd->pmic_info->vsel_to_uv(vsel); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n"); + +static void __init vp_debugfs_init(struct voltagedomain *voltdm) +{ + struct omap_vdd_info *vdd = voltdm->vdd; + struct dentry *debug_dir; + + debug_dir = debugfs_create_dir("vp", vdd->debug_dir); + if (IS_ERR(debug_dir)) + pr_err("%s: Unable to create VP debugfs dir dir\n", __func__); + + (void) debugfs_create_x16("errorgain", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vpconfig_errorgain)); + (void) debugfs_create_x16("smpswaittimemin", S_IRUGO, + debug_dir, + &(vdd->vp_rt_data.vstepmin_smpswaittimemin)); + (void) debugfs_create_x8("stepmin", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vstepmin_stepmin)); + (void) debugfs_create_x16("smpswaittimemax", S_IRUGO, + debug_dir, + &(vdd->vp_rt_data.vstepmax_smpswaittimemax)); + (void) debugfs_create_x8("stepmax", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vstepmax_stepmax)); + (void) debugfs_create_x8("vddmax", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vlimitto_vddmax)); + (void) debugfs_create_x8("vddmin", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vlimitto_vddmin)); + (void) debugfs_create_x16("timeout", S_IRUGO, debug_dir, + &(vdd->vp_rt_data.vlimitto_timeout)); + (void) debugfs_create_file("curr_volt", S_IRUGO, debug_dir, + (void *) voltdm, &vp_volt_debug_fops); +} diff --git a/arch/arm/mach-omap2/vp.h b/arch/arm/mach-omap2/vp.h index 5406b08..025cf16 100644 --- a/arch/arm/mach-omap2/vp.h +++ b/arch/arm/mach-omap2/vp.h @@ -19,6 +19,8 @@ #include +struct voltagedomain; + /* XXX document */ #define VP_IDLE_TIMEOUT 200 #define VP_TRANXDONE_TIMEOUT 300 @@ -139,4 +141,11 @@ extern struct omap_vp_instance_data omap4_vp_mpu_data; extern struct omap_vp_instance_data omap4_vp_iva_data; extern struct omap_vp_instance_data omap4_vp_core_data; +void omap_vp_init(struct voltagedomain *voltdm); +void omap_vp_enable(struct voltagedomain *voltdm); +void omap_vp_disable(struct voltagedomain *voltdm); +unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm); +int omap_vp_forceupdate_scale(struct voltagedomain *voltdm, + unsigned long target_volt); + #endif