drivers: pinctrl: Add pinctrl driver for xmc4xxx

Add pinctrl driver for infineon xmc4xxx devices.

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
Andriy Gelman 2022-07-14 10:01:23 -04:00 committed by Anas Nashif
parent 105cd84eb7
commit 5feae0eafc
12 changed files with 437 additions and 23 deletions

View file

@ -24,3 +24,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ESP32 pinctrl_esp32.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_RV32M1 pinctrl_rv32m1.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_XLNX_ZYNQ pinctrl_xlnx_zynq.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_SMARTBOND pinctrl_smartbond.c)
zephyr_library_sources_ifdef(CONFIG_PINCTRL_XMC4XXX pinctrl_xmc4xxx.c)

View file

@ -53,5 +53,6 @@ source "drivers/pinctrl/Kconfig.esp32"
source "drivers/pinctrl/Kconfig.rv32m1"
source "drivers/pinctrl/Kconfig.xlnx"
source "drivers/pinctrl/Kconfig.smartbond"
source "drivers/pinctrl/Kconfig.xmc4xxx"
endif # PINCTRL

View file

@ -0,0 +1,9 @@
# Copyright (c) 2022 Schlumberger
# SPDX-License-Identifier: Apache-2.0
config PINCTRL_XMC4XXX
bool "XMC4XXX pin controller driver"
default y
depends on DT_HAS_INFINEON_XMC4XXX_PINCTRL_ENABLED
help
Enables XMC4XXX pin controller driver.

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2022 Schlumberger
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT infineon_xmc4xxx_pinctrl
#include <zephyr/devicetree.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h>
#include <xmc_gpio.h>
#define GPIO_REG_SIZE 0x100
static int pinctrl_configure_pin(const pinctrl_soc_pin_t pinmux)
{
int port_id, pin, alt_fun, hwctrl;
XMC_GPIO_CONFIG_t pin_cfg = {0};
XMC_GPIO_PORT_t *gpio_port;
port_id = XMC4XXX_PINMUX_GET_PORT(pinmux);
if (port_id >= DT_INST_REG_SIZE(0) / GPIO_REG_SIZE) {
return -EINVAL;
}
pin = XMC4XXX_PINMUX_GET_PIN(pinmux);
if (XMC4XXX_PINMUX_GET_PULL_DOWN(pinmux)) {
pin_cfg.mode = XMC_GPIO_MODE_INPUT_PULL_DOWN;
}
if (XMC4XXX_PINMUX_GET_PULL_UP(pinmux)) {
pin_cfg.mode = XMC_GPIO_MODE_INPUT_PULL_UP;
}
if (XMC4XXX_PINMUX_GET_INV_INPUT(pinmux)) {
pin_cfg.mode |= 0x4;
}
if (XMC4XXX_PINMUX_GET_OPEN_DRAIN(pinmux)) {
pin_cfg.mode = XMC_GPIO_MODE_OUTPUT_OPEN_DRAIN;
}
if (XMC4XXX_PINMUX_GET_PUSH_PULL(pinmux)) {
pin_cfg.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL;
}
alt_fun = XMC4XXX_PINMUX_GET_ALT(pinmux);
pin_cfg.mode |= alt_fun << PORT0_IOCR0_PC0_Pos;
/* only has effect if mode is push_pull */
if (XMC4XXX_PINMUX_GET_OUT_HIGH(pinmux)) {
pin_cfg.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH;
}
/* only has effect if mode is push_pull */
if (XMC4XXX_PINMUX_GET_OUT_LOW(pinmux)) {
pin_cfg.output_level = XMC_GPIO_OUTPUT_LEVEL_LOW;
}
/* only has effect if mode is push_pull */
pin_cfg.output_strength = XMC4XXX_PINMUX_GET_DRIVE(pinmux);
gpio_port = (XMC_GPIO_PORT_t *)((uint32_t)DT_INST_REG_ADDR(0) + port_id * GPIO_REG_SIZE);
XMC_GPIO_Init(gpio_port, pin, &pin_cfg);
hwctrl = XMC4XXX_PINMUX_GET_HWCTRL(pinmux);
if (hwctrl) {
XMC_GPIO_SetHardwareControl(gpio_port, pin, hwctrl);
}
return 0;
}
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++) {
int ret = pinctrl_configure_pin(*pins++);
if (ret < 0) {
return ret;
}
}
return 0;
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2022 Schlumberger
* SPDX-License-Identifier: Apache-2.0
*/
#include <infineon/xmc4xxx.dtsi>
#include <zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h>
&pinctrl {
/omit-if-no-ref/ uart_tx_p0_1_u1c1: uart_tx_p0_1_u1c1 {
pinmux = <XMC4XXX_PINMUX_SET(0, 1, 2)>;
};
/omit-if-no-ref/ uart_tx_p0_5_u1c0: uart_tx_p0_5_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 2)>;
};
/omit-if-no-ref/ uart_tx_p1_5_u0c0: uart_tx_p1_5_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 2)>;
};
/omit-if-no-ref/ uart_tx_p1_7_u0c0: uart_tx_p1_7_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(1, 7, 2)>;
};
/omit-if-no-ref/ uart_tx_p2_5_u0c1: uart_tx_p2_5_u0c1 {
pinmux = <XMC4XXX_PINMUX_SET(2, 5, 2)>;
};
/omit-if-no-ref/ uart_tx_p2_14_u1c0: uart_tx_p2_14_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 2)>;
};
/omit-if-no-ref/ uart_tx_p3_5_u2c1: uart_tx_p3_5_u2c1 {
pinmux = <XMC4XXX_PINMUX_SET(3, 5, 1)>;
};
/omit-if-no-ref/ uart_tx_p3_5_u0c1: uart_tx_p3_5_u0c1 {
pinmux = <XMC4XXX_PINMUX_SET(3, 5, 4)>;
};
/omit-if-no-ref/ uart_tx_p5_0_u2c0: uart_tx_p5_0_u2c0 {
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 1)>;
};
/omit-if-no-ref/ uart_tx_p5_1_u0c0: uart_tx_p5_1_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(5, 1, 1)>;
};
/omit-if-no-ref/ uart_rx_p1_4_u0c0: uart_rx_p1_4_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(1, 4, 0)>; /* USIC input src = DX0B */
};
/omit-if-no-ref/ uart_rx_p1_5_u0c0: uart_rx_p1_5_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 0)>; /* USIC input src = DX0A */
};
/omit-if-no-ref/ uart_rx_p5_0_u0c0: uart_rx_p5_0_u0c0 {
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0)>; /* USIC input src = DX0D */
};
/omit-if-no-ref/ uart_rx_p2_2_u0c1: uart_rx_p2_2_u0c1 {
pinmux = <XMC4XXX_PINMUX_SET(2, 2, 0)>; /* USIC input src = DX0A */
};
/omit-if-no-ref/ uart_rx_p2_5_u0c1: uart_rx_p2_5_u0c1 {
pinmux = <XMC4XXX_PINMUX_SET(2, 5, 0)>; /* USIC input src = DX0B */
};
/omit-if-no-ref/ uart_rx_p4_0_u0c1: uart_rx_p4_0_u0c1 {
pinmux = <XMC4XXX_PINMUX_SET(4, 0, 0)>; /* USIC input src = DX0E */
};
/omit-if-no-ref/ uart_rx_p0_4_u1c0: uart_rx_p0_4_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(0, 4, 0)>; /* USIC input src = DX0A */
};
/omit-if-no-ref/ uart_rx_p0_5_u1c0: uart_rx_p0_5_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 0)>; /* USIC input src = DX0B */
};
/omit-if-no-ref/ uart_rx_p2_14_u1c0: uart_rx_p2_14_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 0)>; /* USIC input src = DX0D */
};
/omit-if-no-ref/ uart_rx_p2_15_u1c0: uart_rx_p2_15_u1c0 {
pinmux = <XMC4XXX_PINMUX_SET(2, 15, 0)>; /* USIC input src = DX0C */
};
/omit-if-no-ref/ uart_rx_p0_0_u1c1: uart_rx_p0_0_u1c1 {
pinmux = <XMC4XXX_PINMUX_SET(0, 0, 0)>; /* USIC input src = DX0D */
};
/omit-if-no-ref/ uart_rx_p5_0_u2c0: uart_rx_p5_0_u2c0 {
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0)>; /* USIC input src = DX0B */
};
/omit-if-no-ref/ uart_rx_p5_1_u2c0: uart_rx_p5_1_u2c0 {
pinmux = <XMC4XXX_PINMUX_SET(5, 1, 0)>; /* USIC input src = DX0A */
};
/omit-if-no-ref/ uart_rx_p3_4_u2c1: uart_rx_p3_4_u2c1 {
pinmux = <XMC4XXX_PINMUX_SET(3, 4, 0)>; /* USIC input src = DX0B */
};
/omit-if-no-ref/ uart_rx_p3_5_u2c1: uart_rx_p3_5_u2c1 {
pinmux = <XMC4XXX_PINMUX_SET(3, 5, 0)>; /* USIC input src = DX0A */
};
/omit-if-no-ref/ uart_rx_p4_0_u2c1: uart_rx_p4_0_u2c1 {
pinmux = <XMC4XXX_PINMUX_SET(4, 0, 0)>; /* USIC input src = DX0C */
};
};

View file

@ -36,7 +36,8 @@
ngpios = <13>;
};
&soc {
&pinctrl {
reg = <0x48028000 0x600>;
gpio3: gpio@48028300 {
compatible = "infineon,xmc4xxx-gpio";

View file

@ -43,30 +43,36 @@
#clock-cells = <0>;
};
soc: soc {
soc {
pinctrl: pinctrl@48028000 {
compatible = "infineon,xmc4xxx-pinctrl";
#address-cells = <1>;
#size-cells = <1>;
gpio0: gpio@48028000 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028000 0x100>;
status = "disabled";
};
gpio0: gpio@48028000 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028000 0x100>;
status = "disabled";
};
gpio1: gpio@48028100 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028100 0x100>;
status = "disabled";
};
gpio1: gpio@48028100 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028100 0x100>;
status = "disabled";
};
gpio2: gpio@48028200 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028200 0x100>;
status = "disabled";
};
gpio2: gpio@48028200 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028200 0x100>;
status = "disabled";
};
usic0ch0: usic@40030000 {

View file

@ -0,0 +1,112 @@
# Copyright (c) 2022, Andriy Gelman <andriy.gelman@gmail.com>
# SPDX-License-Identifier: Apache-2.0
description: |
The Infineon XMC4XXX pin controller is responsible for connecting peripheral outputs
to specific port/pins (also known as alternate functions) and configures pin properties.
The pinctrl settings are referenced in a device tree peripheral node. For example in a UART
node:
&usic1ch1 {
compatible = "infineon,xmc4xxx-uart";
pinctrl-0 = <&uart_tx_p0_1_u1c1 &uart_rx_p0_0_u1c1>;
pinctrl-names = "default";
input-src = "DX0D";
...
};
pinctrl-0 is the phandle that stores the pin settings for two pins: &uart_tx_p0_1_u1c1
and &uart_rx_p0_0_u1c1. These nodes are pre-defined and their naming convention is designed
to help the user select the correct pin settings. Note the use of peripheral type,
pin direction, port/pin number and USIC in the name.
The pre-defined nodes only set the alternate function of the output pin. The
configuration for the pin (i.e. drive strength) should be set in the board setup.
The set of possible configurations are defined in the properties section below (in addition
to the inherited property-allowlist list from pincfg-node.yaml).
To create a new pin configuration, the user may append to the &pinctrl node, for example
#include <zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h>
&pinctrl {
my_node_config: my_node_config {
pinmux = <XMC4XXX_PINMUX_SET(0, 1, 2)>;
drive-push-pull;
... other supported pin configurations ..
};
where XMC4XXX_PINMUX_SET(PORT, PIN, ALTERNATE_FUNCTION) is a helper macro for setting the
alternate function for a given port/pin. Setting ALTERNATE_FUNCTION = 0 means that no
alternate function is selected.
The pinctrl driver only sets the alternate function for output pins. The input mux is
handled by the peripheral drivers. For example the &usic1ch1 node has input-src property for
this purpose. There are no pre-defined nodes for the input mux and this must be properly set
by the user. Refer to the peripheral .yaml file (i.e. infineon,xmc4xxx-uart.yaml) and
XMC4XXX documentation.
compatible: "infineon,xmc4xxx-pinctrl"
include:
- name: base.yaml
- name: pincfg-node.yaml
child-binding:
property-allowlist:
- bias-pull-down
- bias-pull-up
- drive-push-pull
- drive-open-drain
- output-high
- output-low
properties:
"#address-cells":
required: true
const: 1
"#size-cells":
required: true
const: 1
child-binding:
description: Each child node defines the configuration for a particular state.
properties:
pinmux:
description: |
Encodes port/pin and alternate function. See helper macro XMC4XX_PINMUX_SET().
Alternate function is only set for output pins; It selects ALT1-ALT4
output line in the GPIO element. The alternate function for input pins is
handled separately by the peripheral. It is upto the peripheral to configure which
input pin to use (For example see parameter input-src in infineon,xmc4xxx-uart.yaml).
required: true
type: int
drive-strength:
description: |
Drive strength of the output pin. Following options as in XMC_GPIO_OUTPUT_STRENGTH
See xmc4_gpio.h. This only has an effect if the pin is in drive-push-pull mode.
required: true
type: string
enum:
- "strong-sharp-edge"
- "strong-medium-edge"
- "strong-soft-edge"
- "strong-slow-edge"
- "medium"
- "medium-unknown1-edge"
- "medium-unknown2-edge"
- "weak"
invert-input:
description: Inverts the input.
required: false
type: boolean
hwctrl:
description: Pre-assigns hardware control of the pin to a certain peripheral.
required: true
type: string
enum:
- "disabled"
- "periph1"
- "periph2"

View file

@ -2,7 +2,7 @@ description: INFINEON XMC4XXX UART
compatible: "infineon,xmc4xxx-uart"
include: uart-controller.yaml
include: [uart-controller.yaml, pinctrl-device.yaml]
properties:
reg:

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 Schlumberger
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_XMC4XXX_PINCTRL_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_XMC4XXX_PINCTRL_H_
/* Bit Masks */
#define XMC4XXX_PORT_POS 0
#define XMC4XXX_PORT_MASK 0xf
#define XMC4XXX_PIN_POS 4
#define XMC4XXX_PIN_MASK 0xf
#define XMC4XXX_ALT_POS 8
#define XMC4XXX_ALT_MASK 0xf
#define XMC4XXX_PULL_DOWN_POS 12
#define XMC4XXX_PULL_DOWN_MASK 0x1
#define XMC4XXX_PULL_UP_POS 13
#define XMC4XXX_PULL_UP_MASK 0x1
#define XMC4XXX_PUSH_PULL_POS 14
#define XMC4XXX_PUSH_PULL_MASK 0x1
#define XMC4XXX_OPEN_DRAIN_POS 15
#define XMC4XXX_OPEN_DRAIN_MASK 0x1
#define XMC4XXX_OUT_HIGH_POS 16
#define XMC4XXX_OUT_HIGH_MASK 0x1
#define XMC4XXX_OUT_LOW_POS 17
#define XMC4XXX_OUT_LOW_MASK 0x1
#define XMC4XXX_INV_INPUT_POS 18
#define XMC4XXX_INV_INPUT_MASK 0x1
#define XMC4XXX_DRIVE_POS 19
#define XMC4XXX_DRIVE_MASK 0x7
#define XMC4XXX_HWCTRL_POS 22
#define XMC4XXX_HWCTRL_MASK 0x3
/* Setters and getters */
#define XMC4XXX_PINMUX_SET(port, pin, alt_fun) \
((port) << XMC4XXX_PORT_POS | (pin) << XMC4XXX_PIN_POS | (alt_fun) << XMC4XXX_ALT_POS)
#define XMC4XXX_PINMUX_GET_PORT(mx) ((mx >> XMC4XXX_PORT_POS) & XMC4XXX_PORT_MASK)
#define XMC4XXX_PINMUX_GET_PIN(mx) ((mx >> XMC4XXX_PIN_POS) & XMC4XXX_PIN_MASK)
#define XMC4XXX_PINMUX_GET_ALT(mx) ((mx >> XMC4XXX_ALT_POS) & XMC4XXX_ALT_MASK)
#define XMC4XXX_PINMUX_GET_PULL_DOWN(mx) ((mx >> XMC4XXX_PULL_DOWN_POS) & XMC4XXX_PULL_DOWN_MASK)
#define XMC4XXX_PINMUX_GET_PULL_UP(mx) ((mx >> XMC4XXX_PULL_UP_POS) & XMC4XXX_PULL_UP_MASK)
#define XMC4XXX_PINMUX_GET_PUSH_PULL(mx) ((mx >> XMC4XXX_PUSH_PULL_POS) & XMC4XXX_PUSH_PULL_MASK)
#define XMC4XXX_PINMUX_GET_OPEN_DRAIN(mx) ((mx >> XMC4XXX_OPEN_DRAIN_POS) & XMC4XXX_OPEN_DRAIN_MASK)
#define XMC4XXX_PINMUX_GET_OUT_HIGH(mx) ((mx >> XMC4XXX_OUT_HIGH_POS) & XMC4XXX_OUT_HIGH_MASK)
#define XMC4XXX_PINMUX_GET_OUT_LOW(mx) ((mx >> XMC4XXX_OUT_LOW_POS) & XMC4XXX_OUT_LOW_MASK)
#define XMC4XXX_PINMUX_GET_INV_INPUT(mx) ((mx >> XMC4XXX_INV_INPUT_POS) & XMC4XXX_INV_INPUT_MASK)
#define XMC4XXX_PINMUX_GET_DRIVE(mx) ((mx >> XMC4XXX_DRIVE_POS) & XMC4XXX_DRIVE_MASK)
#define XMC4XXX_PINMUX_GET_HWCTRL(mx) ((mx >> XMC4XXX_HWCTRL_POS) & XMC4XXX_HWCTRL_MASK)
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_XMC4XXX_PINCTRL_H_ */

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 Schlumberger
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SOC_ARM_INFINEON_XMC_4XXX_PINCTRL_SOC_H_
#define ZEPHYR_SOC_ARM_INFINEON_XMC_4XXX_PINCTRL_SOC_H_
#include <stdint.h>
#include <zephyr/devicetree.h>
#include <zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h>
typedef uint32_t pinctrl_soc_pin_t;
#define Z_PINCTRL_STATE_PIN_INIT(node, pr, idx) \
(DT_PROP_BY_PHANDLE_IDX(node, pr, idx, pinmux) | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, bias_pull_down) << XMC4XXX_PULL_DOWN_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, bias_pull_up) << XMC4XXX_PULL_UP_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, drive_push_pull) << XMC4XXX_PUSH_PULL_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, drive_open_drain) << XMC4XXX_OPEN_DRAIN_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, output_high) << XMC4XXX_OUT_HIGH_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, output_low) << XMC4XXX_OUT_LOW_POS | \
DT_PROP_BY_PHANDLE_IDX(node, pr, idx, invert_input) << XMC4XXX_INV_INPUT_POS | \
DT_ENUM_IDX(DT_PHANDLE_BY_IDX(node, pr, idx), drive_strength) << XMC4XXX_DRIVE_POS | \
DT_ENUM_IDX(DT_PHANDLE_BY_IDX(node, pr, idx), hwctrl) << XMC4XXX_HWCTRL_POS),
#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \
{ DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) }
#endif /* ZEPHYR_SOC_ARM_INFINEON_XMC_4XXX_PINCTRL_SOC_H_ */

View file

@ -4,3 +4,10 @@
# Author: Parthiban Nallathambi <parthiban@linumiz.com>
source "soc/arm/infineon_xmc/*/Kconfig.defconfig.series"
if SOC_FAMILY_XMC
config PINCTRL
default y
endif # SOC_FAMILY_XMC