Commit af6179d5 authored by Andriy Gelman's avatar Andriy Gelman Committed by Carles Cufi
Browse files

drivers: gpio: Add xmc4xxx drivers

Adds gpio drivers for xmc4xxx SoCs.

Signed-off-by: default avatarAndriy Gelman <andriy.gelman@gmail.com>
parent a5700134
Loading
Loading
Loading
Loading
+1 −0
Changes for drivers/gpio/CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -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)
+2 −0
Changes for drivers/gpio/Kconfig: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -144,4 +144,6 @@ source "drivers/gpio/Kconfig.sn74hc595"

source "drivers/gpio/Kconfig.mchp_mss"

source "drivers/gpio/Kconfig.xmc4xxx"

endif # GPIO
+11 −0
Changes for drivers/gpio/Kconfig.xmc4xxx: 11 added lines, 0 removed lines.
Original line number Diff line number Diff line
# 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 −0
Changes for drivers/gpio/gpio_xmc4xxx.c: 189 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*
 * 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)
+42 −0
Changes for dts/arm/infineon/xmc4500_F100x1024.dtsi: 42 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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";
	};
};
Loading