ds1302: add detection logic
authorAlan Cox <alan@linux.intel.com>
Sun, 27 Jan 2019 21:26:32 +0000 (21:26 +0000)
committerAlan Cox <alan@linux.intel.com>
Sun, 27 Jan 2019 21:26:32 +0000 (21:26 +0000)
Kernel/dev/ds1302.c
Kernel/dev/ds1302.h
Kernel/dev/ds1302_discard.c

index e0adf3b..f141170 100644 (file)
@@ -12,6 +12,8 @@
 #include <rtc.h>
 #include <ds1302.h>
 
+uint8_t ds1302_present;
+
 void ds1302_send_byte(uint8_t byte)
 {
     uint8_t i;
@@ -81,8 +83,11 @@ void ds1302_read_clock(uint8_t *buffer, uint8_t length)
 uint8_t platform_rtc_secs(void)
 {
     uint8_t buffer;
-    ds1302_read_clock(&buffer, 1);   /* read out only the seconds value */
-    return uint8_from_bcd(buffer & 0x7F); /* mask off top bit (clock-halt) */
+    if (ds1302_present) {
+        ds1302_read_clock(&buffer, 1);   /* read out only the seconds value */
+        return uint8_from_bcd(buffer & 0x7F); /* mask off top bit (clock-halt) */
+    }
+    return 0xFF;
 }
 
 static uint8_t rtc_buf[8];
@@ -95,6 +100,11 @@ int platform_rtc_read(void)
        struct cmos_rtc cmos;
        uint8_t *p = cmos.data.bytes;
 
+       if (!ds1302_present) {
+               udata.u_error = EOPNOTSUPP;
+               return -1;
+       }
+
        if (udata.u_count < len)
                len = udata.u_count;
 
@@ -129,6 +139,6 @@ int platform_rtc_read(void)
 
 int platform_rtc_write(void)
 {
-       udata.u_error = -EOPNOTSUPP;
+       udata.u_error = EOPNOTSUPP;
        return -1;
 }
index 4315d9d..aa3ca7c 100644 (file)
@@ -2,12 +2,14 @@
 #define __DS1302_DOT_H__
 
 /* public interface */
-void ds1302_init(void);
+uint8_t ds1302_init(void);
 uint8_t platform_rtc_secs(void);
 void ds1302_read_clock(uint8_t *buffer, uint8_t length);
 int platform_rtc_read(void);
 int platform_rtc_write(void);
 
+extern uint8_t ds1302_present;
+
 #ifdef _DS1302_PRIVATE
 /* consult the DS1302 datasheet for data format;
    http://datasheets.maximintegrated.com/en/ds/DS1302.pdf table 3 */
index 7f52029..754887e 100644 (file)
@@ -35,27 +35,53 @@ void ds1302_write_seconds(uint8_t seconds)
     irqrestore(irq);
 }
 
-void ds1302_check_rtc(void)
+static uint8_t bad_bcd(uint8_t x, uint8_t max)
+{
+    uint8_t c;
+
+    c = x >> 4;
+    x &= 15;
+    if (c > 9 || x > 9)
+        return 1;
+    c = c * 10 + x;
+    if (c > max)
+        return 1;
+    return 0;
+}
+
+uint8_t ds1302_check_rtc(void)
 {
     uint8_t buffer[7];
 
     ds1302_read_clock(buffer, 7); /* read all calendar data */
 
+    if (bad_bcd(buffer[0] & 0x7F, 59) ||
+        bad_bcd(buffer[1], 59) ||
+        bad_bcd(buffer[3], 31) ||
+        bad_bcd(buffer[4], 12) ||
+        bad_bcd(buffer[5], 7) ||
+        bad_bcd(buffer[6], 99))
+            return 0;
+
     if(buffer[0] & 0x80){ /* is the clock halted? */
         kputs("ds1302: start clock\n");
         ds1302_write_seconds(buffer[0] & 0x7F); /* start it */
     }
+    ds1302_read_clock(buffer, 7);
+    if (buffer[0] & 0x80)
+        return 0;
+    return 1;
 }
 
-void ds1302_init(void)
+uint8_t ds1302_init(void)
 {
-    time_t tod;
-
     /* initialise the hardware into a sensible state */
     ds1302_set_pin_data_driven(true);
     ds1302_set_pin_data(false);
     ds1302_set_pin_ce(false);
     ds1302_set_pin_clk(false);
-    ds1302_check_rtc();
-    wrtime(&tod);
+    if (ds1302_check_rtc() == 0)
+        return 0;
+    ds1302_present = 1;
+    return 1;
 }