| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 | 
							- /*
 
-  * Read/write DS3231M RTC to/from the sysclock.
 
-  *
 
-  * This currently doesn't try to maintain any kind of subsecond
 
-  * accuracy.
 
-  */
 
- #include <string.h>
 
- #include "fw.h"
 
- #include "console.h"
 
- #include "io.h"
 
- #include "systime.h"
 
- static inline uint32_t i2c_wait(void)
 
- {
 
-     waitfor(I2C_IRQ);
 
- }
 
- static void i2c_send(uint8_t byte, uint8_t ctl)
 
- {
 
-     i2c_wait();
 
-     I2C_WDATA = (byte << 8) | I2C_NAK | ctl;
 
- }
 
- static bool i2c_acked(void)
 
- {
 
-     i2c_wait();
 
-     return !(I2C_RDATA & I2C_NAK);
 
- }
 
- static uint8_t i2c_recv(uint8_t ctl)
 
- {
 
-     uint32_t rdata;
 
-     i2c_wait();
 
-     I2C_WDATA = (~0xff) | ctl;
 
-     i2c_wait();
 
-     return I2C_RDATA_DATA;
 
- }
 
- #define RTC_REGS 19		/* Total RTC registers */
 
- #define RTC_TIME_REGS 7		/* RTC registers with time info */
 
- #define RTC_ADDR 0x68
 
- #define RTC_WCMD ((RTC_ADDR << 1)+0)
 
- #define RTC_RCMD ((RTC_ADDR << 1)+1)
 
- static unsigned int unbcd(uint8_t v)
 
- {
 
-     return (v & 0x0f) + (v >> 4) * 10;
 
- }
 
- static uint8_t tobcd(unsigned int v)
 
- {
 
-     uint8_t q;
 
-     v %= 100;
 
-     return ((v/10) << 4) + (v%10);
 
- }
 
- static int i2c_start_rtc(void)
 
- {
 
-     int sda_retry_count = 16;
 
-     i2c_set_speed(400);
 
-     /* SDA held low? */
 
-     while (!(I2C_RDATA & I2C_SDA)) {
 
- 	i2c_send(0xff, I2C_DUMMY);
 
- 	if (!sda_retry_count--) {
 
- 	    con_printf("RTC: I2C SDA stuck low\n");
 
- 	    return -1;
 
- 	}
 
-     }
 
-     i2c_send(RTC_WCMD, 0);
 
-     if (!i2c_acked()) {
 
- 	con_printf("No RTC detected at I2C address 0x%02x\n", RTC_ADDR);
 
- 	i2c_send(0xff, I2C_P);
 
- 	return -1;
 
-     }
 
-     return 0;
 
- }
 
- void read_rtc(void)
 
- {
 
-     uint8_t rtc_regs[RTC_TIME_REGS];
 
-     int i;
 
-     struct tms tms;
 
-     if (i2c_start_rtc())
 
- 	return;
 
-     i2c_send(0, I2C_SR);	/* Starting register */
 
-     i2c_send(RTC_RCMD, 0);
 
-     for (i = 0; i < RTC_TIME_REGS-1; i++)
 
- 	rtc_regs[i] = i2c_recv(0);
 
-     rtc_regs[i] = i2c_recv(I2C_NAK | I2C_P);
 
-     /* Convert to struct tms and set systime */
 
-     memset(&tms, 0, sizeof tms);
 
-     unsigned int sec = unbcd(rtc_regs[0]);
 
-     tms.tm_2sec = sec >> 1;
 
-     tms.hold.tm_1sec = sec & 1;
 
-     tms.hold.tm_tick = 0x4000;	/* Without more info, assume mid-second */
 
-     tms.tm_min = unbcd(rtc_regs[1]);
 
-     unsigned int hour;
 
-     if (rtc_regs[2] & 0x40) {
 
- 	/* AM/PM mode - this shouldn't happen */
 
- 	hour = unbcd(rtc_regs[2] & 0x1f);
 
- 	if (hour > 11)
 
- 	    hour -= 12;
 
- 	if (rtc_regs[2] & 0x20)
 
- 	    hour += 12;
 
-     } else {
 
- 	/* 24-hour mode */
 
- 	hour = unbcd(rtc_regs[2]);
 
-     }
 
-     tms.tm_hour = hour;
 
-     tms.tm_mday = unbcd(rtc_regs[4]);
 
-     tms.tm_mon  = unbcd(rtc_regs[5] & 0x1f);
 
-     tms.tm_year = unbcd(rtc_regs[6]) + (rtc_regs[5] & 0x80 ? 100 : 0) + 20;
 
-     set_systime(tms);
 
- #ifdef TEST
 
-     con_printf("RTC register content:\n");
 
-     for (i = 0; i < RTC_REGS; i++)
 
- 	con_printf(" %02x", rtc_regs[i]);
 
- #endif
 
-     con_printf("RTC time: %04u-%02u-%02u %02u:%02u:%02u\n",
 
- 	       tms.tm_year + 1980, tms.tm_mon, tms.tm_mday,
 
- 	       tms.tm_hour, tms.tm_min, tms_sec(tms));
 
- }
 
- bool do_write_rtc;
 
- void write_rtc(void)
 
- {
 
-     uint8_t rtc_regs[RTC_TIME_REGS];
 
-     int i;
 
-     struct tms tms;
 
-     int sda_retry_count = 16;
 
-     do_write_rtc = false;
 
-     tms = get_systime();
 
-     rtc_regs[0] = tobcd(tms_sec(tms));
 
-     rtc_regs[1] = tobcd(tms.tm_min);
 
-     rtc_regs[2] = tobcd(tms.tm_hour);
 
-     rtc_regs[3] = 0;		/* Day of week, unused */
 
-     rtc_regs[4] = tobcd(tms.tm_mday);
 
-     rtc_regs[5] = tobcd(tms.tm_mon);
 
-     rtc_regs[6] = tobcd(tms.tm_year - 20);
 
-     if (i2c_start_rtc())
 
- 	return;
 
-     i2c_send(0, 0);		/* Starting register */
 
-     for (i = 0; i < RTC_TIME_REGS-1; i++)
 
- 	i2c_send(rtc_regs[i], 0);
 
-     i2c_send(rtc_regs[i], I2C_P);
 
- }
 
 
  |