Skip to content

Commit e1d495b

Browse files
CkovMknashif
authored andcommitted
driver: add new gpio driver "gpio_mcux_rgpio"
Add RGPIO gpio driver. This driver is used for i.MX93 and i.MX8ULP. GPIO pinctrl, read/write and interrupt is supported. Runtime mmio configuration is enabled, so no need for region definition in mimx9/mmu_region.c Signed-off-by: Chekhov Ma <[email protected]>
1 parent 2effad3 commit e1d495b

File tree

6 files changed

+356
-2
lines changed

6 files changed

+356
-2
lines changed

drivers/gpio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_MCP230XX gpio_mcp230xx.c)
2626
zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c)
2727
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX gpio_mcux.c)
2828
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_IGPIO gpio_mcux_igpio.c)
29+
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_RGPIO gpio_mcux_rgpio.c)
2930
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_LPC gpio_mcux_lpc.c)
3031
zephyr_library_sources_ifdef(CONFIG_GPIO_MMIO32 gpio_mmio32.c)
3132
zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c)

drivers/gpio/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ source "drivers/gpio/Kconfig.mcux"
105105

106106
source "drivers/gpio/Kconfig.mcux_igpio"
107107

108+
source "drivers/gpio/Kconfig.mcux_rgpio"
109+
108110
source "drivers/gpio/Kconfig.mcux_lpc"
109111

110112
source "drivers/gpio/Kconfig.mmio32"

drivers/gpio/Kconfig.mcux_rgpio

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# MCUX RGPIO configuration options
2+
3+
# Copyright 2023, NXP
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config GPIO_MCUX_RGPIO
7+
bool "MCUX RGPIO driver"
8+
default y
9+
depends on DT_HAS_NXP_IMX_RGPIO_ENABLED
10+
select PINCTRL
11+
help
12+
Enable the MCUX RGPIO driver.

drivers/gpio/gpio_mcux_rgpio.c

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*
2+
* Copyright 2023, NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nxp_imx_rgpio
8+
9+
#include <errno.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/drivers/gpio.h>
12+
#include <zephyr/drivers/pinctrl.h>
13+
#include <zephyr/irq.h>
14+
#include <fsl_common.h>
15+
#include <fsl_rgpio.h>
16+
17+
#include <zephyr/drivers/gpio/gpio_utils.h>
18+
19+
struct gpio_pin_gaps {
20+
uint8_t start;
21+
uint8_t len;
22+
};
23+
24+
/* Required by DEVICE_MMIO_NAMED_* macros */
25+
#define DEV_CFG(_dev) \
26+
((const struct mcux_rgpio_config *)(_dev)->config)
27+
#define DEV_DATA(_dev) ((struct mcux_rgpio_data *)(_dev)->data)
28+
29+
struct mcux_rgpio_config {
30+
/* gpio_driver_config needs to be first */
31+
struct gpio_driver_config common;
32+
33+
DEVICE_MMIO_NAMED_ROM(reg_base);
34+
35+
const struct pinctrl_soc_pinmux *pin_muxes;
36+
const struct gpio_pin_gaps *pin_gaps;
37+
uint8_t mux_count;
38+
uint8_t gap_count;
39+
};
40+
41+
struct mcux_rgpio_data {
42+
/* gpio_driver_data needs to be first */
43+
struct gpio_driver_data general;
44+
45+
DEVICE_MMIO_NAMED_RAM(reg_base);
46+
47+
/* port ISR callback routine address */
48+
sys_slist_t callbacks;
49+
};
50+
51+
static int mcux_rgpio_configure(const struct device *dev,
52+
gpio_pin_t pin, gpio_flags_t flags)
53+
{
54+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
55+
const struct mcux_rgpio_config *config = dev->config;
56+
57+
struct pinctrl_soc_pin pin_cfg;
58+
int cfg_idx = pin, i;
59+
60+
/* Some SOCs have non-contiguous gpio pin layouts, account for this */
61+
for (i = 0; i < config->gap_count; i++) {
62+
if (pin >= config->pin_gaps[i].start) {
63+
if (pin < (config->pin_gaps[i].start +
64+
config->pin_gaps[i].len)) {
65+
/* Pin is not connected to a mux */
66+
return -ENOTSUP;
67+
}
68+
cfg_idx -= config->pin_gaps[i].len;
69+
}
70+
}
71+
72+
/* Init pin configuration struct, and use pinctrl api to apply settings */
73+
if (cfg_idx >= config->mux_count) {
74+
/* Pin is not connected to a mux */
75+
return -ENOTSUP;
76+
}
77+
78+
/* Set appropriate bits in pin configuration register */
79+
volatile uint32_t *gpio_cfg_reg = (volatile uint32_t *)
80+
((size_t)config->pin_muxes[cfg_idx].config_register);
81+
uint32_t reg = *gpio_cfg_reg;
82+
83+
/* TODO: Default flags, work for i.MX 9352 */
84+
if ((flags & GPIO_SINGLE_ENDED) != 0) {
85+
/* Set ODE bit */
86+
reg |= (0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT);
87+
} else {
88+
reg &= ~(0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT);
89+
}
90+
if (((flags & GPIO_PULL_UP) != 0) || ((flags & GPIO_PULL_DOWN) != 0)) {
91+
/* i.MX93 has no pull enable bit */
92+
if (((flags & GPIO_PULL_UP) != 0)) {
93+
reg |= (0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT);
94+
reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT);
95+
} else {
96+
reg |= (0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT);
97+
reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT);
98+
}
99+
} else {
100+
/* Set pin to highz */
101+
reg &= ~((0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT) |
102+
(0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT));
103+
}
104+
105+
memcpy(&pin_cfg.pinmux, &config->pin_muxes[cfg_idx], sizeof(pin_cfg));
106+
/* cfg register will be set by pinctrl_configure_pins */
107+
pin_cfg.pin_ctrl_flags = reg;
108+
pinctrl_configure_pins(&pin_cfg, 1, PINCTRL_REG_NONE);
109+
110+
if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
111+
return -ENOTSUP;
112+
}
113+
114+
if (flags & GPIO_OUTPUT_INIT_HIGH) {
115+
RGPIO_WritePinOutput(base, pin, 1);
116+
}
117+
118+
if (flags & GPIO_OUTPUT_INIT_LOW) {
119+
RGPIO_WritePinOutput(base, pin, 0);
120+
}
121+
122+
WRITE_BIT(base->PDDR, pin, flags & GPIO_OUTPUT);
123+
124+
return 0;
125+
}
126+
127+
static int mcux_rgpio_port_get_raw(const struct device *dev, uint32_t *value)
128+
{
129+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
130+
131+
*value = base->PDIR;
132+
133+
return 0;
134+
}
135+
136+
static int mcux_rgpio_port_set_masked_raw(const struct device *dev,
137+
uint32_t mask,
138+
uint32_t value)
139+
{
140+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
141+
142+
base->PDOR = (base->PDOR & ~mask) | (mask & value);
143+
144+
return 0;
145+
}
146+
147+
static int mcux_rgpio_port_set_bits_raw(const struct device *dev,
148+
uint32_t mask)
149+
{
150+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
151+
152+
RGPIO_PortSet(base, mask);
153+
154+
return 0;
155+
}
156+
157+
static int mcux_rgpio_port_clear_bits_raw(const struct device *dev,
158+
uint32_t mask)
159+
{
160+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
161+
162+
RGPIO_PortClear(base, mask);
163+
164+
return 0;
165+
}
166+
167+
static int mcux_rgpio_port_toggle_bits(const struct device *dev,
168+
uint32_t mask)
169+
{
170+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
171+
172+
RGPIO_PortToggle(base, mask);
173+
174+
return 0;
175+
}
176+
177+
static int mcux_rgpio_pin_interrupt_configure(const struct device *dev,
178+
gpio_pin_t pin,
179+
enum gpio_int_mode mode,
180+
enum gpio_int_trig trig)
181+
{
182+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
183+
unsigned int key;
184+
uint8_t irqs, irqc;
185+
186+
irqs = 0; /* only irq0 is used for irq */
187+
188+
if (mode == GPIO_INT_MODE_DISABLED) {
189+
irqc = kRGPIO_InterruptOrDMADisabled;
190+
} else if ((mode == GPIO_INT_MODE_EDGE) &&
191+
(trig == GPIO_INT_TRIG_LOW)) {
192+
irqc = kRGPIO_InterruptFallingEdge;
193+
} else if ((mode == GPIO_INT_MODE_EDGE) &&
194+
(trig == GPIO_INT_TRIG_HIGH)) {
195+
irqc = kRGPIO_InterruptRisingEdge;
196+
} else if ((mode == GPIO_INT_MODE_EDGE) &&
197+
(trig == GPIO_INT_TRIG_BOTH)) {
198+
irqc = kRGPIO_InterruptEitherEdge;
199+
} else if ((mode == GPIO_INT_MODE_LEVEL) &&
200+
(trig == GPIO_INT_TRIG_LOW)) {
201+
irqc = kRGPIO_InterruptLogicZero;
202+
} else if ((mode == GPIO_INT_MODE_LEVEL) &&
203+
(trig == GPIO_INT_TRIG_HIGH)) {
204+
irqc = kRGPIO_InterruptLogicOne;
205+
} else {
206+
return -EINVAL; /* should never end up here */
207+
}
208+
209+
key = irq_lock();
210+
RGPIO_SetPinInterruptConfig(base, pin, irqs, irqc);
211+
irq_unlock(key);
212+
213+
return 0;
214+
}
215+
216+
static int mcux_rgpio_manage_callback(const struct device *dev,
217+
struct gpio_callback *callback,
218+
bool set)
219+
{
220+
struct mcux_rgpio_data *data = dev->data;
221+
222+
return gpio_manage_callback(&data->callbacks, callback, set);
223+
}
224+
225+
static void mcux_rgpio_port_isr(const struct device *dev)
226+
{
227+
RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
228+
struct mcux_rgpio_data *data = dev->data;
229+
uint32_t int_flags;
230+
231+
int_flags = base->ISFR[0]; /* Notice: only irq0 is used for now */
232+
base->ISFR[0] = int_flags;
233+
234+
gpio_fire_callbacks(&data->callbacks, dev, int_flags);
235+
}
236+
237+
static const struct gpio_driver_api mcux_rgpio_driver_api = {
238+
.pin_configure = mcux_rgpio_configure,
239+
.port_get_raw = mcux_rgpio_port_get_raw,
240+
.port_set_masked_raw = mcux_rgpio_port_set_masked_raw,
241+
.port_set_bits_raw = mcux_rgpio_port_set_bits_raw,
242+
.port_clear_bits_raw = mcux_rgpio_port_clear_bits_raw,
243+
.port_toggle_bits = mcux_rgpio_port_toggle_bits,
244+
.pin_interrupt_configure = mcux_rgpio_pin_interrupt_configure,
245+
.manage_callback = mcux_rgpio_manage_callback,
246+
};
247+
248+
/* These macros will declare an array of pinctrl_soc_pinmux types */
249+
#define PINMUX_INIT(node, prop, idx) MCUX_IMX_PINMUX(DT_PROP_BY_IDX(node, prop, idx)),
250+
#define MCUX_RGPIO_PIN_DECLARE(n) \
251+
const struct pinctrl_soc_pinmux mcux_rgpio_pinmux_##n[] = { \
252+
DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), pinmux, PINMUX_INIT) \
253+
}; \
254+
const uint8_t mcux_rgpio_pin_gaps_##n[] = \
255+
DT_INST_PROP_OR(n, gpio_reserved_ranges, {});
256+
#define MCUX_RGPIO_PIN_INIT(n) \
257+
.pin_muxes = mcux_rgpio_pinmux_##n, \
258+
.pin_gaps = (const struct gpio_pin_gaps *)mcux_rgpio_pin_gaps_##n, \
259+
.mux_count = DT_PROP_LEN(DT_DRV_INST(n), pinmux), \
260+
.gap_count = (ARRAY_SIZE(mcux_rgpio_pin_gaps_##n) / 2)
261+
262+
#define MCUX_RGPIO_IRQ_INIT(n, i) \
263+
do { \
264+
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \
265+
DT_INST_IRQ_BY_IDX(n, i, priority), \
266+
mcux_rgpio_port_isr, \
267+
DEVICE_DT_INST_GET(n), 0); \
268+
\
269+
irq_enable(DT_INST_IRQ_BY_IDX(n, i, irq)); \
270+
} while (false)
271+
272+
#define MCUX_RGPIO_INIT(n) \
273+
MCUX_RGPIO_PIN_DECLARE(n) \
274+
static int mcux_rgpio_##n##_init(const struct device *dev); \
275+
\
276+
static const struct mcux_rgpio_config mcux_rgpio_##n##_config = {\
277+
.common = { \
278+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
279+
}, \
280+
DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \
281+
MCUX_RGPIO_PIN_INIT(n) \
282+
}; \
283+
\
284+
static struct mcux_rgpio_data mcux_rgpio_##n##_data; \
285+
\
286+
DEVICE_DT_INST_DEFINE(n, \
287+
mcux_rgpio_##n##_init, \
288+
NULL, \
289+
&mcux_rgpio_##n##_data, \
290+
&mcux_rgpio_##n##_config, \
291+
POST_KERNEL, \
292+
CONFIG_GPIO_INIT_PRIORITY, \
293+
&mcux_rgpio_driver_api); \
294+
\
295+
static int mcux_rgpio_##n##_init(const struct device *dev) \
296+
{ \
297+
DEVICE_MMIO_NAMED_MAP(dev, reg_base, \
298+
K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); \
299+
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \
300+
(MCUX_RGPIO_IRQ_INIT(n, 0);)) \
301+
\
302+
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 1), \
303+
(MCUX_RGPIO_IRQ_INIT(n, 1);)) \
304+
\
305+
return 0; \
306+
}
307+
308+
DT_INST_FOREACH_STATUS_OKAY(MCUX_RGPIO_INIT)

dts/bindings/gpio/nxp,imx-rgpio.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2024, NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: i.MX RGPIO node
5+
6+
compatible: "nxp,imx-rgpio"
7+
8+
include: [gpio-controller.yaml, base.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
rdc:
15+
type: int
16+
description: Set the RDC permission for this peripheral
17+
18+
pinmux:
19+
type: phandles
20+
description: |
21+
IMX pin selection peripheral does not follow specific
22+
pattern for which GPIO port uses which pinmux. Use this property to specify
23+
pinctrl nodes to use for the gpio port when CONFIG_PINCTRL=y. Note that
24+
the order of the nodes matters. The first node for gpio1 will be used
25+
as the pinmux for gpio0, port 0.
26+
27+
"#gpio-cells":
28+
const: 2
29+
30+
gpio-cells:
31+
- pin
32+
- flags

soc/arm64/nxp_imx/mimx9/pinctrl_soc.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, NXP
2+
* Copyright (c) 2022-2023, NXP
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -19,7 +19,6 @@ extern "C" {
1919
#define MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_OD_SHIFT
2020
#define MCUX_IMX_BIAS_PULL_DOWN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PD_SHIFT
2121
#define MCUX_IMX_BIAS_PULL_UP_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PU_SHIFT
22-
#define MCUX_IMX_BIAS_PULL_ENABLE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PE_SHIFT
2322
#define MCUX_IMX_SLEW_RATE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_FSEL1_SHIFT
2423
#define MCUX_IMX_DRIVE_STRENGTH_SHIFT IOMUXC1_SW_PAD_CTL_PAD_DSE_SHIFT
2524
#define MCUX_IMX_INPUT_ENABLE_SHIFT 23 /* Shift to a bit not used by IOMUXC_SW_PAD_CTL */

0 commit comments

Comments
 (0)