Voltage code will now enable / disable auto_ret / auto_off dynamically
according to the voltagedomain usecounts. This is accomplished via
the usage of the voltdm callback functions for sleep / wakeup.

Signed-off-by: Tero Kristo <[email protected]>
---
 arch/arm/mach-omap2/vc.c |  139 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 120 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index a587506..2ca00bc 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/bug.h>
 #include <linux/io.h>
+#include <linux/string.h>
 
 #include <asm/div64.h>
 
@@ -240,12 +241,6 @@ static void omap3_set_i2c_timings(struct voltagedomain 
*voltdm, bool off_mode)
        unsigned long voltsetup1;
        u32 tgt_volt;
 
-       /*
-        * Oscillator is shut down only if we are using sys_off_mode pad,
-        * thus we set a minimal setup time here
-        */
-       omap3_set_clksetup(1, voltdm);
-
        if (off_mode)
                tgt_volt = voltdm->vc_param->off;
        else
@@ -259,12 +254,6 @@ static void omap3_set_i2c_timings(struct voltagedomain 
*voltdm, bool off_mode)
        voltdm->rmw(voltdm->vfsm->voltsetup_mask,
                voltsetup1 << __ffs(voltdm->vfsm->voltsetup_mask),
                voltdm->vfsm->voltsetup_reg);
-
-       /*
-        * pmic is not controlling the voltage scaling during retention,
-        * thus set voltsetup2 to 0
-        */
-       voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET);
 }
 
 /**
@@ -286,7 +275,6 @@ static void omap3_set_off_timings(struct voltagedomain 
*voltdm)
        unsigned long voltsetup2;
        unsigned long voltsetup2_old;
        u32 val;
-       u32 tstart, tshut;
 
        /* check if sys_off_mode is used to control off-mode voltages */
        val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
@@ -296,9 +284,6 @@ static void omap3_set_off_timings(struct voltagedomain 
*voltdm)
                return;
        }
 
-       omap_pm_get_oscillator(&tstart, &tshut);
-       omap3_set_clksetup(tstart, voltdm);
-
        clksetup = voltdm->read(OMAP3_PRM_CLKSETUP_OFFSET);
 
        /* voltsetup 2 in us */
@@ -328,17 +313,133 @@ static void omap3_set_off_timings(struct voltagedomain 
*voltdm)
         */
        voltdm->rmw(voltdm->vfsm->voltsetup_mask, 0,
                voltdm->vfsm->voltsetup_reg);
+}
+
+/**
+ * omap3_set_core_ret_timings - set retention timings for core domain
+ * @voltdm: pointer for core voltagedomain struct
+ *
+ * This function is called once core domain is ready to enter
+ * retention. This sets the values for the global setup variables like
+ * oscillator setup time, and the ramp times for voltages.
+ */
+static void omap3_set_core_ret_timings(struct voltagedomain *voltdm)
+{
+       /*
+        * Oscillator is not shut down in retention, thus set minimal
+        * clock setup time
+        */
+       omap3_set_clksetup(1, voltdm);
 
-       /* voltoffset must be clksetup minus voltsetup2 according to TRM */
-       voltdm->write(clksetup - voltsetup2, OMAP3_PRM_VOLTOFFSET_OFFSET);
+       /*
+        * Reset voltsetup 2 and voltoffset when entering retention
+        * as they are only used when pmic is controlling voltages
+        */
+       voltdm->write(0, OMAP3_PRM_VOLTSETUP2_OFFSET);
+       voltdm->write(0, OMAP3_PRM_VOLTOFFSET_OFFSET);
+       omap3_set_i2c_timings(voltdm, false);
 }
 
-static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
+/**
+ * omap3_set_core_off_timings - set off timings for core domain
+ * @voltdm: pointer for core voltagedomain struct
+ *
+ * This function is called once core domain is ready to enter off-mode.
+ * This sets the values for the global setup variables like oscillator
+ * setup time, and the ramp times for voltages.
+ */
+static void omap3_set_core_off_timings(struct voltagedomain *voltdm)
 {
+       u32 tstart, tshut;
+
+       omap_pm_get_oscillator(&tstart, &tshut);
+       omap3_set_clksetup(tstart, voltdm);
        omap3_set_off_timings(voltdm);
 }
 
 /**
+ * omap3_vc_channel_sleep - idle callback for a voltagedomain
+ * @voltdm: voltage channel that is entering idle
+ *
+ * Prepares voltage channel for entering idle. This gets called from
+ * the voltagedomain code once the usecount for the domain reaches zero.
+ * Function checks the target sleep mode and configures the channel
+ * accordingly.
+ */
+static void omap3_vc_channel_sleep(struct voltagedomain *voltdm)
+{
+       /* Set off timings if entering off */
+       if (voltdm->target_state == PWRDM_POWER_OFF)
+               omap3_set_off_timings(voltdm);
+       else
+               omap3_set_i2c_timings(voltdm, false);
+}
+
+/**
+ * omap3_vc_core_sleep - idle callback for core voltagedomain
+ * @voltdm: pointer to core voltagedomain struct
+ *
+ * Prepares core voltagedomain for idle. This checks the target sleep
+ * mode of the device (highest sleep mode of all powerdomains), and
+ * sets up the device according to this either for retention, sleep
+ * or off-mode.
+ */
+static void omap3_vc_core_sleep(struct voltagedomain *voltdm)
+{
+       u8 mode;
+
+       switch (voltdm->target_state) {
+       case PWRDM_POWER_OFF:
+               mode = OMAP3430_AUTO_OFF_MASK;
+               break;
+       case PWRDM_POWER_RET:
+               mode = OMAP3430_AUTO_RET_MASK;
+               break;
+       default:
+               mode = OMAP3430_AUTO_SLEEP_MASK;
+               break;
+       }
+
+       if (mode == OMAP3430_AUTO_OFF_MASK)
+               omap3_set_core_off_timings(voltdm);
+       else
+               omap3_set_core_ret_timings(voltdm);
+
+       voltdm->rmw(OMAP3430_AUTO_OFF_MASK | OMAP3430_AUTO_RET_MASK |
+                   OMAP3430_AUTO_SLEEP_MASK, mode,
+                   OMAP3_PRM_VOLTCTRL_OFFSET);
+}
+
+/**
+ * omap3_vc_core_wakeup - wakeup callback for core domain
+ * @voltdm: pointer to core voltagedomain struct
+ *
+ * Resumes core voltagedomain from idle. Callback from voltagedomain
+ * code once usecount reaches non-zero value.
+ */
+static void omap3_vc_core_wakeup(struct voltagedomain *voltdm)
+{
+       voltdm->rmw(OMAP3430_AUTO_OFF_MASK | OMAP3430_AUTO_RET_MASK |
+                   OMAP3430_AUTO_SLEEP_MASK, 0, OMAP3_PRM_VOLTCTRL_OFFSET);
+}
+
+static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
+{
+       /*
+        * Set up voltagedomain callbacks for idle / resume and init
+        * channel for retention voltage levels.
+        */
+       if (!strcmp(voltdm->name, "core")) {
+               voltdm->sleep = omap3_vc_core_sleep;
+               voltdm->wakeup = omap3_vc_core_wakeup;
+               omap3_set_core_ret_timings(voltdm);
+       } else {
+               voltdm->sleep = omap3_vc_channel_sleep;
+               omap3_set_i2c_timings(voltdm, false);
+       }
+}
+
+/**
  * omap4_calc_volt_ramp - calculates voltage ramping delays on omap4
  * @voltdm: channel to calculate values for
  * @voltage_diff: voltage difference in microvolts
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to