Linux内核---47.关于clk_get与clk_enable

一. clock初始化过程
在arch/arm/mach-s3c64xx/s3c6410.c中
  1. void __init s3c6410_init_clocks(int xtal)
  2. {
  3.     s3c64xx_register_clocks(xtal, S3C6410_CLKDIV0_ARM_MASK);  //1.将clk_src添加到clocks链表中
  4.     s3c6400_setup_clocks();
  5. }
1. 把所有的clk_src添加到clocks链表中
在arch/arm/mach-s3c64xx/clock.c中
  1. void __init s3c64xx_register_clocks(unsigned long xtal, unsigned armclk_divlimit)
  2. {
  3.     armclk_mask = armclk_divlimit;
  4.     //把xtal mpll upll clk_f clk_h clk_p添加到clocks链表中
  5.     s3c24xx_register_baseclocks(xtal);
  6.     //把 ext, epll, 27m, 48m, h2, xusbxti,添加到clocks链表中
  7.     s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
  8.     //把init_clocks区的clk添加到clokcs链表中
  9.     s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));    
  10.     //放在init_clocks_disable区内的clk,先添加进链表然后调用enable(0),禁止clk生效
  11.     clkp = init_clocks_disable;
  12.     for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
  13.         ret = s3c24xx_register_clock(clkp);
  14.         (clkp->enable)(clkp, 0);
  15.     }
  16.     //把cks1区的clk添加到clokcs链表中
  17.     s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1));
  18.     //把clksrcs区的clk添加到clokcs链表中
  19.     s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
  20.     s3c_pwmclk_init();
  21. }
2.把baseclock中的clk添加进链表中
在arch/arm/plat-samsung/clock.c中
  1. int __init s3c24xx_register_baseclocks(unsigned long xtal)
  2. {
  3.     clk_xtal.rate = xtal;
  4.     s3c24xx_register_clock(&clk_xtal) 
  5.     s3c24xx_register_clock(&clk_mpll) 
  6.     s3c24xx_register_clock(&clk_upll) 
  7.     s3c24xx_register_clock(&clk_f) 
  8.     s3c24xx_register_clock(&clk_h) 
  9.     s3c24xx_register_clock(&clk_p) 
  10. }

3.将clk结构体添加到clocks链表中
在arch/arm/plat-samsung/clock.c中
  1. int s3c24xx_register_clock(struct clk *clk)
  2. {
  3.     if (clk->enable == NULL)
  4.         clk->enable = clk_null_enable;

  5.     spin_lock(&clocks_lock);
  6.     list_add(&clk->list, &clocks);     //把参数中的clk结构体添加到clocks链表中
  7.     spin_unlock(&clocks_lock);
  8.     return 0;
  9. }
CLOCK的类型:
a. init_clocks
  1. static struct clk init_clocks[] = {
  2.         .name        = "lcd",
  3.         .name        = "gpio",
  4.         .name        = "usb-host",
  5.         .name        = "hsmmc",
  6.         .name        = "hsmmc",
  7.         .name        = "hsmmc",
  8.         .name        = "otg",
  9.         .name        = "timers",
  10.         .name        = "uart",
  11.         .name        = "uart",
  12.         .name        = "uart",
  13.         .name        = "uart",
  14.         .name        = "watchdog",
  15.         .name        = "ac97",
  16.         .name        = "cfcon",
  17.         .name        = "fimc",
  18.         .name        = "hclk_mfc",
  19.         .name        = "sclk_mfc",
  20.         .name        = "pclk_mfc",
  21.         .name        = "hclk_jpeg",
  22.         .name        = "sclk_jpeg",
  23.         .name        = "sclk_cam",
  24. };
b. init_clocks_disable
  1. static struct clk init_clocks_disable[] = {
  2.         .name        = "nand",
  3.         .name        = "rtc",
  4.         .name        = "adc",
  5.         .name        = "i2c",
  6.         .name        = "iis",
  7.         .name        = "iis",
  8.         .name        = "iis",
  9.         .name        = "keypad",
  10.         .name        = "spi",
  11.         .name        = "spi",
  12.         .name        = "spi_48m",
  13.         .name        = "spi_48m",
  14.         .name        = "48m",
  15.         .name        = "48m",
  16.         .name        = "48m",
  17.         .name        = "dma0",
  18.         .name        = "dma1",
  19. };
c. clks1与clks
  1. static struct clk *clks1[] __initdata = {
  2.     &clk_ext_xtal_mux,
  3.     &clk_iis_cd0,
  4.     &clk_iis_cd1,
  5.     &clk_iisv4_cd,
  6.     &clk_pcm_cd,
  7.     &clk_mout_epll.clk,
  8.     &clk_mout_mpll.clk,
  9.     &clk_dout_mpll,
  10.     &clk_arm,
  11. };

  12. static struct clk *clks[] __initdata = {
  13.     &clk_ext,
  14.     &clk_epll,
  15.     &clk_27m,
  16.     &clk_48m,
  17.     &clk_h2,
  18.     &clk_xusbxti,
  19. };
二. clock enable过程
在drivers/video/s3c-fb.c中
  1. static int __devinit s3c_fb_probe(struct platform_device *pdev)
  2. {
  3.     sfb->bus_clk = clk_get(dev, "lcd");    //1.从clocks链表中查找lcd的clk结构体
  4.     clk_enable(sfb->bus_clk);              //2.调用clk的enableb函数
  5. }

1. 从clocks链表中查找lcd的clk结构体
在arch/arm/plat-samsung/clock.c中
  1. struct clk *clk_get(struct device *dev, const char *id)
  2. {
  3.     spin_lock(&clocks_lock);
  4.     //从clocks中查找id与name都与参数相同的clk结构体
  5.     list_for_each_entry(p, &clocks, list) {     
  6.         if (p->id == idno && strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
  7.             clk = p;
  8.             break;
  9.         }
  10.     }
  11.     spin_unlock(&clocks_lock);
  12.     return clk;
  13. }

2. 具体的enable过程
在arch/arm/plat-samsung/clock.c中
  1. int clk_enable(struct clk *clk)
  2. {
  3.     clk_enable(clk->parent);   //先调用parent的enable

  4.     spin_lock(&clocks_lock);

  5.     if ((clk->usage++) == 0)
  6.         (clk->enable)(clk, 1);  //2.1 再调用具体的enable

  7.     spin_unlock(&clocks_lock);
  8.     return 0;
  9. }
2.1 以lcd为例为调用 s3c64xx_hclk_ctrl
在arch/arm/plat-samsung/clock.c中
  1. static struct clk init_clocks[] = {
  2. {
  3.     .name        = "lcd",
  4.     .id        = -1,
  5.     .parent        = &clk_h,
  6.     .enable        = s3c64xx_hclk_ctrl,
  7.     .ctrlbit    = S3C_CLKCON_HCLK_LCD,   //S3C_CLKCON_HCLK_LCD    (1<<3)
  8. }
  9. }
在arch/arm/plat-samsung/clock.c中
  1. static int s3c64xx_hclk_ctrl(struct clk *clk, int enable)
  2. {
  3.     return s3c64xx_gate(S3C_HCLK_GATE, clk, enable);
  4. }
#define S3C_HCLK_GATE        S3C_CLKREG(0x30)
#define S3C_CLKREG(x)        (S3C_VA_SYS + (x))
HCLK_GATE 0x7E00_F030
2.2 修改gate寄存器,使能或禁止clock
在arch/arm/plat-samsung/clock.c中
  1. static int inline s3c64xx_gate(void __iomem *regstruct clk *clk, int enable)
  2. {
  3.     unsigned int ctrlbit = clk->ctrlbit;
  4.     u32 con;

  5.     con = __raw_readl(reg);  //读取寄存器的值

  6.     if (enable)             //如果是enable,将这位清0 
  7.         con |= ctrlbit;     
  8.     else                    //如果是disable,将这位清0
  9.         con &= ~ctrlbit;    

  10.     __raw_writel(con, reg);  //修改后,写入到寄存器中
  11.     return 0;
  12. }
附录:
1. 获取clk的值
    clk_get_rate(struct clk);

你可能感兴趣的:(linux内核)