Linux 内核中 RTC 驱动的注册方式
在 Linux 内核中,RTC(Real-Time Clock)驱动的注册可以通过多种方式实现,以下整理了常见的注册方式及其注意事项。
1. 使用 devm_rtc_device_register
这是注册 RTC 驱动的最常用方法,基于设备资源管理(devm_
)机制,能够自动管理资源释放。
示例代码
#include <linux/rtc.h>static int rtc_read_time(struct device *dev, struct rtc_time *tm) {// 模拟读取时间tm->tm_sec = 30;tm->tm_min = 15;tm->tm_hour = 10;tm->tm_mday = 25;tm->tm_mon = 5;tm->tm_year = 123; // 表示 2023 年return 0;
}static int rtc_set_time(struct device *dev, struct rtc_time *tm) {// 模拟设置时间pr_info("Setting time: %d:%d:%d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);return 0;
}static const struct rtc_class_ops rtc_ops = {.read_time = rtc_read_time,.set_time = rtc_set_time,
};static int rtc_probe(struct platform_device *pdev) {struct rtc_device *rtc;rtc = devm_rtc_device_register(&pdev->dev, "rtc-name", &rtc_ops, THIS_MODULE);if (IS_ERR(rtc))return PTR_ERR(rtc);return 0;
}
适用场景
- 驱动逻辑较简单。
- 希望简化资源管理工作。
注意事项
- 必须确保设备正确传递到
devm_
机制中。 - 如果需要手动释放资源,请使用
rtc_device_register
。
2. 使用 rtc_device_register
相比 devm_rtc_device_register
,此方法需要手动管理资源,适用于需要更高资源控制的场景。
示例代码
#include <linux/rtc.h>static int rtc_read_time(struct device *dev, struct rtc_time *tm) {// 模拟读取时间tm->tm_sec = 30;tm->tm_min = 15;tm->tm_hour = 10;tm->tm_mday = 25;tm->tm_mon = 5;tm->tm_year = 123; // 表示 2023 年return 0;
}static int rtc_set_time(struct device *dev, struct rtc_time *tm) {// 模拟设置时间pr_info("Setting time: %d:%d:%d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);return 0;
}static const struct rtc_class_ops rtc_ops = {.read_time = rtc_read_time,.set_time = rtc_set_time,
};struct rtc_device *rtc;rtc = rtc_device_register("rtc-name", dev, &rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))return PTR_ERR(rtc);/* 在 remove 或出错路径中释放资源 */
rtc_device_unregister(rtc);
适用场景
- 驱动需要复杂的初始化逻辑。
- 不希望依赖
devm_
机制。
注意事项
- 在驱动卸载时需手动调用
rtc_device_unregister
释放资源。 - 避免资源泄漏。
3. 通过设备树或 ACPI 自动绑定
当 RTC 设备通过设备树或 ACPI 描述时,可以自动绑定到对应的驱动。
示例设备树
rtc@10000000 {compatible = "vendor,rtc";reg = <0x10000000 0x100>;
};
示例驱动代码
static int rtc_read_time(struct device *dev, struct rtc_time *tm) {// 模拟读取时间tm->tm_sec = 30;tm->tm_min = 15;tm->tm_hour = 10;tm->tm_mday = 25;tm->tm_mon = 5;tm->tm_year = 123; // 表示 2023 年return 0;
}static int rtc_set_time(struct device *dev, struct rtc_time *tm) {// 模拟设置时间pr_info("Setting time: %d:%d:%d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);return 0;
}static const struct rtc_class_ops rtc_ops = {.read_time = rtc_read_time,.set_time = rtc_set_time,
};static int rtc_probe(struct platform_device *pdev) {struct rtc_device *rtc;rtc = devm_rtc_device_register(&pdev->dev, "rtc-name", &rtc_ops, THIS_MODULE);if (IS_ERR(rtc))return PTR_ERR(rtc);return 0;
}
适用场景
- 嵌入式系统中常见。
- RTC 资源通过设备树或 ACPI 描述。
注意事项
- 确保
compatible
字段与驱动匹配。 - 驱动需正确处理资源获取和释放。
4. 使用 rtc_class
适用于创建自定义 RTC 类设备的场景。
示例代码
#include <linux/rtc.h>
#include <linux/device.h>struct class *rtc_class;
struct device *rtc_dev;rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class))return PTR_ERR(rtc_class);rtc_dev = device_create(rtc_class, NULL, MKDEV(0, 0), NULL, "rtc0");
if (IS_ERR(rtc_dev)) {class_destroy(rtc_class);return PTR_ERR(rtc_dev);
}/* 在退出时清理资源 */
device_destroy(rtc_class, MKDEV(0, 0));
class_destroy(rtc_class);
适用场景
- 自定义 RTC 类设备。
- 需要特殊行为的 RTC 设备。
注意事项
- 必须手动管理资源,避免资源泄漏。
- 需要显式调用
class_destroy
和device_destroy
。
注意事项
-
选择合适的注册方式:
- 简单驱动可用
devm_rtc_device_register
。 - 需要手动控制资源时选择
rtc_device_register
。 - 测试或模拟设备时使用设备树或 ACPI 自动绑定。
- 简单驱动可用
-
设备树支持:确保设备树描述与驱动匹配。
-
资源管理:
- 使用
devm_
接口时资源自动管理。 - 手动注册时注意清理资源。
- 使用
-
兼容性:
- 检查硬件是否支持 RTC。
- 根据具体硬件接口(I2C、SPI、平台设备)选择正确的实现方式。
-
功能扩展:可根据需求增加闹钟功能、中断支持等。