From: George Moussalem <george.moussalem@outlook.com>
Date: Sun, 19 Jan 2025 11:25:27 +0400
Subject: [PATCH] net: phy: qcom: ipq5018 enable configuration of DAC settings

Allow setting amplitude and bias current as needed on the IPQ5018 Internal
GE PHY. When the "qcom,dac" property is set in the DTS, the driver expects
a pair of u32 values:

(from QCA8337 datasheet)
11: follow DSP setting
10: bypass half amplitude and follow DSP half bias current
01: half amplitude follow DSP and bypass half bias current
00: full amplitude and full bias current

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
--- a/drivers/net/phy/qcom/ipq5018.c
+++ b/drivers/net/phy/qcom/ipq5018.c
@@ -13,6 +13,10 @@
 #define IPQ5018_PHY_FIFO_CONTROL	0x19
 #define  IPQ5018_PHY_FIFO_RESET		GENMASK(1, 0)
 
+#define IPQ5018_PHY_DEBUG_EDAC			0x4380
+#define IPQ5018_PHY_MMD1_MDAC			0x8100
+#define  IPQ5018_PHY_DAC_MASK			GENMASK(15,8)
+
 struct ipq5018_phy {
 	int num_clks;
 	struct clk_bulk_data *clks;
@@ -20,20 +24,35 @@ struct ipq5018_phy {
 
 	struct clk_hw *clk_rx, *clk_tx;
 	struct clk_hw_onecell_data *clk_data;
+
+	u32 mdac;
+	u32 edac;
 };
 
 static int ipq5018_probe(struct phy_device *phydev)
 {
-	struct ipq5018_phy *priv;
 	struct device *dev = &phydev->mdio.dev;
+	struct ipq5018_phy *priv;
+	u32 mdac, edac = 0;
 	char name[64];
-	int ret;
+	int ret, cnt;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return dev_err_probe(dev, -ENOMEM,
 				     "failed to allocate priv\n");
 
+	cnt = of_property_count_u32_elems(dev->of_node, "qcom,dac");
+	if (cnt == 2) {
+		ret = of_property_read_u32_index(dev->of_node, "qcom,dac", 0, &mdac);
+		if (!ret)
+			priv->mdac = mdac;
+
+		ret = of_property_read_u32_index(dev->of_node, "qcom,dac", 1, &edac);
+		if (!ret)
+			priv->edac = edac;
+	}
+
 	priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks);
 	if (priv->num_clks < 0)
 		return dev_err_probe(dev, priv->num_clks,
@@ -84,6 +103,8 @@ static int ipq5018_probe(struct phy_devi
 		return dev_err_probe(dev, ret,
 				     "fail to register clock provider\n");
 
+	phydev->priv = priv;
+
 	return 0;
 }
 
@@ -112,12 +133,34 @@ static int ipq5018_cable_test_start(stru
 	return 0;
 }
 
+static int ipq5018_config_init(struct phy_device *phydev)
+{
+	struct ipq5018_phy *priv = phydev->priv;
+	int ret;
+
+	/* setting mdac in MMD1 */
+	if (priv->mdac) {
+		ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC,
+							IPQ5018_PHY_DAC_MASK, priv->mdac);
+		if (ret)
+			return ret;
+	}
+
+	/* setting edac in debug register */
+	if (priv->edac)
+		return at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC,
+							IPQ5018_PHY_DAC_MASK, priv->edac);
+
+	return 0;
+}
+
 static struct phy_driver ipq5018_internal_phy_driver[] = {
 	{
 		PHY_ID_MATCH_EXACT(IPQ5018_PHY_ID),
 		.name		= "Qualcomm IPQ5018 internal PHY",
 		.flags		= PHY_IS_INTERNAL | PHY_POLL_CABLE_TEST,
 		.probe		= ipq5018_probe,
+		.config_init	= ipq5018_config_init,
 		.soft_reset	= ipq5018_soft_reset,
 		.read_status	= at803x_read_status,
 		.config_intr	= at803x_config_intr,
