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