1 /*
2 * Copyright 2022 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_s32_gpio
8
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/gpio/gpio_utils.h>
11
12 #include <Siul2_Port_Ip.h>
13 #include <Siul2_Dio_Ip.h>
14
15 #ifdef CONFIG_NXP_S32_EIRQ
16 #include <zephyr/drivers/interrupt_controller/intc_eirq_nxp_s32.h>
17
18 struct eirq_nxp_s32_info {
19 const struct device *eirq_dev;
20 uint8_t num_lines;
21 struct gpio_pin_line {
22 uint8_t pin;
23 uint8_t line;
24 } gpio_pin_lines[];
25 };
26 #endif
27
28 struct gpio_nxp_s32_config {
29 /* gpio_driver_config needs to be first */
30 struct gpio_driver_config common;
31
32 Siul2_Dio_Ip_GpioType *gpio_base;
33 Siul2_Port_Ip_PortType *port_base;
34
35 #ifdef CONFIG_NXP_S32_EIRQ
36 struct eirq_nxp_s32_info *eirq_info;
37 #endif
38 };
39
40 struct gpio_nxp_s32_data {
41 /* gpio_driver_data needs to be first */
42 struct gpio_driver_data common;
43
44 #ifdef CONFIG_NXP_S32_EIRQ
45 sys_slist_t callbacks;
46 #endif
47 };
48
nxp_s32_gpio_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)49 static int nxp_s32_gpio_configure(const struct device *dev, gpio_pin_t pin,
50 gpio_flags_t flags)
51 {
52 const struct gpio_nxp_s32_config *port_config = dev->config;
53 Siul2_Dio_Ip_GpioType *gpio_base = port_config->gpio_base;
54 Siul2_Port_Ip_PortType *port_base = port_config->port_base;
55 Siul2_Port_Ip_PortPullConfig pull_config;
56
57 if ((flags & GPIO_SINGLE_ENDED) != 0) {
58 return -ENOTSUP;
59 }
60
61 switch (flags & GPIO_DIR_MASK) {
62 case GPIO_INPUT:
63 Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_IN);
64 break;
65 case GPIO_OUTPUT:
66 Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_OUT);
67 break;
68 case GPIO_INPUT | GPIO_OUTPUT:
69 Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_IN_OUT);
70 break;
71 default:
72 Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_HI_Z);
73 break;
74 }
75
76 Siul2_Port_Ip_SetOutputBuffer(port_base, pin,
77 (flags & GPIO_OUTPUT), PORT_MUX_AS_GPIO);
78
79 switch (flags & (GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH | GPIO_OUTPUT_INIT_LOW)) {
80 case GPIO_OUTPUT_HIGH:
81 Siul2_Dio_Ip_WritePin(gpio_base, pin, 1);
82 break;
83 case GPIO_OUTPUT_LOW:
84 Siul2_Dio_Ip_WritePin(gpio_base, pin, 0);
85 break;
86 default:
87 break;
88 }
89
90 if ((flags & GPIO_PULL_UP) != 0) {
91 pull_config = PORT_INTERNAL_PULL_UP_ENABLED;
92 } else if ((flags & GPIO_PULL_DOWN) != 0) {
93 pull_config = PORT_INTERNAL_PULL_DOWN_ENABLED;
94 } else {
95 pull_config = PORT_INTERNAL_PULL_NOT_ENABLED;
96 }
97 Siul2_Port_Ip_SetPullSel(port_base, pin, pull_config);
98
99 return 0;
100 }
101
nxp_s32_gpio_port_get_raw(const struct device * port,uint32_t * value)102 static int nxp_s32_gpio_port_get_raw(const struct device *port, uint32_t *value)
103 {
104 const struct gpio_nxp_s32_config *config = port->config;
105
106 *value = Siul2_Dio_Ip_ReadPins(config->gpio_base);
107
108 return 0;
109 }
110
nxp_s32_gpio_port_set_masked_raw(const struct device * port,gpio_port_pins_t mask,gpio_port_value_t value)111 static int nxp_s32_gpio_port_set_masked_raw(const struct device *port,
112 gpio_port_pins_t mask,
113 gpio_port_value_t value)
114 {
115 const struct gpio_nxp_s32_config *config = port->config;
116 Siul2_Dio_Ip_GpioType *gpio_base = config->gpio_base;
117 gpio_port_pins_t pins_value = Siul2_Dio_Ip_GetPinsOutput(gpio_base);
118
119 pins_value = (pins_value & ~mask) | (mask & value);
120 Siul2_Dio_Ip_WritePins(gpio_base, pins_value);
121
122 return 0;
123 }
124
nxp_s32_gpio_port_set_bits_raw(const struct device * port,gpio_port_pins_t pins)125 static int nxp_s32_gpio_port_set_bits_raw(const struct device *port,
126 gpio_port_pins_t pins)
127 {
128 const struct gpio_nxp_s32_config *config = port->config;
129
130 Siul2_Dio_Ip_SetPins(config->gpio_base, pins);
131
132 return 0;
133 }
134
nxp_s32_gpio_port_clear_bits_raw(const struct device * port,gpio_port_pins_t pins)135 static int nxp_s32_gpio_port_clear_bits_raw(const struct device *port,
136 gpio_port_pins_t pins)
137 {
138 const struct gpio_nxp_s32_config *config = port->config;
139
140 Siul2_Dio_Ip_ClearPins(config->gpio_base, pins);
141
142 return 0;
143 }
144
nxp_s32_gpio_port_toggle_bits(const struct device * port,gpio_port_pins_t pins)145 static int nxp_s32_gpio_port_toggle_bits(const struct device *port,
146 gpio_port_pins_t pins)
147 {
148 const struct gpio_nxp_s32_config *config = port->config;
149
150 Siul2_Dio_Ip_TogglePins(config->gpio_base, pins);
151
152 return 0;
153 }
154
155 #ifdef CONFIG_NXP_S32_EIRQ
156
nxp_s32_gpio_pin_to_line(const struct eirq_nxp_s32_info * eirq_info,uint8_t pin)157 static uint8_t nxp_s32_gpio_pin_to_line(const struct eirq_nxp_s32_info *eirq_info, uint8_t pin)
158 {
159 uint8_t i;
160
161 for (i = 0; i < eirq_info->num_lines; i++) {
162 if (eirq_info->gpio_pin_lines[i].pin == pin) {
163 return eirq_info->gpio_pin_lines[i].line;
164 }
165 }
166
167 return SIUL2_ICU_IP_NUM_OF_CHANNELS;
168 }
169
nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType * edge_type,enum gpio_int_mode mode,enum gpio_int_trig trigger)170 static int nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type,
171 enum gpio_int_mode mode,
172 enum gpio_int_trig trigger)
173 {
174 if (mode == GPIO_INT_MODE_DISABLED) {
175 *edge_type = SIUL2_ICU_DISABLE;
176 return 0;
177 }
178
179 if (mode == GPIO_INT_MODE_LEVEL) {
180 return -ENOTSUP;
181 }
182
183 switch (trigger) {
184 case GPIO_INT_TRIG_LOW:
185 *edge_type = SIUL2_ICU_FALLING_EDGE;
186 break;
187 case GPIO_INT_TRIG_HIGH:
188 *edge_type = SIUL2_ICU_RISING_EDGE;
189 break;
190 case GPIO_INT_TRIG_BOTH:
191 *edge_type = SIUL2_ICU_BOTH_EDGES;
192 break;
193 default:
194 return -ENOTSUP;
195 }
196
197 return 0;
198 }
199
nxp_s32_gpio_isr(uint8_t pin,void * arg)200 static void nxp_s32_gpio_isr(uint8_t pin, void *arg)
201 {
202 const struct device *dev = (struct device *)arg;
203 struct gpio_nxp_s32_data *data = dev->data;
204
205 gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
206 }
207 #endif /* CONFIG_NXP_S32_EIRQ */
208
nxp_s32_gpio_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)209 static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
210 gpio_pin_t pin,
211 enum gpio_int_mode mode,
212 enum gpio_int_trig trig)
213 {
214 #ifdef CONFIG_NXP_S32_EIRQ
215 const struct gpio_nxp_s32_config *config = dev->config;
216 const struct eirq_nxp_s32_info *eirq_info = config->eirq_info;
217
218 uint8_t eirq_line;
219
220 Siul2_Icu_Ip_EdgeType edge_type;
221
222 if (eirq_info == NULL) {
223 /*
224 * There is no external interrupt device for
225 * the GPIO port or exists but is not enabled
226 */
227 return -ENOTSUP;
228 }
229
230 eirq_line = nxp_s32_gpio_pin_to_line(eirq_info, pin);
231
232 if (eirq_line == SIUL2_ICU_IP_NUM_OF_CHANNELS) {
233 /*
234 * GPIO pin cannot be used for processing
235 * external interrupt signal
236 */
237 return -ENOTSUP;
238 }
239
240 if (nxp_s32_gpio_eirq_get_trigger(&edge_type, mode, trig)) {
241 return -ENOTSUP;
242 }
243
244 if (edge_type == SIUL2_ICU_DISABLE) {
245 eirq_nxp_s32_disable_interrupt(eirq_info->eirq_dev, eirq_line);
246 eirq_nxp_s32_unset_callback(eirq_info->eirq_dev, eirq_line);
247 } else {
248 if (eirq_nxp_s32_set_callback(eirq_info->eirq_dev, eirq_line,
249 nxp_s32_gpio_isr, pin, (void *)dev)) {
250 return -EBUSY;
251 }
252
253 eirq_nxp_s32_enable_interrupt(eirq_info->eirq_dev, eirq_line, edge_type);
254 }
255
256 return 0;
257 #else
258 ARG_UNUSED(dev);
259 ARG_UNUSED(pin);
260 ARG_UNUSED(mode);
261 ARG_UNUSED(trig);
262
263 return -ENOTSUP;
264 #endif
265 }
266
nxp_s32_gpio_manage_callback(const struct device * dev,struct gpio_callback * cb,bool set)267 static int nxp_s32_gpio_manage_callback(const struct device *dev,
268 struct gpio_callback *cb, bool set)
269 {
270 #ifdef CONFIG_NXP_S32_EIRQ
271 struct gpio_nxp_s32_data *data = dev->data;
272
273 return gpio_manage_callback(&data->callbacks, cb, set);
274 #else
275 ARG_UNUSED(dev);
276 ARG_UNUSED(cb);
277 ARG_UNUSED(set);
278
279 return -ENOTSUP;
280 #endif
281 }
282
nxp_s32_gpio_get_pending_int(const struct device * dev)283 static uint32_t nxp_s32_gpio_get_pending_int(const struct device *dev)
284 {
285 #ifdef CONFIG_NXP_S32_EIRQ
286 const struct gpio_nxp_s32_config *config = dev->config;
287 const struct eirq_nxp_s32_info *eirq_info = config->eirq_info;
288
289 if (eirq_info == NULL) {
290 /*
291 * There is no external interrupt device for
292 * the GPIO port or exists but is not enabled
293 */
294 return 0;
295 }
296
297 /*
298 * Return all pending lines of the interrupt controller
299 * that GPIO port belongs to
300 */
301 return eirq_nxp_s32_get_pending(eirq_info->eirq_dev);
302
303 #else
304 ARG_UNUSED(dev);
305
306 return -ENOTSUP;
307 #endif
308 }
309
310 static const struct gpio_driver_api gpio_nxp_s32_driver_api = {
311 .pin_configure = nxp_s32_gpio_configure,
312 .port_get_raw = nxp_s32_gpio_port_get_raw,
313 .port_set_masked_raw = nxp_s32_gpio_port_set_masked_raw,
314 .port_set_bits_raw = nxp_s32_gpio_port_set_bits_raw,
315 .port_clear_bits_raw = nxp_s32_gpio_port_clear_bits_raw,
316 .port_toggle_bits = nxp_s32_gpio_port_toggle_bits,
317 .pin_interrupt_configure = nxp_s32_gpio_pin_interrupt_configure,
318 .manage_callback = nxp_s32_gpio_manage_callback,
319 .get_pending_int = nxp_s32_gpio_get_pending_int
320 };
321
322 /* Calculate the port pin mask based on ngpios and gpio-reserved-ranges node
323 * properties. Multiple reserved ranges are not supported.
324 *
325 * For example, for the following gpio node definition:
326 *
327 * gpioo: gpio@40521716 {
328 * ...
329 * ngpios = <14>;
330 * gpio-reserved-ranges = <0 10>;
331 * };
332 *
333 * the generated mask will be will be 0x3C00.
334 */
335 #define GPIO_NXP_S32_RESERVED_PIN_MASK(n) \
336 (GENMASK(DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0) + \
337 DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 1) - 1, \
338 DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0) \
339 ))
340
341 #define GPIO_NXP_S32_PORT_PIN_MASK(n) \
342 COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_reserved_ranges), \
343 (GPIO_PORT_PIN_MASK_FROM_DT_INST(n) \
344 & ~(GPIO_NXP_S32_RESERVED_PIN_MASK(n))), \
345 (GPIO_PORT_PIN_MASK_FROM_DT_INST(n)))
346
347 #define GPIO_NXP_S32_REG_ADDR(n) \
348 ((Siul2_Dio_Ip_GpioType *)DT_INST_REG_ADDR_BY_NAME(n, pgpdo))
349
350 #define GPIO_NXP_S32_PORT_REG_ADDR(n) \
351 ((Siul2_Port_Ip_PortType *)DT_INST_REG_ADDR_BY_NAME(n, mscr))
352
353 #ifdef CONFIG_NXP_S32_EIRQ
354 #define GPIO_NXP_S32_EIRQ_NODE(n) \
355 DT_INST_PHANDLE(n, interrupt_parent)
356
357 #define GPIO_NXP_S32_EIRQ_PIN_LINE(idx, n) \
358 { \
359 .pin = DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \
360 .line = DT_INST_IRQ_BY_IDX(n, idx, eirq_line), \
361 }
362
363 #define GPIO_NXP_S32_SET_EIRQ_INFO(n) \
364 BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \
365 DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \
366 "interrupts and interrupt-parent must be set when" \
367 " using external interrupts"); \
368 IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay), \
369 (static struct eirq_nxp_s32_info eirq_nxp_s32_info_##n = { \
370 .eirq_dev = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)), \
371 .gpio_pin_lines = { \
372 LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \
373 GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n) \
374 }, \
375 .num_lines = DT_NUM_IRQS(DT_DRV_INST(n)) \
376 }; \
377 ))
378
379 #define GPIO_NXP_S32_GET_EIRQ_INFO(n) \
380 .eirq_info = UTIL_AND(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay),\
381 &eirq_nxp_s32_info_##n)
382 #else
383 #define GPIO_NXP_S32_SET_EIRQ_INFO(n)
384 #define GPIO_NXP_S32_GET_EIRQ_INFO(n)
385 #endif /* CONFIG_NXP_S32_EIRQ */
386
387 #define GPIO_NXP_S32_DEVICE_INIT(n) \
388 GPIO_NXP_S32_SET_EIRQ_INFO(n) \
389 static const struct gpio_nxp_s32_config gpio_nxp_s32_config_##n = { \
390 .common = { \
391 .port_pin_mask = GPIO_NXP_S32_PORT_PIN_MASK(n), \
392 }, \
393 .gpio_base = GPIO_NXP_S32_REG_ADDR(n), \
394 .port_base = GPIO_NXP_S32_PORT_REG_ADDR(n), \
395 GPIO_NXP_S32_GET_EIRQ_INFO(n) \
396 }; \
397 static struct gpio_nxp_s32_data gpio_nxp_s32_data_##n; \
398 static int gpio_nxp_s32_init_##n(const struct device *dev) \
399 { \
400 return 0; \
401 } \
402 DEVICE_DT_INST_DEFINE(n, \
403 gpio_nxp_s32_init_##n, \
404 NULL, \
405 &gpio_nxp_s32_data_##n, \
406 &gpio_nxp_s32_config_##n, \
407 POST_KERNEL, \
408 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
409 &gpio_nxp_s32_driver_api);
410
411 DT_INST_FOREACH_STATUS_OKAY(GPIO_NXP_S32_DEVICE_INIT)
412