clock.c

来自「底层驱动开发」· C语言 代码 · 共 1,339 行 · 第 1/3 页

C
1,339
字号
static struct clk usb_dc_ck = {	.name		= "usb_dc_ck",	/* Direct from ULPD, no parent */	.rate		= 48000000,	.flags		= CLOCK_IN_OMAP16XX | RATE_FIXED,	.enable_reg	= SOFT_REQ_REG,	.enable_bit	= 4,};static struct clk mclk_1510 = {	.name		= "mclk",	/* Direct from ULPD, no parent. May be enabled by ext hardware. */	.rate		= 12000000,	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,};static struct clk mclk_16xx = {	.name		= "mclk",	/* Direct from ULPD, no parent. May be enabled by ext hardware. */	.flags		= CLOCK_IN_OMAP16XX,	.enable_reg	= COM_CLK_DIV_CTRL_SEL,	.enable_bit	= COM_ULPD_PLL_CLK_REQ,	.set_rate	= &set_ext_clk_rate,	.round_rate	= &round_ext_clk_rate,	.init		= &init_ext_clk,};static struct clk bclk_1510 = {	.name		= "bclk",	/* Direct from ULPD, no parent. May be enabled by ext hardware. */	.rate		= 12000000,	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,};static struct clk bclk_16xx = {	.name		= "bclk",	/* Direct from ULPD, no parent. May be enabled by ext hardware. */	.flags		= CLOCK_IN_OMAP16XX,	.enable_reg	= SWD_CLK_DIV_CTRL_SEL,	.enable_bit	= SWD_ULPD_PLL_CLK_REQ,	.set_rate	= &set_ext_clk_rate,	.round_rate	= &round_ext_clk_rate,	.init		= &init_ext_clk,};static struct clk mmc1_ck = {	.name		= "mmc1_ck",	/* Functional clock is direct from ULPD, interface clock is ARMPER */	.parent		= &armper_ck,	.rate		= 48000000,	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |			  RATE_FIXED | ENABLE_REG_32BIT,	.enable_reg	= MOD_CONF_CTRL_0,	.enable_bit	= 23,};static struct clk mmc2_ck = {	.name		= "mmc2_ck",	/* Functional clock is direct from ULPD, interface clock is ARMPER */	.parent		= &armper_ck,	.rate		= 48000000,	.flags		= CLOCK_IN_OMAP16XX |			  RATE_FIXED | ENABLE_REG_32BIT,	.enable_reg	= MOD_CONF_CTRL_0,	.enable_bit	= 20,};static struct clk virtual_ck_mpu = {	.name		= "mpu",	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |			  VIRTUAL_CLOCK | ALWAYS_ENABLED,	.parent		= &arm_ck, /* Is smarter alias for */	.recalc		= &followparent_recalc,	.set_rate	= &select_table_rate,	.round_rate	= &round_to_table_rate,};static struct clk *  onchip_clks[] = {	/* non-ULPD clocks */	&ck_ref,	&ck_dpll1,	/* CK_GEN1 clocks */	&ck_dpll1out,	&arm_ck,	&armper_ck,	&arm_gpio_ck,	&armxor_ck,	&armtim_ck,	&armwdt_ck,	&arminth_ck1510,  &arminth_ck16xx,	/* CK_GEN2 clocks */	&dsp_ck,	&dspmmu_ck,	&dspper_ck,	&dspxor_ck,	&dsptim_ck,	/* CK_GEN3 clocks */	&tc_ck,	&tipb_ck,	&l3_ocpi_ck,	&tc1_ck,	&tc2_ck,	&dma_ck,	&dma_lcdfree_ck,	&api_ck,	&lb_ck,	&rhea1_ck,	&rhea2_ck,	&lcd_ck,	/* ULPD clocks */	&uart1_1510,	&uart1_16xx,	&uart2_ck,	&uart3_1510,	&uart3_16xx,	&usb_clko,	&usb_hhc_ck1510, &usb_hhc_ck16xx,	&usb_dc_ck,	&mclk_1510,  &mclk_16xx,	&bclk_1510,  &bclk_16xx,	&mmc1_ck,	&mmc2_ck,	/* Virtual clocks */	&virtual_ck_mpu,};struct clk *clk_get(struct device *dev, const char *id){	struct clk *p, *clk = ERR_PTR(-ENOENT);	down(&clocks_sem);	list_for_each_entry(p, &clocks, node) {		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {			clk = p;			break;		}	}	up(&clocks_sem);	return clk;}EXPORT_SYMBOL(clk_get);void clk_put(struct clk *clk){	if (clk && !IS_ERR(clk))		module_put(clk->owner);}EXPORT_SYMBOL(clk_put);int __clk_enable(struct clk *clk){	__u16 regval16;	__u32 regval32;	if (clk->flags & ALWAYS_ENABLED)		return 0;	if (unlikely(clk->enable_reg == 0)) {		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",		       clk->name);		return 0;	}	if (clk->flags & DSP_DOMAIN_CLOCK) {		__clk_use(&api_ck);	}	if (clk->flags & ENABLE_REG_32BIT) {		if (clk->flags & VIRTUAL_IO_ADDRESS) {			regval32 = __raw_readl(clk->enable_reg);			regval32 |= (1 << clk->enable_bit);			__raw_writel(regval32, clk->enable_reg);		} else {			regval32 = omap_readl(clk->enable_reg);			regval32 |= (1 << clk->enable_bit);			omap_writel(regval32, clk->enable_reg);		}	} else {		if (clk->flags & VIRTUAL_IO_ADDRESS) {			regval16 = __raw_readw(clk->enable_reg);			regval16 |= (1 << clk->enable_bit);			__raw_writew(regval16, clk->enable_reg);		} else {			regval16 = omap_readw(clk->enable_reg);			regval16 |= (1 << clk->enable_bit);			omap_writew(regval16, clk->enable_reg);		}	}	if (clk->flags & DSP_DOMAIN_CLOCK) {		__clk_unuse(&api_ck);	}	return 0;}void __clk_disable(struct clk *clk){	__u16 regval16;	__u32 regval32;	if (clk->enable_reg == 0)		return;	if (clk->flags & DSP_DOMAIN_CLOCK) {		__clk_use(&api_ck);	}	if (clk->flags & ENABLE_REG_32BIT) {		if (clk->flags & VIRTUAL_IO_ADDRESS) {			regval32 = __raw_readl(clk->enable_reg);			regval32 &= ~(1 << clk->enable_bit);			__raw_writel(regval32, clk->enable_reg);		} else {			regval32 = omap_readl(clk->enable_reg);			regval32 &= ~(1 << clk->enable_bit);			omap_writel(regval32, clk->enable_reg);		}	} else {		if (clk->flags & VIRTUAL_IO_ADDRESS) {			regval16 = __raw_readw(clk->enable_reg);			regval16 &= ~(1 << clk->enable_bit);			__raw_writew(regval16, clk->enable_reg);		} else {			regval16 = omap_readw(clk->enable_reg);			regval16 &= ~(1 << clk->enable_bit);			omap_writew(regval16, clk->enable_reg);		}	}	if (clk->flags & DSP_DOMAIN_CLOCK) {		__clk_unuse(&api_ck);	}}void __clk_unuse(struct clk *clk){	if (clk->usecount > 0 && !(--clk->usecount)) {		__clk_disable(clk);		if (likely(clk->parent))			__clk_unuse(clk->parent);	}}int __clk_use(struct clk *clk){	int ret = 0;	if (clk->usecount++ == 0) {		if (likely(clk->parent))			ret = __clk_use(clk->parent);		if (unlikely(ret != 0)) {			clk->usecount--;			return ret;		}		ret = __clk_enable(clk);		if (unlikely(ret != 0) && clk->parent) {			__clk_unuse(clk->parent);			clk->usecount--;		}	}	return ret;}int clk_enable(struct clk *clk){	unsigned long flags;	int ret;	spin_lock_irqsave(&clockfw_lock, flags);	ret = __clk_enable(clk);	spin_unlock_irqrestore(&clockfw_lock, flags);	return ret;}EXPORT_SYMBOL(clk_enable);void clk_disable(struct clk *clk){	unsigned long flags;	spin_lock_irqsave(&clockfw_lock, flags);	__clk_disable(clk);	spin_unlock_irqrestore(&clockfw_lock, flags);}EXPORT_SYMBOL(clk_disable);int clk_use(struct clk *clk){	unsigned long flags;	int ret = 0;	spin_lock_irqsave(&clockfw_lock, flags);	ret = __clk_use(clk);	spin_unlock_irqrestore(&clockfw_lock, flags);	return ret;}EXPORT_SYMBOL(clk_use);void clk_unuse(struct clk *clk){	unsigned long flags;	spin_lock_irqsave(&clockfw_lock, flags);	__clk_unuse(clk);	spin_unlock_irqrestore(&clockfw_lock, flags);}EXPORT_SYMBOL(clk_unuse);int clk_get_usecount(struct clk *clk){        return clk->usecount;}EXPORT_SYMBOL(clk_get_usecount);unsigned long clk_get_rate(struct clk *clk){	return clk->rate;}EXPORT_SYMBOL(clk_get_rate);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;}static int calc_dsor_exp(struct clk *clk, unsigned long rate){	/* Note: If target frequency is too low, this function will return 4,	 * which is invalid value. Caller must check for this value and act	 * accordingly.	 *	 * Note: This function does not check 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	 */	unsigned long realrate;	struct clk *  parent;	unsigned  dsor_exp;	if (unlikely(!(clk->flags & RATE_CKCTL)))		return -EINVAL;	parent = clk->parent;	if (unlikely(parent == 0))		return -EIO;	realrate = parent->rate;	for (dsor_exp=0; dsor_exp<4; dsor_exp++) {		if (realrate <= rate)			break;		realrate /= 2;	}	return dsor_exp;}static void ckctl_recalc(struct clk *  clk){	int dsor;	/* Calculate divisor encoded as 2-bit exponent */	if (clk->flags & DSP_DOMAIN_CLOCK) {		/* The clock control bits are in DSP domain,		 * so api_ck is needed for access.		 * Note that DSP_CKCTL virt addr = phys addr, so		 * we must use __raw_readw() instead of omap_readw().		 */		__clk_use(&api_ck);		dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));		__clk_unuse(&api_ck);	} else {		dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));	}	if (unlikely(clk->rate == clk->parent->rate / dsor))		return; /* No change, quick exit */	clk->rate = clk->parent->rate / dsor;

⌨️ 快捷键说明

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