|
@@ -0,0 +1,132 @@
|
|
|
+/*
|
|
|
+ * linux/arch/arm/mach-omap1/clock.c
|
|
|
+ *
|
|
|
+ * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation
|
|
|
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
|
|
|
+ *
|
|
|
+ * Modified to use omap shared clock framework by
|
|
|
+ * Tony Lindgren <tony@atomide.com>
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ */
|
|
|
+#include <linux/kernel.h>
|
|
|
+#include <linux/export.h>
|
|
|
+#include <linux/list.h>
|
|
|
+#include <linux/errno.h>
|
|
|
+#include <linux/err.h>
|
|
|
+#include <linux/io.h>
|
|
|
+#include <linux/clk.h>
|
|
|
+#include <linux/clkdev.h>
|
|
|
+
|
|
|
+#include <asm/mach-types.h>
|
|
|
+
|
|
|
+#include <mach/hardware.h>
|
|
|
+
|
|
|
+#include "soc.h"
|
|
|
+#include "iomap.h"
|
|
|
+#include "clock.h"
|
|
|
+#include "opp.h"
|
|
|
+#include "sram.h"
|
|
|
+
|
|
|
+__u32 arm_idlect1_mask;
|
|
|
+struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
|
|
|
+
|
|
|
+static LIST_HEAD(clocks);
|
|
|
+static DEFINE_MUTEX(clocks_mutex);
|
|
|
+static DEFINE_SPINLOCK(clockfw_lock);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Omap1 specific clock functions
|
|
|
+ */
|
|
|
+
|
|
|
+unsigned long omap1_uart_recalc(struct clk *clk)
|
|
|
+{
|
|
|
+ unsigned int val = __raw_readl(clk->enable_reg);
|
|
|
+ return val & clk->enable_bit ? 48000000 : 12000000;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long omap1_sossi_recalc(struct clk *clk)
|
|
|
+{
|
|
|
+ u32 div = omap_readl(MOD_CONF_CTRL_1);
|
|
|
+
|
|
|
+ div = (div >> 17) & 0x7;
|
|
|
+ div++;
|
|
|
+
|
|
|
+ return clk->parent->rate / div;
|
|
|
+}
|
|
|
+
|
|
|
+static void omap1_clk_allow_idle(struct clk *clk)
|
|
|
+{
|
|
|
+ struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
|
|
|
+
|
|
|
+ if (!(clk->flags & CLOCK_IDLE_CONTROL))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count))
|
|
|
+ arm_idlect1_mask |= 1 << iclk->idlect_shift;
|
|
|
+}
|
|
|
+
|
|
|
+static void omap1_clk_deny_idle(struct clk *clk)
|
|
|
+{
|
|
|
+ struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
|
|
|
+
|
|
|
+ if (!(clk->flags & CLOCK_IDLE_CONTROL))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (iclk->no_idle_count++ == 0)
|
|
|
+ arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
|
|
|
+}
|
|
|
+
|
|
|
+static __u16 verify_ckctl_value(__u16 newval)
|
|
|
+{
|
|
|
+ /* This function checks for following limitations set
|
|
|
+ * by the hardware (all conditions must be true):
|
|
|
+ * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
|
|
|
+ * ARM_CK >= TC_CK
|
|
|
+ * DSP_CK >= TC_CK
|
|
|
+ * DSPMMU_CK >= TC_CK
|
|
|
+ *
|
|
|
+ * In addition following rules are enforced:
|
|
|
+ * LCD_CK <= TC_CK
|
|
|
+ * ARMPER_CK <= TC_CK
|
|
|
+ *
|
|
|
+ * However, maximum frequencies are not checked for!
|
|
|
+ */
|
|
|
+ __u8 per_exp;
|
|
|
+ __u8 lcd_exp;
|
|
|
+ __u8 arm_exp;
|
|
|
+ __u8 dsp_exp;
|
|
|
+ __u8 tc_exp;
|
|
|
+ __u8 dspmmu_exp;
|
|
|
+
|
|
|
+ per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
|
|
|
+ lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
|
|
|
+ arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
|
|
|
+ dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
|
|
|
+ tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
|
|
|
+ dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
|
|
|
+
|
|
|
+ if (dspmmu_exp < dsp_exp)
|
|
|
+ dspmmu_exp = dsp_exp;
|
|
|
+ if (dspmmu_exp > dsp_exp+1)
|
|
|
+ dspmmu_exp = dsp_exp+1;
|
|
|
+ if (tc_exp < arm_exp)
|
|
|
+ tc_exp = arm_exp;
|
|
|
+ if (tc_exp < dspmmu_exp)
|
|
|
+ tc_exp = dspmmu_exp;
|
|
|
+ if (tc_exp > lcd_exp)
|
|
|
+ lcd_exp = tc_exp;
|
|
|
+ if (tc_exp > per_exp)
|
|
|
+ per_exp = tc_exp;
|
|
|
+
|
|
|
+ newval &= 0xf000;
|
|
|
+ newval |= per_exp << CKCTL_PERDIV_OFFSET;
|
|
|
+ newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
|
|
|
+ newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
|
|
|
+ newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
|
|
|
+ newval |= tc_exp << CKCTL_TCDIV_OFFSET;
|
|
|
+ newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
|
|
|
+
|
|
|
+ return newval;
|