summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
authorDario Binacchi <dariobin@libero.it>2021-06-02 22:38:01 +0200
committerLokesh Vutla <lokeshvutla@ti.com>2021-06-09 22:23:44 +0530
commit79250ef3e263ef23c16c3c06a50834f0dcca4426 (patch)
tree99fd0aa16b754472f247bb4b83132d784b12c6e2 /drivers/rtc
parent82a456a085facede0913a742660df9a1607d1543 (diff)
rtc: davinci: check BUSY bit before set TC registers
To write correct data to the TC registers, the STATUS register must be read until the BUSY bit is equal to zero. Once the BUSY flag is zero, there is a 15 μs access period in which the TC registers can be programmed. The rtc_wait_not_busy() has been inspired by the Kernel. Signed-off-by: Dario Binacchi <dariobin@libero.it> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com> Link: https://lore.kernel.org/r/20210602203805.11494-5-dariobin@libero.it
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/davinci.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c
index 99ae31e2a5..7b8c729f3b 100644
--- a/drivers/rtc/davinci.c
+++ b/drivers/rtc/davinci.c
@@ -16,19 +16,39 @@
#define RTC_BASE DAVINCI_RTC_BASE
#endif
-int rtc_get(struct rtc_time *tmp)
+static int davinci_rtc_wait_not_busy(struct davinci_rtc *rtc)
{
- struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
- unsigned long sec, min, hour, mday, wday, mon_cent, year;
- unsigned long status;
+ int count;
+ u8 status;
status = readb(&rtc->status);
if ((status & RTC_STATE_RUN) != RTC_STATE_RUN) {
printf("RTC doesn't run\n");
return -1;
}
- if ((status & RTC_STATE_BUSY) == RTC_STATE_BUSY)
- udelay(20);
+
+ /* BUSY may stay active for 1/32768 second (~30 usec) */
+ for (count = 0; count < 50; count++) {
+ if (!(status & RTC_STATE_BUSY))
+ break;
+
+ udelay(1);
+ status = readb(&rtc->status);
+ }
+
+ /* now we have ~15 usec to read/write various registers */
+ return 0;
+}
+
+int rtc_get(struct rtc_time *tmp)
+{
+ struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
+ unsigned long sec, min, hour, mday, wday, mon_cent, year;
+ int ret;
+
+ ret = davinci_rtc_wait_not_busy(rtc);
+ if (ret)
+ return ret;
sec = readb(&rtc->second);
min = readb(&rtc->minutes);
@@ -63,10 +83,12 @@ int rtc_get(struct rtc_time *tmp)
int rtc_set(struct rtc_time *tmp)
{
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
+ int ret;
+
+ ret = davinci_rtc_wait_not_busy(rtc);
+ if (ret)
+ return ret;
- debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
writeb(bin2bcd(tmp->tm_year % 100), &rtc->year);
writeb(bin2bcd(tmp->tm_mon), &rtc->month);
@@ -75,6 +97,11 @@ int rtc_set(struct rtc_time *tmp)
writeb(bin2bcd(tmp->tm_hour), &rtc->hours);
writeb(bin2bcd(tmp->tm_min), &rtc->minutes);
writeb(bin2bcd(tmp->tm_sec), &rtc->second);
+
+ debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
return 0;
}