diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2010-12-07 22:04:02 +0000 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2010-12-07 22:04:02 +0000 |
commit | 3b6b4f90509acaa068d78cce746ef83318d85903 (patch) | |
tree | 2a33c7003320f8071a9cb0d9d36ceffb7ac43cdd /firmware/drivers | |
parent | 1930e9f4baee8086195e147b9580ebbf3042b3cc (diff) |
RTC s35380a - proper alarm support
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28763 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/rtc/rtc_s35380a.c | 189 |
1 files changed, 116 insertions, 73 deletions
diff --git a/firmware/drivers/rtc/rtc_s35380a.c b/firmware/drivers/rtc/rtc_s35380a.c index 9f935b9541..05796e0462 100644 --- a/firmware/drivers/rtc/rtc_s35380a.c +++ b/firmware/drivers/rtc/rtc_s35380a.c @@ -66,6 +66,35 @@ #define STATUS_REG2_INT1ME 0x40 #define STATUS_REG2_INT1FE 0x80 +/* REALTIME_DATA register bytes */ +#define TIME_YEAR 0 +#define TIME_MONTH 1 +#define TIME_DAY 2 +#define TIME_WEEKDAY 3 +#define TIME_HOUR 4 +#define TIME_MINUTE 5 +#define TIME_SECOND 6 +#define TIME_REG_SIZE 7 + +/* INT1, INT2 register bytes */ +#define ALARM_WEEKDAY 0 +#define ALARM_HOUR 1 +#define ALARM_MINUTE 2 +#define ALARM_REG_SIZE 3 + +/* INT1, INT2 register bits */ +#define A1WE 0x80 +#define A1HE 0x80 +#define A1mE 0x80 + +#define A2WE 0x80 +#define A2HE 0x80 +#define A2mE 0x80 + +#define AMPM 0x40 + +static bool int_flag; + static void reverse_bits(unsigned char* v, int size) { static const unsigned char flipnibble[] = @@ -79,75 +108,88 @@ static void reverse_bits(unsigned char* v, int size) } } +static inline void rtc_reset(void) +{ + unsigned char reg = STATUS_REG1_RESET; + i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); +} + void rtc_init(void) { - unsigned char status_reg; - i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); + unsigned char reg; + static bool initialized = false; - if ( (status_reg & STATUS_REG1_POC) || - (status_reg & STATUS_REG1_BLD) ) - { - /* perform rtc reset*/ - status_reg |= STATUS_REG1_RESET; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); - } + if ( initialized ) + return; + + i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); + + /* cache INT1, INT2 flags as reading the register seem to clear + * this bits (which is not described in datasheet) + */ + int_flag = ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2)); + + /* test POC and BLD flags */ + if ( (reg & STATUS_REG1_POC) || (reg & STATUS_REG1_BLD)) + rtc_reset(); + + i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), ®, 1); + + /* test TEST flag */ + if ( reg & STATUS_REG2_TEST ) + rtc_reset(); /* setup 24h time format */ - status_reg = STATUS_REG1_H1224; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); + reg = STATUS_REG1_H1224; + i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); -#ifdef HAVE_RTC_ALARM - rtc_check_alarm_started(false); -#endif - /* disable all alarms */ - status_reg = 0; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &status_reg, 1); + initialized = true; } int rtc_read_datetime(struct tm *tm) { - unsigned char buf[7]; + unsigned char buf[TIME_REG_SIZE]; unsigned int i; int ret; - ret = i2c_read(I2C_IFACE_1, RTC_ADDR | (REALTIME_DATA1<<1), buf, sizeof(buf)); + ret = i2c_read(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf)); reverse_bits(buf, sizeof(buf)); - buf[4] &= 0x3f; /* mask out p.m. flag */ + buf[TIME_HOUR] &= 0x3f; /* mask out p.m. flag */ for (i = 0; i < sizeof(buf); i++) buf[i] = BCD2DEC(buf[i]); - tm->tm_sec = buf[6]; - tm->tm_min = buf[5]; - tm->tm_hour = buf[4]; - tm->tm_wday = buf[3]; - tm->tm_mday = buf[2]; - tm->tm_mon = buf[1] - 1; - tm->tm_year = buf[0] + 100; + tm->tm_sec = buf[TIME_SECOND]; + tm->tm_min = buf[TIME_MINUTE]; + tm->tm_hour = buf[TIME_HOUR]; + tm->tm_wday = buf[TIME_WEEKDAY]; + tm->tm_mday = buf[TIME_DAY]; + tm->tm_mon = buf[TIME_MONTH] - 1; + tm->tm_year = buf[TIME_YEAR] + 100; return ret; } int rtc_write_datetime(const struct tm *tm) { - unsigned char buf[7]; + unsigned char buf[TIME_REG_SIZE]; unsigned int i; int ret; - buf[6] = tm->tm_sec; - buf[5] = tm->tm_min; - buf[4] = tm->tm_hour; - buf[3] = tm->tm_wday; - buf[2] = tm->tm_mday; - buf[1] = tm->tm_mon + 1; - buf[0] = tm->tm_year - 100; + buf[TIME_SECOND] = tm->tm_sec; + buf[TIME_MINUTE] = tm->tm_min; + buf[TIME_HOUR] = tm->tm_hour; + buf[TIME_WEEKDAY] = tm->tm_wday; + buf[TIME_DAY] = tm->tm_mday; + buf[TIME_MONTH] = tm->tm_mon + 1; + buf[TIME_YEAR] = tm->tm_year - 100; for (i = 0; i < sizeof(buf); i++) buf[i] = DEC2BCD(buf[i]); reverse_bits(buf, sizeof(buf)); - ret = i2c_write(I2C_IFACE_1, RTC_ADDR | (REALTIME_DATA1<<1), buf, sizeof(buf)); + ret = i2c_write(I2C_IFACE_1, RTC_ADDR|(REALTIME_DATA1<<1), buf, sizeof(buf)); return ret; } @@ -155,75 +197,76 @@ int rtc_write_datetime(const struct tm *tm) #ifdef HAVE_RTC_ALARM void rtc_set_alarm(int h, int m) { - /* 1) get the date - * 2) compare h:m with current time - if alarm time < current time set day += 1 - 3) check day if it is not needed to wrap around - 4) set the validity bits - 5) write to alarm register - */ + unsigned char buf[ALARM_REG_SIZE]; - unsigned char buf[3]; - unsigned char reg; + /* INT1 register can be accessed only when IN1AE flag is set */ + rtc_enable_alarm(true); - /* 0x80 - validity flag */ - buf[2] = DEC2BCD(m) | 0x80; - buf[1] = DEC2BCD(h) | 0x80; - buf[0] = 0; + /* A1mE, A1HE - validity flags */ + buf[ALARM_MINUTE] = DEC2BCD(m) | A1mE; + buf[ALARM_HOUR] = DEC2BCD(h) | A1HE; + buf[ALARM_WEEKDAY] = 0; - reverse_bits(buf, sizeof(buf)); + /* AM/PM flag have to be set properly regardles of + * time format used (H1224 flag in STATUS_REG1) + * this is not described in datasheet for s35380a + * but is somehow described in datasheet for s35390a + */ + if ( h >= 12 ) + buf[ALARM_HOUR] |= AMPM; - reg = STATUS_REG2_INT1AE; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), ®, 1); - i2c_write(I2C_IFACE_1, RTC_ADDR | (INT1_REG<<1), buf, sizeof(buf)); + reverse_bits(buf, sizeof(buf)); + i2c_write(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf)); } void rtc_get_alarm(int *h, int *m) { - unsigned char buf[3]; - unsigned char reg,reg2; - - i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), ®, 1); + unsigned char buf[ALARM_REG_SIZE]; - reg2 = reg | STATUS_REG2_INT1AE; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), ®2, 1); - i2c_read(I2C_IFACE_1, RTC_ADDR | (INT1_REG<<1), buf, sizeof(buf)); - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), ®, 1); + /* INT1 alarm register can be accessed only when INT1AE is set */ + rtc_enable_alarm(true); + /* read the content of INT1 register */ + i2c_read(I2C_IFACE_1, RTC_ADDR|(INT1_REG<<1), buf, sizeof(buf)); reverse_bits(buf, sizeof(buf)); - *h = BCD2DEC(buf[1] & 0x3f); /* mask out A1HE and PM/AM flag */ - *m = BCD2DEC(buf[2] & 0x7f); /* mask out A1mE */ + *h = BCD2DEC(buf[ALARM_HOUR] & 0x3f); /* mask out A1HE and PM/AM flag */ + *m = BCD2DEC(buf[ALARM_MINUTE] & 0x7f); /* mask out A1mE */ + + rtc_enable_alarm(false); } bool rtc_check_alarm_flag(void) { - unsigned char status_reg; - i2c_read(I2C_IFACE_1, RTC_ADDR | (STATUS_REG1<<1), &status_reg, 1); + unsigned char reg; + i2c_read(I2C_IFACE_1, RTC_ADDR|(STATUS_REG1<<1), ®, 1); - return (status_reg & (STATUS_REG1_INT1 | STATUS_REG1_INT2)); + return ((reg & STATUS_REG1_INT1) || (reg & STATUS_REG1_INT2)); } void rtc_enable_alarm(bool enable) { - unsigned char status_reg2; - status_reg2 = enable ? STATUS_REG2_INT1AE:0; - i2c_write(I2C_IFACE_1, RTC_ADDR | (STATUS_REG2<<1), &status_reg2, 1); + unsigned char reg = 0; + + if (enable) + reg = STATUS_REG2_INT1AE; + + i2c_write(I2C_IFACE_1, RTC_ADDR|(STATUS_REG2<<1), ®, 1); } bool rtc_check_alarm_started(bool release_alarm) { - static bool run_before = false, alarm_state; + static bool run_before; bool rc; if (run_before) { - rc = alarm_state; - alarm_state &= ~release_alarm; + rc = int_flag; + int_flag &= ~release_alarm; } else { - rc = rtc_check_alarm_flag(); + rc = int_flag; run_before = true; } |