The RTL8231 is implemented as an MDIO device, and provides a regmap
interface for register access by the core and child devices.
The chip can also be a device on an SMI bus, an I2C-like bus by Realtek.
Since kernel support for SMI is limited, and no real-world SMI
implementations have been encountered for this device, this is currently
unimplemented. The use of the regmap interface should make any future
support relatively straightforward.
After a soft reset, all pins are muxed to GPIO inputs before the pin
drivers are enabled. This is done to prevent accidental system resets,
when a pin is connected to the main SoC's reset line.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
Changes since v8:
- Drop no longer needed __maybe_unused for PM functions
- No abbreviations in user messages
- Replace {0,RTL8231_REG_COUNT-1} with RTL8231_REG_{START,END}
- Replace led_start regmap_field with direct regmap operations
- Replace SIMPLE_DEV_PM_OPS with DEFINE_SIMPLE_DEV_PM_OPS
- Switch from REGCACHE_MAPLE to REGCACHE_FLAT_S
Changes since v6:
- Sort header includes
- Drop comment on cache type (6.19 will support REGCACHE_FLAT_S)
- Limit scope of LED_START field definition to init
- Variable renames:
- map -> regmap
- val -> status (register value) and ready_code (field value)
- val -> cfg
- Invert logic for !started, reducing code indentation
- Place __maybe_unused after function return type
- Use regmap_field_write() for LED_START field (volatile register)
- Use regcache_drop_region() to invalidate cache, replacing
regcache_mark_dirty() which invalidates the device state
---
drivers/mfd/Kconfig | 9 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/rtl8231.c | 188 ++++++++++++++++++++++++++++++++++++
include/linux/mfd/rtl8231.h | 73 ++++++++++++++
4 files changed, 271 insertions(+)
create mode 100644 drivers/mfd/rtl8231.c
create mode 100644 include/linux/mfd/rtl8231.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aace5766b38a..db448069ad00 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1317,6 +1317,15 @@ config MFD_RDC321X
southbridge which provides access to GPIOs and Watchdog using the
southbridge PCI device configuration space.
+config MFD_RTL8231
+ tristate "Realtek RTL8231 GPIO and LED expander"
+ select MFD_CORE
+ select REGMAP_MDIO
+ help
+ Support for the Realtek RTL8231 GPIO and LED expander.
+ Provides up to 37 GPIOs, 88 LEDs, and one PWM output.
+ When built as a module, this module will be named rtl8231.
+
config MFD_RT4831
tristate "Richtek RT4831 four channel WLED and Display Bias Voltage"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..e486b69d0324 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -253,6 +253,7 @@ obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
+obj-$(CONFIG_MFD_RTL8231) += rtl8231.o
obj-$(CONFIG_MFD_RT4831) += rt4831.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_RT5120) += rt5120.o
diff --git a/drivers/mfd/rtl8231.c b/drivers/mfd/rtl8231.c
new file mode 100644
index 000000000000..60b3619a526c
--- /dev/null
+++ b/drivers/mfd/rtl8231.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mdio.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/rtl8231.h>
+
+static bool rtl8231_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ /*
+ * Registers with self-clearing bits, strapping pin values.
+ * Don't mark the data registers as volatile, since we need
+ * caching for the output values.
+ */
+ case RTL8231_REG_FUNC0:
+ case RTL8231_REG_FUNC1:
+ case RTL8231_REG_PIN_HI_CFG:
+ case RTL8231_REG_LED_END:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct mfd_cell rtl8231_cells[] = {
+ {
+ .name = "rtl8231-pinctrl",
+ },
+ {
+ .name = "rtl8231-leds",
+ .of_compatible = "realtek,rtl8231-leds",
+ },
+};
+
+static int rtl8231_soft_reset(struct regmap *regmap)
+{
+ const unsigned int all_pins_mask = GENMASK(RTL8231_BITS_VAL - 1, 0);
+ unsigned int cfg;
+ int err;
+
+ /* SOFT_RESET bit self-clears when done */
+ regmap_write_bits(regmap, RTL8231_REG_PIN_HI_CFG,
+ RTL8231_PIN_HI_CFG_SOFT_RESET, RTL8231_PIN_HI_CFG_SOFT_RESET);
+
+ err = regmap_read_poll_timeout(regmap, RTL8231_REG_PIN_HI_CFG, cfg,
+ !(cfg & RTL8231_PIN_HI_CFG_SOFT_RESET), 50, 1000);
+ if (err)
+ return err;
+
+ regcache_drop_region(regmap, RTL8231_REG_START, RTL8231_REG_END);
+
+ /*
+ * Chip reset results in a pin configuration that is a mix of LED and GPIO outputs.
+ * Select GPI functionality for all pins before enabling pin outputs.
+ */
+ regmap_write(regmap, RTL8231_REG_PIN_MODE0, all_pins_mask);
+ regmap_write(regmap, RTL8231_REG_GPIO_DIR0, all_pins_mask);
+ regmap_write(regmap, RTL8231_REG_PIN_MODE1, all_pins_mask);
+ regmap_write(regmap, RTL8231_REG_GPIO_DIR1, all_pins_mask);
+ regmap_write(regmap, RTL8231_REG_PIN_HI_CFG,
+ RTL8231_PIN_HI_CFG_MODE_MASK | RTL8231_PIN_HI_CFG_DIR_MASK);
+
+ return 0;
+}
+
+static int rtl8231_init(struct device *dev)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ unsigned int ready_code;
+ unsigned int func0;
+ unsigned int func1;
+ int err;
+
+ err = regmap_read(regmap, RTL8231_REG_FUNC1, &func1);
+ if (err) {
+ dev_err(dev, "failed to read READY_CODE\n");
+ return err;
+ }
+
+ ready_code = FIELD_GET(RTL8231_FUNC1_READY_CODE_MASK, func1);
+ if (ready_code != RTL8231_FUNC1_READY_CODE_VALUE) {
+ dev_err(dev, "RTL8231 not present or ready 0x%x != 0x%x\n",
+ ready_code, RTL8231_FUNC1_READY_CODE_VALUE);
+ return -ENODEV;
+ }
+
+ err = regmap_read(regmap, RTL8231_REG_FUNC0, &func0);
+ if (err)
+ return err;
+
+ if (func0 & RTL8231_FUNC0_LED_START)
+ return 0;
+
+ err = rtl8231_soft_reset(regmap);
+ if (err)
+ return err;
+
+ /* LED_START enables power to output pins, and starts the LED engine */
+ return regmap_write_bits(regmap, RTL8231_REG_FUNC0, RTL8231_FUNC0_LED_START,
+ RTL8231_FUNC0_LED_START);
+}
+
+static const struct regmap_config rtl8231_mdio_regmap_config = {
+ .val_bits = RTL8231_BITS_VAL,
+ .reg_bits = RTL8231_BITS_REG,
+ .volatile_reg = rtl8231_volatile_reg,
+ .max_register = RTL8231_REG_END,
+ .use_single_read = true,
+ .use_single_write = true,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_FLAT_S,
+};
+
+static int rtl8231_mdio_probe(struct mdio_device *mdiodev)
+{
+ struct device *dev = &mdiodev->dev;
+ struct regmap *regmap;
+ int err;
+
+ regmap = devm_regmap_init_mdio(mdiodev, &rtl8231_mdio_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "failed to initialize regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ dev_set_drvdata(dev, regmap);
+
+ mdiodev->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(mdiodev->reset_gpio))
+ return PTR_ERR(mdiodev->reset_gpio);
+
+ device_property_read_u32(dev, "reset-assert-delay", &mdiodev->reset_assert_delay);
+ device_property_read_u32(dev, "reset-deassert-delay", &mdiodev->reset_deassert_delay);
+
+ err = rtl8231_init(dev);
+ if (err)
+ return err;
+
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, rtl8231_cells,
+ ARRAY_SIZE(rtl8231_cells), NULL, 0, NULL);
+}
+
+static int rtl8231_suspend(struct device *dev)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+
+ return regmap_write_bits(regmap, RTL8231_REG_FUNC0, RTL8231_FUNC0_LED_START, 0);
+}
+
+static int rtl8231_resume(struct device *dev)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+
+ return regmap_write_bits(regmap, RTL8231_REG_FUNC0, RTL8231_FUNC0_LED_START,
+ RTL8231_FUNC0_LED_START);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rtl8231_pm_ops, rtl8231_suspend, rtl8231_resume);
+
+static const struct of_device_id rtl8231_of_match[] = {
+ { .compatible = "realtek,rtl8231" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rtl8231_of_match);
+
+static struct mdio_driver rtl8231_mdio_driver = {
+ .mdiodrv.driver = {
+ .name = "rtl8231-expander",
+ .of_match_table = rtl8231_of_match,
+ .pm = pm_ptr(&rtl8231_pm_ops),
+ },
+ .probe = rtl8231_mdio_probe,
+};
+mdio_module_driver(rtl8231_mdio_driver);
+
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Realtek RTL8231 GPIO and LED expander");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/rtl8231.h b/include/linux/mfd/rtl8231.h
new file mode 100644
index 000000000000..13edd987afef
--- /dev/null
+++ b/include/linux/mfd/rtl8231.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Register definitions the RTL8231 GPIO and LED expander chip
+ */
+
+#ifndef __LINUX_MFD_RTL8231_H
+#define __LINUX_MFD_RTL8231_H
+
+#include <linux/bits.h>
+
+/*
+ * Registers addresses are 5 bit, values are 16 bit
+ * Also define a duplicated range of virtual addresses, to enable
+ * different read/write behaviour on the GPIO data registers
+ */
+#define RTL8231_BITS_VAL 16
+#define RTL8231_BITS_REG 5
+
+/* Chip control */
+#define RTL8231_REG_FUNC0 0x00
+#define RTL8231_FUNC0_SCAN_MODE BIT(0)
+#define RTL8231_FUNC0_SCAN_SINGLE 0
+#define RTL8231_FUNC0_SCAN_BICOLOR BIT(0)
+#define RTL8231_FUNC0_LED_START BIT(1)
+
+#define RTL8231_REG_FUNC1 0x01
+#define RTL8231_FUNC1_READY_CODE_VALUE 0x37
+#define RTL8231_FUNC1_READY_CODE_MASK GENMASK(9, 4)
+#define RTL8231_FUNC1_DEBOUNCE_MASK GENMASK(15, 10)
+
+/* Pin control */
+#define RTL8231_REG_PIN_MODE0 0x02
+#define RTL8231_REG_PIN_MODE1 0x03
+
+#define RTL8231_PIN_MODE_LED 0
+#define RTL8231_PIN_MODE_GPIO 1
+
+/* Pin high config: pin and GPIO control for pins 32-26 */
+#define RTL8231_REG_PIN_HI_CFG 0x04
+#define RTL8231_PIN_HI_CFG_MODE_MASK GENMASK(4, 0)
+#define RTL8231_PIN_HI_CFG_DIR_MASK GENMASK(9, 5)
+#define RTL8231_PIN_HI_CFG_INV_MASK GENMASK(14, 10)
+#define RTL8231_PIN_HI_CFG_SOFT_RESET BIT(15)
+
+/* GPIO control registers */
+#define RTL8231_REG_GPIO_DIR0 0x05
+#define RTL8231_REG_GPIO_DIR1 0x06
+#define RTL8231_REG_GPIO_INVERT0 0x07
+#define RTL8231_REG_GPIO_INVERT1 0x08
+
+#define RTL8231_GPIO_DIR_IN 1
+#define RTL8231_GPIO_DIR_OUT 0
+
+/*
+ * GPIO data registers
+ * Only the output data can be written to these registers, and only the input
+ * data can be read.
+ */
+#define RTL8231_REG_GPIO_DATA0 0x1c
+#define RTL8231_REG_GPIO_DATA1 0x1d
+#define RTL8231_REG_GPIO_DATA2 0x1e
+#define RTL8231_PIN_HI_DATA_MASK GENMASK(4, 0)
+
+/* LED control base registers */
+#define RTL8231_REG_LED0_BASE 0x09
+#define RTL8231_REG_LED1_BASE 0x10
+#define RTL8231_REG_LED2_BASE 0x17
+#define RTL8231_REG_LED_END 0x1b
+
+#define RTL8231_REG_START 0x00
+#define RTL8231_REG_END 0x1e
+
+#endif /* __LINUX_MFD_RTL8231_H */
--
2.52.0
Hi Sander,
kernel test robot noticed the following build warnings:
[auto build test WARNING on lee-mfd/for-mfd-fixes]
[also build test WARNING on lee-leds/for-leds-next linusw-pinctrl/devel linusw-pinctrl/for-next linus/master v6.19-rc2 next-20251219]
[cannot apply to lee-mfd/for-mfd-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Sander-Vanheule/dt-bindings-leds-Binding-for-RTL8231-scan-matrix/20251216-015552
base: https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-fixes
patch link: https://lore.kernel.org/r/20251215175115.135294-4-sander%40svanheule.net
patch subject: [PATCH v9 3/6] mfd: Add RTL8231 core device
config: alpha-kismet-CONFIG_MDIO_BUS-CONFIG_REGMAP_MDIO-0-0 (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512220956.FVakrdhV-lkp@intel.com/
kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for MDIO_BUS when selected by REGMAP_MDIO
WARNING: unmet direct dependencies detected for MDIO_BUS
Depends on [n]: NETDEVICES [=n]
Selected by [y]:
- REGMAP_MDIO [=y]
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Adding the netdev and regmap maintainers for extra input.
On Mon, 2025-12-22 at 09:43 +0100, kernel test robot wrote:
> url: https://github.com/intel-lab-lkp/linux/commits/Sander-Vanheule/dt-bindings-leds-Binding-for-RTL8231-scan-matrix/20251216-015552
> base: https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-fixes
> patch link: https://lore.kernel.org/r/20251215175115.135294-4-sander%40svanheule.net
> patch subject: [PATCH v9 3/6] mfd: Add RTL8231 core device
> config: alpha-kismet-CONFIG_MDIO_BUS-CONFIG_REGMAP_MDIO-0-0 (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/config)
> reproduce: (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/reproduce)
>
For context: these patches introduce a new MFD with pinctrl and led subdevices.
The RTL8231 MFD is attached to an MDIO bus, but it can also be attached to an
I2C bus (not currently supported). The drivers use regmap to provide a bus
abstraction.
> kismet warnings: (new ones prefixed by >>)
> > > kismet: WARNING: unmet direct dependencies detected for MDIO_BUS when
> > > selected by REGMAP_MDIO
> WARNING: unmet direct dependencies detected for MDIO_BUS
> Depends on [n]: NETDEVICES [=n]
> Selected by [y]:
> - REGMAP_MDIO [=y]
I'm a bit puzzled on how to solve this one. The issue detected here is that my
driver (MFD_RTL8231) selects REGMAP_MDIO, which in turn selects MDIO_BUS. The
latter is dependent on NETDEVICES, which is not selected in this test.
The kernel does not yet have any other consumers of REGMAP_MDIO, which is
probably the reason the dependency issue has gone undetected until now.
REGMAP_MDIO is not a visible symbol, so it must be selected by drivers.
Other REGMAP_XYZ symbols (almost) exclusively use "depends on XYZ", but if I
change REGMAP_MDIO to "depends on", the warning just changes to:
WARNING: unmet direct dependencies detected for REGMAP_MDIO
Depends on [n]: MDIO_BUS [=n]
Selected by [y]:
- MFD_RTL8231 [=y] && HAS_IOMEM [=y]
Trying to make MFD_RTL8231 also depend on MDIO_BUS, like .e.g I2C dependent
devices do, results in a recursive dependency:
error: recursive dependency detected!
symbol GPIOLIB is selected by PINCTRL_RTL8231
symbol PINCTRL_RTL8231 depends on MFD_RTL8231
symbol MFD_RTL8231 depends on MDIO_BUS
symbol MDIO_BUS is selected by PHYLIB
symbol PHYLIB is selected by ARC_EMAC_CORE
symbol ARC_EMAC_CORE is selected by EMAC_ROCKCHIP
symbol EMAC_ROCKCHIP depends on OF_IRQ
symbol OF_IRQ depends on IRQ_DOMAIN
symbol IRQ_DOMAIN is selected by GENERIC_IRQ_CHIP
symbol GENERIC_IRQ_CHIP is selected by GPIO_MVEBU
symbol GPIO_MVEBU depends on GPIOLIB
The 'quick fix' appears to be to add "select NETDEVICES" to REGMAP_MDIO. The
platforms that use the RTL8231 MFD are typically ethernet switches, so they
would have NETDEVICES enabled anway, but that feels very heavy handed and
automatically pulls in a lot of extra stuff. Would this be acceptable or is
there a more desirable approach I'm not seeing here?
Best,
Sander
On 26/12/2025 12:59, Sander Vanheule wrote: > Adding the netdev and regmap maintainers for extra input. > > On Mon, 2025-12-22 at 09:43 +0100, kernel test robot wrote: >> url: https://github.com/intel-lab-lkp/linux/commits/Sander-Vanheule/dt-bindings-leds-Binding-for-RTL8231-scan-matrix/20251216-015552 >> base: https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-fixes >> patch link: https://lore.kernel.org/r/20251215175115.135294-4-sander%40svanheule.net >> patch subject: [PATCH v9 3/6] mfd: Add RTL8231 core device >> config: alpha-kismet-CONFIG_MDIO_BUS-CONFIG_REGMAP_MDIO-0-0 (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/config) >> reproduce: (https://download.01.org/0day-ci/archive/20251222/202512220956.FVakrdhV-lkp@intel.com/reproduce) >> > > For context: these patches introduce a new MFD with pinctrl and led subdevices. > The RTL8231 MFD is attached to an MDIO bus, but it can also be attached to an > I2C bus (not currently supported). The drivers use regmap to provide a bus > abstraction. > >> kismet warnings: (new ones prefixed by >>) >>>> kismet: WARNING: unmet direct dependencies detected for MDIO_BUS when >>>> selected by REGMAP_MDIO >> WARNING: unmet direct dependencies detected for MDIO_BUS >> Depends on [n]: NETDEVICES [=n] >> Selected by [y]: >> - REGMAP_MDIO [=y] > > I'm a bit puzzled on how to solve this one. The issue detected here is that my > driver (MFD_RTL8231) selects REGMAP_MDIO, which in turn selects MDIO_BUS. The > latter is dependent on NETDEVICES, which is not selected in this test. > The kernel does not yet have any other consumers of REGMAP_MDIO, which is > probably the reason the dependency issue has gone undetected until now. > > REGMAP_MDIO is not a visible symbol, so it must be selected by drivers. Reminds me old problem, probably the same: https://lore.kernel.org/all/20250515140555.325601-2-krzysztof.kozlowski@linaro.org/ https://lore.kernel.org/all/20250516141722.13772-1-afd@ti.com/ Exactly the same MDIO here and there. > > Other REGMAP_XYZ symbols (almost) exclusively use "depends on XYZ", but if I > change REGMAP_MDIO to "depends on", the warning just changes to: > > WARNING: unmet direct dependencies detected for REGMAP_MDIO > Depends on [n]: MDIO_BUS [=n] > Selected by [y]: > - MFD_RTL8231 [=y] && HAS_IOMEM [=y] > > Trying to make MFD_RTL8231 also depend on MDIO_BUS, like .e.g I2C dependent > devices do, results in a recursive dependency: > > > error: recursive dependency detected! > symbol GPIOLIB is selected by PINCTRL_RTL8231 > symbol PINCTRL_RTL8231 depends on MFD_RTL8231 > symbol MFD_RTL8231 depends on MDIO_BUS > symbol MDIO_BUS is selected by PHYLIB > symbol PHYLIB is selected by ARC_EMAC_CORE > symbol ARC_EMAC_CORE is selected by EMAC_ROCKCHIP > symbol EMAC_ROCKCHIP depends on OF_IRQ > symbol OF_IRQ depends on IRQ_DOMAIN > symbol IRQ_DOMAIN is selected by GENERIC_IRQ_CHIP > symbol GENERIC_IRQ_CHIP is selected by GPIO_MVEBU > symbol GPIO_MVEBU depends on GPIOLIB > > The 'quick fix' appears to be to add "select NETDEVICES" to REGMAP_MDIO. The > platforms that use the RTL8231 MFD are typically ethernet switches, so they > would have NETDEVICES enabled anway, but that feels very heavy handed and > automatically pulls in a lot of extra stuff. Would this be acceptable or is > there a more desirable approach I'm not seeing here? Rather fix the same way Andrew did it. Or maybe his patch was not merged? Best regards, Krzysztof
Hi Krzysztof, On Fri, 2025-12-26 at 13:19 +0100, Krzysztof Kozlowski wrote: > On 26/12/2025 12:59, Sander Vanheule wrote: > > > kismet warnings: (new ones prefixed by >>) > > > > > kismet: WARNING: unmet direct dependencies detected for MDIO_BUS when > > > > > selected by REGMAP_MDIO > > > WARNING: unmet direct dependencies detected for MDIO_BUS > > > Depends on [n]: NETDEVICES [=n] > > > Selected by [y]: > > > - REGMAP_MDIO [=y] > > > > I'm a bit puzzled on how to solve this one. The issue detected here is that > > my > > driver (MFD_RTL8231) selects REGMAP_MDIO, which in turn selects MDIO_BUS. > > The > > latter is dependent on NETDEVICES, which is not selected in this test. > > The kernel does not yet have any other consumers of REGMAP_MDIO, which is > > probably the reason the dependency issue has gone undetected until now. > > > > REGMAP_MDIO is not a visible symbol, so it must be selected by drivers. > > Reminds me old problem, probably the same: > > https://lore.kernel.org/all/20250515140555.325601-2-krzysztof.kozlowski@linaro.org/ > > https://lore.kernel.org/all/20250516141722.13772-1-afd@ti.com/ > > Exactly the same MDIO here and there. > > [...] > Rather fix the same way Andrew did it. Or maybe his patch was not merged? Andrew's patch was merged, that's the code I'm seeing now. I think by placing the dependency under REGMAP_MDIO (or REGMAP_IRQ) instead of REGMAP, it just made the circular dependency less visible. Making PINCTRL_RTL8231 "depends on GPIOLIB", like the GPIO drivers, only shortens the circular dependency loop: error: recursive dependency detected! symbol IRQ_DOMAIN is selected by MFD_CORE symbol MFD_CORE is selected by MFD_RTL8231 symbol MFD_RTL8231 depends on MDIO_BUS symbol MDIO_BUS is selected by PHYLIB symbol PHYLIB is selected by ARC_EMAC_CORE symbol ARC_EMAC_CORE is selected by EMAC_ROCKCHIP symbol EMAC_ROCKCHIP depends on OF_IRQ symbol OF_IRQ depends on IRQ_DOMAIN Of these symbols, IRQ_DOMAIN and OF_IRQ are hidden symbols, so they must be selected by another symbol to be used. As shown above, OF_IRQ *depends* on IRQ_DOMAIN, which means some other symbol *must* select it for the dependency to be satisfied, as IRQ_DOMAIN also cannot be selected directly by the user. OF_IRQ also appears to be the only symbol in the kernel to depend on, rather than select, IRQ_DOMAIN. Turning the dependency of OF_IRQ on IRQ_DOMAIN around resolves the dependency loop here, and ensures the hidden IRQ_DOMAIN symbol is selected whenever any other symbol selects OF_IRQ. The same reasoning was actually used in 2023 to suggest this change as well: https://lore.kernel.org/lkml/20230213041535.12083-3-rdunlap@infradead.org/ I found some follow-up, but it didn't look like it actually got wrapped up: https://lore.kernel.org/lkml/20230313023935.31037-1-rdunlap@infradead.org/ Randy, do you happen to recall if/why this stalled? Should we just try to invert the dependency again if there is no pressing need for the "proper" clean-up? Best, Sander
© 2016 - 2026 Red Hat, Inc.