diff options
author | Heiko Stübner <heiko@sntech.de> | 2014-07-03 01:59:10 +0200 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-07-13 12:17:06 -0700 |
commit | 90c590254051f511299538c158e12fdad41ce163 (patch) | |
tree | d77e33a138a6b9ec55f2b7f0cdbf259cb3cffff4 /drivers/clk/rockchip/clk.c | |
parent | a245fecbb8064641d9cc317b347b5bdb2b7a4bb6 (diff) | |
download | op-kernel-dev-90c590254051f511299538c158e12fdad41ce163.zip op-kernel-dev-90c590254051f511299538c158e12fdad41ce163.tar.gz |
clk: rockchip: add clock type for pll clocks and pll used on rk3066
All known Rockchip SoCs down to the RK28xx (ARM9) use a similar pattern to
handle their plls:
|--\
xin32k ----------------|mux\
xin24m -----| pll |----|pll|--- pll output
\---------------|src/
|--/
The pll output is sourced from 1 of 3 sources, the actual pll being one of
them. To change the pll frequency it is imperative to remux it to another
source beforehand. This is done by adding a clock-listener to the pll that
handles the remuxing before and after the rate change.
The output mux is implemented as a separate clock to make use of already
existing common-clock features for disabling the pll if one of the other
two sources is used.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-By: Max Schwarz <max.schwarz@online.de>
Tested-By: Max Schwarz <max.schwarz@online.de>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/rockchip/clk.c')
-rw-r--r-- | drivers/clk/rockchip/clk.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index aa15d5a..278cf9d 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -23,6 +23,8 @@ #include <linux/slab.h> #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> #include "clk.h" /** @@ -105,11 +107,15 @@ static DEFINE_SPINLOCK(clk_lock); static struct clk **clk_table; static void __iomem *reg_base; static struct clk_onecell_data clk_data; +static struct device_node *cru_node; +static struct regmap *grf; void __init rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks) { reg_base = base; + cru_node = np; + grf = ERR_PTR(-EPROBE_DEFER); clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); if (!clk_table) @@ -120,12 +126,41 @@ void __init rockchip_clk_init(struct device_node *np, void __iomem *base, of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); } +struct regmap *rockchip_clk_get_grf(void) +{ + if (IS_ERR(grf)) + grf = syscon_regmap_lookup_by_phandle(cru_node, "rockchip,grf"); + return grf; +} + void rockchip_clk_add_lookup(struct clk *clk, unsigned int id) { if (clk_table && id) clk_table[id] = clk; } +void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list, + unsigned int nr_pll, int grf_lock_offset) +{ + struct clk *clk; + int idx; + + for (idx = 0; idx < nr_pll; idx++, list++) { + clk = rockchip_clk_register_pll(list->type, list->name, + list->parent_names, list->num_parents, + reg_base, list->con_offset, grf_lock_offset, + list->lock_shift, list->mode_offset, + list->mode_shift, list->rate_table, &clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + list->name); + continue; + } + + rockchip_clk_add_lookup(clk, list->id); + } +} + void __init rockchip_clk_register_branches( struct rockchip_clk_branch *list, unsigned int nr_clk) |