drivers: pinctrl: gd32: initial support for AF based SoCs

Add a pin control driver for GD32 SoCs using the AF model.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
This commit is contained in:
Gerard Marull-Paretas 2021-11-01 21:37:04 +01:00 committed by Anas Nashif
commit 543a3843ff
11 changed files with 455 additions and 0 deletions

View file

@ -3,3 +3,4 @@
zephyr_library()
zephyr_library_sources(common.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_GD32_AF pinctrl_gd32_af.c)

View file

@ -29,4 +29,6 @@ config PINCTRL_DYNAMIC
runtime. This can be useful, for example, to change the pins assigned to a
peripheral at early boot stages depending on a certain input.
source "drivers/pinctrl/Kconfig.gd32"
endif # PINCTRL

View file

@ -0,0 +1,12 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# SPDX-License-Identifier: Apache-2.0
DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF := gd,gd32-pinctrl-af
config PINCTRL_GD32_AF
bool "GD32 AF pin controller driver"
depends on SOC_FAMILY_GD32 && GD32_HAS_AF_PINMUX
default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_PINCTRL_AF))
help
GD32 AF pin controller driver. This driver is used by series using the
AF pin multiplexing model.

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2021 Teslabs Engineering S.L.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <drivers/pinctrl.h>
BUILD_ASSERT((GD32_PUPD_NONE == GPIO_PUPD_NONE) &&
(GD32_PUPD_PULLUP == GPIO_PUPD_PULLUP) &&
(GD32_PUPD_PULLDOWN == GPIO_PUPD_PULLDOWN),
"pinctrl pull-up/down definitions != HAL definitions");
BUILD_ASSERT((GD32_OTYPE_PP == GPIO_OTYPE_PP) &&
(GD32_OTYPE_OD == GPIO_OTYPE_OD),
"pinctrl output type definitions != HAL definitions");
BUILD_ASSERT((GD32_OSPEED_2MHZ == GPIO_OSPEED_2MHZ) &&
(GD32_OSPEED_25MHZ == GPIO_OSPEED_25MHZ) &&
(GD32_OSPEED_50MHZ == GPIO_OSPEED_50MHZ) &&
(GD32_OSPEED_200MHZ == GPIO_OSPEED_200MHZ),
"pinctrl output speed definitions != HAL definitions");
/** Utility macro that expands to the GPIO port address if it exists */
#define GD32_PORT_ADDR_OR_NONE(nodelabel) \
COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \
(DT_REG_ADDR(DT_NODELABEL(nodelabel)),), ())
/** Utility macro that expands to the GPIO RCU if it exists */
#define GD32_PORT_RCU_OR_NONE(nodelabel) \
COND_CODE_1(DT_NODE_EXISTS(DT_NODELABEL(nodelabel)), \
(DT_PROP(DT_NODELABEL(nodelabel), rcu_periph_clock),), ())
/** GD32 port addresses */
static const uint32_t gd32_port_addrs[] = {
GD32_PORT_ADDR_OR_NONE(gpioa)
GD32_PORT_ADDR_OR_NONE(gpiob)
GD32_PORT_ADDR_OR_NONE(gpioc)
GD32_PORT_ADDR_OR_NONE(gpiod)
GD32_PORT_ADDR_OR_NONE(gpioe)
GD32_PORT_ADDR_OR_NONE(gpiof)
GD32_PORT_ADDR_OR_NONE(gpiog)
GD32_PORT_ADDR_OR_NONE(gpioh)
GD32_PORT_ADDR_OR_NONE(gpioi)
};
/** GD32 port RCUs */
static const uint32_t gd32_port_rcus[] = {
GD32_PORT_RCU_OR_NONE(gpioa)
GD32_PORT_RCU_OR_NONE(gpiob)
GD32_PORT_RCU_OR_NONE(gpioc)
GD32_PORT_RCU_OR_NONE(gpiod)
GD32_PORT_RCU_OR_NONE(gpioe)
GD32_PORT_RCU_OR_NONE(gpiof)
GD32_PORT_RCU_OR_NONE(gpiog)
GD32_PORT_RCU_OR_NONE(gpioh)
GD32_PORT_RCU_OR_NONE(gpioi)
};
/**
* @brief Configure a pin.
*
* @param pin The pin to configure.
*/
static void pinctrl_configure_pin(pinctrl_soc_pin_t pin)
{
uint8_t port_idx;
uint32_t rcu, port, pin_num, af, mode;
port_idx = GD32_PORT_GET(pin);
__ASSERT_NO_MSG(port_idx < ARRAY_SIZE(gd32_port_addrs));
rcu = gd32_port_rcus[port_idx];
port = gd32_port_addrs[port_idx];
pin_num = BIT(GD32_PIN_GET(pin));
af = GD32_AF_GET(pin);
rcu_periph_clock_enable(rcu);
if (af != GD32_ANALOG) {
mode = GPIO_MODE_AF;
gpio_af_set(port, af, pin_num);
} else {
mode = GPIO_MODE_ANALOG;
}
gpio_mode_set(port, mode, GD32_PUPD_GET(pin), pin_num);
gpio_output_options_set(port, GD32_OTYPE_GET(pin),
GD32_OSPEED_GET(pin), pin_num);
rcu_periph_clock_disable(rcu);
}
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
uintptr_t reg)
{
ARG_UNUSED(reg);
for (uint8_t i = 0U; i < pin_cnt; i++) {
pinctrl_configure_pin(pins[i]);
}
return 0;
}

View file

@ -0,0 +1,27 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# SPDX-License-Identifier: Apache-2.0
description: GD32 GPIO node
compatible: "gd,gd32-gpio"
include: [gpio-controller.yaml, base.yaml]
properties:
reg:
required: true
label:
required: true
rcu-periph-clock:
type: int
description: Reset Control Unit Peripheral Clock ID
required: true
"#gpio-cells":
const: 2
gpio-cells:
- pin
- flags

View file

@ -0,0 +1,111 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# SPDX-License-Identifier: Apache-2.0
description: |
The GD32 pin controller (AF model) is a singleton node responsible for
controlling pin function selection and pin properties. For example, you can
use this node to route USART0 RX to pin PA10 and enable the pull-up resistor
on the pin.
The node has the 'pinctrl' node label set in your SoC's devicetree,
so you can modify it like this:
&pinctrl {
/* your modifications go here */
};
All device pin configurations should be placed in child nodes of the
'pinctrl' node, as shown in this example:
/* You can put this in places like a board-pinctrl.dtsi file in
* your board directory, or a devicetree overlay in your application.
*/
/* include pre-defined combinations for the SoC variant used by the board */
#include <dt-bindings/pinctrl/gd32f450i(g-i-k)xx-pinctrl.h>
&pinctrl {
/* configuration for the usart0 "default" state */
usart0_default: usart0_default {
/* group 1 */
group1 {
/* configure PA9 as USART0 TX and PA11 as USART0 CTS */
pinmux = <USART0_TX_PA9>, <USART0_CTS_PA11>;
};
/* group 2 */
group2 {
/* configure PA10 as USART0 RX and PA12 as USART0 RTS */
pinmux = <USART0_RX_PA10>, <USART0_RTS_PA12>;
/* both PA10 and PA12 have pull-up enabled */
bias-pull-up;
};
/* configuration for the usart0 "sleep" state */
usart0_sleep: usart0_sleep {
/* group 1 */
group1 {
/* configure PA9, PA10, PA11 and PA12 in analog mode */
pinmux = <ANALOG_PA9>, <ANALOG_PA10>, <ANALOG_PA12>, <ANALOG_PA11>;
};
};
The 'usart0_default' child node encodes the pin configurations for a
particular state of a device; in this case, the default (that is, active)
state. Similarly, 'usart0_sleep' child node encodes the pin configurations
for the sleep state (used in device low power mode). Note that analog mode
is used for low power states because it disconnects the pin pull-up/down
resistor, schmitt trigger, and output buffer.
As shown, pin configurations are organized in groups within each child node.
Each group can specify a list of pin function selections in the 'pinmux'
property.
A group can also specify shared pin properties common to all the specified
pins, such as the 'bias-pull-up' property in group 2. Here is a list of
supported standard pin properties:
- drive-push-pull: Push-pull drive mode (default, not required).
- drive-open-drain: Open-drain drive mode.
- bias-disable: Disable pull-up/down (default, not required).
- bias-pull-up: Enable pull-up resistor.
- bias-pull-down: Enable pull-down resistor.
- slew-rate: Set the maximum speed (and so the slew-rate) of the output
signal (default: 2MHz).
Note that drive and bias options are mutually exclusive.
To link pin configurations with a device, use a pinctrl-N property for some
number N, like this example you could place in your board's DTS file:
#include "board-pinctrl.dtsi"
&usart0 {
pinctrl-0 = <&usart0_default>;
pinctrl-1 = <&usart0_sleep>;
pinctrl-names = "default", "sleep";
};
compatible: "gd,gd32-pinctrl-af"
include: gd,gd32-pinctrl-common.yaml
child-binding:
description: |
Each child node defines the configuration for a particular state.
child-binding:
description: |
The grandchild nodes group pins that share the same pin configuration.
properties:
slew-rate:
required: false
type: string
default: "max-speed-2mhz"
enum:
- "max-speed-2mhz"
- "max-speed-25mhz"
- "max-speed-50mhz"
- "max-speed-200mhz"
description: |
Set the maximum speed of a pin. This setting effectively limits the
slew rate of the output signal. Defaults to "max-speed-2mhz", the SoC
default.

View file

@ -0,0 +1,26 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# SPDX-License-Identifier: Apache-2.0
include:
- name: base.yaml
- name: pincfg-node-group.yaml
child-binding:
child-binding:
property-allowlist:
- drive-push-pull
- drive-open-drain
- bias-disable
- bias-pull-down
- bias-pull-up
child-binding:
child-binding:
properties:
pinmux:
required: true
type: array
description: |
An array of pins sharing the same group properties. The pins should
be defined using pre-defined macros or, alternatively, using the
GD32_PINMUX_AF or GD32_PINMUX_AFIO utility macros depending on the
pinmux model used by the SoC series.

View file

@ -4,6 +4,11 @@
config ZEPHYR_HAL_GIGADEVICE_MODULE
bool
config GD32_HAS_AF_PINMUX
bool
help
This option should be selected if the series use an AF pinmux model.
config HAS_GD32_HAL
bool
select HAS_CMSIS_CORE if SOC_FAMILY_GD32_ARM

View file

@ -1,4 +1,5 @@
# Copyright (c) 2021, ATL Electronics
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(common)
add_subdirectory(${SOC_SERIES})

View file

@ -0,0 +1,4 @@
# Copyright (c) 2021 Teslabs Engineering S.L.
# SPDX-License-Identifier: Apache-2.0
zephyr_include_directories(.)

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2021 Teslabs Engineering S.L.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* Gigadevice SoC specific helpers for pinctrl driver
*/
#ifndef ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_
#define ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_
#include <devicetree.h>
#include <dt-bindings/pinctrl/gd32-af.h>
#include <zephyr/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @cond INTERNAL_HIDDEN */
/** @brief Type for GD32 pin.
*
* Bits:
* - 0-12: GD32_PINMUX_AF bit field.
* - 13-25: Reserved.
* - 26-31: Pin configuration bit field (@ref GD32_PINCFG).
*/
typedef uint32_t pinctrl_soc_pin_t;
/**
* @brief Utility macro to initialize each pin.
*
* @param node_id Node identifier.
* @param prop Property name.
* @param idx Property entry index.
*/
#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \
(DT_PROP_BY_IDX(node_id, prop, idx) | \
((GD32_PUPD_PULLUP * DT_PROP(node_id, bias_pull_up)) \
<< GD32_PUPD_POS) | \
((GD32_PUPD_PULLDOWN * DT_PROP(node_id, bias_pull_down)) \
<< GD32_PUPD_POS) | \
((GD32_OTYPE_OD * DT_PROP(node_id, drive_open_drain)) \
<< GD32_OTYPE_POS) | \
(DT_ENUM_IDX(node_id, slew_rate) << GD32_OSPEED_POS)),
/**
* @brief Utility macro to initialize state pins contained in a given property.
*
* @param node_id Node identifier.
* @param prop Property name describing state pins.
*/
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
{DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \
DT_FOREACH_PROP_ELEM, pinmux, \
Z_PINCTRL_STATE_PIN_INIT)}
/** @endcond */
/**
* @name GD32 PUPD (values match the ones in the HAL).
* @{
*/
/** No pull-up/down */
#define GD32_PUPD_NONE 0U
/** Pull-up */
#define GD32_PUPD_PULLUP 1U
/** Pull-down */
#define GD32_PUPD_PULLDOWN 2U
/** @} */
/**
* @name GD32 OTYPE (values match the ones in the HAL).
* @{
*/
/** Push-pull */
#define GD32_OTYPE_PP 0U
/** Open-drain */
#define GD32_OTYPE_OD 1U
/** @} */
/**
* @name GD32 OSPEED (values match the ones in the HAL).
* @{
*/
/** Maximum 2MHz */
#define GD32_OSPEED_2MHZ 0U
/** Maximum 25MHz */
#define GD32_OSPEED_25MHZ 1U
/** Maximum 50MHz */
#define GD32_OSPEED_50MHZ 2U
/** Maximum 200MHz */
#define GD32_OSPEED_200MHZ 3U
/** @} */
/**
* @name GD32 pin configuration bit field mask and positions.
* @anchor GD32_PINCFG
*
* Fields:
*
* - 31..29: Pull-up/down
* - 28: Output type
* - 27..26: Output speed
*
* @{
*/
/** PUPD field mask. */
#define GD32_PUPD_MSK 0x3U
/** PUPD field position. */
#define GD32_PUPD_POS 29U
/** OTYPE field mask. */
#define GD32_OTYPE_MSK 0x1U
/** OTYPE field position. */
#define GD32_OTYPE_POS 28U
/** OSPEED field mask. */
#define GD32_OSPEED_MSK 0x3U
/** OSPEED field position. */
#define GD32_OSPEED_POS 26U
/** @} */
/**
* Obtain PUPD field from pinctrl_soc_pin_t configuration.
*
* @param pincfg pinctrl_soc_pin_t bit field value.
*/
#define GD32_PUPD_GET(pincfg) \
(((pincfg) >> GD32_PUPD_POS) & GD32_PUPD_MSK)
/**
* Obtain OTYPE field from pinctrl_soc_pin_t configuration.
*
* @param pincfg pinctrl_soc_pin_t bit field value.
*/
#define GD32_OTYPE_GET(pincfg) \
(((pincfg) >> GD32_OTYPE_POS) & GD32_OTYPE_MSK)
/**
* Obtain OSPEED field from pinctrl_soc_pin_t configuration.
*
* @param pincfg pinctrl_soc_pin_t bit field value.
*/
#define GD32_OSPEED_GET(pincfg) \
(((pincfg) >> GD32_OSPEED_POS) & GD32_OSPEED_MSK)
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_SOC_ARM_GIGADEVICE_COMMON_PINCTRL_SOC_H_ */