diff options
author | Venkata Biswanath <venkata.biswanath@stericsson.com> | 2011-12-15 15:21:27 +0530 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-05-22 10:59:26 +0200 |
commit | 3289f9e4414cfccaf0b42554c712c5d41eccfa34 (patch) | |
tree | 4a43f7092c37caee84761dea9a0edcd3d742de26 | |
parent | ba5d9986a256cee0d3061f21ac428e29b3251c20 (diff) |
ux500: usecase-gov:Set clk to low freq to save pwr
setting ACLK and DMACLK to 25 opp usecases like
voice call to save power. This was present in
u8500 but not implemented in u5500.
ST-Ericsson ID: 403936
ST-Ericsson Linux next: NA
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: Ib09d00c4610fa79baa3dcf08d018f5fca31c5625
Signed-off-by: Venkata Biswanath <venkata.biswanath@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42679
Reviewed-by: QATOOLS
Reviewed-by: QABUILD
Reviewed-by: Vijaya Kumar K-1 <vijay.kilari@stericsson.com>
Reviewed-by: Rabin VINCENT <rabin.vincent@stericsson.com>
-rw-r--r-- | drivers/mfd/db5500-prcmu.c | 60 |
1 files changed, 57 insertions, 3 deletions
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c index 76d8a3132ae..364a4432e38 100644 --- a/drivers/mfd/db5500-prcmu.c +++ b/drivers/mfd/db5500-prcmu.c @@ -1527,14 +1527,57 @@ static void prcmu_ape_clocks_scale(u8 opp) spin_unlock_irqrestore(&clk_mgt_lock, irqflags); } +/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */ +static void request_even_slower_clocks(bool enable) +{ + void __iomem *clock_reg[] = { + (_PRCMU_BASE + DB5500_PRCM_ACLK_MGT), + (_PRCMU_BASE + DB5500_PRCM_DMACLK_MGT) + }; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&clk_mgt_lock, flags); + + /* Grab the HW semaphore. */ + while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) + cpu_relax(); + + for (i = 0; i < ARRAY_SIZE(clock_reg); i++) { + u32 val; + u32 div; + val = readl(clock_reg[i]); + div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK); + if (enable) { + if ((div <= 1) || (div > 15)) { + pr_err("prcmu: Bad clock divider %d in %s\n", + div, __func__); + goto unlock_and_return; + } + div <<= 1; + } else { + if (div <= 2) + goto unlock_and_return; + div >>= 1; + } + val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) | + (div & PRCM_CLK_MGT_CLKPLLDIV_MASK)); + writel(val, clock_reg[i]); + } + +unlock_and_return: + /* Release the HW semaphore. */ + writel(0, _PRCMU_BASE + PRCM_SEM); + + spin_unlock_irqrestore(&clk_mgt_lock, flags); +} int db5500_prcmu_set_ape_opp(u8 opp) { int ret = 0; u8 db5500_opp; - - if (opp == db5500_prcmu_get_ape_opp()) - return ret; + if (opp == mb1_transfer.req_ape_opp) + return 0; if (cpu_is_u5500v1()) return -EINVAL; @@ -1544,6 +1587,7 @@ int db5500_prcmu_set_ape_opp(u8 opp) db5500_opp = DB5500_APE_100_OPP; break; case APE_50_OPP: + case APE_50_PARTLY_25_OPP: db5500_opp = DB5500_APE_50_OPP; break; default: @@ -1554,6 +1598,10 @@ int db5500_prcmu_set_ape_opp(u8 opp) } mutex_lock(&mb1_transfer.lock); + if (mb1_transfer.req_ape_opp == APE_50_PARTLY_25_OPP) + request_even_slower_clocks(false); + if ((opp != APE_100_OPP) && (mb1_transfer.req_ape_opp != APE_100_OPP)) + goto skip_message; prcmu_ape_clocks_scale(db5500_opp); @@ -1576,6 +1624,12 @@ int db5500_prcmu_set_ape_opp(u8 opp) (mb1_transfer.ack.arm_voltage_st != RC_SUCCESS)) ret = -EIO; +skip_message: + if ((!ret && (opp == APE_50_PARTLY_25_OPP)) || + (ret && (mb1_transfer.req_ape_opp == APE_50_PARTLY_25_OPP))) + request_even_slower_clocks(true); + if (!ret) + mb1_transfer.req_ape_opp = opp; unlock_and_return: mutex_unlock(&mb1_transfer.lock); bailout: |