From patchwork Tue Sep 25 16:33:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 1506151 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id C28D540079 for ; Tue, 25 Sep 2012 16:42:09 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TGYAM-00034h-UY; Tue, 25 Sep 2012 16:39:23 +0000 Received: from comal.ext.ti.com ([198.47.26.152]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TGY5X-0000VY-Uf for linux-arm-kernel@lists.infradead.org; Tue, 25 Sep 2012 16:34:26 +0000 Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id q8PGYN2m023930; Tue, 25 Sep 2012 11:34:23 -0500 Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8PGYNjK001127; Tue, 25 Sep 2012 11:34:23 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by dfle73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.1.323.3; Tue, 25 Sep 2012 11:34:23 -0500 Received: from localhost.localdomain (h64-6.vpn.ti.com [172.24.64.6]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8PGY1Bp005410; Tue, 25 Sep 2012 11:34:21 -0500 From: Tero Kristo To: , , Subject: [PATCHv7 13/21] ARM: OMAP3: vc: auto_ret / auto_off support Date: Tue, 25 Sep 2012 19:33:45 +0300 Message-ID: <1348590833-12335-14-git-send-email-t-kristo@ti.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1348590833-12335-1-git-send-email-t-kristo@ti.com> References: <1348590833-12335-1-git-send-email-t-kristo@ti.com> MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -7.7 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [198.47.26.152 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.8 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 --- 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 #include #include +#include #include @@ -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