1
0
Fork 0

clk: mmp: add basic support functions for DT support

In order to support DT for mmp SOC clocks, it defines
some basic APIs which are shared by all mmp SOC clock
units.

Signed-off-by: Chao Xie <chao.xie@marvell.com>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
hifive-unleashed-5.1
Chao Xie 2014-10-31 10:13:47 +08:00 committed by Michael Turquette
parent cdce35460f
commit 4661fda10f
3 changed files with 298 additions and 2 deletions

View File

@ -2,7 +2,7 @@
# Makefile for mmp specific clk
#
obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o
obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o
obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o

View File

@ -0,0 +1,192 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "clk.h"
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
int nr_clks)
{
static struct clk **clk_table;
clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
if (!clk_table)
return;
unit->clk_table = clk_table;
unit->nr_clks = nr_clks;
unit->clk_data.clks = clk_table;
unit->clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data);
}
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_rate_clk *clks,
int size)
{
int i;
struct clk *clk;
for (i = 0; i < size; i++) {
clk = clk_register_fixed_rate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
clks[i].fixed_rate);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_factor_clk *clks,
int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_fixed_factor(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags, clks[i].mult,
clks[i].div);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_general_gate_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_gate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].bit_idx,
clks[i].gate_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_gate_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = mmp_clk_register_gate(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].mask,
clks[i].val_enable,
clks[i].val_disable,
clks[i].gate_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
struct mmp_param_mux_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_mux(NULL, clks[i].name,
clks[i].parent_name,
clks[i].num_parents,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].mux_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_register_div_clks(struct mmp_clk_unit *unit,
struct mmp_param_div_clk *clks,
void __iomem *base, int size)
{
struct clk *clk;
int i;
for (i = 0; i < size; i++) {
clk = clk_register_divider(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].div_flags,
clks[i].lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].id)
unit->clk_table[clks[i].id] = clk;
}
}
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
struct clk *clk)
{
if (IS_ERR_OR_NULL(clk)) {
pr_err("CLK %d has invalid pointer %p\n", id, clk);
return;
}
if (id > unit->nr_clks) {
pr_err("CLK %d is invalid\n", id);
return;
}
unit->clk_table[id] = clk;
}

View File

@ -96,8 +96,8 @@ struct mmp_clk_mix {
extern const struct clk_ops mmp_clk_mix_ops;
extern struct clk *mmp_clk_register_mix(struct device *dev,
const char *name,
u8 num_parents,
const char **parent_names,
u8 num_parents,
unsigned long flags,
struct mmp_clk_mix_config *config,
spinlock_t *lock);
@ -132,4 +132,108 @@ extern struct clk *mmp_clk_register_apbc(const char *name,
extern struct clk *mmp_clk_register_apmu(const char *name,
const char *parent_name, void __iomem *base, u32 enable_mask,
spinlock_t *lock);
struct mmp_clk_unit {
unsigned int nr_clks;
struct clk **clk_table;
struct clk_onecell_data clk_data;
};
struct mmp_param_fixed_rate_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long fixed_rate;
};
void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_rate_clk *clks,
int size);
struct mmp_param_fixed_factor_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long mult;
unsigned long div;
unsigned long flags;
};
void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit,
struct mmp_param_fixed_factor_clk *clks,
int size);
struct mmp_param_general_gate_clk {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 bit_idx;
u8 gate_flags;
spinlock_t *lock;
};
void mmp_register_general_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_general_gate_clk *clks,
void __iomem *base, int size);
struct mmp_param_gate_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u32 mask;
u32 val_enable;
u32 val_disable;
unsigned int gate_flags;
spinlock_t *lock;
};
void mmp_register_gate_clks(struct mmp_clk_unit *unit,
struct mmp_param_gate_clk *clks,
void __iomem *base, int size);
struct mmp_param_mux_clk {
unsigned int id;
char *name;
const char **parent_name;
u8 num_parents;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u8 mux_flags;
spinlock_t *lock;
};
void mmp_register_mux_clks(struct mmp_clk_unit *unit,
struct mmp_param_mux_clk *clks,
void __iomem *base, int size);
struct mmp_param_div_clk {
unsigned int id;
char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u8 div_flags;
spinlock_t *lock;
};
void mmp_register_div_clks(struct mmp_clk_unit *unit,
struct mmp_param_div_clk *clks,
void __iomem *base, int size);
#define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \
{ \
.width_div = (w_d), \
.shift_div = (s_d), \
.width_mux = (w_m), \
.shift_mux = (s_m), \
.bit_fc = (fc), \
}
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
int nr_clks);
void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id,
struct clk *clk);
#endif