~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/rtc.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * RTC related functions
  4  */
  5 #include <linux/platform_device.h>
  6 #include <linux/mc146818rtc.h>
  7 #include <linux/export.h>
  8 #include <linux/pnp.h>
  9 
 10 #include <asm/vsyscall.h>
 11 #include <asm/x86_init.h>
 12 #include <asm/time.h>
 13 #include <asm/setup.h>
 14 
 15 #ifdef CONFIG_X86_32
 16 /*
 17  * This is a special lock that is owned by the CPU and holds the index
 18  * register we are working with.  It is required for NMI access to the
 19  * CMOS/RTC registers.  See arch/x86/include/asm/mc146818rtc.h for details.
 20  */
 21 volatile unsigned long cmos_lock;
 22 EXPORT_SYMBOL(cmos_lock);
 23 #endif /* CONFIG_X86_32 */
 24 
 25 DEFINE_SPINLOCK(rtc_lock);
 26 EXPORT_SYMBOL(rtc_lock);
 27 
 28 /*
 29  * In order to set the CMOS clock precisely, mach_set_cmos_time has to be
 30  * called 500 ms after the second nowtime has started, because when
 31  * nowtime is written into the registers of the CMOS clock, it will
 32  * jump to the next second precisely 500 ms later. Check the Motorola
 33  * MC146818A or Dallas DS12887 data sheet for details.
 34  */
 35 int mach_set_cmos_time(const struct timespec64 *now)
 36 {
 37         unsigned long long nowtime = now->tv_sec;
 38         struct rtc_time tm;
 39         int retval = 0;
 40 
 41         rtc_time64_to_tm(nowtime, &tm);
 42         if (!rtc_valid_tm(&tm)) {
 43                 retval = mc146818_set_time(&tm);
 44                 if (retval)
 45                         printk(KERN_ERR "%s: RTC write failed with error %d\n",
 46                                __func__, retval);
 47         } else {
 48                 printk(KERN_ERR
 49                        "%s: Invalid RTC value: write of %llx to RTC failed\n",
 50                         __func__, nowtime);
 51                 retval = -EINVAL;
 52         }
 53         return retval;
 54 }
 55 
 56 void mach_get_cmos_time(struct timespec64 *now)
 57 {
 58         struct rtc_time tm;
 59 
 60         /*
 61          * If pm_trace abused the RTC as storage, set the timespec to 0,
 62          * which tells the caller that this RTC value is unusable.
 63          */
 64         if (!pm_trace_rtc_valid()) {
 65                 now->tv_sec = now->tv_nsec = 0;
 66                 return;
 67         }
 68 
 69         if (mc146818_get_time(&tm, 1000)) {
 70                 pr_err("Unable to read current time from RTC\n");
 71                 now->tv_sec = now->tv_nsec = 0;
 72                 return;
 73         }
 74 
 75         now->tv_sec = rtc_tm_to_time64(&tm);
 76         now->tv_nsec = 0;
 77 }
 78 
 79 /* Routines for accessing the CMOS RAM/RTC. */
 80 unsigned char rtc_cmos_read(unsigned char addr)
 81 {
 82         unsigned char val;
 83 
 84         lock_cmos_prefix(addr);
 85         outb(addr, RTC_PORT(0));
 86         val = inb(RTC_PORT(1));
 87         lock_cmos_suffix(addr);
 88 
 89         return val;
 90 }
 91 EXPORT_SYMBOL(rtc_cmos_read);
 92 
 93 void rtc_cmos_write(unsigned char val, unsigned char addr)
 94 {
 95         lock_cmos_prefix(addr);
 96         outb(addr, RTC_PORT(0));
 97         outb(val, RTC_PORT(1));
 98         lock_cmos_suffix(addr);
 99 }
100 EXPORT_SYMBOL(rtc_cmos_write);
101 
102 int update_persistent_clock64(struct timespec64 now)
103 {
104         return x86_platform.set_wallclock(&now);
105 }
106 
107 /* not static: needed by APM */
108 void read_persistent_clock64(struct timespec64 *ts)
109 {
110         x86_platform.get_wallclock(ts);
111 }
112 
113 
114 static struct resource rtc_resources[] = {
115         [0] = {
116                 .start  = RTC_PORT(0),
117                 .end    = RTC_PORT(1),
118                 .flags  = IORESOURCE_IO,
119         },
120         [1] = {
121                 .start  = RTC_IRQ,
122                 .end    = RTC_IRQ,
123                 .flags  = IORESOURCE_IRQ,
124         }
125 };
126 
127 static struct platform_device rtc_device = {
128         .name           = "rtc_cmos",
129         .id             = -1,
130         .resource       = rtc_resources,
131         .num_resources  = ARRAY_SIZE(rtc_resources),
132 };
133 
134 static __init int add_rtc_cmos(void)
135 {
136 #ifdef CONFIG_PNP
137         static const char * const ids[] __initconst =
138             { "PNP0b00", "PNP0b01", "PNP0b02", };
139         struct pnp_dev *dev;
140         int i;
141 
142         pnp_for_each_dev(dev) {
143                 for (i = 0; i < ARRAY_SIZE(ids); i++) {
144                         if (compare_pnp_id(dev->id, ids[i]) != 0)
145                                 return 0;
146                 }
147         }
148 #endif
149         if (!x86_platform.legacy.rtc)
150                 return -ENODEV;
151 
152         platform_device_register(&rtc_device);
153         dev_info(&rtc_device.dev,
154                  "registered platform RTC device (no PNP device found)\n");
155 
156         return 0;
157 }
158 device_initcall(add_rtc_cmos);
159 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php