rtc: Make the API ready for multiple RTC instances

A platform might provide multiple RTC, either internally or externally.
Applying the changes to the DesignWare driver relevantly as well as
to the sample code.

Change-Id: Ia70e791a6c45e186cbc4dc900a268fa882331af5
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2015-12-02 19:06:24 +01:00 committed by Anas Nashif
commit 466cb00d3f
5 changed files with 69 additions and 43 deletions

View file

@ -26,8 +26,6 @@
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83) #define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
#define CCU_RTC_CLK_DIV_EN (2) #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) static void rtc_dw_set_div(const enum clk_rtc_div div)
{ {
/* set default division mask */ /* set default division mask */
@ -43,8 +41,10 @@ static void rtc_dw_set_div(const enum clk_rtc_div div)
* @brief Function to enable clock gating for the RTC * @brief Function to enable clock gating for the RTC
* @return N/A * @return N/A
*/ */
static void rtc_dw_enable(void) static void rtc_dw_enable(struct device *dev)
{ {
ARG_UNUSED(dev);
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11); sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11);
sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 1); sys_set_bit(CLOCK_PERIPHERAL_BASE_ADDR, 1);
} }
@ -53,8 +53,10 @@ static void rtc_dw_enable(void)
* @brief Function to disable clock gating for the RTC * @brief Function to disable clock gating for the RTC
* @return N/A * @return N/A
*/ */
static void rtc_dw_disable(void) static void rtc_dw_disable(struct device *dev)
{ {
ARG_UNUSED(dev);
sys_clear_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11); sys_clear_bit(CLOCK_PERIPHERAL_BASE_ADDR, 11);
} }
@ -65,30 +67,35 @@ static void rtc_dw_disable(void)
* *
* @return N/A * @return N/A
*/ */
void rtc_dw_isr(void) void rtc_dw_isr(void *arg)
{ {
/* Disable RTC interrupt */ struct device *dev = arg;
sys_clear_bit(RTC_BASE_ADDR + RTC_CCR, 0); struct rtc_dw_dev_config *rtc_dev = dev->config->config_info;
struct rtc_dw_runtime *context = dev->driver_data;
if (rtc_dw_cb_fn) { /* Disable RTC interrupt */
(*rtc_dw_cb_fn)(); sys_clear_bit(rtc_dev->base_address + RTC_CCR, 0);
if (context->rtc_dw_cb_fn) {
context->rtc_dw_cb_fn(dev);
} }
/* clear interrupt */ /* clear interrupt */
sys_read32(RTC_BASE_ADDR + RTC_EOI); sys_read32(rtc_dev->base_address + RTC_EOI);
} }
IRQ_CONNECT_STATIC(rtc, INT_RTC_IRQ, CONFIG_RTC_IRQ_PRI, rtc_dw_isr, 0, 0);
/** /**
* @brief Sets an RTC alarm * @brief Sets an RTC alarm
* @param alarm_val Alarm value * @param alarm_val Alarm value
* @return 0 on success * @return 0 on success
*/ */
static int rtc_dw_set_alarm(const uint32_t alarm_val) static int rtc_dw_set_alarm(struct device *dev, const uint32_t alarm_val)
{ {
sys_set_bit(RTC_BASE_ADDR + RTC_CCR, 0); struct rtc_dw_dev_config *rtc_dev = dev->config->config_info;
sys_write32(alarm_val, RTC_BASE_ADDR + RTC_CMR); sys_set_bit(rtc_dev->base_address + RTC_CCR, 0);
sys_write32(alarm_val, rtc_dev->base_address + RTC_CMR);
return DEV_OK; return DEV_OK;
} }
@ -98,22 +105,25 @@ static int rtc_dw_set_alarm(const uint32_t alarm_val)
* @param config pointer to a RTC configuration structure * @param config pointer to a RTC configuration structure
* @return 0 on success * @return 0 on success
*/ */
static int rtc_dw_set_config(struct rtc_config *config) static int rtc_dw_set_config(struct device *dev, struct rtc_config *config)
{ {
struct rtc_dw_dev_config *rtc_dev = dev->config->config_info;
struct rtc_dw_runtime *context = dev->driver_data;
/* Set RTC divider - 32768 / 32.768 khz = 1 second. */ /* Set RTC divider - 32768 / 32.768 khz = 1 second. */
rtc_dw_set_div(RTC_DIVIDER); rtc_dw_set_div(RTC_DIVIDER);
/* set initial RTC value */ /* set initial RTC value */
sys_write32(config->init_val, RTC_BASE_ADDR + RTC_CLR); sys_write32(config->init_val, rtc_dev->base_address + RTC_CLR);
/* clear any pending interrupts */ /* clear any pending interrupts */
sys_read32(RTC_BASE_ADDR + RTC_EOI); sys_read32(rtc_dev->base_address + RTC_EOI);
rtc_dw_cb_fn = config->cb_fn; context->rtc_dw_cb_fn = config->cb_fn;
if (config->alarm_enable) { if (config->alarm_enable) {
rtc_dw_set_alarm(config->alarm_val); rtc_dw_set_alarm(dev, config->alarm_val);
} else { } else {
sys_clear_bit(RTC_BASE_ADDR + RTC_CCR, 0); sys_clear_bit(rtc_dev->base_address + RTC_CCR, 0);
} }
return DEV_OK; return DEV_OK;
@ -123,9 +133,11 @@ static int rtc_dw_set_config(struct rtc_config *config)
* @brief Read current RTC value * @brief Read current RTC value
* @return current rtc value * @return current rtc value
*/ */
static uint32_t rtc_dw_read(void) static uint32_t rtc_dw_read(struct device *dev)
{ {
return sys_read32(RTC_BASE_ADDR + RTC_CCVR); struct rtc_dw_dev_config *rtc_dev = dev->config->config_info;
return sys_read32(rtc_dev->base_address + RTC_CCVR);
} }
static struct rtc_driver_api funcs = { static struct rtc_driver_api funcs = {
@ -136,6 +148,9 @@ static struct rtc_driver_api funcs = {
.set_alarm = rtc_dw_set_alarm, .set_alarm = rtc_dw_set_alarm,
}; };
/* IRQ_CONFIG needs the flags variable declared by IRQ_CONNECT_STATIC */
IRQ_CONNECT_STATIC(rtc, INT_RTC_IRQ, CONFIG_RTC_IRQ_PRI, rtc_dw_isr, 0, 0);
int rtc_dw_init(struct device *dev) int rtc_dw_init(struct device *dev)
{ {
IRQ_CONFIG(rtc, INT_RTC_IRQ); IRQ_CONFIG(rtc, INT_RTC_IRQ);
@ -145,12 +160,15 @@ int rtc_dw_init(struct device *dev)
return DEV_OK; return DEV_OK;
} }
struct rtc_dw_runtime rtc_runtime;
struct rtc_dw_dev_config rtc_dev = { struct rtc_dw_dev_config rtc_dev = {
.base_address = RTC_BASE_ADDR, .base_address = RTC_BASE_ADDR,
}; };
#ifdef CONFIG_RTC_DW
DECLARE_DEVICE_INIT_CONFIG(rtc, RTC_DRV_NAME, &rtc_dw_init, &rtc_dev); DECLARE_DEVICE_INIT_CONFIG(rtc, RTC_DRV_NAME, &rtc_dw_init, &rtc_dev);
SYS_DEFINE_DEVICE(rtc, NULL, SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); SYS_DEFINE_DEVICE(rtc, &rtc_runtime, SECONDARY,
#endif CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
struct device *rtc_dw_isr_dev = SYS_GET_DEVICE(rtc);

View file

@ -44,6 +44,10 @@
#define RTC_CLK_DIV_8192_HZ (0x2 << 3) #define RTC_CLK_DIV_8192_HZ (0x2 << 3)
#define RTC_CLK_DIV_4096_HZ (0x3 << 3) #define RTC_CLK_DIV_4096_HZ (0x3 << 3)
struct rtc_dw_runtime {
void (*rtc_dw_cb_fn)(struct device *dev);
};
struct rtc_dw_dev_config { struct rtc_dw_dev_config {
uint32_t base_address; uint32_t base_address;
}; };

View file

@ -22,7 +22,7 @@
#if defined(CONFIG_RTC_DW) #if defined(CONFIG_RTC_DW)
#if defined(CONFIG_IOAPIC) || defined(CONFIG_MVIC) #if defined(CONFIG_IOAPIC) || defined(CONFIG_MVIC)
ioapic_mkstub rtc rtc_dw_isr 0 ioapic_mkstub rtc rtc_dw_isr rtc_dw_isr_dev
#endif #endif
#endif #endif

View file

@ -64,15 +64,18 @@ struct rtc_config {
uint8_t alarm_enable; uint8_t alarm_enable;
/*!< initial configuration value for the 32bit RTC alarm value */ /*!< initial configuration value for the 32bit RTC alarm value */
uint32_t alarm_val; uint32_t alarm_val;
/*!< Pointer to function to call when alarm value matches current RTC value */ /*!< Pointer to function to call when alarm value
void (*cb_fn)(void); * matches current RTC value */
void (*cb_fn)(struct device *dev);
}; };
typedef void (*rtc_api_enable)(void); typedef void (*rtc_api_enable)(struct device *dev);
typedef void (*rtc_api_disable)(void); typedef void (*rtc_api_disable)(struct device *dev);
typedef int (*rtc_api_set_config)(struct rtc_config *config); typedef int (*rtc_api_set_config)(struct device *dev,
typedef int (*rtc_api_set_alarm)(const uint32_t alarm_val); struct rtc_config *config);
typedef uint32_t (*rtc_api_read)(void); typedef int (*rtc_api_set_alarm)(struct device *dev,
const uint32_t alarm_val);
typedef uint32_t (*rtc_api_read)(struct device *dev);
struct rtc_driver_api { struct rtc_driver_api {
rtc_api_enable enable; rtc_api_enable enable;
@ -87,7 +90,7 @@ static inline uint32_t rtc_read(struct device *dev)
struct rtc_driver_api *api; struct rtc_driver_api *api;
api = (struct rtc_driver_api *)dev->driver_api; api = (struct rtc_driver_api *)dev->driver_api;
return api->read(); return api->read(dev);
} }
static inline void rtc_enable(struct device *dev) static inline void rtc_enable(struct device *dev)
@ -95,7 +98,7 @@ static inline void rtc_enable(struct device *dev)
struct rtc_driver_api *api; struct rtc_driver_api *api;
api = (struct rtc_driver_api *)dev->driver_api; api = (struct rtc_driver_api *)dev->driver_api;
api->enable(); api->enable(dev);
} }
@ -104,23 +107,25 @@ static inline void rtc_disable(struct device *dev)
struct rtc_driver_api *api; struct rtc_driver_api *api;
api = (struct rtc_driver_api *)dev->driver_api; api = (struct rtc_driver_api *)dev->driver_api;
api->disable(); api->disable(dev);
} }
static inline int rtc_set_config(struct device *dev, struct rtc_config *cfg) static inline int rtc_set_config(struct device *dev,
struct rtc_config *cfg)
{ {
struct rtc_driver_api *api; struct rtc_driver_api *api;
api = (struct rtc_driver_api *)dev->driver_api; api = (struct rtc_driver_api *)dev->driver_api;
return api->set_config(cfg); return api->set_config(dev, cfg);
} }
static inline int rtc_set_alarm(struct device *dev, const uint32_t alarm_val) static inline int rtc_set_alarm(struct device *dev,
const uint32_t alarm_val)
{ {
struct rtc_driver_api *api; struct rtc_driver_api *api;
api = (struct rtc_driver_api *)dev->driver_api; api = (struct rtc_driver_api *)dev->driver_api;
return api->set_alarm(alarm_val); return api->set_alarm(dev, alarm_val);
} }
#endif #endif

View file

@ -23,9 +23,8 @@
#define ALARM (RTC_ALARM_MINUTE / 6) #define ALARM (RTC_ALARM_MINUTE / 6)
#define RTC_DRIVER "rtc" #define RTC_DRIVER "rtc"
struct device *rtc_dev;
void test_rtc_interrupt_fn(void) void test_rtc_interrupt_fn(struct device *rtc_dev)
{ {
uint32_t now = rtc_read(rtc_dev); uint32_t now = rtc_read(rtc_dev);
@ -36,7 +35,7 @@ void test_rtc_interrupt_fn(void)
void main(void) void main(void)
{ {
struct rtc_config config; struct rtc_config config;
struct device *rtc_dev;
printk("Test RTC driver\n"); printk("Test RTC driver\n");
rtc_dev = device_get_binding(RTC_DRIVER); rtc_dev = device_get_binding(RTC_DRIVER);