clk子系统 - 驱动框架

clk子系统负责为整个系统硬件提供时钟信号,这个要和linux的时钟系统区别开来;现在的ASoC上包含许多clk模块,比如晶振,pll,divider等,那么clk子系统就把这些模块抽象出来,并形成一个驱动框架,这样对于其他驱动开发人员来说,只需要调用通用的接口就能操作各自设备的clk,没必要从上到下重新配置clk

1.驱动框架

这里写图片描述
clk驱动框架如上图,API层是提供操作clk的通用接口,CORE层是抽象各个clk设备为一个对象加入到框架中,HARDWARE层主要是为不同的clk设备生成一个对象,最后会加入到一个clk链表:

static HLIST_HEAD(clk_root_list);
static HLIST_HEAD(clk_orphan_list);

如果你是个根设备那个就加入clk_root_list,其他的clk设备加入到clk_orphan_list,它们的关系如下图:

这里写图片描述

2.相关结构体及关系

2.1 struct clk

struct clk {
    const char      *name;
    const struct clk_ops    *ops;
    struct clk_hw       *hw;
    struct clk      *parent;
    const char      **parent_names;
    struct clk      **parents;
    u8          num_parents;
    u8          new_parent_index;
    unsigned long       rate;
    unsigned long       new_rate;
    struct clk      *new_parent;
    struct clk      *new_child;
    unsigned long       flags;
    unsigned int        enable_count;
    unsigned int        prepare_count;
    struct hlist_head   children;
    struct hlist_node   child_node;
    unsigned int        notifier_count;

    void            *private_data;
#ifdef CONFIG_COMMON_CLK_DEBUG
    struct dentry       *dentry;
#endif
};

clk结构体是clk子系统的主要结构体,每个clk设备都会抽象为一个clk结构体,这个结构体构建了clk的拓扑关系

2.2 struct clk_hw

struct clk_hw {
    struct clk *clk;
    const struct clk_init_data *init;
};

clk_hw为不同的clk设备到统一的clk设备搭建桥梁,通过clk_hw就能找到clk_fixed_rate/clk_gate/clk_divider…;比如要找到clk_gate,就可以通过以下宏定义实现:

#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)

2.3clk的相关操作函数ops

struct clk_ops {
    int     (*prepare)(struct clk_hw *hw);
    void        (*unprepare)(struct clk_hw *hw);
    int     (*is_prepared)(struct clk_hw *hw);
    void        (*unprepare_unused)(struct clk_hw *hw);
    int     (*enable)(struct clk_hw *hw);
    void        (*disable)(struct clk_hw *hw);
    int     (*is_enabled)(struct clk_hw *hw);
    void        (*disable_unused)(struct clk_hw *hw);
    unsigned long   (*recalc_rate)(struct clk_hw *hw,
                    unsigned long parent_rate);
    long        (*round_rate)(struct clk_hw *hw, unsigned long,
                    unsigned long *);
    long        (*determine_rate)(struct clk_hw *hw, unsigned long rate,
                    unsigned long *best_parent_rate,
                    struct clk **best_parent_clk);
    int     (*set_parent)(struct clk_hw *hw, u8 index);
    u8      (*get_parent)(struct clk_hw *hw);
    int     (*set_rate)(struct clk_hw *hw, unsigned long,
                    unsigned long);
    void        (*init)(struct clk_hw *hw);
};

这些操作函数不是每种clk设备都会用到,对于特定的设备只会用到其对应的操作函数,下表总结为:
“y”表示会用到,”-“表示看情况

opsclk_fixed_rateclk_gateclk_dividerclk_muxclk_fixed_factorclk_composite
prepare-
unprepare-
is_prepared-
unprepare_unused-
enabley-
disabley-
is_enabledy-
disable_unused-
recalc_rateyyy-
round_rateyy-
determine_ratey-
set_parenty-
get_parenty-
set_rateyy-

clk源代码在目录drivers/clk:
core的代码源文件为:clkdev.c ,clk-devres.c, clk.c,还有hardware相关的源文件:

clk_fixed_rateclk_gateclk_dividerclk_muxclk_fixed_factorclk_composite
clk-fixed-rate.cclk-gate.cclk-divider.cclk-mux.cclk-fixed-factor.cclk-composite.c

3.clk通用函数接口介绍

这些通用函数接口在头文件include/linux/clk.h中:
clk的打开与关闭:

int clk_enable(struct clk *clk);
void clk_disable(struct clk *clk);
static inline int clk_prepare_enable(struct clk *clk);
static inline void clk_disable_unprepare(struct clk *clk);

clk设备频率:

int clk_set_rate(struct clk *clk, unsigned long rate);
long clk_round_rate(struct clk *clk, unsigned long rate);
unsigned long clk_get_rate(struct clk *clk);

当然还有其他的接口,具体请参考源文件

ref.

linux3.1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值