Convert i.MX31 and AMS target to use RTC interrupt

Instead of checking ticks, set a sticky dirty flag that indicates
that the RTC needs to be read. This gives a timely update and more
accurate readout without actually reading the RTC until it changes.
The implementation should atomically read the flag and clear it.
Setting the flag would typically happen in an RTC tick ISR.

Change-Id: I6fd325f22845029a485c502c884812d3676026ea
This commit is contained in:
Michael Sevakis 2017-01-26 21:08:55 -05:00
parent 12bc24adbf
commit f4c4221306
7 changed files with 140 additions and 21 deletions

View file

@ -24,13 +24,21 @@
#include "kernel.h" #include "kernel.h"
#include "rtc.h" #include "rtc.h"
#ifdef HAVE_RTC_IRQ
#include "rtc-target.h"
#endif
#include "timefuncs.h" #include "timefuncs.h"
#include "debug.h" #include "debug.h"
static struct tm tm; static struct tm tm;
#if !CONFIG_RTC #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_sec = 0;
tm->tm_min = 0; tm->tm_min = 0;
@ -38,9 +46,9 @@ static void fill_default_tm(struct tm *tm)
tm->tm_mday = 1; tm->tm_mday = 1;
tm->tm_mon = 0; tm->tm_mon = 0;
tm->tm_year = 70; tm->tm_year = 70;
tm->tm_wday = 1; tm->tm_wday = 4;
tm->tm_yday = 0; /* Not implemented for now */ tm->tm_yday = 0;
tm->tm_isdst = -1; /* Not implemented for now */ return 1;
} }
#endif /* !CONFIG_RTC */ #endif /* !CONFIG_RTC */
@ -58,24 +66,37 @@ bool valid_time(const struct tm *tm)
else else
return true; 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; static long timeout = 0;
/* Don't read the RTC more than once per second */ /* Don't read the RTC more than once per second */
if (TIME_AFTER(current_tick, timeout)) if (TIME_AFTER(current_tick, timeout))
{ {
/* Once per second, 1/10th of a second off */ /* Once per second, 1/5th of a second off */
timeout = HZ * (current_tick / HZ + 1) + HZ / 5; 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); rtc_read_datetime(&tm);
tm.tm_isdst = -1; /* Not implemented for now */ tm.tm_isdst = -1; /* Not implemented for now */
} }
#else /* No RTC */
fill_default_tm(&tm);
#endif /* RTC */
return &tm; return &tm;
} }

View file

@ -69,6 +69,7 @@ static const unsigned char rtc_registers[RTC_NUM_REGS_RD] =
/* was it an alarm that triggered power on ? */ /* was it an alarm that triggered power on ? */
static bool alarm_start = false; static bool alarm_start = false;
static unsigned long rtc_is_dirty = 1; /* force a read right away */
static const unsigned short month_table[13] = 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; 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 **/ /** Public APIs **/
void rtc_init(void) void rtc_init(void)
{ {
@ -105,6 +116,8 @@ void rtc_init(void)
alarm_start = true; alarm_start = true;
mc13783_write(MC13783_INTERRUPT_STATUS1, MC13783_TODAI); mc13783_write(MC13783_INTERRUPT_STATUS1, MC13783_TODAI);
} }
mc13783_enable_event(MC13783_INT_ID_1HZ, true);
} }
int rtc_read_datetime(struct tm *tm) int rtc_read_datetime(struct tm *tm)

View file

@ -742,6 +742,16 @@ Lyre prototype 1 */
#endif /* CONFIG_RDS */ #endif /* CONFIG_RDS */
#endif /* HAVE_RDS_CAP */ #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 #ifndef CONFIG_ORIENTATION
#if LCD_HEIGHT > LCD_WIDTH #if LCD_HEIGHT > LCD_WIDTH
#define CONFIG_ORIENTATION SCREEN_PORTRAIT #define CONFIG_ORIENTATION SCREEN_PORTRAIT

View file

@ -131,6 +131,16 @@ static unsigned long ascodec_enrd0_shadow = 0;
static void ascodec_wait_cb(struct ascodec_request *req); 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-- **/ /** --debugging help-- **/
#ifdef DEBUG #ifdef DEBUG
@ -149,7 +159,6 @@ static struct int_audio_counters {
#define COUNT_INT(x) IFDEBUG((int_audio_counters.int_##x)++) #define COUNT_INT(x) IFDEBUG((int_audio_counters.int_##x)++)
/** --stock request and callback functionality -- **/ /** --stock request and callback functionality -- **/
/* init for common request data (call before submitting) */ /* 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 */ if (data[2] & IRQ_RTC) { /* rtc irq */
/* ascodec_enrd0_shadow |= IRQ_RTC;
* Can be configured for once per second or once per minute,
* default is once per second
*/
COUNT_INT(rtc); COUNT_INT(rtc);
} }
#endif /* CONFIG_RTC */
if (data[2] & IRQ_ADC) { /* adc finished */ if (data[2] & IRQ_ADC) { /* adc finished */
COUNT_INT(adc); COUNT_INT(adc);
@ -580,6 +588,14 @@ int ascodec_read_charger(void)
} }
#endif /* CONFIG_CHARGING */ #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: * NOTE:
* After the conversion to interrupts, ascodec_(lock|unlock) are only used by * 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_I2C_AUDIO;
VIC_INT_ENABLE = INTERRUPT_AUDIO; VIC_INT_ENABLE = INTERRUPT_AUDIO;
/* detect if USB was connected at startup since there is no transition */ /* detect if USB was connected at startup since there is no transition;
ascodec_enrd0_shadow = ascodec_read(AS3514_IRQ_ENRD0); 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) if(ascodec_enrd0_shadow & USB_STATUS)
usb_insert_int(); usb_insert_int();
@ -651,10 +668,10 @@ void ascodec_init(void)
/* XIRQ = IRQ, active low reset signal, 6mA push-pull output */ /* XIRQ = IRQ, active low reset signal, 6mA push-pull output */
ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */ ascodec_write_pmu(0x1a, 3, (1<<2)|3); /* 1A-3 = Out_Cntr3 register */
/* Generate irq on (rtc,) adc change */ /* 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 #else
/* Generate irq for push-pull, active high, irq on rtc+adc change */ /* Generate irq for push-pull, active high, irq on rtc+adc change */
ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
/*IRQ_RTC |*/ IRQ_ADC); IFRTC_IRQ_RTC | IRQ_ADC);
#endif #endif
} }

View file

@ -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 */

View file

@ -46,6 +46,10 @@ static struct spi_node mc13783_spi =
MC13783_EVENT_VECTOR_TBL_START() MC13783_EVENT_VECTOR_TBL_START()
/* ADC conversion complete */ /* ADC conversion complete */
MC13783_EVENT_VECTOR(ADCDONE, 0) MC13783_EVENT_VECTOR(ADCDONE, 0)
#if CONFIG_RTC
/* RTC tick */
MC13783_EVENT_VECTOR(1HZ, 0)
#endif /* CONFIG_RTC */
/* Power button */ /* Power button */
MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S) MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S)
/* Main charger detection */ /* Main charger detection */

View file

@ -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 */