Hello,
this third version of the series is basically just a rebase on top of linux-next 20141009.
The first six patches are just cleanups that should be desirable on their own,
and that should make easier to review the actual per-user clock patch.
The seventh patch actually moves the per-clock data that was stored in struct
clk to a new struct clk_core and adds references to it from both struct clk and
struct clk_hw. struct clk is now ready to contain information that is specific
to a given clk consumer.
The eighth patch adds API for setting floor and ceiling constraints and stores
that information on the per-user struct clk, which is iterable from struct
clk_core.
http://cgit.collabora.com/git/user/tomeu/linux.git/log/?h=per-user-clk-constraints-v3
Thanks,
Tomeu
Tomeu Vizoso (8):
MIPS: Alchemy: Remove direct access to prepare_count field of struct
clk
clk: Remove unused function __clk_get_prepare_count
clk: Don't try to use a struct clk* after it could have been freed
clk: Don't expose __clk_get_accuracy
clk: change clk_debugfs_add_file to take a struct clk_hw
clk: Change clk_ops->determine_rate to return a clk_hw as the best
parent
clk: Make clk API return per-user struct clk instances
clk: Add floor and ceiling constraints to clock rates
Documentation/clk.txt | 2 +-
arch/arm/mach-omap2/cclock3xxx_data.c | 108 +++--
arch/arm/mach-omap2/clock.h | 11 +-
arch/arm/mach-omap2/clock_common_data.c | 5 +-
arch/mips/alchemy/common/clock.c | 17 +-
drivers/clk/at91/clk-programmable.c | 4 +-
drivers/clk/bcm/clk-kona.c | 4 +-
drivers/clk/clk-composite.c | 9 +-
drivers/clk/clk.c | 748 ++++++++++++++++++++------------
drivers/clk/clk.h | 5 +
drivers/clk/clkdev.c | 24 +-
drivers/clk/hisilicon/clk-hi3620.c | 2 +-
drivers/clk/qcom/clk-rcg.c | 20 +-
drivers/clk/qcom/clk-rcg2.c | 28 +-
drivers/clk/sunxi/clk-factors.c | 4 +-
drivers/clk/sunxi/clk-sun6i-ar100.c | 4 +-
include/linux/clk-private.h | 40 +-
include/linux/clk-provider.h | 30 +-
include/linux/clk.h | 18 +
19 files changed, 717 insertions(+), 366 deletions(-)
--
1.9.3
As it's only used internally, in drivers/clk/clk.c.
Signed-off-by: Tomeu Vizoso <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
drivers/clk/clk.c | 2 +-
include/linux/clk-provider.h | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 40aa7ad..3c650c4 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -596,7 +596,7 @@ out:
}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk *clk)
{
if (!clk)
return 0;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 17fb661..67c29e5 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -546,7 +546,6 @@ struct clk *__clk_get_parent(struct clk *clk);
struct clk *clk_get_parent_by_index(struct clk *clk, u8 index);
unsigned int __clk_get_enable_count(struct clk *clk);
unsigned long __clk_get_rate(struct clk *clk);
-unsigned long __clk_get_accuracy(struct clk *clk);
unsigned long __clk_get_flags(struct clk *clk);
bool __clk_is_prepared(struct clk *clk);
bool __clk_is_enabled(struct clk *clk);
--
1.9.3
As __clk_release could call kfree on clk and then we wouldn't have a safe way
of getting the module that owns the clock.
Signed-off-by: Tomeu Vizoso <[email protected]>
---
drivers/clk/clk.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d0712b7..40aa7ad 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2268,14 +2268,16 @@ int __clk_get(struct clk *clk)
void __clk_put(struct clk *clk)
{
+ struct module *owner;
+
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
clk_prepare_lock();
+ owner = clk->owner;
kref_put(&clk->ref, __clk_release);
+ module_put(owner);
clk_prepare_unlock();
-
- module_put(clk->owner);
}
/*** clk rate change notifiers ***/
--
1.9.3
Instead of struct clk, as this should be only used by providers.
Signed-off-by: Tomeu Vizoso <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
drivers/clk/clk.c | 6 +++---
include/linux/clk-provider.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 3c650c4..627dc91 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -354,13 +354,13 @@ out:
mutex_unlock(&clk_debug_lock);
}
-struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode,
+struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
void *data, const struct file_operations *fops)
{
struct dentry *d = NULL;
- if (clk->dentry)
- d = debugfs_create_file(name, mode, clk->dentry, data, fops);
+ if (hw->clk->dentry)
+ d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
return d;
}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 67c29e5..55f3b49 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -651,7 +651,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
#endif /* platform dependent I/O accessors */
#ifdef CONFIG_DEBUG_FS
-struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode,
+struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
void *data, const struct file_operations *fops);
#endif
--
1.9.3
This is in preparation for clock providers to not have to deal with struct clk.
Signed-off-by: Tomeu Vizoso <[email protected]>
---
v3: * Rebase on top of linux-next 20141009
* Update Documentation/clk.txt
---
Documentation/clk.txt | 2 +-
arch/mips/alchemy/common/clock.c | 10 +++++-----
drivers/clk/at91/clk-programmable.c | 4 ++--
drivers/clk/bcm/clk-kona.c | 4 ++--
drivers/clk/clk-composite.c | 9 +++++----
drivers/clk/clk.c | 11 +++++++----
drivers/clk/hisilicon/clk-hi3620.c | 2 +-
drivers/clk/qcom/clk-rcg.c | 20 ++++++++++++--------
drivers/clk/qcom/clk-rcg2.c | 28 +++++++++++++++++-----------
drivers/clk/sunxi/clk-factors.c | 4 ++--
drivers/clk/sunxi/clk-sun6i-ar100.c | 4 ++--
include/linux/clk-provider.h | 4 ++--
12 files changed, 58 insertions(+), 44 deletions(-)
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index 1fee72f..4ff8462 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -74,7 +74,7 @@ the operations defined in clk.h:
long (*determine_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk);
+ struct clk_hw **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw,
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index 203e440..48a9dfc 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -374,7 +374,7 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate,
static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk,
+ struct clk_hw **best_parent_clk,
int scale, int maxdiv)
{
struct clk *pc, *bpc, *free;
@@ -453,7 +453,7 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
}
*best_parent_rate = bpr;
- *best_parent_clk = bpc;
+ *best_parent_clk = __clk_get_hw(bpc);
return br;
}
@@ -547,7 +547,7 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk)
+ struct clk_hw **best_parent_clk)
{
return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
best_parent_clk, 2, 512);
@@ -679,7 +679,7 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk)
+ struct clk_hw **best_parent_clk)
{
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
int scale, maxdiv;
@@ -898,7 +898,7 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk)
+ struct clk_hw **best_parent_clk)
{
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index 62e2509..bbdb1b9 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -57,7 +57,7 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk)
+ struct clk_hw **best_parent_hw)
{
struct clk *parent = NULL;
long best_rate = -EINVAL;
@@ -84,7 +84,7 @@ static long clk_programmable_determine_rate(struct clk_hw *hw,
if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
best_rate = tmp_rate;
*best_parent_rate = parent_rate;
- *best_parent_clk = parent;
+ *best_parent_hw = __clk_get_hw(parent);
}
if (!best_rate)
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 95af2e6..1c06f6f 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1032,7 +1032,7 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
}
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate, struct clk **best_parent)
+ unsigned long *best_parent_rate, struct clk_hw **best_parent)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct clk *clk = hw->clk;
@@ -1075,7 +1075,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
if (delta < best_delta) {
best_delta = delta;
best_rate = other_rate;
- *best_parent = parent;
+ *best_parent = __clk_get_hw(parent);
*best_parent_rate = parent_rate;
}
}
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index b9355da..4386697 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -57,7 +57,7 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p)
+ struct clk_hw **best_parent_p)
{
struct clk_composite *composite = to_clk_composite(hw);
const struct clk_ops *rate_ops = composite->rate_ops;
@@ -80,8 +80,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
*best_parent_p = NULL;
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
- *best_parent_p = clk_get_parent(mux_hw->clk);
- *best_parent_rate = __clk_get_rate(*best_parent_p);
+ parent = clk_get_parent(mux_hw->clk);
+ *best_parent_p = __clk_get_hw(parent);
+ *best_parent_rate = __clk_get_rate(parent);
return rate_ops->round_rate(rate_hw, rate,
best_parent_rate);
@@ -103,7 +104,7 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
if (!rate_diff || !*best_parent_p
|| best_rate_diff > rate_diff) {
- *best_parent_p = parent;
+ *best_parent_p = __clk_get_hw(parent);
*best_parent_rate = parent_rate;
best_rate_diff = rate_diff;
best_rate = tmp_rate;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 627dc91..fb820bf 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -702,7 +702,7 @@ struct clk *__clk_lookup(const char *name)
*/
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p)
+ struct clk_hw **best_parent_p)
{
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents;
@@ -738,7 +738,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
out:
if (best_parent)
- *best_parent_p = best_parent;
+ *best_parent_p = best_parent->hw;
*best_parent_rate = best;
return best;
@@ -946,6 +946,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = 0;
struct clk *parent;
+ struct clk_hw *parent_hw;
if (!clk)
return 0;
@@ -956,7 +957,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
if (clk->ops->determine_rate)
return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
- &parent);
+ &parent_hw);
else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
@@ -1345,6 +1346,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
{
struct clk *top = clk;
struct clk *old_parent, *parent;
+ struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
int p_index = 0;
@@ -1362,7 +1364,8 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
if (clk->ops->determine_rate) {
new_rate = clk->ops->determine_rate(clk->hw, rate,
&best_parent_rate,
- &parent);
+ &parent_hw);
+ parent = parent_hw->clk;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 339945d..480c24e 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -296,7 +296,7 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p)
+ struct clk_hw **best_parent_p)
{
struct clk_mmc *mclk = to_mmc(hw);
unsigned long best = 0;
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index b6e6959..0b93972 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -368,16 +368,17 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p_hw)
{
unsigned long clk_flags;
+ struct clk *p;
f = qcom_find_freq(f, rate);
if (!f)
return -EINVAL;
clk_flags = __clk_get_flags(hw->clk);
- *p = clk_get_parent_by_index(hw->clk, f->src);
+ p = clk_get_parent_by_index(hw->clk, f->src);
if (clk_flags & CLK_SET_RATE_PARENT) {
rate = rate * f->pre_div;
if (f->n) {
@@ -387,15 +388,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
rate = tmp;
}
} else {
- rate = __clk_get_rate(*p);
+ rate = __clk_get_rate(p);
}
+ *p_hw = __clk_get_hw(p);
*p_rate = rate;
return f->freq;
}
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
@@ -403,7 +405,7 @@ static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
}
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
@@ -411,13 +413,15 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
}
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
const struct freq_tbl *f = rcg->freq_tbl;
+ struct clk *p;
- *p = clk_get_parent_by_index(hw->clk, f->src);
- *p_rate = __clk_round_rate(*p, rate);
+ p = clk_get_parent_by_index(hw->clk, f->src);
+ *p_hw = __clk_get_hw(p);
+ *p_rate = __clk_round_rate(p, rate);
return *p_rate;
}
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index cfa9eb4..08b8b37 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -175,16 +175,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p_hw)
{
unsigned long clk_flags;
+ struct clk *p;
f = qcom_find_freq(f, rate);
if (!f)
return -EINVAL;
clk_flags = __clk_get_flags(hw->clk);
- *p = clk_get_parent_by_index(hw->clk, f->src);
+ p = clk_get_parent_by_index(hw->clk, f->src);
if (clk_flags & CLK_SET_RATE_PARENT) {
if (f->pre_div) {
rate /= 2;
@@ -198,15 +199,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
rate = tmp;
}
} else {
- rate = __clk_get_rate(*p);
+ rate = __clk_get_rate(p);
}
+ *p_hw = __clk_get_hw(p);
*p_rate = rate;
return f->freq;
}
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -359,7 +361,7 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
}
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const struct freq_tbl *f = rcg->freq_tbl;
@@ -371,7 +373,7 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
u32 hid_div;
/* Force the correct parent */
- *p = clk_get_parent_by_index(hw->clk, f->src);
+ *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, f->src));
if (src_rate == 810000000)
frac = frac_table_810m;
@@ -410,18 +412,20 @@ const struct clk_ops clk_edp_pixel_ops = {
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const struct freq_tbl *f = rcg->freq_tbl;
unsigned long parent_rate, div;
u32 mask = BIT(rcg->hid_width) - 1;
+ struct clk *p;
if (rate == 0)
return -EINVAL;
- *p = clk_get_parent_by_index(hw->clk, f->src);
- *p_rate = parent_rate = __clk_round_rate(*p, rate);
+ p = clk_get_parent_by_index(hw->clk, f->src);
+ *p_hw = __clk_get_hw(p);
+ *p_rate = parent_rate = __clk_round_rate(p, rate);
div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
div = min_t(u32, div, mask);
@@ -472,14 +476,16 @@ static const struct frac_entry frac_table_pixel[] = {
};
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *p_rate, struct clk **p)
+ unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
unsigned long request, src_rate;
int delta = 100000;
const struct freq_tbl *f = rcg->freq_tbl;
const struct frac_entry *frac = frac_table_pixel;
- struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src);
+ struct clk *parent = clk_get_parent_by_index(hw->clk, f->src);
+
+ *p = __clk_get_hw(parent);
for (; frac->num; frac++) {
request = (rate * frac->den) / frac->num;
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index f83ba09..57d621d 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -81,7 +81,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p)
+ struct clk_hw **best_parent_p)
{
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents;
@@ -108,7 +108,7 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
}
if (best_parent)
- *best_parent_p = best_parent;
+ *best_parent_p = __clk_get_hw(best_parent);
*best_parent_rate = best;
return best_child_rate;
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index acca532..3d282fb 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -46,7 +46,7 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk)
+ struct clk_hw **best_parent_clk)
{
int nparents = __clk_get_num_parents(hw->clk);
long best_rate = -EINVAL;
@@ -100,7 +100,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
tmp_rate = (parent_rate >> shift) / div;
if (!*best_parent_clk || tmp_rate > best_rate) {
- *best_parent_clk = parent;
+ *best_parent_clk = __clk_get_hw(parent);
*best_parent_rate = parent_rate;
best_rate = tmp_rate;
}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 55f3b49..4ccd388 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -176,7 +176,7 @@ struct clk_ops {
unsigned long *parent_rate);
long (*determine_rate)(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_clk);
+ struct clk_hw **best_parent_hw);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long rate,
@@ -552,7 +552,7 @@ bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name);
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
- struct clk **best_parent_p);
+ struct clk_hw **best_parent_p);
/*
* FIXME clock api without lock protection
--
1.9.3
Adds a way for clock consumers to set maximum and minimum rates. This can be
used for thermal drivers to set ceiling rates, or by misc. drivers to set
floor rates to assure a minimum performance level.
Signed-off-by: Tomeu Vizoso <[email protected]>
---
drivers/clk/clk.c | 118 +++++++++++++++++++++++++++++++++-----------
include/linux/clk-private.h | 5 ++
include/linux/clk.h | 18 +++++++
3 files changed, 113 insertions(+), 28 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 4db918a..97cf1a3 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1597,30 +1597,10 @@ static void clk_change_rate(struct clk_core *clk)
clk_change_rate(clk->new_child);
}
-/**
- * clk_set_rate - specify a new rate for clk
- * @clk: the clk whose rate is being changed
- * @rate: the new rate for clk
- *
- * In the simplest case clk_set_rate will only adjust the rate of clk.
- *
- * Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to
- * propagate up to clk's parent; whether or not this happens depends on the
- * outcome of clk's .round_rate implementation. If *parent_rate is unchanged
- * after calling .round_rate then upstream parent propagation is ignored. If
- * *parent_rate comes back with a new rate for clk's parent then we propagate
- * up to clk's parent and set its rate. Upward propagation will continue
- * until either a clk does not support the CLK_SET_RATE_PARENT flag or
- * .round_rate stops requesting changes to clk's parent_rate.
- *
- * Rate changes are accomplished via tree traversal that also recalculates the
- * rates for the clocks and fires off POST_RATE_CHANGE notifiers.
- *
- * Returns 0 on success, -EERROR otherwise.
- */
-int clk_set_rate(struct clk *clk, unsigned long rate)
+static int clk_core_set_rate(struct clk_core *clk, unsigned long rate)
{
struct clk_core *top, *fail_clk;
+ struct clk *clk_user;
int ret = 0;
if (!clk)
@@ -1629,18 +1609,27 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
+ hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
+ rate = max(rate, clk_user->floor_constraint);
+ }
+
+ hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
+ if (clk_user->ceiling_constraint > 0)
+ rate = min(rate, clk_user->ceiling_constraint);
+ }
+
/* bail early if nothing to do */
- if (rate == clk_get_rate(clk))
+ if (rate == clk_core_get_rate(clk))
goto out;
- if ((clk->core->flags & CLK_SET_RATE_GATE) &&
- clk->core->prepare_count) {
+ if ((clk->flags & CLK_SET_RATE_GATE) &&
+ clk->prepare_count) {
ret = -EBUSY;
goto out;
}
/* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(clk->core, rate);
+ top = clk_calc_new_rates(clk, rate);
if (!top) {
ret = -EINVAL;
goto out;
@@ -1664,8 +1653,69 @@ out:
return ret;
}
+
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only adjust the rate of clk.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows the rate change operation to
+ * propagate up to clk's parent; whether or not this happens depends on the
+ * outcome of clk's .round_rate implementation. If *parent_rate is unchanged
+ * after calling .round_rate then upstream parent propagation is ignored. If
+ * *parent_rate comes back with a new rate for clk's parent then we propagate
+ * up to clk's parent and set its rate. Upward propagation will continue
+ * until either a clk does not support the CLK_SET_RATE_PARENT flag or
+ * .round_rate stops requesting changes to clk's parent_rate.
+ *
+ * Rate changes are accomplished via tree traversal that also recalculates the
+ * rates for the clocks and fires off POST_RATE_CHANGE notifiers.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_core_set_rate(clk->core, rate);
+}
EXPORT_SYMBOL_GPL(clk_set_rate);
+int clk_set_floor_rate(struct clk *clk, unsigned long rate)
+{
+ int ret;
+
+ clk_prepare_lock();
+
+ clk->floor_constraint = rate;
+ ret = clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_prepare_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_floor_rate);
+
+int clk_set_ceiling_rate(struct clk *clk, unsigned long rate)
+{
+ int ret;
+
+ clk_prepare_lock();
+
+ WARN(rate > 0 && rate < clk->floor_constraint,
+ "clk %s dev %s con %s: new ceiling %lu lower than existing floor %lu\n",
+ clk->core->name, clk->dev_id, clk->con_id, rate,
+ clk->floor_constraint);
+
+ clk->ceiling_constraint = rate;
+ ret = clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_prepare_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_ceiling_rate);
+
static struct clk_core *clk_core_get_parent(struct clk_core *clk)
{
struct clk_core *parent;
@@ -2082,6 +2132,8 @@ int __clk_init(struct device *dev, struct clk *clk_user)
}
}
+ INIT_HLIST_HEAD(&clk->per_user_clks);
+
/*
* optional platform-specific magic
*
@@ -2143,6 +2195,12 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(__clk_register);
+static void __clk_free_clk(struct clk *clk_user)
+{
+ hlist_del(&clk_user->child_node);
+ kfree(clk_user);
+}
+
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
@@ -2207,7 +2265,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
if (!ret)
return hw->clk;
- kfree(hw->clk);
+ __clk_free_clk(hw->clk);
fail_parent_names_copy:
while (--i >= 0)
kfree(clk->parent_names[i]);
@@ -2409,7 +2467,7 @@ int __clk_get(struct clk *clk)
void __clk_put(struct clk *clk)
{
clk_core_put(clk->core);
- kfree(clk);
+ __clk_free_clk(clk);
}
/*** clk rate change notifiers ***/
@@ -2537,6 +2595,10 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
clk->dev_id = dev_id;
clk->con_id = con_id;
+ clk_prepare_lock();
+ hlist_add_head(&clk->child_node, &hw->core->per_user_clks);
+ clk_prepare_unlock();
+
return clk;
}
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index 1cdb727..025aca2 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -50,6 +50,7 @@ struct clk_core {
struct hlist_head children;
struct hlist_node child_node;
struct hlist_node debug_node;
+ struct hlist_head per_user_clks;
unsigned int notifier_count;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
@@ -61,6 +62,10 @@ struct clk {
struct clk_core *core;
const char *dev_id;
const char *con_id;
+
+ unsigned long floor_constraint;
+ unsigned long ceiling_constraint;
+ struct hlist_node child_node;
};
/*
diff --git a/include/linux/clk.h b/include/linux/clk.h
index c7f258a..0d55570 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -302,6 +302,24 @@ long clk_round_rate(struct clk *clk, unsigned long rate);
int clk_set_rate(struct clk *clk, unsigned long rate);
/**
+ * clk_set_floor_rate - set a minimum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired minimum clock rate in Hz
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_floor_rate(struct clk *clk, unsigned long rate);
+
+/**
+ * clk_set_ceiling_rate - set a maximum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired maximum clock rate in Hz
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_ceiling_rate(struct clk *clk, unsigned long rate);
+
+/**
* clk_set_parent - set the parent clock source for this clock
* @clk: clock source
* @parent: parent clock source
--
1.9.3
Moves clock state to struct clk_core, but takes care to change as little API as
possible.
struct clk_hw still has a pointer to a struct clk, which is the
implementation's per-user clk instance, for backwards compatibility.
The struct clk that clk_get_parent() returns isn't owned by the caller, but by
the clock implementation, so the former shouldn't call clk_put() on it.
Because some boards in mach-omap2 still register clocks statically, their clock
registration had to be updated to take into account that the clock information
is stored in struct clk_core now.
Signed-off-by: Tomeu Vizoso <[email protected]>
---
v3: * Rebase on top of linux-next 20141009
v2: * Remove exported functions that aren't really used outside clk.c
* Rename new internal functions to clk_core_ prefix
* Remove redundant checks for error pointers in *_get_parent
* Change __clk_create_clk to take a struct clk_hw instead
* Match the original error behavior in clk_get_sys
---
arch/arm/mach-omap2/cclock3xxx_data.c | 108 ++++--
arch/arm/mach-omap2/clock.h | 11 +-
arch/arm/mach-omap2/clock_common_data.c | 5 +-
drivers/clk/clk.c | 630 ++++++++++++++++++++------------
drivers/clk/clk.h | 5 +
drivers/clk/clkdev.c | 24 +-
include/linux/clk-private.h | 35 +-
include/linux/clk-provider.h | 22 +-
8 files changed, 549 insertions(+), 291 deletions(-)
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index eb8c75e..9b210df 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -82,7 +82,7 @@ DEFINE_CLK_MUX(osc_sys_ck, osc_sys_ck_parent_names, NULL, 0x0,
OMAP3430_PRM_CLKSEL, OMAP3430_SYS_CLKIN_SEL_SHIFT,
OMAP3430_SYS_CLKIN_SEL_WIDTH, 0x0, NULL);
-DEFINE_CLK_DIVIDER(sys_ck, "osc_sys_ck", &osc_sys_ck, 0x0,
+DEFINE_CLK_DIVIDER(sys_ck, "osc_sys_ck", &osc_sys_ck_core, 0x0,
OMAP3430_PRM_CLKSRC_CTRL, OMAP_SYSCLKDIV_SHIFT,
OMAP_SYSCLKDIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
@@ -131,7 +131,7 @@ static struct clk_hw_omap dpll3_ck_hw = {
DEFINE_STRUCT_CLK(dpll3_ck, dpll3_ck_parent_names, dpll3_ck_ops);
-DEFINE_CLK_DIVIDER(dpll3_m2_ck, "dpll3_ck", &dpll3_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll3_m2_ck, "dpll3_ck", &dpll3_ck_core, 0x0,
OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT,
OMAP3430_CORE_DPLL_CLKOUT_DIV_WIDTH,
@@ -148,12 +148,12 @@ static const struct clk_ops core_ck_ops = {};
DEFINE_STRUCT_CLK_HW_OMAP(core_ck, NULL);
DEFINE_STRUCT_CLK(core_ck, core_ck_parent_names, core_ck_ops);
-DEFINE_CLK_DIVIDER(l3_ick, "core_ck", &core_ck, 0x0,
+DEFINE_CLK_DIVIDER(l3_ick, "core_ck", &core_ck_core, 0x0,
OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_L3_SHIFT, OMAP3430_CLKSEL_L3_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
-DEFINE_CLK_DIVIDER(l4_ick, "l3_ick", &l3_ick, 0x0,
+DEFINE_CLK_DIVIDER(l4_ick, "l3_ick", &l3_ick_core, 0x0,
OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_L4_SHIFT, OMAP3430_CLKSEL_L4_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -271,9 +271,9 @@ static struct clk_hw_omap dpll1_ck_hw = {
DEFINE_STRUCT_CLK(dpll1_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-DEFINE_CLK_FIXED_FACTOR(dpll1_x2_ck, "dpll1_ck", &dpll1_ck, 0x0, 2, 1);
+DEFINE_CLK_FIXED_FACTOR(dpll1_x2_ck, "dpll1_ck", &dpll1_ck_core, 0x0, 2, 1);
-DEFINE_CLK_DIVIDER(dpll1_x2m2_ck, "dpll1_x2_ck", &dpll1_x2_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll1_x2m2_ck, "dpll1_x2_ck", &dpll1_x2_ck_core, 0x0,
OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL),
OMAP3430_MPU_DPLL_CLKOUT_DIV_SHIFT,
OMAP3430_MPU_DPLL_CLKOUT_DIV_WIDTH,
@@ -288,7 +288,7 @@ static const char *mpu_ck_parent_names[] = {
DEFINE_STRUCT_CLK_HW_OMAP(mpu_ck, "mpu_clkdm");
DEFINE_STRUCT_CLK(mpu_ck, mpu_ck_parent_names, core_l4_ick_ops);
-DEFINE_CLK_DIVIDER(arm_fck, "mpu_ck", &mpu_ck, 0x0,
+DEFINE_CLK_DIVIDER(arm_fck, "mpu_ck", &mpu_ck_core, 0x0,
OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
OMAP3430_ST_MPU_CLK_SHIFT, OMAP3430_ST_MPU_CLK_WIDTH,
0x0, NULL);
@@ -417,7 +417,7 @@ static const struct clk_div_table dpll4_mx_ck_div_table[] = {
{ .div = 0 },
};
-DEFINE_CLK_DIVIDER(dpll4_m5_ck, "dpll4_ck", &dpll4_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll4_m5_ck, "dpll4_ck", &dpll4_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_CAM_SHIFT, OMAP3630_CLKSEL_CAM_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -459,7 +459,7 @@ static struct clk_hw_omap dpll4_m5x2_ck_hw = {
DEFINE_STRUCT_CLK_FLAGS(dpll4_m5x2_ck, dpll4_m5x2_ck_parent_names,
dpll4_m5x2_ck_ops, CLK_SET_RATE_PARENT);
-static struct clk dpll4_m5x2_ck_3630 = {
+static struct clk_core dpll4_m5x2_ck_3630_core = {
.name = "dpll4_m5x2_ck",
.hw = &dpll4_m5x2_ck_hw.hw,
.parent_names = dpll4_m5x2_ck_parent_names,
@@ -468,6 +468,10 @@ static struct clk dpll4_m5x2_ck_3630 = {
.flags = CLK_SET_RATE_PARENT,
};
+static struct clk dpll4_m5x2_ck_3630 = {
+ .core = &dpll4_m5x2_ck_3630_core,
+};
+
static struct clk cam_mclk;
static const char *cam_mclk_parent_names[] = {
@@ -483,7 +487,7 @@ static struct clk_hw_omap cam_mclk_hw = {
.clkdm_name = "cam_clkdm",
};
-static struct clk cam_mclk = {
+static struct clk_core cam_mclk_core = {
.name = "cam_mclk",
.hw = &cam_mclk_hw.hw,
.parent_names = cam_mclk_parent_names,
@@ -492,6 +496,10 @@ static struct clk cam_mclk = {
.flags = CLK_SET_RATE_PARENT,
};
+static struct clk cam_mclk = {
+ .core = &cam_mclk_core,
+};
+
static const struct clksel_rate clkout2_src_core_rates[] = {
{ .div = 1, .val = 0, .flags = RATE_IN_3XXX },
{ .div = 0 }
@@ -507,7 +515,7 @@ static const struct clksel_rate clkout2_src_96m_rates[] = {
{ .div = 0 }
};
-DEFINE_CLK_DIVIDER(dpll4_m2_ck, "dpll4_ck", &dpll4_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll4_m2_ck, "dpll4_ck", &dpll4_ck_core, 0x0,
OMAP_CM_REGADDR(PLL_MOD, OMAP3430_CM_CLKSEL3),
OMAP3430_DIV_96M_SHIFT, OMAP3630_DIV_96M_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -531,7 +539,7 @@ static struct clk_hw_omap dpll4_m2x2_ck_hw = {
DEFINE_STRUCT_CLK(dpll4_m2x2_ck, dpll4_m2x2_ck_parent_names, dpll4_m5x2_ck_ops);
-static struct clk dpll4_m2x2_ck_3630 = {
+static struct clk_core dpll4_m2x2_ck_3630_core = {
.name = "dpll4_m2x2_ck",
.hw = &dpll4_m2x2_ck_hw.hw,
.parent_names = dpll4_m2x2_ck_parent_names,
@@ -539,6 +547,10 @@ static struct clk dpll4_m2x2_ck_3630 = {
.ops = &dpll4_m5x2_ck_3630_ops,
};
+static struct clk dpll4_m2x2_ck_3630 = {
+ .core = &dpll4_m2x2_ck_3630_core,
+};
+
static struct clk omap_96m_alwon_fck;
static const char *omap_96m_alwon_fck_parent_names[] = {
@@ -563,7 +575,7 @@ static const struct clksel_rate clkout2_src_54m_rates[] = {
{ .div = 0 }
};
-DEFINE_CLK_DIVIDER_TABLE(dpll4_m3_ck, "dpll4_ck", &dpll4_ck, 0x0,
+DEFINE_CLK_DIVIDER_TABLE(dpll4_m3_ck, "dpll4_ck", &dpll4_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_TV_SHIFT, OMAP3630_CLKSEL_TV_WIDTH,
0, dpll4_mx_ck_div_table, NULL);
@@ -587,7 +599,7 @@ static struct clk_hw_omap dpll4_m3x2_ck_hw = {
DEFINE_STRUCT_CLK(dpll4_m3x2_ck, dpll4_m3x2_ck_parent_names, dpll4_m5x2_ck_ops);
-static struct clk dpll4_m3x2_ck_3630 = {
+static struct clk_core dpll4_m3x2_ck_3630_core = {
.name = "dpll4_m3x2_ck",
.hw = &dpll4_m3x2_ck_hw.hw,
.parent_names = dpll4_m3x2_ck_parent_names,
@@ -595,6 +607,10 @@ static struct clk dpll4_m3x2_ck_3630 = {
.ops = &dpll4_m5x2_ck_3630_ops,
};
+static struct clk dpll4_m3x2_ck_3630 = {
+ .core = &dpll4_m3x2_ck_3630_core,
+};
+
static const char *omap_54m_fck_parent_names[] = {
"dpll4_m3x2_ck", "sys_altclk",
};
@@ -670,7 +686,7 @@ static struct clk_hw_omap omap_48m_fck_hw = {
DEFINE_STRUCT_CLK(omap_48m_fck, omap_48m_fck_parent_names, omap_48m_fck_ops);
-DEFINE_CLK_FIXED_FACTOR(omap_12m_fck, "omap_48m_fck", &omap_48m_fck, 0x0, 1, 4);
+DEFINE_CLK_FIXED_FACTOR(omap_12m_fck, "omap_48m_fck", &omap_48m_fck_core, 0x0, 1, 4);
static struct clk core_12m_fck;
@@ -716,7 +732,7 @@ static const char *core_l3_ick_parent_names[] = {
DEFINE_STRUCT_CLK_HW_OMAP(core_l3_ick, "core_l3_clkdm");
DEFINE_STRUCT_CLK(core_l3_ick, core_l3_ick_parent_names, core_l4_ick_ops);
-DEFINE_CLK_FIXED_FACTOR(dpll3_m2x2_ck, "dpll3_m2_ck", &dpll3_m2_ck, 0x0, 2, 1);
+DEFINE_CLK_FIXED_FACTOR(dpll3_m2x2_ck, "dpll3_m2_ck", &dpll3_m2_ck_core, 0x0, 2, 1);
static struct clk corex2_fck;
@@ -798,7 +814,7 @@ static struct clk_hw_omap des2_ick_hw = {
DEFINE_STRUCT_CLK(des2_ick, aes2_ick_parent_names, aes2_ick_ops);
-DEFINE_CLK_DIVIDER(dpll1_fck, "core_ck", &core_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll1_fck, "core_ck", &core_ck_core, 0x0,
OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
OMAP3430_MPU_CLK_SRC_SHIFT, OMAP3430_MPU_CLK_SRC_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -841,18 +857,18 @@ static struct clk_hw_omap dpll2_ck_hw = {
DEFINE_STRUCT_CLK(dpll2_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-DEFINE_CLK_DIVIDER(dpll2_fck, "core_ck", &core_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll2_fck, "core_ck", &core_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
OMAP3430_IVA2_CLK_SRC_SHIFT, OMAP3430_IVA2_CLK_SRC_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
-DEFINE_CLK_DIVIDER(dpll2_m2_ck, "dpll2_ck", &dpll2_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll2_m2_ck, "dpll2_ck", &dpll2_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL2_PLL),
OMAP3430_IVA2_DPLL_CLKOUT_DIV_SHIFT,
OMAP3430_IVA2_DPLL_CLKOUT_DIV_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
-DEFINE_CLK_DIVIDER(dpll3_m3_ck, "dpll3_ck", &dpll3_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll3_m3_ck, "dpll3_ck", &dpll3_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_DIV_DPLL3_SHIFT, OMAP3430_DIV_DPLL3_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -876,7 +892,7 @@ static struct clk_hw_omap dpll3_m3x2_ck_hw = {
DEFINE_STRUCT_CLK(dpll3_m3x2_ck, dpll3_m3x2_ck_parent_names, dpll4_m5x2_ck_ops);
-static struct clk dpll3_m3x2_ck_3630 = {
+static struct clk_core dpll3_m3x2_ck_3630_core = {
.name = "dpll3_m3x2_ck",
.hw = &dpll3_m3x2_ck_hw.hw,
.parent_names = dpll3_m3x2_ck_parent_names,
@@ -884,9 +900,13 @@ static struct clk dpll3_m3x2_ck_3630 = {
.ops = &dpll4_m5x2_ck_3630_ops,
};
-DEFINE_CLK_FIXED_FACTOR(dpll3_x2_ck, "dpll3_ck", &dpll3_ck, 0x0, 2, 1);
+static struct clk dpll3_m3x2_ck_3630 = {
+ .core = &dpll3_m3x2_ck_3630_core,
+};
+
+DEFINE_CLK_FIXED_FACTOR(dpll3_x2_ck, "dpll3_ck", &dpll3_ck_core, 0x0, 2, 1);
-DEFINE_CLK_DIVIDER_TABLE(dpll4_m4_ck, "dpll4_ck", &dpll4_ck, 0x0,
+DEFINE_CLK_DIVIDER_TABLE(dpll4_m4_ck, "dpll4_ck", &dpll4_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_DSS1_SHIFT, OMAP3630_CLKSEL_DSS1_WIDTH,
0, dpll4_mx_ck_div_table, NULL);
@@ -911,7 +931,7 @@ static struct clk_hw_omap dpll4_m4x2_ck_hw = {
DEFINE_STRUCT_CLK_FLAGS(dpll4_m4x2_ck, dpll4_m4x2_ck_parent_names,
dpll4_m5x2_ck_ops, CLK_SET_RATE_PARENT);
-static struct clk dpll4_m4x2_ck_3630 = {
+static struct clk_core dpll4_m4x2_ck_3630_core = {
.name = "dpll4_m4x2_ck",
.hw = &dpll4_m4x2_ck_hw.hw,
.parent_names = dpll4_m4x2_ck_parent_names,
@@ -920,7 +940,11 @@ static struct clk dpll4_m4x2_ck_3630 = {
.flags = CLK_SET_RATE_PARENT,
};
-DEFINE_CLK_DIVIDER(dpll4_m6_ck, "dpll4_ck", &dpll4_ck, 0x0,
+static struct clk dpll4_m4x2_ck_3630 = {
+ .core = &dpll4_m4x2_ck_3630_core,
+};
+
+DEFINE_CLK_DIVIDER(dpll4_m6_ck, "dpll4_ck", &dpll4_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_DIV_DPLL4_SHIFT, OMAP3630_DIV_DPLL4_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -944,7 +968,7 @@ static struct clk_hw_omap dpll4_m6x2_ck_hw = {
DEFINE_STRUCT_CLK(dpll4_m6x2_ck, dpll4_m6x2_ck_parent_names, dpll4_m5x2_ck_ops);
-static struct clk dpll4_m6x2_ck_3630 = {
+static struct clk_core dpll4_m6x2_ck_3630_core = {
.name = "dpll4_m6x2_ck",
.hw = &dpll4_m6x2_ck_hw.hw,
.parent_names = dpll4_m6x2_ck_parent_names,
@@ -952,7 +976,11 @@ static struct clk dpll4_m6x2_ck_3630 = {
.ops = &dpll4_m5x2_ck_3630_ops,
};
-DEFINE_CLK_FIXED_FACTOR(dpll4_x2_ck, "dpll4_ck", &dpll4_ck, 0x0, 2, 1);
+static struct clk dpll4_m6x2_ck_3630 = {
+ .core = &dpll4_m6x2_ck_3630_core,
+};
+
+DEFINE_CLK_FIXED_FACTOR(dpll4_x2_ck, "dpll4_ck", &dpll4_ck_core, 0x0, 2, 1);
static struct dpll_data dpll5_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4),
@@ -989,7 +1017,7 @@ static struct clk_hw_omap dpll5_ck_hw = {
DEFINE_STRUCT_CLK(dpll5_ck, dpll3_ck_parent_names, dpll1_ck_ops);
-DEFINE_CLK_DIVIDER(dpll5_m2_ck, "dpll5_ck", &dpll5_ck, 0x0,
+DEFINE_CLK_DIVIDER(dpll5_m2_ck, "dpll5_ck", &dpll5_ck_core, 0x0,
OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL5),
OMAP3430ES2_DIV_120M_SHIFT, OMAP3430ES2_DIV_120M_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -1236,7 +1264,7 @@ static struct clk_hw_omap emu_src_ck_hw = {
DEFINE_STRUCT_CLK(emu_src_ck, emu_src_ck_parent_names, emu_src_ck_ops);
-DEFINE_CLK_DIVIDER(atclk_fck, "emu_src_ck", &emu_src_ck, 0x0,
+DEFINE_CLK_DIVIDER(atclk_fck, "emu_src_ck", &emu_src_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_CLKSEL_ATCLK_SHIFT, OMAP3430_CLKSEL_ATCLK_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -1287,7 +1315,7 @@ static struct clk_hw_omap gfx_l3_ck_hw = {
DEFINE_STRUCT_CLK(gfx_l3_ck, core_l3_ick_parent_names, aes1_ick_ops);
-DEFINE_CLK_DIVIDER(gfx_l3_fck, "l3_ick", &l3_ick, 0x0,
+DEFINE_CLK_DIVIDER(gfx_l3_fck, "l3_ick", &l3_ick_core, 0x0,
OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
OMAP_CLKSEL_GFX_SHIFT, OMAP_CLKSEL_GFX_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -2487,7 +2515,7 @@ static struct clk_hw_omap omap_96m_alwon_fck_3630_hw = {
.clksel_mask = OMAP3630_CLKSEL_96M_MASK,
};
-static struct clk omap_96m_alwon_fck_3630 = {
+static struct clk_core omap_96m_alwon_fck_3630_core = {
.name = "omap_96m_alwon_fck",
.hw = &omap_96m_alwon_fck_3630_hw.hw,
.parent_names = omap_96m_alwon_fck_3630_parent_names,
@@ -2495,6 +2523,10 @@ static struct clk omap_96m_alwon_fck_3630 = {
.ops = &omap_96m_alwon_fck_3630_ops,
};
+static struct clk omap_96m_alwon_fck_3630 = {
+ .core = &omap_96m_alwon_fck_3630_core,
+};
+
static struct clk omapctrl_ick;
static struct clk_hw_omap omapctrl_ick_hw = {
@@ -2510,12 +2542,12 @@ static struct clk_hw_omap omapctrl_ick_hw = {
DEFINE_STRUCT_CLK(omapctrl_ick, aes2_ick_parent_names, aes2_ick_ops);
-DEFINE_CLK_DIVIDER(pclk_fck, "emu_src_ck", &emu_src_ck, 0x0,
+DEFINE_CLK_DIVIDER(pclk_fck, "emu_src_ck", &emu_src_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_CLKSEL_PCLK_SHIFT, OMAP3430_CLKSEL_PCLK_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
-DEFINE_CLK_DIVIDER(pclkx2_fck, "emu_src_ck", &emu_src_ck, 0x0,
+DEFINE_CLK_DIVIDER(pclkx2_fck, "emu_src_ck", &emu_src_ck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_CLKSEL_PCLKX2_SHIFT, OMAP3430_CLKSEL_PCLKX2_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -2547,7 +2579,7 @@ static struct clk_hw_omap pka_ick_hw = {
DEFINE_STRUCT_CLK(pka_ick, pka_ick_parent_names, aes1_ick_ops);
-DEFINE_CLK_DIVIDER(rm_ick, "l4_ick", &l4_ick, 0x0,
+DEFINE_CLK_DIVIDER(rm_ick, "l4_ick", &l4_ick_core, 0x0,
OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
OMAP3430_CLKSEL_RM_SHIFT, OMAP3430_CLKSEL_RM_WIDTH,
CLK_DIVIDER_ONE_BASED, NULL);
@@ -2808,10 +2840,10 @@ DEFINE_CLK_OMAP_MUX_GATE(ssi_ssr_fck_3430es2, "core_l4_clkdm",
ssi_ssr_fck_3430es1_ops);
DEFINE_CLK_FIXED_FACTOR(ssi_sst_fck_3430es1, "ssi_ssr_fck_3430es1",
- &ssi_ssr_fck_3430es1, 0x0, 1, 2);
+ &ssi_ssr_fck_3430es1_core, 0x0, 1, 2);
DEFINE_CLK_FIXED_FACTOR(ssi_sst_fck_3430es2, "ssi_ssr_fck_3430es2",
- &ssi_ssr_fck_3430es2, 0x0, 1, 2);
+ &ssi_ssr_fck_3430es2_core, 0x0, 1, 2);
static struct clk sys_clkout1;
@@ -2829,7 +2861,7 @@ static struct clk_hw_omap sys_clkout1_hw = {
DEFINE_STRUCT_CLK(sys_clkout1, sys_clkout1_parent_names, aes1_ick_ops);
-DEFINE_CLK_DIVIDER(sys_clkout2, "clkout2_src_ck", &clkout2_src_ck, 0x0,
+DEFINE_CLK_DIVIDER(sys_clkout2, "clkout2_src_ck", &clkout2_src_ck_core, 0x0,
OMAP3430_CM_CLKOUT_CTRL, OMAP3430_CLKOUT2_DIV_SHIFT,
OMAP3430_CLKOUT2_DIV_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
@@ -2838,7 +2870,7 @@ DEFINE_CLK_MUX(traceclk_src_fck, emu_src_ck_parent_names, NULL, 0x0,
OMAP3430_TRACE_MUX_CTRL_SHIFT, OMAP3430_TRACE_MUX_CTRL_WIDTH,
0x0, NULL);
-DEFINE_CLK_DIVIDER(traceclk_fck, "traceclk_src_fck", &traceclk_src_fck, 0x0,
+DEFINE_CLK_DIVIDER(traceclk_fck, "traceclk_src_fck", &traceclk_src_fck_core, 0x0,
OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
OMAP3430_CLKSEL_TRACECLK_SHIFT,
OMAP3430_CLKSEL_TRACECLK_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 4592a27..1e42f26 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -40,23 +40,29 @@ struct omap_clk {
struct clockdomain;
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \
- static struct clk _name = { \
+ static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
+ }; \
+ static struct clk _name = { \
+ .core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \
_clkops_name, _flags) \
- static struct clk _name = { \
+ static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
.flags = _flags, \
+ }; \
+ static struct clk _name = { \
+ .core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \
@@ -247,6 +253,7 @@ extern const struct clksel_rate gpt_32k_rates[];
extern const struct clksel_rate gpt_sys_rates[];
extern const struct clksel_rate gfx_l3_rates[];
extern const struct clksel_rate dsp_ick_rates[];
+extern struct clk_core dummy_ck_core;
extern struct clk dummy_ck;
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
diff --git a/arch/arm/mach-omap2/clock_common_data.c b/arch/arm/mach-omap2/clock_common_data.c
index ef4d21b..febd0a2 100644
--- a/arch/arm/mach-omap2/clock_common_data.c
+++ b/arch/arm/mach-omap2/clock_common_data.c
@@ -119,8 +119,11 @@ const struct clksel_rate div31_1to31_rates[] = {
static struct clk_ops dummy_ck_ops = {};
-struct clk dummy_ck = {
+struct clk_core dummy_ck_core = {
.name = "dummy_clk",
.ops = &dummy_ck_ops,
.flags = CLK_IS_BASIC,
};
+struct clk dummy_ck = {
+ .core = &dummy_ck_core,
+};
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index fb820bf..4db918a 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -37,6 +37,15 @@ static HLIST_HEAD(clk_root_list);
static HLIST_HEAD(clk_orphan_list);
static LIST_HEAD(clk_notifier_list);
+static long clk_core_get_accuracy(struct clk_core *clk);
+static unsigned long clk_core_get_rate(struct clk_core *clk);
+static int clk_core_get_phase(struct clk_core *clk);
+static struct clk_core *clk_core_get_parent(struct clk_core *clk);
+static bool clk_core_is_prepared(struct clk_core *clk);
+static bool clk_core_is_enabled(struct clk_core *clk);
+static long clk_core_round_rate(struct clk_core *clk, unsigned long rate);
+static struct clk_core *clk_core_lookup(const char *name);
+
/*** locking ***/
static void clk_prepare_lock(void)
{
@@ -114,7 +123,7 @@ static struct hlist_head *orphan_list[] = {
NULL,
};
-static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, int level)
{
if (!c)
return;
@@ -122,14 +131,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
level * 3 + 1, "",
30 - level * 3, c->name,
- c->enable_count, c->prepare_count, clk_get_rate(c),
- clk_get_accuracy(c), clk_get_phase(c));
+ c->enable_count, c->prepare_count, clk_core_get_rate(c),
+ clk_core_get_accuracy(c), clk_core_get_phase(c));
}
-static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -142,7 +151,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
static int clk_summary_show(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
struct hlist_head **lists = (struct hlist_head **)s->private;
seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
@@ -172,7 +181,7 @@ static const struct file_operations clk_summary_fops = {
.release = single_release,
};
-static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
{
if (!c)
return;
@@ -180,14 +189,14 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "\"%s\": { ", c->name);
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
- seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
- seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c));
- seq_printf(s, "\"phase\": %d", clk_get_phase(c));
+ seq_printf(s, "\"rate\": %lu", clk_core_get_rate(c));
+ seq_printf(s, "\"accuracy\": %lu", clk_core_get_accuracy(c));
+ seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
}
-static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -204,7 +213,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
static int clk_dump(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
bool first_node = true;
struct hlist_head **lists = (struct hlist_head **)s->private;
@@ -241,7 +250,7 @@ static const struct file_operations clk_dump_fops = {
};
/* caller must hold prepare_lock */
-static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry)
{
struct dentry *d;
int ret = -ENOMEM;
@@ -316,7 +325,7 @@ out:
* initialized. Otherwise it bails out early since the debugfs clk tree
* will be created lazily by clk_debug_init as part of a late_initcall.
*/
-static int clk_debug_register(struct clk *clk)
+static int clk_debug_register(struct clk_core *clk)
{
int ret = 0;
@@ -341,7 +350,7 @@ unlock:
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
*/
-static void clk_debug_unregister(struct clk *clk)
+static void clk_debug_unregister(struct clk_core *clk)
{
mutex_lock(&clk_debug_lock);
if (!clk->dentry)
@@ -359,8 +368,8 @@ struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
{
struct dentry *d = NULL;
- if (hw->clk->dentry)
- d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
+ if (hw->core->dentry)
+ d = debugfs_create_file(name, mode, hw->core->dentry, data, fops);
return d;
}
@@ -380,7 +389,7 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
*/
static int __init clk_debug_init(void)
{
- struct clk *clk;
+ struct clk_core *clk;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
@@ -419,19 +428,20 @@ static int __init clk_debug_init(void)
}
late_initcall(clk_debug_init);
#else
-static inline int clk_debug_register(struct clk *clk) { return 0; }
-static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+static inline int clk_debug_register(struct clk_core *clk) { return 0; }
+static inline void clk_debug_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
}
-static inline void clk_debug_unregister(struct clk *clk)
+static inline void clk_debug_unregister(struct clk_core *clk)
{
}
#endif
/* caller must hold prepare_lock */
-static void clk_unprepare_unused_subtree(struct clk *clk)
+static void clk_unprepare_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
if (!clk)
return;
@@ -445,7 +455,7 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED)
return;
- if (__clk_is_prepared(clk)) {
+ if (clk_core_is_prepared(clk)) {
if (clk->ops->unprepare_unused)
clk->ops->unprepare_unused(clk->hw);
else if (clk->ops->unprepare)
@@ -454,9 +464,9 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
}
/* caller must hold prepare_lock */
-static void clk_disable_unused_subtree(struct clk *clk)
+static void clk_disable_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long flags;
if (!clk)
@@ -478,7 +488,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
* sequence. call .disable_unused if available, otherwise fall
* back to .disable
*/
- if (__clk_is_enabled(clk)) {
+ if (clk_core_is_enabled(clk)) {
if (clk->ops->disable_unused)
clk->ops->disable_unused(clk->hw);
else if (clk->ops->disable)
@@ -502,7 +512,7 @@ __setup("clk_ignore_unused", clk_ignore_unused_setup);
static int clk_disable_unused(void)
{
- struct clk *clk;
+ struct clk_core *clk;
if (clk_ignore_unused) {
pr_warn("clk: Not disabling unused clocks\n");
@@ -533,48 +543,59 @@ late_initcall_sync(clk_disable_unused);
const char *__clk_get_name(struct clk *clk)
{
- return !clk ? NULL : clk->name;
+ return !clk ? NULL : clk->core->name;
}
EXPORT_SYMBOL_GPL(__clk_get_name);
struct clk_hw *__clk_get_hw(struct clk *clk)
{
- return !clk ? NULL : clk->hw;
+ return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);
u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? 0 : clk->num_parents;
+ return !clk ? 0 : clk->core->num_parents;
}
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
struct clk *__clk_get_parent(struct clk *clk)
{
- return !clk ? NULL : clk->parent;
+ /* TODO: Create a per-user clk and change callers to call clk_put */
+ return !clk ? NULL : clk->core->parent->hw->clk;
}
EXPORT_SYMBOL_GPL(__clk_get_parent);
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk,
+ u8 index)
{
if (!clk || index >= clk->num_parents)
return NULL;
else if (!clk->parents)
- return __clk_lookup(clk->parent_names[index]);
+ return clk_core_lookup(clk->parent_names[index]);
else if (!clk->parents[index])
return clk->parents[index] =
- __clk_lookup(clk->parent_names[index]);
+ clk_core_lookup(clk->parent_names[index]);
else
return clk->parents[index];
}
+
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+ struct clk_core *parent;
+
+ parent = clk_core_get_parent_by_index(clk->core, index);
+
+ return !parent ? NULL : parent->hw->clk;
+}
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? 0 : clk->enable_count;
+ return !clk ? 0 : clk->core->enable_count;
}
-unsigned long __clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate_nolock(struct clk_core *clk)
{
unsigned long ret;
@@ -594,9 +615,14 @@ unsigned long __clk_get_rate(struct clk *clk)
out:
return ret;
}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+ return clk_core_get_rate_nolock(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-static unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk_core *clk)
{
if (!clk)
return 0;
@@ -606,11 +632,11 @@ static unsigned long __clk_get_accuracy(struct clk *clk)
unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? 0 : clk->flags;
+ return !clk ? 0 : clk->core->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
-bool __clk_is_prepared(struct clk *clk)
+static bool clk_core_is_prepared(struct clk_core *clk)
{
int ret;
@@ -631,7 +657,12 @@ out:
return !!ret;
}
-bool __clk_is_enabled(struct clk *clk)
+bool __clk_is_prepared(struct clk *clk)
+{
+ return clk_core_is_prepared(clk->core);
+}
+
+static bool clk_core_is_enabled(struct clk_core *clk)
{
int ret;
@@ -651,12 +682,17 @@ bool __clk_is_enabled(struct clk *clk)
out:
return !!ret;
}
+
+bool __clk_is_enabled(struct clk *clk)
+{
+ return clk_core_is_enabled(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_is_enabled);
-static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+static struct clk_core *__clk_lookup_subtree(const char *name, struct clk_core *clk)
{
- struct clk *child;
- struct clk *ret;
+ struct clk_core *child;
+ struct clk_core *ret;
if (!strcmp(clk->name, name))
return clk;
@@ -670,10 +706,10 @@ static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
return NULL;
}
-struct clk *__clk_lookup(const char *name)
+static struct clk_core *clk_core_lookup(const char *name)
{
- struct clk *root_clk;
- struct clk *ret;
+ struct clk_core *root_clk;
+ struct clk_core *ret;
if (!name)
return NULL;
@@ -695,6 +731,13 @@ struct clk *__clk_lookup(const char *name)
return NULL;
}
+struct clk *__clk_lookup(const char *name)
+{
+ struct clk_core *clk = clk_core_lookup(name);
+
+ return !clk ? NULL : clk->hw->clk;
+}
+
/*
* Helper for finding best parent to provide a given frequency. This can be used
* directly as a determine_rate callback (e.g. for a mux), or from a more
@@ -704,7 +747,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ struct clk_core *clk = hw->clk->core, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0;
@@ -712,24 +755,24 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
parent = clk->parent;
if (clk->flags & CLK_SET_RATE_PARENT)
- best = __clk_round_rate(parent, rate);
+ best = clk_core_round_rate(parent, rate);
else if (parent)
- best = __clk_get_rate(parent);
+ best = clk_core_get_rate(parent);
else
- best = __clk_get_rate(clk);
+ best = clk_core_get_rate(clk);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
num_parents = clk->num_parents;
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_core_get_parent_by_index(clk, i);
if (!parent)
continue;
if (clk->flags & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ parent_rate = clk_core_round_rate(parent, rate);
else
- parent_rate = __clk_get_rate(parent);
+ parent_rate = clk_core_get_rate(parent);
if (parent_rate <= rate && parent_rate > best) {
best_parent = parent;
best = parent_rate;
@@ -747,7 +790,7 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
/*** clk api ***/
-void __clk_unprepare(struct clk *clk)
+static void clk_core_unprepare(struct clk_core *clk)
{
if (!clk)
return;
@@ -763,7 +806,12 @@ void __clk_unprepare(struct clk *clk)
if (clk->ops->unprepare)
clk->ops->unprepare(clk->hw);
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
+}
+
+void __clk_unprepare(struct clk *clk)
+{
+ clk_core_unprepare(clk->core);
}
/**
@@ -788,7 +836,7 @@ void clk_unprepare(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_unprepare);
-int __clk_prepare(struct clk *clk)
+static int clk_core_prepare(struct clk_core *clk)
{
int ret = 0;
@@ -796,14 +844,14 @@ int __clk_prepare(struct clk *clk)
return 0;
if (clk->prepare_count == 0) {
- ret = __clk_prepare(clk->parent);
+ ret = clk_core_prepare(clk->parent);
if (ret)
return ret;
if (clk->ops->prepare) {
ret = clk->ops->prepare(clk->hw);
if (ret) {
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
return ret;
}
}
@@ -814,6 +862,11 @@ int __clk_prepare(struct clk *clk)
return 0;
}
+int __clk_prepare(struct clk *clk)
+{
+ return clk_core_prepare(clk->core);
+}
+
/**
* clk_prepare - prepare a clock source
* @clk: the clk being prepared
@@ -838,7 +891,7 @@ int clk_prepare(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_prepare);
-static void __clk_disable(struct clk *clk)
+static void clk_core_disable(struct clk_core *clk)
{
if (!clk)
return;
@@ -852,7 +905,12 @@ static void __clk_disable(struct clk *clk)
if (clk->ops->disable)
clk->ops->disable(clk->hw);
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ clk_core_disable(clk->core);
}
/**
@@ -880,7 +938,7 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_disable);
-static int __clk_enable(struct clk *clk)
+static int clk_core_enable(struct clk_core *clk)
{
int ret = 0;
@@ -891,7 +949,7 @@ static int __clk_enable(struct clk *clk)
return -ESHUTDOWN;
if (clk->enable_count == 0) {
- ret = __clk_enable(clk->parent);
+ ret = clk_core_enable(clk->parent);
if (ret)
return ret;
@@ -899,7 +957,7 @@ static int __clk_enable(struct clk *clk)
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
return ret;
}
}
@@ -909,6 +967,11 @@ static int __clk_enable(struct clk *clk)
return 0;
}
+static int __clk_enable(struct clk *clk)
+{
+ return clk_core_enable(clk->core);
+}
+
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated
@@ -935,17 +998,11 @@ int clk_enable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_enable);
-/**
- * __clk_round_rate - round the given rate for a clk
- * @clk: round the rate of this clock
- * @rate: the rate which is to be rounded
- *
- * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
- */
-unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
+ unsigned long rate)
{
unsigned long parent_rate = 0;
- struct clk *parent;
+ struct clk_core *parent;
struct clk_hw *parent_hw;
if (!clk)
@@ -961,12 +1018,35 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
- return __clk_round_rate(clk->parent, rate);
+ return clk_core_round_rate_nolock(clk->parent, rate);
else
return clk->rate;
}
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ * @rate: the rate which is to be rounded
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_core_round_rate_nolock(clk->core, rate);
+}
EXPORT_SYMBOL_GPL(__clk_round_rate);
+static long clk_core_round_rate(struct clk_core *clk, unsigned long rate)
+{
+ unsigned long ret;
+
+ clk_prepare_lock();
+ ret = clk_core_round_rate_nolock(clk, rate);
+ clk_prepare_unlock();
+
+ return ret;
+}
+
/**
* clk_round_rate - round the given rate for a clk
* @clk: the clk for which we are rounding a rate
@@ -978,13 +1058,7 @@ EXPORT_SYMBOL_GPL(__clk_round_rate);
*/
long clk_round_rate(struct clk *clk, unsigned long rate)
{
- unsigned long ret;
-
- clk_prepare_lock();
- ret = __clk_round_rate(clk, rate);
- clk_prepare_unlock();
-
- return ret;
+ return clk_core_round_rate(clk->core, rate);
}
EXPORT_SYMBOL_GPL(clk_round_rate);
@@ -1002,22 +1076,21 @@ EXPORT_SYMBOL_GPL(clk_round_rate);
* called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
* a driver returns that.
*/
-static int __clk_notify(struct clk *clk, unsigned long msg,
+static int __clk_notify(struct clk_core *clk, unsigned long msg,
unsigned long old_rate, unsigned long new_rate)
{
struct clk_notifier *cn;
struct clk_notifier_data cnd;
int ret = NOTIFY_DONE;
- cnd.clk = clk;
cnd.old_rate = old_rate;
cnd.new_rate = new_rate;
list_for_each_entry(cn, &clk_notifier_list, node) {
- if (cn->clk == clk) {
+ if (cn->clk->core == clk) {
+ cnd.clk = cn->clk;
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
- break;
}
}
@@ -1035,10 +1108,10 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_accuracies(struct clk *clk)
+static void __clk_recalc_accuracies(struct clk_core *clk)
{
unsigned long parent_accuracy = 0;
- struct clk *child;
+ struct clk_core *child;
if (clk->parent)
parent_accuracy = clk->parent->accuracy;
@@ -1053,16 +1126,7 @@ static void __clk_recalc_accuracies(struct clk *clk)
__clk_recalc_accuracies(child);
}
-/**
- * clk_get_accuracy - return the accuracy of clk
- * @clk: the clk whose accuracy is being returned
- *
- * Simply returns the cached accuracy of the clk, unless
- * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be
- * issued.
- * If clk is NULL then returns 0.
- */
-long clk_get_accuracy(struct clk *clk)
+static long clk_core_get_accuracy(struct clk_core *clk)
{
unsigned long accuracy;
@@ -1075,9 +1139,24 @@ long clk_get_accuracy(struct clk *clk)
return accuracy;
}
+
+/**
+ * clk_get_accuracy - return the accuracy of clk
+ * @clk: the clk whose accuracy is being returned
+ *
+ * Simply returns the cached accuracy of the clk, unless
+ * CLK_GET_ACCURACY_NOCACHE flag is set, which means a recalc_rate will be
+ * issued.
+ * If clk is NULL then returns 0.
+ */
+long clk_get_accuracy(struct clk *clk)
+{
+ return clk_core_get_accuracy(clk->core);
+}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
-static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+static unsigned long clk_recalc(struct clk_core *clk,
+ unsigned long parent_rate)
{
if (clk->ops->recalc_rate)
return clk->ops->recalc_rate(clk->hw, parent_rate);
@@ -1098,11 +1177,11 @@ static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
{
unsigned long old_rate;
unsigned long parent_rate = 0;
- struct clk *child;
+ struct clk_core *child;
old_rate = clk->rate;
@@ -1122,15 +1201,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
__clk_recalc_rates(child, msg);
}
-/**
- * clk_get_rate - return the rate of clk
- * @clk: the clk whose rate is being returned
- *
- * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
- * is set, which means a recalc_rate will be issued.
- * If clk is NULL then returns 0.
- */
-unsigned long clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate(struct clk_core *clk)
{
unsigned long rate;
@@ -1139,14 +1210,29 @@ unsigned long clk_get_rate(struct clk *clk)
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
__clk_recalc_rates(clk, 0);
- rate = __clk_get_rate(clk);
+ rate = clk_core_get_rate_nolock(clk);
clk_prepare_unlock();
return rate;
}
+EXPORT_SYMBOL_GPL(clk_core_get_rate);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
+ * is set, which means a recalc_rate will be issued.
+ * If clk is NULL then returns 0.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk_core_get_rate(clk->core);
+}
EXPORT_SYMBOL_GPL(clk_get_rate);
-static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+static int clk_fetch_parent_index(struct clk_core *clk,
+ struct clk_core *parent)
{
int i;
@@ -1160,7 +1246,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
/*
* find index of new parent clock using cached parent ptrs,
* or if not yet cached, use string name comparison and cache
- * them now to avoid future calls to __clk_lookup.
+ * them now to avoid future calls to clk_core_lookup.
*/
for (i = 0; i < clk->num_parents; i++) {
if (clk->parents[i] == parent)
@@ -1170,7 +1256,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
continue;
if (!strcmp(clk->parent_names[i], parent->name)) {
- clk->parents[i] = __clk_lookup(parent->name);
+ clk->parents[i] = clk_core_lookup(parent->name);
return i;
}
}
@@ -1178,7 +1264,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
return -EINVAL;
}
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_reparent(struct clk_core *clk, struct clk_core *new_parent)
{
hlist_del(&clk->child_node);
@@ -1195,10 +1281,11 @@ static void clk_reparent(struct clk *clk, struct clk *new_parent)
clk->parent = new_parent;
}
-static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
+static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
+ struct clk_core *parent)
{
unsigned long flags;
- struct clk *old_parent = clk->parent;
+ struct clk_core *old_parent = clk->parent;
/*
* Migrate prepare state between parents and prevent race with
@@ -1218,9 +1305,9 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
- __clk_prepare(parent);
- clk_enable(parent);
- clk_enable(clk);
+ clk_core_prepare(parent);
+ clk_core_enable(parent);
+ clk_core_enable(clk);
}
/* update the clk tree topology */
@@ -1231,25 +1318,27 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
return old_parent;
}
-static void __clk_set_parent_after(struct clk *clk, struct clk *parent,
- struct clk *old_parent)
+static void __clk_set_parent_after(struct clk_core *clk,
+ struct clk_core *parent,
+ struct clk_core *old_parent)
{
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(old_parent);
- __clk_unprepare(old_parent);
+ clk_core_disable(clk);
+ clk_core_disable(old_parent);
+ clk_core_unprepare(old_parent);
}
}
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
+ u8 p_index)
{
unsigned long flags;
int ret = 0;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_parent = __clk_set_parent_before(clk, parent);
@@ -1263,9 +1352,9 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
clk_enable_unlock(flags);
if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(parent);
- __clk_unprepare(parent);
+ clk_core_disable(clk);
+ clk_core_disable(parent);
+ clk_core_unprepare(parent);
}
return ret;
}
@@ -1291,9 +1380,10 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
*
* Caller must hold prepare_lock.
*/
-static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+static int __clk_speculate_rates(struct clk_core *clk,
+ unsigned long parent_rate)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long new_rate;
int ret = NOTIFY_DONE;
@@ -1319,10 +1409,10 @@ out:
return ret;
}
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
- struct clk *new_parent, u8 p_index)
+static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
+ struct clk_core *new_parent, u8 p_index)
{
- struct clk *child;
+ struct clk_core *child;
clk->new_rate = new_rate;
clk->new_parent = new_parent;
@@ -1342,10 +1432,11 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
* calculate the new rates returning the topmost clock that has to be
* changed.
*/
-static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
+ unsigned long rate)
{
- struct clk *top = clk;
- struct clk *old_parent, *parent;
+ struct clk_core *top = clk;
+ struct clk_core *old_parent, *parent;
struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
@@ -1365,7 +1456,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
new_rate = clk->ops->determine_rate(clk->hw, rate,
&best_parent_rate,
&parent_hw);
- parent = parent_hw->clk;
+ parent = parent_hw->core;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
@@ -1413,9 +1504,10 @@ out:
* so that in case of an error we can walk down the whole tree again and
* abort the change.
*/
-static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
+ unsigned long event)
{
- struct clk *child, *tmp_clk, *fail_clk = NULL;
+ struct clk_core *child, *tmp_clk, *fail_clk = NULL;
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
@@ -1450,14 +1542,14 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
* walk down a subtree and set the new rates notifying the rate
* change on the way
*/
-static void clk_change_rate(struct clk *clk)
+static void clk_change_rate(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
struct hlist_node *tmp;
unsigned long old_rate;
unsigned long best_parent_rate = 0;
bool skip_set_rate = false;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_rate = clk->rate;
@@ -1528,7 +1620,7 @@ static void clk_change_rate(struct clk *clk)
*/
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- struct clk *top, *fail_clk;
+ struct clk_core *top, *fail_clk;
int ret = 0;
if (!clk)
@@ -1541,13 +1633,14 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
if (rate == clk_get_rate(clk))
goto out;
- if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
+ if ((clk->core->flags & CLK_SET_RATE_GATE) &&
+ clk->core->prepare_count) {
ret = -EBUSY;
goto out;
}
/* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(clk, rate);
+ top = clk_calc_new_rates(clk->core, rate);
if (!top) {
ret = -EINVAL;
goto out;
@@ -1573,6 +1666,18 @@ out:
}
EXPORT_SYMBOL_GPL(clk_set_rate);
+static struct clk_core *clk_core_get_parent(struct clk_core *clk)
+{
+ struct clk_core *parent;
+
+ clk_prepare_lock();
+ parent = !clk ? NULL : clk->parent;
+ clk_prepare_unlock();
+
+ return parent;
+}
+EXPORT_SYMBOL_GPL(clk_core_get_parent);
+
/**
* clk_get_parent - return the parent of a clk
* @clk: the clk whose parent gets returned
@@ -1581,13 +1686,11 @@ EXPORT_SYMBOL_GPL(clk_set_rate);
*/
struct clk *clk_get_parent(struct clk *clk)
{
- struct clk *parent;
+ struct clk_core *parent;
- clk_prepare_lock();
- parent = __clk_get_parent(clk);
- clk_prepare_unlock();
+ parent = clk_core_get_parent(clk->core);
- return parent;
+ return !parent ? NULL : parent->hw->clk;
}
EXPORT_SYMBOL_GPL(clk_get_parent);
@@ -1598,11 +1701,11 @@ EXPORT_SYMBOL_GPL(clk_get_parent);
*
* For single-parent clocks without .get_parent, first check to see if the
* .parents array exists, and if so use it to avoid an expensive tree
- * traversal. If .parents does not exist then walk the tree with __clk_lookup.
+ * traversal. If .parents does not exist then walk the tree.
*/
-static struct clk *__clk_init_parent(struct clk *clk)
+static struct clk_core *__clk_init_parent(struct clk_core *clk)
{
- struct clk *ret = NULL;
+ struct clk_core *ret = NULL;
u8 index;
/* handle the trivial cases */
@@ -1612,7 +1715,7 @@ static struct clk *__clk_init_parent(struct clk *clk)
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+ ret = clk->parent = clk_core_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
@@ -1626,8 +1729,8 @@ static struct clk *__clk_init_parent(struct clk *clk)
/*
* Do our best to cache parent clocks in clk->parents. This prevents
- * unnecessary and expensive calls to __clk_lookup. We don't set
- * clk->parent here; that is done by the calling function
+ * unnecessary and expensive lookups. We don't set clk->parent here;
+ * that is done by the calling function.
*/
index = clk->ops->get_parent(clk->hw);
@@ -1637,37 +1740,26 @@ static struct clk *__clk_init_parent(struct clk *clk)
kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
- ret = clk_get_parent_by_index(clk, index);
+ ret = clk_core_get_parent_by_index(clk, index);
out:
return ret;
}
-void __clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_core_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
clk_reparent(clk, new_parent);
__clk_recalc_accuracies(clk);
__clk_recalc_rates(clk, POST_RATE_CHANGE);
}
-/**
- * clk_set_parent - switch the parent of a mux clk
- * @clk: the mux clk whose input we are switching
- * @parent: the new input to clk
- *
- * Re-parent clk to use parent as its new input source. If clk is in
- * prepared state, the clk will get enabled for the duration of this call. If
- * that's not acceptable for a specific clk (Eg: the consumer can't handle
- * that, the reparenting is glitchy in hardware, etc), use the
- * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
- *
- * After successfully changing clk's parent clk_set_parent will update the
- * clk topology, sysfs topology and propagate rate recalculation via
- * __clk_recalc_rates.
- *
- * Returns 0 on success, -EERROR otherwise.
- */
-int clk_set_parent(struct clk *clk, struct clk *parent)
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+ clk_core_reparent(clk->core, new_parent->core);
+}
+
+static int clk_core_set_parent(struct clk_core *clk, struct clk_core *parent)
{
int ret = 0;
int p_index = 0;
@@ -1727,6 +1819,28 @@ out:
return ret;
}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as its new input source. If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ return clk_core_set_parent(clk->core, parent->core);
+}
EXPORT_SYMBOL_GPL(clk_set_parent);
/**
@@ -1763,13 +1877,13 @@ int clk_set_phase(struct clk *clk, int degrees)
clk_prepare_lock();
- if (!clk->ops->set_phase)
+ if (!clk->core->ops->set_phase)
goto out_unlock;
- ret = clk->ops->set_phase(clk->hw, degrees);
+ ret = clk->core->ops->set_phase(clk->core->hw, degrees);
if (!ret)
- clk->phase = degrees;
+ clk->core->phase = degrees;
out_unlock:
clk_prepare_unlock();
@@ -1778,14 +1892,7 @@ out:
return ret;
}
-/**
- * clk_get_phase - return the phase shift of a clock signal
- * @clk: clock signal source
- *
- * Returns the phase shift of a clock node in degrees, otherwise returns
- * -EERROR.
- */
-int clk_get_phase(struct clk *clk)
+static int clk_core_get_phase(struct clk_core *clk)
{
int ret = 0;
@@ -1801,18 +1908,31 @@ out:
}
/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk)
+{
+ return clk_core_get_phase(clk->core);
+}
+
+/**
* __clk_init - initialize the data structures in a struct clk
* @dev: device initializing this clk, placeholder for now
* @clk: clk being initialized
*
- * Initializes the lists in struct clk, queries the hardware for the
+ * Initializes the lists in struct clk_core, queries the hardware for the
* parent and rate and sets them both.
*/
-int __clk_init(struct device *dev, struct clk *clk)
+int __clk_init(struct device *dev, struct clk *clk_user)
{
int i, ret = 0;
- struct clk *orphan;
+ struct clk_core *orphan;
struct hlist_node *tmp2;
+ struct clk_core *clk = clk_user->core;
if (!clk)
return -EINVAL;
@@ -1820,7 +1940,7 @@ int __clk_init(struct device *dev, struct clk *clk)
clk_prepare_lock();
/* check to see if a clock with this name is already registered */
- if (__clk_lookup(clk->name)) {
+ if (clk_core_lookup(clk->name)) {
pr_debug("%s: clk %s already initialized\n",
__func__, clk->name);
ret = -EEXIST;
@@ -1872,7 +1992,7 @@ int __clk_init(struct device *dev, struct clk *clk)
clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
/*
- * __clk_lookup returns NULL for parents that have not been
+ * clk_core_lookup returns NULL for parents that have not been
* clk_init'd; thus any access to clk->parents[] must check
* for a NULL pointer. We can always perform lazy lookups for
* missing parents later on.
@@ -1880,7 +2000,7 @@ int __clk_init(struct device *dev, struct clk *clk)
if (clk->parents)
for (i = 0; i < clk->num_parents; i++)
clk->parents[i] =
- __clk_lookup(clk->parent_names[i]);
+ clk_core_lookup(clk->parent_names[i]);
}
clk->parent = __clk_init_parent(clk);
@@ -1936,7 +2056,7 @@ int __clk_init(struct device *dev, struct clk *clk)
*/
if (clk->ops->recalc_rate)
clk->rate = clk->ops->recalc_rate(clk->hw,
- __clk_get_rate(clk->parent));
+ clk_core_get_rate_nolock(clk->parent));
else if (clk->parent)
clk->rate = clk->parent->rate;
else
@@ -1951,13 +2071,13 @@ int __clk_init(struct device *dev, struct clk *clk)
if (orphan->num_parents && orphan->ops->get_parent) {
i = orphan->ops->get_parent(orphan->hw);
if (!strcmp(clk->name, orphan->parent_names[i]))
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
continue;
}
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
break;
}
}
@@ -1983,12 +2103,13 @@ out:
/**
* __clk_register - register a clock and return a cookie.
*
- * Same as clk_register, except that the .clk field inside hw shall point to a
- * preallocated (generally statically allocated) struct clk. None of the fields
- * of the struct clk need to be initialized.
+ * Same as clk_register, except that the .core and .clk fields inside hw shall
+ * point to preallocated (generally statically allocated) struct clk_core, and
+ * struct clk (respectively). None of the fields of the struct clk_core need
+ * to be initialized.
*
- * The data pointed to by .init and .clk field shall NOT be marked as init
- * data.
+ * The data pointed to by .init, .core and .clk field shall NOT be marked as
+ * init data.
*
* __clk_register is only exposed via clk-private.h and is intended for use with
* very large numbers of clocks that need to be statically initialized. It is
@@ -2000,9 +2121,9 @@ out:
struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
{
int ret;
- struct clk *clk;
+ struct clk_core *clk;
- clk = hw->clk;
+ clk = hw->core;
clk->name = hw->init->name;
clk->ops = hw->init->ops;
clk->hw = hw;
@@ -2014,11 +2135,11 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
else
clk->owner = NULL;
- ret = __clk_init(dev, clk);
+ ret = __clk_init(dev, hw->clk);
if (ret)
return ERR_PTR(ret);
- return clk;
+ return hw->clk;
}
EXPORT_SYMBOL_GPL(__clk_register);
@@ -2036,7 +2157,7 @@ EXPORT_SYMBOL_GPL(__clk_register);
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
int i, ret;
- struct clk *clk;
+ struct clk_core *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
@@ -2057,7 +2178,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
clk->hw = hw;
clk->flags = hw->init->flags;
clk->num_parents = hw->init->num_parents;
- hw->clk = clk;
+ hw->core = clk;
/* allocate local copy in case parent_names is __initdata */
clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
@@ -2081,10 +2202,12 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
}
}
- ret = __clk_init(dev, clk);
+ hw->clk = __clk_create_clk(hw, NULL, NULL);
+ ret = __clk_init(dev, hw->clk);
if (!ret)
- return clk;
+ return hw->clk;
+ kfree(hw->clk);
fail_parent_names_copy:
while (--i >= 0)
kfree(clk->parent_names[i]);
@@ -2104,7 +2227,7 @@ EXPORT_SYMBOL_GPL(clk_register);
*/
static void __clk_release(struct kref *ref)
{
- struct clk *clk = container_of(ref, struct clk, ref);
+ struct clk_core *clk = container_of(ref, struct clk_core, ref);
int i = clk->num_parents;
kfree(clk->parents);
@@ -2162,12 +2285,12 @@ void clk_unregister(struct clk *clk)
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
- clk_debug_unregister(clk);
+ clk_debug_unregister(clk->core);
clk_prepare_lock();
- if (clk->ops == &clk_nodrv_ops) {
- pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
+ if (clk->core->ops == &clk_nodrv_ops) {
+ pr_err("%s: unregistered clock: %s\n", __func__, clk->core->name);
return;
}
/*
@@ -2175,24 +2298,24 @@ void clk_unregister(struct clk *clk)
* a reference to this clock.
*/
flags = clk_enable_lock();
- clk->ops = &clk_nodrv_ops;
+ clk->core->ops = &clk_nodrv_ops;
clk_enable_unlock(flags);
- if (!hlist_empty(&clk->children)) {
- struct clk *child;
+ if (!hlist_empty(&clk->core->children)) {
+ struct clk_core *child;
struct hlist_node *t;
/* Reparent all children to the orphan list. */
- hlist_for_each_entry_safe(child, t, &clk->children, child_node)
- clk_set_parent(child, NULL);
+ hlist_for_each_entry_safe(child, t, &clk->core->children, child_node)
+ clk_core_set_parent(child, NULL);
}
- hlist_del_init(&clk->child_node);
+ hlist_del_init(&clk->core->child_node);
- if (clk->prepare_count)
+ if (clk->core->prepare_count)
pr_warn("%s: unregistering prepared clock: %s\n",
- __func__, clk->name);
- kref_put(&clk->ref, __clk_release);
+ __func__, clk->core->name);
+ kref_put(&clk->core->ref, __clk_release);
clk_prepare_unlock();
}
@@ -2255,32 +2378,38 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
}
EXPORT_SYMBOL_GPL(devm_clk_unregister);
+static void clk_core_put(struct clk_core *clk)
+{
+ struct module *owner;
+
+ if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
+ return;
+
+ clk_prepare_lock();
+ owner = clk->owner;
+ kref_put(&clk->ref, __clk_release);
+ module_put(owner);
+ clk_prepare_unlock();
+}
+
/*
* clkdev helpers
*/
int __clk_get(struct clk *clk)
{
if (clk) {
- if (!try_module_get(clk->owner))
+ if (!try_module_get(clk->core->owner))
return 0;
- kref_get(&clk->ref);
+ kref_get(&clk->core->ref);
}
return 1;
}
void __clk_put(struct clk *clk)
{
- struct module *owner;
-
- if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
- return;
-
- clk_prepare_lock();
- owner = clk->owner;
- kref_put(&clk->ref, __clk_release);
- module_put(owner);
- clk_prepare_unlock();
+ clk_core_put(clk->core);
+ kfree(clk);
}
/*** clk rate change notifiers ***/
@@ -2335,7 +2464,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
- clk->notifier_count++;
+ clk->core->notifier_count++;
out:
clk_prepare_unlock();
@@ -2372,7 +2501,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
- clk->notifier_count--;
+ clk->core->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
@@ -2391,6 +2520,31 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(clk_notifier_unregister);
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id)
+{
+ struct clk *clk;
+
+ /* This is to allow this function to be chained to others */
+ if (!hw || IS_ERR(hw))
+ return (struct clk *) hw;
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->core = hw->core;
+ clk->dev_id = dev_id;
+ clk->con_id = con_id;
+
+ return clk;
+}
+
+struct clk *__clk_core_to_clk(struct clk_core *clk)
+{
+ return !clk ? NULL : clk->hw->clk;
+}
+
#ifdef CONFIG_OF
/**
* struct of_clk_provider - Clock provider registration structure
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index c798138..23c44e5 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -9,9 +9,14 @@
* published by the Free Software Foundation.
*/
+struct clk_hw;
+
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
void of_clk_lock(void);
void of_clk_unlock(void);
#endif
+
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index da4bda8..4411db6 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/of.h>
#include "clk.h"
@@ -69,6 +70,10 @@ struct clk *of_clk_get(struct device_node *np, int index)
clk = of_clk_get_by_clkspec(&clkspec);
of_node_put(clkspec.np);
+
+ if (!IS_ERR(clk))
+ clk = __clk_create_clk(__clk_get_hw(clk), np->full_name, NULL);
+
return clk;
}
EXPORT_SYMBOL(of_clk_get);
@@ -168,14 +173,29 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk_lookup *cl;
+ struct clk *clk = NULL;
mutex_lock(&clocks_mutex);
+
cl = clk_find(dev_id, con_id);
- if (cl && !__clk_get(cl->clk))
+ if (!cl)
+ goto out;
+
+ if (!__clk_get(cl->clk)) {
cl = NULL;
+ goto out;
+ }
+
+#if defined(CONFIG_COMMON_CLK)
+ clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
+#else
+ clk = cl->clk;
+#endif
+
+out:
mutex_unlock(&clocks_mutex);
- return cl ? cl->clk : ERR_PTR(-ENOENT);
+ return cl ? clk : ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get_sys);
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index 0ca5f60..1cdb727 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -28,20 +28,20 @@
struct module;
-struct clk {
+struct clk_core {
const char *name;
const struct clk_ops *ops;
struct clk_hw *hw;
struct module *owner;
- struct clk *parent;
+ struct clk_core *parent;
const char **parent_names;
- struct clk **parents;
+ struct clk_core **parents;
u8 num_parents;
u8 new_parent_index;
unsigned long rate;
unsigned long new_rate;
- struct clk *new_parent;
- struct clk *new_child;
+ struct clk_core *new_parent;
+ struct clk_core *new_child;
unsigned long flags;
unsigned int enable_count;
unsigned int prepare_count;
@@ -57,6 +57,12 @@ struct clk {
struct kref ref;
};
+struct clk {
+ struct clk_core *core;
+ const char *dev_id;
+ const char *con_id;
+};
+
/*
* DOC: Basic clock implementations common to many platforms
*
@@ -69,6 +75,9 @@ struct clk {
#define DEFINE_CLK(_name, _ops, _flags, _parent_names, \
_parents) \
static struct clk _name = { \
+ .core = &_name##_core \
+ }; \
+ static struct clk_core _name##_core = { \
.name = #_name, \
.ops = &_ops, \
.hw = &_name##_hw.hw, \
@@ -81,9 +90,11 @@ struct clk {
#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
_fixed_rate_flags) \
static struct clk _name; \
+ static struct clk_core _name##_core; \
static const char *_name##_parent_names[] = {}; \
static struct clk_fixed_rate _name##_hw = { \
.hw = { \
+ .core = &_name##_core, \
.clk = &_name, \
}, \
.fixed_rate = _rate, \
@@ -96,14 +107,16 @@ struct clk {
_flags, _reg, _bit_idx, \
_gate_flags, _lock) \
static struct clk _name; \
+ static struct clk_core _name##_core; \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
- static struct clk *_name##_parents[] = { \
+ static struct clk_core *_name##_parents[] = { \
_parent_ptr, \
}; \
static struct clk_gate _name##_hw = { \
.hw = { \
+ .core = &_name##_core, \
.clk = &_name, \
}, \
.reg = _reg, \
@@ -118,14 +131,16 @@ struct clk {
_flags, _reg, _shift, _width, \
_divider_flags, _table, _lock) \
static struct clk _name; \
+ static struct clk_core _name##_core; \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
- static struct clk *_name##_parents[] = { \
+ static struct clk_core *_name##_parents[] = { \
_parent_ptr, \
}; \
static struct clk_divider _name##_hw = { \
.hw = { \
+ .core = &_name##_core, \
.clk = &_name, \
}, \
.reg = _reg, \
@@ -157,8 +172,10 @@ struct clk {
_reg, _shift, _width, \
_mux_flags, _lock) \
static struct clk _name; \
+ static struct clk_core _name##_core; \
static struct clk_mux _name##_hw = { \
.hw = { \
+ .core = &_name##_core, \
.clk = &_name, \
}, \
.reg = _reg, \
@@ -174,14 +191,16 @@ struct clk {
_parent_ptr, _flags, \
_mult, _div) \
static struct clk _name; \
+ static struct clk_core _name##_core; \
static const char *_name##_parent_names[] = { \
_parent_name, \
}; \
- static struct clk *_name##_parents[] = { \
+ static struct clk_core *_name##_parents[] = { \
_parent_ptr, \
}; \
static struct clk_fixed_factor _name##_hw = { \
.hw = { \
+ .core = &_name##_core, \
.clk = &_name, \
}, \
.mult = _mult, \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 4ccd388..281e8da 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -33,6 +33,7 @@
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
struct clk_hw;
+struct clk_core;
struct dentry;
/**
@@ -216,13 +217,17 @@ struct clk_init_data {
* clk_foo and then referenced by the struct clk instance that uses struct
* clk_foo's clk_ops
*
- * @clk: pointer to the struct clk instance that points back to this struct
- * clk_hw instance
+ * @core: pointer to the struct clk_core instance that points back to this
+ * struct clk_hw instance
+ *
+ * @clk: pointer to the per-user struct clk instance that can be used to call
+ * into the clk API
*
* @init: pointer to struct clk_init_data that contains the init data shared
* with the common clock framework.
*/
struct clk_hw {
+ struct clk_core *core;
struct clk *clk;
const struct clk_init_data *init;
};
@@ -554,6 +559,19 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p);
+/**
+ * __clk_core_to_clk - return per-user clk
+ * @clk: struct clk_core for which we want a per-user clk
+ *
+ * Returns a per-user clock that is owned by its provider. The caller shall not
+ * call clk_get() on it.
+ *
+ * This function should be only needed by implementors of
+ * clk_ops.determine_rate() and should be dropped once all have moved to a
+ * variant that returns **clk_core instead.
+ */
+struct clk *__clk_core_to_clk(struct clk_core *clk);
+
/*
* FIXME clock api without lock protection
*/
--
1.9.3
Replacing it with a call to __clk_is_prepared(), which isn't entirely
equivalent but in practice shouldn't matter.
Signed-off-by: Tomeu Vizoso <[email protected]>
---
arch/mips/alchemy/common/clock.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index d7557cd..203e440 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -37,7 +37,6 @@
#include <linux/io.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
-#include <linux/clk-private.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -397,10 +396,10 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
break;
/* if this parent is currently unused, remember it.
- * XXX: I know it's a layering violation, but it works
- * so well.. (if (!clk_has_active_children(pc)) )
+ * XXX: we would actually want clk_has_active_children()
+ * but this is a good-enough approximation for now.
*/
- if (pc->prepare_count == 0) {
+ if (!__clk_is_prepared(pc)) {
if (!free)
free = pc;
}
--
1.9.3
Signed-off-by: Tomeu Vizoso <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
---
drivers/clk/clk.c | 5 -----
include/linux/clk-provider.h | 1 -
2 files changed, 6 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 4896ae9..d0712b7 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -574,11 +574,6 @@ unsigned int __clk_get_enable_count(struct clk *clk)
return !clk ? 0 : clk->enable_count;
}
-unsigned int __clk_get_prepare_count(struct clk *clk)
-{
- return !clk ? 0 : clk->prepare_count;
-}
-
unsigned long __clk_get_rate(struct clk *clk)
{
unsigned long ret;
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index be21af1..17fb661 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -545,7 +545,6 @@ u8 __clk_get_num_parents(struct clk *clk);
struct clk *__clk_get_parent(struct clk *clk);
struct clk *clk_get_parent_by_index(struct clk *clk, u8 index);
unsigned int __clk_get_enable_count(struct clk *clk);
-unsigned int __clk_get_prepare_count(struct clk *clk);
unsigned long __clk_get_rate(struct clk *clk);
unsigned long __clk_get_accuracy(struct clk *clk);
unsigned long __clk_get_flags(struct clk *clk);
--
1.9.3
On 10/09, Tomeu Vizoso wrote:
> As __clk_release could call kfree on clk and then we wouldn't have a safe way
> of getting the module that owns the clock.
>
> Signed-off-by: Tomeu Vizoso <[email protected]>
It would be good to mark this as a "Fixes:".
> ---
> drivers/clk/clk.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index d0712b7..40aa7ad 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -2268,14 +2268,16 @@ int __clk_get(struct clk *clk)
>
> void __clk_put(struct clk *clk)
> {
> + struct module *owner;
> +
> if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
> return;
>
> clk_prepare_lock();
> + owner = clk->owner;
> kref_put(&clk->ref, __clk_release);
> + module_put(owner);
> clk_prepare_unlock();
> -
> - module_put(clk->owner);
We don't need to move this call under the prepare lock though, right?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 10/09, Tomeu Vizoso wrote:
> @@ -946,6 +946,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
> {
> unsigned long parent_rate = 0;
> struct clk *parent;
> + struct clk_hw *parent_hw;
>
> if (!clk)
> return 0;
> @@ -956,7 +957,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
>
> if (clk->ops->determine_rate)
> return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
> - &parent);
> + &parent_hw);
We should assign the value of parent_hw somewhere here so that
drivers don't need to if they want the current parent. This would
match the current behavior where parent is already assigned the
current parent.
> else if (clk->ops->round_rate)
> return clk->ops->round_rate(clk->hw, rate, &parent_rate);
> else if (clk->flags & CLK_SET_RATE_PARENT)
> @@ -1345,6 +1346,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
> {
> struct clk *top = clk;
> struct clk *old_parent, *parent;
> + struct clk_hw *parent_hw;
> unsigned long best_parent_rate = 0;
> unsigned long new_rate;
> int p_index = 0;
> @@ -1362,7 +1364,8 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
> if (clk->ops->determine_rate) {
> new_rate = clk->ops->determine_rate(clk->hw, rate,
> &best_parent_rate,
> - &parent);
> + &parent_hw);
> + parent = parent_hw->clk;
Same comment here.
> } else if (clk->ops->round_rate) {
> new_rate = clk->ops->round_rate(clk->hw, rate,
> &best_parent_rate);
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 10/09, Tomeu Vizoso wrote:
> Replacing it with a call to __clk_is_prepared(), which isn't entirely
> equivalent but in practice shouldn't matter.
>
> Signed-off-by: Tomeu Vizoso <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 10/09, Tomeu Vizoso wrote:
> arch/arm/mach-omap2/cclock3xxx_data.c | 108 ++++--
> arch/arm/mach-omap2/clock.h | 11 +-
> arch/arm/mach-omap2/clock_common_data.c | 5 +-
> drivers/clk/clk.c | 630 ++++++++++++++++++++------------
> drivers/clk/clk.h | 5 +
> drivers/clk/clkdev.c | 24 +-
> include/linux/clk-private.h | 35 +-
> include/linux/clk-provider.h | 22 +-
> 8 files changed, 549 insertions(+), 291 deletions(-)
The difstat looks good.
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index fb820bf..4db918a 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -695,6 +731,13 @@ struct clk *__clk_lookup(const char *name)
> return NULL;
> }
>
> +struct clk *__clk_lookup(const char *name)
> +{
> + struct clk_core *clk = clk_core_lookup(name);
> +
> + return !clk ? NULL : clk->hw->clk;
This just looks weird with clk->hw->clk. I know we're trying to
keep the diff small by not renaming clk to core when it's used
extensively throughout the code, but for small little additions
like this I would prefer we use core for clk_core pointers and
clk for clk pointers. Then a patch at the end can rename
everything to be consistent. This thing also threw me off because
I searched for kfree(core) but couldn't find it so I thought we
leaked the clk_core structure.
> +}
> +
> /*
> * Helper for finding best parent to provide a given frequency. This can be used
> * directly as a determine_rate callback (e.g. for a mux), or from a more
> @@ -2175,24 +2298,24 @@ void clk_unregister(struct clk *clk)
> * a reference to this clock.
> */
> flags = clk_enable_lock();
> - clk->ops = &clk_nodrv_ops;
> + clk->core->ops = &clk_nodrv_ops;
> clk_enable_unlock(flags);
>
> - if (!hlist_empty(&clk->children)) {
> - struct clk *child;
> + if (!hlist_empty(&clk->core->children)) {
> + struct clk_core *child;
> struct hlist_node *t;
>
> /* Reparent all children to the orphan list. */
> - hlist_for_each_entry_safe(child, t, &clk->children, child_node)
> - clk_set_parent(child, NULL);
> + hlist_for_each_entry_safe(child, t, &clk->core->children, child_node)
> + clk_core_set_parent(child, NULL);
> }
>
> - hlist_del_init(&clk->child_node);
> + hlist_del_init(&clk->core->child_node);
>
> - if (clk->prepare_count)
> + if (clk->core->prepare_count)
> pr_warn("%s: unregistering prepared clock: %s\n",
> - __func__, clk->name);
> - kref_put(&clk->ref, __clk_release);
> + __func__, clk->core->name);
> + kref_put(&clk->core->ref, __clk_release);
>
> clk_prepare_unlock();
It might be worth it to make a "core" local variable in this
function.
> }
> @@ -2255,32 +2378,38 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
> }
> EXPORT_SYMBOL_GPL(devm_clk_unregister);
>
> +static void clk_core_put(struct clk_core *clk)
> +{
> + struct module *owner;
> +
> + if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
> + return;
> +
> + clk_prepare_lock();
> + owner = clk->owner;
Same here too, we don't need to protect the access to owner so it
can move outside the lock.
> + kref_put(&clk->ref, __clk_release);
> + module_put(owner);
> + clk_prepare_unlock();
> +}
> +
> /*
> * clkdev helpers
> */
> int __clk_get(struct clk *clk)
> {
> if (clk) {
> - if (!try_module_get(clk->owner))
> + if (!try_module_get(clk->core->owner))
> return 0;
>
> - kref_get(&clk->ref);
> + kref_get(&clk->core->ref);
> }
> return 1;
Grow a core pointer?
> }
> @@ -2391,6 +2520,31 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
> }
> EXPORT_SYMBOL_GPL(clk_notifier_unregister);
>
> +struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
Curious, why the underscore?
> + const char *con_id)
> +{
> + struct clk *clk;
> +
> + /* This is to allow this function to be chained to others */
> + if (!hw || IS_ERR(hw))
> + return (struct clk *) hw;
> +
> + clk = kzalloc(sizeof(*clk), GFP_KERNEL);
> + if (!clk)
> + return ERR_PTR(-ENOMEM);
> +
> + clk->core = hw->core;
> + clk->dev_id = dev_id;
> + clk->con_id = con_id;
> +
> + return clk;
> +}
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> index da4bda8..4411db6 100644
> --- a/drivers/clk/clkdev.c
> +++ b/drivers/clk/clkdev.c
> @@ -69,6 +70,10 @@ struct clk *of_clk_get(struct device_node *np, int index)
>
> clk = of_clk_get_by_clkspec(&clkspec);
> of_node_put(clkspec.np);
> +
> + if (!IS_ERR(clk))
> + clk = __clk_create_clk(__clk_get_hw(clk), np->full_name, NULL);
We lost the debugging information here about the device
requesting this clock and the name they called it. We get the
device node name but that might not match the device name. We
probably need to make private functions in here that allow such
information to be passed without changing the API for
of_clk_get(), of_clk_get_by_name(), etc.
> +
> return clk;
> }
> EXPORT_SYMBOL(of_clk_get);
> @@ -168,14 +173,29 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
> struct clk *clk_get_sys(const char *dev_id, const char *con_id)
> {
> struct clk_lookup *cl;
> + struct clk *clk = NULL;
>
> mutex_lock(&clocks_mutex);
> +
> cl = clk_find(dev_id, con_id);
> - if (cl && !__clk_get(cl->clk))
> + if (!cl)
> + goto out;
> +
> + if (!__clk_get(cl->clk)) {
> cl = NULL;
> + goto out;
> + }
> +
> +#if defined(CONFIG_COMMON_CLK)
> + clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
I was hoping we could put the clk_hw pointer next to the clk
pointer in the lookup structure. Then providers don't have to
deal with clk pointers at all and can just assign their clk_hw
pointer in the lookup. This would make most of the omap usage of
struct clk unnecessary. It doesn't seem necessary though so I
guess we can do that in another series?
> +#else
> + clk = cl->clk;
> +#endif
> +
> +out:
> mutex_unlock(&clocks_mutex);
>
> - return cl ? cl->clk : ERR_PTR(-ENOENT);
> + return cl ? clk : ERR_PTR(-ENOENT);
> }
> EXPORT_SYMBOL(clk_get_sys);
>
> @@ -554,6 +559,19 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
> unsigned long *best_parent_rate,
> struct clk_hw **best_parent_p);
>
> +/**
> + * __clk_core_to_clk - return per-user clk
> + * @clk: struct clk_core for which we want a per-user clk
> + *
> + * Returns a per-user clock that is owned by its provider. The caller shall not
> + * call clk_get() on it.
> + *
> + * This function should be only needed by implementors of
> + * clk_ops.determine_rate() and should be dropped once all have moved to a
> + * variant that returns **clk_core instead.
> + */
> +struct clk *__clk_core_to_clk(struct clk_core *clk);
> +
We can drop this now right?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
Kodiak Furr liked your message with Boxer for Android.
On Oct 9, 2014 6:22 PM, Stephen Boyd <[email protected]> wrote:
>
> On 10/09, Tomeu Vizoso wrote:
> > arch/arm/mach-omap2/cclock3xxx_data.c | 108 ++++--
> > arch/arm/mach-omap2/clock.h | 11 +-
> > arch/arm/mach-omap2/clock_common_data.c | 5 +-
> > drivers/clk/clk.c | 630 ++++++++++++++++++++------------
> > drivers/clk/clk.h | 5 +
> > drivers/clk/clkdev.c | 24 +-
> > include/linux/clk-private.h | 35 +-
> > include/linux/clk-provider.h | 22 +-
> > 8 files changed, 549 insertions(+), 291 deletions(-)
>
> The difstat looks good.
>
> >
> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > index fb820bf..4db918a 100644
> > --- a/drivers/clk/clk.c
> > +++ b/drivers/clk/clk.c
> > @@ -695,6 +731,13 @@ struct clk *__clk_lookup(const char *name)
> > return NULL;
> > }
> >
> > +struct clk *__clk_lookup(const char *name)
> > +{
> > + struct clk_core *clk = clk_core_lookup(name);
> > +
> > + return !clk ? NULL : clk->hw->clk;
>
> This just looks weird with clk->hw->clk. I know we're trying to
> keep the diff small by not renaming clk to core when it's used
> extensively throughout the code, but for small little additions
> like this I would prefer we use core for clk_core pointers and
> clk for clk pointers. Then a patch at the end can rename
> everything to be consistent. This thing also threw me off because
> I searched for kfree(core) but couldn't find it so I thought we
> leaked the clk_core structure.
>
> > +}
> > +
> > /*
> > * Helper for finding best parent to provide a given frequency. This can be used
> > * directly as a determine_rate callback (e.g. for a mux), or from a more
> > @@ -2175,24 +2298,24 @@ void clk_unregister(struct clk *clk)
> > * a reference to this clock.
> > */
> > flags = clk_enable_lock();
> > - clk->ops = &clk_nodrv_ops;
> > + clk->core->ops = &clk_nodrv_ops;
> > clk_enable_unlock(flags);
> >
> > - if (!hlist_empty(&clk->children)) {
> > - struct clk *child;
> > + if (!hlist_empty(&clk->core->children)) {
> > + struct clk_core *child;
> > struct hlist_node *t;
> >
> > /* Reparent all children to the orphan list. */
> > - hlist_for_each_entry_safe(child, t, &clk->children, child_node)
> > - clk_set_parent(child, NULL);
> > + hlist_for_each_entry_safe(child, t, &clk->core->children, child_node)
> > + clk_core_set_parent(child, NULL);
> > }
> >
> > - hlist_del_init(&clk->child_node);
> > + hlist_del_init(&clk->core->child_node);
> >
> > - if (clk->prepare_count)
> > + if (clk->core->prepare_count)
> > pr_warn("%s: unregistering prepared clock: %s\n",
> > - __func__, clk->name);
> > - kref_put(&clk->ref, __clk_release);
> > + __func__, clk->core->name);
> > + kref_put(&clk->core->ref, __clk_release);
> >
> > clk_prepare_unlock();
>
> It might be worth it to make a "core" local variable in this
> function.
>
> > }
> > @@ -2255,32 +2378,38 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
> > }
> > EXPORT_SYMBOL_GPL(devm_clk_unregister);
> >
> > +static void clk_core_put(struct clk_core *clk)
> > +{
> > + struct module *owner;
> > +
> > + if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
> > + return;
> > +
> > + clk_prepare_lock();
> > + owner = clk->owner;
>
> Same here too, we don't need to protect the access to owner so it
> can move outside the lock.
>
> > + kref_put(&clk->ref, __clk_release);
> > + module_put(owner);
> > + clk_prepare_unlock();
> > +}
> > +
> > /*
> > * clkdev helpers
> > */
> > int __clk_get(struct clk *clk)
> > {
> > if (clk) {
> > - if (!try_module_get(clk->owner))
> > + if (!try_module_get(clk->core->owner))
> > return 0;
> >
> > - kref_get(&clk->ref);
> > + kref_get(&clk->core->ref);
> > }
> > return 1;
>
> Grow a core pointer?
>
> > }
> > @@ -2391,6 +2520,31 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
> > }
> > EXPORT_SYMBOL_GPL(clk_notifier_unregister);
> >
> > +struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
>
> Curious, why the underscore?
>
> > + const char *con_id)
> > +{
> > + struct clk *clk;
> > +
> > + /* This is to allow this function to be chained to others */
> > + if (!hw || IS_ERR(hw))
> > + return (struct clk *) hw;
> > +
> > + clk = kzalloc(sizeof(*clk), GFP_KERNEL);
> > + if (!clk)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + clk->core = hw->core;
> > + clk->dev_id = dev_id;
> > + clk->con_id = con_id;
> > +
> > + return clk;
> > +}
> > diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> > index da4bda8..4411db6 100644
> > --- a/drivers/clk/clkdev.c
> > +++ b/drivers/clk/clkdev.c
> > @@ -69,6 +70,10 @@ struct clk *of_clk_get(struct device_node *np, int index)
> >
> > clk = of_clk_get_by_clkspec(&clkspec);
> > of_node_put(clkspec.np);
> > +
> > + if (!IS_ERR(clk))
> > + clk = __clk_create_clk(__clk_get_hw(clk), np->full_name, NULL);
>
> We lost the debugging information here about the device
> requesting this clock and the name they called it. We get the
> device node name but that might not match the device name. We
> probably need to make private functions in here that allow such
> information to be passed without changing the API for
> of_clk_get(), of_clk_get_by_name(), etc.
>
> > +
> > return clk;
> > }
> > EXPORT_SYMBOL(of_clk_get);
> > @@ -168,14 +173,29 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
> > struct clk *clk_get_sys(const char *dev_id, const char *con_id)
> > {
> > struct clk_lookup *cl;
> > + struct clk *clk = NULL;
> >
> > mutex_lock(&clocks_mutex);
> > +
> > cl = clk_find(dev_id, con_id);
> > - if (cl && !__clk_get(cl->clk))
> > + if (!cl)
> > + goto out;
> > +
> > + if (!__clk_get(cl->clk)) {
> > cl = NULL;
> > + goto out;
> > + }
> > +
> > +#if defined(CONFIG_COMMON_CLK)
> > + clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
>
> I was hoping we could put the clk_hw pointer next to the clk
> pointer in the lookup structure. Then providers don't have to
> deal with clk pointers at all and can just assign their clk_hw
> pointer in the lookup. This would make most of the omap usage of
> struct clk unnecessary. It doesn't seem necessary though so I
> guess we can do that in another series?
>
> > +#else
> > + clk = cl->clk;
> > +#endif
> > +
> > +out:
> > mutex_unlock(&clocks_mutex);
> >
> > - return cl ? cl->clk : ERR_PTR(-ENOENT);
> > + return cl ? clk : ERR_PTR(-ENOENT);
> > }
> > EXPORT_SYMBOL(clk_get_sys);
> >
> > @@ -554,6 +559,19 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
> > unsigned long *best_parent_rate,
> > struct clk_hw **best_parent_p);
> >
> > +/**
> > + * __clk_core_to_clk - return per-user clk
> > + * @clk: struct clk_core for which we want a per-user clk
> > + *
> > + * Returns a per-user clock that is owned by its provider. The caller shall not
> > + * call clk_get() on it.
> > + *
> > + * This function should be only needed by implementors of
> > + * clk_ops.determine_rate() and should be dropped once all have moved to a
> > + * variant that returns **clk_core instead.
> > + */
> > +struct clk *__clk_core_to_clk(struct clk_core *clk);
> > +
>
> We can drop this now right?
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
On 10/09, Tomeu Vizoso wrote:
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 4db918a..97cf1a3 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -1629,18 +1609,27 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
> /* prevent racing with updates to the clock topology */
> clk_prepare_lock();
>
> + hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
> + rate = max(rate, clk_user->floor_constraint);
> + }
> +
> + hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
> + if (clk_user->ceiling_constraint > 0)
> + rate = min(rate, clk_user->ceiling_constraint);
> + }
> +
> /* bail early if nothing to do */
> - if (rate == clk_get_rate(clk))
> + if (rate == clk_core_get_rate(clk))
Can we use the nolock variant here? As an aside, this is going to
make my per-clock locking series complicated. I'm not even sure
how the two series will work together. In the per-clock locking
series I was hoping we could check if rate == current rate
without holding any locks. Otherwise we get into a recursive lock
situation. Need to think more about that one.
> goto out;
>
> - if ((clk->core->flags & CLK_SET_RATE_GATE) &&
> - clk->core->prepare_count) {
> + if ((clk->flags & CLK_SET_RATE_GATE) &&
> + clk->prepare_count) {
> ret = -EBUSY;
> goto out;
> }
>
> /* calculate new rates and get the topmost changed clock */
> - top = clk_calc_new_rates(clk->core, rate);
> + top = clk_calc_new_rates(clk, rate);
> if (!top) {
> ret = -EINVAL;
> goto out;
> @@ -1664,8 +1653,69 @@ out:
[...]
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + return clk_core_set_rate(clk->core, rate);
> +}
> EXPORT_SYMBOL_GPL(clk_set_rate);
>
What about clk_round_rate()? That needs to tell us what the rate
will be if we call clk_set_rate() with whatever value is passed
here. I would expect that the rate aggregation logic would be
somewhere in that codepath but I don't see it.
> +int clk_set_floor_rate(struct clk *clk, unsigned long rate)
We need some documentation for these new functions. I see we have
them in the header, maybe we can copy that here.
> +{
> + int ret;
> +
> + clk_prepare_lock();
> +
> + clk->floor_constraint = rate;
No check for ceiling being less than floor?
> + ret = clk_set_rate(clk, clk_get_rate(clk));
> +
> + clk_prepare_unlock();
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_floor_rate);
> +
> +int clk_set_ceiling_rate(struct clk *clk, unsigned long rate)
> +{
> + int ret;
> +
> + clk_prepare_lock();
We don't need to grab the lock this early right? Presumably the
caller is doing any required locking so they don't call different
clk APIs for the same clk pointer at the same time. So we should
be able to grab this lock after checking for this error
condition.
> +
> + WARN(rate > 0 && rate < clk->floor_constraint,
> + "clk %s dev %s con %s: new ceiling %lu lower than existing floor %lu\n",
> + clk->core->name, clk->dev_id, clk->con_id, rate,
> + clk->floor_constraint);
> +
> + clk->ceiling_constraint = rate;
> + ret = clk_set_rate(clk, clk_get_rate(clk));
Why not just pass 0 as the second argument? The same comment
applies in the floor function.
> +
> + clk_prepare_unlock();
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_ceiling_rate);
> +
> static struct clk_core *clk_core_get_parent(struct clk_core *clk)
> {
> struct clk_core *parent;
> @@ -2143,6 +2195,12 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
> }
> EXPORT_SYMBOL_GPL(__clk_register);
>
> +static void __clk_free_clk(struct clk *clk_user)
> +{
> + hlist_del(&clk_user->child_node);
> + kfree(clk_user);
We need to re-evaluate the rate when a user is removed, right?
This leads to another question though. What does it means for a
per-user clock to be disabled and change it's floor or ceiling?
Should that count in the aggregation logic?
So far we haven't required drivers to explicitly call
clk_set_rate() with 0 so they can "drop" their rate request
because there isn't any other user and disabling the clock is
pretty much the same. With multiple users it looks like we're
going to require them to set the floor or ceiling to 0 or INT_MAX
if they want to remove their request. Alternatively we could
track the prepare/unprepare state of the per-user clock and drop
the constraint when that instance is unprepared (or reapply it
when prepared). It's pretty much a semantic difference, but one
benefit would be that we don't have to make two (or three?) calls
to the clock framework if we want to drop the rate constraints
and disable the clock.
> +}
> +
> /**
> * clk_register - allocate a new clock, register it and return an opaque cookie
> * @dev: device that is registering this clock
> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
> index 1cdb727..025aca2 100644
> --- a/include/linux/clk-private.h
> +++ b/include/linux/clk-private.h
> @@ -50,6 +50,7 @@ struct clk_core {
> struct hlist_head children;
> struct hlist_node child_node;
> struct hlist_node debug_node;
> + struct hlist_head per_user_clks;
Can we just call it 'clks'?
> unsigned int notifier_count;
> #ifdef CONFIG_DEBUG_FS
> struct dentry *dentry;
> @@ -61,6 +62,10 @@ struct clk {
> struct clk_core *core;
> const char *dev_id;
> const char *con_id;
> +
> + unsigned long floor_constraint;
> + unsigned long ceiling_constraint;
> + struct hlist_node child_node;
> };
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
On 10 October 2014 01:22, Stephen Boyd <[email protected]> wrote:
> On 10/09, Tomeu Vizoso wrote:
>> arch/arm/mach-omap2/cclock3xxx_data.c | 108 ++++--
>> arch/arm/mach-omap2/clock.h | 11 +-
>> arch/arm/mach-omap2/clock_common_data.c | 5 +-
>> drivers/clk/clk.c | 630 ++++++++++++++++++++------------
>> drivers/clk/clk.h | 5 +
>> drivers/clk/clkdev.c | 24 +-
>> include/linux/clk-private.h | 35 +-
>> include/linux/clk-provider.h | 22 +-
>> 8 files changed, 549 insertions(+), 291 deletions(-)
>
> The difstat looks good.
>
>>
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index fb820bf..4db918a 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -695,6 +731,13 @@ struct clk *__clk_lookup(const char *name)
>> return NULL;
>> }
>>
>> +struct clk *__clk_lookup(const char *name)
>> +{
>> + struct clk_core *clk = clk_core_lookup(name);
>> +
>> + return !clk ? NULL : clk->hw->clk;
>
> This just looks weird with clk->hw->clk. I know we're trying to
> keep the diff small by not renaming clk to core when it's used
> extensively throughout the code, but for small little additions
> like this I would prefer we use core for clk_core pointers and
> clk for clk pointers. Then a patch at the end can rename
> everything to be consistent. This thing also threw me off because
> I searched for kfree(core) but couldn't find it so I thought we
> leaked the clk_core structure.
Makes sense, I have tried to reduce confusion in this regard.
>> +}
>> +
>> /*
>> * Helper for finding best parent to provide a given frequency. This can be used
>> * directly as a determine_rate callback (e.g. for a mux), or from a more
>> @@ -2175,24 +2298,24 @@ void clk_unregister(struct clk *clk)
>> * a reference to this clock.
>> */
>> flags = clk_enable_lock();
>> - clk->ops = &clk_nodrv_ops;
>> + clk->core->ops = &clk_nodrv_ops;
>> clk_enable_unlock(flags);
>>
>> - if (!hlist_empty(&clk->children)) {
>> - struct clk *child;
>> + if (!hlist_empty(&clk->core->children)) {
>> + struct clk_core *child;
>> struct hlist_node *t;
>>
>> /* Reparent all children to the orphan list. */
>> - hlist_for_each_entry_safe(child, t, &clk->children, child_node)
>> - clk_set_parent(child, NULL);
>> + hlist_for_each_entry_safe(child, t, &clk->core->children, child_node)
>> + clk_core_set_parent(child, NULL);
>> }
>>
>> - hlist_del_init(&clk->child_node);
>> + hlist_del_init(&clk->core->child_node);
>>
>> - if (clk->prepare_count)
>> + if (clk->core->prepare_count)
>> pr_warn("%s: unregistering prepared clock: %s\n",
>> - __func__, clk->name);
>> - kref_put(&clk->ref, __clk_release);
>> + __func__, clk->core->name);
>> + kref_put(&clk->core->ref, __clk_release);
>>
>> clk_prepare_unlock();
>
> It might be worth it to make a "core" local variable in this
> function.
>
>> }
>> @@ -2255,32 +2378,38 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
>> }
>> EXPORT_SYMBOL_GPL(devm_clk_unregister);
>>
>> +static void clk_core_put(struct clk_core *clk)
>> +{
>> + struct module *owner;
>> +
>> + if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
>> + return;
>> +
>> + clk_prepare_lock();
>> + owner = clk->owner;
>
> Same here too, we don't need to protect the access to owner so it
> can move outside the lock.
>
>> + kref_put(&clk->ref, __clk_release);
>> + module_put(owner);
>> + clk_prepare_unlock();
>> +}
>> +
>> /*
>> * clkdev helpers
>> */
>> int __clk_get(struct clk *clk)
>> {
>> if (clk) {
>> - if (!try_module_get(clk->owner))
>> + if (!try_module_get(clk->core->owner))
>> return 0;
>>
>> - kref_get(&clk->ref);
>> + kref_get(&clk->core->ref);
>> }
>> return 1;
>
> Grow a core pointer?
>
>> }
>> @@ -2391,6 +2520,31 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
>> }
>> EXPORT_SYMBOL_GPL(clk_notifier_unregister);
>>
>> +struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
>
> Curious, why the underscore?
To denote it's internal to the CCF implementation.
>> + const char *con_id)
>> +{
>> + struct clk *clk;
>> +
>> + /* This is to allow this function to be chained to others */
>> + if (!hw || IS_ERR(hw))
>> + return (struct clk *) hw;
>> +
>> + clk = kzalloc(sizeof(*clk), GFP_KERNEL);
>> + if (!clk)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + clk->core = hw->core;
>> + clk->dev_id = dev_id;
>> + clk->con_id = con_id;
>> +
>> + return clk;
>> +}
>> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
>> index da4bda8..4411db6 100644
>> --- a/drivers/clk/clkdev.c
>> +++ b/drivers/clk/clkdev.c
>> @@ -69,6 +70,10 @@ struct clk *of_clk_get(struct device_node *np, int index)
>>
>> clk = of_clk_get_by_clkspec(&clkspec);
>> of_node_put(clkspec.np);
>> +
>> + if (!IS_ERR(clk))
>> + clk = __clk_create_clk(__clk_get_hw(clk), np->full_name, NULL);
>
> We lost the debugging information here about the device
> requesting this clock and the name they called it. We get the
> device node name but that might not match the device name. We
> probably need to make private functions in here that allow such
> information to be passed without changing the API for
> of_clk_get(), of_clk_get_by_name(), etc.
Ok, I have made sure that we don't lose any information in that regard.
>> +
>> return clk;
>> }
>> EXPORT_SYMBOL(of_clk_get);
>> @@ -168,14 +173,29 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
>> struct clk *clk_get_sys(const char *dev_id, const char *con_id)
>> {
>> struct clk_lookup *cl;
>> + struct clk *clk = NULL;
>>
>> mutex_lock(&clocks_mutex);
>> +
>> cl = clk_find(dev_id, con_id);
>> - if (cl && !__clk_get(cl->clk))
>> + if (!cl)
>> + goto out;
>> +
>> + if (!__clk_get(cl->clk)) {
>> cl = NULL;
>> + goto out;
>> + }
>> +
>> +#if defined(CONFIG_COMMON_CLK)
>> + clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
>
> I was hoping we could put the clk_hw pointer next to the clk
> pointer in the lookup structure. Then providers don't have to
> deal with clk pointers at all and can just assign their clk_hw
> pointer in the lookup. This would make most of the omap usage of
> struct clk unnecessary. It doesn't seem necessary though so I
> guess we can do that in another series?
Yes, I think this is the kind of refinements that we want to do in
further series, moving the drivers one by one.
>> +#else
>> + clk = cl->clk;
>> +#endif
>> +
>> +out:
>> mutex_unlock(&clocks_mutex);
>>
>> - return cl ? cl->clk : ERR_PTR(-ENOENT);
>> + return cl ? clk : ERR_PTR(-ENOENT);
>> }
>> EXPORT_SYMBOL(clk_get_sys);
>>
>> @@ -554,6 +559,19 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
>> unsigned long *best_parent_rate,
>> struct clk_hw **best_parent_p);
>>
>> +/**
>> + * __clk_core_to_clk - return per-user clk
>> + * @clk: struct clk_core for which we want a per-user clk
>> + *
>> + * Returns a per-user clock that is owned by its provider. The caller shall not
>> + * call clk_get() on it.
>> + *
>> + * This function should be only needed by implementors of
>> + * clk_ops.determine_rate() and should be dropped once all have moved to a
>> + * variant that returns **clk_core instead.
>> + */
>> +struct clk *__clk_core_to_clk(struct clk_core *clk);
>> +
>
> We can drop this now right?
Indeed.
I will be sending soon a v4 with your comments addressed. Thanks for
the thorough reviews!
Cheers,
Tomeu
On 11 October 2014 01:55, Stephen Boyd <[email protected]> wrote:
> On 10/09, Tomeu Vizoso wrote:
>> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> index 4db918a..97cf1a3 100644
>> --- a/drivers/clk/clk.c
>> +++ b/drivers/clk/clk.c
>> @@ -1629,18 +1609,27 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
>> /* prevent racing with updates to the clock topology */
>> clk_prepare_lock();
>>
>> + hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
>> + rate = max(rate, clk_user->floor_constraint);
>> + }
>> +
>> + hlist_for_each_entry(clk_user, &clk->per_user_clks, child_node) {
>> + if (clk_user->ceiling_constraint > 0)
>> + rate = min(rate, clk_user->ceiling_constraint);
>> + }
>> +
>> /* bail early if nothing to do */
>> - if (rate == clk_get_rate(clk))
>> + if (rate == clk_core_get_rate(clk))
>
> Can we use the nolock variant here?
It's true that we have the lock already, but I'm not sure about the
implications of not calling __clk_recalc_rates. Nothing that cannot be
solved with one more function though...
> As an aside, this is going to
> make my per-clock locking series complicated. I'm not even sure
> how the two series will work together. In the per-clock locking
> series I was hoping we could check if rate == current rate
> without holding any locks. Otherwise we get into a recursive lock
> situation. Need to think more about that one.
Ok.
>> goto out;
>>
>> - if ((clk->core->flags & CLK_SET_RATE_GATE) &&
>> - clk->core->prepare_count) {
>> + if ((clk->flags & CLK_SET_RATE_GATE) &&
>> + clk->prepare_count) {
>> ret = -EBUSY;
>> goto out;
>> }
>>
>> /* calculate new rates and get the topmost changed clock */
>> - top = clk_calc_new_rates(clk->core, rate);
>> + top = clk_calc_new_rates(clk, rate);
>> if (!top) {
>> ret = -EINVAL;
>> goto out;
>> @@ -1664,8 +1653,69 @@ out:
> [...]
>> +int clk_set_rate(struct clk *clk, unsigned long rate)
>> +{
>> + return clk_core_set_rate(clk->core, rate);
>> +}
>> EXPORT_SYMBOL_GPL(clk_set_rate);
>>
>
> What about clk_round_rate()? That needs to tell us what the rate
> will be if we call clk_set_rate() with whatever value is passed
> here.
My thinking was that clock consumers would be setting constraints and
calling set_rate regardless of any constraints that may be set at the
moment.
Though in my particular use case (scaling of the external memory bus)
it shouldn't really matter as the clock would be given a suitably low
frequency at startup and from that moment on only the constraints
would be updated.
> I would expect that the rate aggregation logic would be
> somewhere in that codepath but I don't see it.
I can certainly make round_rate aware of constraints, no problem.
Mike, what do you think?
>> +int clk_set_floor_rate(struct clk *clk, unsigned long rate)
>
> We need some documentation for these new functions. I see we have
> them in the header, maybe we can copy that here.
Ok.
>> +{
>> + int ret;
>> +
>> + clk_prepare_lock();
>> +
>> + clk->floor_constraint = rate;
>
> No check for ceiling being less than floor?
No, otherwise the calling code would have to be very careful to set
both constraints in the correct order based on the current and next
values. In practice I expect a given consumer to either set a floor or
a constraint, but not both.
>> + ret = clk_set_rate(clk, clk_get_rate(clk));
>> +
>> + clk_prepare_unlock();
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(clk_set_floor_rate);
>> +
>> +int clk_set_ceiling_rate(struct clk *clk, unsigned long rate)
>> +{
>> + int ret;
>> +
>> + clk_prepare_lock();
>
> We don't need to grab the lock this early right? Presumably the
> caller is doing any required locking so they don't call different
> clk APIs for the same clk pointer at the same time. So we should
> be able to grab this lock after checking for this error
> condition.
Sounds good.
>> +
>> + WARN(rate > 0 && rate < clk->floor_constraint,
>> + "clk %s dev %s con %s: new ceiling %lu lower than existing floor %lu\n",
>> + clk->core->name, clk->dev_id, clk->con_id, rate,
>> + clk->floor_constraint);
>> +
>> + clk->ceiling_constraint = rate;
>> + ret = clk_set_rate(clk, clk_get_rate(clk));
>
> Why not just pass 0 as the second argument? The same comment
> applies in the floor function.
Both behaviours seem equally correct to me, but wonder if it wouldn't
be better to store the rate that was last set explicitly with set_rate
and try to reapply that one after every update to the constraints,
instead of the current rate, or 0/INT_MAX.
>> +
>> + clk_prepare_unlock();
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(clk_set_ceiling_rate);
>> +
>> static struct clk_core *clk_core_get_parent(struct clk_core *clk)
>> {
>> struct clk_core *parent;
>> @@ -2143,6 +2195,12 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
>> }
>> EXPORT_SYMBOL_GPL(__clk_register);
>>
>> +static void __clk_free_clk(struct clk *clk_user)
>> +{
>> + hlist_del(&clk_user->child_node);
>> + kfree(clk_user);
>
> We need to re-evaluate the rate when a user is removed, right?
Oops, you are right.
> This leads to another question though. What does it means for a
> per-user clock to be disabled and change it's floor or ceiling?
> Should that count in the aggregation logic?
Per-user clocks don't get disabled, the whole clock does (but we can
use per-user clk information to provide better debug information about
unbalanced calls to prepare and enable).
> So far we haven't required drivers to explicitly call
> clk_set_rate() with 0 so they can "drop" their rate request
> because there isn't any other user and disabling the clock is
> pretty much the same. With multiple users it looks like we're
> going to require them to set the floor or ceiling to 0 or INT_MAX
> if they want to remove their request. Alternatively we could
> track the prepare/unprepare state of the per-user clock and drop
> the constraint when that instance is unprepared (or reapply it
> when prepared). It's pretty much a semantic difference, but one
> benefit would be that we don't have to make two (or three?) calls
> to the clock framework if we want to drop the rate constraints
> and disable the clock.
In my mind this is not such an issue because I view clock constraints
as attributes of the per-user clks, while the enable and prepare
states and the actual rate are attributes of the global clock
instance.
>> +}
>> +
>> /**
>> * clk_register - allocate a new clock, register it and return an opaque cookie
>> * @dev: device that is registering this clock
>> diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
>> index 1cdb727..025aca2 100644
>> --- a/include/linux/clk-private.h
>> +++ b/include/linux/clk-private.h
>> @@ -50,6 +50,7 @@ struct clk_core {
>> struct hlist_head children;
>> struct hlist_node child_node;
>> struct hlist_node debug_node;
>> + struct hlist_head per_user_clks;
>
> Can we just call it 'clks'?
Sure.
Thanks,
Tomeu
>> unsigned int notifier_count;
>> #ifdef CONFIG_DEBUG_FS
>> struct dentry *dentry;
>> @@ -61,6 +62,10 @@ struct clk {
>> struct clk_core *core;
>> const char *dev_id;
>> const char *con_id;
>> +
>> + unsigned long floor_constraint;
>> + unsigned long ceiling_constraint;
>> + struct hlist_node child_node;
>> };
>>
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
On 10/14/2014 06:27 AM, Tomeu Vizoso wrote:
> On 11 October 2014 01:55, Stephen Boyd <[email protected]> wrote:
>> On 10/09, Tomeu Vizoso wrote:
>>> +{
>>> + int ret;
>>> +
>>> + clk_prepare_lock();
>>> +
>>> + clk->floor_constraint = rate;
>> No check for ceiling being less than floor?
> No, otherwise the calling code would have to be very careful to set
> both constraints in the correct order based on the current and next
> values. In practice I expect a given consumer to either set a floor or
> a constraint, but not both.
I totally missed this. Why can't we set the ceiling to ULONG_MAX when
the clock is created? That way we can drop the if check in the
aggregation logic for a 0 valued ceiling and then we can add the ceiling
being less than floor check here too?
>
>
>>> +
>>> + WARN(rate > 0 && rate < clk->floor_constraint,
>>> + "clk %s dev %s con %s: new ceiling %lu lower than existing floor %lu\n",
>>> + clk->core->name, clk->dev_id, clk->con_id, rate,
>>> + clk->floor_constraint);
>>> +
>>> + clk->ceiling_constraint = rate;
>>> + ret = clk_set_rate(clk, clk_get_rate(clk));
>> Why not just pass 0 as the second argument? The same comment
>> applies in the floor function.
> Both behaviours seem equally correct to me, but wonder if it wouldn't
> be better to store the rate that was last set explicitly with set_rate
> and try to reapply that one after every update to the constraints,
> instead of the current rate, or 0/INT_MAX.
>
>
>> This leads to another question though. What does it means for a
>> per-user clock to be disabled and change it's floor or ceiling?
>> Should that count in the aggregation logic?
> Per-user clocks don't get disabled, the whole clock does (but we can
> use per-user clk information to provide better debug information about
> unbalanced calls to prepare and enable).
Ok.
>> So far we haven't required drivers to explicitly call
>> clk_set_rate() with 0 so they can "drop" their rate request
>> because there isn't any other user and disabling the clock is
>> pretty much the same. With multiple users it looks like we're
>> going to require them to set the floor or ceiling to 0 or INT_MAX
>> if they want to remove their request. Alternatively we could
>> track the prepare/unprepare state of the per-user clock and drop
>> the constraint when that instance is unprepared (or reapply it
>> when prepared). It's pretty much a semantic difference, but one
>> benefit would be that we don't have to make two (or three?) calls
>> to the clock framework if we want to drop the rate constraints
>> and disable the clock.
> In my mind this is not such an issue because I view clock constraints
> as attributes of the per-user clks, while the enable and prepare
> states and the actual rate are attributes of the global clock
> instance.
>
>
Alright, I just want to make sure we thought about it. I'll try to think
of any reason for this behavior and if I don't think of anything I'm
happy with the way things are.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project