From 227d0698e501feee6efe5e2eff31ce1a981f7cf7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Jan 2019 21:26:32 +0000 Subject: [PATCH] ds1302: add detection logic --- Kernel/dev/ds1302.c | 16 +++++++++++++--- Kernel/dev/ds1302.h | 4 +++- Kernel/dev/ds1302_discard.c | 38 +++++++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Kernel/dev/ds1302.c b/Kernel/dev/ds1302.c index e0adf3b4..f141170e 100644 --- a/Kernel/dev/ds1302.c +++ b/Kernel/dev/ds1302.c @@ -12,6 +12,8 @@ #include #include +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; } diff --git a/Kernel/dev/ds1302.h b/Kernel/dev/ds1302.h index 4315d9d6..aa3ca7c6 100644 --- a/Kernel/dev/ds1302.h +++ b/Kernel/dev/ds1302.h @@ -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 */ diff --git a/Kernel/dev/ds1302_discard.c b/Kernel/dev/ds1302_discard.c index 7f520296..754887eb 100644 --- a/Kernel/dev/ds1302_discard.c +++ b/Kernel/dev/ds1302_discard.c @@ -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; } -- 2.34.1