diff options
author | Mattias Nilsson <mattias.i.nilsson@stericsson.com> | 2011-09-12 11:49:13 +0200 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-09-29 09:07:24 +0200 |
commit | 9e7cead4b8c0c3e182c90653565c292a73b7dea1 (patch) | |
tree | 4fe9616ba307d2a60040673190d7f15d14139500 /drivers | |
parent | 69aea9a09b41410c04564a23d59da09267192da3 (diff) |
u8500: change clk_get_rate for prcmu clocks
This patch changes the implementation of clk_get_rate for
PRCMU clocks, so that it returns a rate according to the
hardware settings instead of a hardcoded value.
ST Ericsson ID: 343004, 359227
ST Ericsson FOSS-OUT ID: trivial
ST Ericsson Linux next: -
Change-Id: I9a4ff57884017dd22774553c5bcabbb0756a604f
Signed-off-by: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32138
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/db8500-prcmu.c | 168 | ||||
-rw-r--r-- | drivers/mfd/dbx500-prcmu-regs.h | 24 |
2 files changed, 156 insertions, 36 deletions
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index fccdd5c1815..36e07605db4 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -426,41 +426,50 @@ static __iomem void *tcdm_base; struct clk_mgt { unsigned int offset; u32 pllsw; + int branch; + bool clk38div; +}; + +enum { + PLL_RAW, + PLL_FIX, + PLL_DIV }; static DEFINE_SPINLOCK(clk_mgt_lock); -#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 } +#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \ + { (PRCM_##_name##_MGT), 0 , _branch, _clk38div} struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { - CLK_MGT_ENTRY(SGACLK), - CLK_MGT_ENTRY(UARTCLK), - CLK_MGT_ENTRY(MSP02CLK), - CLK_MGT_ENTRY(MSP1CLK), - CLK_MGT_ENTRY(I2CCLK), - CLK_MGT_ENTRY(SDMMCCLK), - CLK_MGT_ENTRY(SLIMCLK), - CLK_MGT_ENTRY(PER1CLK), - CLK_MGT_ENTRY(PER2CLK), - CLK_MGT_ENTRY(PER3CLK), - CLK_MGT_ENTRY(PER5CLK), - CLK_MGT_ENTRY(PER6CLK), - CLK_MGT_ENTRY(PER7CLK), - CLK_MGT_ENTRY(LCDCLK), - CLK_MGT_ENTRY(BMLCLK), - CLK_MGT_ENTRY(HSITXCLK), - CLK_MGT_ENTRY(HSIRXCLK), - CLK_MGT_ENTRY(HDMICLK), - CLK_MGT_ENTRY(APEATCLK), - CLK_MGT_ENTRY(APETRACECLK), - CLK_MGT_ENTRY(MCDECLK), - CLK_MGT_ENTRY(IPI2CCLK), - CLK_MGT_ENTRY(DSIALTCLK), - CLK_MGT_ENTRY(DMACLK), - CLK_MGT_ENTRY(B2R2CLK), - CLK_MGT_ENTRY(TVCLK), - CLK_MGT_ENTRY(SSPCLK), - CLK_MGT_ENTRY(RNGCLK), - CLK_MGT_ENTRY(UICCCLK), + CLK_MGT_ENTRY(SGACLK, PLL_DIV, false), + CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true), + CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true), + CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true), + CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true), + CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true), + CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true), + CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true), + CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true), + CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true), + CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true), + CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false), + CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true), + CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true), + CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true), + CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true), + CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false), + CLK_MGT_ENTRY(DMACLK, PLL_DIV, true), + CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true), + CLK_MGT_ENTRY(TVCLK, PLL_FIX, false), + CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true), + CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true), + CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false), }; static struct regulator *hwacc_regulator[NUM_HW_ACC]; @@ -1445,7 +1454,7 @@ static int request_timclk(bool enable) return 0; } -static int request_reg_clock(u8 clock, bool enable) +static int request_clock(u8 clock, bool enable) { u32 val; unsigned long flags; @@ -1483,7 +1492,7 @@ static int request_sga_clock(u8 clock, bool enable) writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS); } - ret = request_reg_clock(clock, enable); + ret = request_clock(clock, enable); if (!ret && !enable) { val = readl(PRCM_CGATING_BYPASS); @@ -1506,7 +1515,7 @@ int db8500_prcmu_request_clock(u8 clock, bool enable) if (clock == PRCMU_SGACLK) return request_sga_clock(clock, enable); else if (clock < PRCMU_NUM_REG_CLOCKS) - return request_reg_clock(clock, enable); + return request_clock(clock, enable); else if (clock == PRCMU_TIMCLK) return request_timclk(enable); else if (clock == PRCMU_SYSCLK) @@ -1517,6 +1526,99 @@ int db8500_prcmu_request_clock(u8 clock, bool enable) return -EINVAL; } +static unsigned long pll_rate(unsigned int reg_offset, unsigned long src_rate, + u32 div, int branch) +{ + u64 rate; + u32 val; + u32 d; + + val = readl(_PRCMU_BASE + reg_offset); + + rate = src_rate; + rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT); + + d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT); + if (d > 1) + div *= d; + + d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT); + if (d > 1) + div *= d; + + if (val & PRCM_PLL_FREQ_SELDIV2) + div *= 2; + + if ((branch == PLL_FIX) || ((branch == PLL_DIV) && + (val & PRCM_PLL_FREQ_DIV2EN) && + ((reg_offset == PRCM_PLLSOC0_FREQ) || + (reg_offset == PRCM_PLLDDR_FREQ)))) + div *= 2; + + (void)do_div(rate, div); + + return (unsigned long)rate; +} + +#define ROOT_CLOCK_RATE 38400000 + +static unsigned long clock_rate(u8 clock) +{ + u32 val; + u32 div; + unsigned long src_rate = ROOT_CLOCK_RATE; + + val = readl(_PRCMU_BASE + clk_mgt[clock].offset); + + if (val & PRCM_CLK_MGT_CLK38) { + if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV)) + src_rate /= 2; + return src_rate; + } + + if ((clock == PRCMU_SGACLK) && + (val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) { + src_rate *= 10; + div = 25; + } else { + div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK); + if (!div) + return 0; + } + + switch ((val | clk_mgt[clock].pllsw) & PRCM_CLK_MGT_CLKPLLSW_MASK) { + case PRCM_CLK_MGT_CLKPLLSW_SOC0: + return pll_rate(PRCM_PLLSOC0_FREQ, src_rate, div, + clk_mgt[clock].branch); + case PRCM_CLK_MGT_CLKPLLSW_SOC1: + return pll_rate(PRCM_PLLSOC1_FREQ, src_rate, div, + clk_mgt[clock].branch); + case PRCM_CLK_MGT_CLKPLLSW_DDR: + return pll_rate(PRCM_PLLDDR_FREQ, src_rate, div, + clk_mgt[clock].branch); + default: + return 0; + } +} + +unsigned long prcmu_clock_rate(u8 clock) +{ + if (clock < PRCMU_NUM_REG_CLOCKS) + return clock_rate(clock); + else if (clock == PRCMU_TIMCLK) + return ROOT_CLOCK_RATE / 16; + else if (clock == PRCMU_SYSCLK) + return ROOT_CLOCK_RATE; + else if (clock == PRCMU_PLLSOC0) + return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else if (clock == PRCMU_PLLSOC1) + return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else if (clock == PRCMU_PLLDDR) + return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, 1, PLL_RAW); + else + return 0; +} + int db8500_prcmu_config_esram0_deep_sleep(u8 state) { if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h index 457fa4dc212..d8a916becf5 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/dbx500-prcmu-regs.h @@ -133,6 +133,18 @@ #define PRCM_MMIP_LS_CLAMP_CLR (_PRCMU_BASE + 0x424) /* PRCMU clock/PLL/reset registers */ +#define PRCM_PLLSOC0_FREQ 0x080 +#define PRCM_PLLSOC1_FREQ 0x084 +#define PRCM_PLLDDR_FREQ 0x08C +#define PRCM_PLL_FREQ_D_SHIFT 0 +#define PRCM_PLL_FREQ_D_MASK BITS(0, 7) +#define PRCM_PLL_FREQ_N_SHIFT 8 +#define PRCM_PLL_FREQ_N_MASK BITS(8, 13) +#define PRCM_PLL_FREQ_R_SHIFT 16 +#define PRCM_PLL_FREQ_R_MASK BITS(16, 18) +#define PRCM_PLL_FREQ_SELDIV2 BIT(24) +#define PRCM_PLL_FREQ_DIV2EN BIT(25) + #define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500) #define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504) #define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508) @@ -184,9 +196,15 @@ #define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24) #define PRCM_CLKOCR_CLK1TYPE BIT(28) -#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4) -#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7) -#define PRCM_CLK_MGT_CLKEN BIT(8) +#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4) +#define PRCM_CLK_MGT_CLKPLLSW_SOC0 BIT(5) +#define PRCM_CLK_MGT_CLKPLLSW_SOC1 BIT(6) +#define PRCM_CLK_MGT_CLKPLLSW_DDR BIT(7) +#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7) +#define PRCM_CLK_MGT_CLKEN BIT(8) +#define PRCM_CLK_MGT_CLK38 BIT(9) +#define PRCM_CLK_MGT_CLK38DIV BIT(11) +#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN BIT(12) /* GPIOCR register */ #define PRCM_GPIOCR_SPI2_SELECT BIT(23) |