Re: [PATCH v1 2/2] mfd: Add Host Interface (HIF) support for Nuvoton NCT6694

From: Marc Kleine-Budde

Date: Thu Apr 02 2026 - 07:13:35 EST


On 02.04.2026 13:14:42, a0282524688@xxxxxxxxx wrote:
> From: Ming Yu <a0282524688@xxxxxxxxx>
>
> The Nuvoton NCT6694 also provides a Host Interface (HIF) via eSPI
> to the host to access its features.
>
> Sub-devices can use the common functions nct6694_read_msg() and
> nct6694_write_msg() to issue a command. They can also request
> interrupts that will be called when the HIF device triggers a
> shared memory interrupt.
>
> To support multiple transports, the driver configuration is
> updated to allow selecting between the USB and HIF interfaces.
>
> Signed-off-by: Ming Yu <a0282524688@xxxxxxxxx>
> ---
> MAINTAINERS | 1 +
> drivers/gpio/gpio-nct6694.c | 7 -
> drivers/hwmon/nct6694-hwmon.c | 21 -
> drivers/i2c/busses/i2c-nct6694.c | 7 -
> drivers/mfd/Kconfig | 47 +-
> drivers/mfd/Makefile | 3 +-
> drivers/mfd/nct6694-hif.c | 649 ++++++++++++++++++++++++++++
> drivers/mfd/nct6694.c | 97 +++--
> drivers/net/can/usb/nct6694_canfd.c | 6 -
> drivers/rtc/rtc-nct6694.c | 7 -
> drivers/watchdog/nct6694_wdt.c | 7 -
> include/linux/mfd/nct6694.h | 51 ++-
> 12 files changed, 787 insertions(+), 116 deletions(-)
> create mode 100644 drivers/mfd/nct6694-hif.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c3fe46d7c4bc..7b6241faa6df 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -18899,6 +18899,7 @@ S: Supported
> F: drivers/gpio/gpio-nct6694.c
> F: drivers/hwmon/nct6694-hwmon.c
> F: drivers/i2c/busses/i2c-nct6694.c
> +F: drivers/mfd/nct6694-hif.c
> F: drivers/mfd/nct6694.c
> F: drivers/net/can/usb/nct6694_canfd.c
> F: drivers/rtc/rtc-nct6694.c
> diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c
> index 3703a61209e6..a279510ece89 100644
> --- a/drivers/gpio/gpio-nct6694.c
> +++ b/drivers/gpio/gpio-nct6694.c
> @@ -12,13 +12,6 @@
> #include <linux/module.h>
> #include <linux/platform_device.h>
>
> -/*
> - * USB command module type for NCT6694 GPIO controller.
> - * This defines the module type used for communication with the NCT6694
> - * GPIO controller over the USB interface.
> - */
> -#define NCT6694_GPIO_MOD 0xFF
> -
> #define NCT6694_GPIO_VER 0x90
> #define NCT6694_GPIO_VALID 0x110
> #define NCT6694_GPI_DATA 0x120
> diff --git a/drivers/hwmon/nct6694-hwmon.c b/drivers/hwmon/nct6694-hwmon.c
> index 6dcf22ca5018..581451875f2c 100644
> --- a/drivers/hwmon/nct6694-hwmon.c
> +++ b/drivers/hwmon/nct6694-hwmon.c
> @@ -15,13 +15,6 @@
> #include <linux/platform_device.h>
> #include <linux/slab.h>
>
> -/*
> - * USB command module type for NCT6694 report channel
> - * This defines the module type used for communication with the NCT6694
> - * report channel over the USB interface.
> - */
> -#define NCT6694_RPT_MOD 0xFF
> -
> /* Report channel */
> /*
> * The report channel is used to report the status of the hardware monitor
> @@ -38,13 +31,6 @@
> #define NCT6694_TIN_STS(x) (0x6A + (x))
> #define NCT6694_FIN_STS(x) (0x6E + (x))
>
> -/*
> - * USB command module type for NCT6694 HWMON controller.
> - * This defines the module type used for communication with the NCT6694
> - * HWMON controller over the USB interface.
> - */
> -#define NCT6694_HWMON_MOD 0x00
> -
> /* Command 00h - Hardware Monitor Control */
> #define NCT6694_HWMON_CONTROL 0x00
> #define NCT6694_HWMON_CONTROL_SEL 0x00
> @@ -53,13 +39,6 @@
> #define NCT6694_HWMON_ALARM 0x02
> #define NCT6694_HWMON_ALARM_SEL 0x00
>
> -/*
> - * USB command module type for NCT6694 PWM controller.
> - * This defines the module type used for communication with the NCT6694
> - * PWM controller over the USB interface.
> - */
> -#define NCT6694_PWM_MOD 0x01
> -
> /* PWM Command - Manual Control */
> #define NCT6694_PWM_CONTROL 0x01
> #define NCT6694_PWM_CONTROL_SEL 0x00
> diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
> index 7d8ad997f6d2..7ee209a04d16 100644
> --- a/drivers/i2c/busses/i2c-nct6694.c
> +++ b/drivers/i2c/busses/i2c-nct6694.c
> @@ -11,13 +11,6 @@
> #include <linux/module.h>
> #include <linux/platform_device.h>
>
> -/*
> - * USB command module type for NCT6694 I2C controller.
> - * This defines the module type used for communication with the NCT6694
> - * I2C controller over the USB interface.
> - */
> -#define NCT6694_I2C_MOD 0x03
> -
> /* Command 00h - I2C Deliver */
> #define NCT6694_I2C_DELIVER 0x00
> #define NCT6694_I2C_DELIVER_SEL 0x00
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 7192c9d1d268..8a715ec2f79f 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1164,19 +1164,46 @@ config MFD_MENF21BMC
> will be called menf21bmc.
>
> config MFD_NCT6694
> - tristate "Nuvoton NCT6694 support"
> + tristate
> select MFD_CORE
> + help
> + Core MFD support for the Nuvoton NCT6694 peripheral expander.
> + This provides the common APIs and shared structures used by all
> + interfaces (USB, HIF) to access the NCT6694 hardware features
> + such as GPIO, I2C, CAN-FD, Watchdog, ADC, PWM, and RTC.
> +
> + It is selected automatically by the transport interface drivers.
> +
> +config MFD_NCT6694_HIF
> + tristate "Nuvoton NCT6694 HIF (eSPI) interface support"
> + depends on HAS_IOPORT && ACPI
> + select MFD_NCT6694
> + select REGMAP_MMIO
> + help
> + This enables support for the Nuvoton NCT6694 peripheral expander
> + connected via the Host Interface (HIF) using eSPI transport.
> +
> + The transport driver uses Super-I/O mapping and shared memory to
> + communicate with the NCT6694 firmware. Enable this option if you
> + are using the NCT6694 over an eSPI interface on an ACPI platform.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called nct6694-hif.
> +
> +config MFD_NCT6694_USB
> + tristate "Nuvoton NCT6694 USB interface support"
> + select MFD_NCT6694
> depends on USB
> help
> - This enables support for the Nuvoton USB device NCT6694, which shares
> - peripherals.
> - The Nuvoton NCT6694 is a peripheral expander with 16 GPIO chips,
> - 6 I2C controllers, 2 CANfd controllers, 2 Watchdog timers, ADC,
> - PWM, and RTC.
> - This driver provides core APIs to access the NCT6694 hardware
> - monitoring and control features.
> - Additional drivers must be enabled to utilize the specific
> - functionalities of the device.
> + This enables support for the Nuvoton NCT6694 peripheral expander
> + connected via the USB interface.
> +
> + The transport driver uses USB bulk and interrupt transfers to
> + communicate with the NCT6694 firmware. Enable this option if you
> + are using the NCT6694 via a USB connection.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called nct6694.
>
> config MFD_OCELOT
> tristate "Microsemi Ocelot External Control Support"
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index e75e8045c28a..4cee9b74978c 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -124,7 +124,8 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
>
> obj-$(CONFIG_MFD_PF1550) += pf1550.o
>
> -obj-$(CONFIG_MFD_NCT6694) += nct6694.o
> +obj-$(CONFIG_MFD_NCT6694_HIF) += nct6694-hif.o
> +obj-$(CONFIG_MFD_NCT6694_USB) += nct6694.o
>
> obj-$(CONFIG_MFD_CORE) += mfd-core.o
>
> diff --git a/drivers/mfd/nct6694-hif.c b/drivers/mfd/nct6694-hif.c
> new file mode 100644
> index 000000000000..a5953c951eb5
> --- /dev/null
> +++ b/drivers/mfd/nct6694-hif.c
> @@ -0,0 +1,649 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 Nuvoton Technology Corp.
> + *
> + * Nuvoton NCT6694 host-interface (eSPI) transport driver.
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/nct6694.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/unaligned.h>
> +
> +#define DRVNAME "nct6694-hif"
> +
> +#define NCT6694_POLL_INTERVAL_US 10
> +#define NCT6694_POLL_TIMEOUT_US 10000
> +
> +/*
> + * Super-I/O registers
> + */
> +#define SIO_REG_LDSEL 0x07 /* Logical device select */
> +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
> +#define SIO_REG_LD_SHM 0x0F /* Logical device shared memory control */
> +
> +#define SIO_REG_SHM_ENABLE 0x30 /* Enable shared memory */
> +#define SIO_REG_SHM_BASE_ADDR 0x60 /* Shared memory base address (2 bytes) */
> +#define SIO_REG_SHM_IRQ_NR 0x70 /* Shared memory interrupt number */
> +
> +#define SIO_REG_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
> +#define SIO_REG_LOCK_KEY 0xAA /* Key to disable Super-I/O */
> +
> +#define SIO_NCT6694B_ID 0xD029
> +#define SIO_NCT6694D_ID 0x5832
> +
> +/*
> + * Super-I/O Shared Memory Logical Device registers
> + */
> +#define NCT6694_SHM_COFS_STS 0x2E
> +#define NCT6694_SHM_COFS_STS_COFS4W BIT(7)
> +
> +#define NCT6694_SHM_COFS_CTL2 0x3B
> +#define NCT6694_SHM_COFS_CTL2_COFS4W_IE BIT(3)
> +
> +#define NCT6694_SHM_INTR_STATUS 0x9C /* Interrupt status register (4 bytes) */
> +
> +enum nct6694_chips {
> + NCT6694B = 0,
> + NCT6694D,
> +};
> +
> +enum nct6694_module_id {
> + NCT6694_GPIO0 = 0,
> + NCT6694_GPIO1,
> + NCT6694_GPIO2,
> + NCT6694_GPIO3,
> + NCT6694_GPIO4,
> + NCT6694_GPIO5,
> + NCT6694_GPIO6,
> + NCT6694_GPIO7,
> + NCT6694_GPIO8,
> + NCT6694_GPIO9,
> + NCT6694_GPIOA,
> + NCT6694_GPIOB,
> + NCT6694_GPIOC,
> + NCT6694_GPIOD,
> + NCT6694_GPIOE,
> + NCT6694_GPIOF,
> + NCT6694_I2C0,
> + NCT6694_I2C1,
> + NCT6694_I2C2,
> + NCT6694_I2C3,
> + NCT6694_I2C4,
> + NCT6694_I2C5,
> + NCT6694_CAN0,
> + NCT6694_CAN1,
> +};
> +
> +struct __packed nct6694_msg {
> + struct nct6694_cmd_header cmd_header;
> + struct nct6694_response_header response_header;
> + unsigned char *data;
> +};
> +
> +struct nct6694_sio_data {
> + enum nct6694_chips chip;
> + int sioreg; /* Super-I/O index port */
> +
> + /* Super-I/O access functions */
> + int (*sio_enter)(struct nct6694_sio_data *sio_data);
> + void (*sio_exit)(struct nct6694_sio_data *sio_data);
> + void (*sio_select)(struct nct6694_sio_data *sio_data, int ld);
> + int (*sio_inb)(struct nct6694_sio_data *sio_data, int reg);
> + int (*sio_inw)(struct nct6694_sio_data *sio_data, int reg);
> + void (*sio_outb)(struct nct6694_sio_data *sio_data, int reg, int val);

The signatures of the function look a bit strange. I expect functions
reading/writing bytes use u8 not int, register offsets should probably
be an unsigned int.

Why do you have pointers to the access functions? Why not use them
directly?

Marc

--
Pengutronix e.K. | Marc Kleine-Budde |
Embedded Linux | https://www.pengutronix.de |
Vertretung Nürnberg | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |

Attachment: signature.asc
Description: PGP signature