zephyr/drivers/counter/counter_imx_epit.c

176 lines
4.5 KiB
C

/*
* Copyright (c) 2018-2019 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_imx_epit
#include <drivers/counter.h>
#include <device.h>
#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(const struct device *dev)
{
return CONTAINER_OF(dev->config, struct imx_epit_config,
info);
}
static void imx_epit_isr(const struct device *dev)
{
EPIT_Type *base = get_epit_config(dev)->base;
struct imx_epit_data *driver_data = dev->data;
EPIT_ClearStatusFlag(base);
if (driver_data->callback != NULL) {
driver_data->callback(dev, (void *)driver_data->user_data);
}
}
static void imx_epit_init(const 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(const 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(const struct device *dev)
{
EPIT_Type *base = get_epit_config(dev)->base;
/* Disable EPIT */
EPIT_Disable(base);
return 0;
}
static int imx_epit_get_value(const 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(const struct device *dev,
const struct counter_top_cfg *cfg)
{
EPIT_Type *base = get_epit_config(dev)->base;
struct imx_epit_data *driver_data = dev->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(const 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(const struct device *dev)
{
EPIT_Type *base = get_epit_config(dev)->base;
return EPIT_GetCounterLoadValue(base);
}
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,
};
#define COUNTER_IMX_EPIT_DEVICE(idx) \
static int imx_epit_config_func_##idx(const 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_DT_INST_DEFINE(idx, \
&imx_epit_config_func_##idx, \
NULL, \
&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(const struct device *dev) \
{ \
imx_epit_init(dev); \
IRQ_CONNECT(DT_INST_IRQN(idx), \
DT_INST_IRQ(idx, priority), \
imx_epit_isr, DEVICE_DT_INST_GET(idx), 0); \
irq_enable(DT_INST_IRQN(idx)); \
return 0; \
}
DT_INST_FOREACH_STATUS_OKAY(COUNTER_IMX_EPIT_DEVICE)