RTC: Simplify the RTC driver interface. Way too much stuff in that interface and it is not fully implemented anywhere.

This commit is contained in:
Gregory Nutt 2016-04-02 13:01:02 -06:00
parent ab3f9b764e
commit 58d6624f29
5 changed files with 220 additions and 399 deletions

View File

@ -11600,3 +11600,9 @@
* arch/arm/src/armv7-m and stm32: Add support for the IAR toolchain for
the limited case of the ARMv7-M architecture and the STM32 chip. From
Aleksandr Vyhovanec (2016-04-02).
* arch/arm/src/stm32/stm32f40xxx_rtc.c: Add a custom RTC driver. From
Neil Hancock (2016-04-02).
* include/nuttx/timer/rtc.h and drivers/timers/rtc.c: Simplify the RTC
interface. The old interface was way to complex and was not fully
implemented anywhere (2016-04-02).

2
arch

@ -1 +1 @@
Subproject commit 2eab1d6482612e2e8d7c6b226a5275694a8d682b
Subproject commit 97812e3a3e124c579a66b07a79a5595c84123d5d

View File

@ -70,6 +70,12 @@ config RTC_ALARM
Enable if the RTC hardware supports setting of an alarm. A callback
function will be executed when the alarm goes off.
config RTC_NALARMS
int "Number of alarms"
default 1
---help---
Number of alarms supported by the hardware.
config RTC_DRIVER
bool "RTC Driver Support"
default n

View File

@ -53,13 +53,32 @@
* Private Types
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
struct rtc_alarminfo_s
{
bool active; /* True: alarm is active */
uint8_t signo; /* Signal number for alarm notification */
pid_t pid; /* Identifies task to be notified */
union sigval sigvalue; /* Data passed with notification */
};
#endif
struct rtc_upperhalf_s
{
FAR struct rtc_lowerhalf_s *lower; /* Contained lower half driver */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
uint8_t crefs; /* Number of open references */
bool unlinked; /* True if the driver has been unlinked */
#endif
#ifdef CONFIG_RTC_ALARM
/* This is an array, indexed by the alarm ID, that provides information
* needed to map an alarm expiration to a signal event.
*/
struct rtc_alarminfo_s alarminfo[CONFIG_RTC_NALARMS];
#endif
};
/****************************************************************************
@ -72,6 +91,10 @@ struct rtc_upperhalf_s
static void rtc_destroy(FAR struct rtc_upperhalf_s *upper);
#endif
#ifdef CONFIG_RTC_ALARM
static void rtc_alarm_callback(FAR void *priv, int id);
#endif
/* Character driver methods */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
@ -119,7 +142,7 @@ static const struct file_operations rtc_fops =
****************************************************************************/
/****************************************************************************
* Name: rtc_destory
* Name: rtc_destroy
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
@ -142,6 +165,43 @@ static void rtc_destroy(FAR struct rtc_upperhalf_s *upper)
}
#endif
/****************************************************************************
* Name: rtc_alarm_callback
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
static void rtc_alarm_callback(FAR void *priv, int alarmid)
{
FAR struct rtc_upperhalf_s *upper = (FAR struct rtc_upperhalf_s *)priv;
FAR struct rtc_alarminfo_s *alarminfo;
DEBUGASSERT(upper != NULL && id >=0 && ID < CONFIG_RTC_NALARMS);
alarminfo = &upper->alarminfo[alarmid];
/* Do we think that the alaram is active? It might be due to some
* race condition between a cancellation event and the alarm
* expiration.
*/
if (alarminfo->active)
{
/* Yes.. signal the alarm expriration */
#ifdef CONFIG_CAN_PASS_STRUCTS
(void)sigqueue(alarminfo->pid, alarminfo->signo,
alarminfo->sigvalue);
#else
(void)sigqueue(alarminfo->pid, alarminfo->signo,
alarminfo->sigvalue->sival_ptr);
#endif
}
/* The alarm is no longer active */
alarminfo->active = false;
}
#endif
/****************************************************************************
* Name: rtc_open
****************************************************************************/
@ -289,238 +349,117 @@ static int rtc_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
break;
#ifdef CONFIG_RTC_ALARM
/* RTC_ALM_READ reads the alarm time (for RTCs that support alarms)
/* RTC_RD_ALARM reads the alarm time
*
* Argument: A writeable reference to a struct rtc_time to receive the
* RTC's alarm time.
* Argument: A writeable reference to struct rtc_rdalarm_s to receive the
* current alarm settings.
*/
case RTC_ALM_READ:
case RTC_RD_ALARM:
{
FAR struct rtc_time *almtime = (FAR struct rtc_time *)((uintptr_t)arg);
FAR struct rtc_rdalarm_s *alarminfo =
(FAR struct rtc_rdalarm_s *)((uintptr_t)arg);
int alarmid;
if (ops->almread)
DEBUGASSERT(alarminfo != NULL);
alarmid = alarminfo->id;
DEBUGASSERT(alarmid >= 0 && alarmid < RTC_NALARMS);
/* Is the alarm active? */
if (upper->alarminfo[alarmid].active)
{
ret = ops->almread(upper->lower, almtime);
/* Yes, read the alarm */
if (ops->rdalarm)
{
ret = ops->rdalarm(upper->lower, alarminfo);
}
}
else
{
/* No.. decline the request to return the time. */
alarminfo->active = false;
ret = OK;
}
}
break;
/* RTC_ALM_SET sets the alarm time (for RTCs that support alarms).
/* RTC_SET_ALARM sets the alarm time.
*
* Argument: A read-only reference to a struct rtc_time containing the
* new alarm time to be set.
*/
case RTC_ALM_SET:
case RTC_SET_ALARM:
{
FAR const struct rtc_time *almtime =
(FAR const struct rtc_time *)((uintptr_t)arg);
FAR const struct rtc_setalarm_s *alarminfo =
(FAR const struct rtc_setalarm_s *)((uintptr_t)arg);
FAR struct rtc_alarminfo_s *upperinfo;
struct lower_setalarm_s lowerinfo;
int alarmid;
if (ops->almset)
DEBUGASSERT(alarminfo != NULL);
alarmid = alarminfo->id;
DEBUGASSERT(alarminfo->id >= 0 && alarminfo->id < RTC_NALARMS);
/* Is the alarm active? */
upperinfo = &upper->alarminfo[alarmid];
if (upperinfo->active)
{
ret = ops->almset(upper->lower, almtime);
/* Yes, cancel the alarm */
if (ops->cancelalarm)
{
ret = ops->cancelalarm(upper->lower, alarmid);
}
}
upperinfo->active = false;
if (ops->setalarm)
{
/* Save the signal info to be used to notify the caller when the
* alarm expires.
*/
upperinfo->signo = alarminfo->signo;
upperinfo->pid = alarminfo->pid;
upperinfo->sigvalue = alarminfo->sigvalue;
/* Format the alarm info needed by the lower half driver */
lowerinfo.id = alarmid;
lowerinfo.cb = rtc_alarm_callback;
lowerinfo.priv = (FAR void *)upper;
lowerinfo.time = alarminfo->time;
/* Then set the alarm */
ret = ops->setalarm(upper->lower, &lowerinfo);
if (ret >= 0)
{
upperinfo->active = true;
}
}
}
break;
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_PERIODIC
/* RTC_IRQP_READ read the frequency for periodic interrupts (for RTCs
* that support periodic interrupts)
/* RTC_WKALRM_CANCEL cancel the alarm.
*
* Argument: A pointer to a writeable unsigned long value in which to
* receive the frequency value.
* Argument: An ALARM ID value that indicates which alarm should be
* canceled.
*/
case RTC_IRQP_READ:
case RTC_CANCEL_ALARM:
{
FAR unsigned long *irqpfreq = (FAR unsigned long *)((uintptr_t)arg);
int alarmid = (int)arg;
if (ops->irqpread)
DEBUGASSERT(alarmid >= 0 && alarmid < RTC_NALARMS);
if (ops->cancelalarm)
{
ret = ops->irqpread(upper->lower, irqpfreq);
}
}
break;
/* RTC_IRQP_SET set the frequency for periodic interrupts (for RTCs that
* support periodic interrupts)
*
* Argument: An unsigned long value providing the new periodic frequency
*/
case RTC_IRQP_SET:
{
if (ops->irqpset)
{
ret = ops->irqpset(upper->lower, arg);
}
}
break;
#endif /* CONFIG_RTC_PERIODIC */
#ifdef CONFIG_RTC_ALARM
/* RTC_AIE_ON enable alarm interrupts (for RTCs that support alarms)
*
* Argument: None
*/
case RTC_AIE_ON:
{
if (ops->aie)
{
ret = ops->aie(upper->lower, true);
}
}
break;
/* RTC_AIE_OFF disable the alarm interrupt (for RTCs that support
* alarms)
*
* Argument: None
*/
case RTC_AIE_OFF:
{
if (ops->aie)
{
ret = ops->aie(upper->lower, false);
}
}
break;
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_ONESEC
/* RTC_UIE_ON enable the interrupt on every clock update (for RTCs that
* support this once-per-second interrupt).
*
* Argument: None
*/
case RTC_UIE_ON:
{
if (ops->uie)
{
ret = ops->uie(upper->lower, true);
}
}
break;
/* RTC_UIE_OFF disable the interrupt on every clock update (for RTCs
* that support this once-per-second interrupt).
*
* Argument: None
*/
case RTC_UIE_OFF:
{
if (ops->uie)
{
ret = ops->uie(upper->lower, false);
}
}
break;
#endif /* CONFIG_RTC_ONESEC */
#ifdef CONFIG_RTC_PERIODIC
/* RTC_PIE_ON enable the periodic interrupt (for RTCs that support these
* periodic interrupts).
*
* Argument: None
*/
case RTC_PIE_ON:
{
if (ops->pie)
{
ret = ops->pie(upper->lower, true);
}
}
break;
/* RTC_PIE_OFF disable the periodic interrupt (for RTCs that support
* these periodic interrupts).
*
* Argument: None
*/
case RTC_PIE_OFF:
{
if (ops->pie)
{
ret = ops->pie(upper->lower, false);
}
}
break;
#endif /* CONFIG_RTC_PERIODIC */
#ifdef CONFIG_RTC_EPOCHYEAR
/* RTC_EPOCH_READ read the Epoch.
*
* Argument: A reference to a writeable unsigned low variable that will
* receive the Epoch value.
*/
case RTC_EPOCH_READ:
{
FAR unsigned long *epoch = (FAR unsigned long *)((uintptr_t)arg);
if (ops->rdepoch)
{
ret = ops->rdepoch(upper->lower, epoch);
}
}
break;
/* RTC_EPOCH_SET set the Epoch
*
* Argument: An unsigned long value containing the new Epoch value to be
* set.
*/
case RTC_EPOCH_SET:
{
if (ops->setepoch)
{
ret = ops->setepoch(upper->lower, arg);
}
}
break;
#endif /* CONFIG_RTC_EPOCHYEAR */
#ifdef CONFIG_RTC_ALARM
/* RTC_WKALM_RD read the current alarm
*
* Argument: A writeable reference to struct rtc_wkalrm to receive the
* current alarm settings.
*/
case RTC_WKALM_RD:
{
FAR struct rtc_wkalrm *wkalrm = (FAR struct rtc_wkalrm *)((uintptr_t)arg);
if (ops->rdwkalm)
{
ret = ops->rdwkalm(upper->lower, wkalrm);
}
}
break;
/* RTC_WKALM_SET set the alarm.
*
* Argument: A read-only reference to struct rtc_wkalrm containing the
* new alarm settings.
*/
case RTC_WKALM_SET:
{
FAR const struct rtc_wkalrm *wkalrm =
(FAR const struct rtc_wkalrm *)((uintptr_t)arg);
if (ops->setwkalm)
{
ret = ops->setwkalm(upper->lower, wkalrm);
ret = ops->cancelalarm(upper->lower, alarmid);
}
}
break;

View File

@ -6,7 +6,7 @@
*
* With extensions, modifications by:
*
* Copyright (C) 2011-2012, 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2011-2012, 2015-2016 Gregory Nutt. All rights reserved.
* Author: Gregroy Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -107,6 +107,15 @@
# endif
#endif
#ifdef CONFIG_RTC_ALARM
# ifdef CONFIG_DISABLE_SIGNALS
# error RTC driver alarm support depends on signals
# endif
# ifndef CONFIG_RTC_NALARMS
# define CONFIG_RTC_NALARMS 1
# endif
#endif
/* The remainder of the contain of this header file is only valid if the
* RTC upper half driver is built.
*/
@ -134,132 +143,28 @@
#define RTC_SET_TIME _RTCIOC(0x0002)
/* RTC_ALM_READ reads the alarm time (for RTCs that support alarms)
/* RTC_RD_ALARM reads the alarm time (for RTCs that support alarms)
*
* Argument: A writeable reference to a struct rtc_time to receive the RTC's
* Argument: A writeable reference to a struct rtc_rdalarm_s to receive the RTC's
* alarm time.
*/
#define RTC_ALM_READ _RTCIOC(0x0003)
#define RTC_RD_ALARM _RTCIOC(0x0003)
/* RTC_ALM_SET sets the alarm time (for RTCs that support alarms).
/* RTC_SET_ALARM sets the alarm time (for RTCs that support alarms).
*
* Argument: A read-only reference to a struct rtc_time containing the
* Argument: A read-only reference to a struct rtc_setalarm_s containing the
* new alarm time to be set.
*/
#define RTC_ALM_SET _RTCIOC(0x0004)
#define RTC_SET_ALARM _RTCIOC(0x0004)
/* RTC_IRQP_READ read the frequency for periodic interrupts (for RTCs that
* support periodic interrupts)
/* RTC_WKALRM_CANCEL cancel the alarm.
*
* Argument: A pointer to a writeable unsigned long value in which to
* receive the frequency value.
* Argument: An ALARM ID value that indicates which alarm should be canceled.
*/
#define RTC_IRQP_READ _RTCIOC(0x0005)
/* RTC_IRQP_SET set the frequency for periodic interrupts (for RTCs that
* support periodic interrupts)
*
* Argument: An unsigned long value providing the new periodic frequency
*/
#define RTC_IRQP_SET _RTCIOC(0x0006)
/* RTC_AIE_ON enable alarm interrupts (for RTCs that support alarms)
*
* Argument: None
*/
#define RTC_AIE_ON _RTCIOC(0x0007)
/* RTC_AIE_OFF disable the alarm interrupt (for RTCs that support alarms)
*
* Argument: None
*/
#define RTC_AIE_OFF _RTCIOC(0x0008)
/* RTC_UIE_ON enable the interrupt on every clock update (for RTCs that
* support this once-per-second interrupt).
*
* Argument: None
*/
#define RTC_UIE_ON _RTCIOC(0x0009)
/* RTC_UIE_OFF disable the interrupt on every clock update (for RTCs that
* support this once-per-second interrupt).
*
* Argument: None
*/
#define RTC_UIE_OFF _RTCIOC(0x000a)
/* RTC_PIE_ON enable the periodic interrupt (for RTCs that support these
* periodic interrupts).
*
* Argument: None
*/
#define RTC_PIE_ON _RTCIOC(0x000b)
/* RTC_PIE_OFF disable the periodic interrupt (for RTCs that support these
* periodic interrupts).
*
* Argument: None
*/
#define RTC_PIE_OFF _RTCIOC(0x000c)
/* RTC_EPOCH_READ and RTC_EPOCH_SET.
*
* Many RTCs encode the year in an 8-bit register which is either interpreted
* as an 8-bit binary number or as a BCD number. In both cases, the number is
* interpreted relative to this RTC's Epoch. The RTC's Epoch is initialized to
* 1900 on most systems but on Alpha and MIPS it might also be initialized to
* 1952, 1980, or 2000, depending on the value of an RTC register for the year.
* With some RTCs, these operations can be used to read or to set the RTC's
* Epoch, respectively.
*/
/* RTC_EPOCH_READ read the Epoch.
*
* Argument: A reference to a writeable unsigned low variable that will
* receive the Epoch value.
*/
#define RTC_EPOCH_READ _RTCIOC(0x000d)
/* RTC_EPOCH_SET set the Epoch
*
* Argument: An unsigned long value containing the new Epoch value to be set.
*/
#define RTC_EPOCH_SET _RTCIOC(0x000e)
/* RTC_WKALM_RD and RTC_WKALM_SET.
*
* Some RTCs support a more powerful alarm interface, using these ioctls to
* read or write the RTC's alarm time (respectively) with the rtc_wkalrm.
*/
/* RTC_WKALM_RD read the current alarm
*
* Argument: A writeable reference to struct rtc_wkalrm to receive the
* current alarm settings.
*/
#define RTC_WKALM_RD _RTCIOC(0x000f)
/* RTC_WKALM_SET set the alarm.
*
* Argument: A read-only reference to struct rtc_wkalrm containing the
* new alarm settings.
*/
#define RTC_WKALM_SET _RTCIOC(0x0010)
#define RTC_CANCEL_ALARM _RTCIOC(0x005)
/* Architecture-specific RTC IOCTLS should begin at RTC_USER_IOCBASE. For
* example:
@ -269,7 +174,7 @@
* etc.
*/
#define RTC_USER_IOCBASE 0x0011
#define RTC_USER_IOCBASE 0x0006
/****************************************************************************
* Public Types
@ -299,21 +204,42 @@ struct rtc_time
};
#ifdef CONFIG_RTC_ALARM
/* Structure used with the RTC_WKALM_RD and RTC_WKALM_SET IOCTL commands.
*
* The enabled flag is used to enable or disable the alarm interrupt, or to
* read its current status; when using these calls, RTC_AIE_ON and
* RTC_AIE_OFF are not used. The pending flag is used by RTC_WKALM_RD to
* report a pending interrupt . The time field is as used with RTC_ALM_READ
* and RTC_ALM_SET except that the tm_mday, tm_mon, and tm_year fields are
* also valid.
/* Structure used with the RTC_RD_ALARM IOCTL command and with
* rdalarm() method.
*/
struct rtc_wkalrm
struct rtc_rdalarm_s
{
unsigned char enabled;
unsigned char pending;
struct rtc_time time;
uint8_t id; /* Indicates the alarm being queried */
bool active; /* Alarm actively timing or disabled */
struct rtc_time time; /* Current RTC time (if enabled) */
};
/* Structure used with the RTC_SETALARM IOCTL command. */
struct rtc_setalarm_s
{
uint8_t id; /* Indicates the alarm to be set */
uint8_t signo; /* Signal number for alarm notification */
pid_t pid; /* Identifies task to be notified */
union sigval sigvalue; /* Data passed with notification */
struct rtc_time time; /* Alarm time */
};
/* Callback type used by the RTC harware to notify the RTC driver when the
* alarm expires.
*/
typedef CODE void (*rtc_alarm_callback_t)(FAR void *priv, int alarmid);
/* Structure used with the setalarm method */
struct lower_setalarm_s
{
uint8_t id; /* Indicates the alarm to be set */
rtc_alarm_callback_t cb; /* Callback when the alarm expires */
FAR void *priv; /* Private argurment to accompany callback */
struct rtc_time time; /* Alarm time */
};
#endif
@ -343,77 +269,19 @@ struct rtc_ops_s
FAR const struct rtc_time *rtctime);
#ifdef CONFIG_RTC_ALARM
/* almread reads the alarm time (for RTCs that support alarms) */
/* rdalarm reads the current alarm time */
CODE int (*almread)(FAR struct rtc_lowerhalf_s *lower,
FAR struct rtc_time *almtime);
CODE int (*rdalarm)(FAR struct rtc_lowerhalf_s *lower,
FAR struct rtc_rdalarm_s *alarminfo);
/* almset sets the alarm time (for RTCs that support alarms). */
/* setalarm sets up a new alarm. */
CODE int (*almset)(FAR struct rtc_lowerhalf_s *lower,
FAR const struct rtc_time *almtime);
#endif
CODE int (*setalarm)(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setalarm_s *alarminfo);
#ifdef CONFIG_RTC_PERIODIC
/* irqpread the frequency for periodic interrupts (for RTCs that support
* periodic interrupts)
*/
/* cancelalarm cancels the alarm. */
CODE int (*irqpread)(FAR struct rtc_lowerhalf_s *lower,
FAR unsigned long *irqpfreq);
/* irqpset set the frequency for periodic interrupts (for RTCs that
* support periodic interrupts)
*/
CODE int (*irqpset)(FAR struct rtc_lowerhalf_s *lower,
unsigned long irqpfreq);
#endif
#ifdef CONFIG_RTC_ALARM
/* aie enable/disable alarm interrupts (for RTCs that support alarms) */
CODE int (*aie)(FAR struct rtc_lowerhalf_s *lower, bool enable);
#endif
#ifdef CONFIG_RTC_ONESEC
/* uie enable/disable the interrupt on every clock update (for RTCs that
* support this once-per-second interrupt).
*/
CODE int (*uie)(FAR struct rtc_lowerhalf_s *lower, bool enable);
#endif
#ifdef CONFIG_RTC_PERIODIC
/* pie enable the periodic interrupt (for RTCs that support these periodic
* interrupts).
*/
CODE int (*pie)(FAR struct rtc_lowerhalf_s *lower, bool enable);
#endif
#ifdef CONFIG_RTC_EPOCHYEAR
/* rdepoch read the Epoch. */
CODE int (*rdepoch)(FAR struct rtc_lowerhalf_s *lower,
FAR unsigned long *epoch);
/* setepoch set the Epoch */
CODE int (*setepoch)(FAR struct rtc_lowerhalf_s *lower,
unsigned long epoch);
#endif
#ifdef CONFIG_RTC_ALARM
/* rdwkalm read the current alarm */
CODE int (*rdwkalm)(FAR struct rtc_lowerhalf_s *lower,
FAR struct rtc_wkalrm *wkalrm);
/* setwkalm set the alarm. */
CODE int (*setwkalm)(FAR struct rtc_lowerhalf_s *lower,
FAR const struct rtc_wkalrm *wkalrm);
CODE int (*cancelalarm)(FAR struct rtc_lowerhalf_s *lower, int alarmid);
#endif
#ifdef CONFIG_RTC_IOCTL
@ -478,7 +346,9 @@ extern "C"
*
****************************************************************************/
#ifdef __KERNEL__
int rtc_initialize(int minor, FAR struct rtc_lowerhalf_s *lower);
#endif
#undef EXTERN
#if defined(__cplusplus)