rtc: pcf2127: Fix typo in comment
[linux-2.6-microblaze.git] / drivers / rtc / rtc-mc146818-lib.c
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  * Execute a function while the UIP (Update-in-progress) bit of the RTC is
13  * unset.
14  *
15  * Warning: callback may be executed more then once.
16  */
17 bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
18                         void *param)
19 {
20         int i;
21         unsigned long flags;
22         unsigned char seconds;
23
24         for (i = 0; i < 10; i++) {
25                 spin_lock_irqsave(&rtc_lock, flags);
26
27                 /*
28                  * Check whether there is an update in progress during which the
29                  * readout is unspecified. The maximum update time is ~2ms. Poll
30                  * every msec for completion.
31                  *
32                  * Store the second value before checking UIP so a long lasting
33                  * NMI which happens to hit after the UIP check cannot make
34                  * an update cycle invisible.
35                  */
36                 seconds = CMOS_READ(RTC_SECONDS);
37
38                 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
39                         spin_unlock_irqrestore(&rtc_lock, flags);
40                         mdelay(1);
41                         continue;
42                 }
43
44                 /* Revalidate the above readout */
45                 if (seconds != CMOS_READ(RTC_SECONDS)) {
46                         spin_unlock_irqrestore(&rtc_lock, flags);
47                         continue;
48                 }
49
50                 if (callback)
51                         callback(seconds, param);
52
53                 /*
54                  * Check for the UIP bit again. If it is set now then
55                  * the above values may contain garbage.
56                  */
57                 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
58                         spin_unlock_irqrestore(&rtc_lock, flags);
59                         mdelay(1);
60                         continue;
61                 }
62
63                 /*
64                  * A NMI might have interrupted the above sequence so check
65                  * whether the seconds value has changed which indicates that
66                  * the NMI took longer than the UIP bit was set. Unlikely, but
67                  * possible and there is also virt...
68                  */
69                 if (seconds != CMOS_READ(RTC_SECONDS)) {
70                         spin_unlock_irqrestore(&rtc_lock, flags);
71                         continue;
72                 }
73                 spin_unlock_irqrestore(&rtc_lock, flags);
74
75                 return true;
76         }
77         return false;
78 }
79 EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
80
81 /*
82  * If the UIP (Update-in-progress) bit of the RTC is set for more then
83  * 10ms, the RTC is apparently broken or not present.
84  */
85 bool mc146818_does_rtc_work(void)
86 {
87         return mc146818_avoid_UIP(NULL, NULL);
88 }
89 EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
90
91 struct mc146818_get_time_callback_param {
92         struct rtc_time *time;
93         unsigned char ctrl;
94 #ifdef CONFIG_ACPI
95         unsigned char century;
96 #endif
97 #ifdef CONFIG_MACH_DECSTATION
98         unsigned int real_year;
99 #endif
100 };
101
102 static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
103 {
104         struct mc146818_get_time_callback_param *p = param_in;
105
106         /*
107          * Only the values that we read from the RTC are set. We leave
108          * tm_wday, tm_yday and tm_isdst untouched. Even though the
109          * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
110          * by the RTC when initially set to a non-zero value.
111          */
112         p->time->tm_sec = seconds;
113         p->time->tm_min = CMOS_READ(RTC_MINUTES);
114         p->time->tm_hour = CMOS_READ(RTC_HOURS);
115         p->time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
116         p->time->tm_mon = CMOS_READ(RTC_MONTH);
117         p->time->tm_year = CMOS_READ(RTC_YEAR);
118 #ifdef CONFIG_MACH_DECSTATION
119         p->real_year = CMOS_READ(RTC_DEC_YEAR);
120 #endif
121 #ifdef CONFIG_ACPI
122         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
123             acpi_gbl_FADT.century) {
124                 p->century = CMOS_READ(acpi_gbl_FADT.century);
125         } else {
126                 p->century = 0;
127         }
128 #endif
129
130         p->ctrl = CMOS_READ(RTC_CONTROL);
131 }
132
133 unsigned int mc146818_get_time(struct rtc_time *time)
134 {
135         struct mc146818_get_time_callback_param p = {
136                 .time = time
137         };
138
139         if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
140                 memset(time, 0, sizeof(*time));
141                 return -EIO;
142         }
143
144         if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
145         {
146                 time->tm_sec = bcd2bin(time->tm_sec);
147                 time->tm_min = bcd2bin(time->tm_min);
148                 time->tm_hour = bcd2bin(time->tm_hour);
149                 time->tm_mday = bcd2bin(time->tm_mday);
150                 time->tm_mon = bcd2bin(time->tm_mon);
151                 time->tm_year = bcd2bin(time->tm_year);
152 #ifdef CONFIG_ACPI
153                 p.century = bcd2bin(p.century);
154 #endif
155         }
156
157 #ifdef CONFIG_MACH_DECSTATION
158         time->tm_year += p.real_year - 72;
159 #endif
160
161 #ifdef CONFIG_ACPI
162         if (p.century > 20)
163                 time->tm_year += (p.century - 19) * 100;
164 #endif
165
166         /*
167          * Account for differences between how the RTC uses the values
168          * and how they are defined in a struct rtc_time;
169          */
170         if (time->tm_year <= 69)
171                 time->tm_year += 100;
172
173         time->tm_mon--;
174
175         return 0;
176 }
177 EXPORT_SYMBOL_GPL(mc146818_get_time);
178
179 /* Set the current date and time in the real time clock. */
180 int mc146818_set_time(struct rtc_time *time)
181 {
182         unsigned long flags;
183         unsigned char mon, day, hrs, min, sec;
184         unsigned char save_control, save_freq_select;
185         unsigned int yrs;
186 #ifdef CONFIG_MACH_DECSTATION
187         unsigned int real_yrs, leap_yr;
188 #endif
189         unsigned char century = 0;
190
191         yrs = time->tm_year;
192         mon = time->tm_mon + 1;   /* tm_mon starts at zero */
193         day = time->tm_mday;
194         hrs = time->tm_hour;
195         min = time->tm_min;
196         sec = time->tm_sec;
197
198         if (yrs > 255)  /* They are unsigned */
199                 return -EINVAL;
200
201 #ifdef CONFIG_MACH_DECSTATION
202         real_yrs = yrs;
203         leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
204                         !((yrs + 1900) % 400));
205         yrs = 72;
206
207         /*
208          * We want to keep the year set to 73 until March
209          * for non-leap years, so that Feb, 29th is handled
210          * correctly.
211          */
212         if (!leap_yr && mon < 3) {
213                 real_yrs--;
214                 yrs = 73;
215         }
216 #endif
217
218 #ifdef CONFIG_ACPI
219         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
220             acpi_gbl_FADT.century) {
221                 century = (yrs + 1900) / 100;
222                 yrs %= 100;
223         }
224 #endif
225
226         /* These limits and adjustments are independent of
227          * whether the chip is in binary mode or not.
228          */
229         if (yrs > 169)
230                 return -EINVAL;
231
232         if (yrs >= 100)
233                 yrs -= 100;
234
235         if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
236             || RTC_ALWAYS_BCD) {
237                 sec = bin2bcd(sec);
238                 min = bin2bcd(min);
239                 hrs = bin2bcd(hrs);
240                 day = bin2bcd(day);
241                 mon = bin2bcd(mon);
242                 yrs = bin2bcd(yrs);
243                 century = bin2bcd(century);
244         }
245
246         spin_lock_irqsave(&rtc_lock, flags);
247         save_control = CMOS_READ(RTC_CONTROL);
248         CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
249         save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
250         CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
251
252 #ifdef CONFIG_MACH_DECSTATION
253         CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
254 #endif
255         CMOS_WRITE(yrs, RTC_YEAR);
256         CMOS_WRITE(mon, RTC_MONTH);
257         CMOS_WRITE(day, RTC_DAY_OF_MONTH);
258         CMOS_WRITE(hrs, RTC_HOURS);
259         CMOS_WRITE(min, RTC_MINUTES);
260         CMOS_WRITE(sec, RTC_SECONDS);
261 #ifdef CONFIG_ACPI
262         if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
263             acpi_gbl_FADT.century)
264                 CMOS_WRITE(century, acpi_gbl_FADT.century);
265 #endif
266
267         CMOS_WRITE(save_control, RTC_CONTROL);
268         CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
269
270         spin_unlock_irqrestore(&rtc_lock, flags);
271
272         return 0;
273 }
274 EXPORT_SYMBOL_GPL(mc146818_set_time);