1 /*
2  * Copyright (c) 2024, STRIM, ALC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_flexio
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/misc/nxp_flexio/nxp_flexio.h>
14 #include <fsl_flexio.h>
15 
16 LOG_MODULE_REGISTER(mcux_flexio, CONFIG_MCUX_FLEXIO_LOG_LEVEL);
17 
18 
19 struct mcux_flexio_config {
20 	FLEXIO_Type *base;
21 	const struct device *clock_dev;
22 	clock_control_subsys_t clock_subsys;
23 	void (*irq_config_func)(const struct device *dev);
24 	void (*irq_enable_func)(void);
25 	void (*irq_disable_func)(void);
26 };
27 
28 typedef const struct nxp_flexio_child *nxp_flexio_map_child_t;
29 
30 struct mcux_flexio_data {
31 	struct k_mutex lock;
32 	uint32_t shifter_indexes_used;
33 	uint32_t timer_indexes_used;
34 	nxp_flexio_map_child_t *map_shifter_child;
35 	nxp_flexio_map_child_t *map_timer_child;
36 	uint32_t map_shifter_child_count;
37 	uint32_t map_timer_child_count;
38 };
39 
40 
mcux_flexio_child_take_shifter_idx(const struct device * dev)41 static int mcux_flexio_child_take_shifter_idx(const struct device *dev)
42 {
43 	struct mcux_flexio_data *data = dev->data;
44 
45 	for (uint32_t i = 0; i < data->map_shifter_child_count; i++) {
46 		if ((data->shifter_indexes_used & BIT(i)) == 0) {
47 			WRITE_BIT(data->shifter_indexes_used, i, 1);
48 			return i;
49 		}
50 	}
51 
52 	return -ENOBUFS;
53 }
54 
mcux_flexio_child_take_timer_idx(const struct device * dev)55 static int mcux_flexio_child_take_timer_idx(const struct device *dev)
56 {
57 	struct mcux_flexio_data *data = dev->data;
58 
59 	for (uint32_t i = 0; i < data->map_timer_child_count; i++) {
60 		if ((data->timer_indexes_used & BIT(i)) == 0) {
61 			WRITE_BIT(data->timer_indexes_used, i, 1);
62 			return i;
63 		}
64 	}
65 
66 	return -ENOBUFS;
67 }
68 
mcux_flexio_isr(const struct device * dev)69 static void mcux_flexio_isr(const struct device *dev)
70 {
71 	const struct mcux_flexio_config *config = dev->config;
72 	struct mcux_flexio_data *data = dev->data;
73 	FLEXIO_Type *base = config->base;
74 
75 	nxp_flexio_map_child_t *map_shifter_child = data->map_shifter_child;
76 	uint32_t map_shifter_child_count = data->map_shifter_child_count;
77 	uint32_t shifter_status_flag = FLEXIO_GetShifterStatusFlags(base);
78 	uint32_t shifter_error_flag = FLEXIO_GetShifterErrorFlags(base);
79 
80 	if (shifter_status_flag || shifter_error_flag) {
81 		for (uint32_t idx = 0; idx < map_shifter_child_count; idx++) {
82 			if (((shifter_status_flag | shifter_error_flag) & BIT(idx)) != 0) {
83 				const struct nxp_flexio_child *child = map_shifter_child[idx];
84 
85 				if (child != NULL) {
86 					nxp_flexio_child_isr_t isr = child->isr;
87 
88 					if (isr != NULL) {
89 						isr(child->user_data);
90 					}
91 				}
92 			}
93 		}
94 	}
95 
96 	nxp_flexio_map_child_t *map_timer_child = data->map_timer_child;
97 	uint32_t map_timer_child_count = data->map_timer_child_count;
98 	uint32_t timer_status_flag = FLEXIO_GetTimerStatusFlags(base);
99 
100 	if (timer_status_flag) {
101 		for (uint32_t idx = 0; idx < map_timer_child_count; idx++) {
102 			if ((timer_status_flag & BIT(idx)) != 0) {
103 				const struct nxp_flexio_child *child = map_timer_child[idx];
104 
105 				if (child != NULL) {
106 					nxp_flexio_child_isr_t isr = child->isr;
107 
108 					if (isr != NULL) {
109 						isr(child->user_data);
110 					}
111 				}
112 			}
113 		}
114 	}
115 
116 	SDK_ISR_EXIT_BARRIER;
117 }
118 
mcux_flexio_init(const struct device * dev)119 static int mcux_flexio_init(const struct device *dev)
120 {
121 	const struct mcux_flexio_config *config = dev->config;
122 	struct mcux_flexio_data *data = dev->data;
123 	flexio_config_t flexio_config;
124 
125 	k_mutex_init(&data->lock);
126 
127 	FLEXIO_GetDefaultConfig(&flexio_config);
128 	FLEXIO_Init(config->base, &flexio_config);
129 	config->irq_config_func(dev);
130 
131 	return 0;
132 }
133 
nxp_flexio_irq_enable(const struct device * dev)134 void nxp_flexio_irq_enable(const struct device *dev)
135 {
136 	const struct mcux_flexio_config *config = dev->config;
137 
138 	config->irq_enable_func();
139 }
140 
nxp_flexio_irq_disable(const struct device * dev)141 void nxp_flexio_irq_disable(const struct device *dev)
142 {
143 	const struct mcux_flexio_config *config = dev->config;
144 
145 	config->irq_disable_func();
146 }
147 
nxp_flexio_lock(const struct device * dev)148 void nxp_flexio_lock(const struct device *dev)
149 {
150 	struct mcux_flexio_data *data = dev->data;
151 
152 	k_mutex_lock(&data->lock, K_FOREVER);
153 }
154 
nxp_flexio_unlock(const struct device * dev)155 void nxp_flexio_unlock(const struct device *dev)
156 {
157 	struct mcux_flexio_data *data = dev->data;
158 
159 	k_mutex_unlock(&data->lock);
160 }
161 
nxp_flexio_get_rate(const struct device * dev,uint32_t * rate)162 int nxp_flexio_get_rate(const struct device *dev, uint32_t *rate)
163 {
164 	const struct mcux_flexio_config *config = dev->config;
165 
166 	return clock_control_get_rate(config->clock_dev, config->clock_subsys, rate);
167 }
168 
nxp_flexio_child_attach(const struct device * dev,const struct nxp_flexio_child * child)169 int nxp_flexio_child_attach(const struct device *dev,
170 	const struct nxp_flexio_child *child)
171 {
172 	struct mcux_flexio_data *data = dev->data;
173 	const struct nxp_flexio_child_res *child_res = &child->res;
174 
175 	for (uint32_t i = 0; i < child_res->shifter_count; i++) {
176 		int shifter_idx = mcux_flexio_child_take_shifter_idx(dev);
177 
178 		if (shifter_idx < 0) {
179 			LOG_ERR("Failed to take shifter index: %d", shifter_idx);
180 			return shifter_idx;
181 		}
182 		child_res->shifter_index[i] = shifter_idx;
183 		data->map_shifter_child[shifter_idx] = child;
184 		LOG_DBG("child %p: shifter_idx[%d] is %d", child, i, shifter_idx);
185 	}
186 
187 	for (uint32_t i = 0; i < child_res->timer_count; i++) {
188 		int timer_idx = mcux_flexio_child_take_timer_idx(dev);
189 
190 		if (timer_idx < 0) {
191 			LOG_ERR("Failed to take timer index: %d", timer_idx);
192 			return timer_idx;
193 		}
194 		child_res->timer_index[i] = timer_idx;
195 		data->map_timer_child[timer_idx] = child;
196 		LOG_DBG("child %p: timer_idx[%d] is %d", child, i, timer_idx);
197 	}
198 
199 	return 0;
200 }
201 
202 #define MCUX_FLEXIO_SHIFTER_COUNT_MAX(n) \
203 	ARRAY_SIZE(((FLEXIO_Type *)DT_INST_REG_ADDR(n))->SHIFTCTL)
204 
205 #define MCUX_FLEXIO_TIMER_COUNT_MAX(n) \
206 	ARRAY_SIZE(((FLEXIO_Type *)DT_INST_REG_ADDR(n))->TIMCTL)
207 
208 #define MCUX_FLEXIO_INIT(n)						\
209 	static void mcux_flexio_irq_config_func_##n(const struct device *dev); \
210 	static void mcux_flexio_irq_enable_func_##n(void);		\
211 	static void mcux_flexio_irq_disable_func_##n(void);		\
212 									\
213 	static nxp_flexio_map_child_t					\
214 		nxp_flexio_map_shifter_child_##n[MCUX_FLEXIO_SHIFTER_COUNT_MAX(n)] = {0}; \
215 	static nxp_flexio_map_child_t					\
216 		nxp_flexio_map_timer_child_##n[MCUX_FLEXIO_TIMER_COUNT_MAX(n)] = {0}; \
217 									\
218 	static struct mcux_flexio_data mcux_flexio_data_##n = {		\
219 		.map_shifter_child = nxp_flexio_map_shifter_child_##n, \
220 		.map_shifter_child_count = ARRAY_SIZE(nxp_flexio_map_shifter_child_##n), \
221 		.map_timer_child = nxp_flexio_map_timer_child_##n, \
222 		.map_timer_child_count = ARRAY_SIZE(nxp_flexio_map_timer_child_##n), \
223 	};								\
224 									\
225 	static const struct mcux_flexio_config mcux_flexio_config_##n = { \
226 		.base = (FLEXIO_Type *)DT_INST_REG_ADDR(n),		\
227 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),	\
228 		.clock_subsys =						\
229 		(clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),	\
230 		.irq_config_func = mcux_flexio_irq_config_func_##n,	\
231 		.irq_enable_func = mcux_flexio_irq_enable_func_##n,	\
232 		.irq_disable_func = mcux_flexio_irq_disable_func_##n,	\
233 	};								\
234 									\
235 	DEVICE_DT_INST_DEFINE(n, &mcux_flexio_init,			\
236 				NULL,					\
237 				&mcux_flexio_data_##n,			\
238 				&mcux_flexio_config_##n,		\
239 				POST_KERNEL,				\
240 				CONFIG_MCUX_FLEXIO_INIT_PRIORITY,	\
241 				NULL);					\
242 									\
243 	static void mcux_flexio_irq_config_func_##n(const struct device *dev) \
244 	{								\
245 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),	\
246 			mcux_flexio_isr, DEVICE_DT_INST_GET(n), 0);	\
247 		irq_enable(DT_INST_IRQN(n));				\
248 	}								\
249 									\
250 	static void mcux_flexio_irq_enable_func_##n(void)		\
251 	{								\
252 		irq_enable(DT_INST_IRQN(n));				\
253 	}								\
254 									\
255 	static void mcux_flexio_irq_disable_func_##n(void)		\
256 	{								\
257 		irq_disable(DT_INST_IRQN(n));				\
258 	}
259 
260 DT_INST_FOREACH_STATUS_OKAY(MCUX_FLEXIO_INIT)
261