Linux CommonClock Framework分析之三 驱动开发流程说明

         在上两篇文章中,我们简要介绍了CCF子系统内部的设计,并说明了CCF子系统内部数据结构的定义及关联。本篇文章主要介绍CCF子系统下驱动程序的开发,本章涉及如下三个方面的内容:

一、clk注册与注销接口说明

 

二、clk驱动开发流程

 

三、clk使用流程

 

四、依据clk provider用途封装的注册接口

 

一、clk注册与注销接口说明

     clk注册与注销接口分别为clk_register、clk_unregister,在上一章我们已经简要说过,clk_register主要实现一个clk provider的逻辑抽象对象struct clk_hw类型变量的创建、clk provider driver的创建(struct clk_core)、clk provider的操作接口、父子clk provider的关联等等信息。

clk注册接口实现的功能,大概可分为如下几个主要内容:

  1. 完成struct clk_core类型的变量的初始化,主要包括该clk provider driver的父节点个数及每个父节点的名称的设置、该clk provider的访问方法的设置,即完成struct clk_ops类型中各操作接口的注册,并对这些成员变量进行有效性判断(如设置了set_parent接口而没有设置get_parent接口,则认为参数不合法);
  2. 完成clk provider的
  3. 若该clk_core存在父节点,则将该clk_core插入到父节点的children链表中;
  4. 若该clk_core为root节点,则将该clk_core插入到clk_root_list链表中;
  5. 遍历链表clk_orphan_list中的clk_core,若其父节点为本次注册的节点,则将其从clk_orphan_list链表上移除,并加入到本次注册节点的children链表中;

主要就是完成该clk provider driver的访问方法、父节点、子节点设置,并最终完成下图的关联。

 

 

 

 

二、clk驱动开发流程

针对clk provider驱动的开发,主要涉及两部分内容:

  1. 完成clk的注册,主要是调用clk_register接口,完成上述章节一所述的内容;
  2. 完成该clk provider的map,这种map机制可以理解为定义了clk consumer与clk_provider的映射关系,即该clk provider可以给哪些clk consumer提供时钟(如针对非设备树模式,则定义了clk consumer的设备名称、clk consumer的时钟使用名称),而clk provider的map存在两种方式:
    1. 若linux不支持设备树机制,则通过调用接口clk_register_clkdev,完成这种映射操作(即完成下图中“非设备树模式下clk_core的map”)。
    2. 若linux支持设备树机制,则通过调用接口of_clk_add_provider,完成map操作(即完成下图中“设备树模式下clk_core的map”)

 

基本上完成上述两种操作即可实现clk驱动。

下面说明下这两种clk provider map机制对应的驱动开发:

  1. 针对不支持设备树机制,则通过调用接口clk_register_clkdev实现clk_core map,如下代码片段是bcm2835的初始化接口,首先调用clk_register_fixed_rate完成clk的注册,借助调用clk_register_clkdev完成clk的map操作,如定义了clk provider uart0_pclk供设备“20201000.uart”使用

 

  1. 针对支持设备树机制,则主要是在clk provider的驱动代码中通过调用接口of_clk_add_provider实现这种map操作,另外需要在设备树文件中描述该clk的一些注册信息,设备树涉及的用法如下:
    1. #clock-cells用于说明该clk的标识,若一个clock仅对外输出一路clock,则该值设备为0;若支持多路输出,则该值设置为1;
    2. clock-output-names用于说明一个clk provider输出多路clock的名称,clock consumer的设备树节点中提供的clock provider的标识是一个index,通过这个index可以在clock-output-names属性值中找到对应的输出clock provider的名字。
    3. clock-indices标识上述“clock-output-names”中的名称对应序号,若不设置该值,则上述clock-output-names的名称对应的序号是从0开始累加的,若设置了该值,则使用该值中的顺序。
    4. clock-frequency用于设置clock输出的时钟频率;

如下即定义了两个时钟,其中时钟源osc为时钟源pll的父时钟,而时钟源pll输出两路时钟(没有定义clock-indices,因此这两路时钟的需要分别为pll 0,pll 1,若外设驱动需要使用pll的第二路输出时钟,则在其设备驱动节点中定义clocks = <&pll 1>即可)。

 

三、clk使用流程

       clk的使用只需要调用接口clk_get即可获取一个struct clk类型的变量(可理解为一个clk consumer),而clk_get中传递了struct device类型的变量和con-id,依据这两个变量即可在上述图中的clk provider map链表中查找到对应的clk provider device,进而创建clk consumer device。因此clk的使用相对来说就简单了很多,主要是CCF子系统内部设计的比较好,因此对外提供的接口就比较简单。

 

四、依据clk provider用途封装的注册接口

     在上述章节二中我们已经说明了clk provider的注册接口,已经比较简单了。但CCF子系统又根据clk provider的用途进一步封装了clk provider的注册接口,相对来说进一步降低了clk provider driver的开发难度。在本专栏的第一篇文章中,我们介绍clk可分为提供基础时钟源的晶振(可分为有源晶振、无源晶振两种)、用于倍频的锁相环、用于分频的divider、用于多路时钟源选择的mux、用于时钟使能的与门电路等。因此CCF子系统针对这几种类型封装了对应的注册接口。此处仅对clk mux、clk gate进行简要说明。

clk mux注册接口

     针对多路时钟源选择的mux,CCF提供了clk mux的注册接口,该子模块主要实现针对clk mux的操作接口(提供了get_parent、set_parent、determine_rate接口),提供的注册函数为clk_register_mux,该接口内部封装了clk_register,并提供了通用的时钟源选择相关的操作接口,即clk_mux_ops。相关的结构体及clk_mux_ops的定义如下:

struct clk_mux {

struct clk_hw        hw;

void __iomem        *reg;

u32                *table;

u32                mask;

u8                shift;

u8                flags;

spinlock_t        *lock;

};

const struct clk_ops clk_mux_ops = {

.get_parent = clk_mux_get_parent,

.set_parent = clk_mux_set_parent,

.determine_rate = __clk_mux_determine_rate,

};

 

 

clk gate注册接口

针对时钟使能的与门电路,仅涉及使能与否,因此CCF子系统提供了一个clk gate的注册接口,并定义

了clk_gate结构体,该结构体主要定义了clk gate使能的寄存器、使能位、自旋锁等。

struct clk_gate {

struct clk_hw hw;

void __iomem        *reg;

u8                bit_idx;

u8                flags;

spinlock_t        *lock;

};

同时该clk gate模块提供了clk gate provider的操作接口,定义如下,提供了enable/disable接口

     然后提供了接口clk_register_gate进行注册,使用clk_register_gate进行clk provider的注册,不需要实现struct clk_ops中的接口。

 

 

 

以上即为本章的主要内容,主要介绍clk provider driver、 clk consumer实现等相关的内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值