/* * Copyright (c) 2018-2019 NXP * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nxp_imx_epit #include #include #include "clock_freq.h" #include "epit.h" #define COUNTER_MAX_RELOAD 0xFFFFFFFF struct imx_epit_config { struct counter_config_info info; EPIT_Type *base; uint16_t prescaler; }; struct imx_epit_data { volatile counter_top_callback_t callback; volatile void *user_data; }; static inline const struct imx_epit_config *get_epit_config(struct device *dev) { return CONTAINER_OF(dev->config_info, struct imx_epit_config, info); } static void imx_epit_isr(void *arg) { struct device *dev = (struct device *)arg; EPIT_Type *base = get_epit_config(dev)->base; struct imx_epit_data *driver_data = dev->driver_data; EPIT_ClearStatusFlag(base); if (driver_data->callback != NULL) { driver_data->callback(dev, (void *)driver_data->user_data); } } static void imx_epit_init(struct device *dev) { struct imx_epit_config *config = (struct imx_epit_config *) get_epit_config(dev); EPIT_Type *base = config->base; epit_init_config_t epit_config = { .freeRun = true, .waitEnable = true, .stopEnable = true, .dbgEnable = true, .enableMode = true }; /* Adjust frequency in the counter configuration info */ config->info.freq = get_epit_clock_freq(base)/(config->prescaler + 1U); EPIT_Init(base, &epit_config); } static int imx_epit_start(struct device *dev) { EPIT_Type *base = get_epit_config(dev)->base; /* Set EPIT clock source */ EPIT_SetClockSource(base, epitClockSourcePeriph); /* Set prescaler */ EPIT_SetPrescaler(base, get_epit_config(dev)->prescaler); /* Start the counter */ EPIT_Enable(base); return 0; } static int imx_epit_stop(struct device *dev) { EPIT_Type *base = get_epit_config(dev)->base; /* Disable EPIT */ EPIT_Disable(base); return 0; } static int imx_epit_get_value(struct device *dev, uint32_t *ticks) { EPIT_Type *base = get_epit_config(dev)->base; *ticks = EPIT_GetCounterLoadValue(base) - EPIT_ReadCounter(base); return 0; } static int imx_epit_set_top_value(struct device *dev, const struct counter_top_cfg *cfg) { EPIT_Type *base = get_epit_config(dev)->base; struct imx_epit_data *driver_data = dev->driver_data; /* Disable EPIT Output Compare interrupt for consistency */ EPIT_SetIntCmd(base, false); driver_data->callback = cfg->callback; driver_data->user_data = cfg->user_data; /* Set reload value and optionally counter to "ticks" */ EPIT_SetOverwriteCounter(base, !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)); EPIT_SetCounterLoadValue(base, cfg->ticks); if (cfg->callback != NULL) { /* (Re)enable EPIT Output Compare interrupt */ EPIT_SetIntCmd(base, true); } return 0; } static uint32_t imx_epit_get_pending_int(struct device *dev) { EPIT_Type *base = get_epit_config(dev)->base; return EPIT_GetStatusFlag(base) ? 1U : 0U; } static uint32_t imx_epit_get_top_value(struct device *dev) { EPIT_Type *base = get_epit_config(dev)->base; return EPIT_GetCounterLoadValue(base); } static uint32_t imx_epit_get_max_relative_alarm(struct device *dev) { return COUNTER_MAX_RELOAD; } static const struct counter_driver_api imx_epit_driver_api = { .start = imx_epit_start, .stop = imx_epit_stop, .get_value = imx_epit_get_value, .set_top_value = imx_epit_set_top_value, .get_pending_int = imx_epit_get_pending_int, .get_top_value = imx_epit_get_top_value, .get_max_relative_alarm = imx_epit_get_max_relative_alarm, }; #define COUNTER_IMX_EPIT_DEVICE(idx) \ static int imx_epit_config_func_##idx(struct device *dev); \ static const struct imx_epit_config imx_epit_##idx##z_config = { \ .info = { \ .max_top_value = COUNTER_MAX_RELOAD, \ .freq = 1U, \ .flags = 0, \ .channels = 0U, \ }, \ .base = (EPIT_Type *)DT_INST_REG_ADDR(idx), \ .prescaler = DT_INST_PROP(idx, prescaler), \ }; \ static struct imx_epit_data imx_epit_##idx##_data; \ DEVICE_AND_API_INIT(epit_##idx, DT_INST_LABEL(idx), \ &imx_epit_config_func_##idx, \ &imx_epit_##idx##_data, &imx_epit_##idx##z_config.info, \ PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &imx_epit_driver_api); \ static int imx_epit_config_func_##idx(struct device *dev) \ { \ imx_epit_init(dev); \ IRQ_CONNECT(DT_INST_IRQN(idx), \ DT_INST_IRQ(idx, priority), \ imx_epit_isr, DEVICE_GET(epit_##idx), 0); \ irq_enable(DT_INST_IRQN(idx)); \ return 0; \ } DT_INST_FOREACH_STATUS_OKAY(COUNTER_IMX_EPIT_DEVICE)