diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/clk/versatile/clk-sp810.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/clk/versatile/clk-sp810.c')
-rw-r--r-- | kernel/drivers/clk/versatile/clk-sp810.c | 81 |
1 files changed, 18 insertions, 63 deletions
diff --git a/kernel/drivers/clk/versatile/clk-sp810.c b/kernel/drivers/clk/versatile/clk-sp810.c index 5122ef25f..a1cdef6b0 100644 --- a/kernel/drivers/clk/versatile/clk-sp810.c +++ b/kernel/drivers/clk/versatile/clk-sp810.c @@ -12,7 +12,8 @@ */ #include <linux/amba/sp810.h> -#include <linux/clkdev.h> +#include <linux/slab.h> +#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/err.h> #include <linux/of.h> @@ -32,12 +33,9 @@ struct clk_sp810_timerclken { struct clk_sp810 { struct device_node *node; - int refclk_index, timclk_index; void __iomem *base; spinlock_t lock; struct clk_sp810_timerclken timerclken[4]; - struct clk *refclk; - struct clk *timclk; }; static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw) @@ -70,55 +68,7 @@ static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index) return 0; } -/* - * FIXME - setting the parent every time .prepare is invoked is inefficient. - * This is better handled by a dedicated clock tree configuration mechanism at - * init-time. Revisit this later when such a mechanism exists - */ -static int clk_sp810_timerclken_prepare(struct clk_hw *hw) -{ - struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); - struct clk_sp810 *sp810 = timerclken->sp810; - struct clk *old_parent = __clk_get_parent(hw->clk); - struct clk *new_parent; - - if (!sp810->refclk) - sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index); - - if (!sp810->timclk) - sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index); - - if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk))) - return -ENOENT; - - /* Select fastest parent */ - if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk)) - new_parent = sp810->refclk; - else - new_parent = sp810->timclk; - - /* Switch the parent if necessary */ - if (old_parent != new_parent) { - clk_prepare(new_parent); - clk_set_parent(hw->clk, new_parent); - clk_unprepare(old_parent); - } - - return 0; -} - -static void clk_sp810_timerclken_unprepare(struct clk_hw *hw) -{ - struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw); - struct clk_sp810 *sp810 = timerclken->sp810; - - clk_put(sp810->timclk); - clk_put(sp810->refclk); -} - static const struct clk_ops clk_sp810_timerclken_ops = { - .prepare = clk_sp810_timerclken_prepare, - .unprepare = clk_sp810_timerclken_unprepare, .get_parent = clk_sp810_timerclken_get_parent, .set_parent = clk_sp810_timerclken_set_parent, }; @@ -135,28 +85,22 @@ static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec, return sp810->timerclken[clkspec->args[0]].clk; } -void __init clk_sp810_of_setup(struct device_node *node) +static void __init clk_sp810_of_setup(struct device_node *node) { struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL); const char *parent_names[2]; + int num = ARRAY_SIZE(parent_names); char name[12]; struct clk_init_data init; int i; + bool deprecated; if (!sp810) { pr_err("Failed to allocate memory for SP810!\n"); return; } - sp810->refclk_index = of_property_match_string(node, "clock-names", - "refclk"); - parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index); - - sp810->timclk_index = of_property_match_string(node, "clock-names", - "timclk"); - parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index); - - if (parent_names[0] <= 0 || parent_names[1] <= 0) { + if (of_clk_parent_fill(node, parent_names, num) != num) { pr_warn("Failed to obtain parent clocks for SP810!\n"); return; } @@ -169,7 +113,9 @@ void __init clk_sp810_of_setup(struct device_node *node) init.ops = &clk_sp810_timerclken_ops; init.flags = CLK_IS_BASIC; init.parent_names = parent_names; - init.num_parents = ARRAY_SIZE(parent_names); + init.num_parents = num; + + deprecated = !of_find_property(node, "assigned-clock-parents", NULL); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); @@ -178,6 +124,15 @@ void __init clk_sp810_of_setup(struct device_node *node) sp810->timerclken[i].channel = i; sp810->timerclken[i].hw.init = &init; + /* + * If DT isn't setting the parent, force it to be + * the 1 MHz clock without going through the framework. + * We do this before clk_register() so that it can determine + * the parent and setup the tree properly. + */ + if (deprecated) + init.ops->set_parent(&sp810->timerclken[i].hw, 1); + sp810->timerclken[i].clk = clk_register(NULL, &sp810->timerclken[i].hw); WARN_ON(IS_ERR(sp810->timerclken[i].clk)); |