diff options
author | Vincenzo Frascino <vincenzo.frascino@linaro.org> | 2016-12-12 17:05:49 +0000 |
---|---|---|
committer | Kumar Gala <kumar.gala@linaro.org> | 2017-01-23 15:15:54 -0600 |
commit | b11242d11f4057ee8aca2ab8d39c18edbecb2c6d (patch) | |
tree | c4c1327f8e8bf5f223ab5e9f53b9f3c92c614c9b /drivers | |
parent | d36543828b9f6e178fd5aad8c6b3d465b78e255f (diff) |
counter: cmsdk: Add Timer 0 and 1 as Timers
This patch adds Timer 0 and 1 to be used as timers.
Jira: ZEP-1300
Change-Id: I57112a8ed6f5daa22345e8807e9ebe87bb09e782
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/counter/Kconfig.tmr_cmsdk_apb | 62 | ||||
-rw-r--r-- | drivers/counter/Makefile | 1 | ||||
-rw-r--r-- | drivers/counter/timer_tmr_cmsdk_apb.c | 241 |
3 files changed, 303 insertions, 1 deletions
diff --git a/drivers/counter/Kconfig.tmr_cmsdk_apb b/drivers/counter/Kconfig.tmr_cmsdk_apb index e3ed8c34d..fa88f7c7b 100644 --- a/drivers/counter/Kconfig.tmr_cmsdk_apb +++ b/drivers/counter/Kconfig.tmr_cmsdk_apb @@ -1,4 +1,4 @@ -# Kconfig - counter configuration options +# Kconfig - counter and timer configuration options # # # Copyright (c) 2016 Linaro Limited @@ -8,6 +8,64 @@ if SOC_FAMILY_ARM +config TIMER_TMR_CMSDK_APB + bool + prompt "ARM CMSDK (Cortex-M System Design Kit) Timer driver" + default n + help + The timers (TMR) present in the platform are used as timers. + This option enables the support for the timers. + +if TIMER_TMR_CMSDK_APB + +# ---------- Timer 0 ---------- + +config TIMER_TMR_CMSDK_APB_0 + bool + prompt "Timer 0 driver" + default n + help + Enable support for Timer 0. + +config TIMER_TMR_CMSDK_APB_0_DEV_NAME + string "Timer 0 Device Name" + depends on TIMER_TMR_CMSDK_APB_0 + default "TIMER_0" + help + Specify the device name for Timer 0 driver. + +config TIMER_TMR_CMSDK_APB_0_IRQ_PRI + int "Interrupt Priority for Timer 0" + depends on TIMER_TMR_CMSDK_APB_0 + default 3 + help + Interrupt priority for Timer 0. + +# ---------- Timer 1 ---------- + +config TIMER_TMR_CMSDK_APB_1 + bool + prompt "Timer 1 driver" + default n + help + Enable support for Timer 1. + +config TIMER_TMR_CMSDK_APB_1_DEV_NAME + string "Timer 1 Device Name" + depends on TIMER_TMR_CMSDK_APB_1 + default "TIMER_1" + help + Specify the device name for Timer 1 driver. + +config TIMER_TMR_CMSDK_APB_1_IRQ_PRI + int "Interrupt Priority for Timer 1" + depends on TIMER_TMR_CMSDK_APB_1 + default 3 + help + Interrupt priority for Timer 1. + +endif # TIMER_TMR_CMSDK_APB + config COUNTER_TMR_CMSDK_APB bool prompt "ARM CMSDK (Cortex-M System Design Kit) Counter driver" @@ -23,6 +81,7 @@ if COUNTER_TMR_CMSDK_APB config COUNTER_TMR_CMSDK_APB_0 bool prompt "Counter 0 driver" + depends on !TIMER_TMR_CMSDK_APB_0 default n help Enable support for Counter 0. @@ -39,6 +98,7 @@ config COUNTER_TMR_CMSDK_APB_0_DEV_NAME config COUNTER_TMR_CMSDK_APB_1 bool prompt "Counter 1 driver" + depends on !TIMER_TMR_CMSDK_APB_1 default n help Enable support for Counter 1. diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index ede6afe5a..2a94e5e44 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_AON_COUNTER_QMSI) += counter_qmsi_aon.o obj-$(CONFIG_AON_TIMER_QMSI) += counter_qmsi_aonpt.o obj-$(CONFIG_COUNTER_TMR_CMSDK_APB) += counter_tmr_cmsdk_apb.o +obj-$(CONFIG_TIMER_TMR_CMSDK_APB) += timer_tmr_cmsdk_apb.o diff --git a/drivers/counter/timer_tmr_cmsdk_apb.c b/drivers/counter/timer_tmr_cmsdk_apb.c new file mode 100644 index 000000000..dc41bed36 --- /dev/null +++ b/drivers/counter/timer_tmr_cmsdk_apb.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <counter.h> +#include <device.h> +#include <errno.h> +#include <init.h> +#include <soc.h> +#include <clock_control/arm_clock_control.h> + +#include "timer_cmsdk_apb.h" + +typedef void (*timer_config_func_t)(struct device *dev); + +static counter_callback_t user_cb; + +#define TIMER_MAX_RELOAD 0xFFFFFFFF + +enum timer_status_t { + TIMER_DISABLED = 0, + TIMER_ENABLED, +}; + +struct timer_tmr_cmsdk_apb_cfg { + volatile struct timer_cmsdk_apb *timer; + timer_config_func_t timer_config_func; + /* Timer Clock control in Active State */ + const struct arm_clock_control_t timer_cc_as; + /* Timer Clock control in Sleep State */ + const struct arm_clock_control_t timer_cc_ss; + /* Timer Clock control in Deep Sleep State */ + const struct arm_clock_control_t timer_cc_dss; +}; + +struct timer_tmr_cmsdk_apb_dev_data { + uint32_t load; + enum timer_status_t status; +}; + +static int timer_tmr_cmsdk_apb_start(struct device *dev) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + struct timer_tmr_cmsdk_apb_dev_data *data = dev->driver_data; + + /* Set the timer to Max reload */ + cfg->timer->reload = TIMER_MAX_RELOAD; + + /* Enable the timer */ + cfg->timer->ctrl = TIMER_CTRL_EN; + + /* Update the status */ + data->status = TIMER_ENABLED; + + return 0; +} + +static int timer_tmr_cmsdk_apb_stop(struct device *dev) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + struct timer_tmr_cmsdk_apb_dev_data *data = dev->driver_data; + + /* Disable the timer */ + cfg->timer->ctrl = 0x0; + + /* Update the status */ + data->status = TIMER_DISABLED; + + return 0; +} + +static uint32_t timer_tmr_cmsdk_apb_read(struct device *dev) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + struct timer_tmr_cmsdk_apb_dev_data *data = dev->driver_data; + + /* Return Counter Value */ + uint32_t value = 0; + + value = data->load - cfg->timer->value; + + return value; +} + +static int timer_tmr_cmsdk_apb_set_alarm(struct device *dev, + counter_callback_t callback, + uint32_t count, void *user_data) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + struct timer_tmr_cmsdk_apb_dev_data *data = dev->driver_data; + + if (data->status == TIMER_DISABLED) { + return -ENOTSUP; + } + + /* Set callback */ + user_cb = callback; + + /* Store the reload value */ + data->load = count; + + /* Set value register to count */ + cfg->timer->value = count; + + /* Set the timer reload to count */ + cfg->timer->reload = count; + + /* Enable IRQ */ + cfg->timer->ctrl |= TIMER_CTRL_IRQ_EN; + + return 0; +} + +static uint32_t timer_tmr_cmsdk_apb_get_pending_int(struct device *dev) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + + return cfg->timer->intstatus; +} + +static const struct counter_driver_api timer_tmr_cmsdk_apb_api = { + .start = timer_tmr_cmsdk_apb_start, + .stop = timer_tmr_cmsdk_apb_stop, + .read = timer_tmr_cmsdk_apb_read, + .set_alarm = timer_tmr_cmsdk_apb_set_alarm, + .get_pending_int = timer_tmr_cmsdk_apb_get_pending_int, +}; + +static void timer_tmr_cmsdk_apb_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + + cfg->timer->intclear = TIMER_CTRL_INT_CLEAR; + if (user_cb) { + /* user_data paramenter is not used by this driver */ + (*user_cb)(dev, NULL); + } +} + +static int timer_tmr_cmsdk_apb_init(struct device *dev) +{ + const struct timer_tmr_cmsdk_apb_cfg * const cfg = + dev->config->config_info; + +#ifdef CONFIG_CLOCK_CONTROL + /* Enable clock for subsystem */ + struct device *clk = + device_get_binding(CONFIG_ARM_CLOCK_CONTROL_DEV_NAME); + +#ifdef CONFIG_SOC_SERIES_BEETLE + clock_control_on(clk, (clock_control_subsys_t *) &cfg->timer_cc_as); + clock_control_on(clk, (clock_control_subsys_t *) &cfg->timer_cc_ss); + clock_control_on(clk, (clock_control_subsys_t *) &cfg->timer_cc_dss); +#endif /* CONFIG_SOC_SERIES_BEETLE */ +#endif /* CONFIG_CLOCK_CONTROL */ + + cfg->timer_config_func(dev); + + return 0; +} + +/* TIMER 0 */ +#ifdef CONFIG_TIMER_TMR_CMSDK_APB_0 +static void timer_cmsdk_apb_config_0(struct device *dev); + +static const struct timer_tmr_cmsdk_apb_cfg timer_tmr_cmsdk_apb_cfg_0 = { + .timer = ((volatile struct timer_cmsdk_apb *)CMSDK_APB_TIMER0), + .timer_config_func = timer_cmsdk_apb_config_0, + .timer_cc_as = {.bus = CMSDK_APB, .state = SOC_ACTIVE, + .device = CMSDK_APB_TIMER0,}, + .timer_cc_ss = {.bus = CMSDK_APB, .state = SOC_SLEEP, + .device = CMSDK_APB_TIMER0,}, + .timer_cc_dss = {.bus = CMSDK_APB, .state = SOC_DEEPSLEEP, + .device = CMSDK_APB_TIMER0,}, +}; + +static struct timer_tmr_cmsdk_apb_dev_data timer_tmr_cmsdk_apb_dev_data_0 = { + .load = TIMER_MAX_RELOAD, + .status = TIMER_DISABLED, +}; + +DEVICE_AND_API_INIT(timer_tmr_cmsdk_apb_0, + CONFIG_TIMER_TMR_CMSDK_APB_0_DEV_NAME, + timer_tmr_cmsdk_apb_init, &timer_tmr_cmsdk_apb_dev_data_0, + &timer_tmr_cmsdk_apb_cfg_0, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &timer_tmr_cmsdk_apb_api); + +static void timer_cmsdk_apb_config_0(struct device *dev) +{ + IRQ_CONNECT(CMSDK_APB_TIMER_0_IRQ, CONFIG_TIMER_TMR_CMSDK_APB_0_IRQ_PRI, + timer_tmr_cmsdk_apb_isr, + DEVICE_GET(timer_tmr_cmsdk_apb_0), 0); + irq_enable(CMSDK_APB_TIMER_0_IRQ); +} +#endif /* CONFIG_TIMER_TMR_CMSDK_APB_0 */ + +/* TIMER 1 */ +#ifdef CONFIG_TIMER_TMR_CMSDK_APB_1 +static void timer_cmsdk_apb_config_1(struct device *dev); + +static const struct timer_tmr_cmsdk_apb_cfg timer_tmr_cmsdk_apb_cfg_1 = { + .timer = ((volatile struct timer_cmsdk_apb *)CMSDK_APB_TIMER1), + .timer_config_func = timer_cmsdk_apb_config_1, + .timer_cc_as = {.bus = CMSDK_APB, .state = SOC_ACTIVE, + .device = CMSDK_APB_TIMER1,}, + .timer_cc_ss = {.bus = CMSDK_APB, .state = SOC_SLEEP, + .device = CMSDK_APB_TIMER1,}, + .timer_cc_dss = {.bus = CMSDK_APB, .state = SOC_DEEPSLEEP, + .device = CMSDK_APB_TIMER1,}, +}; + +static struct timer_tmr_cmsdk_apb_dev_data timer_tmr_cmsdk_apb_dev_data_1 = { + .load = TIMER_MAX_RELOAD, + .status = TIMER_DISABLED, +}; + +DEVICE_AND_API_INIT(timer_tmr_cmsdk_apb_1, + CONFIG_TIMER_TMR_CMSDK_APB_1_DEV_NAME, + timer_tmr_cmsdk_apb_init, &timer_tmr_cmsdk_apb_dev_data_1, + &timer_tmr_cmsdk_apb_cfg_1, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &timer_tmr_cmsdk_apb_api); + +static void timer_cmsdk_apb_config_1(struct device *dev) +{ + IRQ_CONNECT(CMSDK_APB_TIMER_1_IRQ, CONFIG_TIMER_TMR_CMSDK_APB_1_IRQ_PRI, + timer_tmr_cmsdk_apb_isr, + DEVICE_GET(timer_tmr_cmsdk_apb_0), 0); + irq_enable(CMSDK_APB_TIMER_1_IRQ); +} +#endif /* CONFIG_TIMER_TMR_CMSDK_APB_1 */ |