1 /*
2 * Copyright (c) 2018-2019 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #define DT_DRV_COMPAT nxp_imx_epit
7
8 #include <zephyr/drivers/counter.h>
9 #include <zephyr/device.h>
10 #include <zephyr/irq.h>
11 #include "clock_freq.h"
12 #include "epit.h"
13
14 #define COUNTER_MAX_RELOAD 0xFFFFFFFF
15
16 struct imx_epit_config {
17 struct counter_config_info info;
18 EPIT_Type *base;
19 uint16_t prescaler;
20 };
21
22 struct imx_epit_data {
23 volatile counter_top_callback_t callback;
24 volatile void *user_data;
25 };
26
get_epit_config(const struct device * dev)27 static inline const struct imx_epit_config *get_epit_config(const struct device *dev)
28 {
29 return CONTAINER_OF(dev->config, struct imx_epit_config,
30 info);
31 }
32
imx_epit_isr(const struct device * dev)33 static void imx_epit_isr(const struct device *dev)
34 {
35 EPIT_Type *base = get_epit_config(dev)->base;
36 struct imx_epit_data *driver_data = dev->data;
37
38 EPIT_ClearStatusFlag(base);
39
40 if (driver_data->callback != NULL) {
41 driver_data->callback(dev, (void *)driver_data->user_data);
42 }
43 }
44
imx_epit_init(const struct device * dev)45 static void imx_epit_init(const struct device *dev)
46 {
47 struct imx_epit_config *config = (struct imx_epit_config *)
48 get_epit_config(dev);
49 EPIT_Type *base = config->base;
50 epit_init_config_t epit_config = {
51 .freeRun = true,
52 .waitEnable = true,
53 .stopEnable = true,
54 .dbgEnable = true,
55 .enableMode = true
56 };
57
58 /* Adjust frequency in the counter configuration info */
59 config->info.freq = get_epit_clock_freq(base)/(config->prescaler + 1U);
60
61 EPIT_Init(base, &epit_config);
62 }
63
imx_epit_start(const struct device * dev)64 static int imx_epit_start(const struct device *dev)
65 {
66 EPIT_Type *base = get_epit_config(dev)->base;
67
68 /* Set EPIT clock source */
69 EPIT_SetClockSource(base, epitClockSourcePeriph);
70
71 /* Set prescaler */
72 EPIT_SetPrescaler(base, get_epit_config(dev)->prescaler);
73
74 /* Start the counter */
75 EPIT_Enable(base);
76
77 return 0;
78 }
79
imx_epit_stop(const struct device * dev)80 static int imx_epit_stop(const struct device *dev)
81 {
82 EPIT_Type *base = get_epit_config(dev)->base;
83
84 /* Disable EPIT */
85 EPIT_Disable(base);
86
87 return 0;
88 }
89
imx_epit_get_value(const struct device * dev,uint32_t * ticks)90 static int imx_epit_get_value(const struct device *dev, uint32_t *ticks)
91 {
92 EPIT_Type *base = get_epit_config(dev)->base;
93
94 *ticks = EPIT_GetCounterLoadValue(base) - EPIT_ReadCounter(base);
95
96 return 0;
97 }
98
imx_epit_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)99 static int imx_epit_set_top_value(const struct device *dev,
100 const struct counter_top_cfg *cfg)
101 {
102 EPIT_Type *base = get_epit_config(dev)->base;
103 struct imx_epit_data *driver_data = dev->data;
104
105 /* Disable EPIT Output Compare interrupt for consistency */
106 EPIT_SetIntCmd(base, false);
107
108 driver_data->callback = cfg->callback;
109 driver_data->user_data = cfg->user_data;
110
111 /* Set reload value and optionally counter to "ticks" */
112 EPIT_SetOverwriteCounter(base,
113 !(cfg->flags & COUNTER_TOP_CFG_DONT_RESET));
114 EPIT_SetCounterLoadValue(base, cfg->ticks);
115
116 if (cfg->callback != NULL) {
117 /* (Re)enable EPIT Output Compare interrupt */
118 EPIT_SetIntCmd(base, true);
119 }
120
121 return 0;
122 }
123
imx_epit_get_pending_int(const struct device * dev)124 static uint32_t imx_epit_get_pending_int(const struct device *dev)
125 {
126 EPIT_Type *base = get_epit_config(dev)->base;
127
128 return EPIT_GetStatusFlag(base) ? 1U : 0U;
129 }
130
imx_epit_get_top_value(const struct device * dev)131 static uint32_t imx_epit_get_top_value(const struct device *dev)
132 {
133 EPIT_Type *base = get_epit_config(dev)->base;
134
135 return EPIT_GetCounterLoadValue(base);
136 }
137
138 static const struct counter_driver_api imx_epit_driver_api = {
139 .start = imx_epit_start,
140 .stop = imx_epit_stop,
141 .get_value = imx_epit_get_value,
142 .set_top_value = imx_epit_set_top_value,
143 .get_pending_int = imx_epit_get_pending_int,
144 .get_top_value = imx_epit_get_top_value,
145 };
146
147 #define COUNTER_IMX_EPIT_DEVICE(idx) \
148 static int imx_epit_config_func_##idx(const struct device *dev); \
149 static const struct imx_epit_config imx_epit_##idx##z_config = { \
150 .info = { \
151 .max_top_value = COUNTER_MAX_RELOAD, \
152 .freq = 1U, \
153 .flags = 0, \
154 .channels = 0U, \
155 }, \
156 .base = (EPIT_Type *)DT_INST_REG_ADDR(idx), \
157 .prescaler = DT_INST_PROP(idx, prescaler), \
158 }; \
159 static struct imx_epit_data imx_epit_##idx##_data; \
160 DEVICE_DT_INST_DEFINE(idx, \
161 &imx_epit_config_func_##idx, \
162 NULL, \
163 &imx_epit_##idx##_data, &imx_epit_##idx##z_config.info, \
164 PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, \
165 &imx_epit_driver_api); \
166 static int imx_epit_config_func_##idx(const struct device *dev) \
167 { \
168 imx_epit_init(dev); \
169 IRQ_CONNECT(DT_INST_IRQN(idx), \
170 DT_INST_IRQ(idx, priority), \
171 imx_epit_isr, DEVICE_DT_INST_GET(idx), 0); \
172 irq_enable(DT_INST_IRQN(idx)); \
173 return 0; \
174 }
175
176 DT_INST_FOREACH_STATUS_OKAY(COUNTER_IMX_EPIT_DEVICE)
177