Skip to content

Commit dcaf4eb

Browse files
VynDragonnandojve
authored andcommitted
drivers: gpio: bouffalolab: Add bflb gpio driver
Add Bouffalo Lab gpio driver. Signed-off-by: Camille BAUD <[email protected]> Signed-off-by: Gerson Fernando Budke <[email protected]>
1 parent 902bb4e commit dcaf4eb

File tree

8 files changed

+350
-11
lines changed

8 files changed

+350
-11
lines changed

boards/bouffalolab/bl6/bl604e_iot_dvk/bl604e_iot_dvk.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ testing:
1414
- net
1515
- bluetooth
1616
supported:
17+
- gpio
1718
- pinctrl
1819
- uart
1920
vendor: bflb

boards/bouffalolab/bl6/bl604e_iot_dvk/doc/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ The board configuration supports the following hardware features:
3939
+===========+============+=======================+
4040
| MTIMER | on-chip | RISC-V Machine Timer |
4141
+-----------+------------+-----------------------+
42+
| GPIO | on-chip | gpio |
43+
+-----------+------------+-----------------------+
4244
| PINCTRL | on-chip | pin muxing |
4345
+-----------+------------+-----------------------+
4446
| UART | on-chip | serial port-polling; |

drivers/gpio/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_AW9523B gpio_aw9523b.c)
1515
zephyr_library_sources_ifdef(CONFIG_GPIO_AXP192 gpio_axp192.c)
1616
zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c)
1717
zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c)
18+
zephyr_library_sources_ifdef(CONFIG_GPIO_BFLB gpio_bflb.c)
1819
zephyr_library_sources_ifdef(CONFIG_GPIO_BRCMSTB gpio_brcmstb.c)
1920
zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c)
2021
zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c)

drivers/gpio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ source "drivers/gpio/Kconfig.axp192"
105105
source "drivers/gpio/Kconfig.b91"
106106
source "drivers/gpio/Kconfig.bcm2711"
107107
source "drivers/gpio/Kconfig.bd8lb600fs"
108+
source "drivers/gpio/Kconfig.bflb"
108109
source "drivers/gpio/Kconfig.brcmstb"
109110
source "drivers/gpio/Kconfig.cc13xx_cc26xx"
110111
source "drivers/gpio/Kconfig.cc32xx"

drivers/gpio/Kconfig.bflb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2024 MASSDRIVER EI (massdriver.space)
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config GPIO_BFLB
5+
bool "Bouffalo Lab GPIO driver"
6+
depends on DT_HAS_BFLB_BL_GPIO_ENABLED
7+
default y
8+
help
9+
Bouffalo Lab GPIO driver

drivers/gpio/gpio_bflb.c

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
* Copyright (c) 2024 MASSDRIVER EI (massdriver.space)
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT bflb_bl_gpio
8+
9+
#include <zephyr/drivers/gpio.h>
10+
#include <zephyr/drivers/gpio/gpio_utils.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <zephyr/irq.h>
13+
14+
#include <bouffalolab/common/gpio_reg.h>
15+
16+
#include <zephyr/logging/log.h>
17+
LOG_MODULE_REGISTER(gpio_bflb, CONFIG_GPIO_LOG_LEVEL);
18+
19+
#define CLEAR_TIMEOUT_COUNTER 32
20+
21+
/* clang-format off */
22+
23+
struct gpio_bflb_config {
24+
/* gpio_driver_config needs to be first */
25+
struct gpio_driver_config common;
26+
uint32_t base_reg;
27+
void (*irq_config_func)(const struct device *dev);
28+
void (*irq_enable_func)(const struct device *dev);
29+
};
30+
31+
struct gpio_bflb_data {
32+
/* gpio_driver_data needs to be first */
33+
struct gpio_driver_data common;
34+
sys_slist_t callbacks;
35+
};
36+
37+
static int gpio_bflb_port_get_raw(const struct device *dev, uint32_t *value)
38+
{
39+
const struct gpio_bflb_config *const cfg = dev->config;
40+
41+
*value = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL30_OFFSET);
42+
43+
return 0;
44+
}
45+
46+
static int gpio_bflb_port_set_masked_raw(const struct device *dev,
47+
uint32_t mask,
48+
uint32_t value)
49+
{
50+
const struct gpio_bflb_config *const cfg = dev->config;
51+
uint32_t tmp = 0;
52+
53+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
54+
tmp = (tmp & ~mask) | (mask & value);
55+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
56+
57+
return 0;
58+
}
59+
60+
static int gpio_bflb_port_set_bits_raw(const struct device *dev, uint32_t mask)
61+
{
62+
const struct gpio_bflb_config *const cfg = dev->config;
63+
uint32_t tmp = 0;
64+
65+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
66+
tmp |= mask;
67+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
68+
69+
return 0;
70+
}
71+
72+
static int gpio_bflb_port_clear_bits_raw(const struct device *dev, uint32_t mask)
73+
{
74+
const struct gpio_bflb_config *const cfg = dev->config;
75+
uint32_t tmp = 0;
76+
77+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
78+
tmp &= ~mask;
79+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
80+
81+
return 0;
82+
}
83+
84+
static int gpio_bflb_port_toggle_bits(const struct device *dev, uint32_t mask)
85+
{
86+
const struct gpio_bflb_config *const cfg = dev->config;
87+
uint32_t tmp = 0;
88+
89+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
90+
tmp ^= mask;
91+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
92+
93+
return 0;
94+
}
95+
96+
static void gpio_bflb_port_interrupt_configure_mode(const struct device *dev,
97+
uint32_t pin,
98+
enum gpio_int_mode mode,
99+
enum gpio_int_trig trig)
100+
{
101+
const struct gpio_bflb_config *const cfg = dev->config;
102+
uint32_t tmp = 0;
103+
uint8_t trig_mode = 0; /* default to 'sync' mode */
104+
105+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MODE_SET1_OFFSET + ((pin / 10) << 2));
106+
tmp &= ~(0x07 << ((pin % 10) * 3)); /* clear modes */
107+
108+
if ((trig & GPIO_INT_HIGH_1) != 0) {
109+
trig_mode |= 1;
110+
}
111+
112+
if (!(mode & GPIO_INT_EDGE)) {
113+
trig_mode |= 2;
114+
}
115+
116+
tmp |= (trig_mode << ((pin % 10) * 3));
117+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MODE_SET1_OFFSET + ((pin / 10) << 2));
118+
}
119+
120+
static void gpio_bflb_pin_interrupt_clear(const struct device *dev, uint32_t mask)
121+
{
122+
const struct gpio_bflb_config *const cfg = dev->config;
123+
int32_t timeout = CLEAR_TIMEOUT_COUNTER;
124+
125+
sys_write32(mask, cfg->base_reg + GLB_GPIO_INT_CLR1_OFFSET);
126+
127+
while ((sys_read32(cfg->base_reg + GLB_GPIO_INT_STAT1_OFFSET) & mask) != 0
128+
&& timeout > 0) {
129+
--timeout;
130+
}
131+
132+
sys_write32(0x0, cfg->base_reg + GLB_GPIO_INT_CLR1_OFFSET);
133+
}
134+
135+
static int gpio_bflb_pin_interrupt_configure(const struct device *dev,
136+
gpio_pin_t pin,
137+
enum gpio_int_mode mode,
138+
enum gpio_int_trig trig)
139+
{
140+
const struct gpio_bflb_config *const cfg = dev->config;
141+
uint32_t tmp = 0;
142+
143+
/* Disable the interrupt. */
144+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
145+
tmp |= BIT(pin);
146+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
147+
148+
gpio_bflb_port_interrupt_configure_mode(dev, pin, mode, trig);
149+
150+
if (mode != GPIO_INT_MODE_DISABLED) {
151+
/* clear */
152+
gpio_bflb_pin_interrupt_clear(dev, BIT(pin));
153+
154+
/* unmask */
155+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
156+
tmp &= ~BIT(pin);
157+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
158+
} else {
159+
/* mask */
160+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
161+
tmp |= BIT(pin);
162+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_INT_MASK1_OFFSET);
163+
}
164+
165+
/* enable clic interrupt for us as it gets cleared in soc init */
166+
cfg->irq_enable_func(dev);
167+
return 0;
168+
}
169+
170+
static int gpio_bflb_config(const struct device *dev, gpio_pin_t pin,
171+
gpio_flags_t flags)
172+
{
173+
const struct gpio_bflb_config *const cfg = dev->config;
174+
uint8_t is_odd = 0;
175+
uint32_t cfg_address;
176+
uint32_t tmp = 0;
177+
uint32_t tmp_a = 0;
178+
uint32_t tmp_b = 0;
179+
180+
/* Disable output anyway */
181+
tmp_a = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2));
182+
tmp_a &= ~(1 << (pin & 0x1f));
183+
sys_write32(tmp_a, cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2));
184+
185+
is_odd = pin & 1;
186+
cfg_address = cfg->base_reg + GLB_GPIO_CFGCTL0_OFFSET + (pin / 2 * 4);
187+
tmp_b = sys_read32(cfg_address);
188+
189+
tmp_a = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2));
190+
191+
if ((flags & GPIO_INPUT) != 0) {
192+
tmp_b |= (1 << (is_odd * 16 + 0));
193+
tmp_a &= ~(1 << (pin & 0x1f));
194+
} else {
195+
tmp_b &= ~(1 << (is_odd * 16 + 0));
196+
}
197+
198+
if ((flags & GPIO_OUTPUT) != 0) {
199+
tmp_a |= (1 << (pin & 0x1f));
200+
tmp_b &= ~(1 << (is_odd * 16 + 0));
201+
202+
if (flags & GPIO_OUTPUT_INIT_HIGH) {
203+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
204+
tmp = tmp | pin;
205+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
206+
}
207+
208+
if (flags & GPIO_OUTPUT_INIT_LOW) {
209+
tmp = sys_read32(cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
210+
tmp = tmp & ~pin;
211+
sys_write32(tmp, cfg->base_reg + GLB_GPIO_CFGCTL32_OFFSET);
212+
}
213+
} else {
214+
tmp_a &= ~(1 << (pin & 0x1f));
215+
}
216+
217+
sys_write32(tmp_a, cfg->base_reg + GLB_GPIO_CFGCTL34_OFFSET + ((pin >> 5) << 2));
218+
219+
if ((flags & GPIO_PULL_UP) != 0) {
220+
tmp_b |= (1 << (is_odd * 16 + 4));
221+
tmp_b &= ~(1 << (is_odd * 16 + 5));
222+
} else if ((flags & GPIO_PULL_DOWN) != 0) {
223+
tmp_b |= (1 << (is_odd * 16 + 5));
224+
tmp_b &= ~(1 << (is_odd * 16 + 4));
225+
} else {
226+
tmp_b &= ~(1 << (is_odd * 16 + 4));
227+
tmp_b &= ~(1 << (is_odd * 16 + 5));
228+
}
229+
230+
/* GPIO mode */
231+
tmp_b &= ~(0x1f << (is_odd * 16 + 8));
232+
tmp_b |= (11 << (is_odd * 16 + 8));
233+
234+
/* enabled SMT in GPIO mode */
235+
tmp_b |= (1 << (is_odd * 16 + 1));
236+
237+
sys_write32(tmp_b, cfg_address);
238+
239+
return 0;
240+
}
241+
242+
static int gpio_bflb_init(const struct device *dev)
243+
{
244+
const struct gpio_bflb_config *const cfg = dev->config;
245+
246+
/* nothing to do beside link irq */
247+
248+
cfg->irq_config_func(dev);
249+
250+
return 0;
251+
}
252+
253+
static void gpio_bflb_isr(const struct device *dev)
254+
{
255+
const struct gpio_bflb_config *const cfg = dev->config;
256+
struct gpio_bflb_data *data = dev->data;
257+
uint32_t int_stat;
258+
259+
/* interrupt data is in format 1 bit = 1 pin */
260+
int_stat = sys_read32(cfg->base_reg + GLB_GPIO_INT_STAT1_OFFSET);
261+
262+
gpio_fire_callbacks(&data->callbacks, dev, int_stat);
263+
264+
/* clear interrupts */
265+
gpio_bflb_pin_interrupt_clear(dev, int_stat);
266+
}
267+
268+
static int gpio_bflb_manage_callback(const struct device *port,
269+
struct gpio_callback *callback,
270+
bool set)
271+
{
272+
struct gpio_bflb_data *data = port->data;
273+
274+
return gpio_manage_callback(&(data->callbacks), callback, set);
275+
}
276+
277+
static const struct gpio_driver_api gpio_bflb_api = {
278+
.pin_configure = gpio_bflb_config,
279+
.port_get_raw = gpio_bflb_port_get_raw,
280+
.port_set_masked_raw = gpio_bflb_port_set_masked_raw,
281+
.port_set_bits_raw = gpio_bflb_port_set_bits_raw,
282+
.port_clear_bits_raw = gpio_bflb_port_clear_bits_raw,
283+
.port_toggle_bits = gpio_bflb_port_toggle_bits,
284+
.pin_interrupt_configure = gpio_bflb_pin_interrupt_configure,
285+
.manage_callback = gpio_bflb_manage_callback,
286+
};
287+
288+
#define GPIO_BFLB_INIT(n) \
289+
static void port_##n##_bflb_irq_config_func(const struct device *dev); \
290+
static void port_##n##_bflb_irq_enable_func(const struct device *dev); \
291+
\
292+
static const struct gpio_bflb_config port_##n##_bflb_config = { \
293+
.common = { \
294+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
295+
}, \
296+
.base_reg = DT_INST_REG_ADDR(n), \
297+
.irq_config_func = port_##n##_bflb_irq_config_func, \
298+
.irq_enable_func = port_##n##_bflb_irq_enable_func, \
299+
}; \
300+
\
301+
static struct gpio_bflb_data port_##n##_bflb_data; \
302+
\
303+
DEVICE_DT_INST_DEFINE(n, gpio_bflb_init, NULL, \
304+
&port_##n##_bflb_data, \
305+
&port_##n##_bflb_config, PRE_KERNEL_1, \
306+
CONFIG_GPIO_INIT_PRIORITY, \
307+
&gpio_bflb_api); \
308+
\
309+
static void port_##n##_bflb_irq_config_func(const struct device *dev) \
310+
{ \
311+
IRQ_CONNECT(DT_INST_IRQN(n), \
312+
DT_INST_IRQ(n, priority), \
313+
gpio_bflb_isr, \
314+
DEVICE_DT_INST_GET(n), 0); \
315+
} \
316+
\
317+
static void port_##n##_bflb_irq_enable_func(const struct device *dev) \
318+
{ \
319+
irq_enable(DT_INST_IRQN(n)); \
320+
}
321+
322+
DT_INST_FOREACH_STATUS_OKAY(GPIO_BFLB_INIT)
323+
324+
/* clang-format on */

dts/bindings/gpio/bflb,bl-gpio.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ include:
1111
- name: gpio-controller.yaml
1212

1313
properties:
14-
reg:
15-
required: true
14+
reg:
15+
required: true
1616

17-
interrupts:
18-
required: true
17+
interrupts:
18+
required: true
1919

20-
"#gpio-cells":
21-
const: 2
20+
"#gpio-cells":
21+
const: 2
2222

23-
"#bflb,pin-cells":
24-
type: int
25-
required: true
26-
const: 2
27-
description: Number of items to expect in a bflb,pins specifier
23+
"#bflb,pin-cells":
24+
type: int
25+
required: true
26+
const: 2
27+
description: Number of items to expect in a bflb,pins specifier
2828

2929
gpio-cells:
3030
- pin

0 commit comments

Comments
 (0)