[LG Optimus Black] Huexxx:
Part 2/2:

> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > +/**
> > + * do_recalibrate() - work which actually does the calibration
> > + * @work: pointer to the work
> > + *
> > + * on a periodic basis, we come and reset our calibration setup
> > + * so that a recalibration of the OPPs take place. This takes
> > + * care of aging factor in the system.
> > + */
> > +static void do_recalibrate(struct work_struct *work)
> > +{
> > + struct voltagedomain *voltdm;
> > + int idx;
> > + static struct sr_class1p5_work_data *work_data;
> > +
> > + for (idx = 0; idx < MAX_VDDS; idx++) {
> > + work_data = &class_1p5_data.work_data[idx];
> > + voltdm = work_data->voltdm;
> > + if (voltdm) {
> > + /* if sr is not enabled, we check later */
> > + if (!is_sr_enabled(voltdm))
> > + continue;
> > + /* TODO: Pause the dvfs transitions */
> > + /* if sr is not enabled, we check later */
> > +
> > + /* Reset and force a recalibration for current opp */
> > + sr_class1p5_reset_calib(voltdm, true, true);
> > +
> > + /* TODO: unpause DVFS transitions */
> > + }
> > + }
> > + /* We come back again after time the usual delay */
> > + schedule_delayed_work(&recal_work,
> > + msecs_to_jiffies(CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +}
> > +#endif /* CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY */
> > +
> > +/**
> > + * sr_class1p5_enable() - class 1.5 mode of enable
> > + * @voltdm: voltage domain to enable SR for
> > + * @volt_data: voltdata to the voltage transition taking place
> > + *
> > + * when this gets called, we use the h/w loop to setup our voltages
> > + * to an calibrated voltage, detect any oscillations, recover from the same
> > + * and finally store the optimized voltage as the calibrated voltage in the
> > + * system
> > + */
> > +static int sr_class1p5_enable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data)
> > +{
> > + int r;
> > + struct sr_class1p5_work_data *work_data;
> > + /* if already calibrated, nothing to do here.. */
> > + if (volt_data->volt_calibrated)
> > + return 0;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > + if (unlikely(!work_data)) {
> > + pr_err("%s: aieeee.. bad work data??\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + if (work_data->work_active)
> > + return 0;
> > +
> > + omap_vp_enable(voltdm);
> > + r = sr_enable(voltdm, volt_data);
> > + if (r) {
> > + pr_err("%s: sr[%s] failed\n", __func__, voltdm->name);
> > + omap_vp_disable(voltdm);
> > + return r;
> > + }
> > + work_data->vdata = volt_data;
> > + work_data->work_active = true;
> > + work_data->num_calib_triggers = 0;
> > + /* program the workqueue and leave it to calibrate offline.. */
> > + schedule_delayed_work(&work_data->work,
> > + msecs_to_jiffies(SR1P5_SAMPLING_DELAY_MS *
> > + SR1P5_STABLE_SAMPLES));
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_disable() - disable for class 1p5
> > + * @voltdm: voltage domain for the sr which needs disabling
> > + * @volt_data: voltagedata to disable
> > + * @is_volt_reset: reset the voltage?
> > + *
> > + * we dont do anything if the class 1p5 is being used. this is because we
> > + * already disable sr at the end of calibration and no h/w loop is actually
> > + * active when this is called.
> > + */
> > +static int sr_class1p5_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data,
> > + int is_volt_reset)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > + if (work_data->work_active) {
> > + /* if volt reset and work is active, we dont allow this */
> > + if (is_volt_reset)
> > + return -EBUSY;
> > + /* flag work is dead and remove the old work */
> > + work_data->work_active = false;
> > + cancel_delayed_work_sync(&work_data->work);
> > + sr_notifier_control(voltdm, false);
> > + omap_vp_disable(voltdm);
> > + sr_disable(voltdm);
> > + }
> > +
> > + /* if already calibrated, nothin special to do here.. */
> > + if (volt_data->volt_calibrated)
> > + return 0;
> > +
> > + if (is_volt_reset)
> > + omap_voltage_reset(voltdm);
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_configure() - configuration function
> > + * @voldm: configure for which voltage domain
> > + *
> > + * we dont do much here other than setup some registers for
> > + * the sr module involved.
> > + */
> > +static int sr_class1p5_configure(struct voltagedomain *voltdm)
> > +{
> > + return sr_configure_errgen(voltdm);
> > +}
> > +
> > +/**
> > + * sr_class1p5_reset_calib() - reset all calibrated voltages
> > + * @srid: srid to reset the calibration for
> > + * @reset: reset voltage before we recal?
> > + * @recal: should I recalibrate my current opp?
> > + *
> > + * if we call this, it means either periodic calibration trigger was
> > + * fired(either from sysfs or other mechanisms) or we have disabled class 1p5,
> > + * meaning we cant trust the calib voltages anymore, it is better to use
> > + * nominal in the system
> > + */
> > +static void sr_class1p5_reset_calib(struct voltagedomain *voltdm, bool reset,
> > + bool recal)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + /* I dont need to go further if sr is not present */
> > + if (!is_sr_enabled(voltdm))
> > + return;
> > +
> > + work_data = get_sr1p5_work(voltdm);
> > +
> > + if (work_data->work_active)
> > + sr_class1p5_disable(voltdm, work_data->vdata, 0);
> > +
> > + omap_voltage_calib_reset(voltdm);
> > +
> > + /*
> > + * I should now reset the voltages to my nominal to be safe
> > + */
> > + if (reset)
> > + omap_voltage_reset(voltdm);
> > +
> > + /*
> > + * I should fire a recalibration for current opp if needed
> > + * Note: i have just reset my calibrated voltages, and if
> > + * i call sr_enable equivalent, I will cause a recalibration
> > + * loop, even though the function is called sr_enable.. we
> > + * are in class 1.5 ;)
> > + */
> > + if (reset && recal)
> > + sr_class1p5_enable(voltdm, work_data->vdata);
> > +}
> > +
> > +/**
> > + * sr_class1p5_cinit() - class 1p5 init
> > + * @voltdm: sr voltage domain
> > + * @class_priv_data: private data for the class
> > + *
> > + * we do class specific initialization like creating sysfs/debugfs entries
> > + * needed, spawning of a kthread if needed etc.
> > + */
> > +static int sr_class1p5_cinit(struct voltagedomain *voltdm,
> > + void *class_priv_data)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > + int idx;
> > +
> > + if (!class_priv_data) {
> > + pr_err("%s: bad param? no priv data!\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* setup our work params */
> > + work_data = get_sr1p5_work(voltdm);
> > + if (!IS_ERR_OR_NULL(work_data)) {
> > + pr_err("%s: ooopps.. class already initialized for %s! bug??\n",
> > + __func__, voltdm->name);
> > + return -EINVAL;
> > + }
> > + work_data = NULL;
> > + /* get the next spare work_data */
> > + for (idx = 0; idx < MAX_VDDS; idx++) {
> > + if (!class_1p5_data.work_data[idx].voltdm) {
> > + work_data = &class_1p5_data.work_data[idx];
> > + break;
> > + }
> > + }
> > + if (!work_data) {
> > + pr_err("%s: no more space for work data for domains!\n",
> > + __func__);
> > + return -ENOMEM;
> > + }
> > + work_data->voltdm = voltdm;
> > + INIT_DELAYED_WORK_DEFERRABLE(&work_data->work, do_calibrate);
> > + return 0;
> > +}
> > +
> > +/**
> > + * sr_class1p5_cdeinit() - class 1p5 deinitialization
> > + * @voltdm: voltage domain for which to do this.
> > + * @class_priv_data: class private data for deinitialiation
> > + *
> > + * currently only resets the calibrated voltage forcing dvfs voltages
> > + * to be used in the system
> > + */
> > +static int sr_class1p5_cdeinit(struct voltagedomain *voltdm,
> > + void *class_priv_data)
> > +{
> > + struct sr_class1p5_work_data *work_data;
> > +
> > + /* setup our work params */
> > + work_data = get_sr1p5_work(voltdm);
> > + if (IS_ERR_OR_NULL(work_data)) {
> > + pr_err("%s: ooopps.. class not initialized for %s! bug??\n",
> > + __func__, voltdm->name);
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * we dont have SR periodic calib anymore.. so reset calibs
> > + * we are already protected by sr debugfs lock, so no lock needed
> > + * here.
> > + */
> > + sr_class1p5_reset_calib(voltdm, true, false);
> > +
> > + /* reset all data for this work data */
> > + memset(work_data, 0, sizeof(*work_data));
> > +
> > + return 0;
> > +}
> > +
> > +/* SR class1p5 structure */
> > +static struct omap_sr_class_data class1p5_data = {
> > + .enable = sr_class1p5_enable,
> > + .disable = sr_class1p5_disable,
> > + .configure = sr_class1p5_configure,
> > + .class_type = SR_CLASS1P5,
> > + .class_init = sr_class1p5_cinit,
> > + .class_deinit = sr_class1p5_cdeinit,
> > + .notify = sr_class1p5_notify,
> > + /*
> > + * trigger for bound - this tells VP that SR has a voltage
> > + * change. we should ensure transdone is set before reading
> > + * vp voltage.
> > + */
> > + .notify_flags = SR_NOTIFY_MCUBOUND,
> > + .class_priv_data = (void *)&class_1p5_data,
> > +};
> > +
> > +/**
> > + * sr_class1p5_init() - register class 1p5 as default
> > + *
> > + * board files call this function to use class 1p5, we register with the
> > + * smartreflex subsystem
> > + */
> > +static int __init sr_class1p5_init(void)
> > +{
> > + int r;
> > +
> > + /* Enable this class only for OMAP3630 and OMAP4 */
> > + if (!(cpu_is_omap3630() || cpu_is_omap44xx()))
> > + return -EINVAL;
> > +
> > + r = sr_register_class(&class1p5_data);
> > + if (r) {
> > + pr_err("SmartReflex class 1.5 driver: "
> > + "failed to register with %d\n", r);
> > + } else {
> > +#if CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > + INIT_DELAYED_WORK_DEFERRABLE(&recal_work, do_recalibrate);
> > + schedule_delayed_work(&recal_work, msecs_to_jiffies(
> > + CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY));
> > +#endif
> > + pr_info("SmartReflex class 1.5 driver: initialized (%dms)\n",
> > + CONFIG_OMAP_SR_CLASS1P5_RECALIBRATION_DELAY);
> > + }
> > + return r;
> > +}
> > +late_initcall(sr_class1p5_init);
> > diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
> > index 7ac88da..5f7a33e 100644
> > --- a/arch/arm/mach-omap2/smartreflex-class3.c
> > +++ b/arch/arm/mach-omap2/smartreflex-class3.c
> > @@ -21,7 +21,9 @@ static int sr_class3_enable(struct voltagedomain *voltdm,
> > return sr_enable(voltdm, volt_data);
> > }
> >
> > -static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
> > +static int sr_class3_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *vdata,
> > + int is_volt_reset)
> > {
> > omap_vp_disable(voltdm);
> > sr_disable(voltdm);
> > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
> > index 3a5f2f6..bb55b65 100644
> > --- a/arch/arm/mach-omap2/smartreflex.c
> > +++ b/arch/arm/mach-omap2/smartreflex.c
> > @@ -317,7 +317,9 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
> > }
> >
> > if (sr->autocomp_active) {
> > - sr_class->disable(sr->voltdm, 1);
> > + sr_class->disable(sr->voltdm,
> > + omap_voltage_get_nom_volt(sr->voltdm),
> > + 1);
> > if (sr_class->class_deinit &&
> > sr_class->class_deinit(sr->voltdm,
> > sr_class->class_priv_data)) {
> > @@ -471,6 +473,28 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
> > /* Public Functions */
> >
> > /**
> > + * is_sr_enabled() - is Smart reflex enabled for this domain?
> > + * @voltdm: voltage domain to check
> > + *
> > + * Returns 0 if SR is enabled for this domain, else returns err
> > + */
> > +bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > + struct omap_sr *sr;
> > + if (IS_ERR_OR_NULL(voltdm)) {
> > + pr_warning("%s: invalid param voltdm\n", __func__);
> > + return false;
> > + }
> > + sr = _sr_lookup(voltdm);
> > + if (IS_ERR(sr)) {
> > + pr_warning("%s: omap_sr struct for sr_%s not found\n",
> > + __func__, voltdm->name);
> > + return false;
> > + }
> > + return sr->autocomp_active;
> > +}
> > +
> > +/**
> > * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
> > * error generator module.
> > * @voltdm: VDD pointer to which the SR module to be configured belongs to.
> > @@ -839,6 +863,7 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> > * omap_sr_disable() - API to disable SR without resetting the voltage
> > * processor voltage
> > * @voltdm: VDD pointer to which the SR module to be configured belongs to.
> > + * @volt_data: Voltage data to go to
> > *
> > * This API is to be called from the kernel in order to disable
> > * a particular smartreflex module. This API will in turn call
> > @@ -846,7 +871,8 @@ void omap_sr_enable(struct voltagedomain *voltdm,
> > * the smartreflex class disable not to reset the VP voltage after
> > * disabling smartreflex.
> > */
> > -void omap_sr_disable(struct voltagedomain *voltdm)
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *vdata)
> > {
> > struct omap_sr *sr = _sr_lookup(voltdm);
> >
> > @@ -865,7 +891,7 @@ void omap_sr_disable(struct voltagedomain *voltdm)
> > return;
> > }
> >
> > - sr_class->disable(voltdm, 0);
> > + sr_class->disable(voltdm, vdata, 0);
> > }
> >
> > /**
> > @@ -898,7 +924,7 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm)
> > return;
> > }
> >
> > - sr_class->disable(voltdm, 1);
> > + sr_class->disable(voltdm, omap_voltage_get_nom_volt(voltdm), 1);
> > }
> >
> > /**
> > diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
> > index 77cb0cd..c451835 100644
> > --- a/arch/arm/mach-omap2/voltage.c
> > +++ b/arch/arm/mach-omap2/voltage.c
> > @@ -374,9 +374,45 @@ static int nom_volt_debug_get(void *data, u64 *val)
> > return 0;
> > }
> >
> > +static int dyn_volt_debug_get(void *data, u64 *val)
> > +{
> > + struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (!vdd) {
> > + pr_warning("Wrong paramater passed\n");
> > + return -EINVAL;
> > + }
> > + volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > + *val = volt_data->volt_dynamic_nominal;
> > +
> > + return 0;
> > +}
> > +
> > +static int calib_volt_debug_get(void *data, u64 *val)
> > +{
> > + struct omap_vdd_info *vdd = (struct omap_vdd_info *) data;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (!vdd) {
> > + pr_warning("Wrong paramater passed\n");
> > + return -EINVAL;
> > + }
> > + volt_data = omap_voltage_get_nom_volt(&vdd->voltdm);
> > +
> > + *val = volt_data->volt_calibrated;
> > +
> > + return 0;
> > +}
> > +
> > DEFINE_SIMPLE_ATTRIBUTE(vp_volt_debug_fops, vp_volt_debug_get, NULL, "%llu\n");
> > DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
> > "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(dyn_volt_debug_fops, dyn_volt_debug_get, NULL,
> > + "%llu\n");
> > +DEFINE_SIMPLE_ATTRIBUTE(calib_volt_debug_fops, calib_volt_debug_get, NULL,
> > + "%llu\n");
> > static void vp_latch_vsel(struct omap_vdd_info *vdd)
> > {
> > u32 vpconfig;
> > @@ -504,6 +540,12 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
> > (void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
> > vdd->debug_dir, (void *) vdd,
> > &nom_volt_debug_fops);
> > + (void) debugfs_create_file("curr_dyn_nominal_volt", S_IRUGO,
> > + vdd->debug_dir, (void *) vdd,
> > + &dyn_volt_debug_fops);
> > + (void) debugfs_create_file("curr_calibrated_volt", S_IRUGO,
> > + vdd->debug_dir, (void *) vdd,
> > + &calib_volt_debug_fops);
> > }
> >
> > /* Voltage scale and accessory APIs */
> > @@ -1132,6 +1174,33 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
> > }
> >
> > /**
> > + * omap_voltage_calib_reset() - reset the calibrated voltage entries
> > + * @voltdm: voltage domain to reset the entries for
> > + *
> > + * when the calibrated entries are no longer valid, this api allows
> > + * the calibrated voltages to be reset.
> > + */
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm)
> > +{
> > + struct omap_vdd_info *vdd;
> > + struct omap_volt_data *volt_data;
> > +
> > + if (IS_ERR_OR_NULL(voltdm)) {
> > + pr_warning("%s: VDD specified does not exist!\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
> > + volt_data = vdd->volt_data;
> > + /* reset the calibrated voltages as 0 */
> > + while (volt_data->volt_nominal) {
> > + volt_data->volt_calibrated = 0;
> > + volt_data++;
> > + }
> > + return 0;
> > +}
> > +
> > +/**
> > * omap_vp_get_curr_volt() - API to get the current vp voltage.
> > * @voltdm: pointer to the VDD.
> > *
> > diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
> > index b6333ae..dba7939 100644
> > --- a/arch/arm/plat-omap/Kconfig
> > +++ b/arch/arm/plat-omap/Kconfig
> > @@ -67,6 +67,23 @@ config OMAP_SMARTREFLEX_CLASS3
> > Class 3 implementation of Smartreflex employs continuous hardware
> > voltage calibration.
> >
> > +config OMAP_SMARTREFLEX_CLASS1P5
> > + bool "Class 1.5 mode of Smartreflex Implementation"
> > + depends on OMAP_SMARTREFLEX && TWL4030_CORE
> > + help
> > + Say Y to enable Class 1.5 implementation of Smartreflex
> > + Class 1.5 implementation of Smartreflex employs software controlled
> > + hardware voltage calibration.
> > +
> > +config OMAP_SR_CLASS1P5_RECALIBRATION_DELAY
> > + int "Class 1.5 mode recalibration recalibration delay(ms)"
> > + depends on OMAP_SMARTREFLEX_CLASS1P5
> > + default 86400000
> > + help
> > + Setup the recalibration delay in milliseconds. Use 0 for never doing
> > + a recalibration. Defaults to recommended recalibration every 24hrs.
> > + If you do not understand this, use the default.
> > +
> > config OMAP_RESET_CLOCKS
> > bool "Reset unused clocks during boot"
> > depends on ARCH_OMAP
> > diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
> > index 07f35b2..ee5c58f 100644
> > --- a/arch/arm/plat-omap/include/plat/smartreflex.h
> > +++ b/arch/arm/plat-omap/include/plat/smartreflex.h
> > @@ -167,6 +167,7 @@ struct omap_sr_pmic_data {
> > #define SR_CLASS1 0x1
> > #define SR_CLASS2 0x2
> > #define SR_CLASS3 0x3
> > +#define SR_CLASS1P5 0x4
> >
> > /**
> > * struct omap_sr_class_data - Smartreflex class driver info
> > @@ -187,7 +188,9 @@ struct omap_sr_pmic_data {
> > struct omap_sr_class_data {
> > int (*enable)(struct voltagedomain *voltdm,
> > struct omap_volt_data *volt_data);
> > - int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
> > + int (*disable)(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data,
> > + int is_volt_reset);
> > int (*class_init)(struct voltagedomain *voltdm, void *class_priv_data);
> > int (*class_deinit)(struct voltagedomain *voltdm,
> > void *class_priv_data);
> > @@ -235,7 +238,8 @@ struct omap_sr_data {
> > /* Smartreflex module enable/disable interface */
> > void omap_sr_enable(struct voltagedomain *voltdm,
> > struct omap_volt_data *volt_data);
> > -void omap_sr_disable(struct voltagedomain *voltdm);
> > +void omap_sr_disable(struct voltagedomain *voltdm,
> > + struct omap_volt_data *volt_data);
> > void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
> >
> > /* API to register the pmic specific data with the smartreflex driver. */
> > @@ -250,6 +254,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm);
> >
> > /* API to register the smartreflex class driver with the smartreflex driver */
> > int sr_register_class(struct omap_sr_class_data *class_data);
> > +bool is_sr_enabled(struct voltagedomain *voltdm);
> > #else
> > static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
> > static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
> > @@ -264,5 +269,9 @@ static inline void omap_sr_disable_reset_volt(
> > struct voltagedomain *voltdm) {}
> > static inline void omap_sr_register_pmic(
> > struct omap_sr_pmic_data *pmic_data) {}
> > +static inline bool is_sr_enabled(struct voltagedomain *voltdm)
> > +{
> > + return false;
> > +}
> > #endif
> > #endif
> > diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
> > index 332c581..54445f0 100644
> > --- a/arch/arm/plat-omap/include/plat/voltage.h
> > +++ b/arch/arm/plat-omap/include/plat/voltage.h
> > @@ -58,6 +58,8 @@
> > #define OMAP4430_VDD_CORE_OPP50_UV 930000
> > #define OMAP4430_VDD_CORE_OPP100_UV 1100000
> >
> > +#define OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV 50000
> > +
> > /**
> > * struct voltagedomain - omap voltage domain global structure.
> > * @name: Name of the voltage domain which can be used as a unique
> > @@ -81,6 +83,8 @@ struct voltagedomain {
> > */
> > struct omap_volt_data {
> > u32 volt_nominal;
> > + u32 volt_calibrated;
> > + u32 volt_dynamic_nominal;
> > u32 sr_efuse_offs;
> > u8 sr_errminlimit;
> > u8 vp_errgain;
> > @@ -127,6 +131,7 @@ struct omap_volt_data *omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
> > bool omap_vp_is_transdone(struct voltagedomain *voltdm);
> > bool omap_vp_clear_transdone(struct voltagedomain *voltdm);
> > struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
> > +int omap_voltage_calib_reset(struct voltagedomain *voltdm);
> > #ifdef CONFIG_PM
> > int omap_voltage_register_pmic(struct voltagedomain *voltdm,
> > struct omap_volt_pmic_info *pmic_info);
> > @@ -160,7 +165,23 @@ static inline unsigned long omap_get_operation_voltage(
> > {
> > if (IS_ERR_OR_NULL(vdata))
> > return 0;
> > - return vdata->volt_nominal;
> > + return (vdata->volt_calibrated) ? vdata->volt_calibrated :
> > + (vdata->volt_dynamic_nominal) ? vdata->volt_dynamic_nominal :
> > + vdata->volt_nominal;
> > }
> >
> > +/* what is my dynamic nominal? */
> > +static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
> > +{
> > + if (IS_ERR_OR_NULL(vdata))
> > + return 0;
> > + if (vdata->volt_calibrated) {
> > + unsigned long v = vdata->volt_calibrated +
> > + OMAP3PLUS_DYNAMIC_NOMINAL_MARGIN_UV;
> > + if (v > vdata->volt_nominal)
> > + return vdata->volt_nominal;
> > + return v;
> > + }
> > + return vdata->volt_nominal;
> > +}
> > #endif
> > --
> > 1.7.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> > the body of a message to majordomo <at> vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> I have tested this Patch Series on OMAP 3630 SDP, for MPU and IVA Powerdomains
Could you clarify on null pointer issue: on SDP3630? or OMAP4SDP? I
see there is a risk with OMAP4 where there is a bug in the following
scenario:
bootloader setups the OPP frequency for an OPP(e.g. 1GHz) which is
disabled by default on OPP table in kernel. this needs to be cleanly
fixed in pm.c, at the same time, the exposed functions in class1p5
needs parameter validation as well.

> it throws error log "Unable to refer to NULL pointer" if
> curr_nominal_volt, curr_calibrated_volt
> or curr_dynamical_volt is accessed through debugfs.
> Could you please provide fix for this.

Regards,
Nishanth Menon