]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: stmmac: refactor clock management in EQoS driver
authorSwathi K S <swathi.ks@samsung.com>
Thu, 13 Feb 2025 04:15:59 +0000 (09:45 +0530)
committerJakub Kicinski <kuba@kernel.org>
Fri, 14 Feb 2025 21:38:21 +0000 (13:38 -0800)
Refactor clock management in EQoS driver for code reuse and to avoid
redundancy. This way, only minimal changes are required when a new platform
is added.

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Swathi K S <swathi.ks@samsung.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250213041559.106111-1-swathi.ks@samsung.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
include/linux/stmmac.h

index bd4eb187f8c64aae68fa4e7395b4000984ac4d88..1fadb8ba1d2ff63da3a58d296fd5f14d9e60d410 100644 (file)
@@ -29,10 +29,8 @@ struct tegra_eqos {
        void __iomem *regs;
 
        struct reset_control *rst;
-       struct clk *clk_master;
        struct clk *clk_slave;
        struct clk *clk_tx;
-       struct clk *clk_rx;
 
        struct gpio_desc *reset;
 };
@@ -123,49 +121,14 @@ static int dwc_qos_probe(struct platform_device *pdev,
                         struct plat_stmmacenet_data *plat_dat,
                         struct stmmac_resources *stmmac_res)
 {
-       int err;
-
-       plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
-       if (IS_ERR(plat_dat->stmmac_clk)) {
-               dev_err(&pdev->dev, "apb_pclk clock not found.\n");
-               return PTR_ERR(plat_dat->stmmac_clk);
-       }
-
-       err = clk_prepare_enable(plat_dat->stmmac_clk);
-       if (err < 0) {
-               dev_err(&pdev->dev, "failed to enable apb_pclk clock: %d\n",
-                       err);
-               return err;
-       }
-
-       plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
-       if (IS_ERR(plat_dat->pclk)) {
-               dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
-               err = PTR_ERR(plat_dat->pclk);
-               goto disable;
-       }
-
-       err = clk_prepare_enable(plat_dat->pclk);
-       if (err < 0) {
-               dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n",
-                       err);
-               goto disable;
+       for (int i = 0; i < plat_dat->num_clks; i++) {
+               if (strcmp(plat_dat->clks[i].id, "apb_pclk") == 0)
+                       plat_dat->stmmac_clk = plat_dat->clks[i].clk;
+               else if (strcmp(plat_dat->clks[i].id, "phy_ref_clk") == 0)
+                       plat_dat->pclk = plat_dat->clks[i].clk;
        }
 
        return 0;
-
-disable:
-       clk_disable_unprepare(plat_dat->stmmac_clk);
-       return err;
-}
-
-static void dwc_qos_remove(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct stmmac_priv *priv = netdev_priv(ndev);
-
-       clk_disable_unprepare(priv->plat->pclk);
-       clk_disable_unprepare(priv->plat->stmmac_clk);
 }
 
 #define SDMEMCOMPPADCTRL 0x8800
@@ -278,52 +241,19 @@ static int tegra_eqos_probe(struct platform_device *pdev,
        if (!is_of_node(dev->fwnode))
                goto bypass_clk_reset_gpio;
 
-       eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
-       if (IS_ERR(eqos->clk_master)) {
-               err = PTR_ERR(eqos->clk_master);
-               goto error;
-       }
-
-       err = clk_prepare_enable(eqos->clk_master);
-       if (err < 0)
-               goto error;
-
-       eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");
-       if (IS_ERR(eqos->clk_slave)) {
-               err = PTR_ERR(eqos->clk_slave);
-               goto disable_master;
-       }
-
-       data->stmmac_clk = eqos->clk_slave;
-
-       err = clk_prepare_enable(eqos->clk_slave);
-       if (err < 0)
-               goto disable_master;
-
-       eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");
-       if (IS_ERR(eqos->clk_rx)) {
-               err = PTR_ERR(eqos->clk_rx);
-               goto disable_slave;
-       }
-
-       err = clk_prepare_enable(eqos->clk_rx);
-       if (err < 0)
-               goto disable_slave;
-
-       eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
-       if (IS_ERR(eqos->clk_tx)) {
-               err = PTR_ERR(eqos->clk_tx);
-               goto disable_rx;
+       for (int i = 0; i < data->num_clks; i++) {
+               if (strcmp(data->clks[i].id, "slave_bus") == 0) {
+                       eqos->clk_slave = data->clks[i].clk;
+                       data->stmmac_clk = eqos->clk_slave;
+               } else if (strcmp(data->clks[i].id, "tx") == 0) {
+                       eqos->clk_tx = data->clks[i].clk;
+               }
        }
 
-       err = clk_prepare_enable(eqos->clk_tx);
-       if (err < 0)
-               goto disable_rx;
-
        eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
        if (IS_ERR(eqos->reset)) {
                err = PTR_ERR(eqos->reset);
-               goto disable_tx;
+               return err;
        }
 
        usleep_range(2000, 4000);
@@ -365,15 +295,7 @@ reset:
        reset_control_assert(eqos->rst);
 reset_phy:
        gpiod_set_value(eqos->reset, 1);
-disable_tx:
-       clk_disable_unprepare(eqos->clk_tx);
-disable_rx:
-       clk_disable_unprepare(eqos->clk_rx);
-disable_slave:
-       clk_disable_unprepare(eqos->clk_slave);
-disable_master:
-       clk_disable_unprepare(eqos->clk_master);
-error:
+
        return err;
 }
 
@@ -383,10 +305,6 @@ static void tegra_eqos_remove(struct platform_device *pdev)
 
        reset_control_assert(eqos->rst);
        gpiod_set_value(eqos->reset, 1);
-       clk_disable_unprepare(eqos->clk_tx);
-       clk_disable_unprepare(eqos->clk_rx);
-       clk_disable_unprepare(eqos->clk_slave);
-       clk_disable_unprepare(eqos->clk_master);
 }
 
 struct dwc_eth_dwmac_data {
@@ -398,7 +316,6 @@ struct dwc_eth_dwmac_data {
 
 static const struct dwc_eth_dwmac_data dwc_qos_data = {
        .probe = dwc_qos_probe,
-       .remove = dwc_qos_remove,
 };
 
 static const struct dwc_eth_dwmac_data tegra_eqos_data = {
@@ -434,9 +351,19 @@ static int dwc_eth_dwmac_probe(struct platform_device *pdev)
        if (IS_ERR(plat_dat))
                return PTR_ERR(plat_dat);
 
+       ret = devm_clk_bulk_get_all(&pdev->dev, &plat_dat->clks);
+       if (ret < 0)
+               return dev_err_probe(&pdev->dev, ret, "Failed to retrieve all required clocks\n");
+       plat_dat->num_clks = ret;
+
+       ret = clk_bulk_prepare_enable(plat_dat->num_clks, plat_dat->clks);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret, "Failed to enable clocks\n");
+
        ret = data->probe(pdev, plat_dat, &stmmac_res);
        if (ret < 0) {
                dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n");
+               clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks);
                return ret;
        }
 
@@ -451,7 +378,8 @@ static int dwc_eth_dwmac_probe(struct platform_device *pdev)
        return ret;
 
 remove:
-       data->remove(pdev);
+       if (data->remove)
+               data->remove(pdev);
 
        return ret;
 }
@@ -459,10 +387,15 @@ remove:
 static void dwc_eth_dwmac_remove(struct platform_device *pdev)
 {
        const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev);
+       struct plat_stmmacenet_data *plat_data = dev_get_platdata(&pdev->dev);
 
        stmmac_dvr_remove(&pdev->dev);
 
-       data->remove(pdev);
+       if (data->remove)
+               data->remove(pdev);
+
+       if (plat_data)
+               clk_bulk_disable_unprepare(plat_data->num_clks, plat_data->clks);
 }
 
 static const struct of_device_id dwc_eth_dwmac_match[] = {
index c9878a612e53243b9c43e6687309317b500fb9f9..24422ac4e41796f751f4e159d80aa5acb3d2e628 100644 (file)
@@ -254,6 +254,8 @@ struct plat_stmmacenet_data {
        struct clk *clk_ptp_ref;
        unsigned long clk_ptp_rate;
        unsigned long clk_ref_rate;
+       struct clk_bulk_data *clks;
+       int num_clks;
        unsigned int mult_fact_100ns;
        s32 ptp_max_adj;
        u32 cdc_error_adj;