RE: [PATCH net-next v2 8/8] net: phy: add X-Powers AC200/AC300 EPHY driver

"Jagielski, Jedrzej" <[email protected]>
Newsgroups org.kernel.vger.netdev,dev.linux.lists.mfd,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-rockchip,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Message-ID <PH0PR11MB5902F56C72ED0C31020B277CF0D22@PH0PR11MB5902.namprd11.prod.outlook.com>
From: James Hilliard <[email protected]> 
Sent: Wednesday, August 5, 2026 4:27 AM

>The AC200 and AC300 MDIO link endpoints report the same Clause 22
>identifier and use a compatible link-side paged register layout. Their
>identification registers are inaccessible until a package-specific
>control path powers and configures the block.
>
>Add a common PHY driver which matches the firmware-provided identifier
>only when the node also references one X-Powers control device. Validate
>that reference and the AC300 address relationship, defer until the
>provider is bound, and create a managed device link to protect its
>lifetime and order teardown and power management.
>
>When the optional two-bit SID configuration field is present, verify that
>its package-selector bit agrees with the fixed control reference. Use its
>second bit to select the AC300 low-calibration tuning sequence. Omitting
>the field skips package validation and selects the normal sequence.
>
>Power the control block in reset-default MII mode during PHY probe. Once
>the MAC supplies phydev->interface, pass MII or RMII to the provider
>before the normal PHY soft reset. Program the AC200 link address through
>its provider and let the AC300 provider validate its strapped address.
>
>Apply the common vendor analog initialization, with the package-specific
>normal value and the optional AC300 low-calibration sequence. Support the
>board-selected xMII receive-clock inversion and leave MDI/MDI-X in its
>vendor automatic mode. Disable standard and Intelligent EEE initially,
>then restore phylib's standard EEE policy after later resets.
>
>Power the package control block down with the PHY and restore the vendor
>configuration on resume. If power-off fails, attempt to restore the PHY
>before returning the original suspend error.
>
>Signed-off-by: James Hilliard <[email protected]>
>---
> drivers/net/phy/Kconfig         |   9 +
> drivers/net/phy/Makefile        |   1 +
> drivers/net/phy/xpowers-acx00.c | 544 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 554 insertions(+)
>

...

>+static struct device *
>+acx00_ephy_find_supplier(struct device_node *control, bool is_ac300)
>+{
>+	struct platform_device *pdev;
>+	struct mdio_device *mdiodev;
>+
>+	if (is_ac300) {

two approaches are mixed now - specific callbacks and ac200/300 checks,
why not to fully stick to callbacks


>+		mdiodev = of_mdio_find_device(control);
>+		return mdiodev ? &mdiodev->dev : NULL;
>+	}
>+
>+	pdev = of_find_device_by_node(control);
>+	return pdev ? &pdev->dev : NULL;
>+}
>+
>+static int acx00_ephy_get_control(struct phy_device *phydev,
>+				  struct acx00_ephy_priv *priv)
>+{
>+	struct device *dev = &phydev->mdio.dev;
>+	struct acx00_ephy_control *control;
>+	struct device_node *control_node;
>+	struct device *supplier;
>+	struct device_link *link;
>+	const char *compatible;
>+	const char *property;
>+	bool has_ac200;
>+	bool has_ac300;
>+	u32 control_addr;
>+	u32 configuration = 0;
>+	int ret;
>+
>+	has_ac200 = of_property_present(dev->of_node,
>+					"x-powers,ac200-control");
>+	has_ac300 = of_property_present(dev->of_node,
>+					"x-powers,ac300-control");
>+	if (has_ac200 == has_ac300)
>+		return dev_err_probe(dev, -EINVAL,
>+				     "exactly one ACx00 control is required\n");
>+
>+	priv->is_ac300 = has_ac300;

wouldn't enum be a better choice here? easier extending for future
possible ac400,500 etc 
dunno whether planned just thinking

>+	property = has_ac300 ? "x-powers,ac300-control" :
>+			       "x-powers,ac200-control";
>+	compatible = has_ac300 ? "x-powers,ac300-ephy-ctl" :
>+				 "x-powers,ac200-ephy-ctl";
>+	control_node = of_parse_phandle(dev->of_node, property, 0);
>+	if (!control_node)
>+		return dev_err_probe(dev, -EINVAL, "missing %s\n", property);
>+	if (!of_device_is_compatible(control_node, compatible)) {
>+		ret = dev_err_probe(dev, -EINVAL,
>+				    "%s does not reference a %s device\n",
>+				    property, compatible);
>+		goto out_put_node;
>+	}
>+	if (!of_device_is_available(control_node)) {
>+		ret = dev_err_probe(dev, -EINVAL,
>+				    "%s references a disabled device\n",
>+				    property);
>+		goto out_put_node;
>+	}
>+
>+	if (has_ac300) {
>+		ret = of_property_read_u32(control_node, "reg", &control_addr);
>+		if (ret || control_addr != phydev->mdio.addr +
>+					       AC300_EPHY_CONTROL_ADDR_OFFSET) {
>+			ret = dev_err_probe(dev, -EINVAL,
>+					    "AC300 control address does not match reg\n");
>+			goto out_put_node;
>+		}
>+	}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.