diff --git a/firmware/common/timefuncs.c b/firmware/common/timefuncs.c index c8819ea76e..50addad27a 100644 --- a/firmware/common/timefuncs.c +++ b/firmware/common/timefuncs.c @@ -24,13 +24,21 @@ #include "kernel.h" #include "rtc.h" +#ifdef HAVE_RTC_IRQ +#include "rtc-target.h" +#endif #include "timefuncs.h" #include "debug.h" static struct tm tm; #if !CONFIG_RTC -static void fill_default_tm(struct tm *tm) +static inline bool rtc_dirty(void) +{ + return true; +} + +static inline int rtc_read_datetime(struct tm *tm) { tm->tm_sec = 0; tm->tm_min = 0; @@ -38,9 +46,9 @@ static void fill_default_tm(struct tm *tm) tm->tm_mday = 1; tm->tm_mon = 0; tm->tm_year = 70; - tm->tm_wday = 1; - tm->tm_yday = 0; /* Not implemented for now */ - tm->tm_isdst = -1; /* Not implemented for now */ + tm->tm_wday = 4; + tm->tm_yday = 0; + return 1; } #endif /* !CONFIG_RTC */ @@ -58,24 +66,37 @@ bool valid_time(const struct tm *tm) else return true; } -#endif /* CONFIG_RTC */ -struct tm *get_time(void) +/* Don't read the RTC more than once per second + * returns true if the rtc needs to be read + * targets may override with their own implementation + */ +#ifndef HAVE_RTC_IRQ +static inline bool rtc_dirty(void) { -#if CONFIG_RTC static long timeout = 0; /* Don't read the RTC more than once per second */ if (TIME_AFTER(current_tick, timeout)) { - /* Once per second, 1/10th of a second off */ - timeout = HZ * (current_tick / HZ + 1) + HZ / 5; + /* Once per second, 1/5th of a second off */ + timeout = current_tick / HZ * HZ + 6*HZ / 5; + return true; + } + + return false; +} +#endif /* HAVE_RTC_IRQ */ +#endif /* CONFIG_RTC */ + +struct tm *get_time(void) +{ + if (rtc_dirty()) + { rtc_read_datetime(&tm); tm.tm_isdst = -1; /* Not implemented for now */ } -#else /* No RTC */ - fill_default_tm(&tm); -#endif /* RTC */ + return &tm; } diff --git a/firmware/drivers/rtc/rtc_mc13783.c b/firmware/drivers/rtc/rtc_mc13783.c index a1f78f738d..aedf5f6fa5 100644 --- a/firmware/drivers/rtc/rtc_mc13783.c +++ b/firmware/drivers/rtc/rtc_mc13783.c @@ -69,6 +69,7 @@ static const unsigned char rtc_registers[RTC_NUM_REGS_RD] = /* was it an alarm that triggered power on ? */ static bool alarm_start = false; +static unsigned long rtc_is_dirty = 1; /* force a read right away */ static const unsigned short month_table[13] = { @@ -96,6 +97,16 @@ static bool read_time_and_day(uint32_t regs[RTC_NUM_REGS_RD]) return true; } +void MC13783_EVENT_CB_1HZ(void) +{ + rtc_is_dirty = 1; +} + +bool rtc_mc13783_dirty(void) +{ + return bitclr32(&rtc_is_dirty, 1); +} + /** Public APIs **/ void rtc_init(void) { @@ -105,6 +116,8 @@ void rtc_init(void) alarm_start = true; mc13783_write(MC13783_INTERRUPT_STATUS1, MC13783_TODAI); } + + mc13783_enable_event(MC13783_INT_ID_1HZ, true); } int rtc_read_datetime(struct tm *tm) diff --git a/firmware/export/config.h b/firmware/export/config.h index 475bd573d4..a4f0ea94fd 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -742,6 +742,16 @@ Lyre prototype 1 */ #endif /* CONFIG_RDS */ #endif /* HAVE_RDS_CAP */ +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if CONFIG_RTC == RTC_AS3514 +#if CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2 +#define HAVE_RTC_IRQ +#endif +#elif CONFIG_RTC == RTC_MC13783 +#define HAVE_RTC_IRQ +#endif +#endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) */ + #ifndef CONFIG_ORIENTATION #if LCD_HEIGHT > LCD_WIDTH #define CONFIG_ORIENTATION SCREEN_PORTRAIT diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c index 1bd07c57b1..a8ad9706f8 100644 --- a/firmware/target/arm/as3525/ascodec-as3525.c +++ b/firmware/target/arm/as3525/ascodec-as3525.c @@ -131,6 +131,16 @@ static unsigned long ascodec_enrd0_shadow = 0; static void ascodec_wait_cb(struct ascodec_request *req); +/* RTC interrupt and status + * Caution: To avoid an extra variable, IRQ_RTC is used as a flag for + * ascodec_enrd0_shadow, which conflicts with RVDD_WASLOW, but we're not using + * that right now */ +#if CONFIG_RTC +#define IFRTC_IRQ_RTC IRQ_RTC +#else /* !CONFIG_RTC */ +#define IFRTC_IRQ_RTC 0 +#endif /* CONFIG_RTC */ + /** --debugging help-- **/ #ifdef DEBUG @@ -149,7 +159,6 @@ static struct int_audio_counters { #define COUNT_INT(x) IFDEBUG((int_audio_counters.int_##x)++) - /** --stock request and callback functionality -- **/ /* init for common request data (call before submitting) */ @@ -510,13 +519,12 @@ static void ascodec_int_audio_cb(struct ascodec_request *req) } } +#if CONFIG_RTC if (data[2] & IRQ_RTC) { /* rtc irq */ - /* - * Can be configured for once per second or once per minute, - * default is once per second - */ + ascodec_enrd0_shadow |= IRQ_RTC; COUNT_INT(rtc); } +#endif /* CONFIG_RTC */ if (data[2] & IRQ_ADC) { /* adc finished */ COUNT_INT(adc); @@ -580,6 +588,14 @@ int ascodec_read_charger(void) } #endif /* CONFIG_CHARGING */ +#if CONFIG_RTC +/* read sticky rtc dirty status */ +bool ascodec_rtc_dirty(void) +{ + return bitclr32(&ascodec_enrd0_shadow, IRQ_RTC) & IRQ_RTC; +} +#endif /* CONFIG_RTC */ + /* * NOTE: * After the conversion to interrupts, ascodec_(lock|unlock) are only used by @@ -635,8 +651,9 @@ void ascodec_init(void) VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO; VIC_INT_ENABLE = INTERRUPT_AUDIO; - /* detect if USB was connected at startup since there is no transition */ - ascodec_enrd0_shadow = ascodec_read(AS3514_IRQ_ENRD0); + /* detect if USB was connected at startup since there is no transition; + force an initial read of the clock (if CONFIG_RTC) */ + ascodec_enrd0_shadow = ascodec_read(AS3514_IRQ_ENRD0) | IFRTC_IRQ_RTC; if(ascodec_enrd0_shadow & USB_STATUS) usb_insert_int(); @@ -651,10 +668,10 @@ void ascodec_init(void) /* XIRQ = IRQ, active low reset signal, 6mA push-pull output */ ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */ /* Generate irq on (rtc,) adc change */ - ascodec_write(AS3514_IRQ_ENRD2, /*IRQ_RTC |*/ IRQ_ADC); + ascodec_write(AS3514_IRQ_ENRD2, IFRTC_IRQ_RTC | IRQ_ADC); #else /* Generate irq for push-pull, active high, irq on rtc+adc change */ ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | - /*IRQ_RTC |*/ IRQ_ADC); + IFRTC_IRQ_RTC | IRQ_ADC); #endif } diff --git a/firmware/target/arm/as3525/rtc-target.h b/firmware/target/arm/as3525/rtc-target.h new file mode 100644 index 0000000000..900aa357d0 --- /dev/null +++ b/firmware/target/arm/as3525/rtc-target.h @@ -0,0 +1,27 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2017 by Michael Sevakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef RTC_TARGET_H +#define RTC_TARGET_H + +bool ascodec_rtc_dirty(void); +#define rtc_dirty ascodec_rtc_dirty + +#endif /* RTC_TARGET_H */ diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h index 179c65cad6..4bb148e36c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h @@ -46,6 +46,10 @@ static struct spi_node mc13783_spi = MC13783_EVENT_VECTOR_TBL_START() /* ADC conversion complete */ MC13783_EVENT_VECTOR(ADCDONE, 0) +#if CONFIG_RTC + /* RTC tick */ + MC13783_EVENT_VECTOR(1HZ, 0) +#endif /* CONFIG_RTC */ /* Power button */ MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S) /* Main charger detection */ diff --git a/firmware/target/arm/imx31/rtc-target.h b/firmware/target/arm/imx31/rtc-target.h new file mode 100644 index 0000000000..b6dc46204d --- /dev/null +++ b/firmware/target/arm/imx31/rtc-target.h @@ -0,0 +1,27 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2017 by Michael Sevakis + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef RTC_TARGET_H +#define RTC_TARGET_H + +bool rtc_mc13783_dirty(void); +#define rtc_dirty rtc_mc13783_dirty + +#endif /* RTC_TARGET_H */