123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /*
- * 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;
|