Linux内核5.10.24下PCF8563 RTC CLKOUT配置问题求助
问题详情
我正在开发基于Linux内核5.10.24的嵌入式系统,系统搭载PCF8563 RTC,其CLKOUT引脚连接至其他硬件逻辑。我需配置PCF8563的CLKOUT输出速率,但未找到对应用户态API。经搜索得知可通过内核模块调用clk_get()和clk_set_rate()实现,遂编写如下内核模块:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/clk.h> static struct clk *rtc_clk; static int __init rtc_module_init(void) { int ret; rtc_clk = clk_get(NULL, "pcf8563"); // Get the RTC of the name if (IS_ERR(rtc_clk)) { ret = PTR_ERR(rtc_clk); printk(KERN_ERR "Failed to get RTC clock: %d\n", ret); return ret; } unsigned long rate = clk_get_rate(rtc_clk); printk(KERN_INFO "Current RTC clock rate: %lu Hz\n", rate); unsigned long new_rate = 32768; ret = clk_set_rate(rtc_clk, new_rate); if (ret < 0) { printk(KERN_ERR "Failed to set RTC clock rate: %d\n", ret); return ret; } rate = clk_get_rate(rtc_clk); printk(KERN_INFO "Updated RTC clock rate: %lu Hz\n", rate); return 0; } static void __exit rtc_module_exit(void) { if (rtc_clk) clk_put(rtc_clk); } module_init(rtc_module_init); module_exit(rtc_module_exit); MODULE_LICENSE("GPL");
加载模块时出现错误:Failed to get RTC clock: -2
系统中RTC的设备树配置如下:
rtc_pcf8563:rtc_pcf8563@51{ compatible = "nxp,pcf8563"; reg = <0x51>; status = "okay"; }
同时查看PCF8563驱动代码发现如下定义:
static const struct clk_ops pcf8563_clkout_ops = { .prepare = pcf8563_clkout_prepare, .unprepare = pcf8563_clkout_unprepare, .is_prepared = pcf8563_clkout_is_prepared, .recalc_rate = pcf8563_clkout_recalc_rate, .round_rate = pcf8563_clkout_round_rate, .set_rate = pcf8563_clkout_set_rate, }; static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) { struct i2c_client *client = pcf8563->client; struct device_node *node = client->dev.of_node; struct clk *clk; struct clk_init_data init; int ret; unsigned char buf; /* disable the clkout output */ buf = 0; ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); if (ret < 0) return ERR_PTR(ret); init.name = "pcf8563-clkout"; init.ops = &pcf8563_clkout_ops; init.flags = 0; init.parent_names = NULL; init.num_parents = 0; pcf8563->clkout_hw.init = &init; /* optional override of the clockname */ of_property_read_string(node, "clock-output-names", &init.name); /* register the clock */ clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); return clk; }
我想知道:
- 调用
clk_get(NULL, ???)时应传入什么名称? - 这些驱动中的函数在Linux中如何调用?
- 系统启用PCF8563的CLKOUT应如何操作?
- 是否存在调用这些函数的用户态接口?
解答
1. clk_get的正确名称
从驱动代码可以看到:
- 默认注册的时钟名称是
pcf8563-clkout - 如果设备树中添加
clock-output-names属性,会覆盖默认名称
你有两种选择:
- 直接使用默认名称修改模块中的
clk_get调用:rtc_clk = clk_get(NULL, "pcf8563-clkout"); - 或者在设备树中自定义名称,比如:
此时rtc_pcf8563:rtc_pcf8563@51{ compatible = "nxp,pcf8563"; reg = <0x51>; status = "okay"; clock-output-names = "my-pcf8563-clk"; }clk_get传入"my-pcf8563-clk"即可。
2. 驱动中函数的调用方式
你看到的pcf8563_clkout_register_clk和pcf8563_clkout_ops下的函数都是内核驱动内部接口,不需要手动调用:
pcf8563_clkout_register_clk会在PCF8563驱动的probe函数中自动执行,设备树配置正确、驱动加载成功后,就会完成CLKOUT时钟的注册pcf8563_clkout_ops中的函数是时钟框架的回调,当你调用clk_set_rate、clk_prepare等上层时钟API时,内核会自动调用这些底层实现函数
3. 启用PCF8563的CLKOUT操作
现有模块仅设置了速率,未启用时钟输出,完整步骤如下:
- 修正
clk_get的名称,成功获取时钟句柄 - 设置目标速率(调用
clk_set_rate) - 启用时钟输出:调用
clk_prepare_enable(触发驱动中的pcf8563_clkout_prepare,完成CLKOUT引脚的启用配置)
修改后的模块初始化函数示例:
static int __init rtc_module_init(void) { int ret; rtc_clk = clk_get(NULL, "pcf8563-clkout"); if (IS_ERR(rtc_clk)) { ret = PTR_ERR(rtc_clk); printk(KERN_ERR "Failed to get RTC clock: %d\n", ret); return ret; } unsigned long rate = clk_get_rate(rtc_clk); printk(KERN_INFO "Current RTC clock rate: %lu Hz\n", rate); unsigned long new_rate = 32768; ret = clk_set_rate(rtc_clk, new_rate); if (ret < 0) { printk(KERN_ERR "Failed to set RTC clock rate: %d\n", ret); clk_put(rtc_clk); return ret; } // 启用CLKOUT输出 ret = clk_prepare_enable(rtc_clk); if (ret < 0) { printk(KERN_ERR "Failed to enable RTC clock: %d\n", ret); clk_put(rtc_clk); return ret; } rate = clk_get_rate(rtc_clk); printk(KERN_INFO "Enabled RTC clock rate: %lu Hz\n", rate); return 0; } static void __exit rtc_module_exit(void) { if (rtc_clk) { clk_disable_unprepare(rtc_clk); clk_put(rtc_clk); } }
注意:PCF8563的CLKOUT仅支持固定几种速率(32768Hz、1024Hz、32Hz、1Hz),clk_set_rate会自动匹配最接近的支持速率,可通过clk_round_rate先确认实际能设置的速率。
4. 用户态接口情况
Linux内核没有提供直接控制PCF8563 CLKOUT的标准用户态API,但可通过两种方式实现用户态控制:
- 利用sysfs时钟接口:内核时钟框架会在
/sys/class/clk/下生成对应时钟的节点,比如/sys/class/clk/pcf8563-clkout/,可通过读写其中的rate、enable文件来设置速率和启用/禁用时钟(需内核开启CONFIG_SYSFS和CONFIG_COMMON_CLK) - 自定义内核模块提供用户态接口:在你的内核模块中添加sysfs节点或字符设备,实现用户态到内核时钟API的转发,比如通过读写sysfs文件触发
clk_set_rate和clk_prepare_enable操作
内容的提问来源于stack exchange,提问作者wangt13
相关产品推荐
相关产品推荐

