Skip to content

Commit

Permalink
clk: mmp: add basic support functions for DT support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chao Xie authored and Michael Turquette committed Nov 13, 2014
1 parent cdce354 commit 4661fda
Show file tree
Hide file tree
Showing 3 changed files with 298 additions and 2 deletions.
2 changes: 1 addition & 1 deletion drivers/clk/mmp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
192 changes: 192 additions & 0 deletions drivers/clk/mmp/clk.c
Original file line number Diff line number Diff line change
@@ -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;
}
106 changes: 105 additions & 1 deletion drivers/clk/mmp/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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

0 comments on commit 4661fda

Please sign in to comment.