summaryrefslogtreecommitdiff
path: root/arch/arm/plat-mxc/time.c
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2012-02-02 05:31:52 -0600
committerRanjani Vaidyanathan <ra5478@freescale.com>2012-02-03 08:28:08 -0600
commit7c9d2a4d02bb1536afe7b135d1cad550d3873b99 (patch)
tree42677700f0721a0f4d54969cbba3fa2b3c6a61e9 /arch/arm/plat-mxc/time.c
parentbf8db8fe33ff1cb8f42a3df18369138ce05f2878 (diff)
ENGR00173586-1 [MX6] Add support to source GPT from 24MHz
On MX6Q TO1.1, MX6DL/S and MX6Solo, GPT can be sourced from a constant source (better for frequency scaling). Currently we set the GPT clock to 3MHz (24MHz div by 8). Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'arch/arm/plat-mxc/time.c')
-rw-r--r--arch/arm/plat-mxc/time.c62
1 files changed, 58 insertions, 4 deletions
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index dd6b74e378c1..437921fdd2c2 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -58,7 +58,13 @@
#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
#define V2_TCTL_CLK_IPG (1 << 6)
#define V2_TCTL_CLK_PER (2 << 6)
-#define V2_TCTL_FRR (1 << 9)
+#define V2_TCTL_CLK_OSC_DIV8 (5 << 6)
+#define V2_TCTL_CLK_OSC (7 << 6)
+#define V2_TCTL_FRR (1 << 9)
+#define V2_TCTL_ENABLE24M (1 << 10)
+#define V2_TPRER_PRE24M_DIV8 7
+#define V2_TPRER_PRE24M_MASK 0xF
+#define V2_TPRER_PRE24M_OFFSET 12
#define V2_IR 0x0c
#define V2_TSTAT 0x08
#define V2_TSTAT_OF1 (1 << 0)
@@ -73,6 +79,10 @@ static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
static void __iomem *timer_base;
+#ifdef CONFIG_ARCH_MX6
+extern int mx6q_revision(void);
+#endif
+
static inline void gpt_irq_disable(void)
{
unsigned int tmp;
@@ -289,9 +299,38 @@ static int __init mxc_clockevent_init(struct clk *timer_clk)
return 0;
}
+#ifdef CONFIG_ARCH_MX6
+unsigned long mx6_timer_rate()
+{
+ struct clk *osc_clk = clk_get(NULL, "osc");
+ u32 parent_rate = clk_get_rate(osc_clk);
+
+ u32 reg = __raw_readl(timer_base + MXC_TCTL);
+ u32 div;
+
+ clk_put(osc_clk);
+
+ if ((reg & V2_TCTL_CLK_OSC_DIV8) == V2_TCTL_CLK_OSC_DIV8) {
+ if (cpu_is_mx6q())
+ /* For MX6Q, only options are 24MHz or 24MHz/8*/
+ return parent_rate / 8;
+ else {
+ /* For MX6DLS and MX6Solo, the rate is based on the
+ * divider value set in prescalar register. */
+ div = __raw_readl(timer_base + MXC_TPRER);
+ div = (div >> V2_TPRER_PRE24M_OFFSET) &
+ V2_TPRER_PRE24M_MASK;
+ return parent_rate / (div + 1);
+ }
+ }
+ return 0;
+}
+#endif
+
void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
{
uint32_t tctl_val;
+ u32 reg;
clk_enable(timer_clk);
@@ -304,9 +343,24 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
__raw_writel(0, timer_base + MXC_TCTL);
__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
- if (timer_is_v2())
- tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
- else
+ if (timer_is_v2()) {
+ if (cpu_is_mx5() ||
+ mx6q_revision() == IMX_CHIP_REVISION_1_0)
+ tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR |
+ V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ else {
+ tctl_val = V2_TCTL_CLK_OSC_DIV8 | V2_TCTL_FRR |
+ V2_TCTL_WAITEN | MXC_TCTL_TEN;
+ if (!cpu_is_mx6q()) {
+ reg = __raw_readl(timer_base + MXC_TPRER);
+ reg |= (V2_TPRER_PRE24M_DIV8 <<
+ V2_TPRER_PRE24M_OFFSET);
+ __raw_writel(reg, timer_base + MXC_TPRER);
+ /* Enable the 24MHz input clock. */
+ tctl_val |= V2_TCTL_ENABLE24M;
+ }
+ }
+ } else
tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
__raw_writel(tctl_val, timer_base + MXC_TCTL);