Commit | Line | Data |
---|---|---|
cecf61bd | 1 | /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems. |
7a138ede DM |
2 | * |
3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | |
4 | */ | |
5 | ||
d959f731 JH |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | ||
7a138ede DM |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> | |
10 | #include <linux/delay.h> | |
11 | #include <linux/init.h> | |
7a138ede DM |
12 | #include <linux/rtc.h> |
13 | #include <linux/platform_device.h> | |
14 | ||
15 | #include <asm/hypervisor.h> | |
16 | ||
7a138ede DM |
17 | static unsigned long hypervisor_get_time(void) |
18 | { | |
19 | unsigned long ret, time; | |
20 | int retries = 10000; | |
21 | ||
22 | retry: | |
23 | ret = sun4v_tod_get(&time); | |
24 | if (ret == HV_EOK) | |
25 | return time; | |
26 | if (ret == HV_EWOULDBLOCK) { | |
27 | if (--retries > 0) { | |
28 | udelay(100); | |
29 | goto retry; | |
30 | } | |
d959f731 | 31 | pr_warn("tod_get() timed out.\n"); |
7a138ede DM |
32 | return 0; |
33 | } | |
d959f731 | 34 | pr_warn("tod_get() not supported.\n"); |
7a138ede DM |
35 | return 0; |
36 | } | |
37 | ||
38 | static int sun4v_read_time(struct device *dev, struct rtc_time *tm) | |
39 | { | |
cecf61bd | 40 | rtc_time_to_tm(hypervisor_get_time(), tm); |
7a138ede DM |
41 | return 0; |
42 | } | |
43 | ||
44 | static int hypervisor_set_time(unsigned long secs) | |
45 | { | |
46 | unsigned long ret; | |
47 | int retries = 10000; | |
48 | ||
49 | retry: | |
50 | ret = sun4v_tod_set(secs); | |
51 | if (ret == HV_EOK) | |
52 | return 0; | |
53 | if (ret == HV_EWOULDBLOCK) { | |
54 | if (--retries > 0) { | |
55 | udelay(100); | |
56 | goto retry; | |
57 | } | |
d959f731 | 58 | pr_warn("tod_set() timed out.\n"); |
7a138ede DM |
59 | return -EAGAIN; |
60 | } | |
d959f731 | 61 | pr_warn("tod_set() not supported.\n"); |
7a138ede DM |
62 | return -EOPNOTSUPP; |
63 | } | |
64 | ||
65 | static int sun4v_set_time(struct device *dev, struct rtc_time *tm) | |
66 | { | |
cecf61bd | 67 | unsigned long secs; |
7a138ede DM |
68 | int err; |
69 | ||
70 | err = rtc_tm_to_time(tm, &secs); | |
71 | if (err) | |
72 | return err; | |
73 | ||
cecf61bd | 74 | return hypervisor_set_time(secs); |
7a138ede DM |
75 | } |
76 | ||
77 | static const struct rtc_class_ops sun4v_rtc_ops = { | |
78 | .read_time = sun4v_read_time, | |
79 | .set_time = sun4v_set_time, | |
80 | }; | |
81 | ||
cecf61bd | 82 | static int __init sun4v_rtc_probe(struct platform_device *pdev) |
7a138ede | 83 | { |
cc40d642 JH |
84 | struct rtc_device *rtc; |
85 | ||
86 | rtc = devm_rtc_device_register(&pdev->dev, "sun4v", | |
87 | &sun4v_rtc_ops, THIS_MODULE); | |
cecf61bd AZ |
88 | if (IS_ERR(rtc)) |
89 | return PTR_ERR(rtc); | |
90 | ||
91 | platform_set_drvdata(pdev, rtc); | |
7a138ede DM |
92 | return 0; |
93 | } | |
94 | ||
7a138ede DM |
95 | static struct platform_driver sun4v_rtc_driver = { |
96 | .driver = { | |
97 | .name = "rtc-sun4v", | |
98 | .owner = THIS_MODULE, | |
99 | }, | |
7a138ede DM |
100 | }; |
101 | ||
61ce8256 | 102 | module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe); |
cecf61bd AZ |
103 | |
104 | MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); | |
105 | MODULE_DESCRIPTION("SUN4V RTC driver"); | |
106 | MODULE_LICENSE("GPL"); |