mirror of
https://github.com/apache/nuttx.git
synced 2026-10-07 22:35:22 +00:00
arch/arm/src/max326xx: Work-in-progress RTC driver for the MAX32660
This commit is contained in:
parent
357deb41f4
commit
49ed9cac86
7 changed files with 1579 additions and 7 deletions
|
|
@ -126,10 +126,6 @@ config MAX326XX_HAVE_WAKEUP
|
|||
bool
|
||||
default n
|
||||
|
||||
config MAX326XX_HAVE_RTC
|
||||
bool
|
||||
default n
|
||||
|
||||
config MAX326XX_HAVE_CRC
|
||||
bool
|
||||
default n
|
||||
|
|
@ -248,7 +244,6 @@ config MAX326XX_WAKEUP
|
|||
config MAX326XX_RTC
|
||||
bool "RTC"
|
||||
default n
|
||||
depends on MAX326XX_HAVE_RTC
|
||||
|
||||
config MAX326XX_CRC
|
||||
bool "CRC 16/32"
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ ifeq ($(CONFIG_MAX326XX_ICC),y)
|
|||
CHIP_CSRCS += max326_icc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RTC_DRIVER),y)
|
||||
CHIP_CSRCS += max326_rtc_lowerhalf.c
|
||||
endif
|
||||
|
||||
# Source Files for the MAX32620 and MAX32630
|
||||
|
||||
# Source Files for the MAX32660
|
||||
|
|
@ -122,6 +126,12 @@ CHIP_CSRCS += max32660_gpioirq.c
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MAX326XX_RTC),y)
|
||||
ifeq ($(CONFIG_ARCH_FAMILY_MAX32660),y)
|
||||
CHIP_CSRCS += max32660_rtc.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MAX32XX_WDT),y)
|
||||
ifeq ($(CONFIG_ARCH_FAMILY_MAX32660),y)
|
||||
CHIP_CSRCS += max32660_rtc.c
|
||||
|
|
|
|||
762
arch/arm/src/max326xx/common/max326_rtc_lowerhalf.c
Normal file
762
arch/arm/src/max326xx/common/max326_rtc_lowerhalf.c
Normal file
|
|
@ -0,0 +1,762 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/max326xx/max326_rtc_lowerhalf.c
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/timers/rtc.h>
|
||||
|
||||
#include "up_arch.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include "max326_rtc.h"
|
||||
|
||||
#ifdef CONFIG_RTC_DRIVER
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define RTC_NALARMS 1
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
struct max326_cbinfo_s
|
||||
{
|
||||
volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */
|
||||
volatile FAR void *priv; /* Private argument to accompany callback */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* This is the private type for the RTC state. It must be cast compatible
|
||||
* with struct rtc_lowerhalf_s.
|
||||
*/
|
||||
|
||||
struct max326_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.
|
||||
*/
|
||||
|
||||
sem_t devsem; /* Threads can only exclusively access the RTC */
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
/* Alarm callback information */
|
||||
|
||||
struct max326_cbinfo_s cbinfo[RTC_NALARMS];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
/* Periodic wakeup information */
|
||||
|
||||
struct lower_setperiodic_s periodic;
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
/* Prototypes for static methods in struct rtc_ops_s */
|
||||
|
||||
static int max326_rdtime(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR struct rtc_time *rtctime);
|
||||
static int max326_settime(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct rtc_time *rtctime);
|
||||
static bool max326_havesettime(FAR struct rtc_lowerhalf_s *lower);
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
static int max326_setalarm(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setalarm_s *alarminfo);
|
||||
static int max326_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setrelative_s *alarminfo);
|
||||
static int max326_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
|
||||
int alarmid);
|
||||
static int max326_rdalarm(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR struct lower_rdalarm_s *alarminfo);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
static int max326_setperiodic(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setperiodic_s *alarminfo);
|
||||
static int max326_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* RTC driver operations */
|
||||
|
||||
static const struct rtc_ops_s g_rtc_ops =
|
||||
{
|
||||
.rdtime = max326_rdtime,
|
||||
.settime = max326_settime,
|
||||
.havesettime = max326_havesettime,
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
.setalarm = max326_setalarm,
|
||||
.setrelative = max326_setrelative,
|
||||
.cancelalarm = max326_cancelalarm,
|
||||
.rdalarm = max326_rdalarm,
|
||||
#endif
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
.setperiodic = max326_setperiodic,
|
||||
.cancelperiodic = max326_cancelperiodic,
|
||||
#endif
|
||||
#ifdef CONFIG_RTC_IOCTL
|
||||
.ioctl = NULL,
|
||||
#endif
|
||||
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
|
||||
.destroy = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* RTC device state */
|
||||
|
||||
static struct max326_lowerhalf_s g_rtc_lowerhalf =
|
||||
{
|
||||
.ops = &g_rtc_ops,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_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 max326_alarm_callback(FAR void *arg, unsigned int alarmid)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *lower;
|
||||
FAR struct max326_cbinfo_s *cbinfo;
|
||||
rtc_alarm_callback_t cb;
|
||||
FAR void *priv;
|
||||
|
||||
DEBUGASSERT(alarmid < RTC_NALARMS);
|
||||
|
||||
lower = (struct max326_lowerhalf_s *)arg;
|
||||
cbinfo = &lower->cbinfo[alarmid];
|
||||
|
||||
/* Sample and clear the callback information to minimize the window in
|
||||
* time in which race conditions can occur.
|
||||
*/
|
||||
|
||||
cb = (rtc_alarm_callback_t)cbinfo->cb;
|
||||
priv = (FAR void *)cbinfo->priv;
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
cbinfo->cb = NULL;
|
||||
cbinfo->priv = NULL;
|
||||
|
||||
/* Perform the callback */
|
||||
|
||||
if (cb != NULL)
|
||||
{
|
||||
cb(priv, alarmid);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_RTC_ALARM */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rdtime
|
||||
*
|
||||
* Description:
|
||||
* Implements the rdtime() method of the RTC driver interface
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - A reference to RTC lower half driver state structure
|
||||
* rcttime - 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 max326_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: max326_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 max326_settime(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct rtc_time *rtctime)
|
||||
{
|
||||
#ifdef CONFIG_RTC_DATETIME
|
||||
/* This operation depends on the fact that struct rtc_time is cast
|
||||
* compatible with struct tm.
|
||||
*/
|
||||
|
||||
return max326_rtc_setdatetime((FAR const struct tm *)rtctime);
|
||||
|
||||
#else
|
||||
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;
|
||||
|
||||
/* Now set the time (to one second accuracy) */
|
||||
|
||||
return up_rtc_settime(&ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_havesettime
|
||||
*
|
||||
* Description:
|
||||
* Implements the havesettime() method of the RTC driver interface
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - A reference to RTC lower half driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns true if RTC date-time have been previously set.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool max326_havesettime(FAR struct rtc_lowerhalf_s *lower)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_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 max326_setalarm(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setalarm_s *alarminfo)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *priv;
|
||||
FAR struct max326_cbinfo_s *cbinfo;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0);
|
||||
priv = (FAR struct max326_lowerhalf_s *)lower;
|
||||
|
||||
ret = nxsem_wait(&priv->devsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
if (alarminfo->id == 0)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
/* Convert the RTC time to a timespec (1 second accuracy) */
|
||||
|
||||
ts.tv_sec = mktime((FAR struct tm *)&alarminfo->time);
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
/* Remember the callback information */
|
||||
|
||||
cbinfo = &priv->cbinfo[0];
|
||||
cbinfo->cb = alarminfo->cb;
|
||||
cbinfo->priv = alarminfo->priv;
|
||||
|
||||
/* And set the alarm */
|
||||
|
||||
ret = max326_rtc_setalarm(&ts, max326_alarm_callback, lower);
|
||||
if (ret < 0)
|
||||
{
|
||||
cbinfo->cb = NULL;
|
||||
cbinfo->priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nxsem_post(&priv->devsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_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 max326_setrelative(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setrelative_s *alarminfo)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *priv;
|
||||
FAR struct max326_cbinfo_s *cbinfo;
|
||||
#if defined(CONFIG_RTC_DATETIME)
|
||||
struct tm time;
|
||||
#endif
|
||||
FAR struct timespec ts;
|
||||
int ret = -EINVAL;
|
||||
|
||||
DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0);
|
||||
priv = (FAR struct max326_lowerhalf_s *)lower;
|
||||
|
||||
if (alarminfo->id == 0 && 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();
|
||||
|
||||
/* Get the current time in seconds */
|
||||
|
||||
#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;
|
||||
|
||||
#elif defined(CONFIG_RTC_HIRES)
|
||||
/* Get the higher resolution time */
|
||||
|
||||
ret = up_rtc_gettime(&ts);
|
||||
if (ret < 0)
|
||||
{
|
||||
sched_unlock();
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
/* The resolution of time is only 1 second */
|
||||
|
||||
ts.tv_sec = up_rtc_time();
|
||||
ts.tv_nsec = 0;
|
||||
#endif
|
||||
|
||||
/* Add the seconds offset. Add one to the number of seconds because
|
||||
* we are unsure of the phase of the timer.
|
||||
*/
|
||||
|
||||
ts.tv_sec += (alarminfo->reltime + 1);
|
||||
|
||||
/* Remember the callback information */
|
||||
|
||||
cbinfo = &priv->cbinfo[0];
|
||||
cbinfo->cb = alarminfo->cb;
|
||||
cbinfo->priv = alarminfo->priv;
|
||||
|
||||
/* And set the alarm */
|
||||
|
||||
ret = max326_rtc_setalarm(&ts, max326_alarm_callback, lower);
|
||||
if (ret < 0)
|
||||
{
|
||||
cbinfo->cb = NULL;
|
||||
cbinfo->priv = NULL;
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_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 max326_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *priv;
|
||||
FAR struct max326_cbinfo_s *cbinfo;
|
||||
|
||||
DEBUGASSERT(lower != NULL);
|
||||
DEBUGASSERT(alarmid == 0);
|
||||
priv = (FAR struct max326_lowerhalf_s *)lower;
|
||||
|
||||
/* Nullify callback information to reduce window for race conditions */
|
||||
|
||||
cbinfo = &priv->cbinfo[0];
|
||||
cbinfo->cb = NULL;
|
||||
cbinfo->priv = NULL;
|
||||
|
||||
/* Then cancel the alarm */
|
||||
|
||||
return max326_rtc_cancelalarm();
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rdalarm
|
||||
*
|
||||
* Description:
|
||||
* Query the RTC alarm.
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - A reference to RTC lower half driver state structure
|
||||
* alarminfo - Provided information needed to query 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 max326_rdalarm(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR struct lower_rdalarm_s *alarminfo)
|
||||
{
|
||||
struct alm_rdalarm_s lowerinfo;
|
||||
int ret = -EINVAL;
|
||||
|
||||
DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->time != NULL);
|
||||
DEBUGASSERT(alarminfo->id < RTC_NALARMS);
|
||||
|
||||
if (alarminfo->id < RTC_NALARMS)
|
||||
{
|
||||
/* 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();
|
||||
lowerinfo.ar_time = alarminfo->time;
|
||||
ret = max326_rtc_rdalarm(&lowerinfo);
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_periodic_callback
|
||||
*
|
||||
* Description:
|
||||
* This is the function that is called from the RTC driver when the periodic
|
||||
* wakeup goes off. It just invokes the upper half drivers callback.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
static int max326_periodic_callback(void)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *lower;
|
||||
struct lower_setperiodic_s *cbinfo;
|
||||
rtc_wakeup_callback_t cb;
|
||||
FAR void *priv;
|
||||
|
||||
lower = (FAR struct max326_lowerhalf_s *)&g_rtc_lowerhalf;
|
||||
|
||||
cbinfo = &lower->periodic;
|
||||
cb = (rtc_wakeup_callback_t)cbinfo->cb;
|
||||
priv = (FAR void *)cbinfo->priv;
|
||||
|
||||
/* Perform the callback */
|
||||
|
||||
if (cb != NULL)
|
||||
{
|
||||
cb(priv, 0);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_RTC_PERIODIC */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_setperiodic
|
||||
*
|
||||
* Description:
|
||||
* Set a new periodic wakeup relative to the current time, with a given
|
||||
* period. This function implements the setperiodic() 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 wakeup activity
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned
|
||||
* on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
static int max326_setperiodic(FAR struct rtc_lowerhalf_s *lower,
|
||||
FAR const struct lower_setperiodic_s *alarminfo)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *priv;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower != NULL && alarminfo != NULL);
|
||||
priv = (FAR struct max326_lowerhalf_s *)lower;
|
||||
|
||||
ret = nxsem_wait(&priv->devsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s));
|
||||
|
||||
ret = max326_rtc_setperiodic(&alarminfo->period, max326_periodic_callback);
|
||||
|
||||
nxsem_post(&priv->devsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_cancelperiodic
|
||||
*
|
||||
* Description:
|
||||
* Cancel the current periodic wakeup activity. This function implements
|
||||
* the cancelperiodic() method of the RTC driver interface
|
||||
*
|
||||
* Input Parameters:
|
||||
* lower - A reference to RTC lower half driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned
|
||||
* on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_PERIODIC
|
||||
static int max326_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id)
|
||||
{
|
||||
FAR struct max326_lowerhalf_s *priv;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower != NULL);
|
||||
priv = (FAR struct max326_lowerhalf_s *)lower;
|
||||
|
||||
DEBUGASSERT(id == 0);
|
||||
|
||||
ret = nxsem_wait(&priv->devsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max326_rtc_cancelperiodic();
|
||||
|
||||
nxsem_post(&priv->devsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_lowerhalf
|
||||
*
|
||||
* Description:
|
||||
* Instantiate the RTC lower half driver for the MAX326XX. General usage:
|
||||
*
|
||||
* #include <nuttx/timers/rtc.h>
|
||||
* #include "max326_rtc.h"
|
||||
*
|
||||
* struct rtc_lowerhalf_s *lower;
|
||||
* lower = max326_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 *max326_rtc_lowerhalf(void)
|
||||
{
|
||||
nxsem_init(&g_rtc_lowerhalf.devsem, 0, 1);
|
||||
|
||||
return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RTC_DRIVER */
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
|
||||
/* Register Bit-field Definitions ***************************************************/
|
||||
|
||||
/* Seconds Counter Register (32-bit seconds count) */
|
||||
/* Seconds Counter Register (32-bit seconds counter) */
|
||||
/* Sub-Seconds Counter Register */
|
||||
|
||||
#define RTC_SSEC_MASK (0xff) /* Bits 0-7: Sub-second counter */
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ static int max326_dmach_interrupt(int irq, FAR void *context, FAR void *arg)
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_dmainitialize
|
||||
* Name: up_dma_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the DMA subsystem
|
||||
|
|
|
|||
637
arch/arm/src/max326xx/max32660/max32660_rtc.c
Normal file
637
arch/arm/src/max326xx/max32660/max32660_rtc.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/max326xx/max32660_rtc.c
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <fixedmath.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/timers/rtc.h>
|
||||
|
||||
#include "up_arch.h"
|
||||
|
||||
#include "hardware/max326_rtc.h"
|
||||
#include "max326_rtc.h"
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* In hi-res mode, the RTC operates at 256Hz. In the lo-res mode, the RTC
|
||||
* operates at 1Hz.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
# ifndef CONFIG_RTC_FREQUENCY
|
||||
# error "CONFIG_RTC_FREQUENCY is required for CONFIG_RTC_HIRES"
|
||||
# elif CONFIG_RTC_FREQUENCY != 256
|
||||
# error "Only hi-res CONFIG_RTC_FREQUENCY of 256Hz is supported"
|
||||
# endif
|
||||
#else
|
||||
# ifndef CONFIG_RTC_FREQUENCY
|
||||
# define CONFIG_RTC_FREQUENCY 1
|
||||
# endif
|
||||
# if CONFIG_RTC_FREQUENCY != 1
|
||||
# error "Only lo-res CONFIG_RTC_FREQUENCY of 1Hz is supported"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
/* Callback to use when the alarm expires */
|
||||
|
||||
static alm_callback_t g_alarmcb;
|
||||
static FAR void *g_alarmarg;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Indicates that the RTC has be initialized */
|
||||
|
||||
volatile bool g_rtc_enabled = false;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_waitbusy
|
||||
*
|
||||
* Description:
|
||||
* Wait for registers to synchronize with the RTC module.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void max326_rtc_waitbusy(void)
|
||||
{
|
||||
while ((getreg32(MAX326_RTC_CTRL) & RTC_CTRL_BUSY) != 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_enable
|
||||
*
|
||||
* Description:
|
||||
* Enable/disable the RTC. RTC must be disabled in order to set the SEC
|
||||
* and SSEC registers.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void max326_rtc_enable(bool enable)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
regval = getreg32(MAX326_RTC_CTRL);
|
||||
if (enable)
|
||||
{
|
||||
regval |= RTC_CTRL_ENABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
regval &= ~RTC_CTRL_ENABLE;
|
||||
}
|
||||
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
max326_rtc_waitbusy();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_wrenable
|
||||
*
|
||||
* Description:
|
||||
* Enable/disable writing to the TRIM register or to the CTRL enable bit.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void max326_rtc_wrenable(bool enable)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
regval = getreg32(MAX326_RTC_CTRL);
|
||||
if (enable)
|
||||
{
|
||||
regval |= RTC_CTRL_WRITEEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
regval &= !RTC_CTRL_WRITEEN;
|
||||
}
|
||||
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_tm2b32
|
||||
*
|
||||
* Description:
|
||||
* Encode time in the standard struct timespec format to type b32_t.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - the time to use
|
||||
*
|
||||
* Returned Value:
|
||||
* Encoded time
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static b32_t max326_rtc_tm2b32(FAR const struct timespec *tp)
|
||||
{
|
||||
b32_t intpart;
|
||||
b32_t fracpart;
|
||||
|
||||
DEBUGASSERT(tp != NULL && tp->tv_nsec < NSEC_PER_SEC);
|
||||
|
||||
/* Convert the time to b32_t type:
|
||||
*
|
||||
* Integer part is easy:
|
||||
*
|
||||
* intpart: ssssssss ssssssss 00000000 00000000
|
||||
* 00000000 00000001 00000000 00000000 = 1 Sec
|
||||
*/
|
||||
|
||||
intpart = itob32(tp->tv_sec);
|
||||
|
||||
/* Fractional part:
|
||||
*
|
||||
* fracpart: 00000000 00000000 ffffffff ffffffff
|
||||
* 00000000 00000001 00000000 00000000 = 1 Sec
|
||||
*/
|
||||
|
||||
if (tp->tv_nsec > 0)
|
||||
{
|
||||
fracpart = itob32(tp->tv_nsec) / NSEC_PER_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
fracpart = 0;
|
||||
}
|
||||
|
||||
return intpart + fracpart;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_interrupt
|
||||
*
|
||||
* Description:
|
||||
* RTC alarm interrupt service routine
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - The IRQ number that generated the interrupt
|
||||
* context - Architecture specific register save information.
|
||||
* arg - Argument that my accompany the interrupt event
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; A negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
static int max326_rtc_interrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* Get the CTRL register */
|
||||
|
||||
regval = getreg32(MAX326_RTC_CTRL);
|
||||
DEBUGASSERT((regval & RTC_CTRL_ALARM_SSFL) != 0);
|
||||
|
||||
/* Clear pending interrupt flags. Disable alarms */
|
||||
|
||||
regval &= ~(RTC_CTRL_ALARM_TODEN | RTC_CTRL_ALARM_SSEN |
|
||||
RTC_CTRL_ALARM_TODFL | RTC_CTRL_ALARM_SSFL);
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
|
||||
/* Disable further RTC interrupts */
|
||||
|
||||
up_disable_irq(MAX326_IRQ_RTC);
|
||||
|
||||
DEBUGASSERT(g_alarmcb != NULL);
|
||||
if (g_alarmcb != NULL)
|
||||
{
|
||||
/* Perform the alarm callback */
|
||||
|
||||
g_alarmcb(g_alarmarg, 0);
|
||||
g_alarmcb = NULL;
|
||||
g_alarmarg = NULL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_rtc_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the hardware RTC per the selected configuration. This
|
||||
* function is called once during the OS initialization sequence
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_rtc_initialize(void)
|
||||
{
|
||||
/* Configure initial the RTC CTRL register
|
||||
*
|
||||
* - RTC disabled
|
||||
* - All interrupts disabled.
|
||||
* - No Square Wave output.
|
||||
* - Oscillator operates in noise immunity mode
|
||||
* - Write disabled.
|
||||
*/
|
||||
|
||||
putreg32(0, MAX326_RTC_CTRL);
|
||||
max326_rtc_waitbusy();
|
||||
|
||||
/* Enable write access */
|
||||
|
||||
max326_rtc_wrenable(false);
|
||||
|
||||
/* No RTC Square Wave Output */
|
||||
|
||||
putreg32(0, MAX326_RTC_OSCCTRL);
|
||||
max326_rtc_waitbusy();
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
/* Attach the ALARM interrupt handler */
|
||||
|
||||
up_disable_irq(MAX326_IRQ_RTC);
|
||||
(void)irq_attach(MAX326_IRQ_RTC, max326_rtc_interrupt, NULL);
|
||||
#endif
|
||||
|
||||
/* Enable the RTC */
|
||||
|
||||
max326_rtc_enable(true);
|
||||
|
||||
/* Disable write access */
|
||||
|
||||
max326_rtc_wrenable(false);
|
||||
|
||||
g_rtc_enabled = true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_rtc_time
|
||||
*
|
||||
* Description:
|
||||
* Get the current time in seconds. This is similar to the
|
||||
* standard time() function. It is only used by the RTOS during
|
||||
* [re-]initialization to set up the system time when CONFIG_RTC is set
|
||||
* but neither CONFIG_RTC_HIRES nor CONFIG_RTC_DATETIME are set.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* The current time in seconds
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_RTC_HIRES
|
||||
time_t up_rtc_time(void)
|
||||
{
|
||||
uint32_t sec;
|
||||
uint32_t ssec;
|
||||
uint32_t verify;
|
||||
|
||||
/* Read the time handling rollover to full seconds */
|
||||
|
||||
do
|
||||
{
|
||||
sec = getreg32(MAX326_RTC_SEC);
|
||||
ssec = getreg32(MAX326_RTC_SSEC) &RTC_SSEC_MASK;
|
||||
verify = getreg32(MAX326_RTC_SEC);
|
||||
}
|
||||
while (verify != sec);
|
||||
|
||||
/* Round */
|
||||
|
||||
if (ssec > 128)
|
||||
{
|
||||
sec++;
|
||||
}
|
||||
|
||||
return sec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_rtc_gettime
|
||||
*
|
||||
* Description:
|
||||
* Get the current time from the high resolution RTC clock/counter. This
|
||||
* interface is only supported by the high-resolution RTC/counter hardware
|
||||
* implementation. It is used to replace the system timer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - The location to return the high resolution time value.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_HIRES
|
||||
int up_rtc_gettime(FAR struct timespec *tp)
|
||||
{
|
||||
uint64_t tmp;
|
||||
uint32_t sec;
|
||||
uint32_t ssec;
|
||||
uint32_t verify;
|
||||
|
||||
/* Read the time handling rollover to full seconds */
|
||||
|
||||
do
|
||||
{
|
||||
sec = getreg32(MAX326_RTC_SEC);
|
||||
ssec = getreg32(MAX326_RTC_SSEC) & RTC_SSEC_MASK;
|
||||
verify = getreg32(MAX326_RTC_SEC);
|
||||
}
|
||||
while (verify != sec);
|
||||
|
||||
/* Format as a tm */
|
||||
|
||||
tmp = ((uint64_t)ssec * NSEC_PER_SEC) / 256;
|
||||
|
||||
tp->tv_sec = sec;
|
||||
tp->tv_nsec = (long)tmp;
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_rtc_settime
|
||||
*
|
||||
* Description:
|
||||
* Set the RTC to the provided time. All RTC implementations must be able to
|
||||
* set their time based on a standard tm.
|
||||
*
|
||||
* Input Parameters:
|
||||
* tp - the time to use
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int up_rtc_settime(FAR const struct timespec *tp)
|
||||
{
|
||||
irqstate_t flags;
|
||||
b32_t ftime;
|
||||
uint32_t sec;
|
||||
uint32_t ssec;
|
||||
uint32_t verify;
|
||||
|
||||
/* Get the time as a fixed precision number. */
|
||||
|
||||
ftime = max326_rtc_tm2b32(tp);
|
||||
sec = b32toi(ftime);
|
||||
ssec = (uint32_t)(b32frac(ftime) >> (32 - 8));
|
||||
|
||||
/* Enable write access to RTC configuration registers */
|
||||
|
||||
flags = spin_lock_irqsave();
|
||||
max326_rtc_wrenable(true);
|
||||
|
||||
/* We need to disable the RTC in order to write to the SEC and SSEC
|
||||
* registers.
|
||||
*/
|
||||
|
||||
max326_rtc_enable(false);
|
||||
|
||||
/* Then write the time values to the SEC and SSEC registers. */
|
||||
|
||||
do
|
||||
{
|
||||
putreg32(sec, MAX326_RTC_SEC);
|
||||
putreg32(ssec, MAX326_RTC_SSEC);
|
||||
verify = getreg32(MAX326_RTC_SEC);
|
||||
}
|
||||
while (verify != sec);
|
||||
|
||||
/* Re-enable the RTC and disable write access */
|
||||
|
||||
max326_rtc_enable(true);
|
||||
max326_rtc_wrenable(false);
|
||||
|
||||
spin_unlock_irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_setalarm
|
||||
*
|
||||
* Description:
|
||||
* Set an alarm to an absolute time using associated hardware.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ts - Alarm time
|
||||
* cb - Callback invoked when alarm expires
|
||||
* arg - Argument passed with the alarm
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
int max326_rtc_setalarm(FAR struct timespec *ts, alm_callback_t cb, FAR void *arg)
|
||||
{
|
||||
irqstate_t flags;
|
||||
b32_t ftime;
|
||||
uint32_t regval;
|
||||
uint32_t sec;
|
||||
uint32_t ssec;
|
||||
uint32_t verify;
|
||||
int ret = -EBUSY;
|
||||
|
||||
DEBUGASSERT(alminfo != NULL && alminfo->as_cb != NULL);
|
||||
|
||||
flags = spin_lock_irqsave();
|
||||
|
||||
/* Is there already something waiting on the ALARM? */
|
||||
|
||||
if (g_alarmcb == NULL)
|
||||
{
|
||||
/* No.. Save the callback function pointer */
|
||||
|
||||
g_alarmcb = cb;
|
||||
g_alarmarg = arg;
|
||||
|
||||
/* Get the time as a fixed precision number. */
|
||||
|
||||
ftime = max326_rtc_tm2b32(ts);
|
||||
sec = b32toi(ftime);
|
||||
ssec = (uint32_t)(b32frac(ftime) >> (32 - 8));
|
||||
|
||||
/* We need to disable ALARMs in order to write to the RAS and RSSA
|
||||
* registers.
|
||||
*/
|
||||
|
||||
flags = spin_lock_irqsave();
|
||||
|
||||
regval = getreg32(MAX326_RTC_CTRL);
|
||||
regval &= ~(RTC_CTRL_ALARM_TODEN | RTC_CTRL_ALARM_SSEN);
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
max326_rtc_waitbusy();
|
||||
|
||||
/* Then write the time values to the RAS and RSSA registers. */
|
||||
|
||||
do
|
||||
{
|
||||
putreg32(sec, MAX326_RTC_RAS);
|
||||
putreg32(ssec, MAX326_RTC_RSSA);
|
||||
verify = getreg32(MAX326_RTC_RAS);
|
||||
}
|
||||
while (verify != sec);
|
||||
|
||||
/* Enable sub-second alarm */
|
||||
|
||||
regval |= RTC_CTRL_ALARM_SSEN;
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
|
||||
/* Enable the RTC interrupt at the NVIC */
|
||||
|
||||
up_enable_irq(MAX326_IRQ_RTC);
|
||||
spin_unlock_irqrestore(flags);
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_cancelalarm
|
||||
*
|
||||
* Description:
|
||||
* Cancel a pending alarm alarm
|
||||
*
|
||||
* Input Parameters:
|
||||
* none
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
int max326_rtc_cancelalarm(void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
int ret = -ENODATA;
|
||||
|
||||
flags = spin_lock_irqsave();
|
||||
|
||||
if (g_alarmcb != NULL)
|
||||
{
|
||||
/* Disable the alarm interrupt */
|
||||
|
||||
up_disable_irq(MAX326_IRQ_RTC);
|
||||
|
||||
/* Disable the alarm */
|
||||
|
||||
regval = getreg32(MAX326_RTC_CTRL);
|
||||
regval &= ~(RTC_CTRL_ALARM_TODEN | RTC_CTRL_ALARM_SSEN);
|
||||
putreg32(regval, MAX326_RTC_CTRL);
|
||||
max326_rtc_waitbusy();
|
||||
|
||||
/* Cancel the global callback function */
|
||||
|
||||
g_alarmcb = NULL;
|
||||
g_alarmarg = NULL;
|
||||
|
||||
/* Unset the alarm (for debug) */
|
||||
|
||||
putreg32(0, MAX326_RTC_RAS);
|
||||
putreg32(0, MAX326_RTC_RSSA);
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(flags);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
168
arch/arm/src/max326xx/max326_rtc.h
Normal file
168
arch/arm/src/max326xx/max326_rtc.h
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/max326xx/max326_rtc.h
|
||||
*
|
||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org> (On-going support and development)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_MAX326XX_MAX326_RTC_H
|
||||
#define __ARCH_ARM_SRC_MAX326XX_MAX326_RTC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* Type of callback invoked when an ALARM interrupt occurs */
|
||||
|
||||
typedef CODE void (*alm_callback_t)(FAR void *arg, unsigned int alarmid);
|
||||
|
||||
/* Structure used to pass parameters to query an alarm */
|
||||
|
||||
struct alm_rdalarm_s
|
||||
{
|
||||
FAR struct rtc_time *ar_time; /* Argument for storing ALARM RTC time */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_setalarm
|
||||
*
|
||||
* Description:
|
||||
* Set an alarm to an absolute time using associated hardware.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ts - Alarm time
|
||||
* cb - Callback invoked when alarm expires
|
||||
* arg - Argument passed with the alarm
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
int max326_rtc_setalarm(FAR struct timespec *ts, alm_callback_t cb,
|
||||
FAR void *arg);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_rdalarm
|
||||
*
|
||||
* Description:
|
||||
* Query an alarm configured in hardware.
|
||||
*
|
||||
* Input Parameters:
|
||||
* alminfo - Information about the alarm configuration.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
int max326_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_cancelalarm
|
||||
*
|
||||
* Description:
|
||||
* Cancel a pending alarm alarm
|
||||
*
|
||||
* Input Parameters:
|
||||
* none
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RTC_ALARM
|
||||
int max326_rtc_cancelalarm(void);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: max326_rtc_lowerhalf
|
||||
*
|
||||
* Description:
|
||||
* Instantiate the RTC lower half driver for the MAX326XX. General usage:
|
||||
*
|
||||
* #include <nuttx/timers/rtc.h>
|
||||
* #include "max326_rtc.h"
|
||||
*
|
||||
* struct rtc_lowerhalf_s *lower;
|
||||
* lower = max326_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
|
||||
struct rtc_lowerhalf_s;
|
||||
FAR struct rtc_lowerhalf_s *max326_rtc_lowerhalf(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_MAX326XX_MAX326_RTC_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue