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>
This commit is contained in:
Maxime Ripard 2014-07-04 22:24:52 +02:00
parent 9824cf73c3
commit 601da9d0a5
3 changed files with 115 additions and 101 deletions

View File

@ -9,18 +9,18 @@
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.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/string.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;
}

View File

@ -3,9 +3,12 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h>
#define SUNXI_FACTORS_NOT_APPLICABLE (0)
#define SUNXI_FACTORS_MUX_MASK 0x3
struct clk_factors_config {
u8 nshift;
u8 nwidth;
@ -18,6 +21,14 @@ struct clk_factors_config {
u8 n_start;
};
struct factors_data {
int enable;
int mux;
struct clk_factors_config *table;
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
const char *name;
};
struct clk_factors {
struct clk_hw hw;
void __iomem *reg;
@ -26,5 +37,8 @@ struct clk_factors {
spinlock_t *lock;
};
extern const struct clk_ops clk_factors_ops;
struct clk * __init sunxi_factors_register(struct device_node *node,
const struct factors_data *data,
spinlock_t *lock);
#endif

View File

@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
#include "clk-factors.h"
@ -440,16 +441,6 @@ EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
* sunxi_factors_clk_setup() - Setup function for factor clocks
*/
#define SUNXI_FACTORS_MUX_MASK 0x3
struct factors_data {
int enable;
int mux;
struct clk_factors_config *table;
void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
const char *name;
};
static struct clk_factors_config sun4i_pll1_config = {
.nshift = 8,
.nwidth = 5,
@ -583,89 +574,9 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
};
static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
const struct factors_data *data)
const struct factors_data *data)
{
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[SUNXI_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 < SUNXI_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;
/* 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 = &clk_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 = &clk_lock;
mux_hw = &mux->hw;
}
/* set up factors properties */
factors->reg = reg;
factors->config = data->table;
factors->get_factors = data->getter;
factors->lock = &clk_lock;
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;
return sunxi_factors_register(node, data, &clk_lock);
}