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