linux clk驱动框架

来源:互联网 发布:橱柜设计cad软件 编辑:程序博客网 时间:2024/06/01 03:57

clk common framework(ccf)子系统,用来完成对clock的统一管理.
如今,可运行Linux的主流处理器平台,都有非常复杂的clock tree,我们随便拿一个处理器的spec,查看clock相关的章节,一定会有一个非常庞大和复杂的树状图,这个图由clock相关的器件,以及这些器件输出的clock组成。下图是一个示例:
这里写图片描述
clock相关的器件包括:用于产生clock的Oscillator(有源振荡器,也称作谐振荡器)或者Crystal(无源振荡器,也称晶振);用于倍频的PLL(锁相环,Phase Locked Loop);用于分频的divider;用于多路选择的Mux;用于clock enable控制的与门;使用clock的硬件模块(可称作consumer);等等.common clock framework的管理对象,就是上图蓝色字体描述的clock(在软件中用struct clk抽象,以后就简称clk),主要内容包括(不需要所有clk都支持):
1)enable/disable clk。
2)设置clk的频率。
3)选择clk的parent,例如hw3_clk可以选择osc_clk、pll2_clk或者pll3_clk作为输入源.

clk framework是内核中用来统一管理clock的子系统。代码存在于kernel/driver/clk目录中。 要使用clkframework来实现厂商自己平台上的clock驱动,首先需要在defconfig中使能如下的几个CONFIG来配置内核。
CONFIG_CLKDEV_LOOKUP=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_DEBUG=y
如果配置了debug ,内核将生成相应的debugfs,在启动后将会挂载于/sys/kernel/debug目录下。
内核中clk framework 主要提供的功能有:

1. 向上提供给其他driver调用的接口API2.  向下提供给clock driver注册的接口API3.  debugfs创建4.  若干个基于dts配置的通用clock模型(通过调用注册接口API)

这里写图片描述
上图中的黄色区域都是clk core所实现的功能,灰色区域是clock驱动开发需要做的事情,而绿色区域是其他device driver需要使用clock时要调用到的clk功能。

为其他设备驱动提供的接口(API)
struct clk *clk_get(struct device *dev, const char *id);
struct clk *devm_clk_get(struct device *dev, const char *id);
int clk_enable(struct clk *clk);
void clk_disable(struct clk *clk);
unsigned long clk_get_rate(struct clk *clk);
void clk_put(struct clk *clk);
long clk_round_rate(struct clk *clk, unsigned long rate);
int clk_set_rate(struct clk *clk, unsigned long rate);
int clk_set_parent(struct clk *clk, struct clk *parent);
struct clk *clk_get_parent(struct clk *clk);
int clk_prepare(struct clk *clk);
void clk_unprepare(struct clk *clk);
这些都是比较重要的api接口,主要是在device driver中调用来设置device的clk的。这部分的实现最终会调用到clk_ops中的回调函数来设置硬件并且会更新core中的clk链表.作为一个clk设备,它有可能会改变rate,那么作为device driver的一方需要获取到这个改变,并作出相应的响应,那么就可以通过通知功能的接口来实现,我们可以在感兴趣的clk上注册notifier_block,然后当该clk的rate发生了改变的时候会通过__clk_notify,通知到相应的回调函数,来做相应的处理。
int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);

clk 设备驱动
1.几个重要的结构体,具体的结构可以参看内核源码。
clk_hw,clk_init_data ,clk_ops
clk
clk_hw结构体可以看到其中封装了一个clk_ops结构体,它是一个clk驱动需要实现的关键结构,厂商需要实现此结构体,并把它注册到clk framework。clk_hw是联系clk_ops和struct clk的纽带。它一般会被封装到一个厂商自己定义的更大的结构体中,主要是用来建立与struct clk的联系。
clk主要是用来抽象clk硬件的差异,并完成一些通用操作的封装。其中的hw成员变量是与之关联的clk_hw结构。