RE: [PATCH net-next v3 0/4] net: phy: add X-Powers AC200/AC300 EPHY support
"Jagielski, Jedrzej" <[email protected]> Thu, 6 Aug 2026 09:18:31 +0000
| Newsgroups | dev.linux.lists.mfd,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <PH0PR11MB590277BD30A0D65438E4C5CBF0D22@PH0PR11MB5902.namprd11.prod.outlook.com> |
From: James Hilliard <[email protected]> Sent: Wednesday, August 5, 2026 4:27 AM >The X-Powers AC200 is a mixed-signal companion IC with a paged register >map accessed over I2C. > >Enable the package supplies and input clock, prevent the clock rate from >changing, and apply the vendor settling delays around common reset. >Initialize the paged regmap, report the chip and package revision, and >instantiate the Ethernet PHY control child when firmware describes it. > >Cache only the common page selector. Individual function resets can >invalidate other registers without regmap's knowledge, so all functional >registers remain volatile. > >The AC200 and its children cannot initiate DMA. Mark the parent as >DMA-incapable before adding the child. Register the common-reset action >before the MFD child so managed teardown removes the child before >resetting its parent, and also reset the chip during system shutdown. > >Signed-off-by: James Hilliard <[email protected]> >--- > drivers/mfd/Kconfig | 12 +++ > drivers/mfd/Makefile | 1 + > drivers/mfd/ac200.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 220 insertions(+) > >diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig >index 763ce6a34782..3360c9b86be8 100644 >--- a/drivers/mfd/Kconfig >+++ b/drivers/mfd/Kconfig >@@ -205,6 +205,18 @@ config MFD_AC100 > This driver include only the core APIs. You have to select individual > components like codecs or RTC under the corresponding menus. > >+config MFD_AC200 >+ tristate "X-Powers AC200" >+ depends on I2C >+ depends on OF >+ select MFD_CORE >+ select REGMAP_I2C >+ help >+ Support for the X-Powers AC200 mixed-signal companion IC. The AC200 >+ contains audio, video, RTC and Fast Ethernet PHY functions and is >+ co-packaged with some Allwinner H6 and H616 SoCs. This driver provides >+ the shared register access used by the individual function drivers. >+ > config MFD_AXP20X > tristate > select MFD_CORE >diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile >index dd4bb7e77c33..890e76a9ad00 100644 >--- a/drivers/mfd/Makefile >+++ b/drivers/mfd/Makefile >@@ -150,6 +150,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o > obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o > > obj-$(CONFIG_MFD_AC100) += ac100.o >+obj-$(CONFIG_MFD_AC200) += ac200.o > obj-$(CONFIG_MFD_AXP20X) += axp20x.o > obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o > obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o >diff --git a/drivers/mfd/ac200.c b/drivers/mfd/ac200.c >new file mode 100644 ... >+static void ac200_disable_action(void *data) >+{ >+ ac200_disable(data); >+} Hi James any particular reason why ac200_disable cannot be called direcrly? couldn't find anywhere extending this later in the series >+ >+static int ac200_probe(struct i2c_client *client) >+{ >+ struct device *dev = &client->dev; >+ struct device_node *ephy_node __free(device_node) = NULL; >+ struct ac200 *ac200; >+ struct clk *clk; >+ unsigned int version; >+ int ret; i believe it would be nice to stick to RCT especially for netdev targeted pacthes >+ >+ ac200 = devm_kzalloc(dev, sizeof(*ac200), GFP_KERNEL); >+ if (!ac200) >+ return -ENOMEM; >+ >+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ac200_supplies), >+ ac200_supplies); >+ if (ret) >+ return dev_err_probe(dev, ret, "failed to enable supplies\n"); >+ >+ clk = devm_clk_get_enabled(dev, NULL); >+ if (IS_ERR(clk)) >+ return dev_err_probe(dev, PTR_ERR(clk), >+ "failed to enable input clock\n"); >+ >+ ret = devm_clk_rate_exclusive_get(dev, clk); >+ if (ret) >+ return dev_err_probe(dev, ret, "failed to lock clock rate\n"); >+ >+ ac200->regmap = devm_regmap_init_i2c(client, &ac200_regmap_config); >+ if (IS_ERR(ac200->regmap)) >+ return dev_err_probe(dev, PTR_ERR(ac200->regmap), >+ "failed to initialize regmap\n"); >+ >+ i2c_set_clientdata(client, ac200); >+ >+ /* >+ * No minimum delay is documented. Match the vendor driver's 40 ms delay >+ * before its first AC200 register access after enabling the input clock. >+ */ >+ msleep(40); >+ >+ ret = regmap_read(ac200->regmap, AC200_SYS_VERSION_REG, &version); >+ if (ret) >+ return dev_err_probe(dev, ret, >+ "failed to read chip version\n"); >+ >+ dev_info(dev, "AC200 revision %#lx in package %lu\n", >+ FIELD_GET(AC200_SYS_VERSION_CHIP_MASK, version), >+ FIELD_GET(AC200_SYS_VERSION_PACKAGE_MASK, version)); >+ >+ /* Run after the MFD children have been removed. */ >+ ret = devm_add_action_or_reset(dev, ac200_disable_action, ac200); >+ if (ret) >+ return ret; >+ >+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL_REG, 0); >+ if (ret) >+ return ret; >+ >+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL_REG, >+ AC200_SYS_CONTROL_CHIP_RESET_DEASSERT); >+ if (ret) >+ return ret; >+ >+ /* Match the settling interval used by the vendor initialization. */ >+ usleep_range(1000, 2000); >+ >+ /* Neither the AC200 nor its child devices can perform DMA. */ >+ dev->coherent_dma_mask = 0; >+ dev->dma_mask = &dev->coherent_dma_mask; >+ ephy_node = of_get_compatible_child(dev->of_node, >+ "x-powers,ac200-ephy-ctl"); >+ if (!ephy_node) >+ return 0; >+ >+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ac200_cells, >+ ARRAY_SIZE(ac200_cells), NULL, 0, NULL); >+ if (ret) >+ return dev_err_probe(dev, ret, "failed to add MFD devices\n"); >+ >+ return 0; >+} >+ >+static void ac200_shutdown(struct i2c_client *client) >+{ >+ struct ac200 *ac200 = i2c_get_clientdata(client); >+ >+ ac200_disable(ac200); >+} >+ >+static const struct of_device_id ac200_of_match[] = { >+ { .compatible = "x-powers,ac200" }, >+ { } >+}; >+MODULE_DEVICE_TABLE(of, ac200_of_match); >+ >+static const struct i2c_device_id ac200_i2c_ids[] = { >+ { "ac200" }, >+ { } >+}; >+MODULE_DEVICE_TABLE(i2c, ac200_i2c_ids); >+ >+static struct i2c_driver ac200_driver = { >+ .driver = { >+ .name = "ac200", >+ .of_match_table = ac200_of_match, >+ }, >+ .probe = ac200_probe, >+ .shutdown = ac200_shutdown, >+ .id_table = ac200_i2c_ids, >+}; >+module_i2c_driver(ac200_driver); >+ >+MODULE_AUTHOR("James Hilliard <[email protected]>"); >+MODULE_DESCRIPTION("X-Powers AC200 MFD core driver"); >+MODULE_LICENSE("GPL"); > >-- >2.53.0