| 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;
 |