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