From: Lee Jones <lee@kernel.org>
To: a0282524688@gmail.com
Cc: Ming Yu <tmyu0@nuvoton.com>,
linux-kernel@vger.kernel.org, mfd@lists.linux.dev
Subject: Re: [PATCH v7 05/10] mfd: nct6694: Extract core device management into a separate module
Date: Thu, 3 Sep 2026 11:42:53 +0100 [thread overview]
Message-ID: <20260903104253.GM2133376@google.com> (raw)
In-Reply-To: <20260821033505.4017901-6-a0282524688@gmail.com>
On Fri, 21 Aug 2026, a0282524688@gmail.com wrote:
> From: Ming Yu <a0282524688@gmail.com>
>
> Extract the transport-agnostic core logic, including IRQ domain setup,
> IDA initialization, and MFD sub-device registration, from the USB driver
> into a new nct6694-core.c module.
>
> The core routines are exported as nct6694_core_probe() and
> nct6694_core_remove() to be consumed by the transport drivers. The USB
> driver is updated to pass its specific MFD cells to the core probe
> routine.
>
> This completes the transport abstraction, ensuring that the shared
> device management logic is cleanly separated from the underlying I/O
> implementation, and is fully ready for new transport backends
> (e.g., HIF).
>
> Signed-off-by: Ming Yu <a0282524688@gmail.com>
> ---
> Changes in v7:
>
> Changes in v6:
> - Reordered to sit before the transport-abstraction patch; no functional
> change.
>
> Changes in v5:
> - Split from the monolithic v4 patch to follow the single logical change
> principle.
>
> MAINTAINERS | 2 +-
> drivers/mfd/Makefile | 1 +
> drivers/mfd/nct6694-core.c | 136 ++++++++++++++++++++++++++++++++++++
> drivers/mfd/nct6694-usb.c | 91 ++----------------------
> include/linux/mfd/nct6694.h | 9 ++-
> 5 files changed, 153 insertions(+), 86 deletions(-)
> create mode 100644 drivers/mfd/nct6694-core.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 89d7339f3613..f1894e88ba62 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19356,7 +19356,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-usb.c
> +F: drivers/mfd/nct6694-*.c
> F: drivers/net/can/usb/nct6694_canfd.c
> F: drivers/rtc/rtc-nct6694.c
> F: drivers/watchdog/nct6694_wdt.c
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 48caac64f3d8..10c19a19541e 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -124,6 +124,7 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
>
> obj-$(CONFIG_MFD_PF1550) += pf1550.o
>
> +obj-$(CONFIG_MFD_NCT6694) += nct6694-core.o
> obj-$(CONFIG_MFD_NCT6694_USB) += nct6694-usb.o
>
> obj-$(CONFIG_MFD_CORE) += mfd-core.o
> diff --git a/drivers/mfd/nct6694-core.c b/drivers/mfd/nct6694-core.c
> new file mode 100644
> index 000000000000..36dfaa2e327f
> --- /dev/null
> +++ b/drivers/mfd/nct6694-core.c
> @@ -0,0 +1,136 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2026 Nuvoton Technology Corp.
> + *
> + * Nuvoton NCT6694 MFD core driver.
> + *
> + * This provides common registration for IRQ domain, IDA pools,
> + * and MFD sub-devices shared by all transport drivers.
> + */
> +
> +#include <linux/idr.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/spinlock.h>
> +
> +static void nct6694_irq_enable(struct irq_data *data)
> +{
> + struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
> + irq_hw_number_t hwirq = irqd_to_hwirq(data);
> +
> + guard(spinlock_irqsave)(&nct6694->irq_lock);
> +
> + nct6694->irq_enable |= BIT(hwirq);
> +}
> +
> +static void nct6694_irq_disable(struct irq_data *data)
> +{
> + struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
> +
> + guard(spinlock_irqsave)(&nct6694->irq_lock);
> +
> + nct6694->irq_enable &= ~BIT(hwirq);
> +}
> +
> +static const struct irq_chip nct6694_irq_chip = {
> + .name = "nct6694-irq",
> + .flags = IRQCHIP_SKIP_SET_WAKE,
> + .irq_enable = nct6694_irq_enable,
> + .irq_disable = nct6694_irq_disable,
> +};
> +
> +static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq,
> + irq_hw_number_t hw)
> +{
> + struct nct6694 *nct6694 = d->host_data;
> +
> + irq_set_chip_data(irq, nct6694);
> + irq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq);
> +
> + return 0;
> +}
> +
> +static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
> +{
> + irq_set_chip_and_handler(irq, NULL, NULL);
> + irq_set_chip_data(irq, NULL);
> +}
> +
> +static const struct irq_domain_ops nct6694_irq_domain_ops = {
> + .map = nct6694_irq_domain_map,
> + .unmap = nct6694_irq_domain_unmap,
> +};
> +
> +/**
> + * nct6694_core_probe() - Register IRQ domain, IDAs, and MFD sub-devices
> + * @dev: parent device (USB interface or platform device)
> + * @nct6694: initialized nct6694 structure with its transport regmap set
> + *
> + * This function completes the common probe steps shared by all transport
> + * drivers: IRQ domain creation, IDA initialization, and MFD cell registration.
> + *
> + * The caller must have already set nct6694->dev, nct6694->priv, and
> + * nct6694->regmap before calling this.
> + *
> + * Return: 0 on success or negative errno on failure.
> + */
> +int nct6694_core_probe(struct device *dev, struct nct6694 *nct6694,
You can put nct6694 into the device's private struct attribute which
means that you no longer have to pass it around.
I'm not particularly keen on passing mfd_cells around. Why not call
mfd_add_*() from the transport's probe?
> + const struct mfd_cell *cells, int n_cells)
> +{
> + int ret;
> +
> + spin_lock_init(&nct6694->irq_lock);
> +
> + ida_init(&nct6694->gpio_ida);
> + ida_init(&nct6694->i2c_ida);
> + ida_init(&nct6694->canfd_ida);
> + ida_init(&nct6694->wdt_ida);
> +
> + nct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
> + &nct6694_irq_domain_ops,
> + nct6694);
> + if (!nct6694->domain) {
> + ret = -ENODEV;
Should we return '-ENOMEM' here instead of '-ENODEV', as this represents
a resource allocation failure?
> + goto err_ida;
> + }
> +
> + ret = mfd_add_hotplug_devices(dev, cells, n_cells);
> + if (ret)
> + goto err_domain;
> +
> + return 0;
> +
> +err_domain:
> + irq_domain_remove(nct6694->domain);
> +err_ida:
> + ida_destroy(&nct6694->wdt_ida);
> + ida_destroy(&nct6694->canfd_ida);
> + ida_destroy(&nct6694->i2c_ida);
> + ida_destroy(&nct6694->gpio_ida);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(nct6694_core_probe);
> +
> +/**
> + * nct6694_core_remove() - Unregister MFD sub-devices and free core resources
> + * @nct6694: nct6694 structure previously passed to nct6694_core_probe()
> + */
> +void nct6694_core_remove(struct nct6694 *nct6694)
Should we also rename 'nct6694' to 'ddata' here?
> +{
> + mfd_remove_devices(nct6694->dev);
> + irq_domain_remove(nct6694->domain);
> + ida_destroy(&nct6694->wdt_ida);
> + ida_destroy(&nct6694->canfd_ida);
> + ida_destroy(&nct6694->i2c_ida);
> + ida_destroy(&nct6694->gpio_ida);
> +}
> +EXPORT_SYMBOL_GPL(nct6694_core_remove);
> +
> +MODULE_DESCRIPTION("Nuvoton NCT6694 MFD core driver");
> +MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/mfd/nct6694-usb.c b/drivers/mfd/nct6694-usb.c
> index 7c6b986db7f7..2289ebfde7fa 100644
> --- a/drivers/mfd/nct6694-usb.c
> +++ b/drivers/mfd/nct6694-usb.c
> @@ -10,7 +10,6 @@
> */
>
> #include <linux/bits.h>
> -#include <linux/idr.h>
> #include <linux/interrupt.h>
> #include <linux/irq.h>
> #include <linux/irqdomain.h>
> @@ -19,7 +18,6 @@
> #include <linux/mfd/nct6694.h>
> #include <linux/module.h>
> #include <linux/slab.h>
> -#include <linux/spinlock.h>
> #include <linux/usb.h>
>
> #define NCT6694_VENDOR_ID 0x0416
> @@ -246,57 +244,9 @@ static void nct6694_usb_int_callback(struct urb *urb)
> resubmit:
> ret = usb_submit_urb(urb, GFP_ATOMIC);
> if (ret)
> - dev_warn(nct6694->dev, "Failed to resubmit urb, status %pe", ERR_PTR(ret));
> + dev_warn(nct6694->dev, "Failed to resubmit urb, status %pe", ERR_PTR(ret));
> }
>
> -static void nct6694_irq_enable(struct irq_data *data)
> -{
> - struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
> - irq_hw_number_t hwirq = irqd_to_hwirq(data);
> -
> - guard(spinlock_irqsave)(&nct6694->irq_lock);
> -
> - nct6694->irq_enable |= BIT(hwirq);
> -}
> -
> -static void nct6694_irq_disable(struct irq_data *data)
> -{
> - struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
> - irq_hw_number_t hwirq = irqd_to_hwirq(data);
> -
> - guard(spinlock_irqsave)(&nct6694->irq_lock);
> -
> - nct6694->irq_enable &= ~BIT(hwirq);
> -}
> -
> -static const struct irq_chip nct6694_irq_chip = {
> - .name = "nct6694-irq",
> - .flags = IRQCHIP_SKIP_SET_WAKE,
> - .irq_enable = nct6694_irq_enable,
> - .irq_disable = nct6694_irq_disable,
> -};
> -
> -static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
> -{
> - struct nct6694 *nct6694 = d->host_data;
> -
> - irq_set_chip_data(irq, nct6694);
> - irq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq);
> -
> - return 0;
> -}
> -
> -static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
> -{
> - irq_set_chip_and_handler(irq, NULL, NULL);
> - irq_set_chip_data(irq, NULL);
> -}
> -
> -static const struct irq_domain_ops nct6694_irq_domain_ops = {
> - .map = nct6694_irq_domain_map,
> - .unmap = nct6694_irq_domain_unmap,
> -};
> -
> static int nct6694_usb_probe(struct usb_interface *iface,
> const struct usb_device_id *id)
> {
> @@ -330,35 +280,19 @@ static int nct6694_usb_probe(struct usb_interface *iface,
>
> udata->udev = udev;
>
> - nct6694->priv = udata;
> -
> - nct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
> - &nct6694_irq_domain_ops,
> - nct6694);
> - if (!nct6694->domain) {
> - ret = -ENODEV;
> - goto err_urb;
> - }
> -
> nct6694->dev = dev;
> -
> - ida_init(&nct6694->gpio_ida);
> - ida_init(&nct6694->i2c_ida);
> - ida_init(&nct6694->canfd_ida);
> - ida_init(&nct6694->wdt_ida);
> -
> - spin_lock_init(&nct6694->irq_lock);
> + nct6694->priv = udata;
>
> ret = devm_mutex_init(dev, &udata->access_lock);
> if (ret)
> - goto err_ida;
> + goto err_urb;
>
> interface = iface->cur_altsetting;
>
> int_endpoint = &interface->endpoint[0].desc;
> if (!usb_endpoint_is_int_in(int_endpoint)) {
> ret = -ENODEV;
> - goto err_ida;
> + goto err_urb;
> }
>
> usb_fill_int_urb(udata->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
> @@ -367,11 +301,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,
>
> ret = usb_submit_urb(udata->int_in_urb, GFP_KERNEL);
> if (ret)
> - goto err_ida;
> + goto err_urb;
>
> usb_set_intfdata(iface, nct6694);
>
> - ret = mfd_add_hotplug_devices(dev, nct6694_usb_devs, ARRAY_SIZE(nct6694_usb_devs));
> + ret = nct6694_core_probe(dev, nct6694, nct6694_usb_devs, ARRAY_SIZE(nct6694_usb_devs));
> if (ret)
> goto err_mfd;
>
> @@ -379,12 +313,6 @@ static int nct6694_usb_probe(struct usb_interface *iface,
>
> err_mfd:
> usb_kill_urb(udata->int_in_urb);
> -err_ida:
> - ida_destroy(&nct6694->wdt_ida);
> - ida_destroy(&nct6694->canfd_ida);
> - ida_destroy(&nct6694->i2c_ida);
> - ida_destroy(&nct6694->gpio_ida);
> - irq_domain_remove(nct6694->domain);
> err_urb:
> usb_free_urb(udata->int_in_urb);
> return ret;
> @@ -395,13 +323,8 @@ static void nct6694_usb_disconnect(struct usb_interface *iface)
> struct nct6694 *nct6694 = usb_get_intfdata(iface);
> struct nct6694_usb_data *udata = nct6694->priv;
>
> - mfd_remove_devices(nct6694->dev);
> + nct6694_core_remove(nct6694);
> usb_kill_urb(udata->int_in_urb);
> - ida_destroy(&nct6694->wdt_ida);
> - ida_destroy(&nct6694->canfd_ida);
> - ida_destroy(&nct6694->i2c_ida);
> - ida_destroy(&nct6694->gpio_ida);
> - irq_domain_remove(nct6694->domain);
> usb_free_urb(udata->int_in_urb);
> }
>
> diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
> index 43b51f243e8e..853b1530755d 100644
> --- a/include/linux/mfd/nct6694.h
> +++ b/include/linux/mfd/nct6694.h
> @@ -10,10 +10,13 @@
> #define __MFD_NCT6694_H
>
> #include <linux/idr.h>
> -#include <linux/mutex.h>
> #include <linux/spinlock.h>
> #include <linux/types.h>
>
> +struct device;
> +struct irq_domain;
> +struct mfd_cell;
> +
> #define NCT6694_HWMON_MOD 0x00
> #define NCT6694_PWM_MOD 0x01
> #define NCT6694_I2C_MOD 0x03
> @@ -94,6 +97,10 @@ struct nct6694 {
> void *priv;
> };
>
> +int nct6694_core_probe(struct device *dev, struct nct6694 *nct6694,
> + const struct mfd_cell *cells, int n_cells);
> +void nct6694_core_remove(struct nct6694 *nct6694);
> +
> int nct6694_usb_read_msg(struct nct6694 *nct6694,
> const struct nct6694_cmd_header *cmd_hd,
> void *buf);
> --
> 2.34.1
>
--
Lee Jones
next prev parent reply other threads:[~2026-09-03 10:42 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 3:34 [PATCH v7 00/10] mfd: nct6694: Refactor transport layer and add HIF (eSPI) support a0282524688
2026-08-21 3:34 ` [PATCH v7 01/10] mfd: nct6694: Move module type macros to shared header a0282524688
2026-08-21 3:34 ` [PATCH v7 02/10] mfd: nct6694: Refactor USB-specific data into nct6694_usb_data a0282524688
2026-09-03 9:53 ` Lee Jones
2026-08-21 3:34 ` [PATCH v7 03/10] mfd: nct6694: Rename USB transport functions with _usb_ prefix a0282524688
2026-08-21 3:34 ` [PATCH v7 04/10] mfd: nct6694: Rename driver to nct6694-usb and update Kconfig a0282524688
2026-09-03 10:24 ` Lee Jones
2026-08-21 3:35 ` [PATCH v7 05/10] mfd: nct6694: Extract core device management into a separate module a0282524688
2026-09-03 10:42 ` Lee Jones [this message]
2026-08-21 3:35 ` [PATCH v7 06/10] mfd: nct6694: Transfer command payloads via a dedicated DMA buffer a0282524688
2026-09-03 11:09 ` Lee Jones
2026-09-03 11:12 ` Lee Jones
2026-08-21 3:35 ` [PATCH v7 07/10] mfd: nct6694: Validate the interrupt IN endpoint a0282524688
2026-08-21 3:35 ` [PATCH v7 08/10] mfd: nct6694: Submit the interrupt URB after the core is registered a0282524688
2026-08-21 3:35 ` [PATCH v7 09/10] mfd: nct6694: Introduce regmap-based transport abstraction a0282524688
2026-08-21 3:35 ` [PATCH v7 10/10] mfd: nct6694: Add Host Interface (HIF) eSPI transport driver a0282524688
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260903104253.GM2133376@google.com \
--to=lee@kernel.org \
--cc=a0282524688@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mfd@lists.linux.dev \
--cc=tmyu0@nuvoton.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®