⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock_34xx.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/arch/arm/mach-omap2/clock.c * *  OMAP34XX clock framework * *  Copyright (C) 2007 Texas Instruments Inc. *  Karthik Dasu <karthik-dp@ti.com> * *  Based on omap2 clock.c Copyright (C) 2005 Texas Instruments Inc *  Richard Woodruff <r-woodruff2@ti.com> *  Cleaned up and modified to use omap shared clock framework by *  Tony Lindgren <tony@atomide.com> * *  Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.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. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *  GNU General Public License for more details. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/device.h>#include <linux/list.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/clk.h>#include <linux/cpufreq.h>#include <asm/io.h>#include <asm/arch/clock.h>#include <asm/arch/sram.h>#include "prcm-regs.h"#include "memory.h"#include "clock_34xx.h"/* #define DEBUG_CLK 1 */#  define DPRINTK(fmt, args...)static struct vdd_prcm_config *curr_vdd1_prcm_set;static struct vdd_prcm_config *curr_vdd2_prcm_set;static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult){	unsigned long new_jiffy_l, new_jiffy_h;	/*	 * Recalculate loops_per_jiffy.  We do it this way to	 * avoid math overflow on 32-bit machines.  Maybe we	 * should make this architecture dependent?  If you have	 * a better way of doing this, please replace!	 *	 *    new = old * mult / div	 */	new_jiffy_h = ref / div;	new_jiffy_l = (ref % div) / 100;	new_jiffy_h *= mult;	new_jiffy_l = new_jiffy_l * mult / div;	return new_jiffy_h + new_jiffy_l * 100;}/*------------------------------------------------------------------------- * Omap3 specific clock functions *-------------------------------------------------------------------------*//** * omap3_followparent_recalc: Makes clock rate same as parent. * @clk: Target clock. * * Makes clock rate same as parent. If required, propagates the change. */static void omap3_followparent_recalc(struct clk *clk){	followparent_recalc(clk);	if (clk->flags & RATE_PROPAGATES)		propagate_rate(clk);}/** * omap3_followparent_recalc: Progagates the clock rate. * @clk: Target clock. */static void omap3_propagate_rate(struct clk *clk){	propagate_rate(clk);}/** * _omap3_clk_enable: Enable OMAP3 clock. * @clk: Clock to be enabled. * * Low level function to enable specified clock. */static int _omap3_clk_enable(struct clk *clk){	int ret = 0;	DPRINTK("Clk: %s\n", clk->name);	if (clk->flags & ALWAYS_ENABLED)		return 0;	if (clk == &sys_clkout1)		ret = prcm_control_external_output_clock1(PRCM_ENABLE);	if (clk == &sys_clkout2)		ret = prcm_control_external_output_clock2(PRCM_ENABLE);	if (clk->flags & F_CLK) {		ret = prcm_clock_control(clk->prcmid, 						FCLK,						PRCM_ENABLE,						PRCM_ACCESS_CHK);	}	if (clk->flags & I_CLK) {		ret =		    prcm_clock_control(clk->prcmid,						ICLK,						PRCM_ENABLE,						PRCM_ACCESS_CHK);	}	DPRINTK("Done Clk: %s\n", clk->name);	if (ret == PRCM_FAIL)		return -EINVAL;	else		return 0;}/** * _omap3_clk_disable: Disable OMAP3 clock. * @clk: Clock to be disabled. * * Low level function to disable specified clock. */static void _omap3_clk_disable(struct clk *clk){	DPRINTK("Clk: %s\n", clk->name);	if (clk->flags & ALWAYS_ENABLED)		return;	if (clk == &sys_clkout1)		prcm_control_external_output_clock1(PRCM_DISABLE);	if (clk == &sys_clkout2)		prcm_control_external_output_clock2(PRCM_DISABLE);	if (clk->flags & F_CLK) {		prcm_clock_control(clk->prcmid, FCLK, PRCM_DISABLE,				   PRCM_NO_ACCESS_CHK);	}	if (clk->flags & I_CLK) {		prcm_clock_control(clk->prcmid, ICLK, PRCM_DISABLE,				   PRCM_NO_ACCESS_CHK);	}	DPRINTK("Done Clk: %s\n", clk->name);}/** * omap3_clk_disable: Disable OMAP3 clock. * @clk: * * Decrement the use count for specified clock. Disable the clock, if * use count becomes 0. */static void omap3_clk_disable(struct clk *clk){	DPRINTK("Clock: %s\n", clk->name);	if (clk->usecount > 0 && !(--clk->usecount)) {		_omap3_clk_disable(clk);		if (likely((u32) clk->parent))			omap3_clk_disable(clk->parent);	}	DPRINTK("Clock: %d usecount: %d\n", clk->name, clk->usecount);}/** * omap3_clk_enable: Enable OMAP3 clock. * @clk: * * Enable specified clock, if it isn't already. Increment the use count. */static int omap3_clk_enable(struct clk *clk){	int ret = 0;	DPRINTK("Clock: %s\n", clk->name);	if (clk->usecount++ == 0) {		if (likely((u32) clk->parent))			ret = omap3_clk_enable(clk->parent);		if (unlikely(ret != 0)) {			clk->usecount--;			return ret;		}		ret = _omap3_clk_enable(clk);		if (unlikely(ret != 0) && clk->parent) {			omap3_clk_disable(clk->parent);			clk->usecount--;		}	}	DPRINTK("Clock: %d usecount: %d\n", clk->name, clk->usecount);	return ret;}/* Calls appropriate PRCM API to calculate rate of clock */static void omap3_clk_recalc(struct clk *clk){	u32 parent_rate, divider, ret, rate;	parent_rate = clk->parent->rate;	ret = PRCM_PASS;	DPRINTK("Clock name: %s\n", clk->name);	if (clk == &sys_ck) {		clk->rate = prcm_get_system_clock_speed() * 1000;		ret = PRCM_PASS;	}	if (clk == &mpu_ck) {		ret = prcm_get_processor_speed(clk->prcmid, &rate);		clk->rate = rate * 1000;	}	if (clk == &iva2_ck) {		ret = prcm_get_processor_speed(clk->prcmid, &rate);		clk->rate = rate * 1000;	}	if (clk->flags & DPLL_OUTPUT) {		ret = prcm_get_dpll_rate(clk->prcmid, &rate);		if (ret == PRCM_PASS)			clk->rate = rate * 1000;	}	if (clk->flags & RATE_CKCTL) {		ret = prcm_clksel_get_divider(clk->prcmid, &divider);		DPRINTK("Divider: %d\n", divider);		if (ret == PRCM_PASS)			clk->rate = clk->parent->rate / divider;	}	if (ret != PRCM_PASS)		printk(KERN_ERR "Error in clk_recalc: %d,%s\n", ret, clk->name);	DPRINTK("Rate: %lu\n", clk->rate);	if (clk->flags & RATE_PROPAGATES)		propagate_rate(clk);}/* Given a clock and a rate apply a clock specific rounding function *//* This function should be called only for those clocks which have * dividers and which are not part of a clock configuration. In case * it is called for these clocks, it returns the current rate of the clocks */static long omap3_clk_round_rate(struct clk *tclk, unsigned long rate){	u32 new_div = 0, mnoutput;	int ret;	int valid_rate, parent_rate;	DPRINTK("Clock name: %s\n", tclk->name);	if (tclk->flags & RATE_FIXED)		return tclk->rate;	/* For external mcbsp clock node, rate is supposed to be set by	 * the corresponding device driver. So round rate will return	 * the rate that is supposed to be set */	if (tclk == &ext_mcbsp_ck) {		return rate;	}	if ((tclk->flags & VDD1_CONFIG_PARTICIPANT)	    || (tclk->flags & VDD2_CONFIG_PARTICIPANT)) 	/* If the clock is part of a clock configuration, it cannot	be changed on the fly */		return tclk->rate;	if (tclk->flags & DPLL_OUTPUT) {		/* The only clocks for which DPLL OUTPUT can be changed on		 * the fly (by changing only MX dividers) are:		 * PRCM_DPLL3_M3X2_CLK, PRCM_DPLL4_M2X2_CLK,		 * PRCM_DPLL4_M3X2_CLK, PRCM_DPLL4_M4X2_CLK,		 * PRCM_DPLL4_M5X2_CLK, PRCM_DPLL4_M6X2_CLK */		ret = prcm_get_dpll_mn_output(tclk->prcmid, &mnoutput);		/*mnoutput has CLKOUT = (Freq*m)/n+1 in case dpll is locked		 *or bypass clock if it is not locked */		if (ret != PRCM_PASS)			/* Rate cannot be changed. Return original rate*/			return tclk->rate;		ret =		    prcm_clksel_round_rate(tclk->prcmid, (2 * mnoutput),					   (rate / 1000), &new_div);		if (ret == PRCM_PASS) {			valid_rate = (2 * mnoutput * 1000) / new_div;			DPRINTK("Valid rate: %d\n", valid_rate);			return valid_rate;		} else			/* No acceptable divider - return original rate */			return tclk->rate;	}	if (tclk->flags & RATE_CKCTL) {		parent_rate = tclk->parent->rate;		ret =		    prcm_clksel_round_rate(tclk->prcmid, parent_rate,						   rate, &new_div);		if (ret == PRCM_PASS)			return parent_rate / new_div;		else			/* No acceptable divider - return original rate */			return tclk->rate;	}	if (tclk->round_rate != 0)		return tclk->round_rate(tclk, rate);	return tclk->rate;}/* Set the clock rate for a clock source */static int omap3_clk_set_rate(struct clk *clk, unsigned long rate){	int ret = -EINVAL;	u32 validrate, parent_rate, mnoutput;	u32 new_div = 0;	DPRINTK("Clock name: %s\n", clk->name);	/* For external mcbsp clock, the driver can set the rate using*/	/* clk_set_rate API */	if (clk == &ext_mcbsp_ck) {		clk->rate = rate;		clk->recalc(clk);		return 0;	}	if (!(clk->flags & VDD1_CONFIG_PARTICIPANT)	    && !(clk->flags & VDD2_CONFIG_PARTICIPANT)) {		if (clk->flags & DPLL_OUTPUT) {			ret = prcm_get_dpll_mn_output(clk->prcmid, &mnoutput);			/*mnoutput has CLKOUT = (Freq*m)/n+1 in case dpll			 *is locked or bypass clock if it is not locked */			if (ret != PRCM_PASS)				/* Signal error */				return (-EINVAL);			ret =			    prcm_clksel_round_rate(clk->prcmid, (2 * mnoutput),						   (rate / 1000), &new_div);			if (ret == PRCM_PASS) {				validrate = (2 * mnoutput * 1000) / new_div;				DPRINTK("Valid rate: %d\n", validrate);				if (validrate != rate)					return (-EINVAL);			} else			/* No acceptable divider - signal error */				return (-EINVAL);			ret = prcm_configure_dpll_divider(clk->prcmid, new_div);		} else if (clk->flags & RATE_CKCTL) {			parent_rate = clk->parent->rate;			ret =				prcm_clksel_round_rate(clk->prcmid,							   parent_rate, rate,							   &new_div);			if (ret == PRCM_PASS) {				validrate = parent_rate / new_div;				DPRINTK("Valid rate: %d\n", validrate);				if (validrate != rate)					return (ret);			} else				return (-EINVAL);			ret =				prcm_clksel_set_divider(clk->prcmid,							    new_div);			if (ret != PRCM_PASS)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -