diff mbox

[PATCHv7,13/21] ARM: OMAP3: vc: auto_ret / auto_off support

Message ID 1348590833-12335-14-git-send-email-t-kristo@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tero Kristo Sept. 25, 2012, 4:33 p.m. UTC
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 <t-kristo@ti.com>
---
 arch/arm/mach-omap2/vc.c |  139 +++++++++++++++++++++++++++++++++++++++------
 1 files changed, 120 insertions(+), 19 deletions(-)
diff mbox

Patch

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