{"id":2218931,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2218931/?format=json","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.0/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":"<20260402051442.1426672-3-a0282524688@gmail.com>","date":"2026-04-02T05:14:42","name":"[v1,2/2] mfd: Add Host Interface (HIF) support for Nuvoton NCT6694","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"8adca1235f9e81a5d135f2a76739968551417e18","submitter":{"id":89578,"url":"http://patchwork.ozlabs.org/api/1.0/people/89578/?format=json","name":"Ming Yu","email":"a0282524688@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260402051442.1426672-3-a0282524688@gmail.com/mbox/","series":[{"id":498427,"url":"http://patchwork.ozlabs.org/api/1.0/series/498427/?format=json","date":"2026-04-02T05:14:41","name":"mfd: nct6694: Refactor transport layer and add HIF (eSPI) support","version":1,"mbox":"http://patchwork.ozlabs.org/series/498427/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2218931/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-34575-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=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=TzYSHT4e;\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-34575-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"TzYSHT4e\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.216.46","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.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)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmVVB2tFtz1yGH\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 02 Apr 2026 16:17:38 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id EC718304591A\n\tfor <incoming@patchwork.ozlabs.org>; Thu,  2 Apr 2026 05:16:00 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id B6D34377ED4;\n\tThu,  2 Apr 2026 05:15:46 +0000 (UTC)","from mail-pj1-f46.google.com (mail-pj1-f46.google.com\n [209.85.216.46])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 33A19375F7C\n\tfor <linux-gpio@vger.kernel.org>; Thu,  2 Apr 2026 05:15:43 +0000 (UTC)","by mail-pj1-f46.google.com with SMTP id\n 98e67ed59e1d1-35d8e548a05so414853a91.1\n        for <linux-gpio@vger.kernel.org>;\n Wed, 01 Apr 2026 22:15:43 -0700 (PDT)","from hcdev-d520mt2.. (60-250-196-139.hinet-ip.hinet.net.\n [60.250.196.139])\n        by smtp.gmail.com with ESMTPSA id\n 98e67ed59e1d1-35dbe93661fsm6902107a91.11.2026.04.01.22.15.38\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Wed, 01 Apr 2026 22:15:41 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775106946; cv=none;\n b=iwncsSrjos6cy6RysUN1wX/csmo8CTKip8KFA4Voy9Cn8nzZhW7t0wFqyEMQqsru2m5TGOE+w1ChIxtlthrXIDK9gYqNGTGgWbxU1PiUtEkEEly8zgVsicgyki7WHMTDazny3BwGBuNUdLzA1hI5A0+z1osqrM68NlJo1w4r8Kw=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775106946; c=relaxed/simple;\n\tbh=8CU2mHe8Ft/cnSHYweJrmXkjm6QHznfcLRBHfZxIdJ0=;\n\th=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n\t MIME-Version:Content-Type;\n b=qWjE8ymelzyeYf/D5F+C9e7BTTkq+HW0fQovSXZAFXs3WICbUh7h7vHRkLVkvT7kWvhHbVdLYVlYuhqqb+LEt07i4f/NsX7HyWavq31lj0VUpyMis28PsJZhCCEB52HI37LqdCAMMl2JKNyqykrc6tLh9NMJ64BvqAeSzDNDq5A=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=TzYSHT4e; arc=none smtp.client-ip=209.85.216.46","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1775106942; x=1775711742;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=R/hX4IZ54cyXA00IabMHW3Oiay+D3kHDi2lk9JIA4fI=;\n        b=TzYSHT4evgwfCxitN0HVbK9RILe1N3bbyIz5V77m3qyzmo3QyKSVwSGhHBg/JvqZps\n         zj2SwDZsCzZkzIj4LXb7m8JzDnEecNllhMfd/oQ/kFGLRD7Y/tNEDYN67iOI9TX3AUWP\n         RMM2vGHwB3YVincCNgik5HUuoyHX+KRyLczndV6eajUn24GSEXM1QIaAgC4U6W1TsCfP\n         GlZ2LkM8NSXC92AlhjaOxzUnLIme/XgVcicC6v9hltgJKHRR48PK8PYNpTIK99w89RaK\n         iwffPxynGnZc36ug6R5OF+WyAEGefj4ifsCVG1/8zpfONThp0DeBOSe8JdxinxTOX61v\n         tgxg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1775106942; x=1775711742;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=R/hX4IZ54cyXA00IabMHW3Oiay+D3kHDi2lk9JIA4fI=;\n        b=Vl+DU9t/4E0kjfo9ZGGTmwoC0Q/Rz6REBZeSX8UuV0wyTXsQzFzqVvCr9pQfdR8zte\n         8eDr6RoCXFLYOBKaLKUeTs4LxioNHrk7eex6YFBETxzEmawrLYGPSIRPn6YxjlVTm0SM\n         IsvKG4TF1+TV2UsxEAuJfojfRsUuIO9Ymur8vMNt9L/ayHr2tLybMnNpEQV52/q8rMtB\n         YQzx4tHXJZMlEkRDKh2oXsFono8PLUcY5eLp4Ye8ZGiRutkxZPZ5i1IuV8yGoNwVWq8A\n         bODsBp8++s4yVeboO9gbiQAOtSbpU5du4cJn1BF6EwBXuf6sJNOYFO0zno9HA0ka7rfi\n         rOug==","X-Forwarded-Encrypted":"i=1;\n AJvYcCU250KAGI20wDDG+GP5w50/OvBTqdMFVC31BMeDgtD7O/ebYjCibJdw+K+qhS5ZufHKeKzO2m0+8/4X@vger.kernel.org","X-Gm-Message-State":"AOJu0Yy0uJ4P223gjZtFzXhOPnRVqBDU1LrzBTZ5iS1T3SDcoYk0dVQQ\n\tSlPw9RE10AwJm9bXROXp2zpdCHQYDqzSNsMQg85KPNGK1u1iM946CIik","X-Gm-Gg":"AeBDiet2FmubE9DgNdakP5/geFkX9KzLiSieTddgSFrgKfCdlI9Og3U3DlQ8MKmC1VR\n\tzlXehFP+DVcX0FtV5Toqdmh3E3Ozil93N13vRYpdNb3coGUEYIReG8/nFBA0eEJmhinjBMZ+whh\n\tZcpMl1QgYbYLQg7BzXjW8ZDRBSTuTN7fTF9+fURQGZ9EEjFv5xG39a0OE/HWlpIU+Zus7BPjoWi\n\tB8zx9S5/gXxji+08pGxYv96vPxSreQ23NBsn+LKd4377THaEAMmZRjhLon+jrVS4y8zhZs8+g4/\n\t1U+o5ofEfF2bH0wvwOQAd6k+KnegMi6gykvFxYWqwVtwrVJcfuuFOSK6ni+x/J0W9Yb1laEhAZ4\n\t8mj7VU0SaX17tWupb+cTO04182KtsyDKsOxzSwhBsO2zEfYWEK5KjOcIMTUETvCpZcxopF9XEfn\n\tMs8JheS63mv7zMRoElaSJueRmjBdkPsNJmxX5cmAY3z0Vk5cuiP2Ni/ohjFTr2Mp39Ew==","X-Received":"by 2002:a17:90b:28ce:b0:35b:e551:e776 with SMTP id\n 98e67ed59e1d1-35dc70192b6mr6070276a91.27.1775106942266;\n        Wed, 01 Apr 2026 22:15:42 -0700 (PDT)","From":"a0282524688@gmail.com","To":"tmyu0@nuvoton.com,\n\tlinusw@kernel.org,\n\tbrgl@kernel.org,\n\tlinux@roeck-us.net,\n\tandi.shyti@kernel.org,\n\tlee@kernel.org,\n\tmkl@pengutronix.de,\n\tmailhol@kernel.org,\n\talexandre.belloni@bootlin.com,\n\twim@linux-watchdog.org","Cc":"linux-kernel@vger.kernel.org,\n\tlinux-gpio@vger.kernel.org,\n\tlinux-i2c@vger.kernel.org,\n\tlinux-can@vger.kernel.org,\n\tnetdev@vger.kernel.org,\n\tlinux-watchdog@vger.kernel.org,\n\tlinux-hwmon@vger.kernel.org,\n\tlinux-rtc@vger.kernel.org,\n\tlinux-usb@vger.kernel.org,\n\tMing Yu <a0282524688@gmail.com>","Subject":"[PATCH v1 2/2] mfd: Add Host Interface (HIF) support for Nuvoton\n NCT6694","Date":"Thu,  2 Apr 2026 13:14:42 +0800","Message-Id":"<20260402051442.1426672-3-a0282524688@gmail.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20260402051442.1426672-1-a0282524688@gmail.com>","References":"<20260402051442.1426672-1-a0282524688@gmail.com>","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"},"content":"From: Ming Yu <a0282524688@gmail.com>\n\nThe Nuvoton NCT6694 also provides a Host Interface (HIF) via eSPI\nto the host to access its features.\n\nSub-devices can use the common functions nct6694_read_msg() and\nnct6694_write_msg() to issue a command. They can also request\ninterrupts that will be called when the HIF device triggers a\nshared memory interrupt.\n\nTo support multiple transports, the driver configuration is\nupdated to allow selecting between the USB and HIF interfaces.\n\nSigned-off-by: Ming Yu <a0282524688@gmail.com>\n---\n MAINTAINERS                         |   1 +\n drivers/gpio/gpio-nct6694.c         |   7 -\n drivers/hwmon/nct6694-hwmon.c       |  21 -\n drivers/i2c/busses/i2c-nct6694.c    |   7 -\n drivers/mfd/Kconfig                 |  47 +-\n drivers/mfd/Makefile                |   3 +-\n drivers/mfd/nct6694-hif.c           | 649 ++++++++++++++++++++++++++++\n drivers/mfd/nct6694.c               |  97 +++--\n drivers/net/can/usb/nct6694_canfd.c |   6 -\n drivers/rtc/rtc-nct6694.c           |   7 -\n drivers/watchdog/nct6694_wdt.c      |   7 -\n include/linux/mfd/nct6694.h         |  51 ++-\n 12 files changed, 787 insertions(+), 116 deletions(-)\n create mode 100644 drivers/mfd/nct6694-hif.c","diff":"diff --git a/MAINTAINERS b/MAINTAINERS\nindex c3fe46d7c4bc..7b6241faa6df 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -18899,6 +18899,7 @@ S:\tSupported\n F:\tdrivers/gpio/gpio-nct6694.c\n F:\tdrivers/hwmon/nct6694-hwmon.c\n F:\tdrivers/i2c/busses/i2c-nct6694.c\n+F:\tdrivers/mfd/nct6694-hif.c\n F:\tdrivers/mfd/nct6694.c\n F:\tdrivers/net/can/usb/nct6694_canfd.c\n F:\tdrivers/rtc/rtc-nct6694.c\ndiff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c\nindex 3703a61209e6..a279510ece89 100644\n--- a/drivers/gpio/gpio-nct6694.c\n+++ b/drivers/gpio/gpio-nct6694.c\n@@ -12,13 +12,6 @@\n #include <linux/module.h>\n #include <linux/platform_device.h>\n \n-/*\n- * USB command module type for NCT6694 GPIO controller.\n- * This defines the module type used for communication with the NCT6694\n- * GPIO controller over the USB interface.\n- */\n-#define NCT6694_GPIO_MOD\t0xFF\n-\n #define NCT6694_GPIO_VER\t0x90\n #define NCT6694_GPIO_VALID\t0x110\n #define NCT6694_GPI_DATA\t0x120\ndiff --git a/drivers/hwmon/nct6694-hwmon.c b/drivers/hwmon/nct6694-hwmon.c\nindex 6dcf22ca5018..581451875f2c 100644\n--- a/drivers/hwmon/nct6694-hwmon.c\n+++ b/drivers/hwmon/nct6694-hwmon.c\n@@ -15,13 +15,6 @@\n #include <linux/platform_device.h>\n #include <linux/slab.h>\n \n-/*\n- * USB command module type for NCT6694 report channel\n- * This defines the module type used for communication with the NCT6694\n- * report channel over the USB interface.\n- */\n-#define NCT6694_RPT_MOD\t\t\t0xFF\n-\n /* Report channel */\n /*\n  * The report channel is used to report the status of the hardware monitor\n@@ -38,13 +31,6 @@\n #define NCT6694_TIN_STS(x)\t\t(0x6A + (x))\n #define NCT6694_FIN_STS(x)\t\t(0x6E + (x))\n \n-/*\n- * USB command module type for NCT6694 HWMON controller.\n- * This defines the module type used for communication with the NCT6694\n- * HWMON controller over the USB interface.\n- */\n-#define NCT6694_HWMON_MOD\t\t0x00\n-\n /* Command 00h - Hardware Monitor Control */\n #define NCT6694_HWMON_CONTROL\t\t0x00\n #define NCT6694_HWMON_CONTROL_SEL\t0x00\n@@ -53,13 +39,6 @@\n #define NCT6694_HWMON_ALARM\t\t0x02\n #define NCT6694_HWMON_ALARM_SEL\t\t0x00\n \n-/*\n- * USB command module type for NCT6694 PWM controller.\n- * This defines the module type used for communication with the NCT6694\n- * PWM controller over the USB interface.\n- */\n-#define NCT6694_PWM_MOD\t\t\t0x01\n-\n /* PWM Command - Manual Control */\n #define NCT6694_PWM_CONTROL\t\t0x01\n #define NCT6694_PWM_CONTROL_SEL\t\t0x00\ndiff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c\nindex 7d8ad997f6d2..7ee209a04d16 100644\n--- a/drivers/i2c/busses/i2c-nct6694.c\n+++ b/drivers/i2c/busses/i2c-nct6694.c\n@@ -11,13 +11,6 @@\n #include <linux/module.h>\n #include <linux/platform_device.h>\n \n-/*\n- * USB command module type for NCT6694 I2C controller.\n- * This defines the module type used for communication with the NCT6694\n- * I2C controller over the USB interface.\n- */\n-#define NCT6694_I2C_MOD\t\t\t0x03\n-\n /* Command 00h - I2C Deliver */\n #define NCT6694_I2C_DELIVER\t\t0x00\n #define NCT6694_I2C_DELIVER_SEL\t\t0x00\ndiff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig\nindex 7192c9d1d268..8a715ec2f79f 100644\n--- a/drivers/mfd/Kconfig\n+++ b/drivers/mfd/Kconfig\n@@ -1164,19 +1164,46 @@ config MFD_MENF21BMC\n \t  will be called menf21bmc.\n \n config MFD_NCT6694\n-\ttristate \"Nuvoton NCT6694 support\"\n+\ttristate\n \tselect MFD_CORE\n+\thelp\n+\t  Core MFD support for the Nuvoton NCT6694 peripheral expander.\n+\t  This provides the common APIs and shared structures used by all\n+\t  interfaces (USB, HIF) to access the NCT6694 hardware features\n+\t  such as GPIO, I2C, CAN-FD, Watchdog, ADC, PWM, and RTC.\n+\n+\t  It is selected automatically by the transport interface drivers.\n+\n+config MFD_NCT6694_HIF\n+\ttristate \"Nuvoton NCT6694 HIF (eSPI) interface support\"\n+\tdepends on HAS_IOPORT && ACPI\n+\tselect MFD_NCT6694\n+\tselect REGMAP_MMIO\n+\thelp\n+\t  This enables support for the Nuvoton NCT6694 peripheral expander\n+\t  connected via the Host Interface (HIF) using eSPI transport.\n+\n+\t  The transport driver uses Super-I/O mapping and shared memory to\n+\t  communicate with the NCT6694 firmware. Enable this option if you\n+\t  are using the NCT6694 over an eSPI interface on an ACPI platform.\n+\n+\t  To compile this driver as a module, choose M here: the module\n+\t  will be called nct6694-hif.\n+\n+config MFD_NCT6694_USB\n+\ttristate \"Nuvoton NCT6694 USB interface support\"\n+\tselect MFD_NCT6694\n \tdepends on USB\n \thelp\n-\t  This enables support for the Nuvoton USB device NCT6694, which shares\n-\t  peripherals.\n-\t  The Nuvoton NCT6694 is a peripheral expander with 16 GPIO chips,\n-\t  6 I2C controllers, 2 CANfd controllers, 2 Watchdog timers, ADC,\n-\t  PWM, and RTC.\n-\t  This driver provides core APIs to access the NCT6694 hardware\n-\t  monitoring and control features.\n-\t  Additional drivers must be enabled to utilize the specific\n-\t  functionalities of the device.\n+\t  This enables support for the Nuvoton NCT6694 peripheral expander\n+\t  connected via the USB interface.\n+\n+\t  The transport driver uses USB bulk and interrupt transfers to\n+\t  communicate with the NCT6694 firmware. Enable this option if you\n+\t  are using the NCT6694 via a USB connection.\n+\n+\t  To compile this driver as a module, choose M here: the module\n+\t  will be called nct6694.\n \n config MFD_OCELOT\n \ttristate \"Microsemi Ocelot External Control Support\"\ndiff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile\nindex e75e8045c28a..4cee9b74978c 100644\n--- a/drivers/mfd/Makefile\n+++ b/drivers/mfd/Makefile\n@@ -124,7 +124,8 @@ obj-$(CONFIG_MFD_MC13XXX_I2C)\t+= mc13xxx-i2c.o\n \n obj-$(CONFIG_MFD_PF1550)\t+= pf1550.o\n \n-obj-$(CONFIG_MFD_NCT6694)\t+= nct6694.o\n+obj-$(CONFIG_MFD_NCT6694_HIF)\t+= nct6694-hif.o\n+obj-$(CONFIG_MFD_NCT6694_USB)\t+= nct6694.o\n \n obj-$(CONFIG_MFD_CORE)\t\t+= mfd-core.o\n \ndiff --git a/drivers/mfd/nct6694-hif.c b/drivers/mfd/nct6694-hif.c\nnew file mode 100644\nindex 000000000000..a5953c951eb5\n--- /dev/null\n+++ b/drivers/mfd/nct6694-hif.c\n@@ -0,0 +1,649 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2026 Nuvoton Technology Corp.\n+ *\n+ * Nuvoton NCT6694 host-interface (eSPI) transport driver.\n+ */\n+\n+#include <linux/acpi.h>\n+#include <linux/bits.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/iopoll.h>\n+#include <linux/irq.h>\n+#include <linux/irqdomain.h>\n+#include <linux/kernel.h>\n+#include <linux/mfd/core.h>\n+#include <linux/mfd/nct6694.h>\n+#include <linux/module.h>\n+#include <linux/platform_device.h>\n+#include <linux/regmap.h>\n+#include <linux/unaligned.h>\n+\n+#define DRVNAME \"nct6694-hif\"\n+\n+#define NCT6694_POLL_INTERVAL_US\t10\n+#define NCT6694_POLL_TIMEOUT_US\t\t10000\n+\n+/*\n+ * Super-I/O registers\n+ */\n+#define SIO_REG_LDSEL\t\t0x07\t/* Logical device select */\n+#define SIO_REG_DEVID\t\t0x20\t/* Device ID (2 bytes) */\n+#define SIO_REG_LD_SHM\t\t0x0F\t/* Logical device shared memory control */\n+\n+#define SIO_REG_SHM_ENABLE\t0x30\t/* Enable shared memory */\n+#define SIO_REG_SHM_BASE_ADDR\t0x60\t/* Shared memory base address (2 bytes) */\n+#define SIO_REG_SHM_IRQ_NR\t0x70\t/* Shared memory interrupt number */\n+\n+#define SIO_REG_UNLOCK_KEY\t0x87\t/* Key to enable Super-I/O */\n+#define SIO_REG_LOCK_KEY\t0xAA\t/* Key to disable Super-I/O */\n+\n+#define SIO_NCT6694B_ID\t\t0xD029\n+#define SIO_NCT6694D_ID\t\t0x5832\n+\n+/*\n+ * Super-I/O Shared Memory Logical Device registers\n+ */\n+#define NCT6694_SHM_COFS_STS\t\t\t0x2E\n+#define NCT6694_SHM_COFS_STS_COFS4W\t\tBIT(7)\n+\n+#define NCT6694_SHM_COFS_CTL2\t\t\t0x3B\n+#define NCT6694_SHM_COFS_CTL2_COFS4W_IE\t\tBIT(3)\n+\n+#define NCT6694_SHM_INTR_STATUS\t\t\t0x9C\t/* Interrupt status register (4 bytes) */\n+\n+enum nct6694_chips {\n+\tNCT6694B = 0,\n+\tNCT6694D,\n+};\n+\n+enum nct6694_module_id {\n+\tNCT6694_GPIO0 = 0,\n+\tNCT6694_GPIO1,\n+\tNCT6694_GPIO2,\n+\tNCT6694_GPIO3,\n+\tNCT6694_GPIO4,\n+\tNCT6694_GPIO5,\n+\tNCT6694_GPIO6,\n+\tNCT6694_GPIO7,\n+\tNCT6694_GPIO8,\n+\tNCT6694_GPIO9,\n+\tNCT6694_GPIOA,\n+\tNCT6694_GPIOB,\n+\tNCT6694_GPIOC,\n+\tNCT6694_GPIOD,\n+\tNCT6694_GPIOE,\n+\tNCT6694_GPIOF,\n+\tNCT6694_I2C0,\n+\tNCT6694_I2C1,\n+\tNCT6694_I2C2,\n+\tNCT6694_I2C3,\n+\tNCT6694_I2C4,\n+\tNCT6694_I2C5,\n+\tNCT6694_CAN0,\n+\tNCT6694_CAN1,\n+};\n+\n+struct __packed nct6694_msg {\n+\tstruct nct6694_cmd_header cmd_header;\n+\tstruct nct6694_response_header response_header;\n+\tunsigned char *data;\n+};\n+\n+struct nct6694_sio_data {\n+\tenum nct6694_chips chip;\n+\tint sioreg;\t/* Super-I/O index port */\n+\n+\t/* Super-I/O access functions */\n+\tint (*sio_enter)(struct nct6694_sio_data *sio_data);\n+\tvoid (*sio_exit)(struct nct6694_sio_data *sio_data);\n+\tvoid (*sio_select)(struct nct6694_sio_data *sio_data, int ld);\n+\tint (*sio_inb)(struct nct6694_sio_data *sio_data, int reg);\n+\tint (*sio_inw)(struct nct6694_sio_data *sio_data, int reg);\n+\tvoid (*sio_outb)(struct nct6694_sio_data *sio_data, int reg, int val);\n+};\n+\n+struct nct6694_hif_data {\n+\tstruct regmap *regmap;\n+\tstruct mutex msg_lock;\n+\tstruct nct6694_sio_data *sio_data;\n+\tvoid __iomem *msg_base;\n+\tunsigned int shm_base;\n+};\n+\n+static const char * const nct6694_chip_names[] = {\n+\t\"NCT6694D\",\n+\t\"NCT6694B\"\n+};\n+\n+/*\n+ * Super-I/O functions.\n+ */\n+static int superio_enter(struct nct6694_sio_data *sio_data)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\n+\t/*\n+\t * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.\n+\t */\n+\tif (!request_muxed_region(ioreg, 2, DRVNAME))\n+\t\treturn -EBUSY;\n+\n+\toutb(SIO_REG_UNLOCK_KEY, ioreg);\n+\toutb(SIO_REG_UNLOCK_KEY, ioreg);\n+\n+\treturn 0;\n+}\n+\n+static void superio_exit(struct nct6694_sio_data *sio_data)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\n+\toutb(SIO_REG_LOCK_KEY, ioreg);\n+\n+\trelease_region(ioreg, 2);\n+}\n+\n+static void superio_select(struct nct6694_sio_data *sio_data, int ld)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\n+\toutb(SIO_REG_LDSEL, ioreg);\n+\toutb(ld, ioreg + 1);\n+}\n+\n+static int superio_inb(struct nct6694_sio_data *sio_data, int reg)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\n+\toutb(reg, ioreg);\n+\treturn inb(ioreg + 1);\n+}\n+\n+static int superio_inw(struct nct6694_sio_data *sio_data, int reg)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\tint val;\n+\n+\toutb(reg++, ioreg);\n+\tval = inb(ioreg + 1) << 8;\n+\toutb(reg, ioreg);\n+\tval |= inb(ioreg + 1);\n+\n+\treturn val;\n+}\n+\n+static void superio_outb(struct nct6694_sio_data *sio_data, int reg, int val)\n+{\n+\tint ioreg = sio_data->sioreg;\n+\n+\toutb(reg, ioreg);\n+\toutb(val, ioreg + 1);\n+}\n+\n+static int nct6694_sio_find(struct nct6694_sio_data *sio_data, u8 sioreg)\n+{\n+\tint ret;\n+\tu16 devid;\n+\n+\tsio_data->sioreg = sioreg;\n+\n+\tret = sio_data->sio_enter(sio_data);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Check Chip ID */\n+\tdevid = sio_data->sio_inw(sio_data, SIO_REG_DEVID);\n+\tswitch (devid) {\n+\tcase SIO_NCT6694B_ID:\n+\t\tsio_data->chip = NCT6694B;\n+\t\tbreak;\n+\tcase SIO_NCT6694D_ID:\n+\t\tsio_data->chip = NCT6694D;\n+\t\tbreak;\n+\tdefault:\n+\t\tpr_err(\"Unsupported device 0x%04x\\n\", devid);\n+\t\tgoto err;\n+\t}\n+\n+\tpr_info(\"Found %s at %#x\\n\", nct6694_chip_names[sio_data->chip], sio_data->sioreg);\n+\n+\tsio_data->sio_exit(sio_data);\n+\n+\treturn 0;\n+\n+err:\n+\tsio_data->sio_exit(sio_data);\n+\treturn -ENODEV;\n+}\n+\n+static const struct mfd_cell_acpi_match nct6694_acpi_match_gpio[] = {\n+\t{ .adr = NCT6694_GPIO0 },\n+\t{ .adr = NCT6694_GPIO1 },\n+\t{ .adr = NCT6694_GPIO2 },\n+\t{ .adr = NCT6694_GPIO3 },\n+\t{ .adr = NCT6694_GPIO4 },\n+\t{ .adr = NCT6694_GPIO5 },\n+\t{ .adr = NCT6694_GPIO6 },\n+\t{ .adr = NCT6694_GPIO7 },\n+\t{ .adr = NCT6694_GPIO8 },\n+\t{ .adr = NCT6694_GPIO9 },\n+\t{ .adr = NCT6694_GPIOA },\n+\t{ .adr = NCT6694_GPIOB },\n+\t{ .adr = NCT6694_GPIOC },\n+\t{ .adr = NCT6694_GPIOD },\n+\t{ .adr = NCT6694_GPIOE },\n+\t{ .adr = NCT6694_GPIOF },\n+};\n+\n+static const struct mfd_cell_acpi_match nct6694_acpi_match_i2c[] = {\n+\t{ .adr = NCT6694_I2C0 },\n+\t{ .adr = NCT6694_I2C1 },\n+\t{ .adr = NCT6694_I2C2 },\n+\t{ .adr = NCT6694_I2C3 },\n+\t{ .adr = NCT6694_I2C4 },\n+\t{ .adr = NCT6694_I2C5 },\n+};\n+\n+static const struct mfd_cell_acpi_match nct6694_acpi_match_can[] = {\n+\t{ .adr = NCT6694_CAN0 },\n+\t{ .adr = NCT6694_CAN1 },\n+};\n+\n+static const struct mfd_cell nct6694_devs[] = {\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 0, &nct6694_acpi_match_gpio[0]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 1, &nct6694_acpi_match_gpio[1]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 2, &nct6694_acpi_match_gpio[2]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 3, &nct6694_acpi_match_gpio[3]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 4, &nct6694_acpi_match_gpio[4]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 5, &nct6694_acpi_match_gpio[5]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 6, &nct6694_acpi_match_gpio[6]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 7, &nct6694_acpi_match_gpio[7]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 8, &nct6694_acpi_match_gpio[8]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 9, &nct6694_acpi_match_gpio[9]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 10, &nct6694_acpi_match_gpio[10]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 11, &nct6694_acpi_match_gpio[11]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 12, &nct6694_acpi_match_gpio[12]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 13, &nct6694_acpi_match_gpio[13]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 14, &nct6694_acpi_match_gpio[14]),\n+\tMFD_CELL_ACPI(\"nct6694-gpio\", NULL, NULL, 0, 15, &nct6694_acpi_match_gpio[15]),\n+\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 0, &nct6694_acpi_match_i2c[0]),\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 1, &nct6694_acpi_match_i2c[1]),\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 2, &nct6694_acpi_match_i2c[2]),\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 3, &nct6694_acpi_match_i2c[3]),\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 4, &nct6694_acpi_match_i2c[4]),\n+\tMFD_CELL_ACPI(\"nct6694-i2c\", NULL, NULL, 0, 5, &nct6694_acpi_match_i2c[5]),\n+\n+\tMFD_CELL_ACPI(\"nct6694-canfd\", NULL, NULL, 0, 0, &nct6694_acpi_match_can[0]),\n+\tMFD_CELL_ACPI(\"nct6694-canfd\", NULL, NULL, 0, 1, &nct6694_acpi_match_can[1]),\n+};\n+\n+static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)\n+{\n+\tswitch (err_status) {\n+\tcase NCT6694_NO_ERROR:\n+\t\treturn 0;\n+\tcase NCT6694_NOT_SUPPORT_ERROR:\n+\t\tdev_err(nct6694->dev, \"Command is not supported!\\n\");\n+\t\tbreak;\n+\tcase NCT6694_NO_RESPONSE_ERROR:\n+\t\tdev_warn(nct6694->dev, \"Command received no response!\\n\");\n+\t\tbreak;\n+\tcase NCT6694_TIMEOUT_ERROR:\n+\t\tdev_warn(nct6694->dev, \"Command timed out!\\n\");\n+\t\tbreak;\n+\tcase NCT6694_PENDING:\n+\t\tdev_err(nct6694->dev, \"Command is pending!\\n\");\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn -EIO;\n+}\n+\n+static int nct6694_xfer_msg(struct nct6694 *nct6694,\n+\t\t\t    const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t    u8 hctrl, void *buf)\n+{\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\tvoid __iomem *hdr = hdata->msg_base + offsetof(struct nct6694_msg, cmd_header);\n+\tstruct nct6694_cmd_header cmd = *cmd_hd;\n+\tstruct nct6694_response_header resp;\n+\tu16 len = le16_to_cpu(cmd.len);\n+\tu8 status;\n+\tint ret;\n+\n+\tguard(mutex)(&hdata->msg_lock);\n+\n+\t/* Wait until the previous command is completed */\n+\tret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),\n+\t\t\t\t status, status == 0, NCT6694_POLL_INTERVAL_US,\n+\t\t\t\t NCT6694_POLL_TIMEOUT_US);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/*\n+\t * Write cmd header fields, but skip hctrl — writing to it triggers\n+\t * firmware command processing and must be deferred until data is ready.\n+\t */\n+\tmemcpy_toio(hdr, &cmd, offsetof(struct nct6694_cmd_header, hctrl));\n+\tmemcpy_toio(hdr + offsetof(struct nct6694_cmd_header, rsv2), &cmd.rsv2,\n+\t\t    sizeof(cmd) - offsetof(struct nct6694_cmd_header, rsv2));\n+\n+\tif (hctrl == NCT6694_HCTRL_SET && len)\n+\t\tmemcpy_toio(hdata->msg_base + offsetof(struct nct6694_msg, data),\n+\t\t\t    buf, len);\n+\n+\t/* Write hctrl last to trigger command processing */\n+\twriteb(hctrl, hdr + offsetof(struct nct6694_cmd_header, hctrl));\n+\n+\tret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),\n+\t\t\t\t status, status == 0, NCT6694_POLL_INTERVAL_US,\n+\t\t\t\t NCT6694_POLL_TIMEOUT_US);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmemcpy_fromio(&resp, hdata->msg_base + offsetof(struct nct6694_msg, response_header),\n+\t\t      sizeof(resp));\n+\n+\tret = nct6694_response_err_handling(nct6694, resp.sts);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (le16_to_cpu(resp.len))\n+\t\tmemcpy_fromio(buf, hdata->msg_base + offsetof(struct nct6694_msg, data),\n+\t\t\t      min(len, le16_to_cpu(resp.len)));\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * nct6694_hif_read_msg() - Send a command and read response data via HIF\n+ * @nct6694: NCT6694 device data\n+ * @cmd_hd: command header\n+ * @buf: buffer to store response data\n+ *\n+ * Return: 0 on success or negative errno on failure.\n+ */\n+static int nct6694_hif_read_msg(struct nct6694 *nct6694,\n+\t\t\t\tconst struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\tvoid *buf)\n+{\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\n+\tif (cmd_hd->mod == NCT6694_RPT_MOD)\n+\t\treturn regmap_bulk_read(hdata->regmap,\n+\t\t\t\t\tle16_to_cpu(cmd_hd->offset),\n+\t\t\t\t\tbuf, le16_to_cpu(cmd_hd->len));\n+\treturn nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_GET, buf);\n+}\n+\n+/**\n+ * nct6694_hif_write_msg() - Send a command with data payload via HIF\n+ * @nct6694: NCT6694 device data\n+ * @cmd_hd: command header\n+ * @buf: buffer containing data to send\n+ *\n+ * Return: 0 on success or negative errno on failure.\n+ */\n+static int nct6694_hif_write_msg(struct nct6694 *nct6694,\n+\t\t\t\t const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\t void *buf)\n+{\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\n+\tif (cmd_hd->mod == NCT6694_RPT_MOD)\n+\t\treturn regmap_bulk_write(hdata->regmap,\n+\t\t\t\t\t le16_to_cpu(cmd_hd->offset),\n+\t\t\t\t\t buf, le16_to_cpu(cmd_hd->len));\n+\treturn nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_SET, buf);\n+}\n+\n+static const struct regmap_config nct6694_regmap_config = {\n+\t.reg_bits = 8,\n+\t.val_bits = 8,\n+\t.reg_stride = 1,\n+};\n+\n+static irqreturn_t nct6694_irq_handler(int irq, void *data)\n+{\n+\tstruct nct6694 *nct6694 = data;\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\tu8 reg_data[4];\n+\tu32 intr_status;\n+\tint ret;\n+\n+\t/* Check interrupt status is set */\n+\tif (!(inb(hdata->shm_base + NCT6694_SHM_COFS_STS) & NCT6694_SHM_COFS_STS_COFS4W))\n+\t\treturn IRQ_NONE;\n+\n+\t/* Clear interrupt status */\n+\toutb(NCT6694_SHM_COFS_STS_COFS4W, hdata->shm_base + NCT6694_SHM_COFS_STS);\n+\n+\tret = regmap_bulk_read(hdata->regmap, NCT6694_SHM_INTR_STATUS,\n+\t\t\t       reg_data, ARRAY_SIZE(reg_data));\n+\tif (ret)\n+\t\treturn IRQ_NONE;\n+\n+\tintr_status = get_unaligned_le32(reg_data);\n+\n+\twhile (intr_status) {\n+\t\tint irq = __ffs(intr_status);\n+\n+\t\tgeneric_handle_irq_safe(irq_find_mapping(nct6694->domain, irq));\n+\t\tintr_status &= ~BIT(irq);\n+\t}\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static void nct6694_irq_release(void *data)\n+{\n+\tstruct nct6694 *nct6694 = data;\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\tunsigned char cofs_ctl2;\n+\n+\t/* Disable SIRQ interrupt */\n+\tcofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);\n+\tcofs_ctl2 &= ~NCT6694_SHM_COFS_CTL2_COFS4W_IE;\n+\toutb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);\n+}\n+\n+static int nct6694_irq_init(struct nct6694 *nct6694, int irq)\n+{\n+\tstruct nct6694_hif_data *hdata = nct6694->priv;\n+\tstruct nct6694_sio_data *sio_data = hdata->sio_data;\n+\tunsigned char cofs_ctl2;\n+\n+\t/* Set SIRQ number */\n+\tsio_data->sio_enter(sio_data);\n+\tsio_data->sio_select(sio_data, SIO_REG_LD_SHM);\n+\tif (!sio_data->sio_inb(sio_data, SIO_REG_SHM_ENABLE)) {\n+\t\tsio_data->sio_exit(sio_data);\n+\t\treturn -EIO;\n+\t}\n+\thdata->shm_base = sio_data->sio_inw(sio_data, SIO_REG_SHM_BASE_ADDR);\n+\n+\tsio_data->sio_outb(sio_data, SIO_REG_SHM_IRQ_NR, irq);\n+\n+\tsio_data->sio_exit(sio_data);\n+\n+\t/* Enable SIRQ interrupt */\n+\tcofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);\n+\tcofs_ctl2 |= NCT6694_SHM_COFS_CTL2_COFS4W_IE;\n+\toutb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);\n+\n+\treturn 0;\n+}\n+\n+static void nct6694_irq_enable(struct irq_data *data)\n+{\n+\tstruct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);\n+\tirq_hw_number_t hwirq = irqd_to_hwirq(data);\n+\n+\tguard(spinlock_irqsave)(&nct6694->irq_lock);\n+\n+\tnct6694->irq_enable |= BIT(hwirq);\n+}\n+\n+static void nct6694_irq_disable(struct irq_data *data)\n+{\n+\tstruct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);\n+\tirq_hw_number_t hwirq = irqd_to_hwirq(data);\n+\n+\tguard(spinlock_irqsave)(&nct6694->irq_lock);\n+\n+\tnct6694->irq_enable &= ~BIT(hwirq);\n+}\n+\n+static const struct irq_chip nct6694_irq_chip = {\n+\t.name = \"nct6694-irq\",\n+\t.flags = IRQCHIP_SKIP_SET_WAKE,\n+\t.irq_enable = nct6694_irq_enable,\n+\t.irq_disable = nct6694_irq_disable,\n+};\n+\n+static void nct6694_irq_domain_remove(void *data)\n+{\n+\tstruct nct6694 *nct6694 = data;\n+\n+\tirq_domain_remove(nct6694->domain);\n+}\n+\n+static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)\n+{\n+\tstruct nct6694 *nct6694 = d->host_data;\n+\n+\tirq_set_chip_data(irq, nct6694);\n+\tirq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq);\n+\n+\treturn 0;\n+}\n+\n+static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq)\n+{\n+\tirq_set_chip_and_handler(irq, NULL, NULL);\n+\tirq_set_chip_data(irq, NULL);\n+}\n+\n+static const struct irq_domain_ops nct6694_irq_domain_ops = {\n+\t.map\t= nct6694_irq_domain_map,\n+\t.unmap\t= nct6694_irq_domain_unmap,\n+};\n+\n+static const u8 sio_addrs[] = { 0x2e, 0x4e };\n+\n+static int nct6694_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct nct6694_sio_data *sio_data;\n+\tstruct nct6694_hif_data *hdata;\n+\tstruct nct6694 *data;\n+\tvoid __iomem *rpt_base, *msg_base;\n+\tint ret, i, irq;\n+\n+\tsio_data = devm_kzalloc(dev, sizeof(*sio_data), GFP_KERNEL);\n+\tif (!sio_data)\n+\t\treturn -ENOMEM;\n+\n+\tdata = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);\n+\tif (!data)\n+\t\treturn -ENOMEM;\n+\n+\thdata = devm_kzalloc(dev, sizeof(*hdata), GFP_KERNEL);\n+\tif (!hdata)\n+\t\treturn -ENOMEM;\n+\n+\trpt_base = devm_platform_ioremap_resource(pdev, 0);\n+\tif (IS_ERR(rpt_base))\n+\t\treturn PTR_ERR(rpt_base);\n+\tmsg_base = devm_platform_ioremap_resource(pdev, 1);\n+\tif (IS_ERR(msg_base))\n+\t\treturn PTR_ERR(msg_base);\n+\n+\tirq = platform_get_irq(pdev, 0);\n+\tif (irq < 0)\n+\t\treturn irq;\n+\n+\tsio_data->sio_enter = superio_enter;\n+\tsio_data->sio_exit = superio_exit;\n+\tsio_data->sio_select = superio_select;\n+\tsio_data->sio_inb = superio_inb;\n+\tsio_data->sio_inw = superio_inw;\n+\tsio_data->sio_outb = superio_outb;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(sio_addrs); i++) {\n+\t\tret = nct6694_sio_find(sio_data, sio_addrs[i]);\n+\t\tif (!ret)\n+\t\t\tbreak;\n+\t}\n+\tif (ret)\n+\t\treturn ret;\n+\n+\thdata->sio_data = sio_data;\n+\thdata->msg_base = msg_base;\n+\thdata->regmap = devm_regmap_init_mmio(dev, rpt_base,\n+\t\t\t\t\t      &nct6694_regmap_config);\n+\tif (IS_ERR(hdata->regmap))\n+\t\treturn PTR_ERR(hdata->regmap);\n+\n+\tdata->dev = dev;\n+\tdata->priv = hdata;\n+\tdata->read_msg = nct6694_hif_read_msg;\n+\tdata->write_msg = nct6694_hif_write_msg;\n+\n+\tspin_lock_init(&data->irq_lock);\n+\n+\tdata->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,\n+\t\t\t\t\t\t&nct6694_irq_domain_ops,\n+\t\t\t\t\t\tdata);\n+\tif (!data->domain)\n+\t\treturn -ENODEV;\n+\n+\tret = devm_add_action_or_reset(dev, nct6694_irq_domain_remove, data);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = nct6694_irq_init(data, irq);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = devm_add_action_or_reset(dev, nct6694_irq_release, data);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = devm_request_threaded_irq(dev, irq, NULL, nct6694_irq_handler,\n+\t\t\t\t\tIRQF_ONESHOT | IRQF_SHARED,\n+\t\t\t\t\tdev_name(dev), data);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = devm_mutex_init(dev, &hdata->msg_lock);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tplatform_set_drvdata(pdev, data);\n+\n+\treturn devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs), NULL, 0, NULL);\n+}\n+\n+static const struct acpi_device_id nct6694_acpi_ids[] = {\n+\t{ \"NTN0538\", 0 },\n+\t{}\n+};\n+\n+static struct platform_driver nct6694_driver = {\n+\t.driver = {\n+\t\t.name = DRVNAME,\n+\t\t.acpi_match_table = nct6694_acpi_ids,\n+\t},\n+\t.probe\t= nct6694_probe,\n+};\n+module_platform_driver(nct6694_driver);\n+\n+MODULE_DESCRIPTION(\"Nuvoton NCT6694 host-interface transport driver\");\n+MODULE_AUTHOR(\"Ming Yu <tmyu0@nuvoton.com>\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c\nindex 8ce2c4985aab..903a0a7f0694 100644\n--- a/drivers/mfd/nct6694.c\n+++ b/drivers/mfd/nct6694.c\n@@ -21,6 +21,27 @@\n #include <linux/spinlock.h>\n #include <linux/usb.h>\n \n+#define NCT6694_VENDOR_ID\t0x0416\n+#define NCT6694_PRODUCT_ID\t0x200B\n+#define NCT6694_INT_IN_EP\t0x81\n+#define NCT6694_BULK_IN_EP\t0x02\n+#define NCT6694_BULK_OUT_EP\t0x03\n+\n+#define NCT6694_URB_TIMEOUT\t1000\n+\n+union __packed nct6694_usb_msg {\n+\tstruct nct6694_cmd_header cmd_header;\n+\tstruct nct6694_response_header response_header;\n+};\n+\n+struct nct6694_usb_data {\n+\tstruct mutex access_lock;\n+\tstruct urb *int_in_urb;\n+\tstruct usb_device *udev;\n+\tunion nct6694_usb_msg *usb_msg;\n+\t__le32 *int_buffer;\n+};\n+\n static const struct mfd_cell nct6694_devs[] = {\n \tMFD_CELL_BASIC(\"nct6694-gpio\", NULL, NULL, 0, 0),\n \tMFD_CELL_BASIC(\"nct6694-gpio\", NULL, NULL, 0, 1),\n@@ -57,7 +78,8 @@ static const struct mfd_cell nct6694_devs[] = {\n \tMFD_CELL_NAME(\"nct6694-rtc\"),\n };\n \n-static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)\n+static int nct6694_usb_err_handling(struct nct6694 *nct6694,\n+\t\t\t\t    unsigned char err_status)\n {\n \tswitch (err_status) {\n \tcase NCT6694_NO_ERROR:\n@@ -82,7 +104,7 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char\n }\n \n /**\n- * nct6694_read_msg() - Read message from NCT6694 device\n+ * nct6694_usb_read_msg() - Read message from NCT6694 device via USB\n  * @nct6694: NCT6694 device pointer\n  * @cmd_hd: command header structure\n  * @buf: buffer to store the response data\n@@ -93,13 +115,16 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char\n  *\n  * Return: Negative value on error or 0 on success.\n  */\n-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)\n+static int nct6694_usb_read_msg(struct nct6694 *nct6694,\n+\t\t\t\tconst struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\tvoid *buf)\n {\n-\tunion nct6694_usb_msg *msg = nct6694->usb_msg;\n-\tstruct usb_device *udev = nct6694->udev;\n+\tstruct nct6694_usb_data *udata = nct6694->priv;\n+\tunion nct6694_usb_msg *msg = udata->usb_msg;\n+\tstruct usb_device *udev = udata->udev;\n \tint tx_len, rx_len, ret;\n \n-\tguard(mutex)(&nct6694->access_lock);\n+\tguard(mutex)(&udata->access_lock);\n \n \tmemcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));\n \tmsg->cmd_header.hctrl = NCT6694_HCTRL_GET;\n@@ -128,12 +153,11 @@ int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *c\n \t\treturn -EIO;\n \t}\n \n-\treturn nct6694_response_err_handling(nct6694, msg->response_header.sts);\n+\treturn nct6694_usb_err_handling(nct6694, msg->response_header.sts);\n }\n-EXPORT_SYMBOL_GPL(nct6694_read_msg);\n \n /**\n- * nct6694_write_msg() - Write message to NCT6694 device\n+ * nct6694_usb_write_msg() - Write message to NCT6694 device via USB\n  * @nct6694: NCT6694 device pointer\n  * @cmd_hd: command header structure\n  * @buf: buffer containing the data to be sent\n@@ -143,13 +167,16 @@ EXPORT_SYMBOL_GPL(nct6694_read_msg);\n  *\n  * Return: Negative value on error or 0 on success.\n  */\n-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)\n+static int nct6694_usb_write_msg(struct nct6694 *nct6694,\n+\t\t\t\t const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\t void *buf)\n {\n-\tunion nct6694_usb_msg *msg = nct6694->usb_msg;\n-\tstruct usb_device *udev = nct6694->udev;\n+\tstruct nct6694_usb_data *udata = nct6694->priv;\n+\tunion nct6694_usb_msg *msg = udata->usb_msg;\n+\tstruct usb_device *udev = udata->udev;\n \tint tx_len, rx_len, ret;\n \n-\tguard(mutex)(&nct6694->access_lock);\n+\tguard(mutex)(&udata->access_lock);\n \n \tmemcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));\n \tmsg->cmd_header.hctrl = NCT6694_HCTRL_SET;\n@@ -184,9 +211,8 @@ int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *\n \t\treturn -EIO;\n \t}\n \n-\treturn nct6694_response_err_handling(nct6694, msg->response_header.sts);\n+\treturn nct6694_usb_err_handling(nct6694, msg->response_header.sts);\n }\n-EXPORT_SYMBOL_GPL(nct6694_write_msg);\n \n static void usb_int_callback(struct urb *urb)\n {\n@@ -276,6 +302,7 @@ static int nct6694_usb_probe(struct usb_interface *iface,\n \tstruct usb_endpoint_descriptor *int_endpoint;\n \tstruct usb_host_interface *interface;\n \tstruct device *dev = &iface->dev;\n+\tstruct nct6694_usb_data *udata;\n \tstruct nct6694 *nct6694;\n \tint ret;\n \n@@ -283,18 +310,28 @@ static int nct6694_usb_probe(struct usb_interface *iface,\n \tif (!nct6694)\n \t\treturn -ENOMEM;\n \n-\tnct6694->usb_msg = devm_kzalloc(dev, sizeof(union nct6694_usb_msg), GFP_KERNEL);\n-\tif (!nct6694->usb_msg)\n+\tudata = devm_kzalloc(dev, sizeof(*udata), GFP_KERNEL);\n+\tif (!udata)\n+\t\treturn -ENOMEM;\n+\n+\tudata->usb_msg = devm_kzalloc(dev, sizeof(*udata->usb_msg), GFP_KERNEL);\n+\tif (!udata->usb_msg)\n \t\treturn -ENOMEM;\n \n-\tnct6694->int_buffer = devm_kzalloc(dev, sizeof(*nct6694->int_buffer), GFP_KERNEL);\n-\tif (!nct6694->int_buffer)\n+\tudata->int_buffer = devm_kzalloc(dev, sizeof(*udata->int_buffer), GFP_KERNEL);\n+\tif (!udata->int_buffer)\n \t\treturn -ENOMEM;\n \n-\tnct6694->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);\n-\tif (!nct6694->int_in_urb)\n+\tudata->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);\n+\tif (!udata->int_in_urb)\n \t\treturn -ENOMEM;\n \n+\tudata->udev = udev;\n+\n+\tnct6694->priv = udata;\n+\tnct6694->read_msg = nct6694_usb_read_msg;\n+\tnct6694->write_msg = nct6694_usb_write_msg;\n+\n \tnct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,\n \t\t\t\t\t\t   &nct6694_irq_domain_ops,\n \t\t\t\t\t\t   nct6694);\n@@ -304,11 +341,10 @@ static int nct6694_usb_probe(struct usb_interface *iface,\n \t}\n \n \tnct6694->dev = dev;\n-\tnct6694->udev = udev;\n \n \tspin_lock_init(&nct6694->irq_lock);\n \n-\tret = devm_mutex_init(dev, &nct6694->access_lock);\n+\tret = devm_mutex_init(dev, &udata->access_lock);\n \tif (ret)\n \t\tgoto err_irq_domain;\n \n@@ -320,11 +356,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,\n \t\tgoto err_irq_domain;\n \t}\n \n-\tusb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),\n-\t\t\t nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback,\n+\tusb_fill_int_urb(udata->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),\n+\t\t\t udata->int_buffer, sizeof(*udata->int_buffer), usb_int_callback,\n \t\t\t nct6694, int_endpoint->bInterval);\n \n-\tret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);\n+\tret = usb_submit_urb(udata->int_in_urb, GFP_KERNEL);\n \tif (ret)\n \t\tgoto err_irq_domain;\n \n@@ -337,21 +373,22 @@ static int nct6694_usb_probe(struct usb_interface *iface,\n \treturn 0;\n \n err_mfd:\n-\tusb_kill_urb(nct6694->int_in_urb);\n+\tusb_kill_urb(udata->int_in_urb);\n err_irq_domain:\n \tirq_domain_remove(nct6694->domain);\n err_urb:\n-\tusb_free_urb(nct6694->int_in_urb);\n+\tusb_free_urb(udata->int_in_urb);\n \treturn ret;\n }\n \n static void nct6694_usb_disconnect(struct usb_interface *iface)\n {\n \tstruct nct6694 *nct6694 = usb_get_intfdata(iface);\n+\tstruct nct6694_usb_data *udata = nct6694->priv;\n \n-\tusb_kill_urb(nct6694->int_in_urb);\n+\tusb_kill_urb(udata->int_in_urb);\n \tirq_domain_remove(nct6694->domain);\n-\tusb_free_urb(nct6694->int_in_urb);\n+\tusb_free_urb(udata->int_in_urb);\n }\n \n static const struct usb_device_id nct6694_ids[] = {\ndiff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c\nindex 29282c56430f..05db00455f63 100644\n--- a/drivers/net/can/usb/nct6694_canfd.c\n+++ b/drivers/net/can/usb/nct6694_canfd.c\n@@ -17,12 +17,6 @@\n \n #define DEVICE_NAME \"nct6694-canfd\"\n \n-/* USB command module type for NCT6694 CANfd controller.\n- * This defines the module type used for communication with the NCT6694\n- * CANfd controller over the USB interface.\n- */\n-#define NCT6694_CANFD_MOD\t\t\t0x05\n-\n /* Command 00h - CAN Setting and Initialization */\n #define NCT6694_CANFD_SETTING\t\t\t0x00\n #define NCT6694_CANFD_SETTING_ACTIVE_CTRL1\tBIT(0)\ndiff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c\nindex 35401a0d9cf5..c06902f150c9 100644\n--- a/drivers/rtc/rtc-nct6694.c\n+++ b/drivers/rtc/rtc-nct6694.c\n@@ -14,13 +14,6 @@\n #include <linux/rtc.h>\n #include <linux/slab.h>\n \n-/*\n- * USB command module type for NCT6694 RTC controller.\n- * This defines the module type used for communication with the NCT6694\n- * RTC controller over the USB interface.\n- */\n-#define NCT6694_RTC_MOD\t\t0x08\n-\n /* Command 00h - RTC Time */\n #define NCT6694_RTC_TIME\t0x0000\n #define NCT6694_RTC_TIME_SEL\t0x00\ndiff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c\nindex 2b4b804a1739..847d8f1d1830 100644\n--- a/drivers/watchdog/nct6694_wdt.c\n+++ b/drivers/watchdog/nct6694_wdt.c\n@@ -19,13 +19,6 @@\n \n #define NCT6694_WDT_MAX_DEVS\t\t2\n \n-/*\n- * USB command module type for NCT6694 WDT controller.\n- * This defines the module type used for communication with the NCT6694\n- * WDT controller over the USB interface.\n- */\n-#define NCT6694_WDT_MOD\t\t\t0x07\n-\n /* Command 00h - WDT Setup */\n #define NCT6694_WDT_SETUP\t\t0x00\n #define NCT6694_WDT_SETUP_SEL(idx)\t(idx ? 0x01 : 0x00)\ndiff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h\nindex 496da72949d9..ff0814dc82d4 100644\n--- a/include/linux/mfd/nct6694.h\n+++ b/include/linux/mfd/nct6694.h\n@@ -2,7 +2,8 @@\n /*\n  * Copyright (C) 2025 Nuvoton Technology Corp.\n  *\n- * Nuvoton NCT6694 USB transaction and data structure.\n+ * Nuvoton NCT6694 core definitions shared by all transport drivers\n+ * and sub-device drivers.\n  */\n \n #ifndef __MFD_NCT6694_H\n@@ -12,16 +13,17 @@\n #include <linux/spinlock.h>\n #include <linux/types.h>\n \n-#define NCT6694_VENDOR_ID\t0x0416\n-#define NCT6694_PRODUCT_ID\t0x200B\n-#define NCT6694_INT_IN_EP\t0x81\n-#define NCT6694_BULK_IN_EP\t0x02\n-#define NCT6694_BULK_OUT_EP\t0x03\n-\n #define NCT6694_HCTRL_SET\t0x40\n #define NCT6694_HCTRL_GET\t0x80\n \n-#define NCT6694_URB_TIMEOUT\t1000\n+#define NCT6694_HWMON_MOD\t0x00\n+#define NCT6694_PWM_MOD\t\t0x01\n+#define NCT6694_I2C_MOD\t\t0x03\n+#define NCT6694_CANFD_MOD\t0x05\n+#define NCT6694_WDT_MOD\t\t0x07\n+#define NCT6694_RTC_MOD\t\t0x08\n+#define NCT6694_RPT_MOD\t\t0xFF\n+#define NCT6694_GPIO_MOD\tNCT6694_RPT_MOD\n \n enum nct6694_irq_id {\n \tNCT6694_IRQ_GPIO0 = 0,\n@@ -79,24 +81,33 @@ struct __packed nct6694_response_header {\n \t__le16 len;\n };\n \n-union __packed nct6694_usb_msg {\n-\tstruct nct6694_cmd_header cmd_header;\n-\tstruct nct6694_response_header response_header;\n-};\n-\n struct nct6694 {\n \tstruct device *dev;\n \tstruct irq_domain *domain;\n-\tstruct mutex access_lock;\n \tspinlock_t irq_lock;\n-\tstruct urb *int_in_urb;\n-\tstruct usb_device *udev;\n-\tunion nct6694_usb_msg *usb_msg;\n-\t__le32 *int_buffer;\n \tunsigned int irq_enable;\n+\n+\tvoid *priv;\n+\tint (*read_msg)(struct nct6694 *nct6694,\n+\t\t\tconst struct nct6694_cmd_header *cmd_hd,\n+\t\t\tvoid *buf);\n+\tint (*write_msg)(struct nct6694 *nct6694,\n+\t\t\t const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t void *buf);\n };\n \n-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);\n-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);\n+static inline int nct6694_read_msg(struct nct6694 *nct6694,\n+\t\t\t\t   const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\t   void *buf)\n+{\n+\treturn nct6694->read_msg(nct6694, cmd_hd, buf);\n+}\n+\n+static inline int nct6694_write_msg(struct nct6694 *nct6694,\n+\t\t\t\t    const struct nct6694_cmd_header *cmd_hd,\n+\t\t\t\t    void *buf)\n+{\n+\treturn nct6694->write_msg(nct6694, cmd_hd, buf);\n+}\n \n #endif\n","prefixes":["v1","2/2"]}