2 * An RTC test device/driver
3 * Copyright (C) 2005 Tower Technologies
4 * Author: Alessandro Zummo <a.zummo@towertech.it>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/module.h>
12 #include <linux/err.h>
13 #include <linux/rtc.h>
14 #include <linux/platform_device.h>
16 #define MAX_RTC_TEST 3
18 struct rtc_test_data
{
19 struct rtc_device
*rtc
;
21 struct timer_list alarm
;
25 struct platform_device
*pdev
[MAX_RTC_TEST
];
27 static int test_rtc_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
29 struct rtc_test_data
*rtd
= dev_get_drvdata(dev
);
32 alarm
= (rtd
->alarm
.expires
- jiffies
) / HZ
;
33 alarm
+= ktime_get_real_seconds() + rtd
->offset
;
35 rtc_time64_to_tm(alarm
, &alrm
->time
);
36 alrm
->enabled
= rtd
->alarm_en
;
41 static int test_rtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
43 struct rtc_test_data
*rtd
= dev_get_drvdata(dev
);
47 timeout
= rtc_tm_to_time64(&alrm
->time
) - ktime_get_real_seconds();
48 timeout
-= rtd
->offset
;
50 del_timer(&rtd
->alarm
);
52 expires
= jiffies
+ timeout
* HZ
;
53 if (expires
> U32_MAX
)
56 pr_err("ABE: %s +%d %s\n", __FILE__
, __LINE__
, __func__
);
57 rtd
->alarm
.expires
= expires
;
60 add_timer(&rtd
->alarm
);
62 rtd
->alarm_en
= alrm
->enabled
;
67 static int test_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
69 struct rtc_test_data
*rtd
= dev_get_drvdata(dev
);
71 rtc_time64_to_tm(ktime_get_real_seconds() + rtd
->offset
, tm
);
76 static int test_rtc_set_mmss64(struct device
*dev
, time64_t secs
)
78 struct rtc_test_data
*rtd
= dev_get_drvdata(dev
);
80 rtd
->offset
= secs
- ktime_get_real_seconds();
85 static int test_rtc_alarm_irq_enable(struct device
*dev
, unsigned int enable
)
87 struct rtc_test_data
*rtd
= dev_get_drvdata(dev
);
89 rtd
->alarm_en
= enable
;
91 add_timer(&rtd
->alarm
);
93 del_timer(&rtd
->alarm
);
98 static const struct rtc_class_ops test_rtc_ops_noalm
= {
99 .read_time
= test_rtc_read_time
,
100 .set_mmss64
= test_rtc_set_mmss64
,
101 .alarm_irq_enable
= test_rtc_alarm_irq_enable
,
104 static const struct rtc_class_ops test_rtc_ops
= {
105 .read_time
= test_rtc_read_time
,
106 .read_alarm
= test_rtc_read_alarm
,
107 .set_alarm
= test_rtc_set_alarm
,
108 .set_mmss64
= test_rtc_set_mmss64
,
109 .alarm_irq_enable
= test_rtc_alarm_irq_enable
,
112 static void test_rtc_alarm_handler(struct timer_list
*t
)
114 struct rtc_test_data
*rtd
= from_timer(rtd
, t
, alarm
);
116 rtc_update_irq(rtd
->rtc
, 1, RTC_AF
| RTC_IRQF
);
119 static int test_probe(struct platform_device
*plat_dev
)
121 struct rtc_test_data
*rtd
;
123 rtd
= devm_kzalloc(&plat_dev
->dev
, sizeof(*rtd
), GFP_KERNEL
);
127 platform_set_drvdata(plat_dev
, rtd
);
129 rtd
->rtc
= devm_rtc_allocate_device(&plat_dev
->dev
);
130 if (IS_ERR(rtd
->rtc
))
131 return PTR_ERR(rtd
->rtc
);
133 switch (plat_dev
->id
) {
135 rtd
->rtc
->ops
= &test_rtc_ops_noalm
;
138 rtd
->rtc
->ops
= &test_rtc_ops
;
141 timer_setup(&rtd
->alarm
, test_rtc_alarm_handler
, 0);
142 rtd
->alarm
.expires
= 0;
144 return rtc_register_device(rtd
->rtc
);
147 static struct platform_driver test_driver
= {
154 static int __init
test_init(void)
158 if ((err
= platform_driver_register(&test_driver
)))
162 for (i
= 0; i
< MAX_RTC_TEST
; i
++) {
163 pdev
[i
] = platform_device_alloc("rtc-test", i
);
168 for (i
= 0; i
< MAX_RTC_TEST
; i
++) {
169 err
= platform_device_add(pdev
[i
]);
171 goto exit_device_del
;
178 platform_device_del(pdev
[i
- 1]);
181 for (i
= 0; i
< MAX_RTC_TEST
; i
++)
182 platform_device_put(pdev
[i
]);
184 platform_driver_unregister(&test_driver
);
188 static void __exit
test_exit(void)
192 for (i
= 0; i
< MAX_RTC_TEST
; i
++)
193 platform_device_unregister(pdev
[i
]);
195 platform_driver_unregister(&test_driver
);
198 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
199 MODULE_DESCRIPTION("RTC test driver/device");
200 MODULE_LICENSE("GPL");
202 module_init(test_init
);
203 module_exit(test_exit
);