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;//源碼下是一個空操作,可能是預留
}