clock.c

来自「linux2.6.16版本」· C语言 代码 · 共 621 行

C
621
字号
/* * linux/arch/arm/mach-at91rm9200/clock.c * * Copyright (C) 2005 David Brownell * Copyright (C) 2005 Ivan Kokshaysky * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/debugfs.h>#include <linux/seq_file.h>#include <linux/list.h>#include <linux/errno.h>#include <linux/err.h>#include <linux/spinlock.h>#include <linux/delay.h>#include <linux/clk.h>#include <asm/semaphore.h>#include <asm/io.h>#include <asm/mach-types.h>#include <asm/arch/hardware.h>#include <asm/arch/board.h>		/* for master clock global */#include "generic.h"#undef	DEBUG/* * There's a lot more which can be done with clocks, including cpufreq * integration, slow clock mode support (for system suspend), letting * PLLB be used at other rates (on boards that don't need USB), etc. */struct clk {	const char	*name;	unsigned long	rate_hz;	struct clk	*parent;	u32		pmc_mask;	void		(*mode)(struct clk *, int);	unsigned	id:2;		/* PCK0..3, or 32k/main/a/b */	unsigned	primary:1;	unsigned	pll:1;	unsigned	programmable:1;	u16		users;};static spinlock_t	clk_lock;static u32		at91_pllb_usb_init;/* * Four primary clock sources:  two crystal oscillators (32K, main), and * two PLLs.  PLLA usually runs the master clock; and PLLB must run at * 48 MHz (unless no USB function clocks are needed).  The main clock and * both PLLs are turned off to run in "slow clock mode" (system suspend). */static struct clk clk32k = {	.name		= "clk32k",	.rate_hz	= AT91_SLOW_CLOCK,	.users		= 1,		/* always on */	.id		= 0,	.primary	= 1,};static struct clk main_clk = {	.name		= "main",	.pmc_mask	= 1 << 0,	/* in PMC_SR */	.users		= 1,	.id		= 1,	.primary	= 1,};static struct clk plla = {	.name		= "plla",	.parent		= &main_clk,	.pmc_mask	= 1 << 1,	/* in PMC_SR */	.id		= 2,	.primary	= 1,	.pll		= 1,};static void pllb_mode(struct clk *clk, int is_on){	u32	value;	if (is_on) {		is_on = AT91_PMC_LOCKB;		value = at91_pllb_usb_init;	} else		value = 0;	at91_sys_write(AT91_CKGR_PLLBR, value);	do {		cpu_relax();	} while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);}static struct clk pllb = {	.name		= "pllb",	.parent		= &main_clk,	.pmc_mask	= 1 << 2,	/* in PMC_SR */	.mode		= pllb_mode,	.id		= 3,	.primary	= 1,	.pll		= 1,};static void pmc_sys_mode(struct clk *clk, int is_on){	if (is_on)		at91_sys_write(AT91_PMC_SCER, clk->pmc_mask);	else		at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);}/* USB function clocks (PLLB must be 48 MHz) */static struct clk udpck = {	.name		= "udpck",	.parent		= &pllb,	.pmc_mask	= AT91_PMC_UDP,	.mode		= pmc_sys_mode,};static struct clk uhpck = {	.name		= "uhpck",	.parent		= &pllb,	.pmc_mask	= AT91_PMC_UHP,	.mode		= pmc_sys_mode,};#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS/* * The four programmable clocks can be parented by any primary clock. * You must configure pin multiplexing to bring these signals out. */static struct clk pck0 = {	.name		= "pck0",	.pmc_mask	= AT91_PMC_PCK0,	.mode		= pmc_sys_mode,	.programmable	= 1,	.id		= 0,};static struct clk pck1 = {	.name		= "pck1",	.pmc_mask	= AT91_PMC_PCK1,	.mode		= pmc_sys_mode,	.programmable	= 1,	.id		= 1,};static struct clk pck2 = {	.name		= "pck2",	.pmc_mask	= AT91_PMC_PCK2,	.mode		= pmc_sys_mode,	.programmable	= 1,	.id		= 2,};static struct clk pck3 = {	.name		= "pck3",	.pmc_mask	= AT91_PMC_PCK3,	.mode		= pmc_sys_mode,	.programmable	= 1,	.id		= 3,};#endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS *//* * The master clock is divided from the CPU clock (by 1-4).  It's used for * memory, interfaces to on-chip peripherals, the AIC, and sometimes more * (e.g baud rate generation).  It's sourced from one of the primary clocks. */static struct clk mck = {	.name		= "mck",	.pmc_mask	= 1 << 3,	/* in PMC_SR */	.users		= 1,		/* (must be) always on */};static void pmc_periph_mode(struct clk *clk, int is_on){	if (is_on)		at91_sys_write(AT91_PMC_PCER, clk->pmc_mask);	else		at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);}static struct clk udc_clk = {	.name		= "udc_clk",	.parent		= &mck,	.pmc_mask	= 1 << AT91_ID_UDP,	.mode		= pmc_periph_mode,};static struct clk ohci_clk = {	.name		= "ohci_clk",	.parent		= &mck,	.pmc_mask	= 1 << AT91_ID_UHP,	.mode		= pmc_periph_mode,};static struct clk *const clock_list[] = {	/* four primary clocks -- MUST BE FIRST! */	&clk32k,	&main_clk,	&plla,	&pllb,	/* PLLB children (USB) */	&udpck,	&uhpck,#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS	/* programmable clocks */	&pck0,	&pck1,	&pck2,	&pck3,#endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS */	/* MCK and peripherals */	&mck,	// usart0..usart3	// mmc	&udc_clk,	// i2c	// spi	// ssc0..ssc2	// tc0..tc5	&ohci_clk,	// ether};/* clocks are all static for now; no refcounting necessary */struct clk *clk_get(struct device *dev, const char *id){	int i;	for (i = 0; i < ARRAY_SIZE(clock_list); i++) {		if (strcmp(id, clock_list[i]->name) == 0)			return clock_list[i];	}	return ERR_PTR(-ENOENT);}EXPORT_SYMBOL(clk_get);void clk_put(struct clk *clk){}EXPORT_SYMBOL(clk_put);static void __clk_enable(struct clk *clk){	if (clk->parent)		__clk_enable(clk->parent);	if (clk->users++ == 0 && clk->mode)		clk->mode(clk, 1);}int clk_enable(struct clk *clk){	unsigned long	flags;	spin_lock_irqsave(&clk_lock, flags);	__clk_enable(clk);	spin_unlock_irqrestore(&clk_lock, flags);	return 0;}EXPORT_SYMBOL(clk_enable);static void __clk_disable(struct clk *clk){	BUG_ON(clk->users == 0);	if (--clk->users == 0 && clk->mode)		clk->mode(clk, 0);	if (clk->parent)		__clk_disable(clk->parent);}void clk_disable(struct clk *clk){	unsigned long	flags;	spin_lock_irqsave(&clk_lock, flags);	__clk_disable(clk);	spin_unlock_irqrestore(&clk_lock, flags);}EXPORT_SYMBOL(clk_disable);unsigned long clk_get_rate(struct clk *clk){	unsigned long	flags;	unsigned long	rate;	spin_lock_irqsave(&clk_lock, flags);	for (;;) {		rate = clk->rate_hz;		if (rate || !clk->parent)			break;		clk = clk->parent;	}	spin_unlock_irqrestore(&clk_lock, flags);	return rate;}EXPORT_SYMBOL(clk_get_rate);/*------------------------------------------------------------------------*/#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS/* * For now, only the programmable clocks support reparenting (MCK could * do this too, with care) or rate changing (the PLLs could do this too, * ditto MCK but that's more for cpufreq).  Drivers may reparent to get * a better rate match; we don't. */long clk_round_rate(struct clk *clk, unsigned long rate){	unsigned long	flags;	unsigned	prescale;	unsigned long	actual;	if (!clk->programmable)		return -EINVAL;	spin_lock_irqsave(&clk_lock, flags);	actual = clk->parent->rate_hz;	for (prescale = 0; prescale < 7; prescale++) {		if (actual && actual <= rate)			break;		actual >>= 1;	}	spin_unlock_irqrestore(&clk_lock, flags);	return (prescale < 7) ? actual : -ENOENT;}EXPORT_SYMBOL(clk_round_rate);int clk_set_rate(struct clk *clk, unsigned long rate){	unsigned long	flags;	unsigned	prescale;	unsigned long	actual;	if (!clk->programmable)		return -EINVAL;	if (clk->users)		return -EBUSY;	spin_lock_irqsave(&clk_lock, flags);	actual = clk->parent->rate_hz;	for (prescale = 0; prescale < 7; prescale++) {		if (actual && actual <= rate) {			u32	pckr;			pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));			pckr &= 0x03;			pckr |= prescale << 2;			at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);			clk->rate_hz = actual;			break;		}		actual >>= 1;	}	spin_unlock_irqrestore(&clk_lock, flags);	return (prescale < 7) ? actual : -ENOENT;}EXPORT_SYMBOL(clk_set_rate);struct clk *clk_get_parent(struct clk *clk){	return clk->parent;}EXPORT_SYMBOL(clk_get_parent);int clk_set_parent(struct clk *clk, struct clk *parent){	unsigned long	flags;	if (clk->users)		return -EBUSY;	if (!parent->primary || !clk->programmable)		return -EINVAL;	spin_lock_irqsave(&clk_lock, flags);	clk->rate_hz = parent->rate_hz;	clk->parent = parent;	at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id);	spin_unlock_irqrestore(&clk_lock, flags);	return 0;}EXPORT_SYMBOL(clk_set_parent);#endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS *//*------------------------------------------------------------------------*/#ifdef CONFIG_DEBUG_FSstatic int at91_clk_show(struct seq_file *s, void *unused){	u32		scsr, pcsr, sr;	unsigned	i;	seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));	seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR));	seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));	seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));	seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));	seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));	seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));	for (i = 0; i < 4; i++)		seq_printf(s, "PCK%d = %8x\n", i, at91_sys_read(AT91_PMC_PCKR(i)));	seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));	seq_printf(s, "\n");	for (i = 0; i < ARRAY_SIZE(clock_list); i++) {		char		*state;		struct clk	*clk = clock_list[i];		if (clk->mode == pmc_sys_mode)			state = (scsr & clk->pmc_mask) ? "on" : "off";		else if (clk->mode == pmc_periph_mode)			state = (pcsr & clk->pmc_mask) ? "on" : "off";		else if (clk->pmc_mask)			state = (sr & clk->pmc_mask) ? "on" : "off";		else if (clk == &clk32k || clk == &main_clk)			state = "on";		else			state = "";		seq_printf(s, "%-10s users=%d %-3s %9ld Hz %s\n",			clk->name, clk->users, state, clk_get_rate(clk),			clk->parent ? clk->parent->name : "");	}	return 0;}static int at91_clk_open(struct inode *inode, struct file *file){	return single_open(file, at91_clk_show, NULL);}static struct file_operations at91_clk_operations = {	.open		= at91_clk_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= single_release,};static int __init at91_clk_debugfs_init(void){	/* /sys/kernel/debug/at91_clk */	(void) debugfs_create_file("at91_clk", S_IFREG | S_IRUGO, NULL, NULL, &at91_clk_operations);	return 0;}postcore_initcall(at91_clk_debugfs_init);#endif/*------------------------------------------------------------------------*/static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg){	unsigned mul, div;	div = reg & 0xff;	mul = (reg >> 16) & 0x7ff;	if (div && mul) {		freq /= div;		freq *= mul + 1;	} else		freq = 0;	if (pll == &pllb && (reg & (1 << 28)))		freq /= 2;	return freq;}static unsigned __init at91_pll_calc(unsigned main_freq, unsigned out_freq){	unsigned i, div = 0, mul = 0, diff = 1 << 30;	unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;	/* PLL output max 240 MHz (or 180 MHz per errata) */	if (out_freq > 240000000)		goto fail;	for (i = 1; i < 256; i++) {		int diff1;		unsigned input, mul1;		/*		 * PLL input between 1MHz and 32MHz per spec, but lower		 * frequences seem necessary in some cases so allow 100K.		 */		input = main_freq / i;		if (input < 100000)			continue;		if (input > 32000000)			continue;		mul1 = out_freq / input;		if (mul1 > 2048)			continue;		if (mul1 < 2)			goto fail;		diff1 = out_freq - input * mul1;		if (diff1 < 0)			diff1 = -diff1;		if (diff > diff1) {			diff = diff1;			div = i;			mul = mul1;			if (diff == 0)				break;		}	}	if (i == 256 && diff > (out_freq >> 5))		goto fail;	return ret | ((mul - 1) << 16) | div;fail:	return 0;}int __init at91_clock_init(unsigned long main_clock){	unsigned tmp, freq, mckr;	spin_lock_init(&clk_lock);	/*	 * When the bootloader initialized the main oscillator correctly,	 * there's no problem using the cycle counter.  But if it didn't,	 * or when using oscillator bypass mode, we must be told the speed	 * of the main clock.	 */	if (!main_clock) {		do {			tmp = at91_sys_read(AT91_CKGR_MCFR);		} while (!(tmp & 0x10000));		main_clock = (tmp & 0xffff) * (AT91_SLOW_CLOCK / 16);	}	main_clk.rate_hz = main_clock;	/* report if PLLA is more than mildly overclocked */	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));	if (plla.rate_hz > 209000000)		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);	/*	 * USB clock init:  choose 48 MHz PLLB value, turn all clocks off,	 * disable 48MHz clock during usb peripheral suspend.	 *	 * REVISIT:  assumes MCK doesn't derive from PLLB!	 */	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | 0x10000000;	pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);	at91_sys_write(AT91_PMC_PCDR, (1 << AT91_ID_UHP) | (1 << AT91_ID_UDP));	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_UDP);	at91_sys_write(AT91_CKGR_PLLBR, 0);	at91_sys_write(AT91_PMC_SCER, AT91_PMC_MCKUDP);	/*	 * MCK and CPU derive from one of those primary clocks.	 * For now, assume this parentage won't change.	 */	mckr = at91_sys_read(AT91_PMC_MCKR);	mck.parent = clock_list[mckr & AT91_PMC_CSS];	mck.parent->users++;	freq = mck.parent->rate_hz;	freq /= (1 << ((mckr >> 2) & 3));		/* prescale */	mck.rate_hz = freq / (1 + ((mckr >> 8) & 3));	/* mdiv */	printk("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n",		freq / 1000000, (unsigned) mck.rate_hz / 1000000,		(unsigned) main_clock / 1000000,		((unsigned) main_clock % 1000000) / 1000);	/* FIXME get rid of master_clock global */	at91_master_clock = mck.rate_hz;#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS	/* establish PCK0..PCK3 parentage */	for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) {		struct clk	*clk = clock_list[tmp], *parent;		u32		pckr;		if (!clk->programmable)			continue;		pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));		parent = clock_list[pckr & 3];		clk->parent = parent;		clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));	}#else	/* disable unused clocks */	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3);#endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS */	/* FIXME several unused clocks may still be active...  provide	 * a CONFIG option to turn off all unused clocks at some point	 * before driver init starts.	 */	return 0;}

⌨️ 快捷键说明

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