Skip to content

Commit 290ae4b

Browse files
gmarullcfriedt
authored andcommitted
drivers: gpio: sf32lb: add initial driver
Add initial driver for SF32LB. Signed-off-by: Gerard Marull-Paretas <[email protected]>
1 parent c89b3a8 commit 290ae4b

File tree

4 files changed

+346
-0
lines changed

4 files changed

+346
-0
lines changed

drivers/gpio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SAM0 gpio_sam0.c)
102102
zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c)
103103
zephyr_library_sources_ifdef(CONFIG_GPIO_SAM_PIO4 gpio_sam_pio4.c)
104104
zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c)
105+
zephyr_library_sources_ifdef(CONFIG_GPIO_SF32LB gpio_sf32lb.c)
105106
zephyr_library_sources_ifdef(CONFIG_GPIO_SI32 gpio_si32.c)
106107
zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c)
107108
zephyr_library_sources_ifdef(CONFIG_GPIO_SILABS gpio_silabs.c)

drivers/gpio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ source "drivers/gpio/Kconfig.sam"
184184
source "drivers/gpio/Kconfig.sam0"
185185
source "drivers/gpio/Kconfig.sc18im704"
186186
source "drivers/gpio/Kconfig.sedi"
187+
source "drivers/gpio/Kconfig.sf32lb"
187188
source "drivers/gpio/Kconfig.si32"
188189
source "drivers/gpio/Kconfig.sifive"
189190
source "drivers/gpio/Kconfig.silabs"

drivers/gpio/Kconfig.sf32lb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2025 Core Devices LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config GPIO_SF32LB
5+
bool "SiFli SF32LB GPIO driver"
6+
default y
7+
depends on DT_HAS_SIFLI_SF32LB_GPIO_ENABLED
8+
help
9+
Enable GPIO driver for SiFli SF32LB

drivers/gpio/gpio_sf32lb.c

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
/*
2+
* Copyright (c) 2025 Core Devices LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT sifli_sf32lb_gpio
7+
8+
#include <stdint.h>
9+
10+
#include <zephyr/arch/cpu.h>
11+
#include <zephyr/drivers/gpio.h>
12+
#include <zephyr/drivers/gpio/gpio_utils.h>
13+
#include <zephyr/drivers/clock_control/sf32lb.h>
14+
#include <zephyr/irq.h>
15+
#include <zephyr/sys/math_extras.h>
16+
17+
#include <register.h>
18+
19+
#define GPIO1_DIRX offsetof(GPIO1_TypeDef, DIR0)
20+
#define GPIO1_DORX offsetof(GPIO1_TypeDef, DOR0)
21+
#define GPIO1_DOSRX offsetof(GPIO1_TypeDef, DOSR0)
22+
#define GPIO1_DOCRX offsetof(GPIO1_TypeDef, DOCR0)
23+
#define GPIO1_DOERX offsetof(GPIO1_TypeDef, DOER0)
24+
#define GPIO1_DOESRX offsetof(GPIO1_TypeDef, DOESR0)
25+
#define GPIO1_DOECRX offsetof(GPIO1_TypeDef, DOECR0)
26+
#define GPIO1_IESRX offsetof(GPIO1_TypeDef, IESR0)
27+
#define GPIO1_IECRX offsetof(GPIO1_TypeDef, IECR0)
28+
#define GPIO1_ISRX offsetof(GPIO1_TypeDef, ISR0)
29+
#define GPIO1_ITSRX offsetof(GPIO1_TypeDef, ITSR0)
30+
#define GPIO1_ITCRX offsetof(GPIO1_TypeDef, ITCR0)
31+
#define GPIO1_IPHCRX offsetof(GPIO1_TypeDef, IPHCR0)
32+
#define GPIO1_IPLCRX offsetof(GPIO1_TypeDef, IPLCR0)
33+
#define GPIO1_IPHSRX offsetof(GPIO1_TypeDef, IPHSR0)
34+
#define GPIO1_IPLSRX offsetof(GPIO1_TypeDef, IPLSR0)
35+
36+
#define PINMUX_PAD_XXYY_PE BIT(4)
37+
#define PINMUX_PAD_XXYY_PS_PUP BIT(5)
38+
#define PINMUX_PAD_XXYY_IE BIT(6)
39+
#define PINMUX_PAD_XXYY_SR_SLOW BIT(8)
40+
41+
struct gpio_sf32lb_config {
42+
struct gpio_driver_config common;
43+
uintptr_t gpio;
44+
uintptr_t pinmux;
45+
};
46+
47+
struct gpio_sf32lb_data {
48+
struct gpio_driver_data common;
49+
sys_slist_t callbacks;
50+
gpio_port_pins_t od;
51+
};
52+
53+
static bool shared_initialized;
54+
static const struct device *controllers[] = {
55+
DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_INST_PARENT(0), DEVICE_DT_GET, (,)),
56+
};
57+
58+
BUILD_ASSERT((DT_NODE_HAS_COMPAT(DT_INST_PARENT(0), sifli_sf32lb_gpio_parent)) &&
59+
(DT_NUM_INST_STATUS_OKAY(sifli_sf32lb_gpio_parent) == 1),
60+
"Only one parent instance is supported");
61+
62+
static void gpio_sf32lb_irq(const void *arg)
63+
{
64+
for (size_t c = 0U; c < ARRAY_SIZE(controllers); c++) {
65+
const struct gpio_sf32lb_config *config = controllers[c]->config;
66+
struct gpio_sf32lb_data *data = controllers[c]->data;
67+
uint8_t min, max;
68+
uint32_t val;
69+
70+
min = u32_count_trailing_zeros(config->common.port_pin_mask);
71+
max = 32 - u32_count_leading_zeros(config->common.port_pin_mask);
72+
73+
val = sys_read32(config->gpio + GPIO1_ISRX);
74+
for (uint8_t i = min; i < max; i++) {
75+
if ((val & BIT(i)) != 0U) {
76+
gpio_fire_callbacks(&data->callbacks, controllers[c], BIT(i));
77+
}
78+
}
79+
sys_write32(val, config->gpio + GPIO1_ISRX);
80+
}
81+
}
82+
83+
static inline int gpio_sf32lb_configure(const struct device *port, gpio_pin_t pin,
84+
gpio_flags_t flags)
85+
{
86+
const struct gpio_sf32lb_config *config = port->config;
87+
struct gpio_sf32lb_data *data = port->data;
88+
uint32_t val;
89+
90+
if ((flags & GPIO_OUTPUT) != 0U) {
91+
/* disable ISR */
92+
sys_write32(BIT(pin), config->gpio + GPIO1_IECRX);
93+
94+
if ((flags & GPIO_SINGLE_ENDED) != 0U) {
95+
if ((flags & GPIO_LINE_OPEN_DRAIN) == 0U) {
96+
return -ENOTSUP;
97+
}
98+
99+
data->od |= BIT(pin);
100+
101+
/* disable O */
102+
sys_write32(BIT(pin), config->gpio + GPIO1_DOCRX);
103+
104+
/* set initial state (OE) */
105+
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
106+
sys_write32(BIT(pin), config->gpio + GPIO1_DOESRX);
107+
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
108+
sys_write32(BIT(pin), config->gpio + GPIO1_DOECRX);
109+
}
110+
} else {
111+
data->od &= ~BIT(pin);
112+
113+
/* enable OE */
114+
sys_write32(BIT(pin), config->gpio + GPIO1_DOESRX);
115+
116+
/* set initial state (O) */
117+
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
118+
sys_write32(BIT(pin), config->gpio + GPIO1_DOSRX);
119+
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
120+
sys_write32(BIT(pin), config->gpio + GPIO1_DOCRX);
121+
}
122+
}
123+
} else if ((flags & GPIO_INPUT) != 0U) {
124+
data->od &= ~BIT(pin);
125+
126+
/* disable OE */
127+
sys_write32(BIT(pin), config->gpio + GPIO1_DOECRX);
128+
} else {
129+
return -ENOTSUP;
130+
}
131+
132+
/* configure pad settings in PINMUX */
133+
val = PINMUX_PAD_XXYY_SR_SLOW;
134+
135+
if ((flags & GPIO_INPUT) != 0U) {
136+
val |= PINMUX_PAD_XXYY_IE;
137+
}
138+
139+
if ((flags & GPIO_PULL_UP) != 0U) {
140+
val |= PINMUX_PAD_XXYY_PE | PINMUX_PAD_XXYY_PS_PUP;
141+
} else if ((flags & GPIO_PULL_DOWN) != 0U) {
142+
val |= PINMUX_PAD_XXYY_PE;
143+
}
144+
145+
sys_write32(val, config->pinmux + (pin * 4U));
146+
147+
return 0;
148+
}
149+
150+
static int gpio_sf32lb_port_get_raw(const struct device *port, uint32_t *value)
151+
{
152+
const struct gpio_sf32lb_config *config = port->config;
153+
154+
*value = sys_read32(config->gpio + GPIO1_DIRX);
155+
156+
return 0;
157+
}
158+
159+
static int gpio_sf32lb_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask,
160+
gpio_port_value_t value)
161+
{
162+
const struct gpio_sf32lb_config *config = port->config;
163+
struct gpio_sf32lb_data *data = port->data;
164+
gpio_port_pins_t pp_mask, od_mask;
165+
uint32_t val;
166+
167+
pp_mask = mask & ~data->od;
168+
if (pp_mask != 0U) {
169+
val = sys_read32(config->gpio + GPIO1_DORX);
170+
val = (val & ~pp_mask) | (value & pp_mask);
171+
sys_write32(val, config->gpio + GPIO1_DORX);
172+
}
173+
174+
od_mask = mask & data->od;
175+
if (od_mask != 0U) {
176+
val = sys_read32(config->gpio + GPIO1_DOERX);
177+
val = (val & ~od_mask) | (value & od_mask);
178+
sys_write32(val, config->gpio + GPIO1_DOERX);
179+
}
180+
181+
return 0;
182+
}
183+
184+
static int gpio_sf32lb_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins)
185+
{
186+
const struct gpio_sf32lb_config *config = port->config;
187+
struct gpio_sf32lb_data *data = port->data;
188+
gpio_port_pins_t pp_pins, od_pins;
189+
190+
pp_pins = pins & ~data->od;
191+
sys_write32(pp_pins, config->gpio + GPIO1_DOSRX);
192+
193+
od_pins = pins & data->od;
194+
sys_write32(od_pins, config->gpio + GPIO1_DOESRX);
195+
196+
return 0;
197+
}
198+
199+
static int gpio_sf32lb_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins)
200+
{
201+
const struct gpio_sf32lb_config *config = port->config;
202+
struct gpio_sf32lb_data *data = port->data;
203+
gpio_port_pins_t pp_pins, od_pins;
204+
205+
pp_pins = pins & ~data->od;
206+
sys_write32(pp_pins, config->gpio + GPIO1_DOCRX);
207+
208+
od_pins = pins & data->od;
209+
sys_write32(od_pins, config->gpio + GPIO1_DOECRX);
210+
211+
return 0;
212+
}
213+
214+
static int gpio_sf32lb_port_toggle_bits(const struct device *port, gpio_port_pins_t pins)
215+
{
216+
const struct gpio_sf32lb_config *config = port->config;
217+
struct gpio_sf32lb_data *data = port->data;
218+
gpio_port_pins_t pp_pins, od_pins;
219+
uint32_t val;
220+
221+
pp_pins = pins & ~data->od;
222+
if (pp_pins != 0U) {
223+
val = sys_read32(config->gpio + GPIO1_DORX);
224+
val ^= pp_pins;
225+
sys_write32(val, config->gpio + GPIO1_DORX);
226+
}
227+
228+
od_pins = pins & data->od;
229+
if (od_pins != 0U) {
230+
val = sys_read32(config->gpio + GPIO1_DOERX);
231+
val ^= od_pins;
232+
sys_write32(val, config->gpio + GPIO1_DOERX);
233+
}
234+
235+
return 0;
236+
}
237+
238+
static int gpio_sf32lb_pin_interrupt_configure(const struct device *port, gpio_pin_t pin,
239+
enum gpio_int_mode mode, enum gpio_int_trig trig)
240+
{
241+
const struct gpio_sf32lb_config *config = port->config;
242+
243+
if (mode == GPIO_INT_MODE_DISABLED) {
244+
sys_write32(BIT(pin), config->gpio + GPIO1_IECRX);
245+
} else if ((mode == GPIO_INT_MODE_EDGE) || (mode == GPIO_INT_MODE_LEVEL)) {
246+
if (mode == GPIO_INT_MODE_EDGE) {
247+
sys_write32(BIT(pin), config->gpio + GPIO1_ITSRX);
248+
} else {
249+
sys_write32(BIT(pin), config->gpio + GPIO1_ITCRX);
250+
}
251+
252+
switch (trig) {
253+
case GPIO_INT_TRIG_LOW:
254+
sys_write32(BIT(pin), config->gpio + GPIO1_IPHCRX);
255+
sys_write32(BIT(pin), config->gpio + GPIO1_IPLSRX);
256+
break;
257+
case GPIO_INT_TRIG_HIGH:
258+
sys_write32(BIT(pin), config->gpio + GPIO1_IPHSRX);
259+
sys_write32(BIT(pin), config->gpio + GPIO1_IPLCRX);
260+
break;
261+
case GPIO_INT_TRIG_BOTH:
262+
sys_write32(BIT(pin), config->gpio + GPIO1_IPHSRX);
263+
sys_write32(BIT(pin), config->gpio + GPIO1_IPLSRX);
264+
break;
265+
default:
266+
return -ENOTSUP;
267+
}
268+
269+
sys_write32(BIT(pin), config->gpio + GPIO1_IESRX);
270+
} else {
271+
return -ENOTSUP;
272+
}
273+
274+
return 0;
275+
}
276+
277+
static int gpio_sf32lb_manage_callback(const struct device *dev, struct gpio_callback *callback,
278+
bool set)
279+
{
280+
struct gpio_sf32lb_data *data = dev->data;
281+
282+
return gpio_manage_callback(&data->callbacks, callback, set);
283+
}
284+
285+
static DEVICE_API(gpio, gpio_sf32lb_api) = {
286+
.pin_configure = gpio_sf32lb_configure,
287+
.port_get_raw = gpio_sf32lb_port_get_raw,
288+
.port_set_masked_raw = gpio_sf32lb_port_set_masked_raw,
289+
.port_set_bits_raw = gpio_sf32lb_port_set_bits_raw,
290+
.port_clear_bits_raw = gpio_sf32lb_port_clear_bits_raw,
291+
.port_toggle_bits = gpio_sf32lb_port_toggle_bits,
292+
.pin_interrupt_configure = gpio_sf32lb_pin_interrupt_configure,
293+
.manage_callback = gpio_sf32lb_manage_callback,
294+
};
295+
296+
static int gpio_sf32lb_init(const struct device *dev)
297+
{
298+
if (!shared_initialized) {
299+
struct sf32lb_clock_dt_spec clk = SF32LB_CLOCK_DT_SPEC_GET(DT_INST_PARENT(0));
300+
301+
if (!sf3232lb_clock_is_ready_dt(&clk)) {
302+
return -ENODEV;
303+
}
304+
305+
(void)sf32lb_clock_control_on_dt(&clk);
306+
307+
IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(0)), DT_IRQ(DT_INST_PARENT(0), priority),
308+
gpio_sf32lb_irq, NULL, 0);
309+
irq_enable(DT_IRQN(DT_INST_PARENT(0)));
310+
311+
shared_initialized = true;
312+
}
313+
314+
return 0;
315+
}
316+
317+
#define GPIO_SF32LB_DEFINE(n) \
318+
static const struct gpio_sf32lb_config gpio_sf32lb_config##n = { \
319+
.common = \
320+
{ \
321+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
322+
}, \
323+
.gpio = DT_INST_REG_ADDR(n), \
324+
.pinmux = DT_REG_ADDR_BY_IDX(DT_INST_PHANDLE(n, sifli_pinmuxs), \
325+
DT_INST_PHA(n, sifli_pinmuxs, port)) + \
326+
DT_INST_PHA(n, sifli_pinmuxs, offset), \
327+
}; \
328+
\
329+
static struct gpio_sf32lb_data gpio_sf32lb_data##n; \
330+
\
331+
DEVICE_DT_INST_DEFINE(n, gpio_sf32lb_init, NULL, &gpio_sf32lb_data##n, \
332+
&gpio_sf32lb_config##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
333+
&gpio_sf32lb_api);
334+
335+
DT_INST_FOREACH_STATUS_OKAY(GPIO_SF32LB_DEFINE)

0 commit comments

Comments
 (0)