From nobody Sun Jun 14 09:56:23 2026 Received: from mail-pj1-f43.google.com (mail-pj1-f43.google.com [209.85.216.43]) (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 AA49E373BEB for ; Thu, 2 Apr 2026 05:15:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775106940; cv=none; b=cV7xXhWcipRJxynDqJ7EBUSNsSQpCKTynCM1JxCF8IBSU7WOxZNk+959YaM2YB8fBXej8iQY9Vu7RZ62OU1mRy8//8yU9YkhtWNmRaep2exxu2+zbcC+lkPvdQAs2ExFYvq1JpPDkOOBTsCVc9CEQZPsg8/W7fLmfxIDIfrTCpE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775106940; c=relaxed/simple; bh=lbgRgN14X3CUpEJv6dKvS7/nLgyBUL/xeX7e54cB3vs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=t+UZZavSPb1InRo4j32tU8sewXAsqvWCNImg7bxpfO2Lftkqzw8Q3VfHc4kybbDsW97UdBbL0vuaFrqbeIubxu4P3G+fomi2U/PtxxCSKg1NwfOX6M8yULrp6pvLFz21s3koK2we9vDFVAFMiH9KLubvbTGRAlMxb0j2aSdO1hU= 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=RssiDcyI; arc=none smtp.client-ip=209.85.216.43 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="RssiDcyI" Received: by mail-pj1-f43.google.com with SMTP id 98e67ed59e1d1-358ed696623so177824a91.0 for ; Wed, 01 Apr 2026 22:15:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775106938; x=1775711738; 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=urUQup7dc3mN1NcxY7RoIdIVM9FIVTCa2CM6teh2xWs=; b=RssiDcyIYDWi/EneUGyN80gJd3yyFN0jCmqyYG87SpoPwC8ezAgO0E7bon0Ejb6rqt vIhkND3rYbz8svVlnQYKWp50zY9lBem574aG8fVwIuLItnkEGA4N20OUxUwq/1NovDAz ZfljM+6tbx19w9rO2mLh2xT/O4KppOyXdhnFscVu8WzLYcWuWqf0OCHuUdXajUIDGLCi yeVRdRqH41ncXPLcWPYJv5wLXdYWuUjkrcXgKNauACQeinzTX+E3k/lBjxnuEwxjbSDH +IEm6i4nulNl31VFl4EuTTVIYZmtqCX2oP/HE1tomBoLN2PW+EBOh2uAEavVFfZ7+RmT epKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775106938; x=1775711738; 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=urUQup7dc3mN1NcxY7RoIdIVM9FIVTCa2CM6teh2xWs=; b=ZlCMtZ6AiketBe6ZuCwbC9MODjg/Wol8Z32s3kzzLT8on+k7Pffjs6XnMtSr748wOj UaPSI1RPQt0l8nK4piAZa+Bx+J63e8TY901yLppYAaTPg1k0iSX7P3Pjn/2qCMqxErBu aCqoTsgXnuTKv0W8blDCCjRJ8X5NLfVn95SOROXKLQ4GCTCNc9iaJayXHxssraN0h79b UjKMaAvgct9CER6OiLN+xTsIYzsIUEGkZGt/EelJTHK3M3jmRaFtc9jvxSSFhOU0/GZD xcH9Vu4LJhl5bE6n/Ag4Qc322+7rPdCxnMZChMRRUeQRwNBiEzVDP8TtXIhD6K6WJunX 9Taw== X-Gm-Message-State: AOJu0YycV4RXMh2BLkeDoIgXO691xrzQUhhVH5j+siiSoKvU/YSZpc9a kwRtudAIafpv8QCOzBqWcjvBlD59mR/ct6/p564EK4mOfw/FhkTWQO0Z X-Gm-Gg: AeBDiev+rhmJXdtQv9Fru0bd0ouCQpued9Rc6YaGTpUkusJLJz9XZArQksxYF17HLsj ArKGZpYhq5V3XiS3SolwSqbJLaMiJSrK29/iEyoTslyGG2jOpjvoFQYT2XBypRe7TGVWQE7pDZr SQg51z9k5eQLAP1QK+laOFTDKYQp9mxnC0WAlmaMZNNnBoKQLmlr2sI0gNn5nlMRtvI3fCVD1RU b++5OwMnRTBLVZcq9btQmYd4bswbHzMiH0Z7/fEuCHWMfOsCAqkLySJiSCgw4sJSyeQiG8xgU/V y7AlLsCVu1bhuBepoo9O/A7TASNcl6joNcOxvWhuhzAHoJoxpYSZRIf1A2Ido4LkzsJ7VflEPEJ sCNoIPML9yb8dLqvgYCnfd252Q0H6uiyjuBvPE4XZPoIMCJUPTMQBQakFP/kVqVOGUin0xPjCqC +0EKEExEf7lqktWyiw736/L32wV7IfFHg691K3yLCn7IVxLOs161jJ0fKwp+7HvzmDVg== X-Received: by 2002:a17:90b:2ec4:b0:35d:a8d9:3a8 with SMTP id 98e67ed59e1d1-35dc6f7ad0bmr5899589a91.16.1775106937985; Wed, 01 Apr 2026 22:15:37 -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-35dbe93661fsm6902107a91.11.2026.04.01.22.15.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Apr 2026 22:15:37 -0700 (PDT) From: a0282524688@gmail.com To: tmyu0@nuvoton.com, linusw@kernel.org, brgl@kernel.org, linux@roeck-us.net, andi.shyti@kernel.org, lee@kernel.org, mkl@pengutronix.de, mailhol@kernel.org, alexandre.belloni@bootlin.com, wim@linux-watchdog.org Cc: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org, linux-can@vger.kernel.org, netdev@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-rtc@vger.kernel.org, linux-usb@vger.kernel.org, Ming Yu Subject: [PATCH v1 1/2] mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA Date: Thu, 2 Apr 2026 13:14:41 +0800 Message-Id: <20260402051442.1426672-2-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-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ming Yu Currently, the nct6694 core driver uses mfd_add_hotplug_devices() and an IDA to manage subdevice IDs. Switch the core implementation to use the managed devm_mfd_add_devices() API, which simplifies the error handling and device lifecycle management. Concurrently, drop the custom IDA implementation and transition to using pdev->id. Signed-off-by: Ming Yu --- drivers/gpio/gpio-nct6694.c | 19 +------ drivers/i2c/busses/i2c-nct6694.c | 19 +------ drivers/mfd/nct6694.c | 83 ++++++++++++----------------- drivers/net/can/usb/nct6694_canfd.c | 12 +---- drivers/watchdog/nct6694_wdt.c | 20 +------ include/linux/mfd/nct6694.h | 8 +-- 6 files changed, 43 insertions(+), 118 deletions(-) diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c index a8607f0d9915..3703a61209e6 100644 --- a/drivers/gpio/gpio-nct6694.c +++ b/drivers/gpio/gpio-nct6694.c @@ -7,7 +7,6 @@ =20 #include #include -#include #include #include #include @@ -381,14 +380,6 @@ static void nct6694_irq_dispose_mapping(void *d) irq_dispose_mapping(data->irq); } =20 -static void nct6694_gpio_ida_free(void *d) -{ - struct nct6694_gpio_data *data =3D d; - struct nct6694 *nct6694 =3D data->nct6694; - - ida_free(&nct6694->gpio_ida, data->group); -} - static int nct6694_gpio_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; @@ -403,15 +394,7 @@ static int nct6694_gpio_probe(struct platform_device *= pdev) return -ENOMEM; =20 data->nct6694 =3D nct6694; - - ret =3D ida_alloc(&nct6694->gpio_ida, GFP_KERNEL); - if (ret < 0) - return ret; - data->group =3D ret; - - ret =3D devm_add_action_or_reset(dev, nct6694_gpio_ida_free, data); - if (ret) - return ret; + data->group =3D pdev->id; =20 names =3D devm_kcalloc(dev, NCT6694_NR_GPIO, sizeof(char *), GFP_KERNEL); diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6= 694.c index 1413ab6f9462..7d8ad997f6d2 100644 --- a/drivers/i2c/busses/i2c-nct6694.c +++ b/drivers/i2c/busses/i2c-nct6694.c @@ -6,7 +6,6 @@ */ =20 #include -#include #include #include #include @@ -134,14 +133,6 @@ static int nct6694_i2c_set_baudrate(struct nct6694_i2c= _data *data) return 0; } =20 -static void nct6694_i2c_ida_free(void *d) -{ - struct nct6694_i2c_data *data =3D d; - struct nct6694 *nct6694 =3D data->nct6694; - - ida_free(&nct6694->i2c_ida, data->port); -} - static int nct6694_i2c_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; @@ -155,15 +146,7 @@ static int nct6694_i2c_probe(struct platform_device *p= dev) =20 data->dev =3D dev; data->nct6694 =3D nct6694; - - ret =3D ida_alloc(&nct6694->i2c_ida, GFP_KERNEL); - if (ret < 0) - return ret; - data->port =3D ret; - - ret =3D devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data); - if (ret) - return ret; + data->port =3D pdev->id; =20 ret =3D nct6694_i2c_set_baudrate(data); if (ret) diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c index 308b2fda3055..8ce2c4985aab 100644 --- a/drivers/mfd/nct6694.c +++ b/drivers/mfd/nct6694.c @@ -11,7 +11,6 @@ =20 #include #include -#include #include #include #include @@ -23,35 +22,35 @@ #include =20 static const struct mfd_cell nct6694_devs[] =3D { - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - MFD_CELL_NAME("nct6694-gpio"), - - MFD_CELL_NAME("nct6694-i2c"), - MFD_CELL_NAME("nct6694-i2c"), - MFD_CELL_NAME("nct6694-i2c"), - MFD_CELL_NAME("nct6694-i2c"), - MFD_CELL_NAME("nct6694-i2c"), - MFD_CELL_NAME("nct6694-i2c"), - - MFD_CELL_NAME("nct6694-canfd"), - MFD_CELL_NAME("nct6694-canfd"), - - MFD_CELL_NAME("nct6694-wdt"), - MFD_CELL_NAME("nct6694-wdt"), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 2), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 3), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 4), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 5), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 6), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 7), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 8), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 9), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 10), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 11), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 12), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 13), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 14), + MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 15), + + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 0), + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 1), + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 2), + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 3), + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 4), + MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 5), + + MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 0), + MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 1), + + MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 0), + MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 1), =20 MFD_CELL_NAME("nct6694-hwmon"), =20 @@ -307,23 +306,18 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, nct6694->dev =3D dev; nct6694->udev =3D udev; =20 - 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); =20 ret =3D devm_mutex_init(dev, &nct6694->access_lock); if (ret) - goto err_ida; + goto err_irq_domain; =20 interface =3D iface->cur_altsetting; =20 int_endpoint =3D &interface->endpoint[0].desc; if (!usb_endpoint_is_int_in(int_endpoint)) { ret =3D -ENODEV; - goto err_ida; + goto err_irq_domain; } =20 usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_= INT_IN_EP), @@ -332,11 +326,11 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, =20 ret =3D usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL); if (ret) - goto err_ida; + goto err_irq_domain; =20 usb_set_intfdata(iface, nct6694); =20 - ret =3D mfd_add_hotplug_devices(dev, nct6694_devs, ARRAY_SIZE(nct6694_dev= s)); + ret =3D devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_dev= s), NULL, 0, NULL); if (ret) goto err_mfd; =20 @@ -344,11 +338,7 @@ static int nct6694_usb_probe(struct usb_interface *ifa= ce, =20 err_mfd: usb_kill_urb(nct6694->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); +err_irq_domain: irq_domain_remove(nct6694->domain); err_urb: usb_free_urb(nct6694->int_in_urb); @@ -359,12 +349,7 @@ static void nct6694_usb_disconnect(struct usb_interfac= e *iface) { struct nct6694 *nct6694 =3D usb_get_intfdata(iface); =20 - mfd_remove_devices(nct6694->dev); usb_kill_urb(nct6694->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(nct6694->int_in_urb); } diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6= 694_canfd.c index e5f7f8849a73..29282c56430f 100644 --- a/drivers/net/can/usb/nct6694_canfd.c +++ b/drivers/net/can/usb/nct6694_canfd.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -725,15 +724,13 @@ static int nct6694_canfd_probe(struct platform_device= *pdev) struct net_device *ndev; int port, irq, ret, can_clk; =20 - port =3D ida_alloc(&nct6694->canfd_ida, GFP_KERNEL); - if (port < 0) - return port; + port =3D pdev->id; =20 irq =3D irq_create_mapping(nct6694->domain, NCT6694_IRQ_CAN0 + port); if (!irq) { ret =3D -EINVAL; - goto free_ida; + return ret; } =20 ndev =3D alloc_candev(sizeof(struct nct6694_canfd_priv), 1); @@ -796,24 +793,19 @@ static int nct6694_canfd_probe(struct platform_device= *pdev) free_candev(ndev); dispose_irq: irq_dispose_mapping(irq); -free_ida: - ida_free(&nct6694->canfd_ida, port); return ret; } =20 static void nct6694_canfd_remove(struct platform_device *pdev) { struct nct6694_canfd_priv *priv =3D platform_get_drvdata(pdev); - struct nct6694 *nct6694 =3D priv->nct6694; struct net_device *ndev =3D priv->ndev; - int port =3D ndev->dev_port; int irq =3D ndev->irq; =20 unregister_candev(ndev); can_rx_offload_del(&priv->offload); free_candev(ndev); irq_dispose_mapping(irq); - ida_free(&nct6694->canfd_ida, port); } =20 static struct platform_driver nct6694_canfd_driver =3D { diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c index bc3689bd4b6b..2b4b804a1739 100644 --- a/drivers/watchdog/nct6694_wdt.c +++ b/drivers/watchdog/nct6694_wdt.c @@ -5,7 +5,6 @@ * Copyright (C) 2025 Nuvoton Technology Corp. */ =20 -#include #include #include #include @@ -233,21 +232,12 @@ static const struct watchdog_ops nct6694_wdt_ops =3D { .ping =3D nct6694_wdt_ping, }; =20 -static void nct6694_wdt_ida_free(void *d) -{ - struct nct6694_wdt_data *data =3D d; - struct nct6694 *nct6694 =3D data->nct6694; - - ida_free(&nct6694->wdt_ida, data->wdev_idx); -} - static int nct6694_wdt_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; struct nct6694 *nct6694 =3D dev_get_drvdata(dev->parent); struct nct6694_wdt_data *data; struct watchdog_device *wdev; - int ret; =20 data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -260,15 +250,7 @@ static int nct6694_wdt_probe(struct platform_device *p= dev) =20 data->dev =3D dev; data->nct6694 =3D nct6694; - - ret =3D ida_alloc(&nct6694->wdt_ida, GFP_KERNEL); - if (ret < 0) - return ret; - data->wdev_idx =3D ret; - - ret =3D devm_add_action_or_reset(dev, nct6694_wdt_ida_free, data); - if (ret) - return ret; + data->wdev_idx =3D pdev->id; =20 wdev =3D &data->wdev; wdev->info =3D &nct6694_wdt_info; diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h index 6eb9be2cd4a0..496da72949d9 100644 --- a/include/linux/mfd/nct6694.h +++ b/include/linux/mfd/nct6694.h @@ -8,6 +8,10 @@ #ifndef __MFD_NCT6694_H #define __MFD_NCT6694_H =20 +#include +#include +#include + #define NCT6694_VENDOR_ID 0x0416 #define NCT6694_PRODUCT_ID 0x200B #define NCT6694_INT_IN_EP 0x81 @@ -82,10 +86,6 @@ union __packed nct6694_usb_msg { =20 struct nct6694 { struct device *dev; - struct ida gpio_ida; - struct ida i2c_ida; - struct ida canfd_ida; - struct ida wdt_ida; struct irq_domain *domain; struct mutex access_lock; spinlock_t irq_lock; --=20 2.34.1 From nobody Sun Jun 14 09:56:23 2026 Received: from mail-pj1-f51.google.com (mail-pj1-f51.google.com [209.85.216.51]) (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 2A49C375AA8 for ; Thu, 2 Apr 2026 05:15:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775106947; cv=none; b=IvBkrAWkfjEvRQzuv1CnrQuk58T6YDWI2WcEqfM6DOhnoUpJEWGmiEQOUcI30cQv1SCewdsZiC8PQQVgvMTZb6Lah2IyMeQztLYIe0AH1+e7BBxhn0FyChwqs+vtQxi6DmSSLS/TuijVD2TGSkEZk4IyjW6f4y5X2t9friC6SnI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775106947; c=relaxed/simple; bh=8CU2mHe8Ft/cnSHYweJrmXkjm6QHznfcLRBHfZxIdJ0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=g7VlZ+FRqUExFfKoCKQZrq898K5PHub7XnOAbKMq6jtcsK5yAXrzkEn3yO3fth6re/x6tauPeij8jpmyrzSW9quOlbmQWQ+MV9+F2A4UzP6FqLcI8rBvSzI46dqLhfMuwxU+RABjLCpX1A0TbqUB5ms/oFSWfeFXwbRCcmjjpg4= 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=TzYSHT4e; arc=none smtp.client-ip=209.85.216.51 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="TzYSHT4e" Received: by mail-pj1-f51.google.com with SMTP id 98e67ed59e1d1-35da1af3e10so404219a91.3 for ; Wed, 01 Apr 2026 22:15:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775106942; x=1775711742; 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=R/hX4IZ54cyXA00IabMHW3Oiay+D3kHDi2lk9JIA4fI=; b=TzYSHT4evgwfCxitN0HVbK9RILe1N3bbyIz5V77m3qyzmo3QyKSVwSGhHBg/JvqZps zj2SwDZsCzZkzIj4LXb7m8JzDnEecNllhMfd/oQ/kFGLRD7Y/tNEDYN67iOI9TX3AUWP RMM2vGHwB3YVincCNgik5HUuoyHX+KRyLczndV6eajUn24GSEXM1QIaAgC4U6W1TsCfP GlZ2LkM8NSXC92AlhjaOxzUnLIme/XgVcicC6v9hltgJKHRR48PK8PYNpTIK99w89RaK iwffPxynGnZc36ug6R5OF+WyAEGefj4ifsCVG1/8zpfONThp0DeBOSe8JdxinxTOX61v tgxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775106942; x=1775711742; 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=R/hX4IZ54cyXA00IabMHW3Oiay+D3kHDi2lk9JIA4fI=; b=LUmeOmJUAhCaDMvLR+WmUscMLx8HFgwCJw8k4edZWR1pKG9jtKIeZFL5WjLl3h0gQr P3EG/Er071z/HAOQnGJHBNKQHWKreBZkjboAHVwGFThg5MW2lJz0H/NJPF9KsRVvPKTz ab36hdAB3ZVxblFgf6yc+TCAfybKNuB37rlq1IRamRKknvrOQzdv7kPTX4V8ySZMf/7F ARhUJxNyq6ekfyeBSevbe7qcdZnaTyF09oLRMo7UchHyj71tdfAjGmpaLky6Eq8k4Ll9 4fkQZ0PHm4b4w0Bs60jcwAYY6VCFcJhXRc/dqIloTC012viZg8n0flnjd9CPBntpQluB 0FZA== X-Gm-Message-State: AOJu0YwOyycrXfwvg2wjzZcawDBNnBqxGmYtlFAXKzsWoA7GHeEc3APp zZ6V1LI2/kriwQtSWEY6kDibYIRKCRpIJT+lSpQsw7AdYdNh0IuhfYth X-Gm-Gg: AeBDieuQde0ib1LRrYlH1unjgX3WyuF55zXz/pOde5c65cj3h+RUDgpEsv+fMXHrt99 0D+vpRaAQG7uUDrWsooyqnCL1r6jQuf0Zv0w4sqg8U+X6ZH5eUb5jbKB+Cdw1dkLMyRUMoBkuvw iMF6ycLxZkexMLb00mrJBCHoM8bl9fvGHsc5NXdW/51D7UIM110Lcu0PrciM1/HwrGUNdaF1r45 zfYeSgrmaRuG2AnDEyfmGaRGU8l0xEs+RjP3dJbADNC2P8I+BGPlXLUAvXK7gj7/nwFwxFmw/44 YPT19hpzgnGt9H6OtbOlQcx9YaVzAPe/zotQWtIQetJpCp8fDO5N/A7fZ39M2P3s9a11r4xSKD4 8v05kPXobudtv0XwjMn+323RpVT1nfx71WWGYzYcm85Tx5jyA3RhUEn5cY8eHF3XuLuTSVXTAQu PSyfHyLFA2ztzXrg73MTrCSm3r8PLgMeQnKWIb3bA/J2plAfghSu4vWKHzxL/gk40oFQ== X-Received: by 2002:a17:90b:28ce:b0:35b:e551:e776 with SMTP id 98e67ed59e1d1-35dc70192b6mr6070276a91.27.1775106942266; Wed, 01 Apr 2026 22:15:42 -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-35dbe93661fsm6902107a91.11.2026.04.01.22.15.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Apr 2026 22:15:41 -0700 (PDT) From: a0282524688@gmail.com To: tmyu0@nuvoton.com, linusw@kernel.org, brgl@kernel.org, linux@roeck-us.net, andi.shyti@kernel.org, lee@kernel.org, mkl@pengutronix.de, mailhol@kernel.org, alexandre.belloni@bootlin.com, wim@linux-watchdog.org Cc: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org, linux-can@vger.kernel.org, netdev@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-rtc@vger.kernel.org, linux-usb@vger.kernel.org, Ming Yu Subject: [PATCH v1 2/2] mfd: Add Host Interface (HIF) support for Nuvoton 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-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Ming Yu 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 --- 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 #include =20 -/* - * 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 #include =20 -/* - * 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)) =20 -/* - * 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 =20 -/* - * 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-nct6= 694.c index 7d8ad997f6d2..7ee209a04d16 100644 --- a/drivers/i2c/busses/i2c-nct6694.c +++ b/drivers/i2c/busses/i2c-nct6694.c @@ -11,13 +11,6 @@ #include #include =20 -/* - * 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. =20 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. =20 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) +=3D mc13xxx-i2c.o =20 obj-$(CONFIG_MFD_PF1550) +=3D pf1550.o =20 -obj-$(CONFIG_MFD_NCT6694) +=3D nct6694.o +obj-$(CONFIG_MFD_NCT6694_HIF) +=3D nct6694-hif.o +obj-$(CONFIG_MFD_NCT6694_USB) +=3D nct6694.o =20 obj-$(CONFIG_MFD_CORE) +=3D mfd-core.o =20 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 byt= es) */ + +enum nct6694_chips { + NCT6694B =3D 0, + NCT6694D, +}; + +enum nct6694_module_id { + NCT6694_GPIO0 =3D 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); +}; + +struct nct6694_hif_data { + struct regmap *regmap; + struct mutex msg_lock; + struct nct6694_sio_data *sio_data; + void __iomem *msg_base; + unsigned int shm_base; +}; + +static const char * const nct6694_chip_names[] =3D { + "NCT6694D", + "NCT6694B" +}; + +/* + * Super-I/O functions. + */ +static int superio_enter(struct nct6694_sio_data *sio_data) +{ + int ioreg =3D sio_data->sioreg; + + /* + * Try to reserve and for exclusive access. + */ + if (!request_muxed_region(ioreg, 2, DRVNAME)) + return -EBUSY; + + outb(SIO_REG_UNLOCK_KEY, ioreg); + outb(SIO_REG_UNLOCK_KEY, ioreg); + + return 0; +} + +static void superio_exit(struct nct6694_sio_data *sio_data) +{ + int ioreg =3D sio_data->sioreg; + + outb(SIO_REG_LOCK_KEY, ioreg); + + release_region(ioreg, 2); +} + +static void superio_select(struct nct6694_sio_data *sio_data, int ld) +{ + int ioreg =3D sio_data->sioreg; + + outb(SIO_REG_LDSEL, ioreg); + outb(ld, ioreg + 1); +} + +static int superio_inb(struct nct6694_sio_data *sio_data, int reg) +{ + int ioreg =3D sio_data->sioreg; + + outb(reg, ioreg); + return inb(ioreg + 1); +} + +static int superio_inw(struct nct6694_sio_data *sio_data, int reg) +{ + int ioreg =3D sio_data->sioreg; + int val; + + outb(reg++, ioreg); + val =3D inb(ioreg + 1) << 8; + outb(reg, ioreg); + val |=3D inb(ioreg + 1); + + return val; +} + +static void superio_outb(struct nct6694_sio_data *sio_data, int reg, int v= al) +{ + int ioreg =3D sio_data->sioreg; + + outb(reg, ioreg); + outb(val, ioreg + 1); +} + +static int nct6694_sio_find(struct nct6694_sio_data *sio_data, u8 sioreg) +{ + int ret; + u16 devid; + + sio_data->sioreg =3D sioreg; + + ret =3D sio_data->sio_enter(sio_data); + if (ret) + return ret; + + /* Check Chip ID */ + devid =3D sio_data->sio_inw(sio_data, SIO_REG_DEVID); + switch (devid) { + case SIO_NCT6694B_ID: + sio_data->chip =3D NCT6694B; + break; + case SIO_NCT6694D_ID: + sio_data->chip =3D NCT6694D; + break; + default: + pr_err("Unsupported device 0x%04x\n", devid); + goto err; + } + + pr_info("Found %s at %#x\n", nct6694_chip_names[sio_data->chip], sio_data= ->sioreg); + + sio_data->sio_exit(sio_data); + + return 0; + +err: + sio_data->sio_exit(sio_data); + return -ENODEV; +} + +static const struct mfd_cell_acpi_match nct6694_acpi_match_gpio[] =3D { + { .adr =3D NCT6694_GPIO0 }, + { .adr =3D NCT6694_GPIO1 }, + { .adr =3D NCT6694_GPIO2 }, + { .adr =3D NCT6694_GPIO3 }, + { .adr =3D NCT6694_GPIO4 }, + { .adr =3D NCT6694_GPIO5 }, + { .adr =3D NCT6694_GPIO6 }, + { .adr =3D NCT6694_GPIO7 }, + { .adr =3D NCT6694_GPIO8 }, + { .adr =3D NCT6694_GPIO9 }, + { .adr =3D NCT6694_GPIOA }, + { .adr =3D NCT6694_GPIOB }, + { .adr =3D NCT6694_GPIOC }, + { .adr =3D NCT6694_GPIOD }, + { .adr =3D NCT6694_GPIOE }, + { .adr =3D NCT6694_GPIOF }, +}; + +static const struct mfd_cell_acpi_match nct6694_acpi_match_i2c[] =3D { + { .adr =3D NCT6694_I2C0 }, + { .adr =3D NCT6694_I2C1 }, + { .adr =3D NCT6694_I2C2 }, + { .adr =3D NCT6694_I2C3 }, + { .adr =3D NCT6694_I2C4 }, + { .adr =3D NCT6694_I2C5 }, +}; + +static const struct mfd_cell_acpi_match nct6694_acpi_match_can[] =3D { + { .adr =3D NCT6694_CAN0 }, + { .adr =3D NCT6694_CAN1 }, +}; + +static const struct mfd_cell nct6694_devs[] =3D { + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 0, &nct6694_acpi_match_gpio[= 0]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 1, &nct6694_acpi_match_gpio[= 1]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 2, &nct6694_acpi_match_gpio[= 2]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 3, &nct6694_acpi_match_gpio[= 3]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 4, &nct6694_acpi_match_gpio[= 4]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 5, &nct6694_acpi_match_gpio[= 5]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 6, &nct6694_acpi_match_gpio[= 6]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 7, &nct6694_acpi_match_gpio[= 7]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 8, &nct6694_acpi_match_gpio[= 8]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 9, &nct6694_acpi_match_gpio[= 9]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 10, &nct6694_acpi_match_gpio= [10]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 11, &nct6694_acpi_match_gpio= [11]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 12, &nct6694_acpi_match_gpio= [12]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 13, &nct6694_acpi_match_gpio= [13]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 14, &nct6694_acpi_match_gpio= [14]), + MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 15, &nct6694_acpi_match_gpio= [15]), + + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 0, &nct6694_acpi_match_i2c[0]= ), + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 1, &nct6694_acpi_match_i2c[1]= ), + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 2, &nct6694_acpi_match_i2c[2]= ), + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 3, &nct6694_acpi_match_i2c[3]= ), + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 4, &nct6694_acpi_match_i2c[4]= ), + MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 5, &nct6694_acpi_match_i2c[5]= ), + + MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 0, &nct6694_acpi_match_can[= 0]), + MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 1, &nct6694_acpi_match_can[= 1]), +}; + +static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned= char err_status) +{ + switch (err_status) { + case NCT6694_NO_ERROR: + return 0; + case NCT6694_NOT_SUPPORT_ERROR: + dev_err(nct6694->dev, "Command is not supported!\n"); + break; + case NCT6694_NO_RESPONSE_ERROR: + dev_warn(nct6694->dev, "Command received no response!\n"); + break; + case NCT6694_TIMEOUT_ERROR: + dev_warn(nct6694->dev, "Command timed out!\n"); + break; + case NCT6694_PENDING: + dev_err(nct6694->dev, "Command is pending!\n"); + break; + default: + return -EINVAL; + } + + return -EIO; +} + +static int nct6694_xfer_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + u8 hctrl, void *buf) +{ + struct nct6694_hif_data *hdata =3D nct6694->priv; + void __iomem *hdr =3D hdata->msg_base + offsetof(struct nct6694_msg, cmd_= header); + struct nct6694_cmd_header cmd =3D *cmd_hd; + struct nct6694_response_header resp; + u16 len =3D le16_to_cpu(cmd.len); + u8 status; + int ret; + + guard(mutex)(&hdata->msg_lock); + + /* Wait until the previous command is completed */ + ret =3D readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctr= l), + status, status =3D=3D 0, NCT6694_POLL_INTERVAL_US, + NCT6694_POLL_TIMEOUT_US); + if (ret) + return ret; + + /* + * Write cmd header fields, but skip hctrl =E2=80=94 writing to it trigge= rs + * firmware command processing and must be deferred until data is ready. + */ + memcpy_toio(hdr, &cmd, offsetof(struct nct6694_cmd_header, hctrl)); + memcpy_toio(hdr + offsetof(struct nct6694_cmd_header, rsv2), &cmd.rsv2, + sizeof(cmd) - offsetof(struct nct6694_cmd_header, rsv2)); + + if (hctrl =3D=3D NCT6694_HCTRL_SET && len) + memcpy_toio(hdata->msg_base + offsetof(struct nct6694_msg, data), + buf, len); + + /* Write hctrl last to trigger command processing */ + writeb(hctrl, hdr + offsetof(struct nct6694_cmd_header, hctrl)); + + ret =3D readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctr= l), + status, status =3D=3D 0, NCT6694_POLL_INTERVAL_US, + NCT6694_POLL_TIMEOUT_US); + if (ret) + return ret; + + memcpy_fromio(&resp, hdata->msg_base + offsetof(struct nct6694_msg, respo= nse_header), + sizeof(resp)); + + ret =3D nct6694_response_err_handling(nct6694, resp.sts); + if (ret) + return ret; + + if (le16_to_cpu(resp.len)) + memcpy_fromio(buf, hdata->msg_base + offsetof(struct nct6694_msg, data), + min(len, le16_to_cpu(resp.len))); + + return 0; +} + +/** + * nct6694_hif_read_msg() - Send a command and read response data via HIF + * @nct6694: NCT6694 device data + * @cmd_hd: command header + * @buf: buffer to store response data + * + * Return: 0 on success or negative errno on failure. + */ +static int nct6694_hif_read_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) +{ + struct nct6694_hif_data *hdata =3D nct6694->priv; + + if (cmd_hd->mod =3D=3D NCT6694_RPT_MOD) + return regmap_bulk_read(hdata->regmap, + le16_to_cpu(cmd_hd->offset), + buf, le16_to_cpu(cmd_hd->len)); + return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_GET, buf); +} + +/** + * nct6694_hif_write_msg() - Send a command with data payload via HIF + * @nct6694: NCT6694 device data + * @cmd_hd: command header + * @buf: buffer containing data to send + * + * Return: 0 on success or negative errno on failure. + */ +static int nct6694_hif_write_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) +{ + struct nct6694_hif_data *hdata =3D nct6694->priv; + + if (cmd_hd->mod =3D=3D NCT6694_RPT_MOD) + return regmap_bulk_write(hdata->regmap, + le16_to_cpu(cmd_hd->offset), + buf, le16_to_cpu(cmd_hd->len)); + return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_SET, buf); +} + +static const struct regmap_config nct6694_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .reg_stride =3D 1, +}; + +static irqreturn_t nct6694_irq_handler(int irq, void *data) +{ + struct nct6694 *nct6694 =3D data; + struct nct6694_hif_data *hdata =3D nct6694->priv; + u8 reg_data[4]; + u32 intr_status; + int ret; + + /* Check interrupt status is set */ + if (!(inb(hdata->shm_base + NCT6694_SHM_COFS_STS) & NCT6694_SHM_COFS_STS_= COFS4W)) + return IRQ_NONE; + + /* Clear interrupt status */ + outb(NCT6694_SHM_COFS_STS_COFS4W, hdata->shm_base + NCT6694_SHM_COFS_STS); + + ret =3D regmap_bulk_read(hdata->regmap, NCT6694_SHM_INTR_STATUS, + reg_data, ARRAY_SIZE(reg_data)); + if (ret) + return IRQ_NONE; + + intr_status =3D get_unaligned_le32(reg_data); + + while (intr_status) { + int irq =3D __ffs(intr_status); + + generic_handle_irq_safe(irq_find_mapping(nct6694->domain, irq)); + intr_status &=3D ~BIT(irq); + } + + return IRQ_HANDLED; +} + +static void nct6694_irq_release(void *data) +{ + struct nct6694 *nct6694 =3D data; + struct nct6694_hif_data *hdata =3D nct6694->priv; + unsigned char cofs_ctl2; + + /* Disable SIRQ interrupt */ + cofs_ctl2 =3D inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2); + cofs_ctl2 &=3D ~NCT6694_SHM_COFS_CTL2_COFS4W_IE; + outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2); +} + +static int nct6694_irq_init(struct nct6694 *nct6694, int irq) +{ + struct nct6694_hif_data *hdata =3D nct6694->priv; + struct nct6694_sio_data *sio_data =3D hdata->sio_data; + unsigned char cofs_ctl2; + + /* Set SIRQ number */ + sio_data->sio_enter(sio_data); + sio_data->sio_select(sio_data, SIO_REG_LD_SHM); + if (!sio_data->sio_inb(sio_data, SIO_REG_SHM_ENABLE)) { + sio_data->sio_exit(sio_data); + return -EIO; + } + hdata->shm_base =3D sio_data->sio_inw(sio_data, SIO_REG_SHM_BASE_ADDR); + + sio_data->sio_outb(sio_data, SIO_REG_SHM_IRQ_NR, irq); + + sio_data->sio_exit(sio_data); + + /* Enable SIRQ interrupt */ + cofs_ctl2 =3D inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2); + cofs_ctl2 |=3D NCT6694_SHM_COFS_CTL2_COFS4W_IE; + outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2); + + return 0; +} + +static void nct6694_irq_enable(struct irq_data *data) +{ + struct nct6694 *nct6694 =3D irq_data_get_irq_chip_data(data); + irq_hw_number_t hwirq =3D irqd_to_hwirq(data); + + guard(spinlock_irqsave)(&nct6694->irq_lock); + + nct6694->irq_enable |=3D BIT(hwirq); +} + +static void nct6694_irq_disable(struct irq_data *data) +{ + struct nct6694 *nct6694 =3D irq_data_get_irq_chip_data(data); + irq_hw_number_t hwirq =3D irqd_to_hwirq(data); + + guard(spinlock_irqsave)(&nct6694->irq_lock); + + nct6694->irq_enable &=3D ~BIT(hwirq); +} + +static const struct irq_chip nct6694_irq_chip =3D { + .name =3D "nct6694-irq", + .flags =3D IRQCHIP_SKIP_SET_WAKE, + .irq_enable =3D nct6694_irq_enable, + .irq_disable =3D nct6694_irq_disable, +}; + +static void nct6694_irq_domain_remove(void *data) +{ + struct nct6694 *nct6694 =3D data; + + irq_domain_remove(nct6694->domain); +} + +static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, = irq_hw_number_t hw) +{ + struct nct6694 *nct6694 =3D 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 ir= q) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops nct6694_irq_domain_ops =3D { + .map =3D nct6694_irq_domain_map, + .unmap =3D nct6694_irq_domain_unmap, +}; + +static const u8 sio_addrs[] =3D { 0x2e, 0x4e }; + +static int nct6694_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct nct6694_sio_data *sio_data; + struct nct6694_hif_data *hdata; + struct nct6694 *data; + void __iomem *rpt_base, *msg_base; + int ret, i, irq; + + sio_data =3D devm_kzalloc(dev, sizeof(*sio_data), GFP_KERNEL); + if (!sio_data) + return -ENOMEM; + + data =3D devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + hdata =3D devm_kzalloc(dev, sizeof(*hdata), GFP_KERNEL); + if (!hdata) + return -ENOMEM; + + rpt_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rpt_base)) + return PTR_ERR(rpt_base); + msg_base =3D devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(msg_base)) + return PTR_ERR(msg_base); + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + sio_data->sio_enter =3D superio_enter; + sio_data->sio_exit =3D superio_exit; + sio_data->sio_select =3D superio_select; + sio_data->sio_inb =3D superio_inb; + sio_data->sio_inw =3D superio_inw; + sio_data->sio_outb =3D superio_outb; + + for (i =3D 0; i < ARRAY_SIZE(sio_addrs); i++) { + ret =3D nct6694_sio_find(sio_data, sio_addrs[i]); + if (!ret) + break; + } + if (ret) + return ret; + + hdata->sio_data =3D sio_data; + hdata->msg_base =3D msg_base; + hdata->regmap =3D devm_regmap_init_mmio(dev, rpt_base, + &nct6694_regmap_config); + if (IS_ERR(hdata->regmap)) + return PTR_ERR(hdata->regmap); + + data->dev =3D dev; + data->priv =3D hdata; + data->read_msg =3D nct6694_hif_read_msg; + data->write_msg =3D nct6694_hif_write_msg; + + spin_lock_init(&data->irq_lock); + + data->domain =3D irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0, + &nct6694_irq_domain_ops, + data); + if (!data->domain) + return -ENODEV; + + ret =3D devm_add_action_or_reset(dev, nct6694_irq_domain_remove, data); + if (ret) + return ret; + + ret =3D nct6694_irq_init(data, irq); + if (ret) + return ret; + + ret =3D devm_add_action_or_reset(dev, nct6694_irq_release, data); + if (ret) + return ret; + + ret =3D devm_request_threaded_irq(dev, irq, NULL, nct6694_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(dev), data); + if (ret) + return ret; + + ret =3D devm_mutex_init(dev, &hdata->msg_lock); + if (ret) + return ret; + + platform_set_drvdata(pdev, data); + + return devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs= ), NULL, 0, NULL); +} + +static const struct acpi_device_id nct6694_acpi_ids[] =3D { + { "NTN0538", 0 }, + {} +}; + +static struct platform_driver nct6694_driver =3D { + .driver =3D { + .name =3D DRVNAME, + .acpi_match_table =3D nct6694_acpi_ids, + }, + .probe =3D nct6694_probe, +}; +module_platform_driver(nct6694_driver); + +MODULE_DESCRIPTION("Nuvoton NCT6694 host-interface transport driver"); +MODULE_AUTHOR("Ming Yu "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c index 8ce2c4985aab..903a0a7f0694 100644 --- a/drivers/mfd/nct6694.c +++ b/drivers/mfd/nct6694.c @@ -21,6 +21,27 @@ #include #include =20 +#define NCT6694_VENDOR_ID 0x0416 +#define NCT6694_PRODUCT_ID 0x200B +#define NCT6694_INT_IN_EP 0x81 +#define NCT6694_BULK_IN_EP 0x02 +#define NCT6694_BULK_OUT_EP 0x03 + +#define NCT6694_URB_TIMEOUT 1000 + +union __packed nct6694_usb_msg { + struct nct6694_cmd_header cmd_header; + struct nct6694_response_header response_header; +}; + +struct nct6694_usb_data { + struct mutex access_lock; + struct urb *int_in_urb; + struct usb_device *udev; + union nct6694_usb_msg *usb_msg; + __le32 *int_buffer; +}; + static const struct mfd_cell nct6694_devs[] =3D { MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0), MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1), @@ -57,7 +78,8 @@ static const struct mfd_cell nct6694_devs[] =3D { MFD_CELL_NAME("nct6694-rtc"), }; =20 -static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned= char err_status) +static int nct6694_usb_err_handling(struct nct6694 *nct6694, + unsigned char err_status) { switch (err_status) { case NCT6694_NO_ERROR: @@ -82,7 +104,7 @@ static int nct6694_response_err_handling(struct nct6694 = *nct6694, unsigned char } =20 /** - * nct6694_read_msg() - Read message from NCT6694 device + * nct6694_usb_read_msg() - Read message from NCT6694 device via USB * @nct6694: NCT6694 device pointer * @cmd_hd: command header structure * @buf: buffer to store the response data @@ -93,13 +115,16 @@ static int nct6694_response_err_handling(struct nct669= 4 *nct6694, unsigned char * * Return: Negative value on error or 0 on success. */ -int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_hea= der *cmd_hd, void *buf) +static int nct6694_usb_read_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) { - union nct6694_usb_msg *msg =3D nct6694->usb_msg; - struct usb_device *udev =3D nct6694->udev; + struct nct6694_usb_data *udata =3D nct6694->priv; + union nct6694_usb_msg *msg =3D udata->usb_msg; + struct usb_device *udev =3D udata->udev; int tx_len, rx_len, ret; =20 - guard(mutex)(&nct6694->access_lock); + guard(mutex)(&udata->access_lock); =20 memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd)); msg->cmd_header.hctrl =3D NCT6694_HCTRL_GET; @@ -128,12 +153,11 @@ int nct6694_read_msg(struct nct6694 *nct6694, const s= truct nct6694_cmd_header *c return -EIO; } =20 - return nct6694_response_err_handling(nct6694, msg->response_header.sts); + return nct6694_usb_err_handling(nct6694, msg->response_header.sts); } -EXPORT_SYMBOL_GPL(nct6694_read_msg); =20 /** - * nct6694_write_msg() - Write message to NCT6694 device + * nct6694_usb_write_msg() - Write message to NCT6694 device via USB * @nct6694: NCT6694 device pointer * @cmd_hd: command header structure * @buf: buffer containing the data to be sent @@ -143,13 +167,16 @@ EXPORT_SYMBOL_GPL(nct6694_read_msg); * * Return: Negative value on error or 0 on success. */ -int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_he= ader *cmd_hd, void *buf) +static int nct6694_usb_write_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) { - union nct6694_usb_msg *msg =3D nct6694->usb_msg; - struct usb_device *udev =3D nct6694->udev; + struct nct6694_usb_data *udata =3D nct6694->priv; + union nct6694_usb_msg *msg =3D udata->usb_msg; + struct usb_device *udev =3D udata->udev; int tx_len, rx_len, ret; =20 - guard(mutex)(&nct6694->access_lock); + guard(mutex)(&udata->access_lock); =20 memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd)); msg->cmd_header.hctrl =3D NCT6694_HCTRL_SET; @@ -184,9 +211,8 @@ int nct6694_write_msg(struct nct6694 *nct6694, const st= ruct nct6694_cmd_header * return -EIO; } =20 - return nct6694_response_err_handling(nct6694, msg->response_header.sts); + return nct6694_usb_err_handling(nct6694, msg->response_header.sts); } -EXPORT_SYMBOL_GPL(nct6694_write_msg); =20 static void usb_int_callback(struct urb *urb) { @@ -276,6 +302,7 @@ static int nct6694_usb_probe(struct usb_interface *ifac= e, struct usb_endpoint_descriptor *int_endpoint; struct usb_host_interface *interface; struct device *dev =3D &iface->dev; + struct nct6694_usb_data *udata; struct nct6694 *nct6694; int ret; =20 @@ -283,18 +310,28 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, if (!nct6694) return -ENOMEM; =20 - nct6694->usb_msg =3D devm_kzalloc(dev, sizeof(union nct6694_usb_msg), GFP= _KERNEL); - if (!nct6694->usb_msg) + udata =3D devm_kzalloc(dev, sizeof(*udata), GFP_KERNEL); + if (!udata) + return -ENOMEM; + + udata->usb_msg =3D devm_kzalloc(dev, sizeof(*udata->usb_msg), GFP_KERNEL); + if (!udata->usb_msg) return -ENOMEM; =20 - nct6694->int_buffer =3D devm_kzalloc(dev, sizeof(*nct6694->int_buffer), G= FP_KERNEL); - if (!nct6694->int_buffer) + udata->int_buffer =3D devm_kzalloc(dev, sizeof(*udata->int_buffer), GFP_K= ERNEL); + if (!udata->int_buffer) return -ENOMEM; =20 - nct6694->int_in_urb =3D usb_alloc_urb(0, GFP_KERNEL); - if (!nct6694->int_in_urb) + udata->int_in_urb =3D usb_alloc_urb(0, GFP_KERNEL); + if (!udata->int_in_urb) return -ENOMEM; =20 + udata->udev =3D udev; + + nct6694->priv =3D udata; + nct6694->read_msg =3D nct6694_usb_read_msg; + nct6694->write_msg =3D nct6694_usb_write_msg; + nct6694->domain =3D irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0, &nct6694_irq_domain_ops, nct6694); @@ -304,11 +341,10 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, } =20 nct6694->dev =3D dev; - nct6694->udev =3D udev; =20 spin_lock_init(&nct6694->irq_lock); =20 - ret =3D devm_mutex_init(dev, &nct6694->access_lock); + ret =3D devm_mutex_init(dev, &udata->access_lock); if (ret) goto err_irq_domain; =20 @@ -320,11 +356,11 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, goto err_irq_domain; } =20 - usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_= INT_IN_EP), - nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback, + usb_fill_int_urb(udata->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_IN= T_IN_EP), + udata->int_buffer, sizeof(*udata->int_buffer), usb_int_callback, nct6694, int_endpoint->bInterval); =20 - ret =3D usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL); + ret =3D usb_submit_urb(udata->int_in_urb, GFP_KERNEL); if (ret) goto err_irq_domain; =20 @@ -337,21 +373,22 @@ static int nct6694_usb_probe(struct usb_interface *if= ace, return 0; =20 err_mfd: - usb_kill_urb(nct6694->int_in_urb); + usb_kill_urb(udata->int_in_urb); err_irq_domain: irq_domain_remove(nct6694->domain); err_urb: - usb_free_urb(nct6694->int_in_urb); + usb_free_urb(udata->int_in_urb); return ret; } =20 static void nct6694_usb_disconnect(struct usb_interface *iface) { struct nct6694 *nct6694 =3D usb_get_intfdata(iface); + struct nct6694_usb_data *udata =3D nct6694->priv; =20 - usb_kill_urb(nct6694->int_in_urb); + usb_kill_urb(udata->int_in_urb); irq_domain_remove(nct6694->domain); - usb_free_urb(nct6694->int_in_urb); + usb_free_urb(udata->int_in_urb); } =20 static const struct usb_device_id nct6694_ids[] =3D { diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6= 694_canfd.c index 29282c56430f..05db00455f63 100644 --- a/drivers/net/can/usb/nct6694_canfd.c +++ b/drivers/net/can/usb/nct6694_canfd.c @@ -17,12 +17,6 @@ =20 #define DEVICE_NAME "nct6694-canfd" =20 -/* USB command module type for NCT6694 CANfd controller. - * This defines the module type used for communication with the NCT6694 - * CANfd controller over the USB interface. - */ -#define NCT6694_CANFD_MOD 0x05 - /* Command 00h - CAN Setting and Initialization */ #define NCT6694_CANFD_SETTING 0x00 #define NCT6694_CANFD_SETTING_ACTIVE_CTRL1 BIT(0) diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c index 35401a0d9cf5..c06902f150c9 100644 --- a/drivers/rtc/rtc-nct6694.c +++ b/drivers/rtc/rtc-nct6694.c @@ -14,13 +14,6 @@ #include #include =20 -/* - * USB command module type for NCT6694 RTC controller. - * This defines the module type used for communication with the NCT6694 - * RTC controller over the USB interface. - */ -#define NCT6694_RTC_MOD 0x08 - /* Command 00h - RTC Time */ #define NCT6694_RTC_TIME 0x0000 #define NCT6694_RTC_TIME_SEL 0x00 diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c index 2b4b804a1739..847d8f1d1830 100644 --- a/drivers/watchdog/nct6694_wdt.c +++ b/drivers/watchdog/nct6694_wdt.c @@ -19,13 +19,6 @@ =20 #define NCT6694_WDT_MAX_DEVS 2 =20 -/* - * USB command module type for NCT6694 WDT controller. - * This defines the module type used for communication with the NCT6694 - * WDT controller over the USB interface. - */ -#define NCT6694_WDT_MOD 0x07 - /* Command 00h - WDT Setup */ #define NCT6694_WDT_SETUP 0x00 #define NCT6694_WDT_SETUP_SEL(idx) (idx ? 0x01 : 0x00) diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h index 496da72949d9..ff0814dc82d4 100644 --- a/include/linux/mfd/nct6694.h +++ b/include/linux/mfd/nct6694.h @@ -2,7 +2,8 @@ /* * Copyright (C) 2025 Nuvoton Technology Corp. * - * Nuvoton NCT6694 USB transaction and data structure. + * Nuvoton NCT6694 core definitions shared by all transport drivers + * and sub-device drivers. */ =20 #ifndef __MFD_NCT6694_H @@ -12,16 +13,17 @@ #include #include =20 -#define NCT6694_VENDOR_ID 0x0416 -#define NCT6694_PRODUCT_ID 0x200B -#define NCT6694_INT_IN_EP 0x81 -#define NCT6694_BULK_IN_EP 0x02 -#define NCT6694_BULK_OUT_EP 0x03 - #define NCT6694_HCTRL_SET 0x40 #define NCT6694_HCTRL_GET 0x80 =20 -#define NCT6694_URB_TIMEOUT 1000 +#define NCT6694_HWMON_MOD 0x00 +#define NCT6694_PWM_MOD 0x01 +#define NCT6694_I2C_MOD 0x03 +#define NCT6694_CANFD_MOD 0x05 +#define NCT6694_WDT_MOD 0x07 +#define NCT6694_RTC_MOD 0x08 +#define NCT6694_RPT_MOD 0xFF +#define NCT6694_GPIO_MOD NCT6694_RPT_MOD =20 enum nct6694_irq_id { NCT6694_IRQ_GPIO0 =3D 0, @@ -79,24 +81,33 @@ struct __packed nct6694_response_header { __le16 len; }; =20 -union __packed nct6694_usb_msg { - struct nct6694_cmd_header cmd_header; - struct nct6694_response_header response_header; -}; - struct nct6694 { struct device *dev; struct irq_domain *domain; - struct mutex access_lock; spinlock_t irq_lock; - struct urb *int_in_urb; - struct usb_device *udev; - union nct6694_usb_msg *usb_msg; - __le32 *int_buffer; unsigned int irq_enable; + + void *priv; + int (*read_msg)(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf); + int (*write_msg)(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf); }; =20 -int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_hea= der *cmd_hd, void *buf); -int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_he= ader *cmd_hd, void *buf); +static inline int nct6694_read_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) +{ + return nct6694->read_msg(nct6694, cmd_hd, buf); +} + +static inline int nct6694_write_msg(struct nct6694 *nct6694, + const struct nct6694_cmd_header *cmd_hd, + void *buf) +{ + return nct6694->write_msg(nct6694, cmd_hd, buf); +} =20 #endif --=20 2.34.1