From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f42.google.com (mail-pj1-f42.google.com [209.85.216.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A2653DB994 for ; Mon, 25 May 2026 08:18:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.42 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779697095; cv=none; b=JveRzLDfroC2TYmeX/ymr1ao5orI0tlpn50/lmm2pRpBsmPwKMYpHD7w+kYzofUpCoLdZWrhOZSw78USh7XVSkhhN4y2Ct4gXoNiyzZfcV7QLz3R2izKcr1M+NstSsPP6OitpWOH/ao4pStBijJ9qbp2WjWAs/ZIqqCWk2uFUkQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779697095; c=relaxed/simple; bh=iA60ux1zt5VejibfaMVf6J7kYiY0yU72fN91MlnpVNk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oKGHvGQL0JHj82preZUaMEIGdn6HLH/QIYfHcyzZOBFwy3sHo01BRcy5YoA9v1woCMf2o80t2MD/gOTyZkEgFCqCmUNZGYQ20jmWW00TLjYJUdUg4nc2ChNCbIq+lTtZPHvM0w5Gb3QOaGir5GjMo45iNTQoXHBcw6jFIjmA4as= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Nqz9YQ0D; arc=none smtp.client-ip=209.85.216.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Nqz9YQ0D" Received: by mail-pj1-f42.google.com with SMTP id 98e67ed59e1d1-369002b26f4so5294341a91.3 for ; Mon, 25 May 2026 01:18:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779697093; x=1780301893; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1kXH8Acry7UZKwgRWwzIFUJKLHh+793WN2Q23uS6M4I=; b=Nqz9YQ0Ds3zgeUikCq7rViI3n2pNjqH29J8mpiRBHgAnveYO37GaCmzinkAwwojAIE rh8PQgUOgb4dAZeu3PPt68qaHvU9ysNzpDbb3hQxxdQI1lCpnlt0nILiAkuHD9sJJCle Fi6IvcTKXF2jmjdkqvmGD5+b3Hqvty6mFYzpzZhKzF0x+ZF/QklB5twejEcyxe0tLQyI jBHeWlBSF4ZrDqvFaLWc88H2j8twUSZ63onFQIItAr3Tqn05FEtS1DPhjHKJU7GF0pTJ eXbZ3n3CEsYDleulEIabOZiUkpWu12O3onqAe7BuCPy3sB3Z5E/wfiRp1Tv20J28QHKE rCfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779697093; x=1780301893; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=1kXH8Acry7UZKwgRWwzIFUJKLHh+793WN2Q23uS6M4I=; b=irX7sIQX8pgF4ftozqqjJ/5Ym0GOH2Pn8zDinvoNezaq1fPAORFlsLn3BsemMUvibb 4bjfpe62M+t6/x/Htp0L0hS5Y4N46VfL8iBH39/cpKpyj9JTYd24LeKyIPjhCE5FDqsv rHp9ycGvPZteVJkhovKGoeij60U98PDDl/aYNZTXaN1OsrSoEtLK+c9wm5eZqdU/HqJp gK6n6gr26iLw1Jw2pGQEVAUaLfbdGgQ8adOBUJvpvkZzusml0xShFh7tqj+zoHOo2phR 4KxxFE59pf6yGRVMpnVW7G9lR3J74lFE7zzmjmhVg1aPCtTJNoHQ/4B+ybGTvSl/nf+E IXyw== X-Forwarded-Encrypted: i=1; AFNElJ+B9/ZXCvoKEGIhvceV2jQILw1XX3N5X6k6VrI2C7fWVMa5727M0UR/ng0uOVHvndGSylcqXgy66NvJNfc=@vger.kernel.org X-Gm-Message-State: AOJu0YwTJoRig1lyz+JykenaBtSZ9746x98efHs/Gb6FMp9qVlJcO+lD eRe7RywXKeBVIsm4mVVIsVnLBYZ9QdGpND3JTzkGz+76hRl3Mvz/Osij X-Gm-Gg: Acq92OHSEpV1GNJltB98fAy3Gu9rYhlR4PrgERUBmoLQ+pIdUrpi4BFO/IRBEl2UH/t Ou2l38HQAj9JsW0o8MLhLI7fYyFV57/+ejRUTE5xDKbUaoPnRyzuZGgNeSzc/QDWIK7BiU+sQxO EiUNjPrR2qUHHsQoGrKeIUUfS+DdfbAFBtNOMtB6Mvgm9vDt+w+W0AvcsZcVDMvzvoYGnrbFFeS IWicCFbQ3Ta3OPDn0htQaFz+dhr2ldMOLEKEIeQG1K7NQZMaOZFtNIxLKv4AEF9mR1QC0JqYowI 4pQYbnWIMw1QDjSMi6aw9OE9uEWBpixcw/WgHvHNyabKwDRd0EBplTOpRhwX2dO7tCuOswAbzxH 3RzqcTs5FapNovMvRPUAE5oQegdw9rN3xLeQ/ynMhTFJYeu3/IlVFrr+atw0JrvoHRyIs1iq8qN aSJoQDV/vDXTiUYC+uTzr4JTZxnqq3LunItzDcY8ZKiHqOAdcLLCdT4ucWqHYWUtABlA== X-Received: by 2002:a17:90b:3bcc:b0:367:e244:4c40 with SMTP id 98e67ed59e1d1-36a67893102mr12730617a91.26.1779697092600; Mon, 25 May 2026 01:18:12 -0700 (PDT) Received: from hcdev-d520mt2.. (60-250-196-139.hinet-ip.hinet.net. [60.250.196.139]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-36a721c7cf9sm8964102a91.10.2026.05.25.01.18.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 25 May 2026 01:18:12 -0700 (PDT) From: a0282524688@gmail.com To: Lee Jones , Ming Yu Cc: Ming Yu , linux-kernel@vger.kernel.org Subject: [PATCH v5 6/7] mfd: nct6694: Extract core device management into a separate module Date: Mon, 25 May 2026 16:17:35 +0800 Message-Id: <20260525081736.2904310-7-a0282524688@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260525081736.2904310-1-a0282524688@gmail.com> References: <20260525081736.2904310-1-a0282524688@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Ming Yu 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 --- 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 | 95 +++---------------------- include/linux/mfd/nct6694.h | 9 ++- 5 files changed, 155 insertions(+), 88 deletions(-) create mode 100644 drivers/mfd/nct6694-core.c diff --git a/MAINTAINERS b/MAINTAINERS index d52a3028e7c0..53a81f8afc37 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19098,7 +19098,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 361c5360e656..668a69dc66a7 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..a2afd5f33ea5 --- /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 (USB, HIF). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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, +}; + +/** + * nct6694_core_probe() - Register IRQ domain, IDAs, and MFD sub-devices + * @dev: parent device (USB interface or platform device) + * @nct6694: initialized nct6694 structure with transport callbacks 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, + * nct6694->read_msg, and nct6694->write_msg before calling this. + * + * Return: 0 on success or negative errno on failure. + */ +int nct6694_core_probe(struct device *dev, struct nct6694 *nct6694, + 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; + 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) +{ + 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 "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/nct6694-usb.c b/drivers/mfd/nct6694-usb.c index 289580bbc472..666ad1c442b8 100644 --- a/drivers/mfd/nct6694-usb.c +++ b/drivers/mfd/nct6694-usb.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include @@ -19,7 +18,6 @@ #include #include #include -#include #include #define NCT6694_VENDOR_ID 0x0416 @@ -43,7 +41,7 @@ struct nct6694_usb_data { __le32 *int_buffer; }; -static const struct mfd_cell nct6694_devs[] = { +static const struct mfd_cell nct6694_usb_devs[] = { MFD_CELL_NAME("nct6694-gpio"), MFD_CELL_NAME("nct6694-gpio"), MFD_CELL_NAME("nct6694-gpio"), @@ -244,57 +242,9 @@ static void 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) { @@ -328,37 +278,21 @@ static int nct6694_usb_probe(struct usb_interface *iface, udata->udev = udev; + nct6694->dev = dev; nct6694->priv = udata; nct6694->read_msg = nct6694_usb_read_msg; nct6694->write_msg = nct6694_usb_write_msg; - 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); - 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_devs, ARRAY_SIZE(nct6694_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); } @@ -419,6 +342,6 @@ static struct usb_driver nct6694_usb_driver = { }; module_usb_driver(nct6694_usb_driver); -MODULE_DESCRIPTION("Nuvoton NCT6694 core driver"); +MODULE_DESCRIPTION("Nuvoton NCT6694 USB transport driver"); MODULE_AUTHOR("Ming Yu "); MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h index 3079c74110aa..a150c7d6ceba 100644 --- a/include/linux/mfd/nct6694.h +++ b/include/linux/mfd/nct6694.h @@ -10,10 +10,13 @@ #define __MFD_NCT6694_H #include -#include #include #include +struct device; +struct irq_domain; +struct mfd_cell; + #define NCT6694_HWMON_MOD 0x00 #define NCT6694_PWM_MOD 0x01 #define NCT6694_I2C_MOD 0x03 @@ -115,4 +118,8 @@ static inline int nct6694_write_msg(struct nct6694 *nct6694, return nct6694->write_msg(nct6694, cmd_hd, buf); } +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); + #endif -- 2.34.1