|  | /* | 
|  | * 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,			       \ | 
|  | device_pm_control_nop,				       \ | 
|  | &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) |