rtc: add DesignWare RTC driver
Adding DW real time clock support. This driver is used by the Quark SE and Quark D2000 SoCs. Change-Id: Iba8ddee1b1b5fee298db95b63418e152774662a4 Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
d3d64ca4cf
commit
9d6deb4e8c
8 changed files with 392 additions and 0 deletions
|
@ -53,4 +53,6 @@ source "drivers/pinmux/Kconfig"
|
||||||
|
|
||||||
source "drivers/adc/Kconfig"
|
source "drivers/adc/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/rtc/Kconfig"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -18,3 +18,4 @@ obj-$(CONFIG_I2C) += i2c/
|
||||||
obj-$(CONFIG_PWM) += pwm/
|
obj-$(CONFIG_PWM) += pwm/
|
||||||
obj-$(CONFIG_ADC) += adc/
|
obj-$(CONFIG_ADC) += adc/
|
||||||
obj-$(CONFIG_ETHERNET) += ethernet/
|
obj-$(CONFIG_ETHERNET) += ethernet/
|
||||||
|
obj-$(CONFIG_RTC) += rtc/
|
||||||
|
|
20
drivers/rtc/Kconfig
Normal file
20
drivers/rtc/Kconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
menuconfig RTC
|
||||||
|
bool "Real-Time Clock"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable options for Real-Time Clock drivers.
|
||||||
|
|
||||||
|
if RTC
|
||||||
|
|
||||||
|
config RTC_DW
|
||||||
|
bool "Build Designware RTC Driver"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Designware RTC driver.
|
||||||
|
|
||||||
|
config RTC_IRQ_PRI
|
||||||
|
int "RTC Interrupt Priority"
|
||||||
|
default 2
|
||||||
|
help
|
||||||
|
RTC Interrupt Priority.
|
||||||
|
endif # RTC
|
2
drivers/rtc/Makefile
Normal file
2
drivers/rtc/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
obj-$(CONFIG_RTC) += rtc_static_irq_stubs.o
|
||||||
|
obj-$(CONFIG_RTC_DW) += rtc_dw.o
|
156
drivers/rtc/rtc_dw.c
Normal file
156
drivers/rtc/rtc_dw.c
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <nanokernel.h>
|
||||||
|
#include <sys_io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <rtc.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
#include "rtc_dw.h"
|
||||||
|
|
||||||
|
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
|
||||||
|
#define CCU_RTC_CLK_DIV_EN (2)
|
||||||
|
|
||||||
|
static void (*rtc_dw_cb_fn)(void);
|
||||||
|
|
||||||
|
static void rtc_dw_set_div(const enum clk_rtc_div div)
|
||||||
|
{
|
||||||
|
/* set default division mask */
|
||||||
|
uint32_t reg =
|
||||||
|
sys_read32(CLOCK_SYSTEM_CLOCK_CONTROL) & CLK_RTC_DIV_DEF_MASK;
|
||||||
|
reg |= (div << CCU_RTC_CLK_DIV_OFFSET);
|
||||||
|
sys_write32(reg, CLOCK_SYSTEM_CLOCK_CONTROL);
|
||||||
|
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||||
|
sys_set_bit(CLOCK_SYSTEM_CLOCK_CONTROL, CCU_RTC_CLK_DIV_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to enable clock gating for the RTC
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void rtc_dw_enable(void)
|
||||||
|
{
|
||||||
|
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11);
|
||||||
|
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to disable clock gating for the RTC
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
static void rtc_dw_disable(void)
|
||||||
|
{
|
||||||
|
sys_clear_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief RTC alarm ISR
|
||||||
|
*
|
||||||
|
* calls a user defined callback
|
||||||
|
*
|
||||||
|
* @return N/A
|
||||||
|
*/
|
||||||
|
void rtc_dw_isr(void)
|
||||||
|
{
|
||||||
|
/* Disable RTC interrupt */
|
||||||
|
sys_clear_bit(RTC_BASE_ADDR + RTC_CCR, 0);
|
||||||
|
|
||||||
|
if (rtc_dw_cb_fn) {
|
||||||
|
(*rtc_dw_cb_fn)();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear interrupt */
|
||||||
|
sys_read32(RTC_BASE_ADDR + RTC_EOI);
|
||||||
|
}
|
||||||
|
IRQ_CONNECT_STATIC(rtc, INT_RTC_IRQ, CONFIG_RTC_IRQ_PRI, rtc_dw_isr, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets an RTC alarm
|
||||||
|
* @param alarm_val Alarm value
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
static int rtc_dw_set_alarm(const uint32_t alarm_val)
|
||||||
|
{
|
||||||
|
sys_set_bit(RTC_BASE_ADDR + RTC_CCR, 0);
|
||||||
|
|
||||||
|
sys_write32(alarm_val, RTC_BASE_ADDR + RTC_CMR);
|
||||||
|
|
||||||
|
return DEV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to configure the RTC
|
||||||
|
* @param config pointer to a RTC configuration structure
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
static int rtc_dw_set_config(struct rtc_config *config)
|
||||||
|
{
|
||||||
|
/* Set RTC divider - 32768 / 32.768 khz = 1 second. */
|
||||||
|
rtc_dw_set_div(RTC_DIVIDER);
|
||||||
|
|
||||||
|
/* set initial RTC value */
|
||||||
|
sys_write32(config->init_val, RTC_BASE_ADDR + RTC_CLR);
|
||||||
|
|
||||||
|
/* clear any pending interrupts */
|
||||||
|
sys_read32(RTC_BASE_ADDR + RTC_EOI);
|
||||||
|
|
||||||
|
rtc_dw_cb_fn = config->cb_fn;
|
||||||
|
if (config->alarm_enable) {
|
||||||
|
rtc_dw_set_alarm(config->alarm_val);
|
||||||
|
} else {
|
||||||
|
sys_clear_bit(RTC_BASE_ADDR + RTC_CCR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read current RTC value
|
||||||
|
* @return current rtc value
|
||||||
|
*/
|
||||||
|
static uint32_t rtc_dw_read(void)
|
||||||
|
{
|
||||||
|
return sys_read32(RTC_BASE_ADDR + RTC_CCVR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rtc_driver_api funcs = {
|
||||||
|
.set_config = rtc_dw_set_config,
|
||||||
|
.read = rtc_dw_read,
|
||||||
|
.enable = rtc_dw_enable,
|
||||||
|
.disable = rtc_dw_disable,
|
||||||
|
.set_alarm = rtc_dw_set_alarm,
|
||||||
|
};
|
||||||
|
|
||||||
|
int rtc_dw_init(struct device *dev)
|
||||||
|
{
|
||||||
|
IRQ_CONFIG(rtc, INT_RTC_IRQ, 0);
|
||||||
|
irq_enable(INT_RTC_IRQ);
|
||||||
|
SCSS_INTERRUPT->int_rtc_mask = INT_UNMASK_IA;
|
||||||
|
dev->driver_api = &funcs;
|
||||||
|
return DEV_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rtc_dw_dev_config rtc_dev = {
|
||||||
|
.base_address = RTC_BASE_ADDR,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RTC_DW
|
||||||
|
DECLARE_DEVICE_INIT_CONFIG(rtc, RTC_DRV_NAME, &rtc_dw_init, &rtc_dev);
|
||||||
|
|
||||||
|
nano_early_init(rtc, NULL);
|
||||||
|
#endif
|
53
drivers/rtc/rtc_dw.h
Normal file
53
drivers/rtc/rtc_dw.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTC_DW_H_
|
||||||
|
#define _RTC_DW_H_
|
||||||
|
|
||||||
|
#include <board.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <rtc.h>
|
||||||
|
|
||||||
|
#define RTC_DRV_NAME "rtc"
|
||||||
|
|
||||||
|
#define RTC_CCVR (0x0)
|
||||||
|
#define RTC_CMR (0x4)
|
||||||
|
#define RTC_CLR (0x8)
|
||||||
|
#define RTC_CCR (0xC)
|
||||||
|
#define RTC_STAT (0x10)
|
||||||
|
#define RTC_RSTAT (0x14)
|
||||||
|
#define RTC_EOI (0x18)
|
||||||
|
#define RTC_COMP_VERSION (0x1C)
|
||||||
|
|
||||||
|
#define RTC_INTERRUPT_ENABLE (1 << 0)
|
||||||
|
#define RTC_INTERRUPT_MASK (1 << 1)
|
||||||
|
#define RTC_ENABLE (1 << 2)
|
||||||
|
#define RTC_WRAP_ENABLE (1 << 3)
|
||||||
|
|
||||||
|
#define RTC_CLK_DIV_EN (1 << 2)
|
||||||
|
#define RTC_CLK_DIV_MASK (0xF << 3)
|
||||||
|
#define RTC_CLK_DIV_1_HZ (0xF << 3)
|
||||||
|
#define RTC_CLK_DIV_32768_HZ (0x0 << 3)
|
||||||
|
#define RTC_CLK_DIV_8192_HZ (0x2 << 3)
|
||||||
|
#define RTC_CLK_DIV_4096_HZ (0x3 << 3)
|
||||||
|
|
||||||
|
struct rtc_dw_dev_config {
|
||||||
|
uint32_t base_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rtc_dw_init(struct device *dev);
|
||||||
|
|
||||||
|
#endif /* _RTC_DW_H_ */
|
32
drivers/rtc/rtc_static_irq_stubs.S
Normal file
32
drivers/rtc/rtc_static_irq_stubs.S
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Intel Corportation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define _ASMLANGUAGE
|
||||||
|
|
||||||
|
#include <arch/x86/asm.h>
|
||||||
|
#include <drivers/ioapic.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_RTC_DW)
|
||||||
|
#if defined(CONFIG_IOAPIC)
|
||||||
|
ioapic_mkstub rtc rtc_dw_isr 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* externs (internal APIs) */
|
||||||
|
|
||||||
|
GTEXT(_IntEnt)
|
||||||
|
GTEXT(_IntExit)
|
126
include/rtc.h
Normal file
126
include/rtc.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTC_H_
|
||||||
|
#define _RTC_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <misc/util.h>
|
||||||
|
|
||||||
|
enum clk_rtc_div {
|
||||||
|
CLK_RTC_DIV_1,
|
||||||
|
CLK_RTC_DIV_2,
|
||||||
|
CLK_RTC_DIV_4,
|
||||||
|
CLK_RTC_DIV_8,
|
||||||
|
CLK_RTC_DIV_16,
|
||||||
|
CLK_RTC_DIV_32,
|
||||||
|
CLK_RTC_DIV_64,
|
||||||
|
CLK_RTC_DIV_128,
|
||||||
|
CLK_RTC_DIV_256,
|
||||||
|
CLK_RTC_DIV_512,
|
||||||
|
CLK_RTC_DIV_1024,
|
||||||
|
CLK_RTC_DIV_2048,
|
||||||
|
CLK_RTC_DIV_4096,
|
||||||
|
CLK_RTC_DIV_8192,
|
||||||
|
CLK_RTC_DIV_16384,
|
||||||
|
CLK_RTC_DIV_32768
|
||||||
|
};
|
||||||
|
#ifndef BIT
|
||||||
|
#define BIT(n) (1UL << (n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RTC_DIVIDER CLK_RTC_DIV_1
|
||||||
|
|
||||||
|
/** Number of RTC ticks in a second */
|
||||||
|
#define RTC_ALARM_SECOND (32768 / BIT(RTC_DIVIDER))
|
||||||
|
|
||||||
|
/** Number of RTC ticks in a minute */
|
||||||
|
#define RTC_ALARM_MINUTE (RTC_ALARM_SECOND * 60)
|
||||||
|
|
||||||
|
/** Number of RTC ticks in an hour */
|
||||||
|
#define RTC_ALARM_HOUR (RTC_ALARM_MINUTE * 60)
|
||||||
|
|
||||||
|
/** Number of RTC ticks in a day */
|
||||||
|
#define RTC_ALARM_DAY (RTC_ALARM_HOUR * 24)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct rtc_config {
|
||||||
|
uint32_t init_val;
|
||||||
|
/*!< enable/disable alarm */
|
||||||
|
uint8_t alarm_enable;
|
||||||
|
/*!< initial configuration value for the 32bit RTC alarm value */
|
||||||
|
uint32_t alarm_val;
|
||||||
|
/*!< Pointer to function to call when alarm value matches current RTC value */
|
||||||
|
void (*cb_fn)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*rtc_api_enable)(void);
|
||||||
|
typedef void (*rtc_api_disable)(void);
|
||||||
|
typedef int (*rtc_api_set_config)(struct rtc_config *config);
|
||||||
|
typedef int (*rtc_api_set_alarm)(const uint32_t alarm_val);
|
||||||
|
typedef uint32_t (*rtc_api_read)(void);
|
||||||
|
|
||||||
|
struct rtc_driver_api {
|
||||||
|
rtc_api_enable enable;
|
||||||
|
rtc_api_disable disable;
|
||||||
|
rtc_api_read read;
|
||||||
|
rtc_api_set_config set_config;
|
||||||
|
rtc_api_set_alarm set_alarm;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint32_t rtc_read(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rtc_driver_api *api;
|
||||||
|
|
||||||
|
api = (struct rtc_driver_api *)dev->driver_api;
|
||||||
|
return api->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rtc_enable(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rtc_driver_api *api;
|
||||||
|
|
||||||
|
api = (struct rtc_driver_api *)dev->driver_api;
|
||||||
|
api->enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void rtc_disable(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rtc_driver_api *api;
|
||||||
|
|
||||||
|
api = (struct rtc_driver_api *)dev->driver_api;
|
||||||
|
api->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int rtc_set_config(struct device *dev, struct rtc_config *cfg)
|
||||||
|
{
|
||||||
|
struct rtc_driver_api *api;
|
||||||
|
|
||||||
|
api = (struct rtc_driver_api *)dev->driver_api;
|
||||||
|
return api->set_config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int rtc_set_alarm(struct device *dev, const uint32_t alarm_val)
|
||||||
|
{
|
||||||
|
struct rtc_driver_api *api;
|
||||||
|
|
||||||
|
api = (struct rtc_driver_api *)dev->driver_api;
|
||||||
|
return api->set_alarm(alarm_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue