diff options
author | Pawel Szyszuk <pawel.szyszuk@stericsson.com> | 2011-06-22 16:03:29 +0200 |
---|---|---|
committer | Robert Marklund <robert.marklund@stericsson.com> | 2011-10-05 13:01:38 +0200 |
commit | ab95a7e95ce024a3452a4b06d25503a13d323e06 (patch) | |
tree | a7c44abee7f4f7f2330138ed4348899016ead41e | |
parent | 2332af69affe6196813e61a5dd4c252f71089a8f (diff) |
ARM: U5500: PRCMU CLKOUTx configuration API
U5500 API for setting the programmable CLKOUTx source and divisor.
New API used for setting the sources of camera clocks.
ST-Ericsson ID: -
ST-Ericsson Linux next: NA
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I6d19543f5260af8c9dd4838538848644b3d34f81
Signed-off-by: Pawel Szyszuk <pawel.szyszuk@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/25701
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32443
Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r-- | drivers/mfd/db5500-prcmu.c | 113 | ||||
-rw-r--r-- | include/linux/mfd/db8500-prcmu.h | 6 | ||||
-rw-r--r-- | include/linux/mfd/dbx500-prcmu.h | 23 |
3 files changed, 136 insertions, 6 deletions
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c index ee40b30e0dc..fc38ef7cd6c 100644 --- a/drivers/mfd/db5500-prcmu.c +++ b/drivers/mfd/db5500-prcmu.c @@ -411,6 +411,9 @@ static struct { } ack; } mb5_transfer; +/* Spinlocks */ +static DEFINE_SPINLOCK(clkout_lock); + /* PRCMU TCDM base IO address. */ static __iomem void *tcdm_base; @@ -457,6 +460,116 @@ bool db5500_prcmu_is_ac_wake_requested(void) return false; } +/** + * prcmu_config_clkout - Configure one of the programmable clock outputs. + * @clkout: The CLKOUT number (0 or 1). + * @source: Clock source. + * @div: The divider to be applied. + * + * Configures one of the programmable clock outputs (CLKOUTs). + */ +int prcmu_config_clkout(u8 clkout, u8 source, u8 div) +{ + static bool configured[2] = {false, false}; + int r = 0; + unsigned long flags; + u32 sel_val; + u32 div_val; + u32 sel_bits; + u32 div_bits; + u32 sel_mask; + u32 div_mask; + u8 sel0 = CLKOUT_SEL0_SEL_CLK; + u16 sel = 0; + + BUG_ON(clkout > DB5500_CLKOUT1); + BUG_ON(source > DB5500_CLKOUT_IRDACLK); + BUG_ON(div > 7); + + switch (source) { + case DB5500_CLKOUT_REF_CLK_SEL0: + sel0 = CLKOUT_SEL0_REF_CLK; + break; + case DB5500_CLKOUT_RTC_CLK0_SEL0: + sel0 = CLKOUT_SEL0_RTC_CLK0; + break; + case DB5500_CLKOUT_ULP_CLK_SEL0: + sel0 = CLKOUT_SEL0_ULP_CLK; + break; + case DB5500_CLKOUT_STATIC0: + sel = CLKOUT_SEL_STATIC0; + break; + case DB5500_CLKOUT_REFCLK: + sel = CLKOUT_SEL_REFCLK; + break; + case DB5500_CLKOUT_ULPCLK: + sel = CLKOUT_SEL_ULPCLK; + break; + case DB5500_CLKOUT_ARMCLK: + sel = CLKOUT_SEL_ARMCLK; + break; + case DB5500_CLKOUT_SYSACC0CLK: + sel = CLKOUT_SEL_SYSACC0CLK; + break; + case DB5500_CLKOUT_SOC0PLLCLK: + sel = CLKOUT_SEL_SOC0PLLCLK; + break; + case DB5500_CLKOUT_SOC1PLLCLK: + sel = CLKOUT_SEL_SOC1PLLCLK; + break; + case DB5500_CLKOUT_DDRPLLCLK: + sel = CLKOUT_SEL_DDRPLLCLK; + break; + case DB5500_CLKOUT_TVCLK: + sel = CLKOUT_SEL_TVCLK; + break; + case DB5500_CLKOUT_IRDACLK: + sel = CLKOUT_SEL_IRDACLK; + break; + } + + switch (clkout) { + case DB5500_CLKOUT0: + sel_mask = PRCM_CLKOCR_CLKOUT0_SEL0_MASK | + PRCM_CLKOCR_CLKOUT0_SEL_MASK; + sel_bits = ((sel0 << PRCM_CLKOCR_CLKOUT0_SEL0_SHIFT) | + (sel << PRCM_CLKOCR_CLKOUT0_SEL_SHIFT)); + div_mask = PRCM_CLKODIV_CLKOUT0_DIV_MASK; + div_bits = div << PRCM_CLKODIV_CLKOUT0_DIV_SHIFT; + break; + case DB5500_CLKOUT1: + sel_mask = PRCM_CLKOCR_CLKOUT1_SEL0_MASK | + PRCM_CLKOCR_CLKOUT1_SEL_MASK; + sel_bits = ((sel0 << PRCM_CLKOCR_CLKOUT1_SEL0_SHIFT) | + (sel << PRCM_CLKOCR_CLKOUT1_SEL_SHIFT)); + div_mask = PRCM_CLKODIV_CLKOUT1_DIV_MASK; + div_bits = div << PRCM_CLKODIV_CLKOUT1_DIV_SHIFT; + break; + } + + spin_lock_irqsave(&clkout_lock, flags); + + if (configured[clkout]) { + r = -EINVAL; + goto unlock_and_return; + } + + sel_val = readl(_PRCMU_BASE + PRCM_CLKOCR); + writel((sel_bits | (sel_val & ~sel_mask)), + (_PRCMU_BASE + PRCM_CLKOCR)); + + div_val = readl(_PRCMU_BASE + PRCM_CLKODIV); + writel((div_bits | (div_val & ~div_mask)), + (_PRCMU_BASE + PRCM_CLKODIV)); + + configured[clkout] = true; + +unlock_and_return: + spin_unlock_irqrestore(&clkout_lock, flags); + + return r; +} + static int request_sysclk(bool enable) { int r; diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h index c48d80dec00..7b1a0740939 100644 --- a/include/linux/mfd/db8500-prcmu.h +++ b/include/linux/mfd/db8500-prcmu.h @@ -513,7 +513,6 @@ void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, struct prcmu_auto_pm_config *idle); bool prcmu_is_auto_pm_enabled(void); -int prcmu_config_clkout(u8 clkout, u8 source, u8 div); int prcmu_config_hotdog(u8 threshold); int prcmu_config_hotmon(u8 low, u8 high); @@ -623,11 +622,6 @@ static inline bool prcmu_is_auto_pm_enabled(void) return false; } -static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div) -{ - return 0; -} - static inline int prcmu_config_hotdog(u8 threshold) { return 0; diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h index c98ad55cc92..4996e20e1fa 100644 --- a/include/linux/mfd/dbx500-prcmu.h +++ b/include/linux/mfd/dbx500-prcmu.h @@ -81,6 +81,29 @@ enum prcmu_wakeup_index { #define EPOD_STATE_ON_CLK_OFF 0x03 #define EPOD_STATE_ON 0x04 +/* DB5500 CLKOUT IDs */ +enum { + DB5500_CLKOUT0 = 0, + DB5500_CLKOUT1, +}; + +/* DB5500 CLKOUTx sources */ +enum { + DB5500_CLKOUT_REF_CLK_SEL0, + DB5500_CLKOUT_RTC_CLK0_SEL0, + DB5500_CLKOUT_ULP_CLK_SEL0, + DB5500_CLKOUT_STATIC0, + DB5500_CLKOUT_REFCLK, + DB5500_CLKOUT_ULPCLK, + DB5500_CLKOUT_ARMCLK, + DB5500_CLKOUT_SYSACC0CLK, + DB5500_CLKOUT_SOC0PLLCLK, + DB5500_CLKOUT_SOC1PLLCLK, + DB5500_CLKOUT_DDRPLLCLK, + DB5500_CLKOUT_TVCLK, + DB5500_CLKOUT_IRDACLK, +}; + /* * CLKOUT sources */ |