From mboxrd@z Thu Jan 1 00:00:00 1970 From: Wang Dongsheng Subject: [PATCH v3 2/2] net: qcom/emac: add phy-handle support for ACPI Date: Thu, 25 Oct 2018 18:09:15 +0800 Message-ID: <7935985e49270ad2948b2a52d26510bdf55572e6.1540459999.git.dongsheng.wang@hxt-semitech.com> References: <78719753-77bd-596a-dfc7-ccd676850283@kernel.org> Mime-Version: 1.0 Content-Type: text/plain Cc: Wang Dongsheng , , , To: , Return-path: Received: from mx01.hxt-semitech.com ([223.203.96.7]:55436 "EHLO barracuda.hxt-semitech.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726803AbeJYSl4 (ORCPT ); Thu, 25 Oct 2018 14:41:56 -0400 In-Reply-To: Sender: netdev-owner@vger.kernel.org List-ID: Use "phy-handle" to porint an internal MDIO device port. Signed-off-by: Wang Dongsheng --- drivers/net/ethernet/qualcomm/emac/emac-phy.c | 115 +++++++++++++++--- 1 file changed, 100 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.c b/drivers/net/ethernet/qualcomm/emac/emac-phy.c index f2ed013ce5d5..3dc3ae55e5bb 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-phy.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.c @@ -96,6 +96,96 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) return 0; } +static int acpi_device_match(struct device *dev, void *fwnode) +{ + return dev->fwnode == fwnode; +} + +static struct phy_device * +emac_acpi_get_phydev_from_phy_handle(struct platform_device *pdev) +{ + struct fwnode_reference_args args; + struct fwnode_handle *fw_node; + struct acpi_device *adev; + acpi_handle handle; + struct device *dev; + struct phy_device *phydev; + struct net_device *netdev; + struct emac_adapter *adpt; + int phy_addr; + int ret; + + /* Get PHY Port reference from phy-handle */ + fw_node = acpi_fwnode_handle(ACPI_COMPANION(&pdev->dev)); + ret = acpi_node_get_property_reference(fw_node, "phy-handle", 0, + &args); + if (ACPI_FAILURE(ret) || !is_acpi_device_node(args.fwnode)) + return ERR_PTR(-ENODEV); + + /* Get PHY addr from the port node */ + if (fwnode_property_read_u32(args.fwnode, "phy-channel", &phy_addr)) + return ERR_PTR(-ENODEV); + + /* Get the MDIO bus that included the port */ + handle = ACPI_HANDLE_FWNODE(args.fwnode); + if (!handle || acpi_bus_get_device(handle, &adev)) + return ERR_PTR(-ENODEV); + + while (adev->parent) { + if (!strcmp(acpi_device_hid(adev), "QCOM8070")) + break; + adev = adev->parent; + } + if (!adev->parent) + return ERR_PTR(-ENODEV); + + dev = bus_find_device(&platform_bus_type, NULL, + &adev->fwnode, + acpi_device_match); + if (!dev) + return ERR_PTR(-ENODEV); + + netdev = dev_get_drvdata(dev); + if (!netdev) + return ERR_PTR(-EPROBE_DEFER); + + adpt = netdev_priv(netdev); + if (!adpt->mii_bus) + return ERR_PTR(-EPROBE_DEFER); + + phydev = mdiobus_get_phy(adpt->mii_bus, phy_addr); + return phydev ? phydev : ERR_PTR(-ENODEV); +} + +static struct phy_device * +emac_acpi_get_phydev(struct platform_device *pdev, struct emac_adapter *adpt) +{ + struct phy_device *phydev = NULL; + int phy_addr; + int ret; + + /* Compatible with "phy-channel" */ + ret = device_property_read_u32(&pdev->dev, "phy-channel", + &phy_addr); + if (!ret) + phydev = mdiobus_get_phy(adpt->mii_bus, phy_addr); + if (phydev) + return phydev; + + /* Get PHY Port reference from phy-handle */ + phydev = emac_acpi_get_phydev_from_phy_handle(pdev); + if (!IS_ERR(phydev)) + return phydev; + if (PTR_ERR(phydev) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); + + /* If we can't read a valid phy address from "phy-channel"/"phy-handle", + * then assume that there is only one phy on local mdio bus. + */ + phydev = phy_find_first(adpt->mii_bus); + return phydev ? phydev : ERR_PTR(-ENODEV); +} + static int emac_mdio_bus_create(struct platform_device *pdev, struct emac_adapter *adpt) { @@ -128,13 +218,9 @@ static int emac_get_phydev(struct platform_device *pdev, struct emac_adapter *adpt) { struct device_node *np = pdev->dev.of_node; - struct mii_bus *bus = adpt->mii_bus; struct device_node *phy_np; struct phy_device *phydev; - u32 phy_addr; - int ret; - if (!has_acpi_companion(&pdev->dev)) { phy_np = of_parse_phandle(np, "phy-handle", 0); adpt->phydev = of_phy_find_device(phy_np); @@ -142,14 +228,9 @@ static int emac_get_phydev(struct platform_device *pdev, return adpt->phydev ? 0 : -ENODEV; } - ret = device_property_read_u32(&pdev->dev, "phy-channel", - &phy_addr); - /* If we can't read a valid phy address, then assume - * that there is only one phy on this mdio bus. - */ - phydev = ret ? phy_find_first(bus) : mdiobus_get_phy(bus, phy_addr); - if (!phydev) - return -ENODEV; + phydev = emac_acpi_get_phydev(pdev, adpt); + if (IS_ERR(phydev)) + return PTR_ERR(phydev); /* of_phy_find_device() claims a reference to the phydev, * so we do that here manually as well. When the driver @@ -171,10 +252,14 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) return ret; ret = emac_get_phydev(pdev, adpt); - if (ret) { + if (!ret) + return 0; + + if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Could not find external phy\n"); - mdiobus_unregister(adpt->mii_bus); - } + else + dev_warn(&pdev->dev, "Phy is not available yet, deferred probing\n"); + mdiobus_unregister(adpt->mii_bus); return ret; } -- 2.18.0