struct clk clk-get() clk_enable();

                struct clk;  之ARM

struct clk {
    struct list_head      list;
    struct module        *owner;
    struct clk           *parent;
    const char           *name;
    int              id;
    int              usage;
    unsigned long         rate;
    unsigned long         ctrlbit;

    int            (*enable)(struct clk *, int enable);
    int            (*set_rate)(struct clk *c, unsigned long rate);
    unsigned long        (*get_rate)(struct clk *c);
    unsigned long        (*round_rate)(struct clk *c, unsigned long rate);
    int            (*set_parent)(struct clk *c, struct clk *parent);
};        
        
************************************************
//arm/mach-3c2440/mach-mini2440.c
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));
}
************************************************

************************************************
//arm/plat-s3c/init.c
void __init s3c24xx_init_clocks(int xtal)
{
    if (xtal == 0)
        xtal = 12*1000*1000;

    if (cpu == NULL)
        panic("s3c24xx_init_clocks: no cpu setup?\n");

    if (cpu->init_clocks == NULL)
        panic("s3c24xx_init_clocks: cpu has no clock init\n");
    else
        (cpu->init_clocks)(xtal);     //struct cpu_table
}
^^^^^^^
struct cpu_table {    //cpu的结构
    unsigned long    idcode;
    unsigned long    idmask;
    void        (*map_io)(void);
    void        (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
    void        (*init_clocks)(int xtal);
    int        (*init)(void);
    const char    *name;
};
static struct cpu_table cpu_ids[] __initdata = {  //各个型号的信息与初始化函数
    {
        .idcode        = 0x32410000,
        .idmask        = 0xffffffff,
        .map_io        = s3c2410_map_io,
        .init_clocks    = s3c2410_init_clocks,
        .init_uarts    = s3c2410_init_uarts,
        .init        = s3c2410_init,
        .name        = name_s3c2410
    },
    {
        .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
    },
    {
        .idcode        = 0x32440000,
        .idmask        = 0xffffffff,
        .map_io        = s3c244x_map_io,
        .init_clocks    = s3c244x_init_clocks,
        .init_uarts    = s3c244x_init_uarts,
        .init        = s3c2440_init,
        .name        = name_s3c2440
    },
    {
        .idcode        = 0x32440001,
        .idmask        = 0xffffffff,
        .map_io        = s3c244x_map_io,
        .init_clocks    = s3c244x_init_clocks,
        .init_uarts    = s3c244x_init_uarts,
        .init        = s3c2440_init,
        .name        = name_s3c2440a
    },
    {
        .idcode        = 0x32440aaa,
        .idmask        = 0xffffffff,
        .map_io        = s3c244x_map_io,
        .init_clocks    = s3c244x_init_clocks,
        .init_uarts    = s3c244x_init_uarts,
        .init        = s3c2442_init,
        .name        = name_s3c2442
    },
    {
        .idcode        = 0x32440aab,
        .idmask        = 0xffffffff,
        .map_io        = s3c244x_map_io,
        .init_clocks    = s3c244x_init_clocks,
        .init_uarts    = s3c244x_init_uarts,
        .init        = s3c2442_init,
        .name        = name_s3c2442b
    },
    {
        .idcode        = 0x32412001,
        .idmask        = 0xffffffff,
        .map_io        = s3c2412_map_io,
        .init_clocks    = s3c2412_init_clocks,
        .init_uarts    = s3c2412_init_uarts,
        .init        = s3c2412_init,
        .name        = name_s3c2412,
    },
    {            /* a newer version of the s3c2412 */
        .idcode        = 0x32412003,
        .idmask        = 0xffffffff,
        .map_io        = s3c2412_map_io,
        .init_clocks    = s3c2412_init_clocks,
        .init_uarts    = s3c2412_init_uarts,
        .init        = s3c2412_init,
        .name        = name_s3c2412,
    },
    {
        .idcode        = 0x32443001,
        .idmask        = 0xffffffff,
        .map_io        = s3c2443_map_io,
        .init_clocks    = s3c2443_init_clocks,
        .init_uarts    = s3c2443_init_uarts,
        .init        = s3c2443_init,
        .name        = name_s3c2443,
    },
    {
        .idcode        = 0x0,   /* S3C2400 doesn't have an idcode */
        .idmask        = 0xffffffff,
        .map_io        = s3c2400_map_io,
        .init_clocks    = s3c2400_init_clocks,
        .init_uarts    = s3c2400_init_uarts,
        .init        = s3c2400_init,
        .name        = name_s3c2400
    },
};

************************************************

*******************************************************************************************
/arm/plat-s3c24xx/s3c244x.c
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();
}

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)    //mpll clk时钟
        printk(KERN_ERR "failed to register mpll clock\n");

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

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

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

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

    return 0;
}
加入链表中,统一管理,这里只是注册,还没有填充具体的值,下面这个函数就是获取需要的值
void __init_or_cpufreq s3c244x_setup_clocks(void)//设置时钟频率
{
    struct clk *xtal_clk;
    unsigned long clkdiv;
    unsigned long camdiv;
    unsigned long xtal;
    unsigned long hclk, fclk, pclk;
    int hdiv = 1;

    xtal_clk = clk_get(NULL, "xtal");
    xtal = clk_get_rate(xtal_clk);
    clk_put(xtal_clk);

    fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;//获得fclk时钟频率

    clkdiv = __raw_readl(S3C2410_CLKDIVN);
    camdiv = __raw_readl(S3C2440_CAMDIVN);

    /* work out clock scalings */

    switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) { //获取时钟分配值
    case S3C2440_CLKDIVN_HDIVN_1:
        hdiv = 1;
        break;

    case S3C2440_CLKDIVN_HDIVN_2:
        hdiv = 2;
        break;

    case S3C2440_CLKDIVN_HDIVN_4_8:
        hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
        break;

    case S3C2440_CLKDIVN_HDIVN_3_6:
        hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
        break;
    }

    hclk = fclk / hdiv;
    pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);

    /* print brief summary of clocks, etc */

    printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
           print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));

    s3c24xx_setup_clocks(fclk, hclk, pclk);//设置时钟值,就是填充一直以前注册的时钟
}
上面这个函数完成了对时钟频率的统计到获取
***************************************************
int __init s3c2410_baseclk_add(void)//注册其他的时钟
{
    unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
    unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
    struct clk *clkp;
    struct clk *xtal;
    int ret;
    int ptr;

    clk_upll.enable = s3c2410_upll_enable;

    if (s3c24xx_register_clock(&clk_usb_bus) < 0)
        printk(KERN_ERR "failed to register usb bus clock\n");

    /* register clocks from clock array */

    clkp = init_clocks;
    for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
        /* ensure that we note the clock state */

        clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;

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

    /* We must be careful disabling the clocks we are not intending to
     * be using at boot time, as subsystems such as the LCD which do
     * their own DMA requests to the bus can cause the system to lockup
     * if they where in the middle of requesting bus access.
     *
     * Disabling the LCD clock if the LCD is active is very dangerous,
     * and therefore the bootloader should be careful to not enable
     * the LCD clock if it is not needed.
    */

    /* install (and disable) the clocks we do not need immediately */

    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);
    }

    /* show the clock-slow value */

    xtal = clk_get(NULL, "xtal");

    printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
           print_mhz(clk_get_rate(xtal) /
             ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
           (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
           (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
           (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");

    s3c_pwmclk_init();  //pwm的时钟有些特别,所以单独初始化;(有两个时钟源可选)
    return 0;
}
从上面的这几个函数可以看,平常的和clk_get(,);clk_enable();就是这个原因,不让咱们直接操作寄存器,而采用统一管理的模式,增加了安全性与可靠性。


注1:
Mpll=(2*m*Fin)(p*2^s)
m=M(分频系数M)+8, p=P(分频系数P)+2
集成电路UPLL的工作原理与MPLL相同。
M、P、S的值由PLL控制寄存器(MPLLCON和UPLLCON)来设置。
注2:
USB host接口和USB设备接口提供正常工作需要的48MHz时钟,UCLK主要有4个状态:
1)刚刚复位时,UCLK为外部晶振或外部时钟。
2)配置UPLL结束后,在UPLL稳定时间内,UCLK为低电平,UPLL稳定时间结束,UCLK为48MHz。
3)CLKSLOW寄存器关闭UPLL,UCLK为外部晶振或者外部时钟。
4)CLKSLOW寄存器打开UPLL,UCLK为48MHz。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值