硬件资源越来越庞大和复杂,内核的另一个挑战就是要便捷的管理这些资源。同时,面对如此之多的平台不同的CPU,管理机制需要统一适用,这就需要对资源的管理抽象到更加通用的层次。CPU中各个模块都需要时钟驱动,内核需要一种机制能通用所有的平台,方便的管理CPU上所有的clk资源。这里分析Linux对clk的管理。
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,
  12. struct device *dev);

struct clk

clk结构体是平台相关的。在arch/arm/mach-mx5/clock.c中会预先描述CPU中所有的clk对象。

  • parent - clk是由parent分出来的。那么如果parent关闭了,当前clk也就没有了。
  • secondary - 第二时钟源,用于enable/disable当前clk。
  • usecount - 引用计数。
  • get_rate, set_rate, enable, disable, set_parent - 很显然,这些函数指针指到实际操作的函数。clk.h中的各接口函数最后都会调用到这里的函数指针。函数指针是隔离变化的最好办法,在这里一下就把层次抽象出来了。

2. clocks链表

arch/arm/mach-mx5/clock.c中不仅定义了所有的clk对象,而且每个clk对象还要对应一个struct clk_lookup结构。在初始化时,会将所有的clk_loopup结构添加进入clocks链表中。

  1. struct clk_lookup {
  2. struct list_head    node;
  3. const char      *dev_id;
  4. const char      *con_id;
  5. struct clk      *clk;
  6. };

clk_lookup,顾名思义就知道它是用来查找struct clk结构的。有了它,就可以通过设备名或时钟源的名字来找到相应的struct clk结构。链表操作位于drivers/clk/clkdev.c

3. clk平台通用操作

arch/arm/plat-mxc/clock.c源文件中定义了mxc平台clock的通用操作接口。

enable/disable函数中可以看到引用计数usecount的作用。一个clk只有当其usecount为0的时候才会做实际的打开动作,也只有usecount为0时才能确认没有被任何其他设备使用,可以禁止了。层次关系被递归调用和引用计数巧妙的实现。

  1. static void __clk_disable(struct clk *clk)
  2. {
  3. if (clk == NULL || IS_ERR(clk))
  4. return;
  5. WARN_ON(!clk->usecount);
  6. if (!(--clk->usecount)) {
  7. if (clk->disable)
  8. clk->disable(clk);
  9. __clk_disable(clk->secondary);
  10. __clk_disable(clk->parent);
  11. }
  12. }
  13. static int __clk_enable(struct clk *clk)
  14. {
  15. if (clk == NULL || IS_ERR(clk))
  16. return -EINVAL;
  17. if (clk->usecount++ == 0) {
  18. __clk_enable(clk->parent);
  19. __clk_enable(clk->secondary);
  20. if (clk->enable)
  21. clk->enable(clk);
  22. }
  23. return 0;
  24. }

4. clk与pm

为了省电,当不需要clk时将其关闭,上面的clk_enable/clk_disable实现了此功能。除了关闭clk省电,还可以降低clk频率以达到省电的目的。当系统当前负载较轻,不需要clk跑在那么高的频率时,就可以对该clk降频了。从这些关系可以看到,clk与电源管理,cpufreq等都可能有关联。

5.使用

1.定义struct clk *clk;

2.获取需要操作的clock结构体 clk=clk_get(&pdev->dev, "pclk"); /* 第一个参数一般取NULL */
3.设置频率 clk_set_rate(clk); /* 返回时钟频率 */
4.产生时钟 clk_enable(clk);

5.停止时钟clk_disable(clk);

clk_get从一个时钟list链表中以字符id名称来查找一个时钟clk结构体并且返回,最后调用clk.enable(),来时能对应的外设时钟源。

clk_get_rate函数可以从clk_get得到的某设备结构体中获得该设备的时钟频率。

诸如watchdog等设备可以在类似arch/arm/plat-s3c24xx/S3c2410-clock.c 中找到。

static struct clk init_clocks[] = {{.name       = "lcd",.parent      = &clk_h,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_LCDC,}, {.name        = "gpio",.parent     = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_GPIO,}, {.name        = "usb-host",.parent     = &clk_h,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_USBH,}, {.name        = "usb-device",.parent       = &clk_h,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_USBD,}, {.name        = "timers",.parent       = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_PWMT,}, {.name        = "uart",.devname    = "s3c2410-uart.0",.parent       = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_UART0,}, {.name       = "uart",.devname    = "s3c2410-uart.1",.parent       = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_UART1,}, {.name       = "uart",.devname    = "s3c2410-uart.2",.parent       = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_UART2,}, {.name       = "rtc",.parent      = &clk_p,.enable       = s3c2410_clkcon_enable,.ctrlbit   = S3C2410_CLKCON_RTC,}, {.name     = "watchdog",.parent     = &clk_p,.ctrlbit  = 0,}, {.name      = "usb-bus-host",.parent     = &clk_usb_bus,}, {.name       = "usb-bus-gadget",.parent       = &clk_usb_bus,},
};

Linux时钟管理clk相关推荐

  1. Linux时钟管理clk devm_clk_get clk_prepare_enable等学习

    Linux时钟管理clk devm_clk_get clk_prepare_enable等学习 一.查看系统clk命令 cat d/clk/clk_summary 二.clock获取有关的API. s ...

  2. linux内核时钟管理,Linux时钟管理透彻分析

    Linux时钟管理透彻分析.硬件资源越来越庞大和复杂,内核的另一个挑战就是要便捷的管理这些资源.同时,面对如此之多的平台不同的CPU,管理机制需要统一适用,这就需要对资源的管理抽象到更加通用的层次.C ...

  3. Linux 时钟管理

    Linux 时钟管理 时钟管理是操作系统不可或缺的一个重要组成部分.无论是应用程序还是内核本身都在大量使用各种各样的timer.本文介绍了Linux操作系统曾经使用和现在正在使用的时钟管理机制,着重阐 ...

  4. Linux时钟管理clk_get函数透彻分析

    硬件资源越来越庞大和复杂,内核的另一个挑战就是要便捷的管理这些资源.同时,面对如此之多的平台不同的CPU ,管理机制需要统一适用,这就需要对资源的管理抽象到更加通用的层次.CPU中各个模块都需要时钟驱 ...

  5. Exynos4412的Linux时钟驱动开发(一)——Exynos4412的时钟管理单元CMU

    系列文章目录 Exynos4412的Linux时钟驱动开发(一)--Exynos4412的时钟管理单元CMU Exynos4412的Linux时钟驱动开发(二)--时钟驱动的初始化(CLK_OF_DE ...

  6. linux系统电源时钟,linux电源管理的一些梳理

    由于项目产品需要过能源之星3.0,所以最近做了一些电源管理低功耗方面的工作,抽个时间正好梳理一下. 其实Linux 电源管理非常复杂,牵扯到很多方面,比如系统级的待机.频率电压变换.系统空闲时的处理以 ...

  7. 【原创】xenomai+linux双内核下的时钟管理机制

    双内核下的时钟管理机制 版权声明:本文为本文为博主原创文章,转载请注明出处.如有问题,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 文章目录 双内核下的时钟管理 ...

  8. 基于RK3399分析Linux系统下的CPU时钟管理 - 第3篇

    1. 时钟系统结构 rockchip的时钟系统代码位于drivers/clk/rockchip,目录整体结构如下: ├── rockchip │ ├── clk.c---------------时钟系 ...

  9. Linux 驱动开发 三十五:Linux 内核时钟管理

    参考: linux时间管理,时钟中断,系统节拍_u010936265的博客-CSDN博客_系统节拍时钟中断 Linux内核时钟系统和定时器实现_anonymalias的专栏-CSDN博客_linux内 ...

最新文章

  1. 单文档程序创建的时候,标题栏的无标题怎么可以去掉,并且改成自己想要的字符...
  2. 总结一下MySQL中的锁机制
  3. JAVA泛型知识(一)
  4. python装饰器之函数作用域
  5. mac版有道云笔记切换笔记后内容仍展示前一个笔记内容问题解决
  6. Linux 之 CentOS 7.2 安装 Java JDK
  7. 正确修改LINUX SHELL的.bashrc,显示短路径
  8. spine 破解 闪退打不开
  9. 递归构造格雷码c语言,递归构造格雷码
  10. pr怎么导出预设_怎样用Pr导出清晰度高的视频?
  11. 2021租房合同样板
  12. 建模是什么,建模定义,及学习方法
  13. Esp8266(WIFI模块)刷阿里云固件
  14. 使用中文分词工具切分ArcGIS在线文档
  15. kotlin 原生字符串输出三个引号
  16. ecshop简化虚拟商品购买收货人信息【ECSHOP购物车不存在实体商品电话改为非必须以及隐藏掉】
  17. js简单的文本编辑器(所见即所得)
  18. wave.Error: unknown format: 3解决方法
  19. 行业解决方案|智慧检务:聚焦检察院工作数字化
  20. BZOJ4424: Cf19E Fairy

热门文章

  1. 无聊,几行python代码写一个聊天机器人陪你聊天
  2. jQuery选择器$()
  3. 排他思想 -- 百度换肤效果案例 以及 点击某按钮只是该按钮变色
  4. 三星android5 root包,三星 S5360的安卓 2.3.5系统 root成功
  5. mysql 经典操作_mysql常用经典操作
  6. java泡泡龙开源_2019级C语言大作业 - 泡泡龙
  7. 判断苹果黑条_【苹果iPhoneXR评测】黑边厚也是苹果的“无奈之举”_苹果 iPhone XR_手机评测-中关村在线...
  8. 大数据开发工程师都需要学什么?
  9. 浅论信息流广告与DSP营销推广的区别有哪些
  10. druid监控无法关闭(坑),及处理方式