clk_get函数实现,Linux内核时钟框架

来源:互联网 发布:制作毕业纪念册软件 编辑:程序博客网 时间:2024/05/16 09:04

(1)  对应外设时钟的开启

struct clk=clk_get(NULL,"adc");

clk.enable();

之后adc对应的时钟位就能时能。

struct clk *clk_get(struct device *dev, const char *id)
{
    ..........
    list_for_each_entry(p, &clocks, list) {
        if (p->id == idno &&
            strcmp(id, p->name) == 0 &&
            try_module_get(p->owner)) {
            clk = p;
            break;
        }
    }

    .............................................
    return clk;
}

clk_get从一个时钟list链表中以字符id名称来查找一个时钟clk结构体并且返回,最后调用clk.enable(),来时能对应的外设时钟源。


(2)  list的设置和对应list中的成员。

MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")
    .phys_io    = S3C2410_PA_UART,
    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    .boot_params    = S3C2410_SDRAM_PA + 0x100,

    .init_irq    = s3c24xx_init_irq,
    .map_io        = mini2440_map_io,
    .init_machine    = mini2440_machine_init,
    .timer        = &s3c24xx_timer,
MACHINE_END


static void __init mini2440_map_io(void)
{
    s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
    s3c24xx_init_clocks(12000000);
    s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
}


void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
{
    unsigned long idcode = 0x0;
   ...........
    arm_pm_restart = s3c24xx_pm_restart;

    s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
}


void __init s3c_init_cpu(unsigned long idcode,
             struct cpu_table *cputab, unsigned int cputab_size)
{
    cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
   ......
    cpu->map_io();

static struct cpu_table cpu_ids[] __initdata = {
    .......
    {
        .idcode        = 0x32410002,
        .idmask        = 0xffffffff,
        .map_io        = s3c2410_map_io,
        .init_clocks    = s3c2410_init_clocks,
        .init_uarts    = s3c2410_init_uarts,
        .init        = s3c2410a_init,
        .name        = name_s3c2410a
    },
    .......
}

在static void __init mini2440_map_io(void)中调用s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc))后返回了struct cpu_table cpu_ids中的

    {
        .idcode        = 0x32410002,
        .idmask        = 0xffffffff,
        .map_io        = s3c2410_map_io,
        .init_clocks    = s3c2410_init_clocks,
        .init_uarts    = s3c2410_init_uarts,
        .init        = s3c2410a_init,
        .name        = name_s3c2410a
    }

cpu_table

之后运行s3c24xx_init_clocks(12000000)后又执行(cpu->init_clocks)(xtal),对应就是s3c2410_init_clocks

void __init s3c244x_init_clocks(int xtal)
{
    /* initialise the clocks here, to allow other things like the
     * console to use them, and to add new ones after the initialisation
     */

    s3c24xx_register_baseclocks(xtal); //完成祖宗级别时钟的注册 
    s3c244x_setup_clocks();//填充祖宗级别时钟结构,方便以后调用
    s3c2410_baseclk_add();//添加一些外设时钟结构到list中,并且关闭它们方便省电
}


int __init s3c24xx_register_baseclocks(unsigned long xtal)
{
    printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");

    clk_xtal.rate = xtal;

    /* register our clocks */

    if (s3c24xx_register_clock(&clk_xtal) < 0)
        printk(KERN_ERR "failed to register master xtal\n");

    if (s3c24xx_register_clock(&clk_mpll) < 0)
        printk(KERN_ERR "failed to register mpll clock\n");

    if (s3c24xx_register_clock(&clk_upll) < 0)
        printk(KERN_ERR "failed to register upll clock\n");

    if (s3c24xx_register_clock(&clk_f) < 0)
        printk(KERN_ERR "failed to register cpu fclk\n");

    if (s3c24xx_register_clock(&clk_h) < 0)
        printk(KERN_ERR "failed to register cpu hclk\n");

    if (s3c24xx_register_clock(&clk_p) < 0)
        printk(KERN_ERR "failed to register cpu pclk\n");

    return 0;
}

以上的作用就是将一个个的时钟结构体链接成双向链表的,以后好使用clk_get在时钟结构体链表中查找id字符匹配的clk结构体并返回。

s3c2410_baseclk_add()

{

  ..........

clkp = init_clocks_disable;
    for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {

        ret = s3c24xx_register_clock(clkp);
        if (ret < 0) {
            printk(KERN_ERR "Failed to register clock %s (%d)\n",
                   clkp->name, ret);
        }

        s3c2410_clkcon_enable(clkp, 0);
    }

    ........

}

s3c2410_baseclk_add()添加其他外设的clk结构

clk.enable(),最后调用的

static struct clk init_clocks_disable[] = {

......

{
        .name        = "adc",
        .id        = -1,
        .parent        = &clk_p,
        .enable        = s3c2410_clkcon_enable,
        .ctrlbit    = S3C2410_CLKCON_ADC,

}

......

}中的

int s3c2410_clkcon_enable(struct clk *clk, int enable)
{
    unsigned int clocks = clk->ctrlbit;
    unsigned long clkcon;

    clkcon = __raw_readl(S3C2410_CLKCON);

    if (enable)
        clkcon |= clocks;
    else
        clkcon &= ~clocks;

    /* ensure none of the special function bits set */
    clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);

    __raw_writel(clkcon, S3C2410_CLKCON);

    return 0;
}其根据.ctrlbit    = S3C2410_CLKCON_ADC,来使能对应ADC时钟。


至此完毕。

原创粉丝点击