From ba1f966725223c605ed504b09446c52a3f201c2b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 29 Nov 2017 09:06:11 +0100 Subject: [PATCH] net: designware: add clock support This implementation manages several clocks, disable and free all of them in case of error during probe and in remove callback. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/net/designware.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/designware.h | 4 ++++ 2 files changed, 47 insertions(+) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 036d231..9207324 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -661,6 +662,35 @@ int designware_eth_probe(struct udevice *dev) u32 iobase = pdata->iobase; ulong ioaddr; int ret; +#ifdef CONFIG_CLK + int i, err, clock_nb; + + priv->clock_count = 0; + clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + if (err < 0) + break; + + err = clk_enable(&priv->clocks[i]); + if (err) { + pr_err("failed to enable clock %d\n", i); + clk_free(&priv->clocks[i]); + goto clk_err; + } + priv->clock_count++; + } + } else if (clock_nb != -ENOENT) { + pr_err("failed to get clock phandle(%d)\n", clock_nb); + return clock_nb; + } +#endif #if defined(CONFIG_DM_REGULATOR) struct udevice *phy_supply; @@ -707,6 +737,15 @@ int designware_eth_probe(struct udevice *dev) debug("%s, ret=%d\n", __func__, ret); return ret; + +#ifdef CONFIG_CLK +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + pr_err("failed to disable all clocks\n"); + + return err; +#endif } static int designware_eth_remove(struct udevice *dev) @@ -717,7 +756,11 @@ static int designware_eth_remove(struct udevice *dev) mdio_unregister(priv->bus); mdio_free(priv->bus); +#ifdef CONFIG_CLK + return clk_release_all(priv->clocks, priv->clock_count); +#else return 0; +#endif } const struct eth_ops designware_eth_ops = { diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 7992d0e..252cd24 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -239,6 +239,10 @@ struct dw_eth_dev { #ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio; #endif +#ifdef CONFIG_CLK + struct clk *clocks; /* clock list */ + int clock_count; /* number of clock in clock list */ +#endif struct phy_device *phydev; struct mii_dev *bus;