{"id":2219261,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2219261/?format=json","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.0/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260402174349.3220518-7-o.rempel@pengutronix.de>","date":"2026-04-02T17:43:49","name":"[v11,6/6] mux: add NXP MC33978/MC34978 AMUX driver","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"b11b71d68bf0d305788df8b0c6c4ac9bd7a7a145","submitter":{"id":71360,"url":"http://patchwork.ozlabs.org/api/1.0/people/71360/?format=json","name":"Oleksij Rempel","email":"o.rempel@pengutronix.de"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260402174349.3220518-7-o.rempel@pengutronix.de/mbox/","series":[{"id":498521,"url":"http://patchwork.ozlabs.org/api/1.0/series/498521/?format=json","date":"2026-04-02T17:43:49","name":"mfd: Add support for NXP MC33978/MC34978 MSDI","version":11,"mbox":"http://patchwork.ozlabs.org/series/498521/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2219261/checks/","tags":{},"headers":{"Return-Path":"\n <linux-gpio+bounces-34608-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c09:e001:a7::12fc:5321; helo=sto.lore.kernel.org;\n envelope-from=linux-gpio+bounces-34608-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=185.203.201.7","smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=pengutronix.de","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=pengutronix.de"],"Received":["from sto.lore.kernel.org (sto.lore.kernel.org\n [IPv6:2600:3c09:e001:a7::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmq406Zf2z1yGH\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 03 Apr 2026 04:44:32 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sto.lore.kernel.org (Postfix) with ESMTP id AFBF9301D269\n\tfor <incoming@patchwork.ozlabs.org>; Thu,  2 Apr 2026 17:44:18 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 7F2C03F210C;\n\tThu,  2 Apr 2026 17:44:12 +0000 (UTC)","from metis.whiteo.stw.pengutronix.de\n (metis.whiteo.stw.pengutronix.de [185.203.201.7])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 655AE3C3430\n\tfor <linux-gpio@vger.kernel.org>; Thu,  2 Apr 2026 17:44:10 +0000 (UTC)","from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2])\n\tby metis.whiteo.stw.pengutronix.de with esmtps\n (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256)\n\t(Exim 4.92)\n\t(envelope-from <ore@pengutronix.de>)\n\tid 1w8M59-00053A-3n; Thu, 02 Apr 2026 19:43:51 +0200","from dude04.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::ac]\n helo=dude04)\n\tby drehscheibe.grey.stw.pengutronix.de with esmtps  (TLS1.3) tls\n TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n\t(Exim 4.96)\n\t(envelope-from <ore@pengutronix.de>)\n\tid 1w8M58-003PUw-1J;\n\tThu, 02 Apr 2026 19:43:50 +0200","from ore by dude04 with local (Exim 4.98.2)\n\t(envelope-from <ore@pengutronix.de>)\n\tid 1w8M58-0000000DVq0-1IRj;\n\tThu, 02 Apr 2026 19:43:50 +0200"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1775151852; cv=none;\n b=o2PSHSzNZpbq3d9IXPyETsWp3HQ8nvg2nmLpID5MHzb3bFoQhjIaCPK3h4mNQEeWdV1I3BUyfazmiojzCbyTTe0dIjUfdsLg6aHMS5egFjRFwKqNFBYWBaTa2AUcdD6vGXzTSYqCt4s4Ik+573XjuViHTv+Ve/R7MiA9gsQTClU=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1775151852; c=relaxed/simple;\n\tbh=p/0dhuzszQ1+qC+mwyCnDxRD2bS6x3CEdhzwJJAcqDQ=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=b4a46YBjl61/F5sbQnrUuZV30M1F90ovcb6ntg5Hk2TXQMTdeNsIN1O4blH5MNh5CTa2Hqm81inskV5HCGeDuvSJ4z9/zDaw2CAwT99Ucej4+6qpAijNCQjfOEnM1jm8GahxA67/45sRWyX4bXJcuOD2AGHZkIl1S9B85Sk+Axg=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=pengutronix.de;\n spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7","From":"Oleksij Rempel <o.rempel@pengutronix.de>","To":"Guenter Roeck <linux@roeck-us.net>,\n\tRob Herring <robh@kernel.org>,\n\tKrzysztof Kozlowski <krzk+dt@kernel.org>,\n\tConor Dooley <conor+dt@kernel.org>,\n\tLee Jones <lee@kernel.org>,\n\tPeter Rosin <peda@axentia.se>,\n\tLinus Walleij <linusw@kernel.org>","Cc":"Oleksij Rempel <o.rempel@pengutronix.de>,\n\tkernel@pengutronix.de,\n\tlinux-kernel@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-hwmon@vger.kernel.org,\n\tlinux-gpio@vger.kernel.org,\n\tDavid Jander <david@protonic.nl>","Subject":"[PATCH v11 6/6] mux: add NXP MC33978/MC34978 AMUX driver","Date":"Thu,  2 Apr 2026 19:43:49 +0200","Message-ID":"<20260402174349.3220518-7-o.rempel@pengutronix.de>","X-Mailer":"git-send-email 2.47.3","In-Reply-To":"<20260402174349.3220518-1-o.rempel@pengutronix.de>","References":"<20260402174349.3220518-1-o.rempel@pengutronix.de>","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-SA-Exim-Connect-IP":"2a0a:edc0:0:c01:1d::a2","X-SA-Exim-Mail-From":"ore@pengutronix.de","X-SA-Exim-Scanned":"No (on metis.whiteo.stw.pengutronix.de);\n SAEximRunCond expanded to false","X-PTX-Original-Recipient":"linux-gpio@vger.kernel.org"},"content":"Add a mux-control driver for the 24-to-1 analog multiplexer (AMUX)\nembedded in the NXP MC33978/MC34978 Multiple Switch Detection\nInterface (MSDI) devices.\n\nAssisted-by: Gemini:gemini-3.1-pro Sashiko\nSigned-off-by: Oleksij Rempel <o.rempel@pengutronix.de>\n---\nchanges v11:\n- no changes\nchanges v10:\n- no changes\nchanges v9:\n- rename mc33978-mux to mux-mc33978 in the Kconfig help\n- fail if fwnode is NULL\nchanges v8:\n- no changes\nchanges v7:\n- Simplify the return path and local variable assignment in\n  mc33978_mux_set().\n- Change idle_state to a signed integer to properly handle negative MUX\n  subsystem constants.\n- Default to MUX_IDLE_AS_IS when the \"idle-state\" device tree property\n  is missing.\n- Explicitly reject MUX_IDLE_DISCONNECT since the hardware does not\n  support disconnecting the multiplexer.\nchanges v6:\n- parse optional idle-state property\n- validate idle-state against available AMUX channels\n- lower-case probe error messages\nchanges v5:\n- no changes\nchanges v4:\n- no changes\nchanges v3:\n- no changes\nchanges v2:\n- Add missing <linux/err.h> include.\n- Add platform_device_id table\n---\n drivers/mux/Kconfig       |  14 ++++\n drivers/mux/Makefile      |   2 +\n drivers/mux/mc33978-mux.c | 141 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 157 insertions(+)\n create mode 100644 drivers/mux/mc33978-mux.c","diff":"diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig\nindex c68132e38138..ffe92a714096 100644\n--- a/drivers/mux/Kconfig\n+++ b/drivers/mux/Kconfig\n@@ -45,6 +45,20 @@ config MUX_GPIO\n \t  To compile the driver as a module, choose M here: the module will\n \t  be called mux-gpio.\n \n+config MUX_MC33978\n+\ttristate \"NXP MC33978/MC34978 Analog Multiplexer\"\n+\tdepends on MFD_MC33978\n+\thelp\n+\t  MC33978/MC34978 24-to-1 analog multiplexer (AMUX) driver.\n+\n+\t  This driver provides mux-control for the analog multiplexer,\n+\t  which can route switch voltages, temperature, and battery voltage\n+\t  to an external ADC. Typically used with IIO ADC drivers to measure\n+\t  analog values from the 22 switch inputs plus temperature and VBATP.\n+\n+\t  To compile the driver as a module, choose M here: the module will\n+\t  be called mux-mc33978.\n+\n config MUX_MMIO\n \ttristate \"MMIO/Regmap register bitfield-controlled Multiplexer\"\n \tdepends on OF\ndiff --git a/drivers/mux/Makefile b/drivers/mux/Makefile\nindex 6e9fa47daf56..339c44b4d4f4 100644\n--- a/drivers/mux/Makefile\n+++ b/drivers/mux/Makefile\n@@ -7,10 +7,12 @@ mux-core-objs\t\t\t:= core.o\n mux-adg792a-objs\t\t:= adg792a.o\n mux-adgs1408-objs\t\t:= adgs1408.o\n mux-gpio-objs\t\t\t:= gpio.o\n+mux-mc33978-objs\t\t:= mc33978-mux.o\n mux-mmio-objs\t\t\t:= mmio.o\n \n obj-$(CONFIG_MULTIPLEXER)\t+= mux-core.o\n obj-$(CONFIG_MUX_ADG792A)\t+= mux-adg792a.o\n obj-$(CONFIG_MUX_ADGS1408)\t+= mux-adgs1408.o\n obj-$(CONFIG_MUX_GPIO)\t\t+= mux-gpio.o\n+obj-$(CONFIG_MUX_MC33978)\t+= mux-mc33978.o\n obj-$(CONFIG_MUX_MMIO)\t\t+= mux-mmio.o\ndiff --git a/drivers/mux/mc33978-mux.c b/drivers/mux/mc33978-mux.c\nnew file mode 100644\nindex 000000000000..b44c862f0dbe\n--- /dev/null\n+++ b/drivers/mux/mc33978-mux.c\n@@ -0,0 +1,141 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+// Copyright (c) 2026 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>\n+/*\n+ * MC33978/MC34978 Analog Multiplexer (AMUX) Driver\n+ *\n+ * This driver provides mux-control for the 24-to-1 analog multiplexer.\n+ * The AMUX routes one of the following signals to the external AMUX pin:\n+ * - Channels 0-13: SG0-SG13 switch voltages\n+ * - Channels 14-21: SP0-SP7 switch voltages\n+ * - Channel 22: Internal temperature diode\n+ * - Channel 23: Battery voltage (VBATP)\n+ *\n+ * Consumer drivers (typically IIO ADC drivers) use the mux-control\n+ * subsystem to select which signal to measure.\n+ *\n+ * Architecture:\n+ * The MC33978 does not have an internal ADC. Instead, it routes analog\n+ * signals to an external AMUX pin that must be connected to an external\n+ * ADC (such as the SoC's internal ADC). The IIO subsystem is responsible\n+ * for coordinating the mux selection and ADC sampling.\n+ */\n+\n+#include <linux/device.h>\n+#include <linux/err.h>\n+#include <linux/mod_devicetable.h>\n+#include <linux/module.h>\n+#include <linux/mux/driver.h>\n+#include <linux/platform_device.h>\n+#include <linux/property.h>\n+#include <linux/regmap.h>\n+\n+#include <linux/mfd/mc33978.h>\n+\n+/* AMUX_CTRL register field definitions */\n+#define MC33978_AMUX_CTRL_MASK\tGENMASK(5, 0)\t/* 6-bit channel select */\n+\n+struct mc33978_mux_priv {\n+\tstruct device *dev;\n+\tstruct regmap *map;\n+};\n+\n+static int mc33978_mux_set(struct mux_control *mux, int state)\n+{\n+\tstruct mux_chip *mux_chip = mux->chip;\n+\tstruct mc33978_mux_priv *priv = mux_chip_priv(mux_chip);\n+\tint ret;\n+\n+\tif (state < 0 || state >= MC33978_NUM_AMUX_CH)\n+\t\treturn -EINVAL;\n+\n+\tret = regmap_update_bits(priv->map, MC33978_REG_AMUX_CTRL,\n+\t\t\t\t MC33978_AMUX_CTRL_MASK, state);\n+\tif (ret)\n+\t\tdev_err(priv->dev, \"failed to set AMUX channel %d: %d\\n\",\n+\t\t\tstate, ret);\n+\n+\treturn ret;\n+}\n+\n+static const struct mux_control_ops mc33978_mux_ops = {\n+\t.set = mc33978_mux_set,\n+};\n+\n+static int mc33978_mux_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct mc33978_mux_priv *priv;\n+\tstruct fwnode_handle *fwnode;\n+\tstruct mux_chip *mux_chip;\n+\tstruct mux_control *mux;\n+\ts32 idle_state;\n+\tint ret;\n+\n+\tmux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*priv));\n+\tif (IS_ERR(mux_chip))\n+\t\treturn dev_err_probe(dev, PTR_ERR(mux_chip), \"failed to allocate mux chip\\n\");\n+\n+\tfwnode = dev_fwnode(dev->parent);\n+\tif (!fwnode)\n+\t\treturn dev_err_probe(dev, -ENODEV, \"missing parent firmware node\\n\");\n+\n+\t/* Borrow the parent's firmware node so consumers can find this mux chip */\n+\tdevice_set_node(&mux_chip->dev, fwnode);\n+\n+\tpriv = mux_chip_priv(mux_chip);\n+\tpriv->dev = dev;\n+\n+\tpriv->map = dev_get_regmap(dev->parent, NULL);\n+\tif (!priv->map)\n+\t\treturn dev_err_probe(dev, -ENODEV, \"failed to get parent regmap\\n\");\n+\n+\tmux_chip->ops = &mc33978_mux_ops;\n+\n+\tmux = &mux_chip->mux[0];\n+\tmux->states = MC33978_NUM_AMUX_CH;\n+\n+\tret = device_property_read_u32(&mux_chip->dev, \"idle-state\",\n+\t\t\t\t       (u32 *)&idle_state);\n+\tif (ret < 0 && ret != -EINVAL) {\n+\t\treturn dev_err_probe(dev, ret, \"failed to parse idle-state\\n\");\n+\t} else if (ret == -EINVAL) {\n+\t\tmux->idle_state = MUX_IDLE_AS_IS;\n+\t} else {\n+\t\tif (idle_state == MUX_IDLE_DISCONNECT)\n+\t\t\treturn dev_err_probe(dev, -EINVAL,\n+\t\t\t\t\t     \"idle-disconnect not supported by hardware\\n\");\n+\t\tif (idle_state != MUX_IDLE_AS_IS &&\n+\t\t    (idle_state < 0 || idle_state >= MC33978_NUM_AMUX_CH))\n+\t\t\treturn dev_err_probe(dev, -EINVAL, \"invalid idle-state %d\\n\",\n+\t\t\t\t\t     idle_state);\n+\t\tmux->idle_state = idle_state;\n+\t}\n+\n+\tret = devm_mux_chip_register(dev, mux_chip);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed to register mux chip\\n\");\n+\n+\tplatform_set_drvdata(pdev, mux_chip);\n+\n+\treturn 0;\n+}\n+\n+static const struct platform_device_id mc33978_mux_id[] = {\n+\t{ \"mc33978-mux\", },\n+\t{ \"mc34978-mux\", },\n+\t{ }\n+};\n+MODULE_DEVICE_TABLE(platform, mc33978_mux_id);\n+\n+static struct platform_driver mc33978_mux_driver = {\n+\t.driver = {\n+\t\t.name = \"mc33978-mux\",\n+\t},\n+\t.probe = mc33978_mux_probe,\n+\t.id_table = mc33978_mux_id,\n+};\n+module_platform_driver(mc33978_mux_driver);\n+\n+MODULE_AUTHOR(\"Oleksij Rempel <kernel@pengutronix.de>\");\n+MODULE_DESCRIPTION(\"NXP MC33978/MC34978 Analog Multiplexer Driver\");\n+MODULE_LICENSE(\"GPL\");\n","prefixes":["v11","6/6"]}