{"id":2221030,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2221030/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260408-dev-b4-aaeon-mcu-driver-v5-3-ad98bd481668@bootlin.com/","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.1/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260408-dev-b4-aaeon-mcu-driver-v5-3-ad98bd481668@bootlin.com>","date":"2026-04-08T17:21:56","name":"[v5,3/5] mfd: aaeon: Add SRG-IMX8P MCU driver","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"ccb7851bb0010a24ba972c7b20e123fadcbbbc2d","submitter":{"id":82054,"url":"http://patchwork.ozlabs.org/api/1.1/people/82054/?format=json","name":"Thomas Perrot (Schneider Electric)","email":"thomas.perrot@bootlin.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260408-dev-b4-aaeon-mcu-driver-v5-3-ad98bd481668@bootlin.com/mbox/","series":[{"id":499169,"url":"http://patchwork.ozlabs.org/api/1.1/series/499169/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/list/?series=499169","date":"2026-04-08T17:21:53","name":"Add support for AAEON SRG-IMX8P MCU","version":5,"mbox":"http://patchwork.ozlabs.org/series/499169/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2221030/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2221030/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-34897-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=bootlin.com header.i=@bootlin.com header.a=rsa-sha256\n header.s=dkim header.b=sdcVwchm;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.232.135.74; helo=sto.lore.kernel.org;\n envelope-from=linux-gpio+bounces-34897-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com\n header.b=\"sdcVwchm\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=185.171.202.116","smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=bootlin.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=bootlin.com"],"Received":["from sto.lore.kernel.org (sto.lore.kernel.org [172.232.135.74])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4frVJH59fzz1xv0\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 03:22:55 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id C8DBD3027097\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  8 Apr 2026 17:22:43 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 5B7DD3D8138;\n\tWed,  8 Apr 2026 17:22:30 +0000 (UTC)","from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 60DB73D6486;\n\tWed,  8 Apr 2026 17:22:28 +0000 (UTC)","from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233])\n\tby smtpout-04.galae.net (Postfix) with ESMTPS id 79ECBC5AAA8;\n\tWed,  8 Apr 2026 17:23:01 +0000 (UTC)","from mail.galae.net (mail.galae.net [212.83.136.155])\n\tby smtpout-01.galae.net (Postfix) with ESMTPS id 2D1F7603CE;\n\tWed,  8 Apr 2026 17:22:27 +0000 (UTC)","from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon)\n with ESMTPSA id B4640104500F3;\n\tWed,  8 Apr 2026 19:22:23 +0200 (CEST)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775668950; cv=none;\n b=axHeVNJde7SUmq2SDzEjUDGFk9w0BdsRs3+xaGXA06FAfUR5KZjBeghc1jjKwPuGRGJvDHfkL4leTzu8SnPA+Wwg8i4fKeFkrhwwg1nktyeP5N/QrakWqDWHYiA3Bd64fHl3OqB35DQ4YY37ovXcixLT07zOoypVaueo3UcdYDY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775668950; c=relaxed/simple;\n\tbh=4HVk1b5Uyy7oVp0r1PoPUGu7TAPwcgfxHg/dD7XqfDM=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=R8aOlLNOKrl7RzPsaOwMWYOrA+mQpRNbVJjHEEDvckaqG689vl33pD+LKAjmE6mIKk9edCyHavvEqYAeVrrKeIdRqoS8M4fq8k9oQWRLKIDlqa3lVFfmdASc0SVeroMR2udMwWfHhuui70M8BH611yrbVEqa/VD6g+NIIdgYbV0=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=bootlin.com;\n spf=pass smtp.mailfrom=bootlin.com;\n dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com\n header.b=sdcVwchm; arc=none smtp.client-ip=185.171.202.116","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim;\n\tt=1775668945; h=from:subject:date:message-id:to:cc:mime-version:content-type:\n\t content-transfer-encoding:in-reply-to:references;\n\tbh=HVOFmzYPOR0p5HrF0J6JrrLY2XglFarDffIfsCttOKA=;\n\tb=sdcVwchmSmOxrt9pydsQWm7h0HSt4nZAJwFscyw00EihAaraAkwGUS32vKeq1RnTrEMefe\n\tkNjFsmSobyTL2TDl+oi+hO01VjK1jNY730COxotu7gUjbvFrMFXiq44I+Q6BlHhKAJO9aQ\n\tSBpK65P4+SYZ7cjf+TBZQMhcWw2zLvkfG+egHOpkbF/DDLG3YIGJwhx3PC/zTPeIEQ72gp\n\t7rGpqjYa53Kj6I9NLd9mJg2s/Gs+zBP0J7wMG20GehebdzkMGVxnx1dPImabDy3q15jidz\n\tQPu7NZn2XSwGHJnFyE6J1W4HTK1q5iwa1CLsVzICLNahgEd6ihYr8N4JAiPB1Q==","From":"\"Thomas Perrot (Schneider Electric)\" <thomas.perrot@bootlin.com>","Date":"Wed, 08 Apr 2026 19:21:56 +0200","Subject":"[PATCH v5 3/5] mfd: aaeon: Add SRG-IMX8P MCU driver","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"8bit","Message-Id":"<20260408-dev-b4-aaeon-mcu-driver-v5-3-ad98bd481668@bootlin.com>","References":"<20260408-dev-b4-aaeon-mcu-driver-v5-0-ad98bd481668@bootlin.com>","In-Reply-To":"<20260408-dev-b4-aaeon-mcu-driver-v5-0-ad98bd481668@bootlin.com>","To":"Rob Herring <robh@kernel.org>, Krzysztof Kozlowski <krzk+dt@kernel.org>,\n  Conor Dooley <conor+dt@kernel.org>, Linus Walleij <linusw@kernel.org>,\n  Bartosz Golaszewski <brgl@kernel.org>, Shawn Guo <shawnguo@kernel.org>,\n  Sascha Hauer <s.hauer@pengutronix.de>,\n  Pengutronix Kernel Team <kernel@pengutronix.de>,\n  Fabio Estevam <festevam@gmail.com>,\n =?utf-8?b?SsOpcsOpbWllIERhdXRoZXJpYmVz?= <jeremie.dautheribes@bootlin.com>,\n  Wim Van Sebroeck <wim@linux-watchdog.org>,\n  Guenter Roeck <linux@roeck-us.net>, Lee Jones <lee@kernel.org>","Cc":"devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,\n linux-gpio@vger.kernel.org, imx@lists.linux.dev,\n linux-arm-kernel@lists.infradead.org, linux-watchdog@vger.kernel.org,\n Thomas Petazzoni <thomas.petazzoni@bootlin.com>,\n Miquel Raynal <miquel.raynal@bootlin.com>,\n \"Thomas Perrot (Schneider Electric)\" <thomas.perrot@bootlin.com>","X-Mailer":"b4 0.14.3","X-Developer-Signature":"v=1; a=openpgp-sha256; l=11253;\n i=thomas.perrot@bootlin.com; h=from:subject:message-id;\n bh=4HVk1b5Uyy7oVp0r1PoPUGu7TAPwcgfxHg/dD7XqfDM=;\n b=owEB7QES/pANAwAKAZ/ACwVx/grtAcsmYgBp1o7D7QPqY47pu/4shVnnxFEPrOr7ghT6M0Jvm\n 8boF+7lQHaJAbMEAAEKAB0WIQSHQHfGpqMKIwOoEiGfwAsFcf4K7QUCadaOwwAKCRCfwAsFcf4K\n 7eOrC/9+oTjnc7vqXzBbwzs2V1vFMxRAWTE/X7xV3snk29mF0kQLMXybeCu+IyffTwOq/Xr3Xu3\n QBtEQDwfmCiz7h9Zj+R91cAZkw/qoWVtYtzUPuHHNNfwrg2aLnHOfEf2lW1t/O96goT7MGPTlyy\n xgDdLcof0anjOczK87T0ZYjub1eZFuu3ZlQYy9sG7VAz4c3eA3l8wUD+3gvZ9eUkZL4a79lAYLP\n VwAdx+VplwqyrozyJHd3R2yBm6N4QkikmBNbWXshs9BjipJsWh/4ekzO2g1+s7rSh1vqtm/5vex\n pjF2epcFEc3Y9rDhWn26EldJlEdoRR6pdSfyyjbGMshPuGcD2zTYdtSpepx5sB62X2B7MTDyS2Q\n WIDU6vOmNKhir2aUw2/r1yx/dQD4UXmhBoUqg4MlyfRYrMI+ymXDt7UXy6AIwxcAFXsvpZTBhVS\n 5sWgA2T0xzjTeix7tWgmE3Q0KUUCvxSwFAisyKeRqDxhfSWTbk80x0LIQ+0Rch0q6Cc3E=","X-Developer-Key":"i=thomas.perrot@bootlin.com; a=openpgp;\n fpr=874077C6A6A30A2303A812219FC00B0571FE0AED","X-Last-TLS-Session-Version":"TLSv1.3"},"content":"Add Multi-Function Device (MFD) driver for the Aaeon SRG-IMX8P\nembedded controller. This driver provides the core I2C communication\ninterface and registers child devices (GPIO and watchdog controllers).\n\nThe driver implements a custom regmap bus over I2C to match the MCU's\nfixed 3-byte command format [opcode, arg, value]. Register addresses\nare encoded as 16-bit values (opcode << 8 | arg) using the\nAAEON_MCU_REG() macro defined in the shared header. The regmap\ninstance is shared with child drivers via dev_get_regmap(). Concurrent\nI2C accesses from child drivers are serialized by regmap's built-in\nlocking.\n\nI2C transfers use heap-allocated DMA-safe buffers rather than\nstack-allocated ones, as required by I2C controllers that perform DMA.\n\nRegmap caching is enabled (REGCACHE_MAPLE) with a volatile_reg\ncallback that marks GPIO input read registers (opcode 0x72) and the\nwatchdog status register (opcode 0x63, arg 0x02) as volatile. All\nother registers written by the driver (GPIO direction,\nGPO state, watchdog control) are stable and can be safely cached.\n\nCo-developed-by: Jérémie Dautheribes (Schneider Electric) <jeremie.dautheribes@bootlin.com>\nSigned-off-by: Jérémie Dautheribes (Schneider Electric) <jeremie.dautheribes@bootlin.com>\nSigned-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot@bootlin.com>\n---\n MAINTAINERS                   |   2 +\n drivers/mfd/Kconfig           |  10 +++\n drivers/mfd/Makefile          |   1 +\n drivers/mfd/aaeon-mcu.c       | 204 ++++++++++++++++++++++++++++++++++++++++++\n include/linux/mfd/aaeon-mcu.h |  40 +++++++++\n 5 files changed, 257 insertions(+)","diff":"diff --git a/MAINTAINERS b/MAINTAINERS\nindex ea9d55f76f35..f91b6a1826d0 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -191,6 +191,8 @@ M:\tThomas Perrot <thomas.perrot@bootlin.com>\n R:\tJérémie Dautheribes <jeremie.dautheribes@bootlin.com>\n S:\tMaintained\n F:\tDocumentation/devicetree/bindings/mfd/aaeon,srg-imx8p-mcu.yaml\n+F:\tdrivers/mfd/aaeon-mcu.c\n+F:\tinclude/linux/mfd/aaeon-mcu.h\n \n AAEON UPBOARD FPGA MFD DRIVER\n M:\tThomas Richard <thomas.richard@bootlin.com>\ndiff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig\nindex aace5766b38a..82ec1d8e7224 100644\n--- a/drivers/mfd/Kconfig\n+++ b/drivers/mfd/Kconfig\n@@ -1561,6 +1561,16 @@ config ABX500_CORE\n \t  remain unchanged when IC changes. Binding of the functions to\n \t  actual register access is done by the IC core driver.\n \n+config MFD_AAEON_MCU\n+\ttristate \"Aaeon SRG-IMX8P MCU Driver\"\n+\tdepends on I2C || COMPILE_TEST\n+\tselect MFD_CORE\n+\thelp\n+\t  Select this option to enable support for the Aaeon SRG-IMX8P\n+\t  onboard microcontroller (MCU). This driver provides the core\n+\t  functionality to communicate with the MCU over I2C. The MCU\n+\t  provides GPIO and watchdog functionality.\n+\n config AB8500_CORE\n \tbool \"ST-Ericsson AB8500 Mixed Signal Power Management chip\"\n \tdepends on ABX500_CORE && MFD_DB8500_PRCMU\ndiff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile\nindex e75e8045c28a..34db5b033584 100644\n--- a/drivers/mfd/Makefile\n+++ b/drivers/mfd/Makefile\n@@ -8,6 +8,7 @@ obj-$(CONFIG_MFD_88PM860X)\t+= 88pm860x.o\n obj-$(CONFIG_MFD_88PM800)\t+= 88pm800.o 88pm80x.o\n obj-$(CONFIG_MFD_88PM805)\t+= 88pm805.o 88pm80x.o\n obj-$(CONFIG_MFD_88PM886_PMIC)\t+= 88pm886.o\n+obj-$(CONFIG_MFD_AAEON_MCU)\t+= aaeon-mcu.o\n obj-$(CONFIG_MFD_ACT8945A)\t+= act8945a.o\n obj-$(CONFIG_MFD_SM501)\t\t+= sm501.o\n obj-$(CONFIG_ARCH_BCM2835)\t+= bcm2835-pm.o\ndiff --git a/drivers/mfd/aaeon-mcu.c b/drivers/mfd/aaeon-mcu.c\nnew file mode 100644\nindex 000000000000..3b4e2d891534\n--- /dev/null\n+++ b/drivers/mfd/aaeon-mcu.c\n@@ -0,0 +1,204 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Aaeon MCU driver\n+ *\n+ * Copyright (C) 2026 Bootlin\n+ * Author: Jérémie Dautheribes <jeremie.dautheribes@bootlin.com>\n+ * Author: Thomas Perrot <thomas.perrot@bootlin.com>\n+ */\n+\n+#include <linux/err.h>\n+#include <linux/i2c.h>\n+#include <linux/mfd/aaeon-mcu.h>\n+#include <linux/mfd/core.h>\n+#include <linux/platform_device.h>\n+#include <linux/regmap.h>\n+#include <linux/slab.h>\n+\n+struct aaeon_mcu {\n+\tstruct i2c_client *client;\n+\tu8 *cmd;      /* DMA-safe 3-byte write buffer [opcode, arg, value] */\n+\tu8 *response; /* DMA-safe 1-byte read buffer for MCU acknowledgment */\n+};\n+\n+static const struct mfd_cell aaeon_mcu_devs[] = {\n+\tMFD_CELL_BASIC(\"aaeon-mcu-wdt\", NULL, NULL, 0, 0),\n+\tMFD_CELL_BASIC(\"aaeon-mcu-gpio\", NULL, NULL, 0, 0),\n+};\n+\n+/* Number of bytes in a MCU command: [opcode, arg, value] */\n+#define AAEON_MCU_CMD_LEN      3\n+\n+/*\n+ * Custom regmap bus for the Aaeon MCU I2C protocol.\n+ *\n+ * The MCU uses a fixed 3-byte command format [opcode, arg, value] followed\n+ * by a 1-byte response. It requires a STOP condition between the command\n+ * write and the response read, so two separate i2c_transfer() calls are\n+ * issued.  The regmap lock serialises concurrent accesses from the GPIO\n+ * and watchdog child drivers.\n+ *\n+ * Register addresses are encoded as a 16-bit big-endian value where the\n+ * high byte is the opcode and the low byte is the argument, matching the\n+ * wire layout produced by regmap for reg_bits=16.\n+ */\n+\n+static int aaeon_mcu_regmap_write(void *context, const void *data, size_t count)\n+{\n+\tstruct aaeon_mcu *mcu = context;\n+\tstruct i2c_client *client = mcu->client;\n+\tstruct i2c_msg write_msg;\n+\t/* The MCU always sends a response byte after each command; discard it. */\n+\tstruct i2c_msg response_msg;\n+\tint ret;\n+\n+\tmemcpy(mcu->cmd, data, count);\n+\n+\twrite_msg.addr  = client->addr;\n+\twrite_msg.flags = 0;\n+\twrite_msg.buf   = mcu->cmd;\n+\twrite_msg.len   = count;\n+\n+\tresponse_msg.addr  = client->addr;\n+\tresponse_msg.flags = I2C_M_RD;\n+\tresponse_msg.buf   = mcu->response;\n+\tresponse_msg.len   = 1;\n+\n+\tret = i2c_transfer(client->adapter, &write_msg, 1);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (ret != 1)\n+\t\treturn -EIO;\n+\n+\tret = i2c_transfer(client->adapter, &response_msg, 1);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (ret != 1)\n+\t\treturn -EIO;\n+\n+\treturn 0;\n+}\n+\n+static int aaeon_mcu_regmap_read(void *context, const void *reg_buf,\n+\t\t\t\t size_t reg_size, void *val_buf, size_t val_size)\n+{\n+\tstruct aaeon_mcu *mcu = context;\n+\tstruct i2c_client *client = mcu->client;\n+\tstruct i2c_msg write_msg;\n+\tstruct i2c_msg read_msg;\n+\tint ret;\n+\n+\t/*\n+\t * reg_buf holds the 2-byte big-endian register address [opcode, arg].\n+\t * Append a trailing 0x00 to form the full 3-byte MCU command.\n+\t */\n+\tmcu->cmd[0] = ((u8 *)reg_buf)[0];\n+\tmcu->cmd[1] = ((u8 *)reg_buf)[1];\n+\tmcu->cmd[2] = 0x00;\n+\n+\twrite_msg.addr  = client->addr;\n+\twrite_msg.flags = 0;\n+\twrite_msg.buf   = mcu->cmd;\n+\twrite_msg.len   = AAEON_MCU_CMD_LEN;\n+\n+\tread_msg.addr  = client->addr;\n+\tread_msg.flags = I2C_M_RD;\n+\tread_msg.buf   = val_buf;\n+\tread_msg.len   = val_size;\n+\n+\tret = i2c_transfer(client->adapter, &write_msg, 1);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (ret != 1)\n+\t\treturn -EIO;\n+\n+\tret = i2c_transfer(client->adapter, &read_msg, 1);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tif (ret != 1)\n+\t\treturn -EIO;\n+\n+\treturn 0;\n+}\n+\n+static const struct regmap_bus aaeon_mcu_regmap_bus = {\n+\t.write = aaeon_mcu_regmap_write,\n+\t.read  = aaeon_mcu_regmap_read,\n+};\n+\n+static bool aaeon_mcu_volatile_reg(struct device *dev, unsigned int reg)\n+{\n+\t/*\n+\t * GPIO input registers are driven by external signals and can change\n+\t * at any time without CPU involvement, always read from hardware.\n+\t *\n+\t * The watchdog status register reflects hardware state and can change\n+\t * autonomously.\n+\t *\n+\t * All other registers are written by the driver and their values are\n+\t * stable, so they can be safely cached.\n+\t */\n+\tif ((reg >> 8) == AAEON_MCU_READ_GPIO_OPCODE)\n+\t\treturn true;\n+\tif (reg == AAEON_MCU_REG(AAEON_MCU_CONTROL_WDT_OPCODE, 0x02))\n+\t\treturn true;\n+\treturn false;\n+}\n+\n+static const struct regmap_config aaeon_mcu_regmap_config = {\n+\t.reg_bits          = 16,\n+\t.val_bits          = 8,\n+\t.reg_format_endian = REGMAP_ENDIAN_BIG,\n+\t.max_register      = AAEON_MCU_MAX_REGISTER,\n+\t.volatile_reg      = aaeon_mcu_volatile_reg,\n+\t.cache_type        = REGCACHE_MAPLE,\n+};\n+\n+static int aaeon_mcu_probe(struct i2c_client *client)\n+{\n+\tstruct aaeon_mcu *mcu;\n+\tstruct regmap *regmap;\n+\n+\tmcu = devm_kzalloc(&client->dev, sizeof(*mcu), GFP_KERNEL);\n+\tif (!mcu)\n+\t\treturn -ENOMEM;\n+\n+\tmcu->client = client;\n+\n+\tmcu->cmd = devm_kzalloc(&client->dev, AAEON_MCU_CMD_LEN * sizeof(*mcu->cmd), GFP_KERNEL);\n+\tif (!mcu->cmd)\n+\t\treturn -ENOMEM;\n+\n+\tmcu->response = devm_kzalloc(&client->dev, sizeof(*mcu->response), GFP_KERNEL);\n+\tif (!mcu->response)\n+\t\treturn -ENOMEM;\n+\n+\tregmap = devm_regmap_init(&client->dev, &aaeon_mcu_regmap_bus,\n+\t\t\t\t  mcu, &aaeon_mcu_regmap_config);\n+\tif (IS_ERR(regmap))\n+\t\treturn dev_err_probe(&client->dev, PTR_ERR(regmap),\n+\t\t\t\t     \"failed to initialize regmap\\n\");\n+\n+\treturn devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,\n+\t\t\t\t    aaeon_mcu_devs, ARRAY_SIZE(aaeon_mcu_devs),\n+\t\t\t\t    NULL, 0, NULL);\n+}\n+\n+static const struct of_device_id aaeon_mcu_of_match[] = {\n+\t{ .compatible = \"aaeon,srg-imx8p-mcu\" },\n+\t{},\n+};\n+MODULE_DEVICE_TABLE(of, aaeon_mcu_of_match);\n+\n+static struct i2c_driver aaeon_mcu_driver = {\n+\t.driver = {\n+\t\t.name = \"aaeon_mcu\",\n+\t\t.of_match_table = aaeon_mcu_of_match,\n+\t},\n+\t.probe = aaeon_mcu_probe,\n+};\n+module_i2c_driver(aaeon_mcu_driver);\n+\n+MODULE_DESCRIPTION(\"Aaeon MCU Driver\");\n+MODULE_AUTHOR(\"Jérémie Dautheribes <jeremie.dautheribes@bootlin.com>\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/include/linux/mfd/aaeon-mcu.h b/include/linux/mfd/aaeon-mcu.h\nnew file mode 100644\nindex 000000000000..3a1aeec85d60\n--- /dev/null\n+++ b/include/linux/mfd/aaeon-mcu.h\n@@ -0,0 +1,40 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Aaeon MCU driver definitions\n+ *\n+ * Copyright (C) 2026 Bootlin\n+ * Author: Jérémie Dautheribes <jeremie.dautheribes@bootlin.com>\n+ * Author: Thomas Perrot <thomas.perrot@bootlin.com>\n+ */\n+\n+#ifndef __LINUX_MFD_AAEON_MCU_H\n+#define __LINUX_MFD_AAEON_MCU_H\n+\n+/*\n+ * MCU register address: the high byte is the command opcode, the low\n+ * byte is the argument.  This matches the 3-byte wire format\n+ * [opcode, arg, value] used by the MCU I2C protocol.\n+ */\n+#define AAEON_MCU_REG(op, arg)\t\t(((op) << 8) | (arg))\n+\n+/*\n+ * Opcode for GPIO input reads. These registers are volatile, their values\n+ * are driven by external signals and can change without CPU involvement.\n+ * Used by the MFD driver's volatile_reg callback to bypass the regmap cache.\n+ */\n+#define AAEON_MCU_READ_GPIO_OPCODE\t0x72\n+\n+/*\n+ * Opcode for watchdog control and status commands.\n+ * The status register (arg=0x02) reflects hardware state and is volatile.\n+ */\n+#define AAEON_MCU_CONTROL_WDT_OPCODE\t0x63\n+\n+/*\n+ * Highest register address in the MCU register map.\n+ * The WRITE_GPIO opcode (0x77) with the highest GPIO argument (0x0B = 11,\n+ * i.e. MAX_GPIOS - 1) produces the largest encoded address.\n+ */\n+#define AAEON_MCU_MAX_REGISTER\t\tAAEON_MCU_REG(0x77, 0x0B)\n+\n+#endif /* __LINUX_MFD_AAEON_MCU_H */\n","prefixes":["v5","3/5"]}