Blame view
drivers/rtc/class.c
12.2 KB
cdf7545ae rtc: convert core... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
0c86edc0d [PATCH] RTC subsy... |
2 3 4 5 6 7 8 |
/* * RTC subsystem, base class * * Copyright (C) 2005 Tower Technologies * Author: Alessandro Zummo <a.zummo@towertech.it> * * class skeleton from drivers/hwmon/hwmon.c |
cdf7545ae rtc: convert core... |
9 |
*/ |
0c86edc0d [PATCH] RTC subsy... |
10 |
|
c100a5e02 rtc: use dev_warn... |
11 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
0c86edc0d [PATCH] RTC subsy... |
12 |
#include <linux/module.h> |
9d2b7e532 rtc: honor device... |
13 |
#include <linux/of.h> |
0c86edc0d [PATCH] RTC subsy... |
14 15 16 |
#include <linux/rtc.h> #include <linux/kdev_t.h> #include <linux/idr.h> |
5a0e3ad6a include cleanup: ... |
17 |
#include <linux/slab.h> |
6610e0893 RTC: Rework RTC c... |
18 |
#include <linux/workqueue.h> |
0c86edc0d [PATCH] RTC subsy... |
19 |
|
5726fb201 rtc: remove /sys/... |
20 |
#include "rtc-core.h" |
6d03d06db drivers/rtc/class... |
21 |
static DEFINE_IDA(rtc_ida); |
0c86edc0d [PATCH] RTC subsy... |
22 |
struct class *rtc_class; |
cd9662094 rtc: remove rest ... |
23 |
static void rtc_device_release(struct device *dev) |
0c86edc0d [PATCH] RTC subsy... |
24 |
{ |
cd9662094 rtc: remove rest ... |
25 |
struct rtc_device *rtc = to_rtc_device(dev); |
606cc43c7 rtc: core: correc... |
26 |
|
6d03d06db drivers/rtc/class... |
27 |
ida_simple_remove(&rtc_ida, rtc->id); |
0c86edc0d [PATCH] RTC subsy... |
28 29 |
kfree(rtc); } |
4c24e29e6 rtc_sysfs_show_hc... |
30 31 32 |
#ifdef CONFIG_RTC_HCTOSYS_DEVICE /* Result of the last RTC to system clock attempt. */ int rtc_hctosys_ret = -ENODEV; |
0fb885c7b ANDROID: fix up r... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary * whether it stores the most close value or the value with partial * seconds truncated. However, it is important that we use it to store * the truncated value. This is because otherwise it is necessary, * in an rtc sync function, to read both xtime.tv_sec and * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read * of >32bits is not possible. So storing the most close value would * slow down the sync API. So here we have the truncated value and * the best guess is to add 0.5s. */ static void rtc_hctosys(struct rtc_device *rtc) { int err; struct rtc_time tm; struct timespec64 tv64 = { .tv_nsec = NSEC_PER_SEC >> 1, }; err = rtc_read_time(rtc, &tm); if (err) { dev_err(rtc->dev.parent, "hctosys: unable to read the hardware clock "); goto err_read; } tv64.tv_sec = rtc_tm_to_time64(&tm); #if BITS_PER_LONG == 32 if (tv64.tv_sec > INT_MAX) { err = -ERANGE; goto err_read; } #endif err = do_settimeofday64(&tv64); dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld) ", &tm, (long long)tv64.tv_sec); err_read: rtc_hctosys_ret = err; } |
4c24e29e6 rtc_sysfs_show_hc... |
79 |
#endif |
7ca1d488f rtc: suspend()/re... |
80 |
|
92e7f04a7 drivers/rtc/class... |
81 |
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) |
7ca1d488f rtc: suspend()/re... |
82 83 84 85 |
/* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). */ |
d4bda8f84 rtc: Update suspe... |
86 |
static struct timespec64 old_rtc, old_system, old_delta; |
3dcad5ff0 rtc: Avoid accumu... |
87 |
|
92e7f04a7 drivers/rtc/class... |
88 |
static int rtc_suspend(struct device *dev) |
7ca1d488f rtc: suspend()/re... |
89 90 91 |
{ struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; |
d4bda8f84 rtc: Update suspe... |
92 |
struct timespec64 delta, delta_delta; |
e1d60093c driver/rtc/class.... |
93 |
int err; |
9ecf37eb7 rtc: Skip the sus... |
94 |
|
0fa88cb4b time, drivers/rtc... |
95 |
if (timekeeping_rtc_skipsuspend()) |
9ecf37eb7 rtc: Skip the sus... |
96 |
return 0; |
d4afc76c0 rtc: struct devic... |
97 |
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
7ca1d488f rtc: suspend()/re... |
98 |
return 0; |
3dcad5ff0 rtc: Avoid accumu... |
99 |
/* snapshot the current RTC and system time at suspend*/ |
e1d60093c driver/rtc/class.... |
100 101 102 103 104 105 |
err = rtc_read_time(rtc, &tm); if (err < 0) { pr_debug("%s: fail to read rtc time ", dev_name(&rtc->dev)); return 0; } |
5089ea15b rtc: use ktime_ge... |
106 |
ktime_get_real_ts64(&old_system); |
d4bda8f84 rtc: Update suspe... |
107 |
old_rtc.tv_sec = rtc_tm_to_time64(&tm); |
3dcad5ff0 rtc: Avoid accumu... |
108 |
|
3dcad5ff0 rtc: Avoid accumu... |
109 110 111 112 113 114 |
/* * To avoid drift caused by repeated suspend/resumes, * which each can add ~1 second drift error, * try to compensate so the difference in system time * and rtc time stays close to constant. */ |
d4bda8f84 rtc: Update suspe... |
115 116 |
delta = timespec64_sub(old_system, old_rtc); delta_delta = timespec64_sub(delta, old_delta); |
6a8943d9e rtc: Fix some bug... |
117 |
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) { |
3dcad5ff0 rtc: Avoid accumu... |
118 119 |
/* * if delta_delta is too large, assume time correction |
606cc43c7 rtc: core: correc... |
120 |
* has occurred and set old_delta to the current delta. |
3dcad5ff0 rtc: Avoid accumu... |
121 122 123 124 |
*/ old_delta = delta; } else { /* Otherwise try to adjust old_system to compensate */ |
d4bda8f84 rtc: Update suspe... |
125 |
old_system = timespec64_sub(old_system, delta_delta); |
3dcad5ff0 rtc: Avoid accumu... |
126 |
} |
7ca1d488f rtc: suspend()/re... |
127 |
|
7ca1d488f rtc: suspend()/re... |
128 129 130 131 132 133 134 |
return 0; } static int rtc_resume(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; |
d4bda8f84 rtc: Update suspe... |
135 136 |
struct timespec64 new_system, new_rtc; struct timespec64 sleep_time; |
e1d60093c driver/rtc/class.... |
137 |
int err; |
7ca1d488f rtc: suspend()/re... |
138 |
|
0fa88cb4b time, drivers/rtc... |
139 |
if (timekeeping_rtc_skipresume()) |
9ecf37eb7 rtc: Skip the sus... |
140 |
return 0; |
4c24e29e6 rtc_sysfs_show_hc... |
141 |
rtc_hctosys_ret = -ENODEV; |
d4afc76c0 rtc: struct devic... |
142 |
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
7ca1d488f rtc: suspend()/re... |
143 |
return 0; |
3dcad5ff0 rtc: Avoid accumu... |
144 |
/* snapshot the current rtc and system time at resume */ |
5089ea15b rtc: use ktime_ge... |
145 |
ktime_get_real_ts64(&new_system); |
e1d60093c driver/rtc/class.... |
146 147 148 149 150 151 |
err = rtc_read_time(rtc, &tm); if (err < 0) { pr_debug("%s: fail to read rtc time ", dev_name(&rtc->dev)); return 0; } |
d4bda8f84 rtc: Update suspe... |
152 |
new_rtc.tv_sec = rtc_tm_to_time64(&tm); |
3dcad5ff0 rtc: Avoid accumu... |
153 |
new_rtc.tv_nsec = 0; |
6a8943d9e rtc: Fix some bug... |
154 155 156 |
if (new_rtc.tv_sec < old_rtc.tv_sec) { pr_debug("%s: time travel! ", dev_name(&rtc->dev)); |
7ca1d488f rtc: suspend()/re... |
157 158 |
return 0; } |
3dcad5ff0 rtc: Avoid accumu... |
159 |
/* calculate the RTC time delta (sleep time)*/ |
d4bda8f84 rtc: Update suspe... |
160 |
sleep_time = timespec64_sub(new_rtc, old_rtc); |
3dcad5ff0 rtc: Avoid accumu... |
161 162 163 164 165 166 167 168 |
/* * Since these RTC suspend/resume handlers are not called * at the very end of suspend or the start of resume, * some run-time may pass on either sides of the sleep time * so subtract kernel run-time between rtc_suspend to rtc_resume * to keep things accurate. */ |
d4bda8f84 rtc: Update suspe... |
169 |
sleep_time = timespec64_sub(sleep_time, |
606cc43c7 rtc: core: correc... |
170 |
timespec64_sub(new_system, old_system)); |
7ca1d488f rtc: suspend()/re... |
171 |
|
6a8943d9e rtc: Fix some bug... |
172 |
if (sleep_time.tv_sec >= 0) |
d4bda8f84 rtc: Update suspe... |
173 |
timekeeping_inject_sleeptime64(&sleep_time); |
4c24e29e6 rtc_sysfs_show_hc... |
174 |
rtc_hctosys_ret = 0; |
7ca1d488f rtc: suspend()/re... |
175 176 |
return 0; } |
92e7f04a7 drivers/rtc/class... |
177 178 |
static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume); #define RTC_CLASS_DEV_PM_OPS (&rtc_class_dev_pm_ops) |
7ca1d488f rtc: suspend()/re... |
179 |
#else |
92e7f04a7 drivers/rtc/class... |
180 |
#define RTC_CLASS_DEV_PM_OPS NULL |
7ca1d488f rtc: suspend()/re... |
181 |
#endif |
3068a254d rtc: introduce ne... |
182 |
/* Ensure the caller will set the id before releasing the device */ |
d1bec20fa rtc: class separa... |
183 184 185 186 187 188 189 190 191 |
static struct rtc_device *rtc_allocate_device(void) { struct rtc_device *rtc; rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); if (!rtc) return NULL; device_initialize(&rtc->dev); |
0f295b065 rtc: Allow rtc dr... |
192 193 |
/* Drivers can revise this default after allocating the device. */ rtc->set_offset_nsec = NSEC_PER_SEC / 2; |
d1bec20fa rtc: class separa... |
194 195 196 197 198 199 200 201 |
rtc->irq_freq = 1; rtc->max_user_freq = 64; rtc->dev.class = rtc_class; rtc->dev.groups = rtc_get_dev_attribute_groups(); rtc->dev.release = rtc_device_release; mutex_init(&rtc->ops_lock); spin_lock_init(&rtc->irq_lock); |
d1bec20fa rtc: class separa... |
202 203 204 205 206 207 |
init_waitqueue_head(&rtc->irq_queue); /* Init timerqueue */ timerqueue_init_head(&rtc->timerqueue); INIT_WORK(&rtc->irqwork, rtc_timer_do_work); /* Init aie timer */ |
9a0320117 rtc: enforce rtc_... |
208 |
rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, rtc); |
d1bec20fa rtc: class separa... |
209 |
/* Init uie timer */ |
9a0320117 rtc: enforce rtc_... |
210 |
rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, rtc); |
d1bec20fa rtc: class separa... |
211 212 213 214 215 216 217 |
/* Init pie timer */ hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); rtc->pie_timer.function = rtc_pie_update_irq; rtc->pie_enabled = 0; return rtc; } |
7ca1d488f rtc: suspend()/re... |
218 |
|
b91336df8 rtc: class separa... |
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
static int rtc_device_get_id(struct device *dev) { int of_id = -1, id = -1; if (dev->of_node) of_id = of_alias_get_id(dev->of_node, "rtc"); else if (dev->parent && dev->parent->of_node) of_id = of_alias_get_id(dev->parent->of_node, "rtc"); if (of_id >= 0) { id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL); if (id < 0) dev_warn(dev, "/aliases ID %d not available ", of_id); } if (id < 0) id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); return id; } |
989515647 rtc: Add one offs... |
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
static void rtc_device_get_offset(struct rtc_device *rtc) { time64_t range_secs; u32 start_year; int ret; /* * If RTC driver did not implement the range of RTC hardware device, * then we can not expand the RTC range by adding or subtracting one * offset. */ if (rtc->range_min == rtc->range_max) return; ret = device_property_read_u32(rtc->dev.parent, "start-year", &start_year); if (!ret) { rtc->start_secs = mktime64(start_year, 1, 1, 0, 0, 0); rtc->set_start_time = true; } /* * If user did not implement the start time for RTC driver, then no * need to expand the RTC range. */ if (!rtc->set_start_time) return; range_secs = rtc->range_max - rtc->range_min + 1; /* * If the start_secs is larger than the maximum seconds (rtc->range_max) * supported by RTC hardware or the maximum seconds of new expanded * range (start_secs + rtc->range_max - rtc->range_min) is less than * rtc->range_min, which means the minimum seconds (rtc->range_min) of * RTC hardware will be mapped to start_secs by adding one offset, so * the offset seconds calculation formula should be: * rtc->offset_secs = rtc->start_secs - rtc->range_min; * * If the start_secs is larger than the minimum seconds (rtc->range_min) * supported by RTC hardware, then there is one region is overlapped * between the original RTC hardware range and the new expanded range, * and this overlapped region do not need to be mapped into the new * expanded range due to it is valid for RTC device. So the minimum * seconds of RTC hardware (rtc->range_min) should be mapped to * rtc->range_max + 1, then the offset seconds formula should be: * rtc->offset_secs = rtc->range_max - rtc->range_min + 1; * * If the start_secs is less than the minimum seconds (rtc->range_min), * which is similar to case 2. So the start_secs should be mapped to * start_secs + rtc->range_max - rtc->range_min + 1, then the * offset seconds formula should be: * rtc->offset_secs = -(rtc->range_max - rtc->range_min + 1); * * Otherwise the offset seconds should be 0. */ if (rtc->start_secs > rtc->range_max || rtc->start_secs + range_secs - 1 < rtc->range_min) rtc->offset_secs = rtc->start_secs - rtc->range_min; else if (rtc->start_secs > rtc->range_min) rtc->offset_secs = range_secs; else if (rtc->start_secs < rtc->range_min) rtc->offset_secs = -range_secs; else rtc->offset_secs = 0; } |
0c86edc0d [PATCH] RTC subsy... |
306 |
/** |
0c86edc0d [PATCH] RTC subsy... |
307 308 309 310 |
* rtc_device_unregister - removes the previously registered RTC class device * * @rtc: the RTC class device to destroy */ |
1e479c619 rtc: unexport non... |
311 |
static void rtc_device_unregister(struct rtc_device *rtc) |
0c86edc0d [PATCH] RTC subsy... |
312 |
{ |
c3b399a4b rtc: class: remov... |
313 314 315 316 317 |
mutex_lock(&rtc->ops_lock); /* * Remove innards of this RTC, then disable it, before * letting any rtc_class_open() users access it again */ |
c3b399a4b rtc: class: remov... |
318 |
rtc_proc_del_device(rtc); |
d5ed9177f rtc: utilize new ... |
319 |
cdev_device_del(&rtc->char_dev, &rtc->dev); |
c3b399a4b rtc: class: remov... |
320 321 322 |
rtc->ops = NULL; mutex_unlock(&rtc->ops_lock); put_device(&rtc->dev); |
0c86edc0d [PATCH] RTC subsy... |
323 |
} |
0c86edc0d [PATCH] RTC subsy... |
324 |
|
3068a254d rtc: introduce ne... |
325 326 327 |
static void devm_rtc_release_device(struct device *dev, void *res) { struct rtc_device *rtc = *(struct rtc_device **)res; |
ac75779b7 rtc: nvmem: allow... |
328 |
rtc_nvmem_unregister(rtc); |
3068a254d rtc: introduce ne... |
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
if (rtc->registered) rtc_device_unregister(rtc); else put_device(&rtc->dev); } struct rtc_device *devm_rtc_allocate_device(struct device *dev) { struct rtc_device **ptr, *rtc; int id, err; id = rtc_device_get_id(dev); if (id < 0) return ERR_PTR(id); ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL); if (!ptr) { err = -ENOMEM; goto exit_ida; } rtc = rtc_allocate_device(); if (!rtc) { err = -ENOMEM; goto exit_devres; } *ptr = rtc; devres_add(dev, ptr); rtc->id = id; rtc->dev.parent = dev; dev_set_name(&rtc->dev, "rtc%d", id); return rtc; exit_devres: devres_free(ptr); exit_ida: ida_simple_remove(&rtc_ida, id); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(devm_rtc_allocate_device); int __rtc_register_device(struct module *owner, struct rtc_device *rtc) { struct rtc_wkalrm alrm; int err; |
924068e50 rtc: class: add d... |
377 378 379 |
if (!rtc->ops) { dev_dbg(&rtc->dev, "no ops set "); |
3068a254d rtc: introduce ne... |
380 |
return -EINVAL; |
924068e50 rtc: class: add d... |
381 |
} |
3068a254d rtc: introduce ne... |
382 383 |
rtc->owner = owner; |
989515647 rtc: Add one offs... |
384 |
rtc_device_get_offset(rtc); |
3068a254d rtc: introduce ne... |
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
/* Check to see if there is an ALARM already set in hw */ err = __rtc_read_alarm(rtc, &alrm); if (!err && !rtc_valid_tm(&alrm.time)) rtc_initialize_alarm(rtc, &alrm); rtc_dev_prepare(rtc); err = cdev_device_add(&rtc->char_dev, &rtc->dev); if (err) dev_warn(rtc->dev.parent, "failed to add char device %d:%d ", MAJOR(rtc->dev.devt), rtc->id); else dev_dbg(rtc->dev.parent, "char device (%d:%d) ", MAJOR(rtc->dev.devt), rtc->id); rtc_proc_add_device(rtc); rtc->registered = true; dev_info(rtc->dev.parent, "registered as %s ", dev_name(&rtc->dev)); |
14ad431cd ANDROID: rtc: cla... |
409 410 |
#ifdef CONFIG_RTC_HCTOSYS_DEVICE if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE)) |
0fb885c7b ANDROID: fix up r... |
411 |
rtc_hctosys(rtc); |
14ad431cd ANDROID: rtc: cla... |
412 |
#endif |
3068a254d rtc: introduce ne... |
413 414 415 |
return 0; } EXPORT_SYMBOL_GPL(__rtc_register_device); |
a26944149 rtc: class: reimp... |
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
/** * devm_rtc_device_register - resource managed rtc_device_register() * @dev: the device to register * @name: the name of the device (unused) * @ops: the rtc operations structure * @owner: the module owner * * @return a struct rtc on success, or an ERR_PTR on error * * Managed rtc_device_register(). The rtc_device returned from this function * are automatically freed on driver detach. * This function is deprecated, use devm_rtc_allocate_device and * rtc_register_device instead */ struct rtc_device *devm_rtc_device_register(struct device *dev, |
606cc43c7 rtc: core: correc... |
431 432 433 |
const char *name, const struct rtc_class_ops *ops, struct module *owner) |
a26944149 rtc: class: reimp... |
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
{ struct rtc_device *rtc; int err; rtc = devm_rtc_allocate_device(dev); if (IS_ERR(rtc)) return rtc; rtc->ops = ops; err = __rtc_register_device(owner, rtc); if (err) return ERR_PTR(err); return rtc; } EXPORT_SYMBOL_GPL(devm_rtc_device_register); |
0c86edc0d [PATCH] RTC subsy... |
451 452 453 454 |
static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); if (IS_ERR(rtc_class)) { |
c100a5e02 rtc: use dev_warn... |
455 456 |
pr_err("couldn't create class "); |
0c86edc0d [PATCH] RTC subsy... |
457 458 |
return PTR_ERR(rtc_class); } |
92e7f04a7 drivers/rtc/class... |
459 |
rtc_class->pm = RTC_CLASS_DEV_PM_OPS; |
5726fb201 rtc: remove /sys/... |
460 |
rtc_dev_init(); |
0c86edc0d [PATCH] RTC subsy... |
461 462 |
return 0; } |
818a8674b [PATCH] RTC class... |
463 |
subsys_initcall(rtc_init); |