blob: f50b3321314f30994e5efd0099ea19b9b08e7ee0 [file] [log] [blame]
Alessandro Zummoa95579c2006-03-27 01:16:42 -08001/*
2 * An RTC test device/driver
3 * Copyright (C) 2005 Tower Technologies
4 * Author: Alessandro Zummo <a.zummo@towertech.it>
5 *
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.
9 */
10
11#include <linux/module.h>
12#include <linux/err.h>
13#include <linux/rtc.h>
14#include <linux/platform_device.h>
15
Alexandre Belloni5b257572018-05-31 23:09:56 +020016#define MAX_RTC_TEST 3
17
Alexandre Belloni4dc24032018-05-31 23:09:57 +020018struct rtc_test_data {
19 struct rtc_device *rtc;
20 time64_t offset;
21};
22
Alexandre Belloni5b257572018-05-31 23:09:56 +020023struct platform_device *pdev[MAX_RTC_TEST];
Alessandro Zummoa95579c2006-03-27 01:16:42 -080024
25static int test_rtc_read_alarm(struct device *dev,
26 struct rtc_wkalrm *alrm)
27{
28 return 0;
29}
30
31static int test_rtc_set_alarm(struct device *dev,
32 struct rtc_wkalrm *alrm)
33{
34 return 0;
35}
36
Alexandre Belloni4dc24032018-05-31 23:09:57 +020037static int test_rtc_read_time(struct device *dev, struct rtc_time *tm)
Alessandro Zummoa95579c2006-03-27 01:16:42 -080038{
Alexandre Belloni4dc24032018-05-31 23:09:57 +020039 struct rtc_test_data *rtd = dev_get_drvdata(dev);
40
41 rtc_time64_to_tm(ktime_get_real_seconds() + rtd->offset, tm);
42
Xunlei Pang4d644ab82015-04-01 20:34:28 -070043 return 0;
44}
45
46static int test_rtc_set_mmss64(struct device *dev, time64_t secs)
47{
Alexandre Belloni4dc24032018-05-31 23:09:57 +020048 struct rtc_test_data *rtd = dev_get_drvdata(dev);
49
50 rtd->offset = secs - ktime_get_real_seconds();
51
Alessandro Zummoa95579c2006-03-27 01:16:42 -080052 return 0;
53}
54
John Stultz16380c12011-02-02 17:02:41 -080055static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
Alessandro Zummoa95579c2006-03-27 01:16:42 -080056{
John Stultz16380c12011-02-02 17:02:41 -080057 return 0;
Alessandro Zummoa95579c2006-03-27 01:16:42 -080058}
59
Alexandre Belloni78417682018-05-26 03:57:29 +020060static const struct rtc_class_ops test_rtc_ops = {
Alessandro Zummoa95579c2006-03-27 01:16:42 -080061 .read_time = test_rtc_read_time,
Alessandro Zummoa95579c2006-03-27 01:16:42 -080062 .read_alarm = test_rtc_read_alarm,
63 .set_alarm = test_rtc_set_alarm,
Alexandre Belloni78417682018-05-26 03:57:29 +020064 .set_mmss64 = test_rtc_set_mmss64,
John Stultz16380c12011-02-02 17:02:41 -080065 .alarm_irq_enable = test_rtc_alarm_irq_enable,
Alessandro Zummoa95579c2006-03-27 01:16:42 -080066};
67
68static ssize_t test_irq_show(struct device *dev,
69 struct device_attribute *attr, char *buf)
70{
71 return sprintf(buf, "%d\n", 42);
72}
73static ssize_t test_irq_store(struct device *dev,
74 struct device_attribute *attr,
75 const char *buf, size_t count)
76{
77 int retval;
Wolfram Sang85368bb2018-04-19 16:06:14 +020078 struct rtc_device *rtc = dev_get_drvdata(dev);
Alessandro Zummoa95579c2006-03-27 01:16:42 -080079
80 retval = count;
Marcelo Roberto Jimeneza4174932011-02-07 19:16:07 -020081 if (strncmp(buf, "tick", 4) == 0 && rtc->pie_enabled)
David Brownellab6a2d72007-05-08 00:33:30 -070082 rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
Marcelo Roberto Jimeneza4174932011-02-07 19:16:07 -020083 else if (strncmp(buf, "alarm", 5) == 0) {
84 struct rtc_wkalrm alrm;
85 int err = rtc_read_alarm(rtc, &alrm);
86
87 if (!err && alrm.enabled)
88 rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
89
90 } else if (strncmp(buf, "update", 6) == 0 && rtc->uie_rtctimer.enabled)
David Brownellab6a2d72007-05-08 00:33:30 -070091 rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
Alessandro Zummoa95579c2006-03-27 01:16:42 -080092 else
93 retval = -EINVAL;
94
95 return retval;
96}
97static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
98
99static int test_probe(struct platform_device *plat_dev)
100{
Alexandre Belloni4dc24032018-05-31 23:09:57 +0200101 struct rtc_test_data *rtd;
Jingoo Handd8d8132013-04-29 16:19:52 -0700102
Alexandre Belloni4dc24032018-05-31 23:09:57 +0200103 rtd = devm_kzalloc(&plat_dev->dev, sizeof(*rtd), GFP_KERNEL);
104 if (!rtd)
105 return -ENOMEM;
Jeff Garzik91046a82006-12-06 20:35:34 -0800106
Alexandre Belloni4dc24032018-05-31 23:09:57 +0200107 platform_set_drvdata(plat_dev, rtd);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800108
Alexandre Belloni4dc24032018-05-31 23:09:57 +0200109 rtd->rtc = devm_rtc_device_register(&plat_dev->dev, "test",
110 &test_rtc_ops, THIS_MODULE);
111 if (IS_ERR(rtd->rtc))
112 return PTR_ERR(rtd->rtc);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800113
114 return 0;
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800115}
116
Greg Kroah-Hartman5a167f42012-12-21 13:09:38 -0800117static int test_remove(struct platform_device *plat_dev)
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800118{
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800119 device_remove_file(&plat_dev->dev, &dev_attr_irq);
120
121 return 0;
122}
123
Sam Ravnborgc4646522008-04-28 02:11:55 -0700124static struct platform_driver test_driver = {
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800125 .probe = test_probe,
Greg Kroah-Hartman5a167f42012-12-21 13:09:38 -0800126 .remove = test_remove,
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800127 .driver = {
128 .name = "rtc-test",
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800129 },
130};
131
132static int __init test_init(void)
133{
Alexandre Belloni5b257572018-05-31 23:09:56 +0200134 int i, err;
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800135
Sam Ravnborgc4646522008-04-28 02:11:55 -0700136 if ((err = platform_driver_register(&test_driver)))
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800137 return err;
138
Alexandre Belloni5b257572018-05-31 23:09:56 +0200139 err = -ENOMEM;
140 for (i = 0; i < MAX_RTC_TEST; i++) {
141 pdev[i] = platform_device_alloc("rtc-test", i);
142 if (!pdev[i])
143 goto exit_free_mem;
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800144 }
145
Alexandre Belloni5b257572018-05-31 23:09:56 +0200146 for (i = 0; i < MAX_RTC_TEST; i++) {
147 err = platform_device_add(pdev[i]);
148 if (err)
149 goto exit_device_del;
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800150 }
151
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800152 return 0;
153
Alexandre Belloni5b257572018-05-31 23:09:56 +0200154exit_device_del:
155 for (; i > 0; i--)
156 platform_device_del(pdev[i - 1]);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800157
Alexandre Belloni5b257572018-05-31 23:09:56 +0200158exit_free_mem:
159 for (i = 0; i < MAX_RTC_TEST; i++)
160 platform_device_put(pdev[i]);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800161
Sam Ravnborgc4646522008-04-28 02:11:55 -0700162 platform_driver_unregister(&test_driver);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800163 return err;
164}
165
166static void __exit test_exit(void)
167{
Alexandre Belloni5b257572018-05-31 23:09:56 +0200168 int i;
169
170 for (i = 0; i < MAX_RTC_TEST; i++)
171 platform_device_unregister(pdev[i]);
172
Sam Ravnborgc4646522008-04-28 02:11:55 -0700173 platform_driver_unregister(&test_driver);
Alessandro Zummoa95579c2006-03-27 01:16:42 -0800174}
175
176MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
177MODULE_DESCRIPTION("RTC test driver/device");
178MODULE_LICENSE("GPL");
179
180module_init(test_init);
181module_exit(test_exit);