xref: /linux/drivers/virtio/virtio_rtc_class.c (revision 25489a4f556414445d342951615178368ee45cde)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * virtio_rtc RTC class driver
4  *
5  * Copyright (C) 2023 OpenSynergy GmbH
6  * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
7  */
8 
9 #include <linux/math64.h>
10 #include <linux/overflow.h>
11 #include <linux/rtc.h>
12 #include <linux/time64.h>
13 
14 #include <uapi/linux/virtio_rtc.h>
15 
16 #include "virtio_rtc_internal.h"
17 
18 /**
19  * struct viortc_class - RTC class wrapper
20  * @viortc: virtio_rtc device data
21  * @rtc: RTC device
22  * @vio_clk_id: virtio_rtc clock id
23  * @stopped: Whether RTC ops are disallowed. Access protected by rtc_lock().
24  */
25 struct viortc_class {
26 	struct viortc_dev *viortc;
27 	struct rtc_device *rtc;
28 	u16 vio_clk_id;
29 	bool stopped;
30 };
31 
32 /**
33  * viortc_class_get_locked() - get RTC class wrapper, if ops allowed
34  * @dev: virtio device
35  *
36  * Gets the RTC class wrapper from the virtio device, if it is available and
37  * ops are allowed.
38  *
39  * Context: Caller must hold rtc_lock().
40  * Return: RTC class wrapper if available and ops allowed, ERR_PTR otherwise.
41  */
42 static struct viortc_class *viortc_class_get_locked(struct device *dev)
43 {
44 	struct viortc_class *viortc_class;
45 
46 	viortc_class = viortc_class_from_dev(dev);
47 	if (IS_ERR(viortc_class))
48 		return viortc_class;
49 
50 	if (viortc_class->stopped)
51 		return ERR_PTR(-EBUSY);
52 
53 	return viortc_class;
54 }
55 
56 /**
57  * viortc_class_read_time() - RTC class op read_time
58  * @dev: virtio device
59  * @tm: read time
60  *
61  * Context: Process context.
62  * Return: Zero on success, negative error code otherwise.
63  */
64 static int viortc_class_read_time(struct device *dev, struct rtc_time *tm)
65 {
66 	struct viortc_class *viortc_class;
67 	time64_t sec;
68 	int ret;
69 	u64 ns;
70 
71 	viortc_class = viortc_class_get_locked(dev);
72 	if (IS_ERR(viortc_class))
73 		return PTR_ERR(viortc_class);
74 
75 	ret = viortc_read(viortc_class->viortc, viortc_class->vio_clk_id, &ns);
76 	if (ret)
77 		return ret;
78 
79 	sec = div_u64(ns, NSEC_PER_SEC);
80 
81 	rtc_time64_to_tm(sec, tm);
82 
83 	return 0;
84 }
85 
86 /**
87  * viortc_class_read_alarm() - RTC class op read_alarm
88  * @dev: virtio device
89  * @alrm: alarm read out
90  *
91  * Context: Process context.
92  * Return: Zero on success, negative error code otherwise.
93  */
94 static int viortc_class_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
95 {
96 	struct viortc_class *viortc_class;
97 	time64_t alarm_time_sec;
98 	u64 alarm_time_ns;
99 	bool enabled;
100 	int ret;
101 
102 	viortc_class = viortc_class_get_locked(dev);
103 	if (IS_ERR(viortc_class))
104 		return PTR_ERR(viortc_class);
105 
106 	ret = viortc_read_alarm(viortc_class->viortc, viortc_class->vio_clk_id,
107 				&alarm_time_ns, &enabled);
108 	if (ret)
109 		return ret;
110 
111 	alarm_time_sec = div_u64(alarm_time_ns, NSEC_PER_SEC);
112 	rtc_time64_to_tm(alarm_time_sec, &alrm->time);
113 
114 	alrm->enabled = enabled;
115 
116 	return 0;
117 }
118 
119 /**
120  * viortc_class_set_alarm() - RTC class op set_alarm
121  * @dev: virtio device
122  * @alrm: alarm to set
123  *
124  * Context: Process context.
125  * Return: Zero on success, negative error code otherwise.
126  */
127 static int viortc_class_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
128 {
129 	struct viortc_class *viortc_class;
130 	time64_t alarm_time_sec;
131 	u64 alarm_time_ns;
132 
133 	viortc_class = viortc_class_get_locked(dev);
134 	if (IS_ERR(viortc_class))
135 		return PTR_ERR(viortc_class);
136 
137 	alarm_time_sec = rtc_tm_to_time64(&alrm->time);
138 
139 	if (alarm_time_sec < 0)
140 		return -EINVAL;
141 
142 	if (check_mul_overflow((u64)alarm_time_sec, (u64)NSEC_PER_SEC,
143 			       &alarm_time_ns))
144 		return -EINVAL;
145 
146 	return viortc_set_alarm(viortc_class->viortc, viortc_class->vio_clk_id,
147 				alarm_time_ns, alrm->enabled);
148 }
149 
150 /**
151  * viortc_class_alarm_irq_enable() - RTC class op alarm_irq_enable
152  * @dev: virtio device
153  * @enabled: enable or disable alarm IRQ
154  *
155  * Context: Process context.
156  * Return: Zero on success, negative error code otherwise.
157  */
158 static int viortc_class_alarm_irq_enable(struct device *dev,
159 					 unsigned int enabled)
160 {
161 	struct viortc_class *viortc_class;
162 
163 	viortc_class = viortc_class_get_locked(dev);
164 	if (IS_ERR(viortc_class))
165 		return PTR_ERR(viortc_class);
166 
167 	return viortc_set_alarm_enabled(viortc_class->viortc,
168 					viortc_class->vio_clk_id, enabled);
169 }
170 
171 static const struct rtc_class_ops viortc_class_ops = {
172 	.read_time = viortc_class_read_time,
173 	.read_alarm = viortc_class_read_alarm,
174 	.set_alarm = viortc_class_set_alarm,
175 	.alarm_irq_enable = viortc_class_alarm_irq_enable,
176 };
177 
178 /**
179  * viortc_class_alarm() - propagate alarm notification as alarm interrupt
180  * @viortc_class: RTC class wrapper
181  * @vio_clk_id: virtio_rtc clock id
182  *
183  * Context: Any context.
184  */
185 void viortc_class_alarm(struct viortc_class *viortc_class, u16 vio_clk_id)
186 {
187 	if (vio_clk_id != viortc_class->vio_clk_id) {
188 		dev_warn_ratelimited(&viortc_class->rtc->dev,
189 				     "ignoring alarm for clock id %d, expected id %d\n",
190 				     vio_clk_id, viortc_class->vio_clk_id);
191 		return;
192 	}
193 
194 	rtc_update_irq(viortc_class->rtc, 1, RTC_AF | RTC_IRQF);
195 }
196 
197 /**
198  * viortc_class_stop() - disallow RTC class ops
199  * @viortc_class: RTC class wrapper
200  *
201  * Context: Process context. Caller must NOT hold rtc_lock().
202  */
203 void viortc_class_stop(struct viortc_class *viortc_class)
204 {
205 	rtc_lock(viortc_class->rtc);
206 
207 	viortc_class->stopped = true;
208 
209 	rtc_unlock(viortc_class->rtc);
210 }
211 
212 /**
213  * viortc_class_register() - register RTC class device
214  * @viortc_class: RTC class wrapper
215  *
216  * Context: Process context.
217  * Return: Zero on success, negative error code otherwise.
218  */
219 int viortc_class_register(struct viortc_class *viortc_class)
220 {
221 	return devm_rtc_register_device(viortc_class->rtc);
222 }
223 
224 /**
225  * viortc_class_init() - init RTC class wrapper and device
226  * @viortc: device data
227  * @vio_clk_id: virtio_rtc clock id
228  * @have_alarm: have alarm feature
229  * @parent_dev: virtio device
230  *
231  * Context: Process context.
232  * Return: RTC class wrapper on success, ERR_PTR otherwise.
233  */
234 struct viortc_class *viortc_class_init(struct viortc_dev *viortc,
235 				       u16 vio_clk_id, bool have_alarm,
236 				       struct device *parent_dev)
237 {
238 	struct viortc_class *viortc_class;
239 	struct rtc_device *rtc;
240 
241 	viortc_class =
242 		devm_kzalloc(parent_dev, sizeof(*viortc_class), GFP_KERNEL);
243 	if (!viortc_class)
244 		return ERR_PTR(-ENOMEM);
245 
246 	rtc = devm_rtc_allocate_device(parent_dev);
247 	if (IS_ERR(rtc))
248 		return ERR_CAST(rtc);
249 
250 	viortc_class->viortc = viortc;
251 	viortc_class->rtc = rtc;
252 	viortc_class->vio_clk_id = vio_clk_id;
253 
254 	if (!have_alarm)
255 		clear_bit(RTC_FEATURE_ALARM, rtc->features);
256 	clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
257 
258 	rtc->ops = &viortc_class_ops;
259 	rtc->range_max = div_u64(U64_MAX, NSEC_PER_SEC);
260 
261 	return viortc_class;
262 }
263