linux clk

内核:3.4

平台:allwinner

涉及的主要文件有

include/linux/clk.h

drivers/clk/clkdev.c

drivers/clk/clk.c

arch/rlx/bsp/clock.c


1、 clk通用接口

内核定义了一套标准的接口(include/linux/clk.h),用于所有的平台之上。每个时钟源对象使用一个struct clk结构来表示。而struct clk结构的具体内容由各平台自己定义。clk.h头文件定义了操作一个clk对象的所有接口。内核的其他地方可以也只能使用clk.h中提供的这些接口函数来操作clk。

  1. struct clk *clk_get(struct device *dev, const char *id);  
  2. int clk_enable(struct clk *clk);  
  3. void clk_disable(struct clk *clk);  
  4. unsigned long clk_get_rate(struct clk *clk);  
  5. void clk_put(struct clk *clk);  
  6. long clk_round_rate(struct clk *clk, unsigned long rate);  
  7. int clk_set_rate(struct clk *clk, unsigned long rate);  
  8. int clk_set_parent(struct clk *clk, struct clk *parent);  
  9. struct clk *clk_get_parent(struct clk *clk);  
  10. struct clk *clk_get_sys(const char *dev_id, const char *con_id);  
  11. int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, struct device *dev);  
struct clk *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);
struct clk *clk_get_sys(const char *dev_id, const char *con_id);
int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, struct device *dev);


2、这些操作的具体实现在/arch/rlx/bsp/clock.c文件

  1. static const struct clk_ops rlx_divider_ops = {  
  2.     .enable      = rlx_enable_clk,  
  3.     .disable     = rlx_disable_clk,  
  4.     .round_rate  = rlx_round_rate,  
  5.     .set_rate    = rlx_set_rate,  
  6.     .set_parent  = rlx_set_parent,  
  7.     .get_parent  = rlx_get_parent,  
  8.     .recalc_rate = rlx_recalc,  
  9. };  
static const struct clk_ops rlx_divider_ops = {
	.enable      = rlx_enable_clk,
	.disable     = rlx_disable_clk,
	.round_rate  = rlx_round_rate,
	.set_rate    = rlx_set_rate,
	.set_parent  = rlx_set_parent,
	.get_parent  = rlx_get_parent,
	.recalc_rate = rlx_recalc,
};
通过一个宏DEFINE_CLK_RLX将这个clk_ops赋值给struct clk结构体中的ops

  1. #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name)    \  
  2.     static struct clk _name = {                \  
  3.         .name = #_name,                    \  
  4.         .hw = &_name##_hw.hw,                \  
  5.         .parent_names = _parent_array_name,        \  
  6.         .num_parents = ARRAY_SIZE(_parent_array_name),    \  
  7.         .ops = &_clkops_name,                \  
  8.     };  
  9.   
  10. #define DEFINE_CLK_RLX(_name, _clksel,  \  
  11.                 _clksel_reg, _clk_change, _parent_names, _ops) \  
  12.     static struct clk _name;                \  
  13.     static struct clk_hw_rlx _name##_hw = {     \  
  14.         .hw = {                     \  
  15.             .clk = &_name,              \  
  16.         },                      \  
  17.         .clksel = _clksel,          \  
  18.         .clkreg = (void __iomem *)_clksel_reg,          \  
  19.         .clk_change = _clk_change,          \  
  20.     };                          \  
  21.     DEFINE_STRUCT_CLK(_name, _parent_names, _ops);  
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name)    \
    static struct clk _name = {                \
        .name = #_name,                    \
        .hw = &_name##_hw.hw,                \
        .parent_names = _parent_array_name,        \
        .num_parents = ARRAY_SIZE(_parent_array_name),    \
        .ops = &_clkops_name,                \
    };

#define DEFINE_CLK_RLX(_name, _clksel,	\
			    _clksel_reg, _clk_change, _parent_names, _ops) \
	static struct clk _name;				\
	static struct clk_hw_rlx _name##_hw = {		\
		.hw = {						\
			.clk = &_name,				\
		},						\
		.clksel	= _clksel,			\
		.clkreg	= (void __iomem	*)_clksel_reg,			\
		.clk_change	= _clk_change,			\
	};							\
	DEFINE_STRUCT_CLK(_name, _parent_names, _ops);
  1. DEFINE_CLK_RLX(i2c_ck, 0, I2C_CLK_CFG_REG, I2C_CLK_CHANGE, rlx_ck_parent_names,rlx_divider_ops);  
DEFINE_CLK_RLX(i2c_ck, 0, I2C_CLK_CFG_REG, I2C_CLK_CHANGE, rlx_ck_parent_names,rlx_divider_ops);
其中ic2_ck是struct clk结构体,这样就将rlx_divider_ops赋给了i2c_clk->ops


3、每个struct clk应该对应一个struct clk_lookup结构,有了他,就可以通过设备名或者时钟源的名字来找到相应的struct clk结构,链表操作位于/drivers/clk/clkdev.c

将每一个clk_lookup通过clkdev_add注册到系统中,其实在clkdev_add函数中是这么实现的

  1. void clkdev_add(struct clk_lookup *cl)  
  2. {  
  3.     mutex_lock(&clocks_mutex);  
  4.     list_add_tail(&cl->node, &clocks);  
  5.     mutex_unlock(&clocks_mutex);  
  6. }  
  7. EXPORT_SYMBOL(clkdev_add);  
void clkdev_add(struct clk_lookup *cl)
{
	mutex_lock(&clocks_mutex);
	list_add_tail(&cl->node, &clocks);
	mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clkdev_add);
就是将lookup节点添加到一个clocks为头的链表中去,其实相当于将struct clk添加到clocks链表中。


4、clk_get、clk_enable

通过/drivers/clk/clkdev.c文件中的clk_find函数在上面的clocks链表中找到匹配的clk_lookup,从而找到对应的struct clk,并返回struct clk

/drivers/clk/clk.c中的clk_enable最终调用的是clk中ops里的方法。


部分摘自:http://www.cnblogs.com/sammei/archive/2012/10/15/3295612.html



总结:

1、clk的注册


2、clk的使用

通常操作为以下几步:

1)定义struct clk *clk;

2)获取需要操作的clock结构体实例

clk=clk_get(&pdev->dev, "i2c_clk");

3)设置clock的source,最终频率由此分频得到

clk_set_parent(clk, clk_get(NULL, "usb_pll"));

4)设置频率

clk_set_rate(clk, 4000000);

5)产生时钟

clk_enable(clk);

6)停止时钟

clk_disable(clk);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值