LCOV - code coverage report
Current view: top level - drivers/rtc - rtc-mc146818-lib.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 35 87 40.2 %
Date: 2022-03-28 16:04:14 Functions: 2 3 66.7 %
Branches: 11 54 20.4 %

           Branch data     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                 :            : /*
      12                 :            :  * Returns true if a clock update is in progress
      13                 :            :  */
      14                 :         52 : static inline unsigned char mc146818_is_updating(void)
      15                 :            : {
      16                 :         52 :         unsigned char uip;
      17                 :         52 :         unsigned long flags;
      18                 :            : 
      19                 :         52 :         spin_lock_irqsave(&rtc_lock, flags);
      20                 :         52 :         uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
      21                 :         52 :         spin_unlock_irqrestore(&rtc_lock, flags);
      22                 :         52 :         return uip;
      23                 :            : }
      24                 :            : 
      25                 :         52 : unsigned int mc146818_get_time(struct rtc_time *time)
      26                 :            : {
      27                 :         52 :         unsigned char ctrl;
      28                 :         52 :         unsigned long flags;
      29                 :         52 :         unsigned char century = 0;
      30                 :            : 
      31                 :            : #ifdef CONFIG_MACH_DECSTATION
      32                 :            :         unsigned int real_year;
      33                 :            : #endif
      34                 :            : 
      35                 :            :         /*
      36                 :            :          * read RTC once any update in progress is done. The update
      37                 :            :          * can take just over 2ms. We wait 20ms. There is no need to
      38                 :            :          * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
      39                 :            :          * If you need to know *exactly* when a second has started, enable
      40                 :            :          * periodic update complete interrupts, (via ioctl) and then
      41                 :            :          * immediately read /dev/rtc which will block until you get the IRQ.
      42                 :            :          * Once the read clears, read the RTC time (again via ioctl). Easy.
      43                 :            :          */
      44         [ -  + ]:         52 :         if (mc146818_is_updating())
      45         [ #  # ]:          0 :                 mdelay(20);
      46                 :            : 
      47                 :            :         /*
      48                 :            :          * Only the values that we read from the RTC are set. We leave
      49                 :            :          * tm_wday, tm_yday and tm_isdst untouched. Even though the
      50                 :            :          * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
      51                 :            :          * by the RTC when initially set to a non-zero value.
      52                 :            :          */
      53                 :         52 :         spin_lock_irqsave(&rtc_lock, flags);
      54                 :         52 :         time->tm_sec = CMOS_READ(RTC_SECONDS);
      55                 :         52 :         time->tm_min = CMOS_READ(RTC_MINUTES);
      56                 :         52 :         time->tm_hour = CMOS_READ(RTC_HOURS);
      57                 :         52 :         time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
      58                 :         52 :         time->tm_mon = CMOS_READ(RTC_MONTH);
      59                 :         52 :         time->tm_year = CMOS_READ(RTC_YEAR);
      60                 :            : #ifdef CONFIG_MACH_DECSTATION
      61                 :            :         real_year = CMOS_READ(RTC_DEC_YEAR);
      62                 :            : #endif
      63                 :            : #ifdef CONFIG_ACPI
      64         [ -  + ]:         52 :         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
      65         [ #  # ]:          0 :             acpi_gbl_FADT.century)
      66                 :          0 :                 century = CMOS_READ(acpi_gbl_FADT.century);
      67                 :            : #endif
      68                 :         52 :         ctrl = CMOS_READ(RTC_CONTROL);
      69                 :         52 :         spin_unlock_irqrestore(&rtc_lock, flags);
      70                 :            : 
      71                 :         52 :         if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
      72                 :            :         {
      73         [ -  + ]:         52 :                 time->tm_sec = bcd2bin(time->tm_sec);
      74         [ -  + ]:         52 :                 time->tm_min = bcd2bin(time->tm_min);
      75         [ -  + ]:         52 :                 time->tm_hour = bcd2bin(time->tm_hour);
      76         [ -  + ]:         52 :                 time->tm_mday = bcd2bin(time->tm_mday);
      77         [ -  + ]:         52 :                 time->tm_mon = bcd2bin(time->tm_mon);
      78         [ -  + ]:         52 :                 time->tm_year = bcd2bin(time->tm_year);
      79         [ -  + ]:         52 :                 century = bcd2bin(century);
      80                 :            :         }
      81                 :            : 
      82                 :            : #ifdef CONFIG_MACH_DECSTATION
      83                 :            :         time->tm_year += real_year - 72;
      84                 :            : #endif
      85                 :            : 
      86         [ -  + ]:         52 :         if (century > 20)
      87                 :          0 :                 time->tm_year += (century - 19) * 100;
      88                 :            : 
      89                 :            :         /*
      90                 :            :          * Account for differences between how the RTC uses the values
      91                 :            :          * and how they are defined in a struct rtc_time;
      92                 :            :          */
      93         [ +  - ]:         52 :         if (time->tm_year <= 69)
      94                 :         52 :                 time->tm_year += 100;
      95                 :            : 
      96                 :         52 :         time->tm_mon--;
      97                 :            : 
      98                 :         52 :         return RTC_24H;
      99                 :            : }
     100                 :            : EXPORT_SYMBOL_GPL(mc146818_get_time);
     101                 :            : 
     102                 :            : /* Set the current date and time in the real time clock. */
     103                 :          0 : int mc146818_set_time(struct rtc_time *time)
     104                 :            : {
     105                 :          0 :         unsigned long flags;
     106                 :          0 :         unsigned char mon, day, hrs, min, sec;
     107                 :          0 :         unsigned char save_control, save_freq_select;
     108                 :          0 :         unsigned int yrs;
     109                 :            : #ifdef CONFIG_MACH_DECSTATION
     110                 :            :         unsigned int real_yrs, leap_yr;
     111                 :            : #endif
     112                 :          0 :         unsigned char century = 0;
     113                 :            : 
     114                 :          0 :         yrs = time->tm_year;
     115                 :          0 :         mon = time->tm_mon + 1;   /* tm_mon starts at zero */
     116                 :          0 :         day = time->tm_mday;
     117                 :          0 :         hrs = time->tm_hour;
     118                 :          0 :         min = time->tm_min;
     119                 :          0 :         sec = time->tm_sec;
     120                 :            : 
     121         [ #  # ]:          0 :         if (yrs > 255)       /* They are unsigned */
     122                 :            :                 return -EINVAL;
     123                 :            : 
     124                 :          0 :         spin_lock_irqsave(&rtc_lock, flags);
     125                 :            : #ifdef CONFIG_MACH_DECSTATION
     126                 :            :         real_yrs = yrs;
     127                 :            :         leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
     128                 :            :                         !((yrs + 1900) % 400));
     129                 :            :         yrs = 72;
     130                 :            : 
     131                 :            :         /*
     132                 :            :          * We want to keep the year set to 73 until March
     133                 :            :          * for non-leap years, so that Feb, 29th is handled
     134                 :            :          * correctly.
     135                 :            :          */
     136                 :            :         if (!leap_yr && mon < 3) {
     137                 :            :                 real_yrs--;
     138                 :            :                 yrs = 73;
     139                 :            :         }
     140                 :            : #endif
     141                 :            : 
     142                 :            : #ifdef CONFIG_ACPI
     143         [ #  # ]:          0 :         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
     144         [ #  # ]:          0 :             acpi_gbl_FADT.century) {
     145                 :          0 :                 century = (yrs + 1900) / 100;
     146                 :          0 :                 yrs %= 100;
     147                 :            :         }
     148                 :            : #endif
     149                 :            : 
     150                 :            :         /* These limits and adjustments are independent of
     151                 :            :          * whether the chip is in binary mode or not.
     152                 :            :          */
     153         [ #  # ]:          0 :         if (yrs > 169) {
     154                 :          0 :                 spin_unlock_irqrestore(&rtc_lock, flags);
     155                 :          0 :                 return -EINVAL;
     156                 :            :         }
     157                 :            : 
     158         [ #  # ]:          0 :         if (yrs >= 100)
     159                 :          0 :                 yrs -= 100;
     160                 :            : 
     161                 :          0 :         if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
     162                 :            :             || RTC_ALWAYS_BCD) {
     163         [ #  # ]:          0 :                 sec = bin2bcd(sec);
     164         [ #  # ]:          0 :                 min = bin2bcd(min);
     165         [ #  # ]:          0 :                 hrs = bin2bcd(hrs);
     166         [ #  # ]:          0 :                 day = bin2bcd(day);
     167         [ #  # ]:          0 :                 mon = bin2bcd(mon);
     168         [ #  # ]:          0 :                 yrs = bin2bcd(yrs);
     169         [ #  # ]:          0 :                 century = bin2bcd(century);
     170                 :            :         }
     171                 :            : 
     172                 :          0 :         save_control = CMOS_READ(RTC_CONTROL);
     173                 :          0 :         CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
     174                 :          0 :         save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
     175                 :          0 :         CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
     176                 :            : 
     177                 :            : #ifdef CONFIG_MACH_DECSTATION
     178                 :            :         CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
     179                 :            : #endif
     180                 :          0 :         CMOS_WRITE(yrs, RTC_YEAR);
     181                 :          0 :         CMOS_WRITE(mon, RTC_MONTH);
     182                 :          0 :         CMOS_WRITE(day, RTC_DAY_OF_MONTH);
     183                 :          0 :         CMOS_WRITE(hrs, RTC_HOURS);
     184                 :          0 :         CMOS_WRITE(min, RTC_MINUTES);
     185                 :          0 :         CMOS_WRITE(sec, RTC_SECONDS);
     186                 :            : #ifdef CONFIG_ACPI
     187         [ #  # ]:          0 :         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
     188         [ #  # ]:          0 :             acpi_gbl_FADT.century)
     189                 :          0 :                 CMOS_WRITE(century, acpi_gbl_FADT.century);
     190                 :            : #endif
     191                 :            : 
     192                 :          0 :         CMOS_WRITE(save_control, RTC_CONTROL);
     193                 :          0 :         CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
     194                 :            : 
     195                 :          0 :         spin_unlock_irqrestore(&rtc_lock, flags);
     196                 :            : 
     197                 :          0 :         return 0;
     198                 :            : }
     199                 :            : EXPORT_SYMBOL_GPL(mc146818_set_time);

Generated by: LCOV version 1.14