summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMattias Nilsson <mattias.i.nilsson@stericsson.com>2011-09-12 11:49:13 +0200
committerRobert Marklund <robert.marklund@stericsson.com>2011-10-05 13:01:18 +0200
commite9a5bc2c85fb33f2ecdd9392e3bc13d2624eaa1b (patch)
treedcef5371304934db25db0ef8a01d415884d4d6d5
parent1d4e311d63be8308451b89d7e7174a2c4722de2f (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>
-rw-r--r--drivers/mfd/db8500-prcmu.c168
-rw-r--r--drivers/mfd/dbx500-prcmu-regs.h24
-rw-r--r--include/linux/mfd/db5500-prcmu.h5
-rw-r--r--include/linux/mfd/dbx500-prcmu.h7
4 files changed, 168 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)
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
index 9890687f582..f3f3115ae03 100644
--- a/include/linux/mfd/db5500-prcmu.h
+++ b/include/linux/mfd/db5500-prcmu.h
@@ -50,6 +50,11 @@ static inline int db5500_prcmu_request_clock(u8 clock, bool enable)
return 0;
}
+static inline unsigned long db5500_prcmu_clock_rate(u8 clock)
+{
+ return 0;
+}
+
static inline int db5500_prcmu_set_display_clocks(void)
{
return 0;
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index c58060fa8d4..a0be8cba9fd 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -290,6 +290,8 @@ static inline int prcmu_request_clock(u8 clock, bool enable)
return db8500_prcmu_request_clock(clock, enable);
}
+unsigned long prcmu_clock_rate(u8 clock);
+
int prcmu_set_ape_opp(u8 opp);
int prcmu_get_ape_opp(void);
int prcmu_set_ddr_opp(u8 opp);
@@ -408,6 +410,11 @@ static inline int prcmu_request_clock(u8 clock, bool enable)
return 0;
}
+static inline unsigned long prcmu_clock_rate(u8 clock)
+{
+ return 0;
+}
+
static inline int prcmu_set_ape_opp(u8 opp)
{
return 0;