1 /*
2 * Copyright (c) 2016 Freescale Semiconductor, Inc.
3 * Copyright (c) 2017, NXP
4 * Copyright (c) 2018 Foundries.io
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define DT_DRV_COMPAT openisa_rv32m1_gpio
10
11 #include <errno.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/irq.h>
15 #include <soc.h>
16 #include <fsl_common.h>
17 #include <fsl_port.h>
18 #include <zephyr/drivers/clock_control.h>
19
20 #include <zephyr/drivers/gpio/gpio_utils.h>
21
22 struct gpio_rv32m1_config {
23 /* gpio_driver_config needs to be first */
24 struct gpio_driver_config common;
25 GPIO_Type *gpio_base;
26 PORT_Type *port_base;
27 unsigned int flags;
28 const struct device *clock_dev;
29 clock_control_subsys_t clock_subsys;
30 int (*irq_config_func)(const struct device *dev);
31 };
32
33 struct gpio_rv32m1_data {
34 /* gpio_driver_data needs to be first */
35 struct gpio_driver_data common;
36 /* port ISR callback routine address */
37 sys_slist_t callbacks;
38 };
39
get_port_pcr_irqc_value_from_flags(const struct device * dev,uint32_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)40 static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev,
41 uint32_t pin,
42 enum gpio_int_mode mode,
43 enum gpio_int_trig trig)
44 {
45 port_interrupt_t port_interrupt = 0;
46
47 if (mode == GPIO_INT_MODE_DISABLED) {
48 port_interrupt = kPORT_InterruptOrDMADisabled;
49 } else {
50 if (mode == GPIO_INT_MODE_LEVEL) {
51 if (trig == GPIO_INT_TRIG_LOW) {
52 port_interrupt = kPORT_InterruptLogicZero;
53 } else {
54 port_interrupt = kPORT_InterruptLogicOne;
55 }
56 } else {
57 switch (trig) {
58 case GPIO_INT_TRIG_LOW:
59 port_interrupt = kPORT_InterruptFallingEdge;
60 break;
61 case GPIO_INT_TRIG_HIGH:
62 port_interrupt = kPORT_InterruptRisingEdge;
63 break;
64 case GPIO_INT_TRIG_BOTH:
65 port_interrupt = kPORT_InterruptEitherEdge;
66 break;
67 default:
68 return -EINVAL;
69 }
70 }
71 }
72
73 return PORT_PCR_IRQC(port_interrupt);
74 }
75
gpio_rv32m1_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)76 static int gpio_rv32m1_configure(const struct device *dev,
77 gpio_pin_t pin, gpio_flags_t flags)
78 {
79 const struct gpio_rv32m1_config *config = dev->config;
80 GPIO_Type *gpio_base = config->gpio_base;
81 PORT_Type *port_base = config->port_base;
82 uint32_t mask = 0U;
83 uint32_t pcr = 0U;
84
85 /* Check for an invalid pin number */
86 if (pin >= ARRAY_SIZE(port_base->PCR)) {
87 return -EINVAL;
88 }
89
90 /* Check for an invalid pin configuration */
91 if ((flags & GPIO_INT_ENABLE) && ((flags & GPIO_INPUT) == 0)) {
92 return -EINVAL;
93 }
94
95 if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
96 return -ENOTSUP;
97 }
98
99 if ((flags & GPIO_SINGLE_ENDED) != 0) {
100 return -ENOTSUP;
101 }
102
103 /* Check if GPIO port supports interrupts */
104 if ((flags & GPIO_INT_ENABLE) &&
105 ((config->flags & GPIO_INT_ENABLE) == 0U)) {
106 return -ENOTSUP;
107 }
108
109 /* The flags contain options that require touching registers in the
110 * GPIO module and the corresponding PORT module.
111 *
112 * Start with the GPIO module and set up the pin direction register.
113 * 0 - pin is input, 1 - pin is output
114 */
115
116 switch (flags & GPIO_DIR_MASK) {
117 case GPIO_INPUT:
118 gpio_base->PDDR &= ~BIT(pin);
119 break;
120 case GPIO_OUTPUT:
121 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
122 gpio_base->PSOR = BIT(pin);
123 } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
124 gpio_base->PCOR = BIT(pin);
125 }
126 gpio_base->PDDR |= BIT(pin);
127 break;
128 default:
129 return -ENOTSUP;
130 }
131
132 /* Set PCR mux to GPIO for the pin we are configuring */
133 mask |= PORT_PCR_MUX_MASK;
134 pcr |= PORT_PCR_MUX(kPORT_MuxAsGpio);
135
136 /* Now do the PORT module. Figure out the pullup/pulldown
137 * configuration, but don't write it to the PCR register yet.
138 */
139 mask |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
140
141 if ((flags & GPIO_PULL_UP) != 0) {
142 /* Enable the pull and select the pullup resistor. */
143 pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
144
145 } else if ((flags & GPIO_PULL_DOWN) != 0) {
146 /* Enable the pull and select the pulldown resistor (deselect
147 * the pullup resistor.
148 */
149 pcr |= PORT_PCR_PE_MASK;
150 }
151
152 /* Still in the PORT module. Figure out the interrupt configuration,
153 * but don't write it to the PCR register yet.
154 */
155 mask |= PORT_PCR_IRQC_MASK;
156
157 /* Accessing by pin, we only need to write one PCR register. */
158 port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr;
159
160 return 0;
161 }
162
gpio_rv32m1_port_get_raw(const struct device * dev,uint32_t * value)163 static int gpio_rv32m1_port_get_raw(const struct device *dev, uint32_t *value)
164 {
165 const struct gpio_rv32m1_config *config = dev->config;
166 GPIO_Type *gpio_base = config->gpio_base;
167
168 *value = gpio_base->PDIR;
169
170 return 0;
171 }
172
gpio_rv32m1_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)173 static int gpio_rv32m1_port_set_masked_raw(const struct device *dev,
174 uint32_t mask,
175 uint32_t value)
176 {
177 const struct gpio_rv32m1_config *config = dev->config;
178 GPIO_Type *gpio_base = config->gpio_base;
179
180 gpio_base->PDOR = (gpio_base->PDOR & ~mask) | (mask & value);
181
182 return 0;
183 }
184
gpio_rv32m1_port_set_bits_raw(const struct device * dev,uint32_t mask)185 static int gpio_rv32m1_port_set_bits_raw(const struct device *dev,
186 uint32_t mask)
187 {
188 const struct gpio_rv32m1_config *config = dev->config;
189 GPIO_Type *gpio_base = config->gpio_base;
190
191 gpio_base->PSOR = mask;
192
193 return 0;
194 }
195
gpio_rv32m1_port_clear_bits_raw(const struct device * dev,uint32_t mask)196 static int gpio_rv32m1_port_clear_bits_raw(const struct device *dev,
197 uint32_t mask)
198 {
199 const struct gpio_rv32m1_config *config = dev->config;
200 GPIO_Type *gpio_base = config->gpio_base;
201
202 gpio_base->PCOR = mask;
203
204 return 0;
205 }
206
gpio_rv32m1_port_toggle_bits(const struct device * dev,uint32_t mask)207 static int gpio_rv32m1_port_toggle_bits(const struct device *dev,
208 uint32_t mask)
209 {
210 const struct gpio_rv32m1_config *config = dev->config;
211 GPIO_Type *gpio_base = config->gpio_base;
212
213 gpio_base->PTOR = mask;
214
215 return 0;
216 }
217
gpio_rv32m1_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)218 static int gpio_rv32m1_pin_interrupt_configure(const struct device *dev,
219 gpio_pin_t pin,
220 enum gpio_int_mode mode,
221 enum gpio_int_trig trig)
222 {
223 const struct gpio_rv32m1_config *config = dev->config;
224 PORT_Type *port_base = config->port_base;
225
226 /* Check for an invalid pin number */
227 if (pin >= ARRAY_SIZE(port_base->PCR)) {
228 return -EINVAL;
229 }
230
231 /* Check if GPIO port supports interrupts */
232 if ((mode != GPIO_INT_MODE_DISABLED) &&
233 ((config->flags & GPIO_INT_ENABLE) == 0U)) {
234 return -ENOTSUP;
235 }
236
237 uint32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, mode, trig);
238
239 port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
240
241 return 0;
242 }
243
244
gpio_rv32m1_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)245 static int gpio_rv32m1_manage_callback(const struct device *dev,
246 struct gpio_callback *callback,
247 bool set)
248 {
249 struct gpio_rv32m1_data *data = dev->data;
250
251 gpio_manage_callback(&data->callbacks, callback, set);
252
253 return 0;
254 }
255
gpio_rv32m1_port_isr(const struct device * dev)256 static void gpio_rv32m1_port_isr(const struct device *dev)
257 {
258 const struct gpio_rv32m1_config *config = dev->config;
259 struct gpio_rv32m1_data *data = dev->data;
260 uint32_t int_status;
261
262 int_status = config->port_base->ISFR;
263
264 /* Clear the port interrupts before invoking callbacks */
265 config->port_base->ISFR = int_status;
266
267 gpio_fire_callbacks(&data->callbacks, dev, int_status);
268 }
269
gpio_rv32m1_init(const struct device * dev)270 static int gpio_rv32m1_init(const struct device *dev)
271 {
272 const struct gpio_rv32m1_config *config = dev->config;
273 int ret;
274
275 if (config->clock_dev) {
276 if (!device_is_ready(config->clock_dev)) {
277 return -ENODEV;
278 }
279
280 ret = clock_control_on(config->clock_dev, config->clock_subsys);
281 if (ret < 0) {
282 return ret;
283 }
284 }
285
286 return config->irq_config_func(dev);
287 }
288
289 static DEVICE_API(gpio, gpio_rv32m1_driver_api) = {
290 .pin_configure = gpio_rv32m1_configure,
291 .port_get_raw = gpio_rv32m1_port_get_raw,
292 .port_set_masked_raw = gpio_rv32m1_port_set_masked_raw,
293 .port_set_bits_raw = gpio_rv32m1_port_set_bits_raw,
294 .port_clear_bits_raw = gpio_rv32m1_port_clear_bits_raw,
295 .port_toggle_bits = gpio_rv32m1_port_toggle_bits,
296 .pin_interrupt_configure = gpio_rv32m1_pin_interrupt_configure,
297 .manage_callback = gpio_rv32m1_manage_callback,
298 };
299
300 #define INST_DT_PORT_ADDR(n) \
301 DT_REG_ADDR(DT_INST_PHANDLE(n, openisa_rv32m1_port))
302 #define INST_DT_CLK_CTRL_DEV(n) \
303 UTIL_AND(DT_INST_NODE_HAS_PROP(n, clocks), DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)))
304 #define INST_DT_CLK_CELL_NAME(n) \
305 UTIL_AND(DT_INST_NODE_HAS_PROP(n, clocks), DT_INST_CLOCKS_CELL(n, name))
306
307 #define GPIO_RV32M1_INIT(n) \
308 static int gpio_rv32m1_##n##_init(const struct device *dev); \
309 \
310 static const struct gpio_rv32m1_config gpio_rv32m1_##n##_config = {\
311 .common = { \
312 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
313 }, \
314 .gpio_base = (GPIO_Type *) DT_INST_REG_ADDR(n), \
315 .port_base = (PORT_Type *) INST_DT_PORT_ADDR(n), \
316 .flags = GPIO_INT_ENABLE, \
317 .irq_config_func = gpio_rv32m1_##n##_init, \
318 .clock_dev = INST_DT_CLK_CTRL_DEV(n), \
319 .clock_subsys = (clock_control_subsys_t) \
320 INST_DT_CLK_CELL_NAME(n) \
321 }; \
322 \
323 static struct gpio_rv32m1_data gpio_rv32m1_##n##_data; \
324 \
325 DEVICE_DT_INST_DEFINE(n, \
326 gpio_rv32m1_init, \
327 NULL, \
328 &gpio_rv32m1_##n##_data, \
329 &gpio_rv32m1_##n##_config, \
330 PRE_KERNEL_1, \
331 CONFIG_GPIO_INIT_PRIORITY, \
332 &gpio_rv32m1_driver_api); \
333 \
334 static int gpio_rv32m1_##n##_init(const struct device *dev) \
335 { \
336 IRQ_CONNECT(DT_INST_IRQN(n), \
337 0, \
338 gpio_rv32m1_port_isr, \
339 DEVICE_DT_INST_GET(n), 0); \
340 \
341 irq_enable(DT_INST_IRQN(0)); \
342 \
343 return 0; \
344 }
345
346 DT_INST_FOREACH_STATUS_OKAY(GPIO_RV32M1_INIT)
347