kernel: backport clk *_hw_* API for registering struct clk_hw
Drivers have been modified to use it and new ones have to be written this way, so we need it for backporting code. Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
This commit is contained in:
parent
885910225d
commit
8965cf90f1
2 changed files with 416 additions and 0 deletions
|
@ -0,0 +1,182 @@
|
|||
From 4143804c4fdef40358c654d1fb2271a1a0f1fedf Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 5 Feb 2016 17:02:52 -0800
|
||||
Subject: [PATCH] clk: Add {devm_}clk_hw_{register,unregister}() APIs
|
||||
|
||||
We've largely split the clk consumer and provider APIs along
|
||||
struct clk and struct clk_hw, but clk_register() still returns a
|
||||
struct clk pointer for each struct clk_hw that's registered.
|
||||
Eventually we'd like to only allocate struct clks when there's a
|
||||
user, because struct clk is per-user now, so clk_register() needs
|
||||
to change.
|
||||
|
||||
Let's add new APIs to register struct clk_hws, but this time
|
||||
we'll hide the struct clk from the caller by returning an int
|
||||
error code. Also add an unregistration API that takes the clk_hw
|
||||
structure that was passed to the registration API. This way
|
||||
provider drivers never have to deal with a struct clk pointer
|
||||
unless they're using the clk consumer APIs.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
---
|
||||
Documentation/driver-model/devres.txt | 1 +
|
||||
drivers/clk/clk.c | 86 +++++++++++++++++++++++++++++++++++
|
||||
include/linux/clk-provider.h | 6 +++
|
||||
3 files changed, 93 insertions(+)
|
||||
|
||||
--- a/Documentation/driver-model/devres.txt
|
||||
+++ b/Documentation/driver-model/devres.txt
|
||||
@@ -236,6 +236,7 @@ certainly invest a bit more effort into
|
||||
CLOCK
|
||||
devm_clk_get()
|
||||
devm_clk_put()
|
||||
+ devm_clk_hw_register()
|
||||
|
||||
DMA
|
||||
dmam_alloc_coherent()
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -2595,6 +2595,22 @@ fail_out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register);
|
||||
|
||||
+/**
|
||||
+ * clk_hw_register - register a clk_hw and return an error code
|
||||
+ * @dev: device that is registering this clock
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * clk_hw_register is the primary interface for populating the clock tree with
|
||||
+ * new clock nodes. It returns an integer equal to zero indicating success or
|
||||
+ * less than zero indicating failure. Drivers must test for an error code after
|
||||
+ * calling clk_hw_register().
|
||||
+ */
|
||||
+int clk_hw_register(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ return PTR_ERR_OR_ZERO(clk_register(dev, hw));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_hw_register);
|
||||
+
|
||||
/* Free memory allocated for a clock. */
|
||||
static void __clk_release(struct kref *ref)
|
||||
{
|
||||
@@ -2696,11 +2712,26 @@ void clk_unregister(struct clk *clk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_unregister);
|
||||
|
||||
+/**
|
||||
+ * clk_hw_unregister - unregister a currently registered clk_hw
|
||||
+ * @hw: hardware-specific clock data to unregister
|
||||
+ */
|
||||
+void clk_hw_unregister(struct clk_hw *hw)
|
||||
+{
|
||||
+ clk_unregister(hw->clk);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_hw_unregister);
|
||||
+
|
||||
static void devm_clk_release(struct device *dev, void *res)
|
||||
{
|
||||
clk_unregister(*(struct clk **)res);
|
||||
}
|
||||
|
||||
+static void devm_clk_hw_release(struct device *dev, void *res)
|
||||
+{
|
||||
+ clk_hw_unregister(*(struct clk_hw **)res);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* devm_clk_register - resource managed clk_register()
|
||||
* @dev: device that is registering this clock
|
||||
@@ -2731,6 +2762,36 @@ struct clk *devm_clk_register(struct dev
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_register);
|
||||
|
||||
+/**
|
||||
+ * devm_clk_hw_register - resource managed clk_hw_register()
|
||||
+ * @dev: device that is registering this clock
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * Managed clk_hw_register(). Clocks returned from this function are
|
||||
+ * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
|
||||
+ * for more information.
|
||||
+ */
|
||||
+int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ struct clk_hw **hwp;
|
||||
+ int ret;
|
||||
+
|
||||
+ hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
|
||||
+ if (!hwp)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = clk_hw_register(dev, hw);
|
||||
+ if (!ret) {
|
||||
+ *hwp = hw;
|
||||
+ devres_add(dev, hwp);
|
||||
+ } else {
|
||||
+ devres_free(hwp);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_clk_hw_register);
|
||||
+
|
||||
static int devm_clk_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct clk *c = res;
|
||||
@@ -2739,6 +2800,15 @@ static int devm_clk_match(struct device
|
||||
return c == data;
|
||||
}
|
||||
|
||||
+static int devm_clk_hw_match(struct device *dev, void *res, void *data)
|
||||
+{
|
||||
+ struct clk_hw *hw = res;
|
||||
+
|
||||
+ if (WARN_ON(!hw))
|
||||
+ return 0;
|
||||
+ return hw == data;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* devm_clk_unregister - resource managed clk_unregister()
|
||||
* @clk: clock to unregister
|
||||
@@ -2753,6 +2823,22 @@ void devm_clk_unregister(struct device *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_unregister);
|
||||
|
||||
+/**
|
||||
+ * devm_clk_hw_unregister - resource managed clk_hw_unregister()
|
||||
+ * @dev: device that is unregistering the hardware-specific clock data
|
||||
+ * @hw: link to hardware-specific clock data
|
||||
+ *
|
||||
+ * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
|
||||
+ * this function will not need to be called and the resource management
|
||||
+ * code will ensure that the resource is freed.
|
||||
+ */
|
||||
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
|
||||
+{
|
||||
+ WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
|
||||
+ hw));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
|
||||
+
|
||||
/*
|
||||
* clkdev helpers
|
||||
*/
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -639,9 +639,15 @@ void of_gpio_mux_clk_setup(struct device
|
||||
struct clk *clk_register(struct device *dev, struct clk_hw *hw);
|
||||
struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
|
||||
|
||||
+int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
+int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw);
|
||||
+
|
||||
void clk_unregister(struct clk *clk);
|
||||
void devm_clk_unregister(struct device *dev, struct clk *clk);
|
||||
|
||||
+void clk_hw_unregister(struct clk_hw *hw);
|
||||
+void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw);
|
||||
+
|
||||
/* helper functions */
|
||||
const char *__clk_get_name(const struct clk *clk);
|
||||
const char *clk_hw_get_name(const struct clk_hw *hw);
|
|
@ -0,0 +1,234 @@
|
|||
From 0861e5b8cf80038e91942f1005c8dfce79d18c38 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 5 Feb 2016 17:38:26 -0800
|
||||
Subject: [PATCH] clk: Add clk_hw OF clk providers
|
||||
|
||||
Now that we have a clk registration API that doesn't return
|
||||
struct clks, we need to have some way to hand out struct clks via
|
||||
the clk_get() APIs that doesn't involve associating struct clk
|
||||
pointers with an OF node. Currently we ask the OF provider to
|
||||
give us a struct clk pointer for some clkspec, turn that struct
|
||||
clk into a struct clk_hw and then allocate a new struct clk to
|
||||
return to the caller.
|
||||
|
||||
Let's add a clk_hw based OF provider hook that returns a struct
|
||||
clk_hw directly, so that we skip the intermediate step of
|
||||
converting from struct clk to struct clk_hw. Eventually when
|
||||
we've converted all OF clk providers to struct clk_hw based APIs
|
||||
we can remove the struct clk based ones.
|
||||
|
||||
It should also be noted that we change the onecell provider to
|
||||
have a flex array instead of a pointer for the array of clk_hw
|
||||
pointers. This allows providers to allocate one structure of the
|
||||
correct length in one step instead of two.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
---
|
||||
drivers/clk/clk.c | 85 +++++++++++++++++++++++++++++++++++++++++---
|
||||
include/linux/clk-provider.h | 30 ++++++++++++++++
|
||||
2 files changed, 111 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -3001,6 +3001,7 @@ struct of_clk_provider {
|
||||
|
||||
struct device_node *node;
|
||||
struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
|
||||
+ struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
@@ -3017,6 +3018,12 @@ struct clk *of_clk_src_simple_get(struct
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
|
||||
|
||||
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return data;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
|
||||
+
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct clk_onecell_data *clk_data = data;
|
||||
@@ -3031,6 +3038,21 @@ struct clk *of_clk_src_onecell_get(struc
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
|
||||
|
||||
+struct clk_hw *
|
||||
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ struct clk_hw_onecell_data *hw_data = data;
|
||||
+ unsigned int idx = clkspec->args[0];
|
||||
+
|
||||
+ if (idx >= hw_data->num) {
|
||||
+ pr_err("%s: invalid index %u\n", __func__, idx);
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+ }
|
||||
+
|
||||
+ return hw_data->hws[idx];
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
|
||||
+
|
||||
/**
|
||||
* of_clk_add_provider() - Register a clock provider for a node
|
||||
* @np: Device node pointer associated with clock provider
|
||||
@@ -3067,6 +3089,41 @@ int of_clk_add_provider(struct device_no
|
||||
EXPORT_SYMBOL_GPL(of_clk_add_provider);
|
||||
|
||||
/**
|
||||
+ * of_clk_add_hw_provider() - Register a clock provider for a node
|
||||
+ * @np: Device node pointer associated with clock provider
|
||||
+ * @get: callback for decoding clk_hw
|
||||
+ * @data: context pointer for @get callback.
|
||||
+ */
|
||||
+int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct of_clk_provider *cp;
|
||||
+ int ret;
|
||||
+
|
||||
+ cp = kzalloc(sizeof(*cp), GFP_KERNEL);
|
||||
+ if (!cp)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ cp->node = of_node_get(np);
|
||||
+ cp->data = data;
|
||||
+ cp->get_hw = get;
|
||||
+
|
||||
+ mutex_lock(&of_clk_mutex);
|
||||
+ list_add(&cp->link, &of_clk_providers);
|
||||
+ mutex_unlock(&of_clk_mutex);
|
||||
+ pr_debug("Added clk_hw provider from %s\n", np->full_name);
|
||||
+
|
||||
+ ret = of_clk_set_defaults(np, true);
|
||||
+ if (ret < 0)
|
||||
+ of_clk_del_provider(np);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
|
||||
+
|
||||
+/**
|
||||
* of_clk_del_provider() - Remove a previously registered clock provider
|
||||
* @np: Device node pointer associated with clock provider
|
||||
*/
|
||||
@@ -3087,11 +3144,32 @@ void of_clk_del_provider(struct device_n
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_del_provider);
|
||||
|
||||
+static struct clk_hw *
|
||||
+__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
|
||||
+ struct of_phandle_args *clkspec)
|
||||
+{
|
||||
+ struct clk *clk;
|
||||
+ struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
|
||||
+
|
||||
+ if (provider->get_hw) {
|
||||
+ hw = provider->get_hw(clkspec, provider->data);
|
||||
+ } else if (provider->get) {
|
||||
+ clk = provider->get(clkspec, provider->data);
|
||||
+ if (!IS_ERR(clk))
|
||||
+ hw = __clk_get_hw(clk);
|
||||
+ else
|
||||
+ hw = ERR_CAST(clk);
|
||||
+ }
|
||||
+
|
||||
+ return hw;
|
||||
+}
|
||||
+
|
||||
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
|
||||
const char *dev_id, const char *con_id)
|
||||
{
|
||||
struct of_clk_provider *provider;
|
||||
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
|
||||
+ struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
if (!clkspec)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -3100,10 +3178,9 @@ struct clk *__of_clk_get_from_provider(s
|
||||
mutex_lock(&of_clk_mutex);
|
||||
list_for_each_entry(provider, &of_clk_providers, link) {
|
||||
if (provider->node == clkspec->np)
|
||||
- clk = provider->get(clkspec, provider->data);
|
||||
- if (!IS_ERR(clk)) {
|
||||
- clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
|
||||
- con_id);
|
||||
+ hw = __of_clk_get_hw_from_provider(provider, clkspec);
|
||||
+ if (!IS_ERR(hw)) {
|
||||
+ clk = __clk_create_clk(hw, dev_id, con_id);
|
||||
|
||||
if (!IS_ERR(clk) && !__clk_get(clk)) {
|
||||
__clk_free_clk(clk);
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -693,6 +693,11 @@ struct clk_onecell_data {
|
||||
unsigned int clk_num;
|
||||
};
|
||||
|
||||
+struct clk_hw_onecell_data {
|
||||
+ size_t num;
|
||||
+ struct clk_hw *hws[];
|
||||
+};
|
||||
+
|
||||
extern struct of_device_id __clk_of_table;
|
||||
|
||||
#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)
|
||||
@@ -702,10 +707,19 @@ int of_clk_add_provider(struct device_no
|
||||
struct clk *(*clk_src_get)(struct of_phandle_args *args,
|
||||
void *data),
|
||||
void *data);
|
||||
+int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data);
|
||||
void of_clk_del_provider(struct device_node *np);
|
||||
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
|
||||
void *data);
|
||||
+
|
||||
+struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec,
|
||||
+ void *data);
|
||||
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
|
||||
+struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec,
|
||||
+ void *data);
|
||||
int of_clk_get_parent_count(struct device_node *np);
|
||||
int of_clk_parent_fill(struct device_node *np, const char **parents,
|
||||
unsigned int size);
|
||||
@@ -722,6 +736,13 @@ static inline int of_clk_add_provider(st
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+static inline int of_clk_add_hw_provider(struct device_node *np,
|
||||
+ struct clk_hw *(*get)(struct of_phandle_args *clkspec,
|
||||
+ void *data),
|
||||
+ void *data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
#define of_clk_del_provider(np) \
|
||||
{ while (0); }
|
||||
static inline struct clk *of_clk_src_simple_get(
|
||||
@@ -729,11 +750,21 @@ static inline struct clk *of_clk_src_sim
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
+static inline struct clk_hw *
|
||||
+of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+}
|
||||
static inline struct clk *of_clk_src_onecell_get(
|
||||
struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
+static inline struct clk_hw *
|
||||
+of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
|
||||
+{
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+}
|
||||
static inline int of_clk_get_parent_count(struct device_node *np)
|
||||
{
|
||||
return 0;
|
Loading…
Reference in a new issue