Linux下的clk学习

先看某主板的时钟dts描述,如

1.1固定时钟 fixed-clock

ext_26m: ext-26m {
	compatible = "fixed-clock";
	#clock-cells = <0>;
	clock-frequency = <26000000>;
	clock-output-names = "ext_26m";
 };

ext_6m5: ext-6m5 {
     compatible = "fixed-clock";
     #clock-cells = <0>;
     clock-frequency = <6500000>;
     clock-output-names = "ext_6m5";
 };

该主板有一个外接的26M晶振,ext_26m即外部的26M晶振,有一个固定的ext_6m5时钟,应该是从ext_26m分频而来。

 

1.2固定因子时钟 fixed-factor-clock

ext_26m: ext-26m {
	compatible = "fixed-clock";
	#clock-cells = <0>;
	clock-frequency = <26000000>;
	clock-output-names = "ext_26m";
};

clk_twpll: clk@40353004 {
	compatible = "sprd,sc9863a-adjustable-pll-clock";
	#clock-cells = <0>;
	reg = <0x0 0x40353004 0x0 0x4>,
		<0x0 0x40353008 0x0 0x4>,
		<0x0 0x4035300c 0x0 0x4>;
	clocks = <&ext_26m>;
	clock-output-names = "clk_twpll";
};

clk_twpll_12m: clk-twpll-12m {
	compatible = "fixed-factor-clock";
	#clock-cells = <0>;
	clock-mult = <1>;
	clock-div  = <128>;
	clocks = <&clk_twpll>;
	clock-output-names = "clk_twpll_12m";
};



clk_twpll_768m: clk-twpll-768m {
	compatible = "fixed-factor-clock";
	#clock-cells = <0>;
	clock-mult = <1>;
	clock-div  = <2>;
	clocks = <&clk_twpll>;
	clock-output-names = "clk_twpll_768m";
};

由某个时钟固定分频而来,

clock-div  = <128>;父时钟分频128而来

clocks = <&clk_twpll>,clk_twpll_12m来源于clk_twpll,而clk_twpll来源ext_26m

 

1.3muxed-clock混合时钟(可从多个时钟中选一个父时钟)

如clk_pwm0其可选的父时钟是ext_32k,clk_rpll_26m,&ext_26m,clk_twpll_48m

	clk_pwm0: clk@402d023c {
		compatible = "sprd,muxed-clock";
		#clock-cells = <0>;
		reg = <0x0 0x402d023c 0x0 0x4>;
		sprd,mux-msk = <0x3>;
		clocks = <&ext_32k>, <&clk_rpll_26m>, <&ext_26m>,
			 <&clk_twpll_48m>;
		clock-output-names = "clk_pwm0";
	};

 

1.4composite-clock适配时钟(可从多个时钟中选一个父时钟,并对其进行分频)

如clk_aux0其时钟来源可选(clk_set_parent)

clocks = <&ext_32k>, <&clk_rpll_26m>, <&ext_26m>;

sprd,div-msk = <0xf00>;代表其可以进行1到16的分频

clk_aux0: clk@402d022c {
    compatible = "sprd,composite-clock";
    #clock-cells = <0>;
    reg = <0x0 0x402d022c 0x0 0x4>;
    sprd,mux-msk = <0x3>;
    sprd,div-msk = <0xf00>;
    clocks = <&ext_32k>, <&clk_rpll_26m>, <&ext_26m>;
    clock-output-names = "clk_aux0";
};

1.5gates-clock门时钟(对时钟进行开关,如aux0_clk的开关时钟就是<&clk_aon_apb_gates1 2)

clk_aon_apb_gates1: clk@402e0004 {
    compatible = "sprd,sc1000-gates-clock";
	#clock-cells = <1>;
	reg = <0x0 0x402e0004 0x0 0x3000>;
	sprd,gates-msk = <0xfa7e7fbf>;
	clocks = <&clk_aon_apb>;
	clock-output-names = "pmu_eb", "thm_eb", "aux0_eb",
				"aux1_eb", "aux2_eb", "probe_eb",
				"clk_emc_ref_eb", "ca53_wdg_eb",
				"ap_tmr1_eb", "ap_tmr2_eb", "disp_emc_eb",
				"zip_emc_eb", "gsp_emc_eb", "mm_vsp_eb",
				"mdar_eb", "rtc4m0_cal_eb",
				"rtc4m1_cal_eb", "djtag_eb", "mbox_eb",
				"aon_dma_eb", "aon_apb_def_eb", "orp_jtag_eb",
				"dbg_eb", "dbg_emc_eb", "cross_trig_eb",
				"serdes_dphy_eb";
};

1.6使用例子

      sec-nfc@27 {
                compatible = "sec-nfc";
                clock-names = "clk_aux0","source","enable";
                clocks = <&clk_aux0>,<&ext_26m>,<&clk_aon_apb_gates1 2>;
        };

	
	struct clk clk_aux0,clk_parent,clk_enable;
 	clk_aux0 = devm_clk_get(dev, "clk_aux0");
	if (IS_ERR(clk_aux0)){
			pr_err("can't get nfc clock dts config: clk_aux0\n");
			return -1;
	}
	clk_parent = devm_clk_get(dev, "source");
	if (IS_ERR(clk_parent)) {
		pr_err("can't get nfc clock dts config: source\n");
		return -1;
	}
	clk_set_parent(clk_26m, clk_parent);

	ret=clk_set_rate(clk_26m,2600000);

	clk_enable = devm_clk_get(dev, "enable");
	if (IS_ERR(clk_enable)) {
		pr_err("can't get nfc clock dts config: enable\n");
		return -1;
	}
	clk_prepare_enable(clk_aux0);
	clk_prepare_enable(clk_enable)

1.7调试指南

进入时钟目录,如clk_aux0

/sys/kernel/debug/clk/clk_aux0或/d/clk/clk_aux0/

cat clk_rate可以看设置的频率

cat clk_enable_count看开关状态

如果不正常,继续检索log找原因

比如设置的时钟速率为2M,但实际上设置的速率3M,这是因为源时钟48M,可16分频,能得到的最小时钟为3M,驱动会找一个最进行的时钟频率进行配置。

1.8关键函数解析

clk_set_parent从所有父时钟中选一个(根据名字),计算第几个,然后写相应的寄存器,来选择父时钟,  同时也设置了速率就是父时钟的速率。

clk_set_parent
clk_core_set_parent
__clk_recalc_rates
clk_recalc
clk_divider_ops.recalc_rate
clk_divider_recalc_rate
divider_recalc_rate
DIV_ROUND_UP_ULL

clk_set_rate设置速率代码逻辑如下

clk_set_rate
clk_core_set_rate_nolock
clk_calc_new_rates
clk_calc_subtree
clk_recalc
clk_divider_ops.recalc_rate
clk_divider_recalc_rate
divider_recalc_rate
DIV_ROUND_UP_ULL
#define DIV_ROUND_UP_ULL(ll,d) \
	({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; })

 

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值