STM32MP157驱动开发——Linux RTC驱动

STM32MP157驱动开发——Linux RTC驱动


参考文章:
【正点原子】STM32MP1嵌入式Linux驱动开发——RTC驱动

一、简介

  RTC设备驱动是一个标准的字符设备驱动,应用程序通过open、release、read、write和ioctl等函数完成对RTC设备的操作。Linux内核将RTC设备抽象为rtc_device结构体,因此RTC设备驱动就是申请并初始化rtc_device,最后将rtc_device注册到Linux内核里,这样Linux内核就有一个RTC设备。

二、驱动分析

STM32MP1 的 RTC 驱动已经由 ST 写好,这里仅对其做出简要分析。
先从设备树入手,在 stm32mp151.dtsi文件中,有如下 rtc 设备节点:

rtc: rtc@5c004000 {
	compatible = "st,stm32mp1-rtc";
	reg = <0x5c004000 0x400>;
	clocks = <&scmi0_clk CK_SCMI0_RTCAPB>,
			 <&scmi0_clk CK_SCMI0_RTC>;
	clock-names = "pclk", "rtc_ck";
	interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>;
	status = "disabled";
};

兼容属性 compatible 的值为“st,stm32mp1-rtc”,所以可以找到驱动文件为 drivers/rtc/rtc-stm32.c 文件。其中有如下内容:

......
static const struct of_device_id stm32_rtc_of_match[] = {
	{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
	{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
	{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data },
	{}
};
......
static struct platform_driver stm32_rtc_driver = {
	.probe		= stm32_rtc_probe,
	.remove		= stm32_rtc_remove,
	.driver		= {
		.name	= DRIVER_NAME,
		.pm	= &stm32_rtc_pm_ops,
		.of_match_table = stm32_rtc_of_match,
	},
};

module_platform_driver(stm32_rtc_driver);

stm32_rtc_of_match 为设备树 ID 表,compitable值匹配成功后就会使用本驱动。stm32_rtc_driver 为设备操作函数集,可以看出是一个标准的platform驱动框架,当设备和驱动匹配成功以后 stm32_rtc_probe 函数就会执行。
stm32_rtc_probe函数:

789 static int stm32_rtc_probe(struct platform_device *pdev)
790 {
791 	struct stm32_rtc *rtc;
792 	const struct stm32_rtc_registers *regs;
793 	struct resource *res;
794 	int ret;
795
796 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
797 	if (!rtc)
798 		return -ENOMEM;
799
800 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
801 	rtc->base = devm_ioremap_resource(&pdev->dev, res);
......
856 	ret = clk_prepare_enable(rtc->rtc_ck);
857 	if (ret)
858 		goto err;
......
872 	ret = stm32_rtc_init(pdev, rtc);
873 	if (ret)
874 		goto err;
875
876 	rtc->irq_alarm = platform_get_irq(pdev, 0);
877 	if (rtc->irq_alarm <= 0) {
878 		ret = rtc->irq_alarm;
879 		goto err;
880 	}
......
892 	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
893 	&stm32_rtc_ops, THIS_MODULE);
894 	if (IS_ERR(rtc->rtc_dev)) {
895 		ret = PTR_ERR(rtc->rtc_dev);
896 		dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",ret);
897
898 		goto err;
899 	}
900
901 	/* Handle RTC alarm interrupts */
902 	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
903		stm32_rtc_alarm_irq, IRQF_ONESHOT, pdev->name, rtc);
905 	if (ret) {
906 		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) alreadyclaimed\n", rtc->irq_alarm);
908 		goto err;
909 	}
......
941 	return 0;
......
954 }

第 796 行,调用 devm_kzalloc 申请 rtc 大小的空间,返回申请空间的首地址
第 800 行,调用 platform_get_resource 函数从设备树中获取到 RTC 外设寄存器基地址。
第 801 行,调用函数 devm_ioremap_resource 完成内存映射,得到 RTC 外设寄存器物理基地址对应的虚拟地址。
第 856 行,调用 clk_prepare_enable 函数使能时钟。
第 872 行,初始化 STM32MP1 rtc 的寄存器。
第 876 行,获取设备树的中断号。
第 892 行,调用 devm_rtc_device_register 函数向系统注册 rtc_devcie, RTC 底层驱动集为 stm32_rtc_ops。 stm32_rtc_ops 操作集包含了读取/设置 RTC 时间,读取/设置闹钟等函数。
第 902 行,调用 devm_request_threaded_irq 函数请求 RTC 中断,中断服务函数为stm32_rtc_alarm_irq,用于 RTC 闹钟中断。

三、RTC时间查看与设置

在 Linux 内核移植时,设备树是经过精简的,没有启动 RTC 功能。在 stm32mp157datk.dts 文件中, 添加如下代码:

&rtc {
	status = "okay";
};

就可以使能RTC设备。然后在内核启动时就能看到时钟设置信息:
在这里插入图片描述
可以看出,Linux 内核在启动的时候将 rtc 设置为 rtc0。输入date命令就可以查看时间:
在这里插入图片描述
发现时间还没有校正,使用date --help查看帮助:
在这里插入图片描述
使用date -s "2022-12-25 23:24:00"命令就可以设置当前时间,然后使用hwclock -w命令写入到RTC设备中,就不怕掉电丢失了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值