1. 程式人生 > >clk子系統 - 驅動框架

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”表示會用到,”-“表示看情況

ops clk_fixed_rate clk_gate clk_divider clk_mux clk_fixed_factor clk_composite
prepare -
unprepare -
is_prepared -
unprepare_unused -
enable y -
disable y -
is_enabled y -
disable_unused -
recalc_rate y y y -
round_rate y y -
determine_rate y -
set_parent y -
get_parent y -
set_rate y y -

clk原始碼在目錄drivers/clk:
core的程式碼原始檔為:clkdev.c ,clk-devres.c, clk.c,還有hardware相關的原始檔:

clk_fixed_rate clk_gate clk_divider clk_mux clk_fixed_factor clk_composite
clk-fixed-rate.c clk-gate.c clk-divider.c clk-mux.c clk-fixed-factor.c clk-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