linux clk(二)

参考:

Linux 时钟框架学习笔记_我的学习笔记-CSDN博客___timer_of_table

kernel - clock - qzhang1535 - 博客园

of_clk_get_by_name函数分析:

struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
{
	return __of_clk_get_by_name(np, np->full_name, name);
}
static struct clk *__of_clk_get_by_name(struct device_node *np,
					const char *dev_id,
					const char *name)
{
	struct clk *clk = ERR_PTR(-ENOENT);

	/* Walk up the tree of devices looking for a clock that matches */
	while (np) {
		int index = 0;

		/*
		 * For named clocks, first look up the name in the "clock-names" property.  If it                         
         * cannot be found, then index will be an error code, and of_clk_get() will fail.
		 */
		if (name)
			index = of_property_match_string(np, "clock-names", name);
		clk = __of_clk_get(np, index, dev_id, name);
		if (!IS_ERR(clk)) {
			break;
		} 

	}

    return clk;

}
static struct clk *__of_clk_get(struct device_node *np, int index,
			       const char *dev_id, const char *con_id)
{
	struct of_phandle_args clkspec;
	struct clk *clk;
	int rc;

	rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,&clkspec);

	clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id);
	of_node_put(clkspec.np);

	return clk;
}
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
				       const char *dev_id, const char *con_id)
{
	struct of_clk_provider *provider;
	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
	struct clk_hw *hw;


	/* Check if we have such a provider in our array */
	list_for_each_entry(provider, &of_clk_providers, link) {
		if (provider->node == clkspec->np) {
			hw = __of_clk_get_hw_from_provider(provider, clkspec);
			clk = __clk_create_clk(hw, dev_id, con_id);
		}

		if (!IS_ERR(clk)) {
	
			break;
		}
	}

	return clk;
}

static struct clk_hw * __of_clk_get_hw_from_provider(struct of_clk_provider *provider,
			      struct of_phandle_args *clkspec)
{
	struct clk *clk;

	clk = provider->get(clkspec, provider->data);

	return __clk_get_hw(clk);
}

clk_prepare_enable函数分析:

static inline int clk_prepare_enable(struct clk *clk)
{
	int ret;

	ret = clk_prepare(clk);
	ret = clk_enable(clk);

	return ret;
}

clk_prepare函数:

int clk_prepare(struct clk *clk)
{
	
	return clk_core_prepare_lock(clk->core);
}
static int clk_core_prepare_lock(struct clk_core *core)
{
	int ret;

	ret = clk_core_prepare(core);

	return ret;
}
static int clk_core_prepare(struct clk_core *core)
{
	int ret = 0;

	if (!core)
		return 0;

	if (core->prepare_count == 0) {
		ret = clk_core_prepare(core->parent);   //递归prepare父时钟,父时钟如果还有父时钟,逐个往上追溯
		if (ret)
			return ret;

		if (core->ops->prepare)
			ret = core->ops->prepare(core->hw); //prepare自己

		if (ret) {
			clk_core_unprepare(core->parent);
			return ret;
		}
	}

	core->prepare_count++;

	return 0;
}

clk_enable函数分析:

int clk_enable(struct clk *clk)
{

	return clk_core_enable_lock(clk->core);
}
static int clk_core_enable_lock(struct clk_core *core)
{
	unsigned long flags;
	int ret;

	ret = clk_core_enable(core);

	return ret;
}
static int clk_core_enable(struct clk_core *core)
{
	int ret = 0;

	if (!core)
		return 0;

	if (core->enable_count == 0) {
		ret = clk_core_enable(core->parent);       //递归使能父时钟,父时钟如果还有父时钟,逐个往上追溯

		if (ret)
			return ret;

		if (core->ops->enable)
			ret = core->ops->enable(core->hw);    //最后使能自己的时钟

		if (ret) {
			clk_core_disable(core->parent);
			return ret;
		}
	}

	core->enable_count++;
	return 0;
}

总结:

1、clk_prepare_enable函数最终分别调用了core->ops->prepare( )、core->ops->enable( ),core->ops 是在 clk_register 函数里初始化的。
2、内核使用 Common Clk Framework (CCF)框架,其作用是构建了一个时钟树结构,根时钟下有子时钟,子时钟可以再有子时钟。驱动使用统一的接口去使能一个时钟时,会先递归使能父时钟,然后再使能自己,最终效果是从根时钟开始使能直到叶子时钟使能结束。

补充:

时钟树:参考dts中clk节点布局可知,其完全就是一棵树。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值