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