162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ACPI helpers for the MDIO (Ethernet PHY) API 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file provides helper functions for extracting PHY device information 662306a36Sopenharmony_ci * out of the ACPI ASL and using it to populate an mii_bus. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/acpi.h> 1062306a36Sopenharmony_ci#include <linux/acpi_mdio.h> 1162306a36Sopenharmony_ci#include <linux/bits.h> 1262306a36Sopenharmony_ci#include <linux/dev_printk.h> 1362306a36Sopenharmony_ci#include <linux/fwnode_mdio.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciMODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>"); 1862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/** 2162306a36Sopenharmony_ci * __acpi_mdiobus_register - Register mii_bus and create PHYs from the ACPI ASL. 2262306a36Sopenharmony_ci * @mdio: pointer to mii_bus structure 2362306a36Sopenharmony_ci * @fwnode: pointer to fwnode of MDIO bus. This fwnode is expected to represent 2462306a36Sopenharmony_ci * @owner: module owning this @mdio object. 2562306a36Sopenharmony_ci * an ACPI device object corresponding to the MDIO bus and its children are 2662306a36Sopenharmony_ci * expected to correspond to the PHY devices on that bus. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * This function registers the mii_bus structure and registers a phy_device 2962306a36Sopenharmony_ci * for each child node of @fwnode. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ciint __acpi_mdiobus_register(struct mii_bus *mdio, struct fwnode_handle *fwnode, 3262306a36Sopenharmony_ci struct module *owner) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct fwnode_handle *child; 3562306a36Sopenharmony_ci u32 addr; 3662306a36Sopenharmony_ci int ret; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* Mask out all PHYs from auto probing. */ 3962306a36Sopenharmony_ci mdio->phy_mask = GENMASK(31, 0); 4062306a36Sopenharmony_ci ret = __mdiobus_register(mdio, owner); 4162306a36Sopenharmony_ci if (ret) 4262306a36Sopenharmony_ci return ret; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci ACPI_COMPANION_SET(&mdio->dev, to_acpi_device_node(fwnode)); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Loop over the child nodes and register a phy_device for each PHY */ 4762306a36Sopenharmony_ci fwnode_for_each_child_node(fwnode, child) { 4862306a36Sopenharmony_ci ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &addr); 4962306a36Sopenharmony_ci if (ret || addr >= PHY_MAX_ADDR) 5062306a36Sopenharmony_ci continue; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ret = fwnode_mdiobus_register_phy(mdio, child, addr); 5362306a36Sopenharmony_ci if (ret == -ENODEV) 5462306a36Sopenharmony_ci dev_err(&mdio->dev, 5562306a36Sopenharmony_ci "MDIO device at address %d is missing.\n", 5662306a36Sopenharmony_ci addr); 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ciEXPORT_SYMBOL(__acpi_mdiobus_register); 61