RE: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




>>-----Original Message-----
>>From: Kevin Hilman [mailto:khilman@xxxxxxxxxxxxxxxxxxx]
>>Sent: Wednesday, August 25, 2010 5:32 AM
>>To: Gopinath, Thara
>>Cc: linux-omap@xxxxxxxxxxxxxxx; paul@xxxxxxxxx; Cousson, Benoit; Sripathy, Vishwanath; Sawant, Anand;
>>Derrick, David
>>Subject: Re: [PATCHv2 2/8] OMAP3: PM: Adding voltage driver support for OMAP3
>>
>>Thara Gopinath <thara@xxxxxx> writes:
>>
>>> This patch adds voltage driver support for OMAP3. The driver
>>> allows  configuring the voltage controller and voltage
>>> processors during init and exports APIs to enable/disable
>>> voltage processors, scale voltage and reset voltage.
>>> The driver also maintains the global voltage table on a per
>>> VDD basis which contains the various voltages supported by the
>>> VDD along with per voltage dependent data like smartreflex
>>> n-target value, errminlimit and voltage processor errorgain.
>>> The driver allows scaling of VDD voltages either through
>>> "vc bypass method" or through "vp forceupdate method" the
>>> choice being configurable through the board file.
>>>
>>> This patch contains code originally in linux omap pm branch
>>> smartreflex driver.  Major contributors to this driver are
>>> Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley,
>>> Nishant Menon, Kevin Hilman.
>>>
>>> Signed-off-by: Thara Gopinath <thara@xxxxxx>
>>
>>This is looking pretty good.  Mostly minor style issues left to correct.

Thanks for the review.
>>
>>> ---
>>>  arch/arm/mach-omap2/Makefile              |    3 +-
>>>  arch/arm/mach-omap2/voltage.c             | 1119 +++++++++++++++++++++++++++++
>>>  arch/arm/plat-omap/include/plat/voltage.h |  132 ++++
>>>  3 files changed, 1253 insertions(+), 1 deletions(-)
>>>  create mode 100644 arch/arm/mach-omap2/voltage.c
>>>  create mode 100644 arch/arm/plat-omap/include/plat/voltage.h
>>>
>>> diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
>>> index 63b2d88..1c095cf 100644
>>> --- a/arch/arm/mach-omap2/Makefile
>>> +++ b/arch/arm/mach-omap2/Makefile
>>> @@ -49,7 +49,8 @@ obj-$(CONFIG_ARCH_OMAP2)          += sdrc2xxx.o
>>>  ifeq ($(CONFIG_PM),y)
>>>  obj-$(CONFIG_ARCH_OMAP2)           += pm24xx.o
>>>  obj-$(CONFIG_ARCH_OMAP2)           += sleep24xx.o
>>> -obj-$(CONFIG_ARCH_OMAP3)           += pm34xx.o sleep34xx.o cpuidle34xx.o
>>> +obj-$(CONFIG_ARCH_OMAP3)           += pm34xx.o sleep34xx.o voltage.o \
>>> +                                      cpuidle34xx.o
>>>  obj-$(CONFIG_ARCH_OMAP4)           += pm44xx.o
>>>  obj-$(CONFIG_PM_DEBUG)                     += pm-debug.o
>>>
>>> diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
>>> new file mode 100644
>>> index 0000000..cb0fcac
>>> --- /dev/null
>>> +++ b/arch/arm/mach-omap2/voltage.c
>>> @@ -0,0 +1,1119 @@
>>> +/*
>>> + * OMAP3/OMAP4 Voltage Management Routines
>>> + *
>>> + * Author: Thara Gopinath  <thara@xxxxxx>
>>> + *
>>> + * Copyright (C) 2007 Texas Instruments, Inc.
>>> + * Rajendra Nayak <rnayak@xxxxxx>
>>> + * Lesly A M <x0080970@xxxxxx>
>>> + *
>>> + * Copyright (C) 2008 Nokia Corporation
>>> + * Kalle Jokiniemi
>>> + *
>>> + * Copyright (C) 2010 Texas Instruments, Inc.
>>> + * Thara Gopinath <thara@xxxxxx>
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#include <linux/pm.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/err.h>
>>> +
>>> +#include <plat/omap-pm.h>
>>> +#include <plat/omap34xx.h>
>>> +#include <plat/opp.h>
>>> +#include <plat/opp_twl_tps.h>
>>> +#include <plat/clock.h>
>>> +#include <plat/common.h>
>>> +#include <plat/voltage.h>
>>> +
>>> +#include "prm-regbits-34xx.h"
>>> +
>>> +#define VP_IDLE_TIMEOUT            200
>>> +#define VP_TRANXDONE_TIMEOUT       300
>>> +
>>> +/* PRM voltage module */
>>> +static u32 volt_mod;
>>> +
>>> +/* Voltage processor register offsets */
>>> +struct vp_reg_offs {
>>> +   u8 vpconfig;
>>> +   u8 vstepmin;
>>> +   u8 vstepmax;
>>> +   u8 vlimitto;
>>> +   u8 vstatus;
>>> +   u8 voltage;
>>> +};
>>> +
>>> +/* Voltage Processor bit field values, shifts and masks */
>>> +struct vp_reg_val {
>>> +   /* VPx_VPCONFIG */
>>> +   u32 vpconfig_erroroffset;
>>> +   u16 vpconfig_errorgain;
>>> +   u32 vpconfig_errorgain_mask;
>>> +   u8 vpconfig_errorgain_shift;
>>> +   u32 vpconfig_initvoltage_mask;
>>> +   u8 vpconfig_initvoltage_shift;
>>> +   u32 vpconfig_timeouten;
>>> +   u32 vpconfig_initvdd;
>>> +   u32 vpconfig_forceupdate;
>>> +   u32 vpconfig_vpenable;
>>> +   /* VPx_VSTEPMIN */
>>> +   u8 vstepmin_stepmin;
>>> +   u16 vstepmin_smpswaittimemin;
>>> +   u8 vstepmin_stepmin_shift;
>>> +   u8 vstepmin_smpswaittimemin_shift;
>>> +   /* VPx_VSTEPMAX */
>>> +   u8 vstepmax_stepmax;
>>> +   u16 vstepmax_smpswaittimemax;
>>> +   u8 vstepmax_stepmax_shift;
>>> +   u8 vstepmax_smpswaittimemax_shift;
>>> +   /* VPx_VLIMITTO */
>>> +   u16 vlimitto_vddmin;
>>> +   u16 vlimitto_vddmax;
>>> +   u16 vlimitto_timeout;
>>> +   u16 vlimitto_vddmin_shift;
>>> +   u16 vlimitto_vddmax_shift;
>>> +   u16 vlimitto_timeout_shift;
>>> +   /* PRM_IRQSTATUS*/
>>> +   u32 tranxdone_status;
>>> +};
>>> +
>>> +/**
>>> + * omap_vdd_info - Per Voltage Domain info
>>> + *
>>> + * @volt_data              : voltage table having the distinct voltages supported
>>> + *                   by the domain and other associated per voltage data.
>>> + * @vp_offs                : structure containing the offsets for various
>>> + *                   vp registers
>>> + * @vp_reg         : the register values, shifts, masks for various
>>> + *                   vp registers
>>> + * @volt_clk               : the clock associated with the vdd.
>>> + * @opp_dev                : the 'struct device' associated with this vdd.
>>> + * @volt_data_count        : Number of distinct voltages supported by this vdd.
>>> + * @nominal_volt   : Nominal voltaged for this vdd.
>>> + * cmdval_reg              : Voltage controller cmdval register.
>>> + * @vdd_sr_reg             : The smartreflex register associated with this VDD.
>>> + */
>>> +struct omap_vdd_info{
>>> +   struct omap_volt_data *volt_data;
>>> +   struct vp_reg_offs vp_offs;
>>> +   struct vp_reg_val vp_reg;
>>> +   struct clk *volt_clk;
>>> +   struct device *opp_dev;
>>> +   struct voltagedomain voltdm;
>>> +   int volt_data_count;
>>> +   unsigned long nominal_volt;
>>> +   u8 cmdval_reg;
>>> +   u8 vdd_sr_reg;
>>> +};
>>> +static struct omap_vdd_info *vdd_info;
>>> +/*
>>> + * Number of scalable voltage domains.
>>> + */
>>> +static int no_scalable_vdd;
>>> +
>>> +/* OMAP3 VDD sturctures */
>>> +static struct omap_vdd_info omap3_vdd_info[] = {
>>> +   {
>>> +           .vp_offs = {
>>> +                   .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
>>> +                   .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
>>> +                   .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
>>> +                   .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
>>> +                   .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
>>> +                   .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
>>> +           },
>>> +           .voltdm = {
>>> +                   .name = "mpu",
>>> +           },
>>> +   },
>>> +   {
>>> +           .vp_offs = {
>>> +                   .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
>>> +                   .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
>>> +                   .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
>>> +                   .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
>>> +                   .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
>>> +                   .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
>>> +           },
>>> +           .voltdm = {
>>> +                   .name = "core",
>>> +           },
>>> +   },
>>> +};
>>> +
>>> +#define OMAP3_NO_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)
>>
>>Use of 'NO' here has already been commented on in earlier versions.
>>Please use the  _NUM or _NR suffix which is common.
>>
>>Same issue with the name of the variable that this is assigned to.

Yep.. Will fix this one

>>
>>> +/* TODO: OMAP4 register offsets */
>>> +
>>> +/*
>>> + * Default voltage controller settings.
>>> + */
>>> +static struct omap_volt_vc_data vc_config = {
>>> +   .clksetup = 0xff,
>>> +   .voltsetup_time1 = 0xfff,
>>> +   .voltsetup_time2 = 0xfff,
>>> +   .voltoffset = 0xff,
>>> +   .voltsetup2 = 0xff,
>>> +   .vdd0_on = 0x30,        /* 1.2v */
>>> +   .vdd0_onlp = 0x20,      /* 1.0v */
>>> +   .vdd0_ret = 0x1e,       /* 0.975v */
>>> +   .vdd0_off = 0x00,       /* 0.6v */
>>> +   .vdd1_on = 0x2c,        /* 1.15v */
>>> +   .vdd1_onlp = 0x20,      /* 1.0v */
>>> +   .vdd1_ret = 0x1e,       /* .975v */
>>> +   .vdd1_off = 0x00,       /* 0.6v */
>>> +};
>>> +
>>> +/*
>>> + * Default PMIC Data
>>> + */
>>> +static struct omap_volt_pmic_info volt_pmic_info = {
>>> +   .slew_rate = 4000,
>>> +   .step_size = 12500,
>>> +};
>>> +
>>> +/*
>>> + * Structures containing OMAP3430/OMAP3630 voltage supported and various
>>> + * data associated with it per voltage domain basis. Smartreflex Ntarget
>>> + * values are left as 0 as they have to be populated by smartreflex
>>> + * driver after reading the efuse.
>>> + */
>>> +
>>> +/* VDD1 */
>>> +static struct omap_volt_data omap34xx_vdd1_volt_data[] = {
>>> +   {.volt_nominal = 975000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1075000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1200000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
>>> +   {.volt_nominal = 1270000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
>>> +   {.volt_nominal = 1350000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
>>> +};
>>> +
>>> +static struct omap_volt_data omap36xx_vdd1_volt_data[] = {
>>> +   {.volt_nominal = 930000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1100000, .sr_errminlimit = 0xF9, .vp_errgain = 0x16},
>>> +   {.volt_nominal = 1260000, .sr_errminlimit = 0xFA, .vp_errgain = 0x23},
>>> +   {.volt_nominal = 1350000, .sr_errminlimit = 0xFA, .vp_errgain = 0x27},
>>> +};
>>> +
>>> +/* VDD2 */
>>> +static struct omap_volt_data omap34xx_vdd2_volt_data[] = {
>>> +   {.volt_nominal = 975000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1050000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1150000, .sr_errminlimit = 0xF9, .vp_errgain = 0x18},
>>> +};
>>> +
>>> +static struct omap_volt_data omap36xx_vdd2_volt_data[] = {
>>> +   {.volt_nominal = 930000, .sr_errminlimit = 0xF4, .vp_errgain = 0x0C},
>>> +   {.volt_nominal = 1137500, .sr_errminlimit = 0xF9, .vp_errgain = 0x16},
>>> +};
>>> +
>>> +
>>> +/* By default VPFORCEUPDATE is the chosen method of voltage scaling */
>>> +static bool voltscale_vpforceupdate = true;
>>> +
>>> +static inline u32 voltage_read_reg(u8 offset)
>>> +{
>>> +   return prm_read_mod_reg(volt_mod, offset);
>>> +}
>>> +
>>> +static inline void voltage_write_reg(u8 offset, u32 value)
>>> +{
>>> +   prm_write_mod_reg(value, volt_mod, offset);
>>> +}
>>> +
>>> +static void vp_latch_vsel(struct omap_vdd_info *vdd)
>>> +{
>>> +   u32 vpconfig;
>>> +   unsigned long uvdc;
>>> +   char vsel;
>>> +
>>> +   uvdc = omap_voltage_get_nom_volt(&vdd->voltdm);
>>> +   if (!uvdc) {
>>> +           pr_warning("%s: unable to find current voltage for vdd_%s\n",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +   vsel = omap_twl_uv_to_vsel(uvdc);
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
>>> +                   vdd->vp_reg.vpconfig_initvdd);
>>> +   vpconfig |= vsel << vdd->vp_reg.vpconfig_initvoltage_shift;
>>> +
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /* Trigger initVDD value copy to voltage processor */
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig,
>>> +                   (vpconfig | vdd->vp_reg.vpconfig_initvdd));
>>> +
>>> +   /* Clear initVDD copy trigger bit */
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +}
>>> +
>>> +/* OMAP3 specific voltage init functions */
>>> +/*
>>> + * Intializes the voltage controller registers with the PMIC and board
>>> + * specific parameters and voltage setup times for OMAP3. If the board
>>> + * file does not populate the voltage controller parameters through
>>> + * omap3_pm_init_vc, default values specified in vc_config is used.
>>> + */
>>> +static void __init omap3_init_voltagecontroller(void)
>>> +{
>>> +   voltage_write_reg(OMAP3_PRM_VC_SMPS_SA_OFFSET,
>>> +                   (OMAP3_SRI2C_SLAVE_ADDR <<
>>> +                    OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT) |
>>> +                   (OMAP3_SRI2C_SLAVE_ADDR <<
>>> +                    OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT));
>>> +   voltage_write_reg(OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET,
>>> +                   (OMAP3_VDD2_SR_CONTROL_REG << OMAP3430_VOLRA1_SHIFT) |
>>> +                   (OMAP3_VDD1_SR_CONTROL_REG << OMAP3430_VOLRA0_SHIFT));
>>> +   voltage_write_reg(OMAP3_PRM_VC_CMD_VAL_0_OFFSET,
>>> +                   (vc_config.vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
>>> +                   (vc_config.vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
>>> +                   (vc_config.vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
>>> +                   (vc_config.vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT));
>>> +   voltage_write_reg(OMAP3_PRM_VC_CMD_VAL_1_OFFSET,
>>> +                   (vc_config.vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
>>> +                   (vc_config.vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
>>> +                   (vc_config.vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
>>> +                   (vc_config.vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT));
>>> +   voltage_write_reg(OMAP3_PRM_VC_CH_CONF_OFFSET,
>>> +                   OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK);
>>> +   voltage_write_reg(OMAP3_PRM_VC_I2C_CFG_OFFSET,
>>> +                   OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK);
>>
>>insert blank line when starting a new logical section, especially when
>>its separated by a comment.  There a lots of these to fixup.

Ok.. Will implement this

>>
>>> +   /* Write setup times */
>>> +   voltage_write_reg(OMAP3_PRM_CLKSETUP_OFFSET, vc_config.clksetup);
>>> +   voltage_write_reg(OMAP3_PRM_VOLTSETUP1_OFFSET,
>>> +                   (vc_config.voltsetup_time2 <<
>>> +                    OMAP3430_SETUP_TIME2_SHIFT) |
>>> +                   (vc_config.voltsetup_time1 <<
>>> +                    OMAP3430_SETUP_TIME1_SHIFT));
>>> +   voltage_write_reg(OMAP3_PRM_VOLTOFFSET_OFFSET, vc_config.voltoffset);
>>> +   voltage_write_reg(OMAP3_PRM_VOLTSETUP2_OFFSET, vc_config.voltsetup2);
>>> +}
>>> +
>>> +/* Sets up all the VDD related info for OMAP3 */
>>> +static void __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
>>> +{
>>> +   unsigned long curr_volt;
>>> +   struct omap_volt_data *volt_data;
>>> +   struct clk *sys_ck;
>>> +   u32 sys_clk_speed, timeout_val, waittime;
>>> +
>>> +   if (!strcmp(vdd->voltdm.name, "mpu")) {
>>> +           if (cpu_is_omap3630()) {
>>> +                   vdd->vp_reg.vlimitto_vddmin =
>>> +                                   OMAP3630_VP1_VLIMITTO_VDDMIN;
>>> +                   vdd->vp_reg.vlimitto_vddmax =
>>> +                                   OMAP3630_VP1_VLIMITTO_VDDMAX;
>>> +                   vdd->volt_data = omap36xx_vdd1_volt_data;
>>> +                   vdd->volt_data_count =
>>> +                                   ARRAY_SIZE(omap36xx_vdd1_volt_data);
>>> +           } else {
>>> +                   vdd->vp_reg.vlimitto_vddmin =
>>> +                                   OMAP3430_VP1_VLIMITTO_VDDMIN;
>>> +                   vdd->vp_reg.vlimitto_vddmax =
>>> +                                   OMAP3430_VP1_VLIMITTO_VDDMAX;
>>> +                   vdd->volt_data = omap34xx_vdd1_volt_data;
>>> +                   vdd->volt_data_count =
>>> +                                   ARRAY_SIZE(omap34xx_vdd1_volt_data);
>>> +           }
>>> +           vdd->volt_clk = clk_get(NULL, "dpll1_ck");
>>> +           vdd->opp_dev = omap2_get_mpuss_device();
>>> +           vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
>>> +           vdd->cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
>>> +           vdd->vdd_sr_reg = OMAP3_VDD1_SR_CONTROL_REG;
>>> +   } else if (!strcmp(vdd->voltdm.name, "core")) {
>>> +           if (cpu_is_omap3630()) {
>>> +                   vdd->vp_reg.vlimitto_vddmin =
>>> +                                   OMAP3630_VP2_VLIMITTO_VDDMIN;
>>> +                   vdd->vp_reg.vlimitto_vddmax =
>>> +                                   OMAP3630_VP2_VLIMITTO_VDDMAX;
>>> +                   vdd->volt_data = omap36xx_vdd2_volt_data;
>>> +                   vdd->volt_data_count =
>>> +                                   ARRAY_SIZE(omap36xx_vdd2_volt_data);
>>> +           } else {
>>> +                   vdd->vp_reg.vlimitto_vddmin =
>>> +                                   OMAP3430_VP2_VLIMITTO_VDDMIN;
>>> +                   vdd->vp_reg.vlimitto_vddmax =
>>> +                                   OMAP3430_VP2_VLIMITTO_VDDMAX;
>>> +                   vdd->volt_data = omap34xx_vdd2_volt_data;
>>> +                   vdd->volt_data_count =
>>> +                                   ARRAY_SIZE(omap34xx_vdd2_volt_data);
>>> +           }
>>> +           vdd->volt_clk = clk_get(NULL, "l3_ick");
>>> +           vdd->opp_dev = omap2_get_l3_device();
>>> +           vdd->vp_reg.tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK;
>>> +           vdd->cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
>>> +           vdd->vdd_sr_reg = OMAP3_VDD2_SR_CONTROL_REG;
>>> +   } else {
>>> +           pr_warning("%s: vdd_%s does not exisit in OMAP3\n",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +
>>> +   if (IS_ERR(vdd->volt_clk)) {
>>> +           pr_warning("%s: unable to get clk for vdd_%s\n",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +   if (!vdd->opp_dev) {
>>> +           pr_warning("%s: unable to get the opp device for vdd_%s\n",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +
>>> +   curr_volt = omap_voltage_get_nom_volt(&vdd->voltdm);
>>> +   if (!curr_volt) {
>>> +           pr_warning("%s: unable to find current voltage for vdd_%s\n",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +
>>> +   volt_data = omap_voltage_get_voltdata(&vdd->voltdm, curr_volt);
>>> +   if (IS_ERR(volt_data)) {
>>> +           pr_warning("%s: Unable to get volt table for vdd_%s at init",
>>> +                   __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +   /*
>>> +    * Sys clk rate is require to calculate vp timeout value and
>>> +    * smpswaittimemin and smpswaittimemax.
>>> +    */
>>> +   sys_ck = clk_get(NULL, "sys_ck");
>>> +   if (IS_ERR(sys_ck)) {
>>> +           pr_warning("%s: Could not get the sys clk to calculate"
>>> +                   "various vdd_%s params\n", __func__, vdd->voltdm.name);
>>> +           return;
>>> +   }
>>> +   sys_clk_speed = clk_get_rate(sys_ck);
>>> +   clk_put(sys_ck);
>>> +   /* Divide to avoid overflow */
>>> +   sys_clk_speed /= 1000;
>>> +
>>> +   /* Nominal/Reset voltage of the VDD */
>>> +   vdd->nominal_volt = 1200000;
>>> +
>>> +   /* VPCONFIG bit fields */
>>> +   vdd->vp_reg.vpconfig_erroroffset = (OMAP3_VP_CONFIG_ERROROFFSET <<
>>> +                            OMAP3430_ERROROFFSET_SHIFT);
>>> +   vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
>>> +   vdd->vp_reg.vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK;
>>> +   vdd->vp_reg.vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT;
>>> +   vdd->vp_reg.vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT;
>>> +   vdd->vp_reg.vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK;
>>> +   vdd->vp_reg.vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK;
>>> +   vdd->vp_reg.vpconfig_initvdd = OMAP3430_INITVDD_MASK;
>>> +   vdd->vp_reg.vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK;
>>> +   vdd->vp_reg.vpconfig_vpenable = OMAP3430_VPENABLE_MASK;
>>> +
>>> +   /* VSTEPMIN VSTEPMAX bit fields */
>>> +   waittime = ((volt_pmic_info.step_size / volt_pmic_info.slew_rate) *
>>> +                           sys_clk_speed) / 1000;
>>> +   vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
>>> +   vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
>>> +   vdd->vp_reg.vstepmin_stepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN;
>>> +   vdd->vp_reg.vstepmax_stepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX;
>>> +   vdd->vp_reg.vstepmin_smpswaittimemin_shift =
>>> +                           OMAP3430_SMPSWAITTIMEMIN_SHIFT;
>>> +   vdd->vp_reg.vstepmax_smpswaittimemax_shift =
>>> +                           OMAP3430_SMPSWAITTIMEMAX_SHIFT;
>>> +   vdd->vp_reg.vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT;
>>> +   vdd->vp_reg.vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT;
>>> +
>>> +   /* VLIMITTO bit fields */
>>> +   timeout_val = (sys_clk_speed * OMAP3_VP_VLIMITTO_TIMEOUT_US) / 1000;
>>> +   vdd->vp_reg.vlimitto_timeout = timeout_val;
>>> +   vdd->vp_reg.vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT;
>>> +   vdd->vp_reg.vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT;
>>> +   vdd->vp_reg.vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT;
>>> +}
>>> +
>>> +/* Generic voltage init functions */
>>> +static void __init init_voltageprocessor(struct omap_vdd_info *vdd)
>>> +{
>>> +   u32 vpconfig;
>>> +
>>> +   vpconfig = vdd->vp_reg.vpconfig_erroroffset |
>>> +                   (vdd->vp_reg.vpconfig_errorgain <<
>>> +                   vdd->vp_reg.vpconfig_errorgain_shift) |
>>> +                   vdd->vp_reg.vpconfig_timeouten;
>>> +
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   voltage_write_reg(vdd->vp_offs.vstepmin,
>>> +                   (vdd->vp_reg.vstepmin_smpswaittimemin <<
>>> +                   vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
>>> +                   (vdd->vp_reg.vstepmin_stepmin <<
>>> +                   vdd->vp_reg.vstepmin_stepmin_shift));
>>> +
>>> +   voltage_write_reg(vdd->vp_offs.vstepmax,
>>> +                   (vdd->vp_reg.vstepmax_smpswaittimemax <<
>>> +                   vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
>>> +                   (vdd->vp_reg.vstepmax_stepmax <<
>>> +                   vdd->vp_reg.vstepmax_stepmax_shift));
>>> +
>>> +   voltage_write_reg(vdd->vp_offs.vlimitto,
>>> +                   (vdd->vp_reg.vlimitto_vddmax <<
>>> +                   vdd->vp_reg.vlimitto_vddmax_shift) |
>>> +                   (vdd->vp_reg.vlimitto_vddmin <<
>>> +                   vdd->vp_reg.vlimitto_vddmin_shift) |
>>> +                   (vdd->vp_reg.vlimitto_timeout <<
>>> +                   vdd->vp_reg.vlimitto_timeout_shift));
>>> +
>>> +   /* Set the init voltage */
>>> +   vp_latch_vsel(vdd);
>>> +
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   /* Force update of voltage */
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig,
>>> +                   (vpconfig | vdd->vp_reg.vpconfig_forceupdate));
>>> +   /* Clear force bit */
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +}
>>> +
>>> +static void __init vdd_data_configure(struct omap_vdd_info *vdd)
>>> +{
>>> +   if (cpu_is_omap34xx())
>>> +           omap3_vdd_data_configure(vdd);
>>> +}
>>> +static void __init init_voltagecontroller(void)
>>> +{
>>> +   if (cpu_is_omap34xx())
>>> +           omap3_init_voltagecontroller();
>>> +}
>>> +
>>> +/*
>>> + * vc_bypass_scale_voltage - VC bypass method of voltage scaling
>>> + */
>>> +static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
>>> +           unsigned long target_volt)
>>> +{
>>> +   struct omap_volt_data *volt_data;
>>> +   u32 vc_bypass_value, vc_cmdval, vc_valid, vc_bypass_val_reg_offs;
>>> +   u32 vp_errgain_val, vc_cmd_on_mask;
>>> +   u32 loop_cnt = 0, retries_cnt = 0;
>>> +   u32 smps_steps = 0, smps_delay = 0;
>>> +   u8 vc_data_shift, vc_slaveaddr_shift, vc_regaddr_shift;
>>> +   u8 vc_cmd_on_shift;
>>> +   u8 target_vsel, current_vsel, sr_i2c_slave_addr;
>>> +
>>> +   if (cpu_is_omap34xx()) {
>>> +           vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
>>> +           vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
>>> +           vc_data_shift = OMAP3430_DATA_SHIFT;
>>> +           vc_slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
>>> +           vc_regaddr_shift = OMAP3430_REGADDR_SHIFT;
>>> +           vc_valid = OMAP3430_VALID_MASK;
>>> +           vc_bypass_val_reg_offs = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
>>> +           sr_i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR;
>>> +   }
>>
>>else ?

else this should return. I will update it

>>
>>> +   /* Get volt_data corresponding to target_volt */
>>> +   volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
>>> +   if (IS_ERR(volt_data)) {
>>> +           /*
>>> +            * If a match is not found but the target voltage is
>>> +            * is the nominal vdd voltage allow scaling
>>> +            */
>>> +           if (target_volt != vdd->nominal_volt) {
>>> +                   pr_warning("%s: Unable to get volt table for vdd_%s"
>>> +                           "during voltage scaling. Some really Wrong!",
>>> +                           __func__, vdd->voltdm.name);
>>> +                   return -ENODATA;
>>> +           }
>>> +           volt_data = NULL;
>>> +   }
>>> +
>>> +   target_vsel = omap_twl_uv_to_vsel(target_volt);
>>> +   current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
>>> +   smps_steps = abs(target_vsel - current_vsel);
>>> +
>>> +   /* Setting the ON voltage to the new target voltage */
>>> +   vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
>>> +   vc_cmdval &= ~vc_cmd_on_mask;
>>> +   vc_cmdval |= (target_vsel << vc_cmd_on_shift);
>>> +   voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
>>> +
>>> +   /* Setting vp errorgain based on the voltage */
>>> +   if (volt_data) {
>>> +           vp_errgain_val = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +           vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
>>> +           vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
>>> +           vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
>>> +                           vdd->vp_reg.vpconfig_errorgain_shift;
>>> +           voltage_write_reg(vdd->vp_offs.vpconfig, vp_errgain_val);
>>> +   }
>>> +
>>> +   vc_bypass_value = (target_vsel << vc_data_shift) |
>>> +                   (vdd->vdd_sr_reg << vc_regaddr_shift) |
>>> +                   (sr_i2c_slave_addr << vc_slaveaddr_shift);
>>> +
>>> +   voltage_write_reg(vc_bypass_val_reg_offs, vc_bypass_value);
>>> +
>>> +   voltage_write_reg(vc_bypass_val_reg_offs, vc_bypass_value | vc_valid);
>>> +   vc_bypass_value = voltage_read_reg(vc_bypass_val_reg_offs);
>>> +
>>> +   while ((vc_bypass_value & vc_valid) != 0x0) {
>>
>>the '!= 0x0' is redundant
Ok will take this in

>>
>>> +           loop_cnt++;
>>> +           if (retries_cnt > 10) {
>>> +                   pr_warning("%s: Loop count exceeded in check SR I2C"
>>> +                           "write during voltgae scaling\n", __func__);
>>
>>string is confusing

Will fix this.

>>
>>> +                   return -ETIMEDOUT;
>>> +           }
>>> +           if (loop_cnt > 50) {
>>> +                   retries_cnt++;
>>> +                   loop_cnt = 0;
>>> +                   udelay(10);
>>> +           }
>>> +           vc_bypass_value = voltage_read_reg(vc_bypass_val_reg_offs);
>>> +   }
>>
>>Where do the loop and retry count numbers come from?    This section
>>could use some comments describing the retry logic.

Hmmm... I can try putting in some comments. I had actually taken in
This piece of code from the older version of smartreflex.c. I haven't
changed anything in this function. Hence all the logic and errors in the
old code exist. Btw vc_bypass is not the official voltage scaling method
supported.

>>
>>> +   /* SMPS slew rate / step size. 2us added as buffer. */
>>> +   smps_delay = ((smps_steps * volt_pmic_info.step_size) /
>>> +                   volt_pmic_info.slew_rate) + 2;
>>> +   udelay(smps_delay);
>>> +   return 0;
>>> +}
>>> +
>>> +/* VP force update method of voltage scaling */
>>> +static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
>>> +           unsigned long target_volt)
>>> +{
>>> +   struct omap_volt_data *volt_data;
>>> +   u32 vc_cmd_on_mask, vc_cmdval, vpconfig;
>>> +   u32 smps_steps = 0, smps_delay = 0;
>>> +   int timeout = 0;
>>> +   u8 target_vsel, current_vsel;
>>> +   u8 vc_cmd_on_shift;
>>> +   u8 prm_irqst_reg_offs, ocp_mod;
>>> +
>>> +   if (cpu_is_omap34xx()) {
>>> +           vc_cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
>>> +           vc_cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
>>> +           prm_irqst_reg_offs = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
>>> +           ocp_mod = OCP_MOD;
>>> +   }
>>
>>else?

else this should return. I will update it

>>
>>> +   /* Get volt_data corresponding to the target_volt */
>>> +   volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
>>> +   if (IS_ERR(volt_data)) {
>>> +           /*
>>> +            * If a match is not found but the target voltage is
>>> +            * is the nominal vdd voltage allow scaling
>>> +            */
>>> +           if (target_volt != vdd->nominal_volt) {
>>> +                   pr_warning("%s: Unable to get voltage table for vdd_%s"
>>> +                           "during voltage scaling. Some really Wrong!",
>>> +                           __func__, vdd->voltdm.name);
>>> +                   return -ENODATA;
>>> +           }
>>> +           volt_data = NULL;
>>> +   }
>>> +
>>> +   target_vsel = omap_twl_uv_to_vsel(target_volt);
>>> +   current_vsel = voltage_read_reg(vdd->vp_offs.voltage);
>>> +   smps_steps = abs(target_vsel - current_vsel);
>>> +
>>> +   /* Setting the ON voltage to the new target voltage */
>>> +   vc_cmdval = voltage_read_reg(vdd->cmdval_reg);
>>> +   vc_cmdval &= ~vc_cmd_on_mask;
>>> +   vc_cmdval |= (target_vsel << vc_cmd_on_shift);
>>> +   voltage_write_reg(vdd->cmdval_reg, vc_cmdval);
>>> +
>>> +   /* Getting  vp errorgain based on the voltage */
>>> +   if (volt_data)
>>> +           vdd->vp_reg.vpconfig_errorgain =
>>> +                                   volt_data->vp_errgain;
>>> +   /*
>>> +    * Clear all pending TransactionDone interrupt/status. Typical latency
>>> +    * is <3us
>>> +    */
>>> +   while (timeout++ < VP_TRANXDONE_TIMEOUT) {
>>> +           prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
>>> +                           ocp_mod, prm_irqst_reg_offs);
>>> +           if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                           vdd->vp_reg.tranxdone_status))
>>> +                           break;
>>> +           udelay(1);
>>> +   }
>>
>>I'm a little worried about this racing with the PRCM interrupt handler
>>in pm34xx.c.  I need to be convinced that this would not interfere with
>>that handler.  Even better would be to handle this in an interrupt
>>handler and get rid of the polling.   Is there a reason this is done
>>with polling instead of handled in interrupt?

Yes this will not race as the TRANXDONE is not enabled in the PRM_IRQENABLE
register. Intention behind keeping this in polling mode is to avoid the delays/complications
in getting an interrupt, calling a handler and updating the prcm interrupt handler
to call a callback etc. This is rather short and sweet checking of the status.

>>
>>> +   if (timeout >= VP_TRANXDONE_TIMEOUT) {
>>> +           pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
>>> +                   "Voltage change aborted", __func__, vdd->voltdm.name);
>>> +           return -ETIMEDOUT;
>>> +   }
>>> +   /* Configure for VP-Force Update */
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
>>> +                   vdd->vp_reg.vpconfig_forceupdate |
>>> +                   vdd->vp_reg.vpconfig_initvoltage_mask |
>>> +                   vdd->vp_reg.vpconfig_errorgain_mask);
>>> +   vpconfig |= ((target_vsel <<
>>> +                   vdd->vp_reg.vpconfig_initvoltage_shift) |
>>> +                   (vdd->vp_reg.vpconfig_errorgain <<
>>> +                    vdd->vp_reg.vpconfig_errorgain_shift));
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /* Trigger initVDD value copy to voltage processor */
>>> +   vpconfig |= vdd->vp_reg.vpconfig_initvdd;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /* Force update of voltage */
>>> +   vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   timeout = 0;
>>> +   /*
>>> +    * Wait for TransactionDone. Typical latency is <200us.
>>> +    * Depends on SMPSWAITTIMEMIN/MAX and voltage change
>>> +    */
>>> +   omap_test_timeout((prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                   vdd->vp_reg.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__, vdd->voltdm.name);
>>> +   /*
>>> +    * Wait for voltage to settle with SW wait-loop.
>>> +    * SMPS slew rate / step size. 2us added as buffer.
>>> +    */
>>> +   smps_delay = ((smps_steps * volt_pmic_info.step_size) /
>>> +                   volt_pmic_info.slew_rate) + 2;
>>> +   udelay(smps_delay);
>>> +
>>> +   /*
>>> +    * Disable TransactionDone interrupt , clear all status, clear
>>> +    * control registers
>>> +    */
>>> +   timeout = 0;
>>> +   while (timeout++ < VP_TRANXDONE_TIMEOUT) {
>>> +           prm_write_mod_reg(vdd->vp_reg.tranxdone_status,
>>> +                           ocp_mod, prm_irqst_reg_offs);
>>> +           if (!(prm_read_mod_reg(ocp_mod, prm_irqst_reg_offs) &
>>> +                           vdd->vp_reg.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__, vdd->voltdm.name);
>>> +
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   /* Clear initVDD copy trigger bit */
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +   /* Clear force bit */
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   return 0;
>>> +}
>>> +
>>> +/* Public functions */
>>> +/**
>>> + * omap_voltage_get_nom_volt : Gets the current non-auto-compensated voltage
>>> + * @voltdm : pointer to the VDD for which current voltage info is needed
>>> + *
>>> + * API to get the current non-auto-compensated voltage for a VDD.
>>> + * Returns 0 in case of error else returns the current voltage for the VDD.
>>> + */
>>> +unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
>>> +{
>>> +   struct omap_opp *opp;
>>> +   struct omap_vdd_info *vdd;
>>> +   unsigned long freq;
>>> +
>>> +   if (!voltdm || IS_ERR(voltdm)) {
>>> +           pr_warning("%s: VDD specified does not exist!\n", __func__);
>>> +           return 0;
>>> +   }
>>> +
>>> +   vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   freq = vdd->volt_clk->rate;
>>> +   opp = opp_find_freq_ceil(vdd->opp_dev, &freq);
>>> +   if (IS_ERR(opp)) {
>>> +           pr_warning("%s: Unable to find OPP for vdd_%s freq%ld\n",
>>> +                   __func__, voltdm->name, freq);
>>> +           return 0;
>>> +   }
>>> +
>>> +   /*
>>> +    * Use higher freq voltage even if an exact match is not available
>>> +    * we are probably masking a clock framework bug, so warn
>>> +    */
>>> +   if (unlikely(freq != vdd->volt_clk->rate))
>>> +           pr_warning("%s: Available freq %ld != dpll freq %ld.\n",
>>> +                   __func__, freq, vdd->volt_clk->rate);
>>> +
>>> +   return opp_get_voltage(opp);
>>> +}
>>> +
>>> +/**
>>> + * 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 = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   curr_vsel = voltage_read_reg(vdd->vp_offs.voltage);
>>> +   return omap_twl_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 = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   /* If VP is already enabled, do nothing. Return */
>>> +   if (voltage_read_reg(vdd->vp_offs.vpconfig) &
>>> +                           vdd->vp_reg.vpconfig_vpenable)
>>> +           return;
>>> +   /*
>>> +    * This latching is required only if VC bypass method is used for
>>> +    * voltage scaling during dvfs.
>>> +    */
>>> +   if (!voltscale_vpforceupdate)
>>> +           vp_latch_vsel(vdd);
>>> +
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   /* Enable VP */
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig,
>>> +                           vpconfig | vdd->vp_reg.vpconfig_vpenable);
>>> +}
>>> +
>>> +/**
>>> + * 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 = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   /* If VP is already disabled, do nothing. Return */
>>> +   if (!(voltage_read_reg(vdd->vp_offs.vpconfig) &
>>> +                           vdd->vp_reg.vpconfig_vpenable)) {
>>> +           pr_warning("%s: Trying to disable VP for vdd_%s when"
>>> +                   "it is already disabled\n", __func__, voltdm->name);
>>> +           return;
>>> +   }
>>> +
>>> +   /* Disable VP */
>>> +   vpconfig = voltage_read_reg(vdd->vp_offs.vpconfig);
>>> +   vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
>>> +   voltage_write_reg(vdd->vp_offs.vpconfig, vpconfig);
>>> +
>>> +   /*
>>> +    * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
>>> +    */
>>> +   omap_test_timeout((voltage_read_reg(vdd->vp_offs.vstatus)),
>>> +                           VP_IDLE_TIMEOUT, timeout);
>>> +
>>> +   if (timeout >= VP_IDLE_TIMEOUT)
>>> +           pr_warning("%s: vdd_%s idle timedout\n",
>>> +                   __func__, voltdm->name);
>>> +   return;
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_scale_vdd : API to scale voltage of a particular voltage domain.
>>> + * @voltdm: pointer to the VDD which is to be scaled.
>>> + * @target_volt : The target voltage of the voltage domain
>>> + *
>>> + * This API should be called by the kernel to do the voltage scaling
>>> + * for a particular voltage domain during dvfs or any other situation.
>>> + */
>>> +int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
>>> +           unsigned long target_volt)
>>> +{
>>> +   struct omap_vdd_info *vdd;
>>> +
>>> +   if (!voltdm || IS_ERR(voltdm)) {
>>> +           pr_warning("%s: VDD specified does not exist!\n", __func__);
>>> +           return -EINVAL;
>>> +   }
>>> +
>>> +   vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   if (voltscale_vpforceupdate)
>>> +           return vp_forceupdate_scale_voltage(vdd, target_volt);
>>> +   else
>>> +           return vc_bypass_scale_voltage(vdd, target_volt);
>>> +}
>>> +
>>> +
>>> +
>>> +/**
>>> + * omap_voltage_reset : Resets the voltage of a particular voltage domain
>>> + * to that of the current OPP.
>>> + * @voltdm: pointer to the VDD whose voltage is to be reset.
>>> + *
>>> + * This API finds out the correct voltage the voltage domain is supposed
>>> + * to be at and resets the voltage to that level. Should be used expecially
>>> + * while disabling any voltage compensation modules.
>>> + */
>>> +void omap_voltage_reset(struct voltagedomain *voltdm)
>>> +{
>>> +   unsigned long target_uvdc;
>>> +
>>> +   if (!voltdm || IS_ERR(voltdm)) {
>>> +           pr_warning("%s: VDD specified does not exist!\n", __func__);
>>> +           return;
>>> +   }
>>> +
>>> +   target_uvdc = omap_voltage_get_nom_volt(voltdm);
>>> +   if (!target_uvdc) {
>>> +           pr_err("%s: unable to find current voltage for vdd_%s\n",
>>> +                   __func__, voltdm->name);
>>> +           return;
>>> +   }
>>> +   omap_voltage_scale_vdd(voltdm, target_uvdc);
>>> +}
>>> +
>>> +/**
>>> + * omap_change_voltscale_method : API to change the voltage scaling method.
>>> + * @voltscale_method : the method to be used for voltage scaling.
>>> + *
>>> + * This API can be used by the board files to change the method of voltage
>>> + * scaling between vpforceupdate and vcbypass. The parameter values are
>>> + * defined in voltage.h
>>> + */
>>> +void omap_change_voltscale_method(int voltscale_method)
>>> +{
>>> +   switch (voltscale_method) {
>>> +   case VOLTSCALE_VPFORCEUPDATE:
>>> +           voltscale_vpforceupdate = true;
>>> +           return;
>>> +   case VOLTSCALE_VCBYPASS:
>>> +           voltscale_vpforceupdate = false;
>>> +           return;
>>> +   default:
>>> +           pr_warning("%s: Trying to change the method of voltage scaling"
>>> +                   "to an unsupported one!\n", __func__);
>>> +   }
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_init_vc - polpulates vc_config with values specified in
>>> + *                   board file
>>> + * @setup_vc - the structure with various vc parameters
>>> + *
>>> + * Updates vc_config with the voltage setup times and other parameters as
>>> + * specified in setup_vc. vc_config is later used in init_voltagecontroller
>>> + * to initialize the voltage controller registers. Board files should call
>>> + * this function with the correct volatge settings corresponding
>>> + * the particular PMIC and chip.
>>> + */
>>> +void __init omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc)
>>> +{
>>> +   if (!setup_vc)
>>> +           return;
>>> +
>>> +   vc_config.clksetup = setup_vc->clksetup;
>>> +   vc_config.voltsetup_time1 = setup_vc->voltsetup_time1;
>>> +   vc_config.voltsetup_time2 = setup_vc->voltsetup_time2;
>>> +   vc_config.voltoffset = setup_vc->voltoffset;
>>> +   vc_config.voltsetup2 = setup_vc->voltsetup2;
>>> +   vc_config.vdd0_on = setup_vc->vdd0_on;
>>> +   vc_config.vdd0_onlp = setup_vc->vdd0_onlp;
>>> +   vc_config.vdd0_ret = setup_vc->vdd0_ret;
>>> +   vc_config.vdd0_off = setup_vc->vdd0_off;
>>> +   vc_config.vdd1_on = setup_vc->vdd1_on;
>>> +   vc_config.vdd1_onlp = setup_vc->vdd1_onlp;
>>> +   vc_config.vdd1_ret = setup_vc->vdd1_ret;
>>> +   vc_config.vdd1_off = setup_vc->vdd1_off;
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_get_volttable : API to get the voltage table associated with a
>>> + *                     particular voltage domain.
>>> + *
>>> + * @voltdm: pointer to the VDD for which the voltage table is required
>>> + * @volt_data : the voltage table for the particular vdd which is to be
>>> + *         populated by this API
>>> + * This API populates the voltage table associated with a VDD into the
>>> + * passed parameter pointer. Returns the count of distinct voltages
>>> + * supported by this vdd.
>>> + *
>>> + */
>>> +int omap_voltage_get_volttable(struct voltagedomain *voltdm,
>>> +           struct omap_volt_data **volt_data)
>>> +{
>>> +   struct omap_vdd_info *vdd;
>>> +
>>> +   if (!voltdm || IS_ERR(voltdm)) {
>>> +           pr_warning("%s: VDD specified does not exist!\n", __func__);
>>> +           return 0;
>>> +   }
>>> +
>>> +   vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   *volt_data = vdd->volt_data;
>>> +   return vdd->volt_data_count;
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_get_voltdata : API to get the voltage table entry for a
>>> + *                         particular voltage
>>> + * @voltdm: pointer to the VDD whose voltage table has to be searched
>>> + * @volt : the voltage to be searched in the voltage table
>>> + *
>>> + * This API searches through the voltage table for the required voltage
>>> + * domain and tries to find a matching entry for the passed voltage volt.
>>> + * If a matching entry is found volt_data is populated with that entry.
>>> + * This API searches only through the non-compensated voltages int the
>>> + * voltage table.
>>> + * Returns pointer to the voltage table entry corresponding to volt on
>>> + * sucess. Returns -ENODATA if no voltage table exisits for the passed voltage
>>> + * domain or if there is no matching entry.
>>> + */
>>> +struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
>>> +           unsigned long volt)
>>> +{
>>> +   struct omap_vdd_info *vdd;
>>> +   int i;
>>> +
>>> +   if (!voltdm || IS_ERR(voltdm)) {
>>> +           pr_warning("%s: VDD specified does not exist!\n", __func__);
>>> +           return ERR_PTR(-EINVAL);
>>> +   }
>>> +
>>> +   vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
>>> +
>>> +   if (!vdd->volt_data) {
>>> +           pr_warning("%s: voltage table does not exist for vdd_%s\n",
>>> +                   __func__, voltdm->name);
>>> +           return ERR_PTR(-ENODATA);
>>> +   }
>>> +
>>> +   for (i = 0; i < vdd->volt_data_count; i++) {
>>> +           if (vdd->volt_data[i].volt_nominal == volt)
>>> +                   return &vdd->volt_data[i];
>>> +   }
>>> +
>>> +   pr_notice("%s: Unable to match the current voltage with the voltage"
>>> +           "table for vdd_%s\n", __func__, voltdm->name);
>>> +
>>> +   return ERR_PTR(-ENODATA);
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_register_pmic : API to register PMIC specific data
>>> + * @pmic_info : the structure containing pmic info
>>> + *
>>> + * This API is to be called by the borad file to specify the pmic specific
>>> + * info as present in omap_volt_pmic_info structure. A default pmic info
>>> + * table is maintained in the driver volt_pmic_info. If the board file do
>>> + * not override the default table using this API, the default values wiil
>>> + * be used in the driver.
>>> + */
>>> +void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info)
>>> +{
>>> +   volt_pmic_info.slew_rate = pmic_info->slew_rate;
>>> +   volt_pmic_info.step_size = pmic_info->step_size;
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_domain_get : API to get the voltage domain pointer
>>> + * @name : Name of the voltage domain
>>> + *
>>> + * This API looks up in the global vdd_info struct for the
>>> + * existence of voltage domain <name>. If it exists, the API returns
>>> + * a pointer to the voltage domain structure corresponding to the
>>> + * VDD<name>. Else retuns error pointer.
>>> + */
>>> +struct voltagedomain *omap_voltage_domain_get(char *name)
>>> +{
>>> +   int i;
>>> +
>>> +   if (!vdd_info) {
>>> +           pr_err("%s: Voltage driver init not yet happened.Faulting!\n",
>>> +                   __func__);
>>> +           return ERR_PTR(-EINVAL);
>>> +   }
>>> +
>>> +   if (!name) {
>>> +           pr_err("%s: No name to get the votage domain!\n", __func__);
>>> +           return ERR_PTR(-EINVAL);
>>> +   }
>>> +
>>> +   for (i = 0; i < no_scalable_vdd; i++) {
>>> +           if (!(strcmp(name, vdd_info[i].voltdm.name)))
>>> +                   return &vdd_info[i].voltdm;
>>> +   }
>>> +
>>> +   return ERR_PTR(-EINVAL);
>>> +}
>>> +
>>> +/**
>>> + * omap_voltage_init : Volatage init API which does VP and VC init.
>>> + */
>>> +static int __init omap_voltage_init(void)
>>> +{
>>> +   int i;
>>> +
>>> +   if (!cpu_is_omap34xx()) {
>>> +           pr_warning("%s: voltage driver support not added\n", __func__);
>>> +           return 0;
>>> +   }
>>
>>This is redundant, and doesn't need a warning.

Ok

>>
>>> +   if (cpu_is_omap34xx()) {
>>> +           volt_mod = OMAP3430_GR_MOD;
>>> +           vdd_info = omap3_vdd_info;
>>> +           no_scalable_vdd = OMAP3_NO_SCALABLE_VDD;
>>> +   }
>>
>>rather, just 'else return 0' here, and it makes it cleaner for adding
>>OMAP4 support.

Ok
>>
>>> +   init_voltagecontroller();
>>> +   for (i = 0; i < no_scalable_vdd; i++) {
>>> +           vdd_data_configure(&vdd_info[i]);
>>> +           init_voltageprocessor(&vdd_info[i]);
>>> +   }
>>> +   return 0;
>>> +}
>>> +device_initcall(omap_voltage_init);
>>> diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
>>> new file mode 100644
>>> index 0000000..fc9778b
>>> --- /dev/null
>>> +++ b/arch/arm/plat-omap/include/plat/voltage.h
>>> @@ -0,0 +1,132 @@
>>> +/*
>>> + * OMAP Voltage Management Routines
>>> + *
>>> + * Author: Thara Gopinath  <thara@xxxxxx>
>>> + *
>>> + * Copyright (C) 2009 Texas Instruments, Inc.
>>> + * Thara Gopinath <thara@xxxxxx>
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
>>> +#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
>>> +
>>> +#define VOLTSCALE_VPFORCEUPDATE            1
>>> +#define VOLTSCALE_VCBYPASS         2
>>> +
>>> +/* Voltage SR Parameters for OMAP3*/
>>> +#define OMAP3_SRI2C_SLAVE_ADDR                     0x12
>>> +#define OMAP3_VDD1_SR_CONTROL_REG          0x00
>>> +#define OMAP3_VDD2_SR_CONTROL_REG          0x01
>>> +
>>> +/*
>>> + * Omap3 VP register specific values. Maybe these need to come from
>>> + * board file or PMIC data structure
>>> + */
>>> +#define OMAP3_VP_CONFIG_ERROROFFSET                0x00
>>> +#define    OMAP3_VP_VSTEPMIN_SMPSWAITTIMEMIN       0x3C
>>> +#define OMAP3_VP_VSTEPMIN_VSTEPMIN         0x1
>>> +#define OMAP3_VP_VSTEPMAX_SMPSWAITTIMEMAX  0x3C
>>> +#define OMAP3_VP_VSTEPMAX_VSTEPMAX         0x04
>>> +#define OMAP3_VP_VLIMITTO_TIMEOUT_US               0x200
>>> +
>>> +/*
>>> + * Omap3430 specific VP register values. Maybe these need to come from
>>> + * board file or PMIC data structure
>>> + */
>>> +#define OMAP3430_VP1_VLIMITTO_VDDMIN               0x14
>>> +#define OMAP3430_VP1_VLIMITTO_VDDMAX               0x42
>>> +#define OMAP3430_VP2_VLIMITTO_VDDMAX               0x2C
>>> +#define OMAP3430_VP2_VLIMITTO_VDDMIN               0x18
>>> +
>>> +/*
>>> + * Omap3630 specific VP register values. Maybe these need to come from
>>> + * board file or PMIC data structure
>>> + */
>>> +#define OMAP3630_VP1_VLIMITTO_VDDMIN               0x18
>>> +#define OMAP3630_VP1_VLIMITTO_VDDMAX               0x3C
>>> +#define OMAP3630_VP2_VLIMITTO_VDDMIN               0x18
>>> +#define OMAP3630_VP2_VLIMITTO_VDDMAX               0x30
>>> +
>>> +/* TODO OMAP4 VP register values if the same file is used for OMAP4*/
>>> +/**
>>> + * voltagedomain - omap voltage domain global structure
>>> + * @name       : Name of the voltage domain which can be used as a unique
>>> + *               identifier.
>>> + */
>>> +struct voltagedomain {
>>> +       char *name;
>>> +};
>>> +
>>> +/**
>>> + * omap_volt_data - Omap voltage specific data.
>>> + * @voltage_nominal        : The possible voltage value in uV
>>> + * @sr_nvalue              : Smartreflex N target value at voltage <voltage>
>>> + * @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_nvalue;
>>> +   u8      sr_errminlimit;
>>> +   u8      vp_errgain;
>>> +};
>>> +
>>> +/**
>>> + * omap_volt_pmic_info - PMIC specific data required by the voltage driver.
>>> + * @slew_rate      : PMIC slew rate (in uv/us)
>>> + * @step_size      : PMIC voltage step size (in uv)
>>> + */
>>> +struct omap_volt_pmic_info {
>>> +      int slew_rate;
>>> +      int step_size;
>>> +};
>>> +
>>> +/* Various voltage controller related info */
>>> +struct omap_volt_vc_data {
>>> +   u16 clksetup;
>>> +   u16 voltsetup_time1;
>>> +   u16 voltsetup_time2;
>>> +   u16 voltoffset;
>>> +   u16 voltsetup2;
>>> +/* PRM_VC_CMD_VAL_0 specific bits */
>>
>>indent
>>
>>> +   u16 vdd0_on;
>>> +   u16 vdd0_onlp;
>>> +   u16 vdd0_ret;
>>> +   u16 vdd0_off;
>>> +/* PRM_VC_CMD_VAL_1 specific bits */
>>
>>indent

Will fix the indent issues
>>
>>> +   u16 vdd1_on;
>>> +   u16 vdd1_onlp;
>>> +   u16 vdd1_ret;
>>> +   u16 vdd1_off;
>>> +};
>>> +
>>> +struct voltagedomain *omap_voltage_domain_get(char *name);
>>> +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);
>>> +int omap_voltage_get_volttable(struct voltagedomain *voltdm,
>>> +           struct omap_volt_data **volt_data);
>>> +struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
>>> +           unsigned long volt);
>>> +void omap_voltage_register_pmic(struct omap_volt_pmic_info *pmic_info);
>>> +unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
>>> +#ifdef CONFIG_PM
>>> +void omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc);
>>> +void omap_change_voltscale_method(int voltscale_method);
>>> +#else
>>> +static inline void omap_voltage_init_vc(struct omap_volt_vc_data *setup_vc) {}
>>> +static inline  void omap_change_voltscale_method(int voltscale_method) {}
>>> +#endif
>>> +
>>> +#endif
>>
>>Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux