OpenModem/bertos/cpu/cortex-m3/drv/rtc_stm32.c

153 lines
4.0 KiB
C

/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2011 Develer S.r.l. (http://www.develer.com/)
*
* -->
*
* \brief STM32 RTC driver.
*
* \author Andrea Righi <arighi@develer.com>
*/
#include "clock_stm32.h"
#include <cfg/compiler.h>
#include <cfg/module.h>
#include <cfg/debug.h>
#include <io/stm32.h>
#include <io/stm32_pwr.h>
#include <cpu/power.h> // cpu_relax()
#include <drv/rtc.h>
/* PWR registers base */
static struct PWR *PWR = (struct PWR *)PWR_BASE;
/* RTC clock source: LSE */
#define RTC_CLKSRC 0x00000100
/* RTC clock: 32768 Hz */
#define RTC_CLOCK 32768
/* RTC clock period (in ms) */
#define RTC_PERIOD 1000
/* RTC control register */
#define RTC_CRH (*(reg16_t *)(RTC_BASE + 0x00))
#define RTC_CRL (*(reg16_t *)(RTC_BASE + 0x04))
#define RTC_CRL_SECIE BV(0)
#define RTC_CRL_ALRIE BV(1)
#define RTC_CRL_OWIE BV(2)
#define RTC_CRL_SECF BV(0)
#define RTC_CRL_ALRF BV(1)
#define RTC_CRL_OWF BV(2)
#define RTC_CRL_RSF BV(3)
#define RTC_CRL_CNF BV(4)
#define RTC_CRL_RTOFF BV(5)
/* RTC prescaler load register */
#define RTC_PRLH (*(reg16_t *)(RTC_BASE + 0x08))
#define RTC_PRLL (*(reg16_t *)(RTC_BASE + 0x0c))
/* RTC prescaler divider register */
#define RTC_DIVH (*(reg16_t *)(RTC_BASE + 0x10))
#define RTC_DIVL (*(reg16_t *)(RTC_BASE + 0x14))
/* RTC counter register */
#define RTC_CNTH (*(reg16_t *)(RTC_BASE + 0x18))
#define RTC_CNTL (*(reg16_t *)(RTC_BASE + 0x1c))
/* RTC alarm register */
#define RTC_ALRH (*(reg16_t *)(RTC_BASE + 0x20))
#define RTC_ALRL (*(reg16_t *)(RTC_BASE + 0x24))
static void rtc_enterConfig(void)
{
/* Enter configuration mode */
RTC_CRL |= RTC_CRL_CNF;
}
static void rtc_exitConfig(void)
{
/* Exit from configuration mode */
RTC_CRL &= ~RTC_CRL_CNF;
while (!(RTC_CRL & RTC_CRL_RTOFF))
cpu_relax();
}
uint32_t rtc_time(void)
{
return (RTC_CNTH << 16) | RTC_CNTL;
}
void rtc_setTime(uint32_t val)
{
rtc_enterConfig();
RTC_CNTH = (val >> 16) & 0xffff;
RTC_CNTL = val & 0xffff;
rtc_exitConfig();
}
/* Initialize the RTC clock */
int rtc_init(void)
{
#if CONFIG_KERN
MOD_CHECK(proc);
#endif
/* Enable clock for Power interface */
RCC->APB1ENR |= RCC_APB1_PWR;
/* Enable access to RTC registers */
PWR->CR |= PWR_CR_DBP;
/* Enable LSE */
RCC->BDCR |= RCC_BDCR_LSEON;
/* Wait for LSE ready */
while (!(RCC->BDCR & RCC_BDCR_LSERDY))
cpu_relax();
/* Set clock source and enable RTC peripheral */
RCC->BDCR |= RTC_CLKSRC | RCC_BDCR_RTCEN;
rtc_enterConfig();
/* Set prescaler */
RTC_PRLH = ((RTC_PERIOD * RTC_CLOCK / 1000 - 1) >> 16) & 0xff;
RTC_PRLL = ((RTC_PERIOD * RTC_CLOCK / 1000 - 1)) & 0xffff;
rtc_exitConfig();
/* Disable access to the RTC registers */
PWR->CR &= ~PWR_CR_DBP;
return 0;
}