* [PATCH 1/2] regulator: core: Implement regulator_is_enabled() call
@ 2025-03-28 6:31 Alexander Shiyan
2025-03-28 6:31 ` [PATCH 2/2] gpio: clk-gpio: Updating the driver from the kernel repository Alexander Shiyan
0 siblings, 1 reply; 2+ messages in thread
From: Alexander Shiyan @ 2025-03-28 6:31 UTC (permalink / raw)
To: barebox; +Cc: Alexander Shiyan
Signed-off-by: Alexander Shiyan <eagle.alexander923@gmail.com>
---
drivers/regulator/core.c | 11 +++++++++++
include/regulator.h | 6 ++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2c3b009ea6..c9e30ab3fd 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -610,6 +610,17 @@ int regulator_disable(struct regulator *r)
return regulator_disable_rdev(r->rdev);
}
+int regulator_is_enabled(struct regulator *r)
+{
+ if (!r)
+ return 0;
+
+ if (r->rdev->always_on)
+ return 1;
+
+ return r->rdev->enable_count;
+}
+
int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
{
if (!r)
diff --git a/include/regulator.h b/include/regulator.h
index 9785b8ac07..5fdf1602dd 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -217,6 +217,7 @@ void regulator_put(struct regulator *r);
struct regulator *regulator_get_name(const char *name);
int regulator_enable(struct regulator *);
int regulator_disable(struct regulator *);
+int regulator_is_enabled(struct regulator *);
int regulator_is_enabled_regmap(struct regulator_dev *);
int regulator_enable_regmap(struct regulator_dev *);
int regulator_disable_regmap(struct regulator_dev *);
@@ -285,6 +286,11 @@ static inline int regulator_disable(struct regulator *r)
return 0;
}
+static inline int regulator_is_enabled(struct regulator *r)
+{
+ return 0;
+}
+
static inline int regulator_set_voltage(struct regulator *regulator,
int min_uV, int max_uV)
{
--
2.39.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH 2/2] gpio: clk-gpio: Updating the driver from the kernel repository
2025-03-28 6:31 [PATCH 1/2] regulator: core: Implement regulator_is_enabled() call Alexander Shiyan
@ 2025-03-28 6:31 ` Alexander Shiyan
0 siblings, 0 replies; 2+ messages in thread
From: Alexander Shiyan @ 2025-03-28 6:31 UTC (permalink / raw)
To: barebox; +Cc: Alexander Shiyan
This patch replaces the driver code from the Linux kernel repository,
adding new driver variants gpio-mux-clock and gated-fixed-clock.
Signed-off-by: Alexander Shiyan <eagle.alexander923@gmail.com>
---
drivers/clk/clk-gpio.c | 337 ++++++++++++++++++++++++++++++++---------
1 file changed, 264 insertions(+), 73 deletions(-)
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 940a20523e..325d523921 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -1,121 +1,312 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-License-Identifier: GPL-2.0
/*
- * clk-gpio.c - clock that can be enabled and disabled via GPIO output
- * Based on Linux clk support
+ * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - https://www.ti.com
*
- * Copyright (c) 2018 Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+ * Authors:
+ * Jyri Sarha <jsarha@ti.com>
+ * Sergej Sawazki <ce3a@gmx.de>
+ *
+ * Gpio controlled clock implementation
*/
+
#include <common.h>
-#include <malloc.h>
+#include <regulator.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/err.h>
-#include <gpio.h>
-#include <of_gpio.h>
-#include <init.h>
+#include <linux/gpio/consumer.h>
+/**
+ * struct clk_gpio - gpio gated clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @gpiod: gpio descriptor
+ *
+ * Clock with a gpio control for enabling and disabling the parent clock
+ * or switching between two parents by asserting or deasserting the gpio.
+ *
+ * Implements .enable, .disable and .is_enabled or
+ * .get_parent, .set_parent and .determine_rate depending on which clk_ops
+ * is used.
+ */
struct clk_gpio {
- struct clk_hw hw;
- const char *parent;
- int gpio;
+ struct clk_hw hw;
+ struct gpio_desc *gpiod;
};
+
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
-static int clk_gpio_enable(struct clk_hw *hw)
+static int clk_gpio_gate_enable(struct clk_hw *hw)
{
- struct clk_gpio *clk_gpio = to_clk_gpio(hw);
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ gpiod_set_value(clk->gpiod, 1);
- gpio_set_active(clk_gpio->gpio, true);
return 0;
}
-static void clk_gpio_disable(struct clk_hw *hw)
+static void clk_gpio_gate_disable(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ gpiod_set_value(clk->gpiod, 0);
+}
+
+static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
{
- struct clk_gpio *clk_gpio = to_clk_gpio(hw);
+ struct clk_gpio *clk = to_clk_gpio(hw);
- gpio_set_active(clk_gpio->gpio, false);
+ return gpiod_get_value(clk->gpiod);
}
-static int clk_gpio_is_enabled(struct clk_hw *hw)
+static const struct clk_ops clk_gpio_gate_ops = {
+ .enable = clk_gpio_gate_enable,
+ .disable = clk_gpio_gate_disable,
+ .is_enabled = clk_gpio_gate_is_enabled,
+};
+
+static int clk_gpio_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_gpio *clk = to_clk_gpio(hw);
+
+ return gpiod_get_value(clk->gpiod);
+}
+
+static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
{
- struct clk_gpio *clk_gpio = to_clk_gpio(hw);
+ struct clk_gpio *clk = to_clk_gpio(hw);
- return gpio_is_active(clk_gpio->gpio);
+ gpiod_set_value(clk->gpiod, index);
+
+ return 0;
}
-static struct clk_ops clk_gpio_ops = {
+static const struct clk_ops clk_gpio_mux_ops = {
+ .get_parent = clk_gpio_mux_get_parent,
+ .set_parent = clk_gpio_mux_set_parent,
.set_rate = clk_parent_set_rate,
.round_rate = clk_parent_round_rate,
- .enable = clk_gpio_enable,
- .disable = clk_gpio_disable,
- .is_enabled = clk_gpio_is_enabled,
};
-static int of_gpio_clk_probe(struct device *dev)
+static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
+ struct gpio_desc *gpiod,
+ const struct clk_ops *clk_gpio_ops)
{
- struct device_node *node = dev->device_node;
struct clk_gpio *clk_gpio;
- enum of_gpio_flags of_flags;
- unsigned long flags;
- int ret;
+ struct clk_hw *hw;
+ struct clk_init_data init = {};
+ const char *parent_names[2];
+ int err;
clk_gpio = xzalloc(sizeof(*clk_gpio));
if (!clk_gpio)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- clk_gpio->parent = of_clk_get_parent_name(node, 0);
- if (!clk_gpio->parent) {
- ret = -EINVAL;
- goto no_parent;
- }
+ if (of_clk_parent_fill(dev->of_node, parent_names, num_parents) != num_parents)
+ return ERR_PTR(-EINVAL);
- clk_gpio->hw.clk.ops = &clk_gpio_ops;
- clk_gpio->hw.clk.parent_names = &clk_gpio->parent;
- clk_gpio->hw.clk.num_parents = 1;
-
- clk_gpio->hw.clk.name = node->name;
- of_property_read_string(node, "clock-output-names",
- &clk_gpio->hw.clk.name);
-
- ret = of_get_named_gpio_flags(node, "enable-gpios", 0,
- &of_flags);
- if (ret >= 0 && !gpio_is_valid(ret))
- ret = -EINVAL;
- if (ret < 0)
- goto no_gpio;
- clk_gpio->gpio = ret;
-
- flags = GPIOF_OUT_INIT_ACTIVE;
- if (of_flags & OF_GPIO_ACTIVE_LOW)
- flags |= GPIOF_ACTIVE_LOW;
- ret = gpio_request_one(clk_gpio->gpio, flags, clk_gpio->hw.clk.name);
- if (ret)
- goto no_request;
+ init.name = dev->of_node->name;
+ of_property_read_string(dev->of_node, "clock-output-names", &init.name);
+ init.ops = clk_gpio_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = CLK_SET_RATE_PARENT;
- ret = bclk_register(&clk_gpio->hw.clk);
- if (ret)
- goto no_register;
+ clk_gpio->gpiod = gpiod;
+ clk_gpio->hw.init = &init;
- return of_clk_add_provider(node, of_clk_src_simple_get, &clk_gpio->hw.clk);
+ hw = &clk_gpio->hw;
+ err = bclk_register(&clk_gpio->hw.clk);
+ if (err)
+ return ERR_PTR(err);
-no_register:
- gpio_free(clk_gpio->gpio);
-no_request:
-no_gpio:
-no_parent:
- free(clk_gpio);
- return ret;
+ return hw;
+}
+
+static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
+ int num_parents,
+ struct gpio_desc *gpiod)
+{
+ return clk_register_gpio(dev, num_parents, gpiod, &clk_gpio_gate_ops);
+}
+
+static struct clk_hw *clk_hw_register_gpio_mux(struct device *dev,
+ struct gpio_desc *gpiod)
+{
+ return clk_register_gpio(dev, 2, gpiod, &clk_gpio_mux_ops);
}
-static const struct of_device_id clk_gpio_device_id[] = {
- { .compatible = "gpio-gate-clock", },
- {}
+static int gpio_clk_driver_probe(struct device *dev)
+{
+ struct device_node *node = dev->of_node;
+ const char *gpio_name;
+ unsigned int num_parents;
+ struct gpio_desc *gpiod;
+ struct clk_hw *hw;
+ bool is_mux;
+
+ is_mux = of_device_is_compatible(node, "gpio-mux-clock");
+
+ num_parents = of_clk_get_parent_count(node);
+ if (is_mux && num_parents != 2)
+ return dev_err_probe(dev, -EINVAL,
+ "mux-clock must have 2 parents\n");
+
+ gpio_name = is_mux ? "select" : "enable";
+ gpiod = gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "Can't get '%s' named GPIO property\n", gpio_name);
+
+ if (is_mux)
+ hw = clk_hw_register_gpio_mux(dev, gpiod);
+ else
+ hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ return of_clk_add_provider(node, of_clk_src_simple_get, &hw->clk);
+}
+
+static __maybe_unused const struct of_device_id clk_gpio_device_id[] = {
+ { .compatible = "gpio-mux-clock" },
+ { .compatible = "gpio-gate-clock" },
+ { }
};
MODULE_DEVICE_TABLE(of, clk_gpio_device_id);
static struct driver gpio_gate_clock_driver = {
- .probe = of_gpio_clk_probe,
+ .probe = gpio_clk_driver_probe,
.name = "gpio-gate-clock",
.of_compatible = DRV_OF_COMPAT(clk_gpio_device_id),
};
-
core_platform_driver(gpio_gate_clock_driver);
+
+/**
+ * DOC: gated fixed clock, controlled with a gpio output and a regulator
+ * Traits of this clock:
+ * prepare - clk_prepare and clk_unprepare are function & control regulator
+ * optionally a gpio that can sleep
+ * enable - clk_enable and clk_disable are functional & control gpio
+ * rate - rate is fixed and set on clock registration
+ * parent - fixed clock is a root clock and has no parent
+ */
+
+/**
+ * struct clk_gated_fixed - Gateable fixed rate clock
+ * @clk_gpio: instance of clk_gpio for gate-gpio
+ * @supply: supply regulator
+ * @rate: fixed rate
+ */
+struct clk_gated_fixed {
+ struct clk_gpio clk_gpio;
+ struct regulator *supply;
+ unsigned long rate;
+};
+
+#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio)
+
+static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return to_clk_gated_fixed(to_clk_gpio(hw))->rate;
+}
+
+static int clk_gated_fixed_enable(struct clk_hw *hw)
+{
+ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
+ int ret;
+
+ ret = regulator_enable(clk->supply);
+ if (!ret)
+ gpiod_set_value(clk->clk_gpio.gpiod, 1);
+
+ return ret;
+}
+
+static void clk_gated_fixed_disable(struct clk_hw *hw)
+{
+ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
+
+ gpiod_set_value(clk->clk_gpio.gpiod, 0);
+
+ regulator_disable(clk->supply);
+}
+
+static int clk_gated_fixed_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
+
+ if (clk->supply && !regulator_is_enabled(clk->supply))
+ return 0;
+
+ return clk->clk_gpio.gpiod ? gpiod_get_value(clk->clk_gpio.gpiod) : 1;
+}
+
+static const struct clk_ops clk_gated_fixed_ops = {
+ .enable = clk_gated_fixed_enable,
+ .disable = clk_gated_fixed_disable,
+ .is_enabled = clk_gated_fixed_is_enabled,
+ .recalc_rate = clk_gated_fixed_recalc_rate,
+};
+
+static int clk_gated_fixed_probe(struct device *dev)
+{
+ struct clk_gated_fixed *clk;
+ const char *clk_name;
+ u32 rate;
+ int ret;
+
+ clk = xzalloc(sizeof(*clk));
+ if (!clk)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(dev->of_node, "clock-frequency", &rate);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get clock-frequency\n");
+ clk->rate = rate;
+
+ clk_name = dev->of_node->name;
+ of_property_read_string(dev->of_node, "clock-output-names", &clk_name);
+
+ clk->supply = regulator_get_optional(dev, "vdd");
+ if (IS_ERR(clk->supply)) {
+ if (PTR_ERR(clk->supply) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(clk->supply),
+ "Failed to get regulator\n");
+ clk->supply = NULL;
+ }
+
+ clk->clk_gpio.gpiod = gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(clk->clk_gpio.gpiod))
+ return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod),
+ "Failed to get gpio\n");
+
+
+ clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, &clk_gated_fixed_ops, 0);
+
+ ret = clk_hw_register(dev, &clk->clk_gpio.hw);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register clock\n");
+
+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
+ &clk->clk_gpio.hw);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register clock provider\n");
+
+ return 0;
+}
+
+static __maybe_unused const struct of_device_id gated_fixed_clk_match_table[] = {
+ { .compatible = "gated-fixed-clock" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gated_fixed_clk_match_table);
+
+static struct driver gated_fixed_clk_driver = {
+ .probe = clk_gated_fixed_probe,
+ .name = "gated-fixed-clk",
+ .of_compatible = DRV_OF_COMPAT(gated_fixed_clk_match_table),
+};
+core_platform_driver(gated_fixed_clk_driver);
--
2.39.1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-03-28 6:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-28 6:31 [PATCH 1/2] regulator: core: Implement regulator_is_enabled() call Alexander Shiyan
2025-03-28 6:31 ` [PATCH 2/2] gpio: clk-gpio: Updating the driver from the kernel repository Alexander Shiyan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox