1 /*
2 * Copyright (c) 2018-2019, NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_gpio
8
9 #include <errno.h>
10 #include <device.h>
11 #include <drivers/gpio.h>
12 #include <soc.h>
13 #include <sys/util.h>
14 #include <gpio_imx.h>
15
16 #include "gpio_utils.h"
17
18 struct imx_gpio_config {
19 /* gpio_driver_config needs to be first */
20 struct gpio_driver_config common;
21 GPIO_Type *base;
22 };
23
24 struct imx_gpio_data {
25 /* gpio_driver_data needs to be first */
26 struct gpio_driver_data common;
27 /* port ISR callback routine address */
28 sys_slist_t callbacks;
29 };
30
imx_gpio_configure(const struct device * port,gpio_pin_t pin,gpio_flags_t flags)31 static int imx_gpio_configure(const struct device *port, gpio_pin_t pin,
32 gpio_flags_t flags)
33 {
34 const struct imx_gpio_config *config = port->config;
35 GPIO_Type *base = config->base;
36
37 if (((flags & GPIO_INPUT) != 0U) && ((flags & GPIO_OUTPUT) != 0U)) {
38 return -ENOTSUP;
39 }
40
41 if ((flags & (GPIO_SINGLE_ENDED
42 | GPIO_PULL_UP
43 | GPIO_PULL_DOWN)) != 0U) {
44 return -ENOTSUP;
45 }
46
47 /* Disable interrupts for pin */
48 GPIO_SetPinIntMode(base, pin, false);
49 GPIO_SetIntEdgeSelect(base, pin, false);
50
51 if ((flags & GPIO_OUTPUT) != 0U) {
52 /* Set output pin initial value */
53 if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
54 GPIO_WritePinOutput(base, pin, gpioPinClear);
55 } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
56 GPIO_WritePinOutput(base, pin, gpioPinSet);
57 }
58
59 /* Set pin as output */
60 WRITE_BIT(base->GDIR, pin, 1U);
61 } else {
62 /* Set pin as input */
63 WRITE_BIT(base->GDIR, pin, 0U);
64 }
65
66 return 0;
67 }
68
imx_gpio_port_get_raw(const struct device * port,uint32_t * value)69 static int imx_gpio_port_get_raw(const struct device *port, uint32_t *value)
70 {
71 const struct imx_gpio_config *config = port->config;
72 GPIO_Type *base = config->base;
73
74 *value = GPIO_ReadPortInput(base);
75
76 return 0;
77 }
78
imx_gpio_port_set_masked_raw(const struct device * port,gpio_port_pins_t mask,gpio_port_value_t value)79 static int imx_gpio_port_set_masked_raw(const struct device *port,
80 gpio_port_pins_t mask,
81 gpio_port_value_t value)
82 {
83 const struct imx_gpio_config *config = port->config;
84 GPIO_Type *base = config->base;
85
86 GPIO_WritePortOutput(base,
87 (GPIO_ReadPortInput(base) & ~mask) | (value & mask));
88
89 return 0;
90 }
91
imx_gpio_port_set_bits_raw(const struct device * port,gpio_port_pins_t pins)92 static int imx_gpio_port_set_bits_raw(const struct device *port,
93 gpio_port_pins_t pins)
94 {
95 const struct imx_gpio_config *config = port->config;
96 GPIO_Type *base = config->base;
97
98 GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) | pins);
99
100 return 0;
101 }
102
imx_gpio_port_clear_bits_raw(const struct device * port,gpio_port_pins_t pins)103 static int imx_gpio_port_clear_bits_raw(const struct device *port,
104 gpio_port_pins_t pins)
105 {
106 const struct imx_gpio_config *config = port->config;
107 GPIO_Type *base = config->base;
108
109 GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) & ~pins);
110
111 return 0;
112 }
113
imx_gpio_port_toggle_bits(const struct device * port,gpio_port_pins_t pins)114 static int imx_gpio_port_toggle_bits(const struct device *port,
115 gpio_port_pins_t pins)
116 {
117 const struct imx_gpio_config *config = port->config;
118 GPIO_Type *base = config->base;
119
120 GPIO_WritePortOutput(base, GPIO_ReadPortInput(base) ^ pins);
121
122 return 0;
123 }
124
imx_gpio_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)125 static int imx_gpio_pin_interrupt_configure(const struct device *port,
126 gpio_pin_t pin,
127 enum gpio_int_mode mode,
128 enum gpio_int_trig trig)
129 {
130 const struct imx_gpio_config *config = port->config;
131 GPIO_Type *base = config->base;
132 volatile uint32_t *icr_reg;
133 unsigned int key;
134 uint32_t icr_val;
135 uint8_t shift;
136
137 if (((base->GDIR & BIT(pin)) != 0U)
138 && (mode != GPIO_INT_MODE_DISABLED)) {
139 /* Interrupt on output pin not supported */
140 return -ENOTSUP;
141 }
142
143 if ((mode == GPIO_INT_MODE_EDGE) && (trig == GPIO_INT_TRIG_LOW)) {
144 icr_val = 3U;
145 } else if ((mode == GPIO_INT_MODE_EDGE) &&
146 (trig == GPIO_INT_TRIG_HIGH)) {
147 icr_val = 2U;
148 } else if ((mode == GPIO_INT_MODE_LEVEL) &&
149 (trig == GPIO_INT_TRIG_HIGH)) {
150 icr_val = 1U;
151 } else {
152 icr_val = 0U;
153 }
154
155 if (pin < 16U) {
156 shift = 2U * pin;
157 icr_reg = &(base->ICR1);
158 } else if (pin < 32U) {
159 shift = 2U * (pin - 16U);
160 icr_reg = &(base->ICR2);
161 } else {
162 return -EINVAL;
163 }
164
165 key = irq_lock();
166
167 *icr_reg = (*icr_reg & ~(3U << shift)) | (icr_val << shift);
168
169 WRITE_BIT(base->EDGE_SEL, pin, trig == GPIO_INT_TRIG_BOTH);
170 WRITE_BIT(base->ISR, pin, mode != GPIO_INT_MODE_DISABLED);
171 WRITE_BIT(base->IMR, pin, mode != GPIO_INT_MODE_DISABLED);
172
173 irq_unlock(key);
174
175 return 0;
176 }
177
imx_gpio_manage_callback(const struct device * port,struct gpio_callback * cb,bool set)178 static int imx_gpio_manage_callback(const struct device *port,
179 struct gpio_callback *cb, bool set)
180 {
181 struct imx_gpio_data *data = port->data;
182
183 return gpio_manage_callback(&data->callbacks, cb, set);
184 }
185
imx_gpio_port_isr(const struct device * port)186 static void imx_gpio_port_isr(const struct device *port)
187 {
188 const struct imx_gpio_config *config = port->config;
189 struct imx_gpio_data *data = port->data;
190 uint32_t int_status;
191
192 int_status = config->base->ISR;
193
194 config->base->ISR = int_status;
195
196 gpio_fire_callbacks(&data->callbacks, port, int_status);
197 }
198
199 static const struct gpio_driver_api imx_gpio_driver_api = {
200 .pin_configure = imx_gpio_configure,
201 .port_get_raw = imx_gpio_port_get_raw,
202 .port_set_masked_raw = imx_gpio_port_set_masked_raw,
203 .port_set_bits_raw = imx_gpio_port_set_bits_raw,
204 .port_clear_bits_raw = imx_gpio_port_clear_bits_raw,
205 .port_toggle_bits = imx_gpio_port_toggle_bits,
206 .pin_interrupt_configure = imx_gpio_pin_interrupt_configure,
207 .manage_callback = imx_gpio_manage_callback,
208 };
209
210 #define GPIO_IMX_INIT(n) \
211 static int imx_gpio_##n##_init(const struct device *port); \
212 \
213 static const struct imx_gpio_config imx_gpio_##n##_config = { \
214 .common = { \
215 .port_pin_mask = \
216 GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
217 }, \
218 .base = (GPIO_Type *)DT_INST_REG_ADDR(n), \
219 }; \
220 \
221 static struct imx_gpio_data imx_gpio_##n##_data; \
222 \
223 DEVICE_DT_INST_DEFINE(n, \
224 imx_gpio_##n##_init, \
225 NULL, \
226 &imx_gpio_##n##_data, \
227 &imx_gpio_##n##_config, \
228 POST_KERNEL, \
229 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
230 &imx_gpio_driver_api); \
231 \
232 static int imx_gpio_##n##_init(const struct device *port) \
233 { \
234 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \
235 DT_INST_IRQ_BY_IDX(n, 0, priority), \
236 imx_gpio_port_isr, \
237 DEVICE_DT_INST_GET(n), 0); \
238 \
239 irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \
240 \
241 IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq), \
242 DT_INST_IRQ_BY_IDX(n, 1, priority), \
243 imx_gpio_port_isr, \
244 DEVICE_DT_INST_GET(n), 0); \
245 \
246 irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq)); \
247 \
248 return 0; \
249 }
250
251 DT_INST_FOREACH_STATUS_OKAY(GPIO_IMX_INIT)
252