davinci 达芬奇 时钟驱动分析 dm365/dm368 struct clk

【blog.csdn.net/lanmanck】

本文纯属啰嗦帖子,没有很高的技术含量,仅供参考。

以dm365的spi为例说明之:

1、先在dm365.c里定义几个宏:

定义PLL1/2的属性:static struct pll_data pll1_data{定义寄存器基址灯}

定义参考时钟:static struct clk ref_clk={定义晶振时钟}

定义PLL1的时钟:static struct clk pll1_clk={定义parent(父类)为ref_clk,data(属性)为pll1_data}

  定义PLL1输出的时钟源,例如static struct clk pll1_sysclk6={定义parent(父类)为pll1_clk,}

定义PLL2的时钟:static struct clk pll2_clk={定义parent(父类)为ref_clk,data(属性)为pll2_data}

  定义PLL2输出的时钟源,例如static struct clk pll2_sysclk3={定义parent(父类)为pll2_clk,}

2、定义外设使用的PLL输出源:

static struct clk vpss_dac_clk={定义parent为pll1_sysclk3,LPSC=DM365_LPSC_DAC_CLK}

static struct clk spi2_clk={定义parent为pll1_sysclk4,LPSC=DM365_LPSC_SPI2}


3、定义参考时钟、pll时钟、pll输出源的查找表:

static struct clk_lookup dm365_clks[]={例如CLK("spi_davinci.2",NULL,&spi2_clk)}

4、查找表赋值给struct davinci_soc_info davinci_soc_info_dm365.cpu_clks

5、系统注册时调用davinci_common_init(struct davinci_soc_info *a),此函数会判断.cpu_clks是否有效,

如果有效,则调用davinci_clk_init进行clock初始化,看看davinci_clk_init()都干了些啥


6、davinci_clk_init() 挨个遍历查找表的clk(最后一位成员)

如果查找表中定义的clk->recalc为0(一般都为0),则赋值重计算的api。

例如找到pll1_clk,发现pll_data为pll1_data,则赋值为clk->recalc = clk_pllclk_recalc。

又如,找到标志位clk->flags & CLK_PLL,表示这个clk是PLL输出源,则赋值为clk->recalc = clk_sysclk_recalc。

又如,找到clk有父类clk->parent,表示这个是个PSC时钟,赋值为clk_recalc = clk_leafclk_recalc

因为这几个if有优先级,所以基本上顺序为:PLL、PLL输出源、外设时钟


接着,如果这个clk是PLL,则ioremap这个PLL的寄存器基址,用来后面的配置


现在,调用clk->recalc()来获得当前clk的实际时钟:clk->rate = clk->recalc(clk);

如果时钟管理有效(clk->lpsc),则把标志位置上clk->flags |= CLK_PSC;


调用clk_register(clk)注册该时钟到内核中进行管理


最后如果标志位flags有ALWAYS_ENABLED,则使能该clk:clk_enable(clk);


7、实例:SPI2就是调用clk_leafclk_recalc()来得到自己的bus clock,实际上该函数返回的就是parent的clock,

我们看到spi2_clk定义时parent=pll1_sysclk4,相当于spi2的bus时钟就是pll1_sysclk4,而这个时钟是通过

clk_sysclk_recalc()算出来的。


OK, 就这么多!


你可能感兴趣的:(davinci 达芬奇 时钟驱动分析 dm365/dm368 struct clk)