Skip to content

Commit f8017dc

Browse files
gmarullnandojve
authored andcommitted
drivers: pinctrl: gd32: initial support for AFIO based SoCs
Add a pin control driver for GD32 SoCs using the AFIO model. Thanks to Gerson Fernando Budke for testing and implementation suggestions. Co-authored-by: Gerson Fernando Budke <[email protected]> Signed-off-by: Gerard Marull-Paretas <[email protected]>
1 parent 5c44620 commit f8017dc

File tree

7 files changed

+428
-5
lines changed

7 files changed

+428
-5
lines changed

drivers/pinctrl/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
zephyr_library()
55
zephyr_library_sources(common.c)
66
zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c)
7+
zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AFIO pinctrl_gd32_afio.c)

drivers/pinctrl/Kconfig.gd32

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF := gd,gd32-pinctrl-af
5+
DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AFIO := gd,gd32-pinctrl-afio
56

67
config PINCTRL_GD32_AF
78
bool "GD32 AF pin controller driver"
@@ -10,3 +11,11 @@ config PINCTRL_GD32_AF
1011
help
1112
GD32 AF pin controller driver. This driver is used by series using the
1213
AF pin multiplexing model.
14+
15+
config PINCTRL_GD32_AFIO
16+
bool "GD32 AFIO pin controller driver"
17+
depends on SOC_FAMILY_GD32 && GD32_HAS_AFIO_PINMUX
18+
default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AFIO))
19+
help
20+
GD32 AFIO pin controller driver. This driver is used by series using the
21+
AFIO pin multiplexing model.
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright (c) 2021 Teslabs Engineering S.L.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <drivers/pinctrl.h>
8+
9+
/** AFIO DT node */
10+
#define AFIO_NODE DT_NODELABEL(afio)
11+
12+
/** GPIO mode: input floating (CTL bits) */
13+
#define GPIO_MODE_INP_FLOAT 0x4U
14+
/** GPIO mode: input with pull-up/down (CTL bits) */
15+
#define GPIO_MODE_INP_PUPD 0x8U
16+
/** GPIO mode: output push-pull (CTL bits) */
17+
#define GPIO_MODE_ALT_PP 0x8U
18+
/** GPIO mode: output open-drain (CTL bits) */
19+
#define GPIO_MODE_ALT_OD 0xCU
20+
21+
/** Utility macro that expands to the GPIO port address if it exists */
22+
#define GD32_PORT_ADDR_OR_NONE(nodelabel) \
23+
COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \
24+
(DT_REG_ADDR(DT_NODELABEL(nodelabel)),), ())
25+
26+
/** Utility macro that expands to the GPIO RCU if it exists */
27+
#define GD32_PORT_RCU_OR_NONE(nodelabel) \
28+
COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \
29+
(DT_PROP(DT_NODELABEL(nodelabel), rcu_periph_clock),), ())
30+
31+
/** GD32 port addresses */
32+
static const uint32_t gd32_port_addrs[] = {
33+
GD32_PORT_ADDR_OR_NONE(gpioa)
34+
GD32_PORT_ADDR_OR_NONE(gpiob)
35+
GD32_PORT_ADDR_OR_NONE(gpioc)
36+
GD32_PORT_ADDR_OR_NONE(gpiod)
37+
GD32_PORT_ADDR_OR_NONE(gpioe)
38+
GD32_PORT_ADDR_OR_NONE(gpiof)
39+
GD32_PORT_ADDR_OR_NONE(gpiog)
40+
};
41+
42+
/** GD32 port RCUs */
43+
static const uint32_t gd32_port_rcus[] = {
44+
GD32_PORT_RCU_OR_NONE(gpioa)
45+
GD32_PORT_RCU_OR_NONE(gpiob)
46+
GD32_PORT_RCU_OR_NONE(gpioc)
47+
GD32_PORT_RCU_OR_NONE(gpiod)
48+
GD32_PORT_RCU_OR_NONE(gpioe)
49+
GD32_PORT_RCU_OR_NONE(gpiof)
50+
GD32_PORT_RCU_OR_NONE(gpiog)
51+
};
52+
53+
/**
54+
* @brief Initialize AFIO
55+
*
56+
* This function enables AFIO clock and configures the I/O compensation if
57+
* available and enabled in Devicetree.
58+
*
59+
* @retval 0 Always
60+
*/
61+
static int afio_init(const struct device *dev)
62+
{
63+
ARG_UNUSED(dev);
64+
65+
rcu_periph_clock_enable(DT_PROP(AFIO_NODE, rcu_periph_clock));
66+
67+
#ifdef AFIO_CPSCTL
68+
if (DT_PROP(AFIO_NODE, enable_cps)) {
69+
gpio_compensation_config(GPIO_COMPENSATION_ENABLE);
70+
while (gpio_compensation_flag_get() == RESET)
71+
;
72+
}
73+
#endif /* AFIO_CPSCTL */
74+
75+
return 0;
76+
}
77+
78+
SYS_INIT(afio_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
79+
80+
/**
81+
* @brief Helper function to configure the SPD register if available.
82+
*
83+
* @param port GPIO port address.
84+
* @param pin_bit GPIO pin, set as bit position.
85+
* @param speed GPIO speed.
86+
*
87+
* @return Value of the mode register (speed) that should be set later.
88+
*/
89+
static inline uint8_t configure_spd(uint32_t port, uint32_t pin_bit,
90+
uint8_t speed)
91+
{
92+
switch (speed) {
93+
case GD32_OSPEED_MAX:
94+
#ifdef GPIOx_SPD
95+
GPIOx_SPD(port) |= pin_bit;
96+
#endif /* GPIOx_SPD */
97+
return speed;
98+
default:
99+
#ifdef GPIOx_SPD
100+
GPIOx_SPD(port) &= ~pin_bit;
101+
#endif /* GPIOx_SPD */
102+
return speed + 1U;
103+
}
104+
}
105+
106+
/**
107+
* @brief Configure a pin.
108+
*
109+
* @param pin The pin to configure.
110+
*/
111+
static void configure_pin(pinctrl_soc_pin_t pin)
112+
{
113+
uint8_t port_idx, mode, pin_num;
114+
uint32_t rcu, port, pin_bit, reg_val;
115+
volatile uint32_t *reg;
116+
117+
port_idx = GD32_PORT_GET(pin);
118+
__ASSERT_NO_MSG(port_idx < ARRAY_SIZE(gd32_port_addrs));
119+
120+
rcu = gd32_port_rcus[port_idx];
121+
port = gd32_port_addrs[port_idx];
122+
pin_num = GD32_PIN_GET(pin);
123+
pin_bit = BIT(pin_num);
124+
mode = GD32_MODE_GET(pin);
125+
126+
if (pin_num < 8U) {
127+
reg = &GPIO_CTL0(port);
128+
} else {
129+
reg = &GPIO_CTL1(port);
130+
pin_num -= 8U;
131+
}
132+
133+
rcu_periph_clock_enable(rcu);
134+
135+
reg_val = *reg;
136+
reg_val &= ~GPIO_MODE_MASK(pin_num);
137+
138+
if (mode == GD32_MODE_ALTERNATE) {
139+
uint8_t mode;
140+
141+
mode = configure_spd(port, pin_bit, GD32_OSPEED_GET(pin));
142+
143+
if (GD32_OTYPE_GET(pin) == GD32_OTYPE_PP) {
144+
mode |= GPIO_MODE_ALT_PP;
145+
} else {
146+
mode |= GPIO_MODE_ALT_OD;
147+
}
148+
149+
reg_val |= GPIO_MODE_SET(pin_num, mode);
150+
} else if (mode == GD32_MODE_GPIO_IN) {
151+
uint8_t pupd = GD32_PUPD_GET(pin);
152+
153+
if (pupd == GD32_PUPD_NONE) {
154+
reg_val |= GPIO_MODE_SET(pin_num, GPIO_MODE_INP_FLOAT);
155+
} else {
156+
reg_val |= GPIO_MODE_SET(pin_num, GPIO_MODE_INP_PUPD);
157+
158+
if (pupd == GD32_PUPD_PULLDOWN) {
159+
GPIO_BC(port) = pin_bit;
160+
} else if (pupd == GD32_PUPD_PULLUP) {
161+
GPIO_BOP(port) = pin_bit;
162+
}
163+
}
164+
}
165+
166+
*reg = reg_val;
167+
168+
rcu_periph_clock_disable(rcu);
169+
}
170+
171+
/**
172+
* @brief Configure remap.
173+
*
174+
* @param remap Remap bit field as encoded by #GD32_REMAP.
175+
*/
176+
static void configure_remap(uint16_t remap)
177+
{
178+
uint8_t pos;
179+
uint32_t reg_val;
180+
volatile uint32_t *reg;
181+
182+
/* not remappable */
183+
if (remap == GD32_NORMP) {
184+
return;
185+
}
186+
187+
if (GD32_REMAP_REG_GET(remap) == 0U) {
188+
reg = &AFIO_PCF0;
189+
} else {
190+
reg = &AFIO_PCF1;
191+
}
192+
193+
pos = GD32_REMAP_POS_GET(remap);
194+
195+
reg_val = *reg;
196+
reg_val &= ~(GD32_REMAP_MSK_GET(remap) << pos);
197+
reg_val |= GD32_REMAP_VAL_GET(remap) << pos;
198+
*reg = reg_val;
199+
}
200+
201+
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
202+
uintptr_t reg)
203+
{
204+
ARG_UNUSED(reg);
205+
206+
if (pin_cnt == 0U) {
207+
return -EINVAL;
208+
}
209+
210+
/* same remap is encoded in all pins, so just pick the first */
211+
configure_remap(GD32_REMAP_GET(pins[0]));
212+
213+
/* configure all pins */
214+
for (uint8_t i = 0U; i < pin_cnt; i++) {
215+
configure_pin(pins[i]);
216+
}
217+
218+
return 0;
219+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright (c) 2021 Teslabs Engineering S.L.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
The AFIO peripheral is used to configure pin remapping, EXTI sources and,
6+
when available, enable the I/O compensation cell.
7+
8+
compatible: "gd,gd32-afio"
9+
10+
include: base.yaml
11+
12+
properties:
13+
reg:
14+
required: true
15+
16+
label:
17+
required: true
18+
19+
rcu-periph-clock:
20+
type: int
21+
description: Reset Control Unit Peripheral Clock ID
22+
required: true
23+
24+
enable-cps:
25+
required: false
26+
type: boolean
27+
description: |
28+
Enable the I/O compensation cell. This option should be enabled when the
29+
output speed is greater than 50MHz to reduce the I/O noise effects on
30+
the power supply. This option is only available on certain GD32 series.

0 commit comments

Comments
 (0)