linux/drivers/rtc/rtc-mc146818-lib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2#include <linux/bcd.h>
   3#include <linux/delay.h>
   4#include <linux/export.h>
   5#include <linux/mc146818rtc.h>
   6
   7#ifdef CONFIG_ACPI
   8#include <linux/acpi.h>
   9#endif
  10
  11unsigned int mc146818_get_time(struct rtc_time *time)
  12{
  13        unsigned char ctrl;
  14        unsigned long flags;
  15        unsigned char century = 0;
  16        bool retry;
  17
  18#ifdef CONFIG_MACH_DECSTATION
  19        unsigned int real_year;
  20#endif
  21
  22again:
  23        spin_lock_irqsave(&rtc_lock, flags);
  24        /* Ensure that the RTC is accessible. Bit 6 must be 0! */
  25        if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) {
  26                spin_unlock_irqrestore(&rtc_lock, flags);
  27                memset(time, 0xff, sizeof(*time));
  28                return 0;
  29        }
  30
  31        /*
  32         * Check whether there is an update in progress during which the
  33         * readout is unspecified. The maximum update time is ~2ms. Poll
  34         * every msec for completion.
  35         *
  36         * Store the second value before checking UIP so a long lasting NMI
  37         * which happens to hit after the UIP check cannot make an update
  38         * cycle invisible.
  39         */
  40        time->tm_sec = CMOS_READ(RTC_SECONDS);
  41
  42        if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
  43                spin_unlock_irqrestore(&rtc_lock, flags);
  44                mdelay(1);
  45                goto again;
  46        }
  47
  48        /* Revalidate the above readout */
  49        if (time->tm_sec != CMOS_READ(RTC_SECONDS)) {
  50                spin_unlock_irqrestore(&rtc_lock, flags);
  51                goto again;
  52        }
  53
  54        /*
  55         * Only the values that we read from the RTC are set. We leave
  56         * tm_wday, tm_yday and tm_isdst untouched. Even though the
  57         * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
  58         * by the RTC when initially set to a non-zero value.
  59         */
  60        time->tm_min = CMOS_READ(RTC_MINUTES);
  61        time->tm_hour = CMOS_READ(RTC_HOURS);
  62        time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
  63        time->tm_mon = CMOS_READ(RTC_MONTH);
  64        time->tm_year = CMOS_READ(RTC_YEAR);
  65#ifdef CONFIG_MACH_DECSTATION
  66        real_year = CMOS_READ(RTC_DEC_YEAR);
  67#endif
  68#ifdef CONFIG_ACPI
  69        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
  70            acpi_gbl_FADT.century)
  71                century = CMOS_READ(acpi_gbl_FADT.century);
  72#endif
  73        ctrl = CMOS_READ(RTC_CONTROL);
  74        /*
  75         * Check for the UIP bit again. If it is set now then
  76         * the above values may contain garbage.
  77         */
  78        retry = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
  79        /*
  80         * A NMI might have interrupted the above sequence so check whether
  81         * the seconds value has changed which indicates that the NMI took
  82         * longer than the UIP bit was set. Unlikely, but possible and
  83         * there is also virt...
  84         */
  85        retry |= time->tm_sec != CMOS_READ(RTC_SECONDS);
  86
  87        spin_unlock_irqrestore(&rtc_lock, flags);
  88
  89        if (retry)
  90                goto again;
  91
  92        if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  93        {
  94                time->tm_sec = bcd2bin(time->tm_sec);
  95                time->tm_min = bcd2bin(time->tm_min);
  96                time->tm_hour = bcd2bin(time->tm_hour);
  97                time->tm_mday = bcd2bin(time->tm_mday);
  98                time->tm_mon = bcd2bin(time->tm_mon);
  99                time->tm_year = bcd2bin(time->tm_year);
 100                century = bcd2bin(century);
 101        }
 102
 103#ifdef CONFIG_MACH_DECSTATION
 104        time->tm_year += real_year - 72;
 105#endif
 106
 107        if (century > 20)
 108                time->tm_year += (century - 19) * 100;
 109
 110        /*
 111         * Account for differences between how the RTC uses the values
 112         * and how they are defined in a struct rtc_time;
 113         */
 114        if (time->tm_year <= 69)
 115                time->tm_year += 100;
 116
 117        time->tm_mon--;
 118
 119        return RTC_24H;
 120}
 121EXPORT_SYMBOL_GPL(mc146818_get_time);
 122
 123/* Set the current date and time in the real time clock. */
 124int mc146818_set_time(struct rtc_time *time)
 125{
 126        unsigned long flags;
 127        unsigned char mon, day, hrs, min, sec;
 128        unsigned char save_control, save_freq_select;
 129        unsigned int yrs;
 130#ifdef CONFIG_MACH_DECSTATION
 131        unsigned int real_yrs, leap_yr;
 132#endif
 133        unsigned char century = 0;
 134
 135        yrs = time->tm_year;
 136        mon = time->tm_mon + 1;   /* tm_mon starts at zero */
 137        day = time->tm_mday;
 138        hrs = time->tm_hour;
 139        min = time->tm_min;
 140        sec = time->tm_sec;
 141
 142        if (yrs > 255)  /* They are unsigned */
 143                return -EINVAL;
 144
 145#ifdef CONFIG_MACH_DECSTATION
 146        real_yrs = yrs;
 147        leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
 148                        !((yrs + 1900) % 400));
 149        yrs = 72;
 150
 151        /*
 152         * We want to keep the year set to 73 until March
 153         * for non-leap years, so that Feb, 29th is handled
 154         * correctly.
 155         */
 156        if (!leap_yr && mon < 3) {
 157                real_yrs--;
 158                yrs = 73;
 159        }
 160#endif
 161
 162#ifdef CONFIG_ACPI
 163        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
 164            acpi_gbl_FADT.century) {
 165                century = (yrs + 1900) / 100;
 166                yrs %= 100;
 167        }
 168#endif
 169
 170        /* These limits and adjustments are independent of
 171         * whether the chip is in binary mode or not.
 172         */
 173        if (yrs > 169)
 174                return -EINVAL;
 175
 176        if (yrs >= 100)
 177                yrs -= 100;
 178
 179        if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
 180            || RTC_ALWAYS_BCD) {
 181                sec = bin2bcd(sec);
 182                min = bin2bcd(min);
 183                hrs = bin2bcd(hrs);
 184                day = bin2bcd(day);
 185                mon = bin2bcd(mon);
 186                yrs = bin2bcd(yrs);
 187                century = bin2bcd(century);
 188        }
 189
 190        spin_lock_irqsave(&rtc_lock, flags);
 191        save_control = CMOS_READ(RTC_CONTROL);
 192        CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
 193        save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
 194        CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 195
 196#ifdef CONFIG_MACH_DECSTATION
 197        CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
 198#endif
 199        CMOS_WRITE(yrs, RTC_YEAR);
 200        CMOS_WRITE(mon, RTC_MONTH);
 201        CMOS_WRITE(day, RTC_DAY_OF_MONTH);
 202        CMOS_WRITE(hrs, RTC_HOURS);
 203        CMOS_WRITE(min, RTC_MINUTES);
 204        CMOS_WRITE(sec, RTC_SECONDS);
 205#ifdef CONFIG_ACPI
 206        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
 207            acpi_gbl_FADT.century)
 208                CMOS_WRITE(century, acpi_gbl_FADT.century);
 209#endif
 210
 211        CMOS_WRITE(save_control, RTC_CONTROL);
 212        CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 213
 214        spin_unlock_irqrestore(&rtc_lock, flags);
 215
 216        return 0;
 217}
 218EXPORT_SYMBOL_GPL(mc146818_set_time);
 219