LCOV - code coverage report
Current view: top level - drivers/rtc - rtc-mc146818-lib.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 81 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 2 0.0 %

          Line data    Source code
       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             : 
      11           0 : unsigned int mc146818_get_time(struct rtc_time *time)
      12             : {
      13           0 :         unsigned char ctrl;
      14           0 :         unsigned long flags;
      15           0 :         unsigned char century = 0;
      16           0 :         bool retry;
      17             : 
      18             : #ifdef CONFIG_MACH_DECSTATION
      19             :         unsigned int real_year;
      20             : #endif
      21             : 
      22             : again:
      23           0 :         spin_lock_irqsave(&rtc_lock, flags);
      24             :         /* Ensure that the RTC is accessible. Bit 6 must be 0! */
      25           0 :         if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) {
      26           0 :                 spin_unlock_irqrestore(&rtc_lock, flags);
      27           0 :                 memset(time, 0xff, sizeof(*time));
      28           0 :                 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           0 :         time->tm_sec = CMOS_READ(RTC_SECONDS);
      41             : 
      42           0 :         if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
      43           0 :                 spin_unlock_irqrestore(&rtc_lock, flags);
      44           0 :                 mdelay(1);
      45           0 :                 goto again;
      46             :         }
      47             : 
      48             :         /* Revalidate the above readout */
      49           0 :         if (time->tm_sec != CMOS_READ(RTC_SECONDS)) {
      50           0 :                 spin_unlock_irqrestore(&rtc_lock, flags);
      51           0 :                 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           0 :         time->tm_min = CMOS_READ(RTC_MINUTES);
      61           0 :         time->tm_hour = CMOS_READ(RTC_HOURS);
      62           0 :         time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
      63           0 :         time->tm_mon = CMOS_READ(RTC_MONTH);
      64           0 :         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           0 :         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           0 :         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           0 :         retry |= time->tm_sec != CMOS_READ(RTC_SECONDS);
      86             : 
      87           0 :         spin_unlock_irqrestore(&rtc_lock, flags);
      88             : 
      89           0 :         if (retry)
      90           0 :                 goto again;
      91             : 
      92           0 :         if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
      93             :         {
      94           0 :                 time->tm_sec = bcd2bin(time->tm_sec);
      95           0 :                 time->tm_min = bcd2bin(time->tm_min);
      96           0 :                 time->tm_hour = bcd2bin(time->tm_hour);
      97           0 :                 time->tm_mday = bcd2bin(time->tm_mday);
      98           0 :                 time->tm_mon = bcd2bin(time->tm_mon);
      99           0 :                 time->tm_year = bcd2bin(time->tm_year);
     100           0 :                 century = bcd2bin(century);
     101             :         }
     102             : 
     103             : #ifdef CONFIG_MACH_DECSTATION
     104             :         time->tm_year += real_year - 72;
     105             : #endif
     106             : 
     107           0 :         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           0 :         if (time->tm_year <= 69)
     115           0 :                 time->tm_year += 100;
     116             : 
     117           0 :         time->tm_mon--;
     118             : 
     119           0 :         return RTC_24H;
     120             : }
     121             : EXPORT_SYMBOL_GPL(mc146818_get_time);
     122             : 
     123             : /* Set the current date and time in the real time clock. */
     124           0 : int mc146818_set_time(struct rtc_time *time)
     125             : {
     126           0 :         unsigned long flags;
     127           0 :         unsigned char mon, day, hrs, min, sec;
     128           0 :         unsigned char save_control, save_freq_select;
     129           0 :         unsigned int yrs;
     130             : #ifdef CONFIG_MACH_DECSTATION
     131             :         unsigned int real_yrs, leap_yr;
     132             : #endif
     133           0 :         unsigned char century = 0;
     134             : 
     135           0 :         yrs = time->tm_year;
     136           0 :         mon = time->tm_mon + 1;   /* tm_mon starts at zero */
     137           0 :         day = time->tm_mday;
     138           0 :         hrs = time->tm_hour;
     139           0 :         min = time->tm_min;
     140           0 :         sec = time->tm_sec;
     141             : 
     142           0 :         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           0 :         if (yrs > 169)
     174             :                 return -EINVAL;
     175             : 
     176           0 :         if (yrs >= 100)
     177           0 :                 yrs -= 100;
     178             : 
     179           0 :         if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
     180             :             || RTC_ALWAYS_BCD) {
     181           0 :                 sec = bin2bcd(sec);
     182           0 :                 min = bin2bcd(min);
     183           0 :                 hrs = bin2bcd(hrs);
     184           0 :                 day = bin2bcd(day);
     185           0 :                 mon = bin2bcd(mon);
     186           0 :                 yrs = bin2bcd(yrs);
     187           0 :                 century = bin2bcd(century);
     188             :         }
     189             : 
     190           0 :         spin_lock_irqsave(&rtc_lock, flags);
     191           0 :         save_control = CMOS_READ(RTC_CONTROL);
     192           0 :         CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
     193           0 :         save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
     194           0 :         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           0 :         CMOS_WRITE(yrs, RTC_YEAR);
     200           0 :         CMOS_WRITE(mon, RTC_MONTH);
     201           0 :         CMOS_WRITE(day, RTC_DAY_OF_MONTH);
     202           0 :         CMOS_WRITE(hrs, RTC_HOURS);
     203           0 :         CMOS_WRITE(min, RTC_MINUTES);
     204           0 :         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           0 :         CMOS_WRITE(save_control, RTC_CONTROL);
     212           0 :         CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
     213             : 
     214           0 :         spin_unlock_irqrestore(&rtc_lock, flags);
     215             : 
     216           0 :         return 0;
     217             : }
     218             : EXPORT_SYMBOL_GPL(mc146818_set_time);

Generated by: LCOV version 1.14