From: Will Sowerbutts Date: Thu, 1 Jan 2015 13:58:49 +0000 (+0000) Subject: Kernel: Add generic DS1202/DS1302 Serial Real Time Clock driver X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=64c22af56abc40b84a4aef92105f83a15e68e277;p=FUZIX.git Kernel: Add generic DS1202/DS1302 Serial Real Time Clock driver --- diff --git a/Kernel/dev/ds1302.c b/Kernel/dev/ds1302.c new file mode 100644 index 00000000..065b080b --- /dev/null +++ b/Kernel/dev/ds1302.c @@ -0,0 +1,214 @@ +/*-----------------------------------------------------------------------*/ +/* DS1202 and DS1302 Serial Real Time Clock driver */ +/* 2014-12-30 Will Sowerbutts */ +/*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +static void ds1302_send_byte(uint8_t byte) +{ + uint8_t i; + +#ifdef DS1302_DEBUG + kprintf("ds1302: send byte 0x%x\n", byte); +#endif + /* drive the data pin */ + ds1302_set_pin_data_driven(true); + + /* clock out one byte, LSB first */ + for(i=0; i<8; i++){ + ds1302_set_pin_clk(false); + /* for data input to the chip the data must be valid on the rising edge of the clock */ + ds1302_set_pin_data(byte & 1); + byte >>= 1; + ds1302_set_pin_clk(true); + } +} + +static uint8_t ds1302_receive_byte(void) +{ + uint8_t i, b; + + /* tri-state the data pin */ + ds1302_set_pin_data_driven(false); + + /* clock in one byte, LSB first */ + b = 0; + for(i=0; i<8; i++){ + ds1302_set_pin_clk(false); + b >>= 1; + /* data output from the chip is presented on the falling edge of each clock */ + /* note that output pin goes high-impedance on the rising edge of each clock */ + if(ds1302_get_pin_data()) + b |= 0x80; + ds1302_set_pin_clk(true); + } + + return b; +} + +static uint8_t from_bcd(uint8_t value) +{ + return (value & 0x0F) + (10 * (value >> 4)); +} + +void ds1302_read_clock(uint8_t *buffer, uint8_t length) +{ + uint8_t i; + irqflags_t irq = di(); + + ds1302_set_pin_ce(true); + ds1302_send_byte(0x81 | 0x3E); /* burst read all calendar data */ + for(i=0; i> 2); + + /* calculate days from months */ + ret += mktime_moffset[month]; + + /* add in this year's leap day, if any */ + if (((year & 3) == 0) && (month > 1)) { + ret ++; + } + + /* add in days in this month */ + ret += (day - 1); + + /* convert to hours */ + ret = multiply_8x32(24, ret); + ret += hour; + + /* convert to minutes */ + ret = multiply_8x32(60, ret); + ret += minute; + + /* convert to seconds */ + ret = multiply_8x32(60, ret); + ret += second; + + /* return the result */ + return ret; +} + +void 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); + + tod.high = 0; /* until 2106 */ + tod.low = ds1302_read_rtc(); + wrtime(&tod); +} diff --git a/Kernel/dev/ds1302.h b/Kernel/dev/ds1302.h new file mode 100644 index 00000000..0c488e59 --- /dev/null +++ b/Kernel/dev/ds1302.h @@ -0,0 +1,18 @@ +#ifndef __DS1302_DOT_H__ +#define __DS1302_DOT_H__ + +/* public interface */ +void ds1302_init(void); +uint8_t rtc_secs(void); +/* consult the DS1302 datasheet for data format; + http://datasheets.maximintegrated.com/en/ds/DS1302.pdf table 3 */ +void ds1302_read_clock(uint8_t *buffer, uint8_t length); + +/* platform code must provide these functions */ +void ds1302_set_pin_clk(bool state); +void ds1302_set_pin_ce(bool state); +void ds1302_set_pin_data(bool state); +bool ds1302_get_pin_data(void); +void ds1302_set_pin_data_driven(bool state); /* 0=tristate for input, 1=driven for output */ + +#endif