From 2ece27f4350ae31fcf413f9fed8491832007b896 Mon Sep 17 00:00:00 2001 From: Neil Hancock Date: Tue, 17 Jan 2017 15:34:44 -0600 Subject: [PATCH] Kinetis: Add support for K64/K66 RTC lower half driver --- arch/arm/src/kinetis/Make.defs | 5 +- arch/arm/src/kinetis/chip/kinetis_rtc.h | 264 ++++++---- arch/arm/src/kinetis/kinetis_alarm.h | 55 +- arch/arm/src/kinetis/kinetis_rtc.c | 264 +++++++++- arch/arm/src/kinetis/kinetis_rtc_if.h | 150 ++++++ arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c | 525 +++++++++++++++++++ configs/freedom-k64f/src/freedom-k64f.h | 5 + configs/freedom-k64f/src/k64_bringup.c | 36 +- 8 files changed, 1177 insertions(+), 127 deletions(-) create mode 100644 arch/arm/src/kinetis/kinetis_rtc_if.h create mode 100644 arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c diff --git a/arch/arm/src/kinetis/Make.defs b/arch/arm/src/kinetis/Make.defs index e4dd09df79..a3a9d17343 100644 --- a/arch/arm/src/kinetis/Make.defs +++ b/arch/arm/src/kinetis/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # arch/arm/src/kinetis/Make.defs # -# Copyright (C) 2011, 2013-2016 Gregory Nutt. All rights reserved. +# Copyright (C) 2011, 2013-2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -174,6 +174,9 @@ endif ifeq ($(CONFIG_RTC),y) CHIP_CSRCS += kinetis_rtc.c +ifeq ($(CONFIG_RTC_DRIVER),y) +CHIP_CSRCS += kinetis_rtc_lowerhalf.c +endif endif ifeq ($(CONFIG_NET),y) diff --git a/arch/arm/src/kinetis/chip/kinetis_rtc.h b/arch/arm/src/kinetis/chip/kinetis_rtc.h index 948c6ce877..4ad016af6c 100644 --- a/arch/arm/src/kinetis/chip/kinetis_rtc.h +++ b/arch/arm/src/kinetis/chip/kinetis_rtc.h @@ -1,7 +1,7 @@ /************************************************************************************ * arch/arm/src/kinetis/chip/kinetis_rtc.h * - * Copyright (C) 2011, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -52,39 +52,80 @@ /* Register Offsets *****************************************************************/ -#define KINETIS_RTC_TSR_OFFSET 0x0000 /* RTC Time Seconds Register */ -#define KINETIS_RTC_TPR_OFFSET 0x0004 /* RTC Time Prescaler Register */ -#define KINETIS_RTC_TAR_OFFSET 0x0008 /* RTC Time Alarm Register */ -#define KINETIS_RTC_TCR_OFFSET 0x000c /* RTC Time Compensation Register */ -#define KINETIS_RTC_CR_OFFSET 0x0010 /* RTC Control Register */ -#define KINETIS_RTC_SR_OFFSET 0x0014 /* RTC Status Register */ -#define KINETIS_RTC_LR_OFFSET 0x0018 /* RTC Lock Register */ -#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) -# define KINETIS_RTC_IER_OFFSET 0x001c /* RTC Interrupt Enable Register (K40) */ +/* NXP/Freescale has familes and technology generations (sometimes seen as processor + * speed). These are organized into feature families, and faster speeds sometimes + * have extended features. Families are K02 K10 K20 K22 K24 K30 K40 K50 K60 K64 K65 + * K66 K70 K80 + * + * So far only two variations/generations on the RTC have been discovered. + * GEN1 RTC_TSR TPR TAR TCR CR SR LR IER WAR RAR + * GEN2 RTC_TSR TPR TAR TCR CR SR LR IER TTSR MER MCLR MCHR WAR RAR + * + * KINETIS RTC_GEN1 K20P32-->K20P81M K22 K40 K50 K60@100Mhz K64 120MHz + * Assumed K10 K11 + * + * KINETIS_RTC_GEN2 K02 K20P144M K26P169 K60@120Mhz K65x K66x + * + * Note current naming doesn't allow GEN1:MK60FN...Q10 & GEN2:MK60FN...Q12 + */ + +#if defined(KINETIS_K26) || defined(KINETIS_K65) || defined(KINETIS_K66) +# define KINETIS_RTC_GEN2 #endif + +#define KINETIS_RTC_TSR_OFFSET 0x0000 /* RTC Time Seconds Register */ +#define KINETIS_RTC_TPR_OFFSET 0x0004 /* RTC Time Prescaler Register */ +#define KINETIS_RTC_TAR_OFFSET 0x0008 /* RTC Time Alarm Register */ +#define KINETIS_RTC_TCR_OFFSET 0x000c /* RTC Time Compensation Register */ +#define KINETIS_RTC_CR_OFFSET 0x0010 /* RTC Control Register */ +#define KINETIS_RTC_SR_OFFSET 0x0014 /* RTC Status Register */ +#define KINETIS_RTC_LR_OFFSET 0x0018 /* RTC Lock Register */ +#define KINETIS_RTC_IER_OFFSET 0x001c /* RTC Interrupt Enable Register (K40) */ + #ifdef KINETIS_K60 -# define KINETIS_RTC_CCR_OFFSET 0x001c /* RTC Chip Configuration Register (K60) */ + /* Haven't found a processor or nuttx file where KINETIS_RTC_CCR is in it + * from K60P100M100SF2V2RM this would be called KINETIS_RTC_IER_OFFSET. + */ + +# define KINETIS_RTC_CCR_OFFSET 0x001c /* RTC Chip Configuration Register (K60) */ #endif -#define KINETIS_RTC_WAR_OFFSET 0x0800 /* RTC Write Access Register */ -#define KINETIS_RTC_RAR_OFFSET 0x0804 /* RTC Read Access Register */ + +#ifdef KINETIS_RTC_GEN2 +# define KINETIS_RTC_TTSR_OFFSET 0x0020 /* RTC Tamper Times Seconds Register */ +# define KINETIS_RTC_MR_OFFSET 0x0024 /* RTC Monotonic Enable Register */ +# define KINETIS_RTC_MCLR_OFFSET 0x0028 /* RTC Monotonic Counter Low Register */ +# define KINETIS_RTC_MCHR_OFFSET 0x002c /* RTC Monotonic Counter High Register */ +#endif + +#define KINETIS_RTC_WAR_OFFSET 0x0800 /* RTC Write Access Register */ +#define KINETIS_RTC_RAR_OFFSET 0x0804 /* RTC Read Access Register */ /* Register Addresses ***************************************************************/ -#define KINETIS_RTC_TSR (KINETIS_RTC_BASE+KINETIS_RTC_TSR_OFFSET) -#define KINETIS_RTC_TPR (KINETIS_RTC_BASE+KINETIS_RTC_TPR_OFFSET) -#define KINETIS_RTC_TAR (KINETIS_RTC_BASE+KINETIS_RTC_TAR_OFFSET) -#define KINETIS_RTC_TCR (KINETIS_RTC_BASE+KINETIS_RTC_TCR_OFFSET) -#define KINETIS_RTC_CR (KINETIS_RTC_BASE+KINETIS_RTC_CR_OFFSET) -#define KINETIS_RTC_SR (KINETIS_RTC_BASE+KINETIS_RTC_SR_OFFSET) -#define KINETIS_RTC_LR (KINETIS_RTC_BASE+KINETIS_RTC_LR_OFFSET) -#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) -# define KINETIS_RTC_IER (KINETIS_RTC_BASE+KINETIS_RTC_IER_OFFSET) -#endif +#define KINETIS_RTC_TSR (KINETIS_RTC_BASE+KINETIS_RTC_TSR_OFFSET) +#define KINETIS_RTC_TPR (KINETIS_RTC_BASE+KINETIS_RTC_TPR_OFFSET) +#define KINETIS_RTC_TAR (KINETIS_RTC_BASE+KINETIS_RTC_TAR_OFFSET) +#define KINETIS_RTC_TCR (KINETIS_RTC_BASE+KINETIS_RTC_TCR_OFFSET) +#define KINETIS_RTC_CR (KINETIS_RTC_BASE+KINETIS_RTC_CR_OFFSET) +#define KINETIS_RTC_SR (KINETIS_RTC_BASE+KINETIS_RTC_SR_OFFSET) +#define KINETIS_RTC_LR (KINETIS_RTC_BASE+KINETIS_RTC_LR_OFFSET) +#define KINETIS_RTC_IER (KINETIS_RTC_BASE+KINETIS_RTC_IER_OFFSET) + #ifdef KINETIS_K60 -# define KINETIS_CCR_IER (KINETIS_RTC_BASE+KINETIS_RTC_CCR_OFFSET) +/* From K60P100M100SF2V2RM this would be called KINETIS_RTC_IER */ + +# define KINETIS_CCR_IER (KINETIS_RTC_BASE+KINETIS_RTC_CCR_OFFSET) #endif -#define KINETIS_RTC_WAR (KINETIS_RTC_BASE+KINETIS_RTC_WAR_OFFSET) -#define KINETIS_RTC_RAR (KINETIS_RTC_BASE+KINETIS_RTC_RAR_OFFSET) + +#ifdef KINETIS_RTC_GEN2 +# define KINETIS_RTC_TTSR (KINETIS_RTC_BASE+KINETIS_RTC_TTSR_OFFSET) +# define KINETIS_RTC_MER (KINETIS_RTC_BASE+KINETIS_RTC_MER_OFFSET) +# define KINETIS_RTC_MCLR (KINETIS_RTC_BASE+KINETIS_RTC_MCLR_OFFSET) +# define KINETIS_RTC_MCHR (KINETIS_RTC_BASE+KINETIS_RTC_MCHR_OFFSET) +#endif + +#define KINETIS_RTC_WAR (KINETIS_RTC_BASE+KINETIS_RTC_WAR_OFFSET) +#define KINETIS_RTC_RAR (KINETIS_RTC_BASE+KINETIS_RTC_RAR_OFFSET) /* Register Bit Definitions *********************************************************/ @@ -92,104 +133,133 @@ /* RTC Time Prescaler Register */ -#define RTC_TPR_SHIFT (0) /* Bits 0-15: Time Prescaler Register */ -#define RTC_TPR_MASK (0xffff << RTC_TPR_SHIFT) +#define RTC_TPR_SHIFT (0) /* Bits 0-15: Time Prescaler Register */ +#define RTC_TPR_MASK (0xffff << RTC_TPR_SHIFT) /* Bits 16-31: Reserved */ /* RTC Time Alarm Register (32-bits of time alarm) */ /* RTC Time Compensation Register (32-bits) */ -#define RTC_TCR_TCR_SHIFT (0) /* Bits 0-7: Time Compensation Register */ -#define RTC_TCR_TCR_MASK (0xff << RTC_TCR_CIR_MASK) -#define RTC_TCR_CIR_SHIFT (8) /* Bits 8-15: Compensation Interval Register */ -#define RTC_TCR_CIR_MASK (0xff << RTC_TCR_CIR_SHIFT) -#define RTC_TCR_TCV_SHIFT (16) /* Bits 16-23: Time Compensation Value */ -#define RTC_TCR_TCV_MASK (0xff << RTC_TCR_TCV_SHIFT) -#define RTC_TCR_CIC_SHIFT (24) /* Bits 24-31: Compensation Interval Counter */ -#define RTC_TCR_CIC_MASK (0xff << RTC_TCR_CIC_SHIFT) +#define RTC_TCR_TCR_SHIFT (0) /* Bits 0-7: Time Compensation Register */ +#define RTC_TCR_TCR_MASK (0xff << RTC_TCR_CIR_MASK) +#define RTC_TCR_CIR_SHIFT (8) /* Bits 8-15: Compensation Interval Register */ +#define RTC_TCR_CIR_MASK (0xff << RTC_TCR_CIR_SHIFT) +#define RTC_TCR_TCV_SHIFT (16) /* Bits 16-23: Time Compensation Value */ +#define RTC_TCR_TCV_MASK (0xff << RTC_TCR_TCV_SHIFT) +#define RTC_TCR_CIC_SHIFT (24) /* Bits 24-31: Compensation Interval Counter */ +#define RTC_TCR_CIC_MASK (0xff << RTC_TCR_CIC_SHIFT) /* RTC Control Register (32-bits) */ -#define RTC_CR_SWR (1 << 0) /* Bit 0: Software Reset */ -#define RTC_CR_WPE (1 << 1) /* Bit 1: Wakeup Pin Enable */ -#define RTC_CR_SUP (1 << 2) /* Bit 2: Supervisor Access */ -#define RTC_CR_UM (1 << 3) /* Bit 3: Update Mode */ - /* Bits 4-7: Reserved */ -#define RTC_CR_OSCE (1 << 8) /* Bit 8: Oscillator Enable */ -#define RTC_CR_CLKO (1 << 9) /* Bit 9: Clock Output */ -#define RTC_CR_SC16P (1 << 10) /* Bit 10: Oscillator 16pF load configure */ -#define RTC_CR_SC8P (1 << 11) /* Bit 11: Oscillator 8pF load configure */ -#define RTC_CR_SC4P (1 << 12) /* Bit 12: Oscillator 4pF load configure */ -#define RTC_CR_SC2P (1 << 13) /* Bit 13: Oscillator 2pF load configure */ - /* Bits 14-31: Reserved */ +#define RTC_CR_SWR (1 << 0) /* Bit 0: Software Reset */ +#define RTC_CR_WPE (1 << 1) /* Bit 1: Wakeup Pin Enable */ +#define RTC_CR_SUP (1 << 2) /* Bit 2: Supervisor Access */ +#define RTC_CR_UM (1 << 3) /* Bit 3: Update Mode */ + /* Bits 4-7: Reserved */ +#define RTC_CR_OSCE (1 << 8) /* Bit 8: Oscillator Enable */ +#define RTC_CR_CLKO (1 << 9) /* Bit 9: Clock Output */ +#define RTC_CR_SC16P (1 << 10) /* Bit 10: Oscillator 16pF load configure */ +#define RTC_CR_SC8P (1 << 11) /* Bit 11: Oscillator 8pF load configure */ +#define RTC_CR_SC4P (1 << 12) /* Bit 12: Oscillator 4pF load configure */ +#define RTC_CR_SC2P (1 << 13) /* Bit 13: Oscillator 2pF load configure */ + /* Bits 14-31: Reserved */ /* RTC Status Register (32-bits) */ -#define RTC_SR_TIF (1 << 0) /* Bit 0: Time Invalid Flag */ -#define RTC_SR_TOF (1 << 1) /* Bit 1: Time Overflow Flag */ - /* Bit 3: Reserved */ -#define RTC_SR_TAF (1 << 2) /* Bit 2: Time Alarm Flag */ -#define RTC_SR_TCE (1 << 4) /* Bit 4: Time Counter Enable */ - /* Bits 5-31: Reserved */ -/* RTC Lock Register (32-bits) */ - /* Bits 0-2: Reserved */ -#define RTC_LR_TCL (1 << 3) /* Bit 3: Time Compensation Lock */ -#define RTC_LR_CRL (1 << 4) /* Bit 4: Control Register Lock */ -#define RTC_LR_SRL (1 << 5) /* Bit 5: Status Register Lock */ -#if defined(KINETIS_K20) || defined(KINETIS_K40) -# define RTC_LR_LRL (1 << 6) /* Bit 6: Lock Register Lock (K40) */ +#define RTC_SR_TIF (1 << 0) /* Bit 0: Time Invalid Flag */ +#define RTC_SR_TOF (1 << 1) /* Bit 1: Time Overflow Flag */ +#define RTC_SR_TAF (1 << 2) /* Bit 2: Time Alarm Flag */ + +#ifdef KINETIS_RTC_GEN2 +# define RTC_SR_MOF (1 << 3) /* Bit 3: Time Monotonic overflow Flag */ #endif - /* Bits 7-31: Reserved */ + /* Bit 3: Reserved RTC_GEN1 */ +#define RTC_SR_TCE (1 << 4) /* Bit 4: Time Counter Enable */ + /* Bits 5-31: Reserved */ +/* RTC Lock Register (32-bits) */ + /* Bits 0-2: Reserved */ +#define RTC_LR_TCL (1 << 3) /* Bit 3: Time Compensation Lock */ +#define RTC_LR_CRL (1 << 4) /* Bit 4: Control Register Lock */ +#define RTC_LR_SRL (1 << 5) /* Bit 5: Status Register Lock */ +#define RTC_LR_LRL (1 << 6) /* Bit 6: Lock Register Lock */ + /* Bit 7: Reserved */ +#ifdef KINETIS_RTC_GEN2 +# define RTC_LR_TTSL (1 << 8) /* Bit 8: Tamper Time Seconds Lock */ +# define RTC_LR_MEL (1 << 9) /* Bit 9: Monotonic Enable lock */ +# define RTC_LR_MCLL (1 << 10) /* Bit 10: Monotoic Counter Low Lock */ +# define RTC_LR_MCHL (1 << 11) /* Bit 10: Monotoic Counter High Lock */ +#endif + /* Bits 12-31: Reserved */ /* RTC Interrupt Enable Register (32-bits, K40) */ -#if defined(KINETIS_K20) || defined(KINETIS_K40) || defined(KINETIS_K64) -# define RTC_IER_TIIE (1 << 0) /* Bit 0: Time Invalid Interrupt Enable */ -# define RTC_IER_TOIE (1 << 1) /* Bit 1: Time Overflow Interrupt Enable */ -# define RTC_IER_TAIE (1 << 2) /* Bit 2: Time Alarm Interrupt Enable */ - /* Bit 3: Reserved */ -# define RTC_IER_TSIE (1 << 4) /* Bit 4: Time Seconds Interrupt Enable */ - /* Bits 5-31: Reserved */ +# define RTC_IER_TIIE (1 << 0) /* Bit 0: Time Invalid Interrupt Enable */ +# define RTC_IER_TOIE (1 << 1) /* Bit 1: Time Overflow Interrupt Enable */ +# define RTC_IER_TAIE (1 << 2) /* Bit 2: Time Alarm Interrupt Enable */ + +#ifdef KINETIS_RTC_GEN2 +# define RTC_IER_MOIE (1 << 3) /* Bit 3: Monotonic Overflow Interrupt Enable */ #endif -/* RTC Chip Configuration Register (32-bits,K60) */ +# define RTC_IER_TSIE (1 << 4) /* Bit 4: Time Seconds Interrupt Enable */ + /* Bits 5-6: Reserved */ +# define RTC_IER_WPON (1 << 7) /* Bit 7: Wakeup Pin On */ #ifdef KINETIS_K60 -# define RTC_CCR_CONFIG_SHIFT (0) /* Bits 0-7: Chip Configuration */ -# define RTC_CCR_CONFIG_MASK (0xff << RTC_CCR_CONFIG_SHIFT) - /* Bits 8-31: Reserved */ +/* RTC Chip Configuration Register (32-bits,K60) */ +/* Haven't found this in K60P100M100SF2V2RM */ + +# define RTC_CCR_CONFIG_SHIFT (0) /* Bits 0-7: Chip Configuration */ +# define RTC_CCR_CONFIG_MASK (0xff << RTC_CCR_CONFIG_SHIFT) + /* Bits 8-31: Reserved */ #endif /* RTC Write Access Register (32-bits) */ -#define RTC_WAR_TSRW (1 << 0) /* Bit 0: Time Seconds Register Write */ -#define RTC_WAR_TPRW (1 << 1) /* Bit 1: Time Prescaler Register Write */ -#define RTC_WAR_TARW (1 << 2) /* Bit 2: Time Alarm Register Write */ -#define RTC_WAR_TCRW (1 << 3) /* Bit 3: Time Compensation Register Write */ -#define RTC_WAR_CRW (1 << 4) /* Bit 4: Control Register Write */ -#define RTC_WAR_SRW (1 << 5) /* Bit 5: Status Register Write */ -#define RTC_WAR_LRW (1 << 6) /* Bit 6: Lock Register Write */ -#if defined(KINETIS_K40) || defined(KINETIS_K64) -# define RTC_WAR_IERW (1 << 7) /* Bit 7: Interrupt Enable Register Write */ -#endif +#define RTC_WAR_TSRW (1 << 0) /* Bit 0: Time Seconds Register Write */ +#define RTC_WAR_TPRW (1 << 1) /* Bit 1: Time Prescaler Register Write */ +#define RTC_WAR_TARW (1 << 2) /* Bit 2: Time Alarm Register Write */ +#define RTC_WAR_TCRW (1 << 3) /* Bit 3: Time Compensation Register Write */ +#define RTC_WAR_CRW (1 << 4) /* Bit 4: Control Register Write */ +#define RTC_WAR_SRW (1 << 5) /* Bit 5: Status Register Write */ +#define RTC_WAR_LRW (1 << 6) /* Bit 6: Lock Register Write */ +#define RTC_WAR_IERW (1 << 7) /* Bit 7: Interrupt Enable Register Write */ + #ifdef KINETIS_K60 -# define RTC_WAR_CCRW (1 << 7) /* Bit 7: Chip Config Register Write */ +/* This looks like old name, from K60P100M100SF2V2RM bit 7 would be called RTC_RAR_IERW */ + +# define RTC_WAR_CCRW (1 << 7) /* Bit 7: Chip Config Register Write */ #endif - /* Bits 8-31: Reserved */ + /* Bits 8-31: Reserved */ /* RTC Read Access Register */ -#define RTC_RAR_TSRR (1 << 0) /* Bit 0: Time Seconds Register Read */ -#define RTC_RAR_TPRR (1 << 1) /* Bit 1: Time Prescaler Register Read */ -#define RTC_RAR_TARR (1 << 2) /* Bit 2: Time Alarm Register Read */ -#define RTC_RAR_TCRR (1 << 3) /* Bit 3: Time Compensation Register Read */ -#define RTC_RAR_CRR (1 << 4) /* Bit 4: Control Register Read */ -#define RTC_RAR_SRR (1 << 5) /* Bit 5: Status Register Read */ -#define RTC_RAR_LRR (1 << 6) /* Bit 6: Lock Register Read */ -#if defined(KINETIS_K40) || defined(KINETIS_K64) -# define RTC_RAR_IERR (1 << 7) /* Bit 7: Interrupt Enable Register Read */ -#endif +#define RTC_RAR_TSRR (1 << 0) /* Bit 0: Time Seconds Register Read */ +#define RTC_RAR_TPRR (1 << 1) /* Bit 1: Time Prescaler Register Read */ +#define RTC_RAR_TARR (1 << 2) /* Bit 2: Time Alarm Register Read */ +#define RTC_RAR_TCRR (1 << 3) /* Bit 3: Time Compensation Register Read */ +#define RTC_RAR_CRR (1 << 4) /* Bit 4: Control Register Read */ +#define RTC_RAR_SRR (1 << 5) /* Bit 5: Status Register Read */ +#define RTC_RAR_LRR (1 << 6) /* Bit 6: Lock Register Read */ +#define RTC_RAR_IERR (1 << 7) /* Bit 7: Interrupt Enable Register Read */ + #ifdef KINETIS_K60 -# define RTC_RAR_CCRR (1 << 7) /* Bit 7: Chip Config Register Read */ +/* This is possibly an old name, from K60P100M100SF2V2RM bit 7 would be called + * RTC_RAR_IERR. + */ + +# define RTC_RAR_CCRR (1 << 7) /* Bit 7: Chip Config Register Read */ +#endif + +#ifdef KINETIS_RTC_GEN2 +# define RTC_RAR_TTSR (1 << 8) /* Bit 8: Tamper Time Seconds Read */ +# define RTC_RAR_MERR (1 << 9) /* Bit 9: Monotonic Enable Read */ +# define RTC_RAR_MCLR (1 << 10) /* Bit 10: Monotoic Counter Low Register Read */ +# define RTC_RAR_MCHR (1 << 11) /* Bit 10: Monotoic Counter High Register Read */ +#endif + /* Bits 11-31: Reserved */ + +#if defined(KINETIS_RTC_GEN2)/* && defined(CONFIG_RTC_MAGIC) */ +# define CONFIG_RTC_MAGICL 0xfacefee0 +# define CONFIG_RTC_MAGICH 0xef32a141 #endif - /* Bits 8-31: Reserved */ /************************************************************************************ * Public Types diff --git a/arch/arm/src/kinetis/kinetis_alarm.h b/arch/arm/src/kinetis/kinetis_alarm.h index 751cfd8cf0..3815e374c8 100644 --- a/arch/arm/src/kinetis/kinetis_alarm.h +++ b/arch/arm/src/kinetis/kinetis_alarm.h @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/kinetis/kinetis_alarm.h * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Author: Matias v01d * * Redistribution and use in source and binary forms, with or without @@ -56,6 +56,34 @@ typedef CODE void (*alarmcb_t)(void); +/* These features are in KinetisK 1st generation + * Time Alarm Interrupt + * Time Overflow Interrupt + * Time Seconds Interrupt + * + * For KinetisK 2nd Generation devices + * 64bit Monotonic register. + */ + +enum alm_id_e +{ + /* Used for indexing - must be sequential */ + + RTC_ALARMA = 0, /* RTC ALARM A */ + RTC_ALARMM, /* FUT: RTC Monotonic */ + RTC_ALARM_LAST +}; + +/* Structure used to pass parmaters to set an alarm */ + +struct alm_setalarm_s +{ + int as_id; /* enum alm_id_e */ + struct tm as_time; /* Alarm expiration time */ + alarmcb_t as_cb; /* Callback (if non-NULL) */ + FAR void *as_arg; /* Argument for callback */ +}; + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -84,7 +112,6 @@ extern "C" * ****************************************************************************/ -struct timespec; int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback); /**************************************************************************** @@ -103,6 +130,30 @@ int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback); int kinetis_rtc_cancelalarm(void); +/**************************************************************************** + * Name: kinetis_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the Kinetis. General usage: + * + * #include + * #include "kinetis_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = kinetis_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *kinetis_rtc_lowerhalf(void); + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm/src/kinetis/kinetis_rtc.c b/arch/arm/src/kinetis/kinetis_rtc.c index ca0f4848d1..19db2796b4 100644 --- a/arch/arm/src/kinetis/kinetis_rtc.c +++ b/arch/arm/src/kinetis/kinetis_rtc.c @@ -60,12 +60,23 @@ #if defined(CONFIG_RTC) +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(BOARD_RTC_CAP) +/* Capacitance values 8pF if not already defined */ + +# define BOARD_RTC_CAP RTC_CR_SC8P | RTC_CR_SC4P +#endif + /**************************************************************************** * Private Data ****************************************************************************/ #ifdef CONFIG_RTC_ALARM static alarmcb_t g_alarmcb; +static bool rtc_irq_state = false; #endif /**************************************************************************** @@ -78,6 +89,73 @@ volatile bool g_rtc_enabled = false; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: rtc_dumpregs + * + * Description: + * Disable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumpregs(FAR const char *msg) +{ + rtcinfo("%s:\n", msg); + rtcinfo(" TSR: %08x\n", getreg32(KINETIS_RTC_TSR)); + rtcinfo(" TPR: %08x\n", getreg32(KINETIS_RTC_TPR)); + rtcinfo(" TAR: %08x\n", getreg32(KINETIS_RTC_TAR)); + rtcinfo(" CR: %08x\n", getreg32(KINETIS_RTC_CR)); + rtcinfo(" SR: %08x\n", getreg32(KINETIS_RTC_SR)); + rtcinfo(" LR: %08x\n", getreg32(KINETIS_RTC_LR)); + rtcinfo(" IER: %08x\n", getreg32(KINETIS_RTC_IER)); +#if defined(KINETIS_RTC_GEN2) + rtcinfo(" TTSR: %08x\n", getreg32(KINETIS_RTC_TTSR)); + rtcinfo(" MER: %08x\n", getreg32(KINETIS_RTC_MER)); + rtcinfo(" MCLR: %08x\n", getreg32(KINETIS_RTC_MCLR)); + rtcinfo(" MCHR: %08x\n", getreg32(KINETIS_RTC_MCHR)); + rtcinfo(" WAR: %08x\n", getreg32(KINETIS_RTC_WAR)); + rtcinfo(" RAR: %08x\n", getreg32(KINETIS_RTC_RAR)); +#endif +} +#else +# define rtc_dumpregs(msg) +#endif + +/**************************************************************************** + * Name: rtc_dumptime + * + * Description: + * Disable RTC write protection + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC_INFO +static void rtc_dumptime(FAR struct tm *tp, FAR const char *msg) +{ + rtcinfo("%s:\n", msg); + rtcinfo(" tm_sec: %08x\n", tp->tm_sec); + rtcinfo(" tm_min: %08x\n", tp->tm_min); + rtcinfo(" tm_hour: %08x\n", tp->tm_hour); + rtcinfo(" tm_mday: %08x\n", tp->tm_mday); + rtcinfo(" tm_mon: %08x\n", tp->tm_mon); + rtcinfo(" tm_year: %08x\n", tp->tm_year); +} +#else +# define rtc_dumptime(tp, msg) +#endif + /**************************************************************************** * Name: kinetis_rtc_interrupt * @@ -96,27 +174,119 @@ volatile bool g_rtc_enabled = false; #if defined(CONFIG_RTC_ALARM) static int kinetis_rtc_interrupt(int irq, void *context) { - if (g_alarmcb != NULL) - { - /* Alarm callback */ + uint16_t rtc_sr; - g_alarmcb(); - g_alarmcb = NULL; + /* if alarm */ + rtc_sr = getreg32( KINETIS_RTC_SR); + if (rtc_sr & RTC_SR_TAF ) + { + if (g_alarmcb != NULL) + { + /* Alarm callback */ + + g_alarmcb(); + g_alarmcb = NULL; + } + } + else + { + /* other interrupts are serious and should leave a turd + * + * RTC_SR_TIF _TOF _MOF + */ + + rtcwarn("unexp int src=0x%x, num=", rtc_sr); } /* Clear pending flags, disable alarm */ - putreg32(0, KINETIS_RTC_TAR); /* unset alarm (resets flags) */ - putreg32(0, KINETIS_RTC_IER); /* disable alarm interrupt */ + putreg32(0, KINETIS_RTC_TAR); /* Unset alarm (resets flags) */ + putreg32(0, KINETIS_RTC_IER); /* Disable alarm interrupt */ return 0; } #endif +/**************************************************************************** + * Name: RTC_Reset + * + * Description: + * Reset the RTC to known state + * + * Input Parameters: + * none + * + * Returned Value: + * none + * + ****************************************************************************/ + +static inline void RTC_Reset(void) +{ + putreg32(( RTC_CR_SWR | getreg32(KINETIS_RTC_CR)),KINETIS_RTC_CR); + putreg32((~RTC_CR_SWR & getreg32(KINETIS_RTC_CR)),KINETIS_RTC_CR); + + /* Set TSR register to 0x1 to avoid the timer invalid (TIF) bit being + * set in the SR register + */ + + putreg32(1,KINETIS_RTC_TSR); +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: up_rtc_irqinit + * + * Description: + * Initialize the hardware RTC irq. +* This only needs to be called once when first used. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#if defined(CONFIG_RTC_ALARM) +int up_rtc_irq_attach(void) +{ + uint32_t rtc_sr; + + if (!rtc_irq_state) + { + rtc_irq_state=true; + + /* Clear TAF if pending */ + + rtc_sr = getreg32( KINETIS_RTC_SR); + if (rtc_sr & RTC_SR_TAF ) + { + putreg32(0, KINETIS_RTC_TAR); + } + + /* Enable alarm interrupts. + * This will not work if part of up_rtc_initialize() + * as it is called very early in initialization BEFORE the interrupt + * system will be enabled. All interrupts will disabled later when + * the interrupt system is disabled. This must be done later when the + * alarm is first set. + * + * KINETIS_IRQ_RTCS is a separate interrupt for seconds if needed + */ + + irq_attach(KINETIS_IRQ_RTC, kinetis_rtc_interrupt); + up_enable_irq(KINETIS_IRQ_RTC); + } + + return OK; +} +#endif + /**************************************************************************** * Name: up_rtc_initialize * @@ -134,7 +304,8 @@ static int kinetis_rtc_interrupt(int irq, void *context) int up_rtc_initialize(void) { - int regval; + uint32_t regval; + bool rtc_valid = false; /* Enable RTC module */ @@ -142,16 +313,64 @@ int up_rtc_initialize(void) regval |= SIM_SCGC6_RTC; putreg32(regval, KINETIS_SIM_SCGC6); - /* Disable counters (just in case) */ + regval = getreg32(KINETIS_RTC_SR); + if (!(regval & RTC_SR_TIF)) + { +#ifdef KINETIS_RTC_GEN2 + /* Check if the one-time initialization of the RTC has already been + * performed. We can determine this by checking if the magic number + * has been writing to to back-up date register DR0. + */ - putreg32(0, KINETIS_RTC_SR); + regval = getreg32(KINETIS_RTC_MCLR); + if ((CONFIG_RTC_MAGICL == regval ) && + (CONFIG_RTC_MAGICH == getreg32(KINETIS_RTC_MCHR)) ) +#endif + { + rtc_valid = true; + } + } - /* Enable oscilator */ - /* capacitance values from teensyduino */ + if (rtc_valid) + { + rtcinfo("Do resume\n"); - putreg32(RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE, KINETIS_RTC_CR); + /* RTC already set-up, just resume normal operation */ - /* TODO: delay some time (1024 cycles? would be 30ms) */ + rtc_dumpregs("Did resume"); + } + else + { + rtcinfo("Do setup\n"); + RTC_Reset(); + +#ifdef KINETIS_RTC_GEN2 + /* Configure the RTC to be initialized */ + + putreg32(CONFIG_RTC_MAGICL, KINETIS_RTC_MCLR); + putreg32(CONFIG_RTC_MAGICH, KINETIS_RTC_MCHR); +#endif + + /* Setup the update mode and supervisor access mode */ + + putreg32((~(RTC_CR_UM|RTC_CR_SUP) & getreg32(KINETIS_RTC_CR)), + KINETIS_RTC_CR); + + /* Disable counters (just in case) */ + + putreg32(0, KINETIS_RTC_SR); + + /* Enable oscilator - must have Vbat else hard fault */ + + putreg32((BOARD_RTC_CAP | RTC_CR_OSCE ), KINETIS_RTC_CR); + + /* TODO - add capability to accurately tune RTC + * This is a per individual board customization and requires + * parameters to be configurable and stored in non-volatile eg flash. + */ + + /* TODO: delay some time (1024 cycles? would be 30ms) */ + } /* Disable interrupts */ @@ -163,17 +382,6 @@ int up_rtc_initialize(void) putreg32(getreg32(KINETIS_RTC_TSR), KINETIS_RTC_TSR); -#if defined(CONFIG_RTC_ALARM) - /* Enable alarm interrupts. REVISIT: This will not work. up_rtc_initialize() - * is called very early in initialization BEFORE the interrupt system will be - * enabled. All interrupts will disabled later when the interrupt system is - * disabled. This must be done later when the alarm is first set. - */ - - irq_attach(KINETIS_IRQ_RTC, kinetis_rtc_interrupt); - up_enable_irq(KINETIS_IRQ_RTC); -#endif - /* Enable counters */ putreg32(RTC_SR_TCE, KINETIS_RTC_SR); @@ -319,12 +527,18 @@ int kinetis_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback) g_alarmcb = callback; + /* ensure irq is attached */ + + up_rtc_irq_attach(); + /* Enable and set RTC alarm */ putreg32(tp->tv_sec, KINETIS_RTC_TAR); /* Set alarm (also resets * flags) */ putreg32(RTC_IER_TAIE, KINETIS_RTC_IER); /* Enable alarm interrupt */ + rtc_dumpregs("set alarmtime"); + return OK; } else diff --git a/arch/arm/src/kinetis/kinetis_rtc_if.h b/arch/arm/src/kinetis/kinetis_rtc_if.h new file mode 100644 index 0000000000..78dd7774f2 --- /dev/null +++ b/arch/arm/src/kinetis/kinetis_rtc_if.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_rtc_if.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Neil Hancock + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_KINETIS_KINETIS_RTC_IF_H +#define __ARCH_ARM_SRC_KINETIS_KINETIS_RTC_IF_H + +#include + +#include "chip.h" + +/* Kinetis parts all have a simple battery-backed 32bit counter for its RTC + * KINETIS_RTC_GEN2 have + * a Tamper Time seconds - 32bibt + * a MONOTONC seconds which is used is 2*32bit registers + * + */ + +#include "kinetis_alarm.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: KINETIS_rtc_getdatetime_with_subseconds + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS + * during initialization to set up the system time when CONFIG_RTC and + * CONFIG_RTC_DATETIME are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. + * Thatsub-second accuracy is returned through 'nsec'. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * nsec - The location to return the subsecond time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_KINETIS_HAVE_RTC_SUBSECONDS +int KINETIS_rtc_getdatetime_with_subseconds(FAR struct tm *tp, FAR long *nsec); +#endif + +/**************************************************************************** + * Name: KINETIS_rtc_setdatetime + * + * Description: + * Set the RTC to the provided time. RTC implementations which provide + * up_rtc_getdatetime() (CONFIG_RTC_DATETIME is selected) should provide + * this function. + * + * Input Parameters: + * tp - the time to use + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DATETIME +struct tm; +int kinetis_rtc_setdatetime(FAR const struct tm *tp); +#endif + +/**************************************************************************** + * Name: KINETIS_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the KINETIS. General usage: + * + * #include + * #include "KINETIS_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = KINETIS_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. NULL is + * returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_DRIVER +FAR struct rtc_lowerhalf_s *kinetis_rtc_lowerhalf(void); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_KINETIS_KINETIS_RTC_IF_H */ diff --git a/arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c b/arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c new file mode 100644 index 0000000000..961a212b6a --- /dev/null +++ b/arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c @@ -0,0 +1,525 @@ +/**************************************************************************** + * arch/arm/src/kinetis/kinetis_rtc_lowerhalf.c + * + * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * Updates for kinetis by Neil Hancock + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* REVISIT: This driver is *not* thread-safe! */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "kinetis_rtc_if.h" +#include "kinetis_alarm.h" + +#ifdef CONFIG_RTC_DRIVER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +struct kinetis_cbinfo_s +{ + volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */ + volatile FAR void *priv; /* Private argurment to accompany callback */ +}; +#endif + +/* This is the private type for the RTC state. It must be cast compatible + * with struct rtc_lowerhalf_s. + */ + +struct kinetis_lowerhalf_s +{ + /* This is the contained reference to the read-only, lower-half + * operations vtable (which may lie in FLASH or ROM) + */ + + FAR const struct rtc_ops_s *ops; + + /* Data following is private to this driver and not visible outside of + * this file. + */ + +#ifdef CONFIG_RTC_ALARM + /* Alarm callback information */ + + struct kinetis_cbinfo_s cbinfo; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Prototypes for static methods in struct rtc_ops_s */ + +static int kinetis_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime); +static int kinetis_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime); + +#ifdef CONFIG_RTC_ALARM +static int kinetis_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo); +static int kinetis_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo); +static int kinetis_cancelalarm(FAR struct rtc_lowerhalf_s *lower, + int alarmid); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Kinetis RTC driver operations */ + +static const struct rtc_ops_s g_rtc_ops = +{ + .rdtime = kinetis_rdtime, + .settime = kinetis_settime, +#ifdef CONFIG_RTC_ALARM + .setalarm = kinetis_setalarm, + .setrelative = kinetis_setrelative, + .cancelalarm = kinetis_cancelalarm, +#endif +#ifdef CONFIG_RTC_IOCTL + .ioctl = NULL, +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + .destroy = NULL, +#endif +}; + +/* Kinetis RTC device operations */ + +static struct kinetis_lowerhalf_s g_rtc_lowerhalf = +{ + .ops = &g_rtc_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: kinetis_alarm_callback + * + * Description: + * This is the function that is called from the RTC driver when the alarm + * goes off. It just invokes the upper half drivers callback. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static void kinetis_alarm_callback(void) +{ + FAR struct kinetis_cbinfo_s *cbinfo = &g_rtc_lowerhalf.cbinfo;/*[0];*/ + + /* Sample and clear the callback information to minimize the window in + * time in which race conditions can occur. + */ + + rtc_alarm_callback_t cb = (rtc_alarm_callback_t)cbinfo->cb; + FAR void *arg = (FAR void *)cbinfo->priv; + + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Perform the callback */ + + if (cb != NULL) + { + cb(arg, 0); + } +} +#endif /* CONFIG_RTC_ALARM */ + +/**************************************************************************** + * Name: kinetis_rdtime + * + * Description: + * Implements the rdtime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rtctime - The location in which to return the current RTC time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int kinetis_rdtime(FAR struct rtc_lowerhalf_s *lower, + FAR struct rtc_time *rtctime) +{ +#if defined(CONFIG_RTC_DATETIME) + /* This operation depends on the fact that struct rtc_time is cast + * compatible with struct tm. + */ + + return up_rtc_getdatetime((FAR struct tm *)rtctime); + +#elif defined(CONFIG_RTC_HIRES) + FAR struct timespec ts; + int ret; + + /* Get the higher resolution time */ + + ret = up_rtc_gettime(&ts); + if (ret < 0) + { + goto errout_with_errno; + } + + /* Convert the one second epoch time to a struct tm. This operation + * depends on the fact that struct rtc_time and struct tm are cast + * compatible. + */ + + if (!gmtime_r(&ts.tv_sec, (FAR struct tm *)rtctime)) + { + goto errout_with_errno; + } + + return OK; + +errout_with_errno: + ret = get_errno(); + DEBUGASSERT(ret > 0); + return -ret; + +#else + time_t timer; + + /* The resolution of time is only 1 second */ + + timer = up_rtc_time(); + + /* Convert the one second epoch time to a struct tm */ + + if (!gmtime_r(&timer, (FAR struct tm *)rtctime)) + { + int errcode = get_errno(); + DEBUGASSERT(errcode > 0); + return -errcode; + } + + return OK; +#endif +} + +/**************************************************************************** + * Name: kinetis_settime + * + * Description: + * Implements the settime() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * rcttime - The new time to set + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +static int kinetis_settime(FAR struct rtc_lowerhalf_s *lower, + FAR const struct rtc_time *rtctime) +{ + struct timespec ts; + + /* Convert the struct rtc_time to a time_t. Here we assume that struct + * rtc_time is cast compatible with struct tm. + */ + + ts.tv_sec = mktime((FAR struct tm *)rtctime); + ts.tv_nsec = 0; + + /* Set the time (to one second accuracy) */ + + return up_rtc_settime(&ts); +} + +/**************************************************************************** + * Name: kinetis_setalarm + * + * Description: + * Set a new alarm. This function implements the setalarm() method of the + * RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int kinetis_setalarm(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setalarm_s *alarminfo) +{ + FAR struct kinetis_lowerhalf_s *priv; + FAR struct kinetis_cbinfo_s *cbinfo; + + struct timespec tp; + + int ret = -EINVAL; + + /* ID0-> Alarm A supported */ + + DEBUGASSERT(lower != NULL && alarminfo != NULL); + priv = (FAR struct kinetis_lowerhalf_s *)lower; + + if (alarminfo->id == RTC_ALARMA ) + { + /* Remember the callback information */ + + cbinfo = &priv->cbinfo; + cbinfo->cb = alarminfo->cb; + cbinfo->priv = alarminfo->priv; + + /* Convert from Julian calendar time to epoch time */ + + tp.tv_sec = mktime((FAR struct tm *)&alarminfo->time) ; + + /* And set the alarm */ + + ret = kinetis_rtc_setalarm(&tp, kinetis_alarm_callback); + if (ret < 0) + { + cbinfo->cb = NULL; + cbinfo->priv = NULL; + } + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: kinetis_setrelative + * + * Description: + * Set a new alarm relative to the current time. This function implements + * the setrelative() method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int kinetis_setrelative(FAR struct rtc_lowerhalf_s *lower, + FAR const struct lower_setrelative_s *alarminfo) +{ + struct lower_setalarm_s setalarm; +#if defined(CONFIG_RTC_DATETIME) + struct tm time; +#endif + time_t seconds; + struct timespec ts; + int ret = -EINVAL; + + ASSERT(lower != NULL && alarminfo != NULL); + DEBUGASSERT(alarminfo->id == RTC_ALARMA); + + if ((alarminfo->id == RTC_ALARMA ) && + alarminfo->reltime > 0) + { + /* Disable pre-emption while we do this so that we don't have to worry + * about being suspended and working on an old time. + */ + + sched_lock(); + +#if defined(CONFIG_RTC_DATETIME) + /* Get the broken out time and convert to seconds */ + + ret = up_rtc_getdatetime(&time); + if (ret < 0) + { + sched_unlock(); + return ret; + } + + ts.tv_sec = mktime(&time); + ts.tv_nsec = 0; +#else + /* Get the current time in broken out format */ + + ret = up_rtc_gettime(&ts); + if (ret < 0) + { + sched_unlock(); + return ret; + } +#endif + /* Convert to seconds since the epoch */ + + seconds = ts.tv_sec; + + /* Add the seconds offset. Add one to the number of seconds + * because we are unsure of the phase of the timer. + */ + + seconds += (alarminfo->reltime + 1); + + /* And convert the time back to Julian/broken out format */ + + (void)gmtime_r(&seconds, (FAR struct tm *)&setalarm.time); + + /* The set the alarm using this absolute time */ + + setalarm.id = alarminfo->id; + setalarm.cb = alarminfo->cb; + setalarm.priv = alarminfo->priv; + + ret = kinetis_setalarm(lower, &setalarm); + + sched_unlock(); + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: kinetis_cancelalarm + * + * Description: + * Cancel the current alarm. This function implements the cancelalarm() + * method of the RTC driver interface + * + * Input Parameters: + * lower - A reference to RTC lower half driver state structure + * alarminfo - Provided information needed to set the alarm + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_RTC_ALARM +static int kinetis_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid) +{ + FAR struct kinetis_lowerhalf_s *priv; + FAR struct kinetis_cbinfo_s *cbinfo; + int ret = -EINVAL; + + DEBUGASSERT(lower != NULL); + DEBUGASSERT(alarmid == RTC_ALARMA); + priv = (FAR struct kinetis_lowerhalf_s *)lower; + + /* ID0-> Alarm A */ + + if (alarmid == RTC_ALARMA) + { + /* Nullify callback information to reduce window for race conditions */ + + cbinfo = &priv->cbinfo; + cbinfo->cb = NULL; + cbinfo->priv = NULL; + + /* Then cancel the alarm */ + + ret = kinetis_rtc_cancelalarm(); + + } + + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: kinetis_rtc_lowerhalf + * + * Description: + * Instantiate the RTC lower half driver for the Kinetis. General usage: + * + * #include + * #include "kinetis_rtc.h> + * + * struct rtc_lowerhalf_s *lower; + * lower = kinetis_rtc_lowerhalf(); + * rtc_initialize(0, lower); + * + * Input Parameters: + * None + * + * Returned Value: + * On success, a non-NULL RTC lower interface is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct rtc_lowerhalf_s *kinetis_rtc_lowerhalf(void) +{ + return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf; +} + +#endif /* CONFIG_RTC_DRIVER */ diff --git a/configs/freedom-k64f/src/freedom-k64f.h b/configs/freedom-k64f/src/freedom-k64f.h index d63492a071..40f788d7cd 100644 --- a/configs/freedom-k64f/src/freedom-k64f.h +++ b/configs/freedom-k64f/src/freedom-k64f.h @@ -3,6 +3,7 @@ * * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt + * Updated: Neil Hancock * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,6 +59,10 @@ #define HAVE_AUTOMOUNTER 1 #define HAVE_USBDEV 1 +#if defined(CONFIG_KINETIS_RTC) +#define HAVE_RTC_DRIVER 1 +#endif + /* Automount procfs */ #if !defined(CONFIG_FS_PROCFS) diff --git a/configs/freedom-k64f/src/k64_bringup.c b/configs/freedom-k64f/src/k64_bringup.c index 40590f8962..78bba052f4 100644 --- a/configs/freedom-k64f/src/k64_bringup.c +++ b/configs/freedom-k64f/src/k64_bringup.c @@ -1,7 +1,7 @@ /**************************************************************************** * config/freedom-k64f/src/k64_bringup.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,11 @@ #include #include +#ifdef HAVE_RTC_DRIVER +# include +# include "kinetis_alarm.h" +#endif + #include "freedom-k64f.h" #if defined(CONFIG_LIB_BOARDCTL) || defined(CONFIG_BOARD_INITIALIZE) @@ -64,6 +69,9 @@ int k64_bringup(void) { int ret; +#ifdef HAVE_RTC_DRIVER + FAR struct rtc_lowerhalf_s *lower; +#endif #ifdef HAVE_PROC /* Mount the proc filesystem */ @@ -92,7 +100,6 @@ int k64_bringup(void) #ifdef CONFIG_FRDMK64F_SDHC_MOUNT else { - /* REVISIT: A delay seems to be required here or the mount will fail. */ /* Mount the volume on HSMCI0 */ ret = mount(CONFIG_FRDMK64F_SDHC_MOUNT_BLKDEV, @@ -126,6 +133,31 @@ int k64_bringup(void) k64_automount_initialize(); #endif +#ifdef HAVE_RTC_DRIVER + /* Instantiate the KINETIS lower-half RTC driver */ + + lower = kinetis_rtc_lowerhalf(); + if (!lower) + { + syslog(LOG_ERR, + "ERROR: Failed to instantiate the RTC lower-half driver\n"); + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to bind/register the RTC driver: %d\n", + ret); + } + } +#endif + UNUSED(ret); return OK; }