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