1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd
4 */
5
6 #include <linux/module.h>
7 #include <linux/rtc.h>
8 #include <linux/time.h>
9 #include <linux/of_platform.h>
10
11 static struct timespec begtime;
12 static unsigned long time;
13
timespec_to_ulong(struct timespec * ts)14 static unsigned long timespec_to_ulong(struct timespec *ts)
15 {
16 return ts->tv_nsec < NSEC_PER_SEC / 2 ? ts->tv_sec : ts->tv_sec + 1;
17 }
18
get_uptime(struct timespec * ts)19 static void get_uptime(struct timespec *ts)
20 {
21 getrawmonotonic(ts);
22 }
23
fake_rtc_read_time(struct device * dev,struct rtc_time * tm)24 static int fake_rtc_read_time(struct device *dev, struct rtc_time *tm)
25 {
26 struct timespec now, diff;
27
28 get_uptime(&now);
29 diff = timespec_sub(now, begtime);
30
31 rtc_time_to_tm(time + timespec_to_ulong(&diff), tm);
32
33 return rtc_valid_tm(tm);
34 }
35
fake_rtc_set_time(struct device * dev,struct rtc_time * tm)36 static int fake_rtc_set_time(struct device *dev, struct rtc_time *tm)
37 {
38 get_uptime(&begtime);
39 rtc_tm_to_time(tm, &time);
40
41 return 0;
42 }
43
fake_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)44 static int fake_rtc_alarm_irq_enable(struct device *dev,
45 unsigned int enabled)
46 {
47 return 0;
48 }
49
fake_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alm)50 static int fake_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
51 {
52 return 0;
53 }
54
fake_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alm)55 static int fake_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
56 {
57 return 0;
58 }
59
60 static const struct rtc_class_ops fake_rtc_ops = {
61 .read_time = fake_rtc_read_time,
62 .set_time = fake_rtc_set_time,
63 .alarm_irq_enable = fake_rtc_alarm_irq_enable,
64 .read_alarm = fake_rtc_read_alarm,
65 .set_alarm = fake_rtc_set_alarm,
66 };
67
fake_rtc_probe(struct platform_device * pdev)68 static int fake_rtc_probe(struct platform_device *pdev)
69 {
70 struct rtc_device *fake_rtc;
71 struct rtc_time tm = {
72 .tm_wday = 1,
73 .tm_year = 118,
74 .tm_mon = 0,
75 .tm_mday = 1,
76 .tm_hour = 12,
77 .tm_min = 0,
78 .tm_sec = 0,
79 };
80
81 get_uptime(&begtime);
82 fake_rtc_set_time(&pdev->dev, &tm);
83
84 device_init_wakeup(&pdev->dev, 1);
85
86 fake_rtc = devm_rtc_device_register(&pdev->dev,
87 pdev->name, &fake_rtc_ops, THIS_MODULE);
88 if (IS_ERR(fake_rtc))
89 return PTR_ERR(fake_rtc);
90
91 dev_info(&pdev->dev, "loaded; begtime is %lu, time is %lu\n",
92 timespec_to_ulong(&begtime), time);
93
94 return 0;
95 }
96
97 static const struct of_device_id rtc_dt_ids[] = {
98 { .compatible = "rtc-fake" },
99 {},
100 };
101
102 struct platform_driver fake_rtc_driver = {
103 .driver = {
104 .name = "rtc-fake",
105 .owner = THIS_MODULE,
106 .of_match_table = of_match_ptr(rtc_dt_ids),
107 },
108 .probe = fake_rtc_probe,
109 };
110
111 module_platform_driver(fake_rtc_driver);
112
113 MODULE_AUTHOR("jesse.huang@rock-chips.com");
114 MODULE_DESCRIPTION("FAKE RTC driver");
115 MODULE_LICENSE("GPL");
116
117