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:
parent
a57001347f
commit
af6179d567
|
@ -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)
|
||||
|
|
|
@ -144,4 +144,6 @@ source "drivers/gpio/Kconfig.sn74hc595"
|
|||
|
||||
source "drivers/gpio/Kconfig.mchp_mss"
|
||||
|
||||
source "drivers/gpio/Kconfig.xmc4xxx"
|
||||
|
||||
endif # GPIO
|
||||
|
|
11
drivers/gpio/Kconfig.xmc4xxx
Normal file
11
drivers/gpio/Kconfig.xmc4xxx
Normal 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
189
drivers/gpio/gpio_xmc4xxx.c
Normal 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)
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
16
dts/bindings/gpio/infineon,xmc4xxx-gpio.yaml
Normal file
16
dts/bindings/gpio/infineon,xmc4xxx-gpio.yaml
Normal 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
|
23
include/zephyr/dt-bindings/gpio/infineon-xmc4xxx-gpio.h
Normal file
23
include/zephyr/dt-bindings/gpio/infineon-xmc4xxx-gpio.h
Normal 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_ */
|
Loading…
Reference in a new issue