mini2440的系統時鐘講解

mini2440上爲了降低電磁干擾配備了12MHz的晶振,如果直接給當做cpu的時鐘,那這個s3c2440a就屈才了。幸好cpu內部自帶了MPLL將晶振時鐘倍頻使得cpu工作在FCLk及AHB總線上的外設工作在HCLK和APB總線上的外設工作在PCLK。當然還配有一個UPLL來產生恆定的48MHZ以支持usb2.0.
①.時鐘源選擇
在系統復位時檢測引腳OM3:OM2,若是0:0,則主時鐘源選擇外部晶振,usb時鐘源選擇外部晶振
②.MPLLCON  main pll control  主時鐘寄存器控制
用於設定FCLK和Fin的倍數。

Mpll(FCLK) = ( 2 × m × Fin ) / ( p × 2^s )
其中m=MDIV+8, p=PDIV+2, s=SDIV,Fin晶振頻率

比如
Fin=12MHz
MDIV=0x7F=127,m=135
PDIV=2,p=4
SDIV=1,s=1
則FCLK=405MHz

注意:系統復位時,必須寫一次MPLLCON   UPLLCON ,這樣系統才能正常工作。即使不改變其值,即使復位後MPLL UPLL都是使能的,也要寫一次,另外還有如下   

③.CLKDIVN clock divider control 時鐘分頻控制寄存器  
用於設置 FCLK  HCLK PCLK三者的比例

而CAMDIVN如下

比如
CAMDIVN[8]=0
CAMDIVN[9]=0
HDIVN=2,則HCLK=FCLK / 4
PDIVN=1,,則PCLK=HCLK / 2

有以下示例,摘自嵌入式linux開發完全手冊

/*********************************************************************************************************************************/
2011-12-18 
2440的片內外設時鐘使能控制

linux下將各個片內外設時鐘統一管理,組成時鐘隊列。
arch/arm/plat-s3c24xx/s3c2410-clock.c

/* standard clock definitions */
 
static struct clk init_clocks_disable[] = {
	{
		.name		= "nand",
		.id		= -1,
		.parent		= &clk_h,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_NAND,
	}, {
		.name		= "sdi",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_SDI,
	}, {
		.name		= "adc",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_ADC,
	}, {
		.name		= "i2c",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_IIC,
	}, {
		.name		= "iis",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_IIS,
	}, {
		.name		= "spi",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_SPI,
	}
};
 
static struct clk init_clocks[] = {
	{
		.name		= "lcd",
		.id		= -1,
		.parent		= &clk_h,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_LCDC,
	}, {
		.name		= "gpio",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_GPIO,
	}, {
		.name		= "usb-host",
		.id		= -1,
		.parent		= &clk_h,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_USBH,
	}, {
		.name		= "usb-device",
		.id		= -1,
		.parent		= &clk_h,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_USBD,
	}, {
		.name		= "timers",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_PWMT,
	}, {
		.name		= "uart",
		.id		= 0,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_UART0,
	}, {
		.name		= "uart",
		.id		= 1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_UART1,
	}, {
		.name		= "uart",
		.id		= 2,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_UART2,
	}, {
		.name		= "rtc",
		.id		= -1,
		.parent		= &clk_p,
		.enable		= s3c2410_clkcon_enable,
		.ctrlbit	= S3C2410_CLKCON_RTC,
	}, {
		.name		= "watchdog",
		.id		= -1,
		.parent		= &clk_p,
		.ctrlbit	= 0,
	}, {
		.name		= "usb-bus-host",
		.id		= -1,
		.parent		= &clk_usb_bus,
	}, {
		.name		= "usb-bus-gadget",
		.id		= -1,
		.parent		= &clk_usb_bus,
	},
};
//在需要操作各個外設的時鐘時,就調用用內核提供的各個函數即可。如摘自mini2440_adc.c
static struct clk    *adc_clock;
adc_clock = clk_get(NULL, "adc");//獲取時鐘
if (!adc_clock) 
{
    printk(KERN_ERR "failed to get adc clock source\n");
    return -ENOENT;
}

clk_enable(adc_clock);//使能時鐘
 
//在不需要時,禁止掉
if (adc_clock) 
{
    clk_disable(adc_clock);//禁止時鐘
    clk_put(adc_clock);
    adc_clock = NULL;//源碼下是一個空操作,可能是預留
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章