Re: [PATCH 2/2 v3] OMAP3: PM: SR: SmartReflex Refactor Rev4.0

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

 



Hi Nishanth,

Found some dead code, see below:

On Sat, 2009-10-24 at 08:15 +0300, Nishanth Menon wrote:
> Refactor the smart reflex implementation.
> 
> Original implementation summary:
> Eduardo Valentin (1):
>       OMAP3: PM: SmartReflex: Fix scheduled while atomic problem
> 
> Kalle Jokiniemi (1):
>       OMAP3: PM: SmartReflex driver integration
> 
> Kevin Hilman (1):
>       temp: SR: IO_ADDRESS conversion
> 
> Phil Carmody (2):
>       OMAP3: PM: Don't do unnecessary searches in omap_sr_vdd*_autocomp_store
>       OMAP3: PM: Early exit on invalid parameters
> 
> Rajendra Nayak (10):
>       OMAP3: SR: Fix init voltage on OPP change
>       OMAP3: SR: Update VDD1/2 voltages at boot
>       OMAP3: SR: Use sysclk for SR CLKLENGTH calc
>       OMAP3: SR: Reset voltage level on SR disable
>       OMAP3: SR: Replace printk's with pr_* calls
>       OMAP3: SR: Remove redundant defines
>       OMAP3: SR: Replace (0x1 << n) with BIT(n)
>       OMAP3: SR: Fix SR driver to check for omap-pm return values
>       OMAP3: PM: Put optimal SMPS stabilization delay
>       OMAP3: SR: Wait for VP idle before a VP disable
> 
> Roger Quadros (4):
>       OMAP3: PM: Fix Smartreflex when used with PM_NOOP layer
>       OMAP3: PM: Make Smartreflex driver independent of SRF
>       OMAP3: PM: Do not Enable SmartReflex if OPP tables not defined
>       OMAP3: PM: Smartreflex: Fix VDD2 OPP determining logic
> 
> Teerth Reddy (1):
>       OMAP3: SR: Replace SR_PASS/FAIL,SR_TRUE/FALSE
> 
> This patch introduces the following changes in addition to refactoring
> the implementation:
> a) changes the DVFS transition sequences from:
>     freq, voltage(SR+vp) and viceversa
>     TO:
>     disable_vp,SR; freq, voltage(SR+vp) and viceversa; enable_vp,SR
>         [NOTE: sequence change for disable path - was sr_dis,vp_dis]
>     This change prevents spikes and unexpected voltage changes
>     as a result of SR being left enabled at wrong times
> b) Major rewrite of smartreflex.c to do the following:
> 
>  1) Support VCbypass style of voltage configuration as optional
>    introduce and support forceupdate  default as recommended by
>    OMAP3430 TRM.
>  2) Centralize operations to allow for simpler and predictable code
>    flows
>  3) Modification to SR configured values to be inline with
>    silicon characterization results
>  4) cleanup of header
>  5) Introduce a few omap_pmic weak functions which can be overridden
>   by platforms implementing PMICs which are different from TWL4030
>   derivatives
>  6) srid is standardised to u8 and it is not a bit field
> 
> c) Fix ERRCONFIG access to prevent unplanned cleanup of interrupt
>   status registers - this is done using a interrupt status mask
> d) Test nvalues removed instead use debugfs entries to set any values
>    you like - no more Kconfig option either..
> e) Setup h/w timeout based on cpu sysclk and not hardcoded values
> g) finegrained with raw register values available over
>    debugfs in <debugfs mount point>/<pm_debug mount point>/
>         smartreflex/{srid}/
>         nvalue_opp[1-5] - nvalues for all 5 opps
>         Following register tweakability:
>         VP register values:
>                 vplimito_value
>                 vpstepmax_value
>                 vpstepmin_value
>                 vpconfig_value
>         SR Register values:
>                 sr_errconfig_value
>                 sr_config_value
>         Advice: disable SR before hitting them, no checks at this point.
> 
>         The following ReadONLY entry is provided:
>         vsel - this provides the voltage processor decided voltage value
>         and translated back to voltage based on the type of chip.
>         typical equation is:
>         voltage(mV) = (vsel*12.5) + 600
> 
>         test value equivalent userspace bash script would be:
>         mount -t debugfs none /dbg
>         mount -t sysfs none /sys
>         #vdd1:
>         #0x00AAB48A - OPP3
>         echo -n "11187338" >/dbg/pm_debug/smartreflex/1/nvalue_opp3
>         #0x00ABA2E6 - OPP4
>         echo -n "11248358" >/dbg/pm_debug/smartreflex/1/nvalue_opp4
>         # 0x00AB90D3 - OPP5
>         echo -n "11243731" >/dbg/pm_debug/smartreflex/1/nvalue_opp5
> 
>         #setup senn and senp value (essentially +120)
>         x=`cat /dbg/pm_debug/smartreflex/1/sr_config_value`
>         y=$((x + 120))
>         echo -n $y>/dbg/pm_debug/smartreflex/1/sr_config_value
>         #and enable it..
>         echo -n "1" >/sys/power/sr_vdd1_autocomp
> 
>         #vdd2
>         #0x00AAC695 -OPP3
>         echo -n "11191957" > /dbg/pm_debug/smartreflex/2/nvalue_opp3
>         #setup senn and senp value (essentially +120)
>         x=`cat /dbg/pm_debug/smartreflex/2/sr_config_value`
>         y=$((x + 120))
>         echo -n $y>/dbg/pm_debug/smartreflex/2/sr_config_value
>         #and enable it..
>         echo -n "1" >/sys/power/sr_vdd2_autocomp
> 
> Tested on:
>         SDP3430 with test N values as above and with ES3.1 silicon
> 
> TODO:
> a) Handle scenarios for multiple OMAP variants with differing
>    SR capabilities (e.g. varying OPP levels - e.g. 3630, 4430 etc..)
>         [IMMEDIATE ISSUE - partly done]
> b) Handling OMAP variants with different tuning values
> c) Handling different SR capable PMIC with different tuning values
> d) A proper handling of locking mechanism b/w dvfs and userspace access of
>    sr[x]_vddautocomp
> e) A more robust error handling
> f) using SR on larger number of boards and any tuning parameters
>    which may be needed additionally (HS/FS I2C4 ops etc..)
> g) Wider testing and and bug fixes
> h) Analyse how to use SR decided voltages for OPP1 as retention voltage.
>    some systems may choose to disable OPP1, what do we do then?
> 
> Cc: Rajendra Nayak <rnayak@xxxxxx>
> Cc: Roger Quadros <ext-roger.quadros@xxxxxxxxx>
> Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@xxxxxxxxx>
> Cc: Teerth Reddy <teerth@xxxxxx>
> Cc: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
> Cc: Paul Walmsley <paul@xxxxxxxxx>
> Cc: Högander Jouni <jouni.hogander@xxxxxxxxx>
> Cc: Mike Chan <mikechan@xxxxxxxxxx>
> Signed-off-by: Imberton Guilhem <guilhem.imberton@xxxxxxxxxxxx>
> Signed-off-by: Nishanth Menon <nm@xxxxxx>
> ---
>  arch/arm/mach-omap2/pm-debug.c     |    3 +
>  arch/arm/mach-omap2/resource34xx.c |    8 +-
>  arch/arm/mach-omap2/smartreflex.c  | 1604 ++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-omap2/smartreflex.h  |  274 ++++++
>  arch/arm/plat-omap/Kconfig         |   15 +-
>  5 files changed, 1893 insertions(+), 11 deletions(-)
>  create mode 100644 arch/arm/mach-omap2/smartreflex.c
>  create mode 100644 arch/arm/mach-omap2/smartreflex.h
> 
> diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
> index 767ebbc..34ff068 100644
> --- a/arch/arm/mach-omap2/pm-debug.c
> +++ b/arch/arm/mach-omap2/pm-debug.c
> @@ -35,6 +35,7 @@
>  #include "cm.h"
>  #include "pm.h"
>  #include "prm-regbits-34xx.h"
> +#include "smartreflex.h"
> 
>  int omap2_pm_debug;
> 
> @@ -617,6 +618,8 @@ static int __init pm_dbg_init(void)
>                                            &voltage_off_while_idle,
>                                            &pm_dbg_option_fops);
> 
> +       (void)sr_debugfs_create_entries(d);
> +
>         pm_dbg_init_done = 1;
> 
>         return 0;
> diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c
> index 04be4d2..3789f88 100644
> --- a/arch/arm/mach-omap2/resource34xx.c
> +++ b/arch/arm/mach-omap2/resource34xx.c
> @@ -294,17 +294,23 @@ static int program_opp(int res, struct omap_opp *opp, int target_level,
>         else
>                 raise = 0;
> 
> +#ifdef CONFIG_OMAP_SMARTREFLEX
> +       sr_vp_disable_both(t_opp, c_opp);
> +#endif
>         for (i = 0; i < 2; i++) {
>                 if (i == raise)
>                         ret = program_opp_freq(res, target_level,
>                                         current_level);
>  #ifdef CONFIG_OMAP_SMARTREFLEX
>                 else
> -                       sr_voltagescale_vcbypass(t_opp, c_opp,
> +                       sr_voltage_set(t_opp, c_opp,
>                                 opp[target_level].vsel,
>                                 opp[current_level].vsel);
>  #endif
>         }
> +#ifdef CONFIG_OMAP_SMARTREFLEX
> +       sr_vp_enable_both(t_opp, c_opp);
> +#endif
> 
>         return ret;
>  }
> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> new file mode 100644
> index 0000000..d506896
> --- /dev/null
> +++ b/arch/arm/mach-omap2/smartreflex.c
> @@ -0,0 +1,1604 @@
> +/*
> + * linux/arch/arm/mach-omap3/smartreflex.c
> + *
> + * OMAP34XX SmartReflex Voltage Control
> + *
> + * Copyright (C) 2009 Texas Instruments, Inc.
> + * Nishanth Menon
> + *
> + * Copyright (C) 2008 Nokia Corporation
> + * Kalle Jokiniemi
> + *
> + * Copyright (C) 2007 Texas Instruments, Inc.
> + * Lesly A M <x0080970@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/kernel.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/sysfs.h>
> +#include <linux/kobject.h>
> +#include <linux/i2c/twl4030.h>
> +#include <linux/io.h>
> +#include <linux/debugfs.h>
> +
> +#include <plat/omap34xx.h>
> +#include <plat/control.h>
> +#include <plat/clock.h>
> +#include <plat/omap-pm.h>
> +#include <plat/resource.h>
> +#include <plat/powerdomain.h>
> +
> +#include "prm.h"
> +#include "smartreflex.h"
> +#include "prm-regbits-34xx.h"
> +
> +/* MCUDISACK is expected to happen within 1uSec. */
> +#define COUNT_TIMEOUT_MCUDISACK                200
> +
> +/* VPINIDLE is expected to happen within 100uSec. Typical is 2uSec */
> +#define COUNT_TIMEOUT_VPINIDLE         200
> +
> +/* Time taken for setting the device - worst case as FS I2C
> + * Depends on SMPSWAITIME MIN/MAX Typical is 200uSec
> + */
> +#define COUNT_TIMEOUT_TRANSDONE_SET    400
> +
> +/* Time to clear out multiple transdone events typical is 3uSec */
> +#define COUNT_TIMEOUT_TRANSDONE_CLR    50
> +
> +/* Time For VCBypass mode for TWL4030 derivative chip. */
> +#define COUNT_TIMEOUT_TWL4030_VCBYPASS 500
> +
> +/* How many retries to do for I2C errors seen on bus for Forceupdate? */
> +#define COUNT_RETRY_SMPSNOACK          4
> +
> +#define SR_REGADDR(offset)     (sr->srbase_addr + (offset))
> +
> +/* Which function to use for setting voltage */
> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
> +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH  sr_vc_bypass
> +#else
> +#define SR_CHOSEN_VOLTAGE_UPDATE_MECH  sr_vp_forceupdate
> +#endif
> +
> +#ifdef CONFIG_OMAP_PM_NONE
> +struct omap_opp *mpu_opps;
> +struct omap_opp *dsp_opps;
> +struct omap_opp *l3_opps;
> +#endif
> +
> +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj,
> +                                        struct kobj_attribute *attr,
> +                                        char *buf);
> +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj,
> +                                         struct kobj_attribute *attr,
> +                                         const char *buf, size_t n);
> +/* Structure for Voltage processor */
> +struct omap_sr_vp {
> +       /* Store the commonly used register offsets.
> +        * this saves a if condition decision
> +        */
> +       u16 prm_vpx_status_offset;
> +       u16 prm_vpx_config_offset;
> +       u16 prm_vpx_stepmin_offset;
> +       u16 prm_vpx_stepmax_offset;
> +       u16 prm_vpx_limito_offset;
> +       u32 prm_vpx_vlimito_timeout;
> +       u8 prm_vpx_vlimito_shift;
> +       u16 prm_vpx_voltage_offset;
> +       u16 prm_vc_cmd_val_offset;
> +       /* Store the defaults
> +        * allowing us to save OCP read
> +        * operation
> +        */
> +       u32 vpconfig_value;
> +       u32 vpstepmin_value;
> +       u32 vpstepmax_value;
> +       u32 vplimito_value;
> +       u32 vpenable_mask;
> +       u32 irqmask_trans_done;
> +       u32 irqmask_smps_noack;
> +};
> +
> +/* Structure for Smart Reflex */
> +struct omap_sr {
> +       u8 srid;
> +       u8 prcm_vdd;
> +       char *vdd_name;
> +       struct kobj_attribute autocom_attr;
> +       struct omap_opp **omap_opp;
> +       /* SR activity marker */
> +       u8 is_sr_reset;
> +       u8 is_autocomp_active;
> +       u32 req_opp_no;
> +       u32 sr_config_value;
> +       u32 sr_errconfig_value;
> +       u32 sr_n_mod_mask;
> +       u8 sr_n_mod_shift;
> +       u32 sr_p_mod_mask;
> +       u8 sr_p_mod_shift;
> +       struct clk *fclk;
> +       struct clk *iclk;
> +       void __iomem *srbase_addr;
> +       char *iclk_name;
> +       char *fclk_name;
> +       /* Voltage processor for the specific SR module */
> +       struct omap_sr_vp vp;
> +       /* This will contain the register offset on
> +        * boot, replaced with the actual value
> +        * as part of init routine
> +        */
> +       u8 num_opp;
> +       u8 opp_boundary;
> +       u32 opp_nvalue[];
> +};
> +
> +/* A superset of all SRs in the system ordered by SRID */
> +struct omap_sr_list {
> +       u8 num_sr;
> +       struct omap_sr *sr_list[];
> +};
> +
> +/* Definitions for 3430 Silicon */
> +/* Smart Reflex 1 structure */
> +static __initdata struct omap_sr omap34xx_sr1 = {
> +       /* *INDENT-OFF* */
> +       .srid                   = SR1,
> +       .prcm_vdd               = PRCM_VDD1,
> +       .vdd_name               = "vdd1_opp",
> +       .omap_opp               = &mpu_opps,
> +       .autocom_attr           = {
> +               .attr = {
> +                        .name = __stringify(sr_vdd1_autocomp),
> +                        .mode = 0644,
> +                        },
> +               .show = omap_sr_vdd_autocomp_show,
> +               .store = omap_sr_vdd_autocomp_store,
> +       },
> +       .is_sr_reset            = 1,
> +       .is_autocomp_active     = 0,
> +       .srbase_addr            = (void *)OMAP34XX_SR1_BASE,
> +       .fclk_name              = "sr1_fck",
> +       .iclk_name              = "sr_l4_ick",
> +       .sr_errconfig_value     = SR1_ERRWEIGHT | SR1_ERRMAXLIMIT |
> +               ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
> +               SR_CLKACTIVITY_IOFF_FON,
> +       .sr_n_mod_mask          = OMAP343X_SR1_SENNENABLE_MASK,
> +       .sr_n_mod_shift         = OMAP343X_SR1_SENNENABLE_SHIFT,
> +       .sr_p_mod_mask          = OMAP343X_SR1_SENPENABLE_MASK,
> +       .sr_p_mod_shift         = OMAP343X_SR1_SENPENABLE_SHIFT,
> +       .vp = {
> +               .prm_vpx_status_offset  = OMAP3_PRM_VP1_STATUS_OFFSET,
> +               .prm_vpx_config_offset  = OMAP3_PRM_VP1_CONFIG_OFFSET,
> +               .prm_vpx_stepmin_offset = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
> +               .prm_vpx_stepmax_offset = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
> +               .prm_vpx_limito_offset  = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
> +               .prm_vpx_vlimito_timeout = PRM_VP1_VLIMITTO_TIMEOUT_US,
> +               .prm_vpx_vlimito_shift = PRM_VP1_VLIMITTO_TIMEOUT_SHIFT,
> +               .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
> +               .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_0_OFFSET,
> +               .vpconfig_value         = PRM_VP1_CONFIG_ERROROFFSET |
> +                       PRM_VP1_CONFIG_TIMEOUTEN,
> +               .vpstepmin_value        = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
> +                       PRM_VP1_VSTEPMIN_VSTEPMIN,
> +               .vpstepmax_value        = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
> +                       PRM_VP1_VSTEPMAX_VSTEPMAX,
> +               .vplimito_value         = PRM_VP1_VLIMITTO_VDDMAX |
> +                       PRM_VP1_VLIMITTO_VDDMIN,
> +               .vpenable_mask          = PRM_VP1_CONFIG_VPENABLE,
> +               .irqmask_trans_done     = VP1_IRQMASK_TRANSDONE,
> +               .irqmask_smps_noack     = OMAP3430_VP1_NOSMPSACK_ST,
> +       },
> +       .num_opp                = 5,
> +       .opp_boundary           = 3,
> +       .opp_nvalue             = {
> +                   OMAP343X_CONTROL_FUSE_OPP1_VDD1,
> +                   OMAP343X_CONTROL_FUSE_OPP2_VDD1,
> +                   OMAP343X_CONTROL_FUSE_OPP3_VDD1,
> +                   OMAP343X_CONTROL_FUSE_OPP4_VDD1,
> +                   OMAP343X_CONTROL_FUSE_OPP5_VDD1,
> +       },
> +               /* *INDENT-ON* */
> +};
> +
> +/* Smart Reflex 2 structure */
> +static __initdata struct omap_sr omap34xx_sr2 = {
> +       /* *INDENT-OFF* */
> +       .srid                   = SR2,
> +       .prcm_vdd               = PRCM_VDD2,
> +       .vdd_name               = "vdd2_opp",
> +       .omap_opp               = &l3_opps,
> +       .autocom_attr           = {
> +               .attr = {
> +                        .name = __stringify(sr_vdd2_autocomp),
> +                        .mode = 0644,
> +                        },
> +               .show = omap_sr_vdd_autocomp_show,
> +               .store = omap_sr_vdd_autocomp_store,
> +       },
> +       .is_sr_reset            = 1,
> +       .is_autocomp_active     = 0,
> +       .srbase_addr            = (void *)OMAP34XX_SR2_BASE,
> +       .fclk_name              = "sr2_fck",
> +       .iclk_name              = "sr_l4_ick",
> +       .sr_errconfig_value     = SR2_ERRWEIGHT | SR2_ERRMAXLIMIT |
> +               ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
> +               SR_CLKACTIVITY_IOFF_FON,
> +       .sr_n_mod_mask          = OMAP343X_SR2_SENNENABLE_MASK,
> +       .sr_n_mod_shift         = OMAP343X_SR2_SENNENABLE_SHIFT,
> +       .sr_p_mod_mask          = OMAP343X_SR2_SENPENABLE_MASK,
> +       .sr_p_mod_shift         = OMAP343X_SR2_SENPENABLE_SHIFT,
> +       .vp = {
> +               .prm_vpx_status_offset  = OMAP3_PRM_VP2_STATUS_OFFSET,
> +               .prm_vpx_config_offset  = OMAP3_PRM_VP2_CONFIG_OFFSET,
> +               .prm_vpx_stepmin_offset = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
> +               .prm_vpx_stepmax_offset = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
> +               .prm_vpx_limito_offset  = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
> +               .prm_vpx_vlimito_timeout = PRM_VP2_VLIMITTO_TIMEOUT_US,
> +               .prm_vpx_vlimito_shift = PRM_VP2_VLIMITTO_TIMEOUT_SHIFT,
> +               .prm_vpx_voltage_offset = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
> +               .prm_vc_cmd_val_offset = OMAP3_PRM_VC_CMD_VAL_1_OFFSET,
> +               .vpconfig_value         = PRM_VP2_CONFIG_ERROROFFSET |
> +                       PRM_VP2_CONFIG_TIMEOUTEN,
> +               .vpstepmin_value        = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
> +                       PRM_VP2_VSTEPMIN_VSTEPMIN,
> +               .vpstepmax_value        = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
> +                       PRM_VP2_VSTEPMAX_VSTEPMAX,
> +               .vplimito_value         = PRM_VP2_VLIMITTO_VDDMAX |
> +                       PRM_VP2_VLIMITTO_VDDMIN,
> +               .vpenable_mask          = PRM_VP2_CONFIG_VPENABLE,
> +               .irqmask_trans_done     = VP2_IRQMASK_TRANSDONE,
> +               .irqmask_smps_noack     = OMAP3430_VP2_NOSMPSACK_ST,
> +       },
> +       .num_opp                = 3,
> +       .opp_boundary           = 3,
> +       .opp_nvalue             = {
> +                   OMAP343X_CONTROL_FUSE_OPP1_VDD2,
> +                   OMAP343X_CONTROL_FUSE_OPP2_VDD2,
> +                   OMAP343X_CONTROL_FUSE_OPP3_VDD2,
> +       },
> +               /* *INDENT-ON* */
> +};
> +
> +/* SR list for 3430 */
> +static __initdata struct omap_sr_list omap34xx_srlist = {
> +       .num_sr = 2,
> +       .sr_list = {&omap34xx_sr1, &omap34xx_sr2}
> +};
> +
> +/* The final SR list */
> +static struct omap_sr_list *omap_srlist;
> +
> +/*********************** OPP Accessor functions ****************************/
> +
> +/**
> + * @brief *get_sr - get SR pointer from an SRID
> + *
> + * @param srid - vddid
> + *
> + * @return struct pointer if found, else BUG()s
> + */
> +static inline struct omap_sr *get_sr(u8 srid)
> +{
> +       BUG_ON(srid > omap_srlist->num_sr);
> +       return omap_srlist->sr_list[srid - 1];
> +}
> +
> +/**
> + * @brief *get_sr_from_vdd - get the SR structure indexed by
> + * VDD ID
> + *
> + * @param vddid - vddid
> + *
> + * @return struct pointer if found, else BUG()s
> + */
> +static inline struct omap_sr *get_sr_from_vdd(u8 vddid)
> +{
> +       /* Currently, the SRID and VDDID are the same, misusing it */
> +       return get_sr(vddid);
> +}
> +
> +/**
> + * @brief *get_sr_from_vdd_name - get the SR structure from
> + * sysfs name
> + *
> + * @param name -sysfs entry name
> + *
> + * @return sr struct pointer if found else NULL
> + */
> +static struct omap_sr *get_sr_from_vdd_name(char *name)
> +{
> +       int i;
> +       struct omap_sr *sr;
> +       for (i = 0; i < omap_srlist->num_sr; i++) {
> +               sr = omap_srlist->sr_list[i];
> +               if (!strcmp(name, sr->autocom_attr.attr.name))
> +                       return sr;
> +       }
> +       /* Nothin found, BUG!! */
> +       BUG();
> +       return NULL;
> +}
> +
> +/**
> + * @brief get_current_opp_number_from_sr - get the current active OPP number
> + * from SR pointer
> + *
> + * @param sr struct pointer
> + *
> + * @return current OPP ID
> + */
> +static inline int get_current_opp_number_from_sr(struct omap_sr *sr)
> +{
> +       return (*sr->omap_opp)[resource_get_level(sr->vdd_name)].opp_id;
> +}
> +
> +/**
> + * @brief get_vsel_for_opp - get the VSEL value for the SR/OPP combination
> + *
> + * @param sr  struct pointer
> + * @param opp opp number desired for
> + *
> + * @return vsel value, if bad opp number is given, this will BUG()
> + */
> +static inline u8 get_vsel_for_opp(struct omap_sr *sr, int opp)
> +{
> +       /* Dont ask me to derefence nonexistant OPPs!
> +        * TODO: add check for valid OPPs here
> +        */
> +       BUG_ON(opp > sr->num_opp);
> +       return (*sr->omap_opp)[opp].vsel;
> +}
> +
> +/****************** SMART REFLEX DEBUGFS ENTRIES *************************/
> +
> +#ifdef __SR_DEBUG
> +
> +/**
> + * @brief sr_debugfs_set - set variable with value
> + *
> + * @param data - variable pointer
> + * @param val - value to set
> + *
> + * @return - 0
> + */
> +static int sr_debugfs_set(void *data, u64 val)
> +{
> +       u32 *option = data;
> +
> +       *option = val;
> +
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_debugfs_get - setup the params
> + *
> + * @param data - variable to set
> + * @param val - value to return
> + *
> + * @return - 0
> + */
> +static int sr_debugfs_get(void *data, u64 *val)
> +{
> +       u32 *option = data;
> +
> +       *val = *option;
> +
> +       return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_fops, sr_debugfs_get, sr_debugfs_set,
> +                       "%llu\n");
> +
> +/**
> + * @brief sr_debugfs_vselget - return the vsel value
> + *
> + * @param data - pointer to vp
> + * @param val - value we read back
> + *
> + * @return
> + */
> +static int sr_debugfs_vselget(void *data, u64 *val)
> +{
> +       struct omap_sr_vp *vp = (struct omap_sr_vp *)data;
> +
> +       *val = prm_read_mod_reg(OMAP3430_GR_MOD, vp->prm_vpx_voltage_offset);
> +
> +       return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(sr_debugfs_option_vsel_fops, sr_debugfs_vselget, NULL,
> +                       "%llu\n");
> +
> +/* Temporary store of pm_debug directory entry */
> +static __initdata struct dentry *stored_pm_d;
> +
> +/**
> + * @brief sr_debugfs_create_entries - create the Smart Reflex entries
> + * called from pm-debug, this just stores it for SR to use in late_init
> + *
> + * @param d - parent directory tree
> + *
> + * @return 0 if all ok, else returns with error
> + */
> +int sr_debugfs_create_entries(struct dentry *d)
> +{
> +       stored_pm_d = d;
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_debugfs_create_entries_late - create the Smart Reflex entries -
> + * called as part of init sequence of SR uses the dentry registered early
> + *
> + * @param d - parent directory tree
> + *
> + * @return 0 if all ok, else returns with error
> + */
> +static __init int sr_debugfs_create_entries_late(void)
> +{
> +       struct dentry *sr_dir;
> +       struct dentry *sr_sub_dir;
> +       int count;
> +
> +       sr_dir = debugfs_create_dir("smartreflex", stored_pm_d);
> +       if (IS_ERR(sr_dir))
> +               return PTR_ERR(sr_dir);
> +       for (count = 0; count < omap_srlist->num_sr; count++) {
> +               int i;
> +               struct omap_sr *sr = get_sr(count + 1);
> +               char name[] = "0";
> +               char nval_name[] = "nvalue_opp0";
> +               name[0] += sr->srid;
> +               sr_sub_dir = debugfs_create_dir(name, sr_dir);
> +               if (IS_ERR(sr_sub_dir))
> +                       continue;
> +               for (i = 0; i < sr->num_opp; i++) {
> +                       nval_name[strlen(nval_name) - 1]++;
> +                       (void)debugfs_create_file(nval_name, S_IRUGO | S_IWUGO,
> +                                                 sr_sub_dir,
> +                                                 &(sr->opp_nvalue[i]),
> +                                                 &sr_debugfs_option_fops);
> +               }
> +               (void)debugfs_create_file("sr_errconfig_value",
> +                                         S_IRUGO | S_IWUGO, sr_sub_dir,
> +                                         &(sr->sr_errconfig_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("sr_config_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->sr_config_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vpconfig_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->vp.vpconfig_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vpstepmin_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->vp.vpstepmin_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vpstepmax_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->vp.vpstepmax_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->vp.vplimito_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vplimito_value", S_IRUGO | S_IWUGO,
> +                                         sr_sub_dir, &(sr->vp.vplimito_value),
> +                                         &sr_debugfs_option_fops);
> +               (void)debugfs_create_file("vsel", S_IRUGO, sr_sub_dir,
> +                               &(sr->vp), &sr_debugfs_option_vsel_fops);
> +       }
> +
> +       return 0;
> +}
> +
> +#else
> +
> +static inline int sr_debugfs_create_entries_late(void)
> +{
> +       return 0;
> +}
> +#endif                         /* __SR_DEBUG */
> +
> +/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives **********/
> +
> +/**
> + * @brief pmic_srinit - Power management IC initialization
> + * for smart reflex. The current code is written for TWL4030
> + * derivatives, replace in board file if PMIC requires
> + * a different sequence
> + *
> + * @return result of operation
> + */
> +int __weak __init omap_pmic_srinit(void)
> +{
> +       int ret = -ENODEV;
> +#ifdef CONFIG_TWL4030_CORE
> +       u8 reg;
> +       /* Enable SR on T2 */
> +       ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &reg,
> +                                 R_DCDC_GLOBAL_CFG);
> +
> +       reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
> +       ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg,
> +                                   R_DCDC_GLOBAL_CFG);
> +#endif                         /* End of CONFIG_TWL4030_CORE */
> +       return ret;
> +}
> +
> +/**
> + * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp delay
> + * Various PMICs have different ramp up and down delays. choose to implement
> + * in required pmic file to override this function.
> + * On TWL4030 derivatives:
> + *  T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV,
> + *  2us added as buffer.
> + *
> + * @param srid - which SR is this for?
> + * @param target_vsel - targetted voltage selction
> + * @param current_vsel - current voltage selection
> + *
> + * @return delay in uSeconds
> + */
> +u32 __weak omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel,
> +                                       u8 current_vsel)
> +{
> +       u32 t2_smps_steps = abs(target_vsel - current_vsel);
> +       u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
> +       return t2_smps_delay;
> +}
> +
> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
> +/**
> + * @brief omap_pmic_voltage_cmds - hook for pmic command sequence
> + * to be send out which are specific to pmic to set a specific voltage.
> + * this should inturn call vc_send_command with the required sequence
> + * The current implementation is for TWL4030 derivatives
> + *
> + * @param srid - which SR is this for?
> + * @param target_vsel - what voltage is desired to be set?
> + *
> + * @return specific value to set.
> + */
> +int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel)
> +{
> +       u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL;
> +       u16 timeout = COUNT_TIMEOUT_TWL4030_VCBYPASS;
> +       return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel,
> +                              &timeout);
> +}
> +#endif                         /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */
> +
> +/*********************** Voltage Controller functions *************************/
> +
> +/**
> + * @brief vc_send_command - The actual command transmission using
> + * Voltage controller on I2C4
> + *
> + * @param slave_addr - what is the PMIC slave address
> + * @param reg_addr  - what is the register address I should be using?
> + * @param data - what value do you want to write here?
> + * @param timeout_us timeout in uSeconds - returns actual time left
> + *
> + * @return 0 if all ok, else error value
> + */
> +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us)
> +{
> +       u32 value;
> +       u32 count;
> +
> +       if (unlikely(!timeout_us))
> +               return -EINVAL;
> +
> +       /* timeout = timeout_us/10 -> each udelay event
> +        * 1 udelay event every 50 iteration, assuming
> +        * each iteration is instaneous,
> +        * count = (timeout_us/10) * 50 or timeout_us * 5
> +        */
> +       count = *timeout_us * 5;
> +
> +       value = (data << OMAP3430_DATA_SHIFT) |
> +           (reg_addr << OMAP3430_REGADDR_SHIFT) |
> +           (slave_addr << OMAP3430_SLAVEADDR_SHIFT);
> +
> +       prm_write_mod_reg(value, OMAP3430_GR_MOD,
> +                         OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
> +
> +       value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD,
> +                                    OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
> +       /*
> +        * Do continous 50 checks then follow with a 10usec delay,
> +        * then check again
> +        */
> +       do {
> +               value = prm_read_mod_reg(OMAP3430_GR_MOD,
> +                                        OMAP3_PRM_VC_BYPASS_VAL_OFFSET)
> +                   & OMAP3430_VALID;
> +               /* should i wait? */
> +               if (value && (count % 50)) {
> +                       udelay(10);
> +                       *timeout_us -= 10;
> +               }
> +               count--;
> +       } while (value && count);
> +       if (!count) {
> +               pr_err("VC:Command Timedout! slave_addr=0x%02X,"
> +                      "reg=0x%02X, value=0x%02X", slave_addr, reg_addr, data);
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +EXPORT_SYMBOL(vc_send_command);
> +
> +/**
> + * @brief sr_vc_bypass - setup voltage using VC Bypass technique
> + *
> + * @param target_opp - target opp to go to
> + * @param current_opp  - current opp
> + * @param target_vsel  - which voltage to go to?
> + * @param current_vsel  - current voltage
> + *
> + * @return -success or failure
> + */
> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
> +static int sr_vc_bypass(struct omap_sr *sr,
> +                       u32 target_opp_no, u8 target_vsel, u8 current_vsel)
> +{
> +       int ret = 0;
> +       struct omap_sr_vp *vp = &sr->vp;
> +       u32 vpconfig_value;
> +
> +       vpconfig_value = vp->vpconfig_value;
> +       vpconfig_value |=
> +           ((target_opp_no <
> +             sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) <<
> +           OMAP3430_ERRORGAIN_SHIFT;
> +       vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT;
> +       prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_config_offset);
> +
> +       prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
> +                            (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
> +                            OMAP3430_GR_MOD, vp->prm_vc_cmd_val_offset);
> +
> +       /*
> +        * Various PMIC might need a set of commands
> +        * provide hooks for specific PMICs to implement
> +        */
> +       ret = omap_pmic_voltage_cmds(sr->srid, target_vsel);
> +
> +       /* delay based on pmic */
> +       if (!ret)
> +               udelay(omap_pmic_voltage_ramp_delay(sr->srid,
> +                                                   target_vsel, current_vsel));
> +
> +       WARN_ON(ret);
> +
> +       return ret;
> +}
> +#endif                         /* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */
> +
> +/********************* SR Private functions ***************************/
> +
> +/**
> + * @brief sr_write_reg - write to Smart Reflex Register
> + *
> + * @param sr  - pointer to SR structure
> + * @param offset - SR reg offset to write to
> + * @param value - value to write with
> + */
> +static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
> +{
> +       __raw_writel(value, SR_REGADDR(offset));
> +}
> +
> +/**
> + * @brief sr_modify_reg - Modify a register and write a new value to a field
> + *
> + * @param sr -pointer to SR structure
> + * @param offset -register offset
> + * @param mask -mask to clear out
> + * @param value -value to write there
> + */
> +static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
> +                                u32 value)
> +{
> +       u32 reg_val;
> +
> +       reg_val = __raw_readl(SR_REGADDR(offset));
> +       reg_val &= ~mask;
> +       reg_val |= value;
> +
> +       __raw_writel(reg_val, SR_REGADDR(offset));
> +}
> +
> +/**
> + * @brief sr_read_reg - read a SR register
> + *
> + * @param sr - pointer to SR structure
> + * @param offset - register offset
> + *
> + * @return value in that register
> + */
> +static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
> +{
> +       return __raw_readl(SR_REGADDR(offset));
> +}
> +
> +/**
> + * @brief sr_vplimito_value -return the timeout value based on sysclk
> + *             and desired timeout uSec
> + *
> + * @param sys_clk_speed - internal sysclk freq in hz
> + * @param timeout_us - timeout in uSec
> + *
> + * @return timeout value to use in VPLIMITTO:TIMEOUT reg
> + */
> +static inline u32 sr_vplimito_value(u32 sys_clk_speed, u16 timeout_us)
> +{
> +       u32 timeout_val;
> +       /* prevent round off errors, we will divide by 10 later */
> +       timeout_val = (sys_clk_speed / 100000);
> +       timeout_val *= timeout_us;
> +       timeout_val /= 10;
> +       return timeout_val;
> +}
> +
> +/**
> + * @brief sr_clk_enable - SR clock enable
> + *
> + * @param sr - Structure to SR structure
> + *
> + * @return - result
> + */
> +static int sr_clk_enable(struct omap_sr *sr)
> +{
> +       if (clk_enable(sr->iclk) != 0) {
> +               pr_crit("SR:Could not enable %s for [%d]\n",
> +                       sr->iclk->name, sr->srid);
> +               return -EINVAL;
> +       }
> +       if (clk_enable(sr->fclk) != 0) {
> +               pr_crit("SR:Could not enable %s for [%d]\n",
> +                       sr->fclk->name, sr->srid);
> +               clk_disable(sr->iclk);
> +               return -EINVAL;
> +       }
> +       sr_modify_reg(sr, ERRCONFIG,
> +                     SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK,
> +                     SR_CLKACTIVITY_IOFF_FON);
> +       sr->is_sr_reset = 0;
> +
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_clk_disable - SR func clock disable
> + *
> + * @param sr - pointer to SR structure
> + */
> +static void sr_clk_disable(struct omap_sr *sr)
> +{
> +       /* set fclk, iclk- idle */
> +       sr_modify_reg(sr, ERRCONFIG,
> +                     SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK,
> +                     SR_CLKACTIVITY_IOFF_FOFF);
> +
> +       clk_disable(sr->fclk);
> +       clk_disable(sr->iclk);
> +       sr->is_sr_reset = 1;
> +}
> +
> +/****************** Voltage processor functions ***************************/
> +
> +/**
> + * @brief sr_vp_clear_vptransdone - clear vptrans_done event
> + *
> + * @param sr - sr pointer
> + *
> + * @return 0 if cleared ok, else 1 if timedout!
> + */
> +static int sr_vp_clear_vptransdone(struct omap_sr *sr)
> +{
> +       struct omap_sr_vp *vp = &sr->vp;
> +       u32 irqstat;
> +       u32 count = COUNT_TIMEOUT_TRANSDONE_CLR;
> +       do {
> +               prm_write_mod_reg(vp->irqmask_trans_done, OCP_MOD,
> +                                 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> +               irqstat = prm_read_mod_reg(OCP_MOD,
> +                                          OMAP3_PRM_IRQSTATUS_MPU_OFFSET) &
> +                   vp->irqmask_trans_done;
> +               if (irqstat)
> +                       udelay(1);
> +               count--;
> +       } while (count && irqstat);
> +       if (!count) {
> +               pr_crit("SR:VPTransdone[%d]:Timedout\n", sr->srid);
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_vp_forceupdate - do a forceupdate method
> + *             to update the voltage level
> + *
> + * @param sr - pointer to sr structure
> + * @param target_opp_no - targetted opp number
> + * @param target_vsel - targetted voltage level
> + * @param current_vsel - current voltage level
> + *
> + * @return 0 if all worked out, else 1
> + */
> +#ifndef CONFIG_OMAP_VC_BYPASS_UPDATE
> +static int sr_vp_forceupdate(struct omap_sr *sr, u32 target_opp_no,
> +                            u8 target_vsel, u8 current_vsel)
> +{
> +       u32 count;
> +       u32 irqstat;
> +       u32 vpconfig_value;
> +       u32 retry_counter = COUNT_RETRY_SMPSNOACK;
> +
> +       struct omap_sr_vp *vp = &sr->vp;
> +
> +retry_forceupdate:
> +       /* First clear any pending events in the system */
> +       if (sr_vp_clear_vptransdone(sr)) {
> +               pr_crit("SR:forceupdate-transdone1[%d]:timedout\n", sr->srid);
> +               return -ETIMEDOUT;
> +       }
> +
> +       vpconfig_value = vp->vpconfig_value;
> +       vpconfig_value |=
> +           ((target_opp_no <
> +             sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) <<
> +           OMAP3430_ERRORGAIN_SHIFT;
> +       vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT;
> +
> +       prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_config_offset);
> +
> +       /* Trigger initVDD value copy to voltage processor */
> +       prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
> +                            vp->prm_vpx_config_offset);
> +
> +       /* Force update of voltage */
> +       prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
> +                            vp->prm_vpx_config_offset);
> +
> +       /* Clear initVDD copy trigger bit */
> +       prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +       /* Clear force bit */
> +       prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +
> +       /* Now wait for the i2c transactions to complete */
> +       count = COUNT_TIMEOUT_TRANSDONE_SET;
> +       irqstat = 0;
> +       do {
> +               irqstat = prm_read_mod_reg(OCP_MOD,
> +                                          OMAP3_PRM_IRQSTATUS_MPU_OFFSET) &
> +                   vp->irqmask_trans_done;
> +               if (!irqstat)
> +                       udelay(1);
> +               count--;
> +       } while (count && !irqstat);
> +       if (!count) {
> +               irqstat = prm_read_mod_reg(OCP_MOD,
> +                                          OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> +               if (irqstat & vp->irqmask_smps_noack) {
> +                       WARN(irqstat, "SMPS NO ACK DETECTED[0x%08X]!!"
> +                            "ATTEMPTING RECOVERY [%d left]\n",
> +                            irqstat, retry_counter);
> +                       prm_write_mod_reg(irqstat, OCP_MOD,
> +                                         OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> +                       retry_counter--;
> +                       if (retry_counter)
> +                               goto retry_forceupdate;
> +               }
> +               pr_crit("SR:forceupdate-transdone[%d]:timedout-"
> +                       "irqstat=0x%08X\n", sr->srid, irqstat);
> +               BUG();
> +               return -ETIMEDOUT;
> +       }
> +
> +       /*
> +        * Now we wait for voltage to rise on PMIC
> +        */
> +       udelay(omap_pmic_voltage_ramp_delay(sr->srid, target_vsel,
> +                                           current_vsel));
> +
> +       /* clear that event */
> +       if (sr_vp_clear_vptransdone(sr)) {
> +               pr_crit("SR:forceupdate-transdone2[%d]:timedout\n", sr->srid);
> +               BUG();
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +#endif                         /* ifndef CONFIG_OMAP_VC_BYPASS_UPDATE */
> +
> +/**
> + * @brief sr_vp_enable - enable VP enable code
> + *
> + * @param sr
> + */
> +static int sr_vp_enable(struct omap_sr *sr, u32 target_opp_no)
> +{
> +       u32 vpconfig_value;
> +       struct omap_sr_vp *vp = &sr->vp;
> +
> +       /* Disable VP */
> +       prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +       /* Clear INITVDD */
> +       prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +
> +       vpconfig_value = vp->vpconfig_value;
> +       vpconfig_value |= get_vsel_for_opp(sr, target_opp_no) <<
> +           OMAP3430_INITVOLTAGE_SHIFT;
> +       vpconfig_value |=
> +           ((target_opp_no <
> +             sr->opp_boundary) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) <<
> +           OMAP3430_ERRORGAIN_SHIFT;
> +
> +       prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_config_offset);
> +
> +       prm_write_mod_reg(vp->vpstepmin_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_stepmin_offset);
> +       prm_write_mod_reg(vp->vpstepmax_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_stepmax_offset);
> +       prm_write_mod_reg(vp->vplimito_value, OMAP3430_GR_MOD,
> +                         vp->prm_vpx_limito_offset);
> +
> +       /* write1 to latch */
> +       prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
> +                            vp->prm_vpx_config_offset);
> +       /* write2 clear */
> +       prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +       /* Enable VP */
> +       prm_set_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
> +                            vp->prm_vpx_config_offset);
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_vp_disable - disbale Voltage processor
> + *
> + * @param sr - sr structure
> + *
> + * @return 0 if all ok, else return -ETIMEDOUT
> + */
> +static int sr_vp_disable(struct omap_sr *sr)
> +{
> +       int count;
> +       u32 v;
> +       struct omap_sr_vp *vp = &sr->vp;
> +
> +       v = prm_read_mod_reg(OMAP3430_GR_MOD,
> +                            vp->prm_vpx_config_offset) & vp->vpenable_mask;
> +       /* Am i already disabled? */
> +       if (!v) {
> +               pr_info("SR[%d] attempt to disable VP when already disabled!\n",
> +                       sr->srid);
> +               return 0;
> +       }
> +
> +       /* Disable VP */
> +       prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
> +                              vp->prm_vpx_config_offset);
> +
> +       /* Wait for vp to get idle - clear any events pending */
> +       count = COUNT_TIMEOUT_MCUDISACK;
> +       do {
> +               v = prm_read_mod_reg(OMAP3430_GR_MOD,
> +                                    vp->prm_vpx_status_offset) &
> +                   PRM_VP_STATUS_VPINIDLE;
> +               if (!v)
> +                       udelay(1);
> +               count--;
> +       } while (count && !v);
> +       if (unlikely(!count)) {
> +               v = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
> +               pr_warning("SR[%d]:vpdisable-vpinidle[opp=%d]:timedout-"
> +                          "irqstat=0x%08X\n", sr->srid, sr->req_opp_no, v);
> +               return -ETIMEDOUT;
> +       }
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_vp_configure - configure the basic SR structure
> + *
> + * @param sr - pointer to SR structure
> + */
> +static void sr_vp_configure(struct omap_sr *sr)
> +{
> +       u32 target_opp_no;
> +       u32 target_vsel;
> +       u32 prm_vpx_voltage;
> +
> +       target_opp_no = get_current_opp_number_from_sr(sr);
> +       target_vsel = get_vsel_for_opp(sr, target_opp_no);
> +       prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
> +                                          sr->vp.prm_vpx_voltage_offset);
> +       sr_vp_enable(sr, target_opp_no);
> +       if (SR_CHOSEN_VOLTAGE_UPDATE_MECH
> +           (sr, target_opp_no, target_vsel, prm_vpx_voltage))
> +               pr_crit("SR[%d] CONFIGURE VP failed!!\n", sr->srid);
> +}
> +
> +/**
> + * @brief sr_vp_reset_voltage - reset the voltages back to DVFS values
> + *
> + * @param srid -SRID
> + *
> + * @return 0 if ok, else result
> + */
> +static int sr_vp_reset_voltage(u8 srid)
> +{
> +       u32 target_opp_no;
> +       u32 target_vsel;
> +       u32 prm_vpx_voltage;
> +       struct omap_sr *sr;
> +
> +       sr = get_sr(srid);
> +       target_opp_no = sr->req_opp_no;
> +       target_vsel = get_vsel_for_opp(sr, target_opp_no);
> +       prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
> +                                          sr->vp.prm_vpx_voltage_offset);
> +       return SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no,
> +                                            target_vsel, prm_vpx_voltage);
> +
> +}
> +
> +/*********************** SR functions *************************/
> +
> +/**
> + * @brief sr_enable - enable smart reflex
> + *
> + * @param sr - smartreflex structure we are interest
> + * @param target_opp_no - target opp we want to switch to
> + *
> + * @return 0 if all went right, else return err val
> + */
> +static int sr_enable(struct omap_sr *sr, u32 target_opp_no)
> +{
> +       u32 value;
> +
> +       if (!sr->is_sr_reset) {
> +               pr_info("SR[%d]already enabled\n", sr->srid);
> +               return -EINVAL;
> +       }
> +
> +       sr->req_opp_no = target_opp_no;
> +
> +       value = sr->opp_nvalue[target_opp_no - 1];
> +       if (value == 0) {
> +               pr_info("SR[%d]:OPP%d doesn't support SmartReflex\n",
> +                       sr->srid, target_opp_no);
> +               return -EINVAL;
> +       }
> +
> +       sr_clk_enable(sr);
> +       /* Start with setting SREnable as 0 */
> +       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0);
> +
> +       sr_write_reg(sr, SRCONFIG, sr->sr_config_value);
> +
> +       sr_write_reg(sr, NVALUERECIPROCAL, value);
> +
> +       value = sr->sr_errconfig_value |
> +           ((target_opp_no < sr->opp_boundary) ? SR_ERRMINLIMIT_LOWOPP :
> +            SR_ERRMINLIMIT_HIGHOPP);
> +
> +       sr_write_reg(sr, ERRCONFIG, value);
> +
> +       /* SRCONFIG - enable SR */
> +       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
> +
> +       return 0;
> +}
> +
> +/**
> + * @brief sr_disable - disable Smart Reflex
> + *
> + * @param sr -  pointer to sr structure of interest
> + *
> + * @return 0 if all went right, else return INVAL/TIMEDOUT
> + */
> +int sr_disable(struct omap_sr *sr)
> +{
> +       int count;
> +       u32 stat;
> +       u32 value;
> +
> +       if (sr->is_sr_reset) {
> +               pr_info("SR[%d]-disable:already Disabled\n", sr->srid);
> +               return -EINVAL;
> +       }
> +       value = sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE;
> +       if (!value) {
> +               pr_info("SR[%d] attempt to disable SR when already disabled!\n",
> +                       sr->srid);
> +               return 0;
> +       }
> +       value = sr->opp_nvalue[sr->req_opp_no - 1];
> +       if (value == 0) {
> +               pr_info("SR[%d]-disable:"
> +                       "OPP%d doesn't support SmartReflex\n",
> +                       sr->srid, sr->req_opp_no);
> +               return -EINVAL;
> +       }
> +       /* Enable the MCUDISACKINST */
> +       sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN |
> +                     ERRCONFIG_INTERRUPT_STATUS_MASK,
> +                     ERRCONFIG_MCUDISACKINTEN);
> +
> +       /* SRCONFIG - disable SR */
> +       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0);
> +
> +       /* Disable VPBOUND interrupt and clear any status
> +        * before actually waiting for disack
> +        * should be done after sr is disabled
> +        */
> +       sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_VPBOUNDINTEN |
> +                     ERRCONFIG_INTERRUPT_STATUS_MASK, ERRCONFIG_VPBOUNDINTST);
> +
> +       /* Wait for MCUDISACKINTST to be set */
> +       count = COUNT_TIMEOUT_MCUDISACK;
> +       do {
> +               stat = sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST;
> +               if (!stat)
> +                       udelay(1);
> +               count--;
> +       } while (count && !stat);
> +       /* Clear the event and disable MCUDISACKINST */
> +       sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN |
> +                     ERRCONFIG_INTERRUPT_STATUS_MASK,
> +                     ERRCONFIG_MCUDISACKINTST);
> +
> +       if (!count) {
> +               pr_crit("SR[%d]-disable:MCUDIS timedout\n", sr->srid);
> +               return -ETIMEDOUT;
> +       }
> +       sr_clk_disable(sr);
> +       return 0;
> +}
> +
> +/**************** Common enable/disable functionality *********************/
> +
> +/**
> + * @brief srvp_disable - disable SR and VP
> + * These functions are based on h/w timeouts and should ideally not fail.
> + *
> + * @param sr -sr struct
> + *
> + * @return  result
> + */
> +static int srvp_disable(struct omap_sr *sr)
> +{
> +       int ret;
> +       /* If we dont have an nvalue, dont bother.. */
> +       if (!sr->opp_nvalue[sr->req_opp_no - 1]) {
> +               pr_warning("SR[%d]: OPP%d does not support SR to disable\n",
> +                          sr->srid, sr->req_opp_no);
> +               return -EINVAL;
> +       }
> +       ret = sr_vp_disable(sr);
> +       if (unlikely(ret)) {
> +               pr_err("SR[%d]: failed to disable vp:%d\n", sr->srid, ret);
> +       } else {
> +               ret = sr_disable(sr);
> +               if (unlikely(ret))
> +                       pr_err("SR[%d]: failed to disable sr:%d\n",
> +                              sr->srid, ret);
> +       }
> +       /*
> +        * Does not make much sense renabling SR as
> +        * system is going to be in an invalid state
> +        */
> +       WARN_ON(ret);
> +       return ret;
> +}
> +
> +/**
> + * @brief srvp_enable - enable SR and VP
> + * These functions are based on h/w timeouts and should ideally not fail.
> + *
> + * @param sr -sr struct
> + * @param target_opp -opp to go to
> + *
> + * @return result
> + */
> +static int srvp_enable(struct omap_sr *sr, u32 target_opp)
> +{
> +       int ret;
> +
> +       /* If we dont have an nvalue, dont bother.. */
> +       if (!sr->opp_nvalue[target_opp - 1]) {
> +               pr_warning("SR[%d]: OPP%d does not support SR to enable\n",
> +                          sr->srid, target_opp);
> +               return -EINVAL;
> +       }
> +       ret = sr_vp_enable(sr, target_opp);
> +       if (unlikely(ret)) {
> +               pr_err("SR[%d]: failed to enable vp:%d\n", sr->srid, ret);
> +       } else {
> +               ret = sr_enable(sr, target_opp);
> +               /* Attempt to recover */
> +               if (unlikely(ret)) {
> +                       pr_err("SR[%d]: failed to enable sr:%d\n", sr->srid,
> +                              ret);
> +                       /* nothing we can do if vp_disable fails */
> +                       (void)sr_vp_disable(sr);
> +               }
> +       }
> +       /*
> +        * potentially system in an invalid state - warn..
> +        */
> +       WARN_ON(ret);
> +       return ret;
> +}
> +
> +/*********************** DVFS Entry POINTS **********************************/
> +
> +/**
> + * @brief sr_vp_enable_both - enable both vp and sr
> + *
> + * @param target_opp - targetted op
> + * @param current_opp - current opp
> + *
> + * @return 0 if ok, 1 if not ok
> + */
> +int sr_vp_enable_both(u32 target_opp, u32 current_opp)
> +{
> +       struct omap_sr *sr;
> +       u32 vdd, target_opp_no;
> +       int ret = 0;
> +
> +       vdd = get_vdd(target_opp);
> +       target_opp_no = get_opp_no(target_opp);
> +       sr = get_sr_from_vdd(vdd);
> +
> +       if (sr->is_autocomp_active && sr->is_sr_reset) {
> +               ret = srvp_enable(sr, target_opp_no);
> +               if (ret) {
> +                       pr_err("SR[%d]:enableboth:"
> +                              "failed enable SR\n", sr->srid);
> +               }
> +       }
> +       return ret;
> +}
> +EXPORT_SYMBOL(sr_vp_enable_both);
> +
> +/**
> + * @brief sr_vp_disable_both - disable both vp and sr
> + *
> + * @param target_opp - targetted opp
> + * @param current_opp - current opp
> + *
> + * @return 0 if ok, 1 if not ok
> + */
> +int sr_vp_disable_both(u32 target_opp, u32 current_opp)
> +{
> +       struct omap_sr *sr;
> +       u32 vdd;
> +       int ret = 0;
> +
> +       vdd = get_vdd(target_opp);
> +       sr = get_sr_from_vdd(vdd);
> +
> +       if (sr->is_autocomp_active && !sr->is_sr_reset) {
> +               ret = srvp_disable(sr);
> +               if (ret) {
> +                       pr_err("SR[%d]:disableboth:"
> +                              "failed disable SR\n", sr->srid);
> +               }
> +       }
> +
> +       return ret;
> +
> +}
> +EXPORT_SYMBOL(sr_vp_disable_both);
> +
> +/**
> + * @brief sr_voltage_set - setup a voltage requested
> + *
> + * @param target_opp - targetted opp
> + * @param current_opp  - current opp
> + * @param target_vsel - targeted voltage
> + * @param current_vsel - current voltage
> + *
> + * @return  - result of op -0 if ok, else value
> + */
> +int sr_voltage_set(u32 target_opp, u32 current_opp,
> +                  u8 target_vsel, u8 current_vsel)
> +{
> +       struct omap_sr *sr;
> +       u8 vdd, target_opp_no;
> +       int ret;
> +
> +       vdd = get_vdd(target_opp);
> +       target_opp_no = get_opp_no(target_opp);
> +       sr = get_sr_from_vdd(vdd);
> +
> +       ret =
> +           SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel,
> +                                         current_vsel);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL(sr_voltage_set);
> +
> +/*********************** CPUIDLE ENTRY POINTS *********************************/
> +
> +/**
> + * @brief disable_smartreflex - disable SmartReflex before WFI
> + *
> + * @param srid SRID
> + */
> +void disable_smartreflex(u8 srid)
> +{
> +       struct omap_sr *sr = NULL;
> +       int ret;
> +       u32 current_opp_no;
> +
> +       /* I want to be in irq_disabled context..
> +        * else I will die.. find the rootcause and fix it instead
> +        */
> +       BUG_ON(!irqs_disabled());
> +
> +       sr = get_sr(srid);
> +
> +       current_opp_no = get_current_opp_number_from_sr(sr);
> +
> +       if (sr->is_autocomp_active && !sr->is_sr_reset) {
> +               sr->req_opp_no = current_opp_no;
> +               ret = srvp_disable(sr);
> +               if (ret)
> +                       pr_err("SR[%d]:disable_smartreflex:"
> +                              "failed disable SR\n", sr->srid);
> +       }
> +
> +       /* Reset the voltage for current OPP to nominal if SR was enabled */
> +       if (sr->is_autocomp_active)
> +               sr_vp_reset_voltage(srid);
> +}
> +EXPORT_SYMBOL(disable_smartreflex);
> +
> +/**
> + * @brief enable_smartreflex - enable smart reflex after WFI is hit
> + *
> + * @param srid -SR ID to hit
> + */
> +void enable_smartreflex(u8 srid)
> +{
> +       struct omap_sr *sr;
> +       int ret;
> +       u32 current_opp_no;
> +
> +       /* I want to be in irq_disabled context..
> +        * else I will die.. find the rootcause and fix it instead
> +        */
> +       BUG_ON(!irqs_disabled());
> +
> +       sr = get_sr(srid);
> +       current_opp_no = get_current_opp_number_from_sr(sr);
> +
> +       if (sr->is_autocomp_active && sr->is_sr_reset) {
> +               ret = srvp_enable(sr, current_opp_no);
> +               if (ret)
> +                       pr_err("SR[%d]:enable_smartreflex:"
> +                              "failed enable SR\n", sr->srid);
> +       }
> +}
> +EXPORT_SYMBOL(enable_smartreflex);
> +
> +/*********************** SYSFS ENTRY POINTS *********************************/
> +/**
> + * @brief omap_sr_vdd_autocomp_show - Sysfs entry for showing SR status
> + *
> + */
> +static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj,
> +                                        struct kobj_attribute *attr, char *buf)
> +{
> +       struct omap_sr *sr;
> +       sr = get_sr_from_vdd_name((char *)attr->attr.name);
> +       return sprintf(buf, "%d\n", sr->is_autocomp_active);
> +}
> +
> +/**
> + * @brief omap_sr_vdd_autocomp_store - enable/disable SR
> + *
> + */
> +static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj,
> +                                         struct kobj_attribute *attr,
> +                                         const char *buf, size_t n)
> +{
> +       unsigned short value;
> +       struct omap_sr *sr;
> +       int ret = 0;
> +       char *name;
> +
> +       name = (char *)attr->attr.name;
> +
> +       sr = get_sr_from_vdd_name(name);
> +
> +       if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
> +               pr_err("%s: Invalid value[%d]. Use 0 or 1\n", name, value);
> +               return -EINVAL;
> +       }
> +       if (sr->is_autocomp_active == value) {
> +               pr_info("%s: Already set to %d \n", name, value);
> +               return n;
> +       }
> +       /*
> +        * Sanity check-might happen if SR and dvfs/idle paths collide
> +        * but unlikely though..
> +        */
> +       if (unlikely(value ^ sr->is_sr_reset)) {
> +               pr_warning("%s: Is already set %d Vs %d.\n", name, value,
> +                          sr->is_sr_reset);
> +               return n;
> +       }
> +
> +       if (value) {
> +               u32 current_vddopp_no = get_current_opp_number_from_sr(sr);
> +               ret = srvp_enable(sr, current_vddopp_no);
> +       } else {
> +               ret = srvp_disable(sr);
> +               /* reset the voltage back to nominal */
> +               sr_vp_configure(sr);
> +       }
> +       if (!ret) {
> +               sr->is_autocomp_active = value;
> +               ret = n;
> +       }
> +
> +       return ret;
> +}
> +
> +/*********************** INIT FUNCTIONS *************************************/
> +
> +/**
> + * @brief srvp_init - configure smart reflex and VP params
> + *
> + * @param sr  - structure of sr of interest
> + */
> +static void __init srvp_init(struct omap_sr *sr)
> +{
> +       struct clk *sys_ck;
> +       u32 sys_clk_speed;
> +       u32 clk_len;
> +       u32 senn_mod, senp_mod;
> +       u8 opp_count;
> +
> +       /* Grab the clock speed */
> +       sys_ck = clk_get(NULL, "sys_ck");
> +       sys_clk_speed = clk_get_rate(sys_ck);
> +       clk_put(sys_ck);
> +
> +       switch (sys_clk_speed) {
> +       case 12000000:
> +               clk_len = SRCLKLENGTH_12MHZ_SYSCLK;
> +               break;
> +       case 13000000:
> +               clk_len = SRCLKLENGTH_13MHZ_SYSCLK;
> +               break;
> +       case 19200000:
> +               clk_len = SRCLKLENGTH_19MHZ_SYSCLK;
> +               break;
> +       case 26000000:
> +               clk_len = SRCLKLENGTH_26MHZ_SYSCLK;
> +               break;
> +       case 38400000:
> +               clk_len = SRCLKLENGTH_38MHZ_SYSCLK;
> +               break;
> +       default:
> +               pr_err("SR[%d]:Invalid sysclk value: %d\n", sr->srid,
> +                      sys_clk_speed);
> +               BUG();
> +               return;
> +       }
> +       /* The original nvalue contents were the register offsets
> +        * now we replace them with the nvalue to be used elsewhere
> +        */
> +       for (opp_count = 0; opp_count < sr->num_opp; opp_count++)
> +               sr->opp_nvalue[opp_count] =
> +                   omap_ctrl_readl(sr->opp_nvalue[opp_count]);
> +
> +       sr->vp.vplimito_value |= sr_vplimito_value(sys_clk_speed,
> +                                  sr->vp.prm_vpx_vlimito_timeout)
> +           << sr->vp.prm_vpx_vlimito_shift;
> +       senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
> +                   sr->sr_n_mod_mask) >> sr->sr_n_mod_shift;
> +       senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
> +                   sr->sr_p_mod_mask) >> sr->sr_p_mod_shift;
> +       sr->sr_config_value =
> +           (clk_len << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_ERRGEN_EN |
> +           SRCONFIG_SENENABLE | (senn_mod << SRCONFIG_SENNENABLE_SHIFT) |
> +           (senp_mod << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL;
> +
> +       /* Set up nominal voltage */
> +       sr_vp_configure(sr);
> +}
> +
> +/**
> + * @brief omap_sr_init - SR initialization
> + *
> + * @return  0
> + */
> +static int __init omap_sr_init(void)
> +{
> +       int ret = 0;
> +       int i;
> +       ret = omap_pmic_srinit();
> +       if (ret) {
> +               pr_crit("PMIC init failed during SmartReflex initilization."
> +                       "connectivity issues?: %d\n", ret);
> +               return ret;
> +       }
> +       if (cpu_is_omap3430()) {
> +               omap_srlist = kzalloc(sizeof(omap34xx_srlist), GFP_KERNEL);
> +               if (!omap_srlist) {
> +                       ret = -ENOMEM;
> +                       goto fail_cleanup;
> +               }
> +               omap_srlist->num_sr = omap34xx_srlist.num_sr;
> +               for (i = 0; i < omap_srlist->num_sr; i++) {
> +                       int size = sizeof(*omap34xx_srlist.sr_list[i]);
> +                       size +=
> +                           sizeof(u32) * omap34xx_srlist.sr_list[i]->num_opp;
> +                       omap_srlist->sr_list[i] = kzalloc(size, GFP_KERNEL);
> +                       if (!omap_srlist->sr_list[i]) {
> +                               ret = -ENOMEM;
> +                               goto fail_cleanup;
> +                       }
> +                       memcpy(omap_srlist->sr_list[i],
> +                              omap34xx_srlist.sr_list[i], size);
> +               }
> +       } else {
> +               pr_warning("SmartReflex is not supported on this OMAP\n");
> +               return -ENODEV;
> +       }
> +
> +       /* Create the userspace control knobs */
> +       for (i = 0; i < omap_srlist->num_sr; i++) {
> +               struct omap_sr *sr = get_sr(i + 1);
> +               sr->fclk = clk_get(NULL, sr->fclk_name);
> +               sr->iclk = clk_get(NULL, sr->iclk_name);
> +               sr->srbase_addr = ioremap((u32) sr->srbase_addr, SZ_4K);
> +               srvp_init(sr);
> +               if (sysfs_create_file(power_kobj, &sr->autocom_attr.attr))
> +                       pr_warning("SR: sysfs_create_file failed[%d]: %d\n", i,
> +                                  ret);
> +       }
> +       if (sr_debugfs_create_entries_late())
> +               pr_warning("SR: debugfs_create_file failed\n");
> +
> +       pr_info("SmartReflex driver initialized\n");
> +       return 0;
> +fail_cleanup:
> +       pr_warning("Out of memory..SmartReflex not initialized\n");
> +       if (omap_srlist) {
> +               /* kfree is nullsafe */
> +               for (i = 0; i < omap_srlist->num_sr; i++)
> +                       kfree(omap_srlist->sr_list[i]);
> +               kfree(omap_srlist);
> +       }
> +       return ret;
> +}
> +late_initcall(omap_sr_init);
> diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
> new file mode 100644
> index 0000000..421f8b6
> --- /dev/null
> +++ b/arch/arm/mach-omap2/smartreflex.h
> @@ -0,0 +1,274 @@
> +#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
> +#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
> +/*
> + * linux/arch/arm/mach-omap2/smartreflex.h
> + *
> + * Copyright (C) 2009 Texas Instruments, Inc.
> + * Nishanth Menon
> + *
> + * Copyright (C) 2008 Nokia Corporation
> + * Kalle Jokiniemi
> + *
> + * Copyright (C) 2007 Texas Instruments, Inc.
> + * Lesly A M <x0080970@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.
> + */
> +
> +/* SMART REFLEX REG ADDRESS OFFSET */
> +#define SRCONFIG               0x00
> +#define SRSTATUS               0x04
> +#define SENVAL                 0x08
> +#define SENMIN                 0x0C
> +#define SENMAX                 0x10
> +#define SENAVG                 0x14
> +#define AVGWEIGHT              0x18
> +#define NVALUERECIPROCAL       0x1C
> +#define SENERROR               0x20
> +#define ERRCONFIG              0x24
> +
> +/* SR Modules */
> +#define SR1                    1
> +#define SR2                    2
> +
> +#define VP1_IRQMASK_TRANSDONE          (0x1 << 15)
> +#define VP2_IRQMASK_TRANSDONE          (0x1 << 21)
> +
> +/* PRM_VP1_CONFIG */
> +#define PRM_VP1_CONFIG_ERROROFFSET     (0x00 << 24)
> +#define PRM_VP1_CONFIG_ERRORGAIN       (0x18 << 16)
> +#define SR_ERRGAIN_LOWOP               (0x0C)
> +#define SR_ERRGAIN_HIGHOPP             (0x18)
> +#define SR_ERRMINLIMIT_LOWOPP           (0xF4 << 0)
> +#define SR_ERRMINLIMIT_HIGHOPP          (0xF9 << 0)
> +#define PRM_VP_STATUS_VPINIDLE         (0x1 << 0)
> +
> +#define PRM_VP1_CONFIG_INITVOLTAGE     (0x30 << 8)     /* 1.2 volt */
> +#define PRM_VP1_CONFIG_TIMEOUTEN       (0x1 << 3)
> +#define PRM_VP1_CONFIG_INITVDD         (0x1 << 2)
> +#define PRM_VP1_CONFIG_FORCEUPDATE     (0x1 << 1)
> +#define PRM_VP1_CONFIG_VPENABLE                (0x1 << 0)
> +
> +/* PRM_VP1_VSTEPMIN */
> +#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN       (0x03C << 8)
> +#define PRM_VP1_VSTEPMIN_VSTEPMIN              (0x01 << 0)
> +
> +/* PRM_VP1_VSTEPMAX */
> +#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX       (0x003C << 8)
> +#define PRM_VP1_VSTEPMAX_VSTEPMAX              (0x08 << 0)
> +
> +/* PRM_VP1_VLIMITTO */
> +#define PRM_VP1_VLIMITTO_VDDMAX                (0x44 << 24)
> +#define PRM_VP1_VLIMITTO_VDDMIN                (0x14 << 16)
> +#define PRM_VP1_VLIMITTO_TIMEOUT_US    (200)
> +#define PRM_VP1_VLIMITTO_TIMEOUT_SHIFT (0)
> +
> +/* PRM_VP2_CONFIG */
> +#define PRM_VP2_CONFIG_ERROROFFSET     (0x00 << 24)
> +#define PRM_VP2_CONFIG_ERRORGAIN       (0x18 << 16)
> +
> +#define PRM_VP2_CONFIG_INITVOLTAGE     (0x30 << 8)     /* 1.2 volt */
> +#define PRM_VP2_CONFIG_TIMEOUTEN       (0x1 << 3)
> +#define PRM_VP2_CONFIG_INITVDD         (0x1 << 2)
> +#define PRM_VP2_CONFIG_FORCEUPDATE     (0x1 << 1)
> +#define PRM_VP2_CONFIG_VPENABLE                (0x1 << 0)
> +
> +/* PRM_VP2_VSTEPMIN */
> +#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN       (0x03C << 8)
> +#define PRM_VP2_VSTEPMIN_VSTEPMIN              (0x01 << 0)
> +
> +/* PRM_VP2_VSTEPMAX */
> +#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX       (0x003C << 8)
> +#define PRM_VP2_VSTEPMAX_VSTEPMAX              (0x08 << 0)
> +
> +/* PRM_VP2_VLIMITTO */
> +#define PRM_VP2_VLIMITTO_VDDMAX                (0x42 << 24)
> +#define PRM_VP2_VLIMITTO_VDDMIN                (0x18 << 16)
> +#define PRM_VP2_VLIMITTO_TIMEOUT_US    (200)
> +#define PRM_VP2_VLIMITTO_TIMEOUT_SHIFT (0)
> +
> +/* SRCONFIG */
> +#define SRCLKLENGTH_12MHZ_SYSCLK       0x3C
> +#define SRCLKLENGTH_13MHZ_SYSCLK       0x41
> +#define SRCLKLENGTH_19MHZ_SYSCLK       0x60
> +#define SRCLKLENGTH_26MHZ_SYSCLK       0x82
> +#define SRCLKLENGTH_38MHZ_SYSCLK       0xC0
> +
> +#define SRCONFIG_SRCLKLENGTH_SHIFT     12
> +#define SRCONFIG_SENNENABLE_SHIFT      5
> +#define SRCONFIG_SENPENABLE_SHIFT      3
> +
> +#define SRCONFIG_SRENABLE              (0x01 << 11)
> +#define SRCONFIG_SENENABLE             (0x01 << 10)
> +#define SRCONFIG_ERRGEN_EN             (0x01 << 9)
> +#define SRCONFIG_MINMAXAVG_EN          (0x01 << 8)
> +
> +#define SRCONFIG_DELAYCTRL             (0x01 << 2)
> +#define SRCONFIG_CLKCTRL               (0x00 << 0)
> +
> +/* NVALUERECIPROCAL */
> +#define NVALUERECIPROCAL_SENPGAIN_SHIFT        20
> +#define NVALUERECIPROCAL_SENNGAIN_SHIFT        16
> +#define NVALUERECIPROCAL_RNSENP_SHIFT  8
> +#define NVALUERECIPROCAL_RNSENN_SHIFT  0
> +
> +/* ERRCONFIG */
> +#define SR_CLKACTIVITY_MASK            (0x03 << 20)
> +#define SR_ERRWEIGHT_MASK              (0x07 << 16)
> +#define SR_ERRMAXLIMIT_MASK            (0xFF << 8)
> +#define SR_ERRMINLIMIT_MASK            (0xFF << 0)
> +
> +#define SR_CLKACTIVITY_IOFF_FOFF       (0x00 << 20)
> +#define SR_CLKACTIVITY_IOFF_FON                (0x02 << 20)
> +
> +#define ERRCONFIG_VPBOUNDINTEN         (0x1 << 31)
> +#define ERRCONFIG_MCUDISACKINTEN       (0x1 << 23)
> +
> +/* Status Bits */
> +#define ERRCONFIG_VPBOUNDINTST         (0x1 << 30)
> +#define ERRCONFIG_MCUACCUMINTST                (0x1 << 28)
> +#define ERRCONFIG_MCUVALIDINTST                (0x1 << 26)
> +#define ERRCONFIG_MCUBOUNDINTST                (0x1 << 24)
> +#define ERRCONFIG_MCUDISACKINTST       (0x1 << 22)
> +
> +/* WARNING: Ensure all access to errconfig register skips
> + * clearing intst bits to ensure that we dont clear status
> + * bits unwantedly.. esp vpbound
> + */
> +#define ERRCONFIG_INTERRUPT_STATUS_MASK  (ERRCONFIG_VPBOUNDINTST |\
> +               ERRCONFIG_MCUACCUMINTST |\
> +               ERRCONFIG_MCUVALIDINTST |\
> +               ERRCONFIG_MCUBOUNDINTST |\
> +               ERRCONFIG_MCUDISACKINTST | (0X1<<19))
> +
> +#define SR1_ERRWEIGHT                  (0x04 << 16)
> +#define SR1_ERRMAXLIMIT                        (0x02 << 8)
> +#define SR1_ERRMINLIMIT                        (0xFA << 0)
> +
> +#define SR2_ERRWEIGHT                  (0x04 << 16)
> +#define SR2_ERRMAXLIMIT                        (0x02 << 8)
> +#define SR2_ERRMINLIMIT                        (0xFA << 0)
> +
> +/* T2 SMART REFLEX */
> +#define R_SRI2C_SLAVE_ADDR             0x12
> +#define R_VDD1_SR_CONTROL              0x00
> +#define R_VDD2_SR_CONTROL              0x01
> +
> +/* VDDs*/
> +#define PRCM_VDD1      1
> +#define PRCM_VDD2      2
> +

This comment below can be removed, provided that you apply my other
comments.

> +/*
> + * XXX: These should be removed/moved from here once we have a working DVFS
> + * implementation in place
> + */
> +#define PHY_TO_OFF_PM_MASTER(p)                (p - 0x36)

No need for PHY_TO_OFF_PM_MASTER definition. Remove that.


> +#define PHY_TO_OFF_PM_RECIEVER(p)      (p - 0x5b)
> +#define PHY_TO_OFF_PM_INT(p)           (p - 0x2e)

No need for PHY_TO_OFF_PM_INT def. Remove.

> +
> +/* Vmode control */
> +#define R_DCDC_GLOBAL_CFG              PHY_TO_OFF_PM_RECIEVER(0x61)
> +/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */
> +#define DCDC_GLOBAL_CFG_ENABLE_SRFLX   0x08


As we now have other ways of determining opp, remove code from here...

> +
> +/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */
> +#define OMAP_TYPE_SHIFT                28
> +#define OMAP_TYPE_MASK         0xF
> +/* OPP ID: bits: 0-4 for OPP number */
> +#define OPP_NO_POS             0
> +#define OPP_NO_MASK            0x1F
> +/* OPP ID: bits: 5-6 for VDD */
> +#define VDD_NO_POS             5
> +#define VDD_NO_MASK            0x3
> +/* Other IDs: bits 20-27 for ID type */
> +/* These IDs have bits 25,26,27 as 1 */
> +#define OTHER_ID_TYPE_SHIFT            20
> +#define OTHER_ID_TYPE_MASK             0xFF
> +
> +#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT)
> +#define ID_OPP_NO(X)    ((X & OPP_NO_MASK) << OPP_NO_POS)
> +#define ID_VDD(X)       ((X & VDD_NO_MASK) << VDD_NO_POS)
> +#define OMAP(X)                 ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK)
> +#define get_opp_no(X)   ((X >> OPP_NO_POS) & OPP_NO_MASK)
> +#define get_vdd(X)      ((X >> VDD_NO_POS) & VDD_NO_MASK)
> +
> +/* XXX: end remove/move */
> +
> +/* XXX: find more appropriate place for these once DVFS is in place */
> +extern u32 current_vdd1_opp;
> +extern u32 current_vdd2_opp;

...to here.

At least with a quick glance, it seems the above defs are not in use.
Your compiler should tell if I missed something ;)

- Kalle


> +
> +/*
> + * Smartreflex module enable/disable interface.
> + * NOTE: if smartreflex is not enabled from sysfs, these functions will not
> + * do anything.
> + */
> +#ifdef CONFIG_OMAP_SMARTREFLEX
> +void enable_smartreflex(u8 srid);
> +void disable_smartreflex(u8 srid);
> +int sr_voltage_set(u32 target_opp, u32 current_opp,
> +                  u8 target_vsel, u8 current_vsel);
> +int sr_vp_disable_both(u32 target_opp, u32 current_opp);
> +int sr_vp_enable_both(u32 target_opp, u32 current_opp);
> +int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 *timeout_us);
> +int omap_pmic_srinit(void);
> +u32 omap_pmic_voltage_ramp_delay(u8 srid, u8 target_vsel, u8 current_vsel);
> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
> +int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel);
> +#endif
> +
> +#ifdef CONFIG_PM_DEBUG
> +#define __SR_DEBUG
> +#endif
> +
> +#else
> +static inline void enable_smartreflex(u8 srid)
> +{
> +}
> +
> +static inline void disable_smartreflex(u8 srid)
> +{
> +}
> +
> +static inline int sr_voltage_set(u32 target_opp, u32 current_opp,
> +                                u8 target_vsel, u8 current_vsel)
> +{
> +       return -EINVAL;
> +}
> +
> +static inline int sr_vp_disable_both(u32 target_opp, u32 current_opp)
> +{
> +       return -EINVAL;
> +}
> +
> +static inline int sr_vp_enable_both(u32 target_opp, u32 current_opp)
> +{
> +       return -EINVAL;
> +}
> +
> +static inline int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data,
> +                                 u16 *timeout_us)
> +{
> +       return -EINVAL;
> +}
> +
> +#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
> +static inline int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel)
> +{
> +       return -EINVAL;
> +}
> +#endif
> +#endif
> +
> +#ifdef __SR_DEBUG
> +int sr_debugfs_create_entries(struct dentry *d);
> +#else
> +static inline int sr_debugfs_create_entries(struct dentry *d)
> +{
> +       return -EINVAL;
> +}
> +#endif
> +
> +#endif                         /* __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H */
> diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> index 2143db5..6a3302c 100644
> --- a/arch/arm/plat-omap/Kconfig
> +++ b/arch/arm/plat-omap/Kconfig
> @@ -81,19 +81,14 @@ config OMAP_SMARTREFLEX
>           compensation for VDD1 and VDD2, user must write 1 to
>           /sys/power/sr_vddX_autocomp, where X is 1 or 2.
> 
> -config OMAP_SMARTREFLEX_TESTING
> -       bool "Smartreflex testing support"
> +config OMAP_VC_BYPASS_UPDATE
> +       bool "Use VC Bypass method of updating voltage"
>         depends on OMAP_SMARTREFLEX
>         default n
>         help
> -         Say Y if you want to enable SmartReflex testing with SW hardcoded
> -         NVALUES intead of E-fuse NVALUES set in factory silicon testing.
> -
> -         In some devices the E-fuse values have not been set, even though
> -         SmartReflex modules are included. Using these hardcoded values set
> -         in software, one can test the SmartReflex features without E-fuse.
> -
> -         WARNING: Enabling this option may cause your device to hang!
> +         Say Y if you would like to use VC Bypass method of
> +         update. If this is disabled, the default
> +         VP forceupdate method is used.
> 
>  config OMAP_RESET_CLOCKS
>         bool "Reset unused clocks during boot"
> --
> 1.6.3.3
> 
> --
> 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

--
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