diff --git a/Documentation/devicetree/bindings/mfd/seco,trizeps8-mcu.txt b/Documentation/devicetree/bindings/mfd/seco,trizeps8-mcu.txt
new file mode 100644
index 0000000000000000000000000000000000000000..386eec06cf08d9b7845fb06ec4154544fa0d8109
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/seco,trizeps8-mcu.txt
@@ -0,0 +1,102 @@
+* ROHM BD70528 Power Management Integrated Circuit bindings
+
+BD70528MWV is an ultra-low quiescent current general purpose, single-chip,
+power management IC for battery-powered portable devices. The IC
+integrates 3 ultra-low current consumption buck converters, 3 LDOs and 2
+LED Drivers. Also included are 4 GPIOs, a real-time clock (RTC), a 32kHz
+clock gate, high-accuracy VREF for use with an external ADC, flexible
+dual-input power path, 10 bit SAR ADC for battery temperature monitor and
+1S battery charger with scalable charge currents.
+
+Required properties:
+ - compatible		: Should be "rohm,bd70528"
+ - reg			: I2C slave address.
+ - interrupts		: The interrupt line the device is connected to.
+ - interrupt-controller	: To indicate BD70528 acts as an interrupt controller.
+ - #interrupt-cells	: Should be 2. Usage is compliant to the 2 cells
+			  variant of ../interrupt-controller/interrupts.txt
+ - gpio-controller	: To indicate BD70528 acts as a GPIO controller.
+ - #gpio-cells		: Should be 2. The first cell is the pin number and
+			  the second cell is used to specify flags. See
+			  ../gpio/gpio.txt for more information.
+ - #clock-cells		: Should be 0.
+ - regulators:		: List of child nodes that specify the regulators.
+			  Please see ../regulator/rohm,bd70528-regulator.txt
+
+Optional properties:
+ - clock-output-names	: Should contain name for output clock.
+
+Example:
+/* External oscillator */
+osc: oscillator {
+	compatible = "fixed-clock";
+	#clock-cells = <1>;
+	clock-frequency  = <32768>;
+	clock-output-names = "osc";
+};
+
+pmic: pmic@4b {
+	compatible = "rohm,bd70528";
+	reg = <0x4b>;
+	interrupt-parent = <&gpio1>;
+	interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+	clocks = <&osc 0>;
+	#clock-cells = <0>;
+	clock-output-names = "bd70528-32k-out";
+	#gpio-cells = <2>;
+	gpio-controller;
+	interrupt-controller;
+	#interrupt-cells = <2>;
+
+	regulators {
+		buck1: BUCK1 {
+			regulator-name = "buck1";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <3400000>;
+			regulator-boot-on;
+			regulator-ramp-delay = <125>;
+		};
+		buck2: BUCK2 {
+			regulator-name = "buck2";
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			regulator-ramp-delay = <125>;
+		};
+		buck3: BUCK3 {
+			regulator-name = "buck3";
+			regulator-min-microvolt = <800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-boot-on;
+			regulator-ramp-delay = <250>;
+		};
+		ldo1: LDO1 {
+			regulator-name = "ldo1";
+			regulator-min-microvolt = <1650000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+		};
+		ldo2: LDO2 {
+			regulator-name = "ldo2";
+			regulator-min-microvolt = <1650000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+		};
+
+		ldo3: LDO3 {
+			regulator-name = "ldo3";
+			regulator-min-microvolt = <1650000>;
+			regulator-max-microvolt = <3300000>;
+		};
+		led_ldo1: LED_LDO1 {
+			regulator-name = "led_ldo1";
+			regulator-min-microvolt = <200000>;
+			regulator-max-microvolt = <300000>;
+		};
+		led_ldo2: LED_LDO2 {
+			regulator-name = "led_ldo2";
+			regulator-min-microvolt = <200000>;
+			regulator-max-microvolt = <300000>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/seconorth/trizeps8plus.dtsi b/arch/arm64/boot/dts/seconorth/trizeps8plus.dtsi
index 551ab8a56329c67c2fb3fa9ccd15503efa178b5e..01e379f672fb89d2d4196e5c991aa529b338301e 100644
--- a/arch/arm64/boot/dts/seconorth/trizeps8plus.dtsi
+++ b/arch/arm64/boot/dts/seconorth/trizeps8plus.dtsi
@@ -758,6 +758,33 @@ mcutouch: kuk_tr8mcu_touch@10 { /* Kinetis MCU and touch-controller */
 		linux,wakeup;
 	};
 #endif
+	tr8mcu: tr8mcu@10 { /* Kinetis MCU and touch-controller */
+		compatible = "seco,tr8mcu";
+		reg = <0x10>;
+
+		pinctrl-0 = <&pinctrl_tr8mcu>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <10 GPIO_ACTIVE_LOW>;
+
+		status = "okay";
+
+		gpio_mcu: tr8mcu-gpios {
+			compatible = "seco,tr8mcu-gpio";
+			status = "okay";
+			gpio-controller;
+			#gpio-cells = <2>;
+
+			// Map the 'SODIMM' offsets according to
+			// https://secogroup.atlassian.net/wiki/x/KQE6Vg
+			// to the gpiochipX offset 0-16
+			gpio-mapping = < 2 4 6 8 14 16 18 20 87 75 99 251>;
+
+			gpio-line-names =
+				"SPIN2", "SPIN4", "SPIN6", "SPIN8",
+				"SPIN14", "SPIN16", "SPIN18", "SPIN20",
+				"SPIN87", "SPIN75", "SPIN99", "nPCIE_RESET";
+		};
+	};
 };
 
 &flexcan1 {
@@ -1038,6 +1065,10 @@ pinctrl_restouch: restouchgrp {
 		fsl,pins = < MCU_INT_GPIO       PAD_GPIO >; /* MCU Interrupt */
 	};
 
+	pinctrl_tr8mcu: tr8mcugrp {
+		fsl,pins = < MCU_INT_GPIO       PAD_GPIO >; /* MCU Interrupt */
+	};
+
 #if 0
 	pinctrl_i2c3_sn65dsi84_en: sn65dsi84_iogrp {
 		fsl,pins = < LVDS_EN_GPIO  PAD_GPIO  >; /* Myon internal LVDS Enable and external Pin0-72 */
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 00ab41f2fb286f8f5ea4ca24a9148f4e9810f532..44f351b3756070ac0f4cc0c3cb1f6a75775b2412 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -112,4 +112,6 @@ source "drivers/staging/gpio/Kconfig"
 
 source "drivers/staging/gpu/drm/Kconfig"
 
+source "drivers/staging/mfd/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 279a69f849fc61903fa2be076dc695bd8b920571..bdc47be1070da4aa871f88ee51d5330f716e59f7 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -46,3 +46,4 @@ obj-$(CONFIG_WFX)		+= wfx/
 obj-$(CONFIG_FSL_PPFE)		+= fsl_ppfe/
 obj-y				+= gpio/
 obj-y				+= gpu/drm/
+obj-y				+= mfd/
diff --git a/drivers/staging/gpio/Kconfig b/drivers/staging/gpio/Kconfig
index 4e25bd2625ea308541e0a571681f6baa471cf42b..abef1128fd5c54e671091d9bc216e50c17c7a238 100644
--- a/drivers/staging/gpio/Kconfig
+++ b/drivers/staging/gpio/Kconfig
@@ -2,13 +2,20 @@
 #
 # GPIO infrastructure and drivers
 #
-menu "I2C GPIO expanders"
-	depends on I2C
+menu "GPIO expanders"
 
 config GPIO_PI4IOE5V6408
 	tristate "Pericom PI4IOE5V6408 I2C GPIO Expander"
 	select REGMAP_I2C
+	depends on I2C
 	help
 	  Say yes here to enable the Pericom PI4IOE5V6408 GPIO Expander
 
+config GPIO_TRIZEPS8_MCU
+	tristate "Trizeps8 MCU GPIO Expander"
+	depends on MFD_SECO_TRIZEPS8_MCU
+	help
+	  Say yes here to enable the Trizeps8 MCU based GPIO Expander
+
+
 endmenu
diff --git a/drivers/staging/gpio/Makefile b/drivers/staging/gpio/Makefile
index 16f9877bb517dcb5bbd1de5e9428e0e34baee63e..d64595e4ce29b3a95a11f257141dafb38b322bd9 100644
--- a/drivers/staging/gpio/Makefile
+++ b/drivers/staging/gpio/Makefile
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_GPIO_PI4IOE5V6408)	+= gpio-pi4ioe5v6408.o
+obj-$(CONFIG_GPIO_TRIZEPS8_MCU)	+= gpio-trizeps8mcu.o
diff --git a/drivers/staging/gpio/gpio-trizeps8mcu.c b/drivers/staging/gpio/gpio-trizeps8mcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..55cd0883a0d3c77de56780b687d29e733d252a5f
--- /dev/null
+++ b/drivers/staging/gpio/gpio-trizeps8mcu.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// gpio-tr8mcu.c ROHM TR8MCUMWV gpio driver
+
+#include <linux/gpio/driver.h>
+#include <linux/mfd/seco-trizeps8mcu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct tr8mcu_gpio {
+	struct tr8mcu		*parent;
+	struct gpio_chip	chip;
+	const int			*gpio_to_pin;
+
+	//struct irq_chip		irqchip;
+	//struct mutex		lock;		/* protect 'out' */
+	//unsigned		out;		/* software latch */
+	//unsigned		status;		/* current status */
+	//unsigned int		irq_parent;
+	//unsigned		irq_enabled;	/* enabled irqs */
+};
+
+#define NGPIOS 11
+static const int default_gpio_to_pin[NGPIOS] = {
+/*  0  1  2  3   4   5   6   7   8   9  10 */
+	2, 4, 6, 8, 14, 16, 18, 20, 87, 97, 99
+};
+
+static int tr8mcu_get_pin(struct gpio_chip *chip, unsigned int offset)
+{
+	struct tr8mcu_gpio *tr8mcu_gpio = gpiochip_get_data(chip);
+	struct device * dev = tr8mcu_gpio->chip.parent;
+	int pin;
+
+	if( offset > tr8mcu_gpio->chip.ngpio) goto err;
+
+	// Map gpio 0-X to the MCU's pins
+	pin = tr8mcu_gpio->gpio_to_pin[offset];
+	if( pin == -1 ) goto err;
+
+	dev_info(dev, "Mapped offset %d to pin %d\n", offset, pin);
+	return pin;
+err:
+	dev_err(dev, "Offset %d is not mapped\n", offset);
+	return -ENOENT;
+
+}
+
+static int tr8mcu_set_direction(struct gpio_chip *chip, unsigned int offset,
+								int direction, int value)
+{
+	struct tr8mcu_gpio *tr8mcu_gpio = gpiochip_get_data(chip);
+	struct tr8mcu *tr8mcu = tr8mcu_gpio->parent;
+	struct device * dev = tr8mcu_gpio->chip.parent;
+	int pin, ret;
+	u32 data;
+
+	dev_info(dev, "%s %d: dir %d offset %d value %d\n",
+			 __func__, __LINE__, direction, offset, value);
+
+	pin = tr8mcu_get_pin( chip, offset);
+	if( pin < 0) return pin;
+
+	data = pin;
+
+	//  1; /* Alt1=Input  */
+	// 21; /* Alt1-Output High */
+	// 20; /* Alt1-Output Low  */
+	if( direction == GPIO_LINE_DIRECTION_IN)
+		data |= ( 1) << 8;
+	else // GPIO_LINE_DIRECTION_OUT
+		data |= ( 20 + ( !! value )) << 8;
+
+	ret = tr8mcu_write(tr8mcu, TR8MCU_REG_PIN_CONFIG, 2, data);
+	if(ret)
+		dev_err(dev, "Failed to set direction %s for pin %d level %d\n",
+				  direction == GPIO_LINE_DIRECTION_IN ? "input" : "output",
+				  offset, value);
+
+	return ret;
+}
+
+static int tr8mcu_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+	return tr8mcu_set_direction(chip, offset, GPIO_LINE_DIRECTION_IN, 0);
+}
+
+static int tr8mcu_direction_output(struct gpio_chip *chip, unsigned int offset,
+				    int value)
+{
+	return tr8mcu_set_direction(chip, offset, GPIO_LINE_DIRECTION_OUT, value);
+}
+
+
+static void tr8mcu_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			     int value)
+{
+	struct tr8mcu_gpio *tr8mcu_gpio = gpiochip_get_data(chip);
+	struct device * dev = tr8mcu_gpio->chip.parent;
+	int ret;
+
+	dev_info(dev, "%s %d: offset %d value %d\n",
+			 __func__, __LINE__, offset, value);
+	// From kuk_tr8mci_touch driver
+	// There seems to be a bug in the firmware of the so direction output is
+	// used instead
+	ret = tr8mcu_direction_output(chip, offset, value);
+
+}
+
+static int tr8mcu_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct tr8mcu_gpio *tr8mcu_gpio = gpiochip_get_data(chip);
+	struct tr8mcu *tr8mcu = tr8mcu_gpio->parent;
+	struct device * dev = tr8mcu_gpio->chip.parent;
+	int pin, ret;
+	u32 data;
+
+	dev_info(dev, "%s %d: offset %d \n",
+			 __func__, __LINE__, offset);
+
+	pin = tr8mcu_get_pin( chip, offset);
+	if( pin < 0) return pin;
+
+	ret = tr8mcu_read_with_param(tr8mcu, TR8MCU_REG_PIN_GET, pin, 1, &data);
+
+	dev_info(dev, "%s %d: offset %d pin %d, level %d, ret %d\n",
+			 __func__, __LINE__, offset, pin, data, ret);
+
+	if (ret) {
+		dev_err(dev, "Unable to fetch MCU-pin: %d err: %d\n", pin, ret);
+		return 0;
+	}
+	return data;
+}
+
+static int tr8mcu_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tr8mcu_gpio *tr8mcu_gpio;
+	struct tr8mcu *tr8mcu;
+	const struct device_node * np = pdev->dev.of_node;
+	int ret, count;
+	int *gpio_map;
+
+	dev_info(dev, "%s %d\n", __func__, __LINE__);
+
+	tr8mcu = dev_get_drvdata(pdev->dev.parent);
+	if (!tr8mcu) {
+		dev_err(dev, "No MFD driver data\n");
+		return -EINVAL;
+	}
+
+	tr8mcu_gpio = devm_kzalloc(dev, sizeof(*tr8mcu_gpio),
+			      GFP_KERNEL);
+	if (!tr8mcu_gpio)
+		return -ENOMEM;
+
+	tr8mcu_gpio->parent = tr8mcu;
+	tr8mcu_gpio->chip.parent = dev;
+	tr8mcu_gpio->chip.label = "tr8mcu-gpio";
+	tr8mcu_gpio->chip.owner = THIS_MODULE;
+	tr8mcu_gpio->chip.can_sleep = true;
+	tr8mcu_gpio->chip.direction_input = tr8mcu_direction_input;
+	tr8mcu_gpio->chip.direction_output = tr8mcu_direction_output;
+	tr8mcu_gpio->chip.get = tr8mcu_gpio_get;
+	tr8mcu_gpio->chip.set = tr8mcu_gpio_set;
+	tr8mcu_gpio->chip.base = -1;
+
+	count = of_property_count_u32_elems(np, "gpio-mapping");
+	if(count > 0)
+	{
+		dev_info(dev, "%d gpios configured\n", count);
+		gpio_map = devm_kzalloc(dev, count * sizeof(int), GFP_KERNEL);
+		if(!gpio_map){
+			dev_err(dev, "Failed to allocate memory.");
+			return -ENOMEM;
+		}
+
+		if(of_property_read_u32_array(np, "gpio-mapping", gpio_map, count))
+		{
+			dev_err(dev, "Failed read devicetree property.");
+			return -ENOENT;
+		}
+
+		tr8mcu_gpio->gpio_to_pin = gpio_map;
+		tr8mcu_gpio->chip.ngpio = count;
+
+	}
+	else{
+		dev_info(dev, "Mapping for gpios not configured, using default\n");
+		tr8mcu_gpio->chip.ngpio = NGPIOS;
+		tr8mcu_gpio->gpio_to_pin = default_gpio_to_pin;
+	}
+
+	ret = devm_gpiochip_add_data(dev, &tr8mcu_gpio->chip,
+				     tr8mcu_gpio);
+	if (ret)
+		dev_err(dev, "gpio_init: Failed to add tr8mcu-gpios\n");
+
+	return ret;
+}
+
+static const struct of_device_id tr8mcu_gpio_of_match[] = {
+	{ .compatible = "seco,tr8mcu-gpio", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, tr8mcu_gpio_of_match);
+
+static struct platform_driver tr8mcu_gpio = {
+	.driver = {
+		.name = "tr8mcu-gpios",
+		.of_match_table = tr8mcu_gpio_of_match,
+	},
+	.probe = tr8mcu_gpio_probe,
+};
+
+module_platform_driver(tr8mcu_gpio);
+
+MODULE_AUTHOR("Jonas Höppner <jonas.hoeppner@seco.com>");
+MODULE_DESCRIPTION("Trizeps8 MCU driver gpio");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tr8mcu-gpio");
diff --git a/drivers/staging/mfd/Kconfig b/drivers/staging/mfd/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..972472805450cb11da2b6a0eefc2be34fd906eeb
--- /dev/null
+++ b/drivers/staging/mfd/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menuconfig MFD_SECO_TRIZEPS8_MCU
+	bool "SECO Trizeps8 MCU Multifunction device driver"
+	help
+	  Say yes here to enable the Trizeps8 MCU Multifunction device driver
+
diff --git a/drivers/staging/mfd/Makefile b/drivers/staging/mfd/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ef2fa649a0106022408f84bebfbeb7ef5082ae09
--- /dev/null
+++ b/drivers/staging/mfd/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for GPIO infrastructure and drivers
+#
+
+obj-$(CONFIG_MFD_SECO_TRIZEPS8_MCU)	+= seco-trizeps8mcu.o
diff --git a/drivers/staging/mfd/seco-trizeps8mcu.c b/drivers/staging/mfd/seco-trizeps8mcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c96f20081ebf6bf89d07ce3d623c3e986939d1c
--- /dev/null
+++ b/drivers/staging/mfd/seco-trizeps8mcu.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Copyright (C) 2023 SECO Nothern Europe
+//
+//
+// Multifunction device driver for Trizeps8 MCU
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/seco-trizeps8mcu.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/types.h>
+
+struct tr8mcu {
+	struct i2c_client * client;
+	struct mfd_cell * mfd_cells;
+};
+
+/*== Read Write =======================================================*/
+
+static int tr8mcu_readwrite(struct i2c_client *client,
+				   u16 wr_len, u8 *wr_buf,
+				   u16 rd_len, u8 *rd_buf)
+{
+	//struct device dev = client->dev;
+	struct i2c_msg wrmsg[2];
+	int i = 0;
+	int ret;
+	// TODO do we need a mutex here 
+
+	if (wr_len) {
+		wrmsg[i].addr  = client->addr;
+		wrmsg[i].flags = 0;
+		wrmsg[i].len = wr_len;
+		wrmsg[i].buf = wr_buf;
+		i++;
+	}
+	if (rd_len) {
+		wrmsg[i].addr  = client->addr;
+		wrmsg[i].flags = I2C_M_RD;
+		wrmsg[i].len = rd_len;
+		wrmsg[i].buf = rd_buf;
+		i++;
+	}
+
+	dev_info(&client->dev, "%s %d: write buf: 0x%02X, 0x%02X, 0x%02X\n",
+			 __func__, __LINE__, wr_buf[0], wr_buf[1], wr_buf[2]);
+
+	ret = i2c_transfer(client->adapter, wrmsg, i);
+	if (ret < 0)
+		return ret;
+	if (ret != i)
+		return -EIO;
+	if(rd_buf)
+			dev_info(&client->dev, "%s %d: read buf: 0x%02X, 0x%02X, 0x%02X\n",
+			 __func__, __LINE__, rd_buf[0], rd_buf[1], rd_buf[2]);
+
+	return 0;
+}
+
+int tr8mcu_read_with_param(struct tr8mcu * tr8mcu, u8 reg, u8 param, int len,
+						   u32 * data)
+{
+	struct i2c_client *client = tr8mcu->client;
+	u32 readdata = 0, mask;
+	u8 writedata[2];
+	int error;
+
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d\n",
+			 __func__, __LINE__, reg, len);
+
+	if( len == 0 || len > 4 )
+	{
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_write: reading %d bytes is not supported\n", len);
+		return -EPERM;
+	}
+
+	writedata[0] = reg;
+	writedata[1] = param;
+
+	error = tr8mcu_readwrite( client, 2, writedata, len, (u8*)&readdata);
+	if (error) {
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_read: Unable to fetch %d bytes, error: %d\n",
+				len, error);
+		return error;
+	}
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d: 0x%02X\n",
+			 __func__, __LINE__, reg, len, readdata);
+
+	// Mask out unread bits
+	mask = 0xFFFFFFFF >> ( (4 - len) * 8 );
+	readdata &= mask;
+
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d: 0x%02X, 0x%08X\n",
+			 __func__, __LINE__, reg, len, readdata, mask);
+	*data = readdata;
+	return 0;
+}
+
+int tr8mcu_read(struct tr8mcu * tr8mcu, u8 reg, int len, u32 * data)
+{
+	struct i2c_client *client = tr8mcu->client;
+	u32 readdata, mask;
+	int error;
+
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d\n",
+			 __func__, __LINE__, reg, len);
+
+	if( len == 0 || len > 4 )
+	{
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_write: reading %d bytes is not supported\n", len);
+		return -EPERM;
+	}
+
+	error = tr8mcu_readwrite( client,
+					sizeof(reg), &reg,
+					len, (u8*)&readdata);
+	if (error) {
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_read: Unable to fetch %d bytes, error: %d\n",
+				len, error);
+		return error;
+	}
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d: 0x%02X\n",
+			 __func__, __LINE__, reg, len, readdata);
+
+	// Mask out unread bits
+	mask = 0xFFFFFFFF >> ( (4 - len) * 8 );
+	readdata &= mask;
+
+	dev_info(&client->dev, "%s %d: 0x%02X, len %d: 0x%02X, 0x%08X\n",
+			 __func__, __LINE__, reg, len, readdata, mask);
+	*data = readdata;
+	return 0;
+}
+
+int tr8mcu_write(struct tr8mcu * tr8mcu, u8 reg, int len, u32 data)
+{
+	struct i2c_client *client = tr8mcu->client;
+	u8 buf[5];
+	u32 mask;
+	int i, error;
+
+	dev_info(&client->dev, "%s %d: Reg: 0x%02X, len %d, data 0x%02x\n",
+			 __func__, __LINE__, reg, len, data);
+	if( len == 0 || len > 4 )
+	{
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_write: writing %d bytes is not supported\n", len);
+		return EPERM;
+	}
+
+	buf[0] = reg;
+
+	// Mask out unread bits
+	mask = 0xFFFFFFFF >> ( (4 - len) * 8 );
+	data &= mask;
+
+	for( i = 0; i < 4; i++)
+		buf[1+i] = ( data >> ( 8 * i)) & 0xFF;
+
+	error = tr8mcu_readwrite( client, len + 1, buf, 0, NULL);
+	if (error) {
+		dev_err_ratelimited(&client->dev,
+				"tr8mcu_write: Unable to write %d bytes, error: %d\n",
+				len + 1, error);
+		return error;
+	}
+	return 0;
+}
+
+/*== Read Write =======================================================*/
+
+static int tr8mcu_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct tr8mcu *tr8mcu;
+	//struct regmap_irq_chip_data *irq_data;
+	int ret = 0;
+	u32 data;
+	int child_count = 0;
+	struct device_node *np, *child;
+
+	if (!client->irq) {
+		dev_err(&client->dev, "No IRQ configured\n");
+		return -EINVAL;
+	}
+
+	tr8mcu = devm_kzalloc(&client->dev, sizeof(struct tr8mcu), GFP_KERNEL);
+	if (!tr8mcu)
+		return -ENOMEM;
+
+	tr8mcu->client = client;
+	dev_set_drvdata(&client->dev, tr8mcu);
+
+	// Try to read out the ID to check if we find an MCU
+	if(tr8mcu_read(tr8mcu, TR8MCU_REG_ID, 1, &data) || data != 0x61)
+	{
+		dev_err(&client->dev, "Trizeps8 MCU: probe No MCU found!\n");
+		return -ENODEV;
+	}
+
+	np = client->dev.of_node;
+	child_count = of_get_available_child_count(np);
+	tr8mcu->mfd_cells = devm_kzalloc(&client->dev,
+				child_count * sizeof(struct mfd_cell), GFP_KERNEL);
+	dev_info(&client->dev, "%d child nodes found.\n", child_count);
+
+	for_each_available_child_of_node(np, child)
+	{
+		struct property *prop;
+		const char *cp = child->name, *compatible;
+		dev_info(&client->dev, "%s %d: Found child: %s\n",
+			 __func__, __LINE__, child->name);
+
+		/* TODO use compatible here instead of the name, currently breaks
+		 * everything */
+		prop = of_find_property(child, "compatible", NULL);
+		if(prop){
+			compatible = of_prop_next_string(prop, NULL);
+			dev_info(&client->dev, "%s %d: child: %s\n",
+			 __func__, __LINE__, compatible);
+			if(compatible) cp = compatible;
+			tr8mcu->mfd_cells->of_compatible = devm_kstrdup(&client->dev,
+						compatible, GFP_KERNEL);
+		}
+
+		tr8mcu->mfd_cells->name = devm_kstrdup(&client->dev, cp, GFP_KERNEL);
+	}
+
+	if(child_count)
+	{
+		ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
+				   tr8mcu->mfd_cells, child_count, NULL, 0, NULL);
+		if (ret)
+			dev_err(&client->dev, "Failed to create subdevices\n");
+	}
+
+
+	return ret;
+}
+
+static const struct of_device_id tr8mcu_of_match[] = {
+	{ .compatible = "seco,tr8mcu", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tr8mcu_of_match);
+
+static struct i2c_driver tr8mcu_drv = {
+	.driver = {
+		.name = "seco-tr8mcu",
+		.of_match_table = tr8mcu_of_match,
+	},
+	.probe = &tr8mcu_i2c_probe,
+};
+
+module_i2c_driver(tr8mcu_drv);
+
+MODULE_AUTHOR("Jonas Höppner <jonas.hoeppner@seco.com>");
+MODULE_DESCRIPTION("Trizeps8 MCU driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/seco-trizeps8mcu.h b/include/linux/mfd/seco-trizeps8mcu.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8c8abf82692a6132ef27098ed32cbaf1609445b
--- /dev/null
+++ b/include/linux/mfd/seco-trizeps8mcu.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2018 ROHM Semiconductors */
+
+#ifndef __LINUX_MFD_TR8MCU_H__
+#define __LINUX_MFD_TR8MCU_H__
+
+#include <linux/types.h>
+
+#define TR8MCU_REG_ID				0x01
+#define TR8MCU_REG_CONTROL			0x02
+#define TR8MCU_REG_CONFIG1			0x03
+#define TR8MCU_REG_PIN_CONFIG		0x04
+#define TR8MCU_REG_PIN_SET			0x05
+#define TR8MCU_REG_PIN_GET			0x06
+#define TR8MCU_REG_ADC_CONFIG		0x10
+#define TR8MCU_REG_ADC				0x11
+#define TR8MCU_REG_LSB				0x12
+#define TR8MCU_REG_MSB				0x13
+
+#define TR8MCU_REG_TOUCH_CONFIG		 0x20
+#define TR8MCU_REG_TOUCH_WAITTIME	 0x21
+#define TR8MCU_REG_TOUCH_XSCALE_LSB	 0x22
+#define TR8MCU_REG_TOUCH_XSCALE_MSB	 0x23
+#define TR8MCU_REG_TOUCH_YSCALE_LSB	 0x24
+#define TR8MCU_REG_TOUCH_YSCALE_MSB	 0x25
+#define TR8MCU_REG_TOUCH_XMIN_LSB	 0x26
+#define TR8MCU_REG_TOUCH_XMIN_MSB	 0x27
+#define TR8MCU_REG_TOUCH_YMIN_LSB	 0x28
+#define TR8MCU_REG_TOUCH_YMIN_MSB	 0x29
+#define TR8MCU_REG_TOUCH_XMAX_Z_LSB	 0x2A
+#define TR8MCU_REG_TOUCH_XMAX_Z_MSB	 0x2B
+#define TR8MCU_REG_TOUCH_YMAX_LSB	 0x2C
+#define TR8MCU_REG_TOUCH_YMAX_MSB	 0x2D
+#define TR8MCU_REG_TOUCH_AVERAGE	 0x2E
+
+#define TR8MCU_REG_CONFIG1_RESET2USBBOOT	0x01
+#define TR8MCU_REG_CONFIG1_SDVSEL			0x02
+
+
+struct tr8mcu;
+
+/* Read up to 4 bytes from the MCU
+   Returns 0 or a negative error code
+*/
+int tr8mcu_read(struct tr8mcu * tr8mcu, u8 reg, int len, u32 * data);
+
+/* Read up to 4 bytes from the MCU, specified by reg and param.
+   Returns 0 or a negative error code
+*/
+int tr8mcu_read_with_param(struct tr8mcu * tr8mcu, u8 reg, u8 param, int len,
+						   u32 * data);
+/* Write up to 4 bytes to the MCU
+   Returns 0 or a negative error code
+*/
+int tr8mcu_write(struct tr8mcu * tr8mcu, u8 reg, int len, u32 data);
+
+#endif /* __LINUX_MFD_TR8TR8MCU_H__ */