Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 1/10/24 10:53, Svyatoslav wrote: 10 січня 2024 р. 17:45:57 GMT+02:00, Sean Anderson написав(-ла): On 12/16/23 10:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) Same comment as the first time: Why the conversion from probe to of_to_plat? Same answer as the first time. Last time you said -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) This change should be a separate commit. This actually should not be accepted first place .of_to_plat - convert device tree data to plat .probe - make a device ready for use https://github.com/u-boot/u-boot/blob/master/doc/develop/driver-model/design.rst and I thought "This actually should not be accepted first place" was referring to the conversion (i.e. that you would be removing it next time). This sort of conversion should be mentioned in the commit message. And the weird thing to me is that I would expect of_to_plat to fill in a platdata struct. If you are not doing that, why use this function? You propose to spam commits for this small adjustment? Yes. One change per commit. --Sean
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
10 січня 2024 р. 17:45:57 GMT+02:00, Sean Anderson написав(-ла): >On 12/16/23 10:37, Sean Anderson wrote: >> On 12/16/23 03:48, Svyatoslav Ryhel wrote: >>> Existing gpio-gate-clock driver acts like a simple GPIO switch without any >>> effect on gated clock. Add actual clock actions into enable/disable ops and >>> implement get_rate op by passing gated clock if it is enabled. >>> >>> Signed-off-by: Svyatoslav Ryhel >>> --- >>> drivers/clk/clk-gpio.c | 44 ++ >>> 1 file changed, 36 insertions(+), 8 deletions(-) >>> >>> diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c >>> index 26d795b978..72d9747a47 100644 >>> --- a/drivers/clk/clk-gpio.c >>> +++ b/drivers/clk/clk-gpio.c >>> @@ -3,19 +3,23 @@ >>> * Copyright (C) 2023 Marek Vasut >>> */ >>> -#include >>> -#include >>> -#include >>> +#include >>> #include >>> +#include >>> +#include >>> + >>> +#include >>> struct clk_gpio_priv { >>> - struct gpio_desc enable; >>> + struct gpio_desc enable; /* GPIO, controlling the gate */ >>> + struct clk *clk; /* Gated clock */ >>> }; >>> static int clk_gpio_enable(struct clk *clk) >>> { >>> struct clk_gpio_priv *priv = dev_get_priv(clk->dev); >>> + clk_enable(priv->clk); >>> dm_gpio_set_value(>enable, 1); >>> return 0; >>> @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) >>> struct clk_gpio_priv *priv = dev_get_priv(clk->dev); >>> dm_gpio_set_value(>enable, 0); >>> + clk_disable(priv->clk); >>> return 0; >>> } >>> +static ulong clk_gpio_get_rate(struct clk *clk) >>> +{ >>> + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); >>> + >>> + return clk_get_rate(priv->clk); >>> +} >>> + >>> const struct clk_ops clk_gpio_ops = { >>> .enable = clk_gpio_enable, >>> .disable = clk_gpio_disable, >>> + .get_rate = clk_gpio_get_rate, >>> }; >>> -static int clk_gpio_probe(struct udevice *dev) >>> +static int clk_gpio_of_to_plat(struct udevice *dev) > >Same comment as the first time: > >Why the conversion from probe to of_to_plat? > Same answer as the first time. You propose to spam commits for this small adjustment? >--Sean > >>> { >>> struct clk_gpio_priv *priv = dev_get_priv(dev); >>> + int ret; >>> - return gpio_request_by_name(dev, "enable-gpios", 0, >>> - >enable, GPIOD_IS_OUT); >>> + priv->clk = devm_clk_get(dev, NULL); >>> + if (IS_ERR(priv->clk)) { >>> + log_debug("%s: Could not get gated clock: %ld\n", >>> + __func__, PTR_ERR(priv->clk)); >>> + return PTR_ERR(priv->clk); >>> + } >>> + >>> + ret = gpio_request_by_name(dev, "enable-gpios", 0, >>> + >enable, GPIOD_IS_OUT); >>> + if (ret) { >>> + log_debug("%s: Could not decode enable-gpios (%d)\n", >>> + __func__, ret); >>> + return ret; >>> + } >>> + >>> + return 0; >>> } >>> /* >>> @@ -59,7 +87,7 @@ U_BOOT_DRIVER(gpio_gate_clock) = { >>> .name = "gpio_clock", >>> .id = UCLASS_CLK, >>> .of_match = clk_gpio_match, >>> - .probe = clk_gpio_probe, >>> + .of_to_plat = clk_gpio_of_to_plat, >>> .priv_auto = sizeof(struct clk_gpio_priv), >>> .ops = _gpio_ops, >>> .flags = DM_FLAG_PRE_RELOC, >> >> +CC Marek >
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 10:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) Same comment as the first time: Why the conversion from probe to of_to_plat? --Sean { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; } /* @@ -59,7 +87,7 @@ U_BOOT_DRIVER(gpio_gate_clock) = { .name = "gpio_clock", .id = UCLASS_CLK, .of_match = clk_gpio_match, - .probe = clk_gpio_probe, + .of_to_plat = clk_gpio_of_to_plat, .priv_auto = sizeof(struct clk_gpio_priv), .ops = _gpio_ops, .flags = DM_FLAG_PRE_RELOC, +CC Marek
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/17/23 11:45, Marek Vasut wrote: On 12/17/23 16:37, Sean Anderson wrote: On 12/17/23 10:19, Marek Vasut wrote: On 12/17/23 02:20, Sean Anderson wrote: On 12/16/23 19:19, Marek Vasut wrote: On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ? I'd rather not. This will be useful on non-CCF systems. Then the forwarding functionality should be in the clock core, basically if a driver does not implement callback , call parent clock callback , and repeat until you reach the top of the clock tree. If you do reach the top, fail with some error code. Isn't that how clock enable already works anyway ? No. In the non-CCF case, we have no idea what the parent of any given clock is. So there's no framework we can provide. Huh, but this driver is attempting to grab some sort of parent clock and enable them, so how does that work ? The driver knows what its parent is, so it can enable it just fine. Now, you might say "why not add a get_parent op?" Well, that will work fine for enabling things, but it is a bit hairy on the disable side. You really need to have refcounting to protect parent clocks (which can have many children). But we don't really have anywhere to store refcounts. struct clk has a member for it, but that's only because it's abused as private data by CCF. Non-CCF clocks have no clock subsystem data allocated at all. Another alternative is to just only disable the leaf node, which is what we currently do. That's OK I think. But that solution requires some more-intensive effort which I don't want to impose on random contributors. So for the time being, all non-CCF clock drivers must handle enabling their own parent clocks. So, in light of this, why not push for use of CCF as much as possible and deprecate the current non-CCF clock support ? It seems like the right thing to do, and avoids growing ad-hoc workarounds for missing core functionality in drivers, which I really want to avoid . Because the CCF framework abuses struct clk for private data, uses strings everywhere, and dynamically allocates all its clocks (which are known at compile-time). You can easily save 4K (or more) by moving away from CCF, which can be especially important in SPL. It's a
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/17/23 16:37, Sean Anderson wrote: On 12/17/23 10:19, Marek Vasut wrote: On 12/17/23 02:20, Sean Anderson wrote: On 12/16/23 19:19, Marek Vasut wrote: On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ? I'd rather not. This will be useful on non-CCF systems. Then the forwarding functionality should be in the clock core, basically if a driver does not implement callback , call parent clock callback , and repeat until you reach the top of the clock tree. If you do reach the top, fail with some error code. Isn't that how clock enable already works anyway ? No. In the non-CCF case, we have no idea what the parent of any given clock is. So there's no framework we can provide. Huh, but this driver is attempting to grab some sort of parent clock and enable them, so how does that work ? Now, you might say "why not add a get_parent op?" Well, that will work fine for enabling things, but it is a bit hairy on the disable side. You really need to have refcounting to protect parent clocks (which can have many children). But we don't really have anywhere to store refcounts. struct clk has a member for it, but that's only because it's abused as private data by CCF. Non-CCF clocks have no clock subsystem data allocated at all. Another alternative is to just only disable the leaf node, which is what we currently do. That's OK I think. But that solution requires some more-intensive effort which I don't want to impose on random contributors. So for the time being, all non-CCF clock drivers must handle enabling their own parent clocks. So, in light of this, why not push for use of CCF as much as possible and deprecate the current non-CCF clock support ? It seems like the right thing to do, and avoids growing ad-hoc workarounds for missing core functionality in drivers, which I really want to avoid .
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 17:55, Svyatoslav Ryhel wrote: сб, 16 груд. 2023 р. о 18:52 Marek Vasut пише: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { -struct gpio_descenable; +struct gpio_descenable;/* GPIO, controlling the gate */ +struct clk*clk;/* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); +clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); +clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ +struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + +return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable= clk_gpio_enable, .disable= clk_gpio_disable, +.get_rate= clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); +int ret; -return gpio_request_by_name(dev, "enable-gpios", 0, ->enable, GPIOD_IS_OUT); +priv->clk = devm_clk_get(dev, NULL); +if (IS_ERR(priv->clk)) { +log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); +return PTR_ERR(priv->clk); +} + +ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); +if (ret) { +log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); +return ret; +} + +return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. It is not and this driver, as is, did not work on tegra since you messed up headers. This is not constructive feedback. Skip the assignment of blame and instead explain what the problem with headers is, that is the relevant part and that is missing here.
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/17/23 10:19, Marek Vasut wrote: On 12/17/23 02:20, Sean Anderson wrote: On 12/16/23 19:19, Marek Vasut wrote: On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ? I'd rather not. This will be useful on non-CCF systems. Then the forwarding functionality should be in the clock core, basically if a driver does not implement callback , call parent clock callback , and repeat until you reach the top of the clock tree. If you do reach the top, fail with some error code. Isn't that how clock enable already works anyway ? No. In the non-CCF case, we have no idea what the parent of any given clock is. So there's no framework we can provide. Now, you might say "why not add a get_parent op?" Well, that will work fine for enabling things, but it is a bit hairy on the disable side. You really need to have refcounting to protect parent clocks (which can have many children). But we don't really have anywhere to store refcounts. struct clk has a member for it, but that's only because it's abused as private data by CCF. Non-CCF clocks have no clock subsystem data allocated at all. Another alternative is to just only disable the leaf node, which is what we currently do. That's OK I think. But that solution requires some more-intensive effort which I don't want to impose on random contributors. So for the time being, all non-CCF clock drivers must handle enabling their own parent clocks. --Sean
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/17/23 02:20, Sean Anderson wrote: On 12/16/23 19:19, Marek Vasut wrote: On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ? I'd rather not. This will be useful on non-CCF systems. Then the forwarding functionality should be in the clock core, basically if a driver does not implement callback , call parent clock callback , and repeat until you reach the top of the clock tree. If you do reach the top, fail with some error code. Isn't that how clock enable already works anyway ?
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 19:19, Marek Vasut wrote: On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ? I'd rather not. This will be useful on non-CCF systems. --Sean
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 17:56, Sean Anderson wrote: On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. Shall we add dependency on CCF instead of duplicating code in drivers ?
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 11:52, Marek Vasut wrote: On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core. Only CCF forwards things. It's up to the driver to do it in the non-CCF case. --Sean
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
сб, 16 груд. 2023 р. о 18:52 Marek Vasut пише: > > On 12/16/23 16:37, Sean Anderson wrote: > > On 12/16/23 03:48, Svyatoslav Ryhel wrote: > >> Existing gpio-gate-clock driver acts like a simple GPIO switch without > >> any > >> effect on gated clock. Add actual clock actions into enable/disable > >> ops and > >> implement get_rate op by passing gated clock if it is enabled. > >> > >> Signed-off-by: Svyatoslav Ryhel > >> --- > >> drivers/clk/clk-gpio.c | 44 ++ > >> 1 file changed, 36 insertions(+), 8 deletions(-) > >> > >> diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c > >> index 26d795b978..72d9747a47 100644 > >> --- a/drivers/clk/clk-gpio.c > >> +++ b/drivers/clk/clk-gpio.c > >> @@ -3,19 +3,23 @@ > >>* Copyright (C) 2023 Marek Vasut > >>*/ > >> -#include > >> -#include > >> -#include > >> +#include > >> #include > >> +#include > >> +#include > >> + > >> +#include > >> struct clk_gpio_priv { > >> -struct gpio_descenable; > >> +struct gpio_descenable;/* GPIO, controlling the gate */ > >> +struct clk*clk;/* Gated clock */ > >> }; > >> static int clk_gpio_enable(struct clk *clk) > >> { > >> struct clk_gpio_priv *priv = dev_get_priv(clk->dev); > >> +clk_enable(priv->clk); > >> dm_gpio_set_value(>enable, 1); > >> return 0; > >> @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) > >> struct clk_gpio_priv *priv = dev_get_priv(clk->dev); > >> dm_gpio_set_value(>enable, 0); > >> +clk_disable(priv->clk); > >> return 0; > >> } > >> +static ulong clk_gpio_get_rate(struct clk *clk) > >> +{ > >> +struct clk_gpio_priv *priv = dev_get_priv(clk->dev); > >> + > >> +return clk_get_rate(priv->clk); > >> +} > >> + > >> const struct clk_ops clk_gpio_ops = { > >> .enable= clk_gpio_enable, > >> .disable= clk_gpio_disable, > >> +.get_rate= clk_gpio_get_rate, > >> }; > >> -static int clk_gpio_probe(struct udevice *dev) > >> +static int clk_gpio_of_to_plat(struct udevice *dev) > >> { > >> struct clk_gpio_priv *priv = dev_get_priv(dev); > >> +int ret; > >> -return gpio_request_by_name(dev, "enable-gpios", 0, > >> ->enable, GPIOD_IS_OUT); > >> +priv->clk = devm_clk_get(dev, NULL); > >> +if (IS_ERR(priv->clk)) { > >> +log_debug("%s: Could not get gated clock: %ld\n", > >> + __func__, PTR_ERR(priv->clk)); > >> +return PTR_ERR(priv->clk); > >> +} > >> + > >> +ret = gpio_request_by_name(dev, "enable-gpios", 0, > >> + >enable, GPIOD_IS_OUT); > >> +if (ret) { > >> +log_debug("%s: Could not decode enable-gpios (%d)\n", > >> + __func__, ret); > >> +return ret; > >> +} > >> + > >> +return 0; > > All this forwarding of clock enable/disable/get_rate for parent clock > should already be done in clock core. If it is not, then it should be > fixed in clock core. It is not and this driver, as is, did not work on tegra since you messed up headers.
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 16:37, Sean Anderson wrote: On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_desc enable; + struct gpio_desc enable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable = clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; All this forwarding of clock enable/disable/get_rate for parent clock should already be done in clock core. If it is not, then it should be fixed in clock core.
Re: [PATCH v2 1/1] clk: clk-gpio: add actual gated clock
On 12/16/23 03:48, Svyatoslav Ryhel wrote: Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_descenable; + struct gpio_descenable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable= clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; } /* @@ -59,7 +87,7 @@ U_BOOT_DRIVER(gpio_gate_clock) = { .name = "gpio_clock", .id = UCLASS_CLK, .of_match = clk_gpio_match, - .probe = clk_gpio_probe, + .of_to_plat = clk_gpio_of_to_plat, .priv_auto = sizeof(struct clk_gpio_priv), .ops= _gpio_ops, .flags = DM_FLAG_PRE_RELOC, +CC Marek
[PATCH v2 1/1] clk: clk-gpio: add actual gated clock
Existing gpio-gate-clock driver acts like a simple GPIO switch without any effect on gated clock. Add actual clock actions into enable/disable ops and implement get_rate op by passing gated clock if it is enabled. Signed-off-by: Svyatoslav Ryhel --- drivers/clk/clk-gpio.c | 44 ++ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 26d795b978..72d9747a47 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -3,19 +3,23 @@ * Copyright (C) 2023 Marek Vasut */ -#include -#include -#include +#include #include +#include +#include + +#include struct clk_gpio_priv { - struct gpio_descenable; + struct gpio_descenable; /* GPIO, controlling the gate */ + struct clk *clk; /* Gated clock */ }; static int clk_gpio_enable(struct clk *clk) { struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + clk_enable(priv->clk); dm_gpio_set_value(>enable, 1); return 0; @@ -26,21 +30,45 @@ static int clk_gpio_disable(struct clk *clk) struct clk_gpio_priv *priv = dev_get_priv(clk->dev); dm_gpio_set_value(>enable, 0); + clk_disable(priv->clk); return 0; } +static ulong clk_gpio_get_rate(struct clk *clk) +{ + struct clk_gpio_priv *priv = dev_get_priv(clk->dev); + + return clk_get_rate(priv->clk); +} + const struct clk_ops clk_gpio_ops = { .enable = clk_gpio_enable, .disable= clk_gpio_disable, + .get_rate = clk_gpio_get_rate, }; -static int clk_gpio_probe(struct udevice *dev) +static int clk_gpio_of_to_plat(struct udevice *dev) { struct clk_gpio_priv *priv = dev_get_priv(dev); + int ret; - return gpio_request_by_name(dev, "enable-gpios", 0, - >enable, GPIOD_IS_OUT); + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get gated clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + >enable, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: Could not decode enable-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; } /* @@ -59,7 +87,7 @@ U_BOOT_DRIVER(gpio_gate_clock) = { .name = "gpio_clock", .id = UCLASS_CLK, .of_match = clk_gpio_match, - .probe = clk_gpio_probe, + .of_to_plat = clk_gpio_of_to_plat, .priv_auto = sizeof(struct clk_gpio_priv), .ops= _gpio_ops, .flags = DM_FLAG_PRE_RELOC, -- 2.40.1