aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi/clk-factors.c
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2014-07-04 22:24:52 +0200
committerMaxime Ripard <maxime.ripard@free-electrons.com>2014-09-27 08:58:01 +0200
commit601da9d0a54c0fea7f5a208bc107d7ef1de4f570 (patch)
tree7ef940807784343319cf92c4c23a56e7157964d6 /drivers/clk/sunxi/clk-factors.c
parentclk: Add a function to retrieve phase (diff)
downloadlinux-dev-601da9d0a54c0fea7f5a208bc107d7ef1de4f570.tar.xz
linux-dev-601da9d0a54c0fea7f5a208bc107d7ef1de4f570.zip
clk: sunxi: factors: Invert the probing logic
Until now, the factors clock probing was done directly by sunxi_init_clocks, with the factors registration being called directly with the clocks data passed as an argument. This approch has shown its limits when we added more clocks, since we couldn't really split code with such a logic in smaller files, and led to a huge file having all the clocks. Introduce an intermediate probing function, so that factor clocks will be able to directly be called by CLK_OF_DECLARE, which will in turn ease the split into several files. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/clk/sunxi/clk-factors.c')
-rw-r--r--drivers/clk/sunxi/clk-factors.c101
1 files changed, 95 insertions, 6 deletions
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 2057c8ac648f..f83ba097126c 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -9,18 +9,18 @@
*/
#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/err.h>
#include <linux/string.h>
-#include <linux/delay.h>
-
#include "clk-factors.h"
/*
- * DOC: basic adjustable factor-based clock that cannot gate
+ * DOC: basic adjustable factor-based clock
*
* Traits of this clock:
* prepare - clk_prepare only ensures that parents are prepared
@@ -32,6 +32,8 @@
#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
+#define FACTORS_MAX_PARENTS 5
+
#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
@@ -147,9 +149,96 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
-const struct clk_ops clk_factors_ops = {
+static const struct clk_ops clk_factors_ops = {
.determine_rate = clk_factors_determine_rate,
.recalc_rate = clk_factors_recalc_rate,
.round_rate = clk_factors_round_rate,
.set_rate = clk_factors_set_rate,
};
+
+struct clk * __init sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock)
+{
+ struct clk *clk;
+ struct clk_factors *factors;
+ struct clk_gate *gate = NULL;
+ struct clk_mux *mux = NULL;
+ struct clk_hw *gate_hw = NULL;
+ struct clk_hw *mux_hw = NULL;
+ const char *clk_name = node->name;
+ const char *parents[FACTORS_MAX_PARENTS];
+ void __iomem *reg;
+ int i = 0;
+
+ reg = of_iomap(node, 0);
+
+ /* if we have a mux, we will have >1 parents */
+ while (i < FACTORS_MAX_PARENTS &&
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ /*
+ * some factor clocks, such as pll5 and pll6, may have multiple
+ * outputs, and have their name designated in factors_data
+ */
+ if (data->name)
+ clk_name = data->name;
+ else
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
+ if (!factors)
+ return NULL;
+
+ /* set up factors properties */
+ factors->reg = reg;
+ factors->config = data->table;
+ factors->get_factors = data->getter;
+ factors->lock = lock;
+
+ /* Add a gate if this factor clock can be gated */
+ if (data->enable) {
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(factors);
+ return NULL;
+ }
+
+ /* set up gate properties */
+ gate->reg = reg;
+ gate->bit_idx = data->enable;
+ gate->lock = factors->lock;
+ gate_hw = &gate->hw;
+ }
+
+ /* Add a mux if this factor clock can be muxed */
+ if (data->mux) {
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux) {
+ kfree(factors);
+ kfree(gate);
+ return NULL;
+ }
+
+ /* set up gate properties */
+ mux->reg = reg;
+ mux->shift = data->mux;
+ mux->mask = SUNXI_FACTORS_MUX_MASK;
+ mux->lock = factors->lock;
+ mux_hw = &mux->hw;
+ }
+
+ clk = clk_register_composite(NULL, clk_name,
+ parents, i,
+ mux_hw, &clk_mux_ops,
+ &factors->hw, &clk_factors_ops,
+ gate_hw, &clk_gate_ops, 0);
+
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+
+ return clk;
+}