I am working on an embedded Linux system (kernel-5.10.24).
And there is a PCF8563 RTC in system, its CLKOUT is connected to other hardware logic.
Now in Linux system, I want to configure the CLKOUT rate (it is configurable in PCF8563), but I did NOT find the user space API to do that.
By googling, I found it might be done in kernel module, with clk_get()
and clk_set_rate()
.
So I wrote a simple kernel module to do that, as follows,
#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");
When loading the module in Linux, I got error like this,
Failed to get RTC clock: -2
The device tree of RTC is as follows,
rtc_pcf8563:rtc_pcf8563@51{
compatible = "nxp,pcf8563";
reg = <0x51>;
status = "okay";
}
I am wondering what name should be passed to clk_get(NULL, ???)
?
I also checked the PCF8563 driver, found following definition.
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;
}
So, how do these functions being called in Linux? Or if a system wants to enable the CLKOUT of PCF8563, how to do that? Is there any user space interface to call these functions in Linux?