1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 Intel Corporation 4 * Author: Johannes Berg <johannes@sipsolutions.net> 5 */ 6 #include <linux/platform_device.h> 7 #include <linux/time-internal.h> 8 #include <linux/suspend.h> 9 #include <linux/err.h> 10 #include <linux/rtc.h> 11 #include <kern_util.h> 12 #include <irq_kern.h> 13 #include <os.h> 14 #include "rtc.h" 15 16 static time64_t uml_rtc_alarm_time; 17 static bool uml_rtc_alarm_enabled; 18 static struct rtc_device *uml_rtc; 19 static int uml_rtc_irq_fd, uml_rtc_irq; 20 21 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT 22 23 static void uml_rtc_time_travel_alarm(struct time_travel_event *ev) 24 { 25 uml_rtc_send_timetravel_alarm(); 26 } 27 28 static struct time_travel_event uml_rtc_alarm_event = { 29 .fn = uml_rtc_time_travel_alarm, 30 }; 31 #endif 32 33 static int uml_rtc_read_time(struct device *dev, struct rtc_time *tm) 34 { 35 struct timespec64 ts; 36 37 /* Use this to get correct time in time-travel mode */ 38 read_persistent_clock64(&ts); 39 rtc_time64_to_tm(timespec64_to_ktime(ts) / NSEC_PER_SEC, tm); 40 41 return 0; 42 } 43 44 static int uml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 45 { 46 rtc_time64_to_tm(uml_rtc_alarm_time, &alrm->time); 47 alrm->enabled = uml_rtc_alarm_enabled; 48 49 return 0; 50 } 51 52 static int uml_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) 53 { 54 struct timespec64 ts; 55 unsigned long long secs; 56 57 if (!enable && !uml_rtc_alarm_enabled) 58 return 0; 59 60 uml_rtc_alarm_enabled = enable; 61 62 read_persistent_clock64(&ts); 63 secs = uml_rtc_alarm_time - ts.tv_sec; 64 65 if (time_travel_mode == TT_MODE_OFF) { 66 if (!enable) { 67 uml_rtc_disable_alarm(); 68 return 0; 69 } 70 71 /* enable or update */ 72 return uml_rtc_enable_alarm(secs); 73 } else { 74 time_travel_del_event(¨_rtc_alarm_event); 75 76 if (enable) 77 time_travel_add_event_rel(¨_rtc_alarm_event, 78 secs * NSEC_PER_SEC - 79 ts.tv_nsec); 80 } 81 82 return 0; 83 } 84 85 static int uml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 86 { 87 uml_rtc_alarm_irq_enable(dev, 0); 88 uml_rtc_alarm_time = rtc_tm_to_time64(&alrm->time); 89 uml_rtc_alarm_irq_enable(dev, alrm->enabled); 90 91 return 0; 92 } 93 94 static const struct rtc_class_ops uml_rtc_ops = { 95 .read_time = uml_rtc_read_time, 96 .read_alarm = uml_rtc_read_alarm, 97 .alarm_irq_enable = uml_rtc_alarm_irq_enable, 98 .set_alarm = uml_rtc_set_alarm, 99 }; 100 101 static irqreturn_t uml_rtc_interrupt(int irq, void *data) 102 { 103 unsigned long long c = 0; 104 105 /* alarm triggered, it's now off */ 106 uml_rtc_alarm_enabled = false; 107 108 os_read_file(uml_rtc_irq_fd, &c, sizeof(c)); 109 WARN_ON(c == 0); 110 111 pm_system_wakeup(); 112 rtc_update_irq(uml_rtc, 1, RTC_IRQF | RTC_AF); 113 114 return IRQ_HANDLED; 115 } 116 117 static int uml_rtc_setup(void) 118 { 119 int err; 120 121 err = uml_rtc_start(time_travel_mode != TT_MODE_OFF); 122 if (WARN(err < 0, "err = %d\n", err)) 123 return err; 124 125 uml_rtc_irq_fd = err; 126 127 err = um_request_irq(UM_IRQ_ALLOC, uml_rtc_irq_fd, IRQ_READ, 128 uml_rtc_interrupt, 0, "rtc", NULL); 129 if (err < 0) { 130 uml_rtc_stop(time_travel_mode != TT_MODE_OFF); 131 return err; 132 } 133 134 irq_set_irq_wake(err, 1); 135 136 uml_rtc_irq = err; 137 return 0; 138 } 139 140 static void uml_rtc_cleanup(void) 141 { 142 um_free_irq(uml_rtc_irq, NULL); 143 uml_rtc_stop(time_travel_mode != TT_MODE_OFF); 144 } 145 146 static int uml_rtc_probe(struct platform_device *pdev) 147 { 148 int err; 149 150 err = uml_rtc_setup(); 151 if (err) 152 return err; 153 154 uml_rtc = devm_rtc_allocate_device(&pdev->dev); 155 if (IS_ERR(uml_rtc)) { 156 err = PTR_ERR(uml_rtc); 157 goto cleanup; 158 } 159 160 uml_rtc->ops = ¨_rtc_ops; 161 162 device_init_wakeup(&pdev->dev, 1); 163 164 err = devm_rtc_register_device(uml_rtc); 165 if (err) 166 goto cleanup; 167 168 return 0; 169 cleanup: 170 uml_rtc_cleanup(); 171 return err; 172 } 173 174 static void uml_rtc_remove(struct platform_device *pdev) 175 { 176 device_init_wakeup(&pdev->dev, 0); 177 uml_rtc_cleanup(); 178 } 179 180 static struct platform_driver uml_rtc_driver = { 181 .probe = uml_rtc_probe, 182 .remove = uml_rtc_remove, 183 .driver = { 184 .name = "uml-rtc", 185 }, 186 }; 187 188 static int __init uml_rtc_init(void) 189 { 190 struct platform_device *pdev; 191 int err; 192 193 err = platform_driver_register(¨_rtc_driver); 194 if (err) 195 return err; 196 197 pdev = platform_device_alloc("uml-rtc", 0); 198 if (!pdev) { 199 err = -ENOMEM; 200 goto unregister; 201 } 202 203 err = platform_device_add(pdev); 204 if (err) 205 goto unregister; 206 return 0; 207 208 unregister: 209 platform_device_put(pdev); 210 platform_driver_unregister(¨_rtc_driver); 211 return err; 212 } 213 device_initcall(uml_rtc_init); 214