当前位置: 首页 > news >正文

Linux内核4.14版本——ccf时钟子系统(5)——通用API

1. clk_get

1.1 __of_clk_get_by_name

1.2 clk_get_sys

2. clk_prepare_enable

2.1 clk_prepare

2.2 clk_enable

3. clk_set_rate


1. clk_get

        clock get是通过clock名称获取struct clk指针的过程,由clk_get、devm_clk_get、clk_get_sys、of_clk_get、of_clk_get_by_name、of_clk_get_from_provider等接口负责实现,这里以clk_get为例,分析其实现过程(位于drivers/clk/clkdev.c中)。

struct clk *clk_get(struct device *dev, const char *con_id)
{const char *dev_id = dev ? dev_name(dev) : NULL;struct clk *clk;if (dev) {clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)return clk;}return clk_get_sys(dev_id, con_id);
}

       该函数用于从目标设备上获取指定标识符的时钟。
       (1)它首先尝试从设备树中获取时钟硬件(通过of_clk_get_hw函数),
       (2)如果成功或者返回-EPROBE_DEFER(延迟探测)时,将创建并返回一个表示时钟的struct clk结构体指针。
       (3)如果在设备树中未找到时钟硬件,将调用clk_get_sys函数尝试从系统时钟表中获取时钟。

1.1 __of_clk_get_by_name

static struct clk *__of_clk_get_by_name(struct device_node *np,const char *dev_id,const char *name)
{struct clk *clk = ERR_PTR(-ENOENT);/* Walk up the tree of devices looking for a clock that matches */while (np) {int index = 0;/** For named clocks, first look up the name in the* "clock-names" property.  If it cannot be found, then* index will be an error code, and of_clk_get() will fail.*/if (name)index = of_property_match_string(np, "clock-names", name);clk = __of_clk_get(np, index, dev_id, name);if (!IS_ERR(clk)) {break;} else if (name && index >= 0) {if (PTR_ERR(clk) != -EPROBE_DEFER)pr_err("ERROR: could not get clock %pOF:%s(%i)\n",np, name ? name : "", index);return clk;}/** No matching clock found on this node.  If the parent node* has a "clock-ranges" property, then we can try one of its* clocks.*/np = np->parent;if (np && !of_get_property(np, "clock-ranges", NULL))break;}return clk;
}

      最终调用__of_clk_get-->__of_clk_get_from_provider,__of_clk_get_from_provider函数我们后面介绍。

1.2 clk_get_sys

struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{struct clk_lookup *cl;struct clk *clk = NULL;mutex_lock(&clocks_mutex);cl = clk_find(dev_id, con_id);if (!cl)goto out;clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);if (IS_ERR(clk))goto out;if (!__clk_get(clk)) {__clk_free_clk(clk);cl = NULL;goto out;}out:mutex_unlock(&clocks_mutex);return cl ? clk : ERR_PTR(-ENOENT);
}

1.2.1 clk_find

/** Find the correct struct clk for the device and connection ID.* We do slightly fuzzy matching here:*  An entry with a NULL ID is assumed to be a wildcard.*  If an entry has a device ID, it must match*  If an entry has a connection ID, it must match* Then we take the most specific entry - with the following* order of precedence: dev+con > dev only > con only.*/
static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
{struct clk_lookup *p, *cl = NULL;int match, best_found = 0, best_possible = 0;if (dev_id)best_possible += 2;if (con_id)best_possible += 1;list_for_each_entry(p, &clocks, node) {match = 0;if (p->dev_id) {if (!dev_id || strcmp(p->dev_id, dev_id))continue;match += 2;}if (p->con_id) {if (!con_id || strcmp(p->con_id, con_id))continue;match += 1;}if (match > best_found) {cl = p;if (match != best_possible)best_found = match;elsebreak;}}return cl;
}static LIST_HEAD(clocks);

       clk_find从系统时钟链表中查找已经注册的时钟,这些时钟是通过函数clk_register_clkdev注册的。

2. clk_prepare_enable

/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
static inline int clk_prepare_enable(struct clk *clk)
{int ret;ret = clk_prepare(clk);if (ret)return ret;ret = clk_enable(clk);if (ret)clk_unprepare(clk);return ret;
}

2.1 clk_prepare

        clk_prepare--->clk_core_prepare_lock--->clk_core_prepare

static int clk_core_prepare(struct clk_core *core)
{int ret = 0;lockdep_assert_held(&prepare_lock);if (!core)return 0;if (core->prepare_count == 0) {// 递归调用 clk_core_prepare 准备时钟源的父时钟ret = clk_core_prepare(core->parent);if (ret)return ret;// 跟踪时钟准备操作trace_clk_prepare(core);// 调用时钟源操作函数的 prepare 函数if (core->ops->prepare)ret = core->ops->prepare(core->hw);// 跟踪时钟准备完成trace_clk_prepare_complete(core);if (ret) {clk_core_unprepare(core->parent);return ret;}}// 增加时钟准备计数core->prepare_count++;return 0;
}

         clk_core_prepare 函数用于准备时钟源。它可能会睡眠,这与 clk_enable 不同。在简单的情况下,如果操作可能会睡眠,可以使用 clk_core_prepare 替代 clk_enable 来启用时钟。在复杂的情况下,时钟解锁操作可能需要一个快速和一个慢速部分。这就是 clk_core_prepare 和clk_enable 不是互斥的原因。实际上,必须在调用 clk_core_prepare 之前调用 clk_enable。

2.2 clk_enable

      enable也是差不多的操作这里不做介绍了。

3. clk_set_rate

      clk_set_rate --> clk_core_set_rate_nolock 

3.1 clk_core_set_rate_nolock 

static int clk_core_set_rate_nolock(struct clk_core *core,unsigned long req_rate)
{struct clk_core *top, *fail_clk;unsigned long rate = req_rate;if (!core)return 0;/* bail early if nothing to do */if (rate == clk_core_get_rate_nolock(core))return 0;if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)return -EBUSY;/* calculate new rates and get the topmost changed clock */top = clk_calc_new_rates(core, rate);if (!top)return -EINVAL;/* notify that we are about to change rates */fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);if (fail_clk) {pr_debug("%s: failed to set %s rate\n", __func__,fail_clk->name);clk_propagate_rate_change(top, ABORT_RATE_CHANGE);return -EBUSY;}/* change the rates */clk_change_rate(top);core->req_rate = req_rate;return 0;
}

3.1.1 clk_calc_new_rates

3.1.2 clk_propagate_rate_change

3.1.3 clk_change_rate

http://www.lryc.cn/news/495048.html

相关文章:

  • 安装MySQL 5.7 亲测有效
  • 《Django 5 By Example》阅读笔记:p455-p492
  • Element-UI 官网的主题切换动画
  • Golang 构建学习
  • VM Virutal Box的Ubuntu虚拟机与windows宿主机之间设置共享文件夹(自动挂载,永久有效)
  • 分析 系统滴答时钟(tickClock),设置72MHz系统周期,如何实现1毫秒的系统时间?
  • C++优选算法十七 多源BFS
  • Mongodb入门到放弃
  • 青藤云安全携手财信证券,入选金融科技创新应用优秀案例
  • 在CentOS系统中安装工具包的时候报错的解决方法
  • cad软件打不开报错cad acbrandres dll加载失败
  • 14、保存与加载PyTorch训练的模型和超参数
  • 【前端开发】JS+Vuew3请求列表数据并分页
  • Trimble X12助力电力管廊数据采集,为机器人巡视系统提供精准导航支持
  • Docker 清理镜像策略详解
  • 【Linux】TCP网络编程
  • 排序学习整理(2)
  • AI蛋白质设计与人工智能药物设计
  • IOS ARKit进行图像识别
  • 初级数据结构——二叉搜索树
  • C++设计模式之组合模式中如何实现同一层部件的有序性
  • duxapp RN 端使用AppUpgrade 进行版本更新
  • 【计网】自定义序列化反序列化(三) —— 实现网络版计算器【下】
  • 神经网络中的优化方法(一)
  • Linux 计算机网络基础概念
  • qt QGraphicsEllipseItem详解
  • Python websocket
  • 【MySQL-5】MySQL的内置函数
  • 深度学习笔记之BERT(三)RoBERTa
  • C++知识点总结(59):背包型动态规划