summaryrefslogtreecommitdiff
path: root/drivers/clk/rockchip/clk.c
diff options
context:
space:
mode:
authorHeiko Stübner <heiko@sntech.de>2014-07-03 01:59:10 +0200
committerMike Turquette <mturquette@linaro.org>2014-07-13 12:17:06 -0700
commit90c590254051f511299538c158e12fdad41ce163 (patch)
treed77e33a138a6b9ec55f2b7f0cdbf259cb3cffff4 /drivers/clk/rockchip/clk.c
parenta245fecbb8064641d9cc317b347b5bdb2b7a4bb6 (diff)
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.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index aa15d5ae51d1..278cf9dd1e23 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)