drivers: gpio: Add xmc4xxx drivers

Adds gpio drivers for xmc4xxx SoCs.

Signed-off-by: Andriy Gelman <andriy.gelman@gmail.com>
This commit is contained in:
Andriy Gelman 2022-07-16 11:47:59 -04:00 committed by Carles Cufí
parent a57001347f
commit af6179d567
8 changed files with 312 additions and 1 deletions

View file

@ -60,3 +60,4 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SN74HC595 gpio_sn74hc595.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_MCHP_MSS gpio_mchp_mss.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_SHELL gpio_shell.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE gpio_handlers.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XMC4XXX gpio_xmc4xxx.c)

View file

@ -144,4 +144,6 @@ source "drivers/gpio/Kconfig.sn74hc595"
source "drivers/gpio/Kconfig.mchp_mss"
source "drivers/gpio/Kconfig.xmc4xxx"
endif # GPIO

View file

@ -0,0 +1,11 @@
# XMC4XXX GPIO configuration
#
# Copyright (c) 2022 Schlumberger
# SPDX-License-Identifier: Apache-2.0
config GPIO_XMC4XXX
bool "XMC4XXX GPIO driver"
default y
depends on DT_HAS_INFINEON_XMC4XXX_GPIO_ENABLED
help
Enable GPIO driver for XMC4XXX line of MCUs

189
drivers/gpio/gpio_xmc4xxx.c Normal file
View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2022 Schlumberger
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT infineon_xmc4xxx_gpio
#include <errno.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/dt-bindings/gpio/infineon-xmc4xxx-gpio.h>
#include <xmc_gpio.h>
#include "gpio_utils.h"
struct gpio_xmc4xxx_config {
/* gpio_driver_config needs to be first, required by Zephyr */
struct gpio_driver_config common;
XMC_GPIO_PORT_t *port;
};
struct gpio_xmc4xxx_data {
/* gpio_driver_data needs to be first, required by Zephyr */
struct gpio_driver_data common;
};
static int gpio_xmc4xxx_convert_flags(XMC_GPIO_CONFIG_t *pin_config, gpio_flags_t flags)
{
bool is_input = flags & GPIO_INPUT;
bool is_output = flags & GPIO_OUTPUT;
int ds;
/* GPIO_DISCONNECTED */
if (!is_input && !is_output) {
return -ENOTSUP;
}
if (flags & GPIO_OPEN_SOURCE) {
return -ENOTSUP;
}
if (is_input) {
pin_config->mode = XMC_GPIO_MODE_INPUT_TRISTATE;
if (flags & GPIO_PULL_DOWN) {
pin_config->mode = XMC_GPIO_MODE_INPUT_PULL_DOWN;
}
if (flags & GPIO_PULL_UP) {
pin_config->mode = XMC_GPIO_MODE_INPUT_PULL_UP;
}
}
ds = XMC4XXX_GPIO_GET_DS(flags);
if ((!is_output && ds) || ds > XMC4XXX_GPIO_DS_WEAK) {
return -EINVAL;
}
if (is_output) {
pin_config->mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL;
if (flags & GPIO_OPEN_DRAIN) {
pin_config->mode = XMC_GPIO_MODE_OUTPUT_OPEN_DRAIN;
}
if (flags & GPIO_OUTPUT_INIT_LOW) {
pin_config->output_level = XMC_GPIO_OUTPUT_LEVEL_LOW;
}
if (flags & GPIO_OUTPUT_INIT_HIGH) {
pin_config->output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH;
}
/* Strong medium edge is default */
pin_config->output_strength = XMC_GPIO_OUTPUT_STRENGTH_STRONG_MEDIUM_EDGE;
if (ds > 0) {
pin_config->output_strength = ds - 1;
}
}
return 0;
}
static int gpio_xmc4xxx_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
XMC_GPIO_CONFIG_t pin_config = {0};
gpio_port_pins_t pin_mask = config->common.port_pin_mask;
int ret;
if ((BIT(pin) & pin_mask) == 0) {
return -EINVAL;
}
ret = gpio_xmc4xxx_convert_flags(&pin_config, flags);
if (ret) {
return ret;
}
XMC_GPIO_Init(port, pin, &pin_config);
return 0;
}
static int gpio_xmc4xxx_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
enum gpio_int_mode mode, enum gpio_int_trig trig)
{
ARG_UNUSED(dev);
ARG_UNUSED(pin);
ARG_UNUSED(mode);
ARG_UNUSED(trig);
/* TODO: interrupt controller */
return -ENOTSUP;
}
static int gpio_xmc4xxx_get_raw(const struct device *dev, gpio_port_value_t *value)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
gpio_port_pins_t pin_mask = config->common.port_pin_mask;
*value = port->IN & pin_mask;
return 0;
}
static int gpio_xmc4xxx_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
gpio_port_value_t value)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
gpio_port_pins_t pin_mask = config->common.port_pin_mask;
mask &= pin_mask;
/* OMR - output modification register. Upper 16 bits is used to clear pins */
port->OMR = (value & mask) | (~value & mask) << 16;
return 0;
}
static int gpio_xmc4xxx_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
gpio_port_pins_t pin_mask = config->common.port_pin_mask;
port->OMR = pins & pin_mask;
return 0;
}
static int gpio_xmc4xxx_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
port->OMR = pins << 16;
return 0;
}
static int gpio_xmc4xxx_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
{
const struct gpio_xmc4xxx_config *config = dev->config;
XMC_GPIO_PORT_t *port = config->port;
gpio_port_pins_t pin_mask = config->common.port_pin_mask;
pins &= pin_mask;
port->OMR = pins | pins << 16;
return 0;
}
static int gpio_xmc4xxx_init(const struct device *dev) { return 0; }
static const struct gpio_driver_api gpio_xmc4xxx_driver_api = {
.pin_configure = gpio_xmc4xxx_pin_configure,
.port_get_raw = gpio_xmc4xxx_get_raw,
.port_set_masked_raw = gpio_xmc4xxx_set_masked_raw,
.port_set_bits_raw = gpio_xmc4xxx_set_bits_raw,
.port_clear_bits_raw = gpio_xmc4xxx_clear_bits_raw,
.port_toggle_bits = gpio_xmc4xxx_toggle_bits,
.pin_interrupt_configure = gpio_xmc4xxx_pin_interrupt_configure,
};
#define GPIO_XMC4XXX_INIT(index) \
static struct gpio_xmc4xxx_data xmc4xxx_data_##index; \
\
static const struct gpio_xmc4xxx_config xmc4xxx_config_##index = { \
.port = (XMC_GPIO_PORT_t *)DT_INST_REG_ADDR(index), \
.common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(index)}}; \
\
DEVICE_DT_INST_DEFINE(index, gpio_xmc4xxx_init, NULL, &xmc4xxx_data_##index, \
&xmc4xxx_config_##index, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \
&gpio_xmc4xxx_driver_api);
DT_INST_FOREACH_STATUS_OKAY(GPIO_XMC4XXX_INIT)

View file

@ -23,3 +23,45 @@
&flash0 {
reg = <0xc000000 DT_SIZE_M(1)>;
};
&gpio0 {
ngpios = <13>;
};
&gpio1 {
ngpios = <16>;
};
&gpio2 {
ngpios = <13>;
};
&soc {
gpio3: gpio@48028300 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028300 0x100>;
ngpios = <7>;
status = "disabled";
};
gpio4: gpio@48028400 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028400 0x100>;
ngpios = <2>;
status = "disabled";
};
gpio5: gpio@48028500 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028500 0x100>;
ngpios = <4>;
status = "disabled";
};
};

View file

@ -6,6 +6,8 @@
*/
#include <arm/armv7-m.dtsi>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/gpio/infineon-xmc4xxx-gpio.h>
/ {
cpus {
@ -41,7 +43,32 @@
#clock-cells = <0>;
};
soc {
soc: soc {
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";
};
gpio2: gpio@48028200 {
compatible = "infineon,xmc4xxx-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x48028200 0x100>;
status = "disabled";
};
usic0ch0: usic@40030000 {
reg = <0x40030000 0x1ff>;
clocks = <&sysclk>;

View file

@ -0,0 +1,16 @@
description: INFINEON XMC4XXX GPIO PORT node
compatible: "infineon,xmc4xxx-gpio"
include: [gpio-controller.yaml, base.yaml]
properties:
reg:
required: true
"#gpio-cells":
const: 2
gpio-cells:
- pin
- flags

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Schlumberger
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_INFINEON_XMC4XXX_GPIO_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_INFINEON_XMC4XXX_GPIO_H_
#define XMC4XXX_GPIO_DS_POS 9
#define XMC4XXX_GPIO_DS_MASK 0xf
/* GPIO driver will use XMC_GPIO_OUTPUT_STRENGTH_STRONG_MEDIUM_EDGE if DS is unset */
#define XMC4XXX_GPIO_DS_STRONG_SHARP_EDGE (0x1 << XMC4XXX_GPIO_DS_POS)
#define XMC4XXX_GPIO_DS_STRONG_MEDIUM_EDGE (0x2 << XMC4XXX_GPIO_DS_POS)
#define XMC4XXX_GPIO_DS_STRONG_SOFT_EDGE (0x3 << XMC4XXX_GPIO_DS_POS)
#define XMC4XXX_GPIO_DS_STRONG_SLOW_EDGE (0x4 << XMC4XXX_GPIO_DS_POS)
#define XMC4XXX_GPIO_DS_MEDIUM (0x5 << XMC4XXX_GPIO_DS_POS)
/* values 5, 6 not set in xmc4_gpio.h */
#define XMC4XXX_GPIO_DS_WEAK (0x8 << XMC4XXX_GPIO_DS_POS)
#define XMC4XXX_GPIO_GET_DS(flags) ((flags >> XMC4XXX_GPIO_DS_POS) & XMC4XXX_GPIO_DS_MASK)
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_INFINEON_XMC4XXX_GPIO_H_ */