summaryrefslogtreecommitdiff
path: root/drivers/clk/at91/clk-programmable.c
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@free-electrons.com>2014-09-07 10:14:29 +0400
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2016-02-17 19:52:58 +0300
commit1bdf02326b71eae7e9b4b335b881856aaf9d1af6 (patch)
treea11ad267acd940e4e7aff9846d94689158c246b2 /drivers/clk/at91/clk-programmable.c
parent863a81c3be1d931bdae6426e231add9334311f13 (diff)
downloadlinux-1bdf02326b71eae7e9b4b335b881856aaf9d1af6.tar.xz
clk: at91: make use of syscon/regmap internally
Use the regmap coming from syscon to access the registers instead of using pmc_read/pmc_write. This allows to avoid passing the at91_pmc structure to the child nodes of the PMC. The final benefit is to have each clock register itself instead of having to iterate over the children. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Acked-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/clk/at91/clk-programmable.c')
-rw-r--r--drivers/clk/at91/clk-programmable.c92
1 files changed, 51 insertions, 41 deletions
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index 14b270b85fec..78814ba448c4 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -16,6 +16,8 @@
#include <linux/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include "pmc.h"
@@ -24,6 +26,7 @@
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
#define PROG_PRES_MASK 0x7
+#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
#define PROG_MAX_RM9200_CSS 3
struct clk_programmable_layout {
@@ -34,7 +37,7 @@ struct clk_programmable_layout {
struct clk_programmable {
struct clk_hw hw;
- struct at91_pmc *pmc;
+ struct regmap *regmap;
u8 id;
const struct clk_programmable_layout *layout;
};
@@ -44,14 +47,12 @@ struct clk_programmable {
static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
- u32 pres;
struct clk_programmable *prog = to_clk_programmable(hw);
- struct at91_pmc *pmc = prog->pmc;
- const struct clk_programmable_layout *layout = prog->layout;
+ unsigned int pckr;
+
+ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
- pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) &
- PROG_PRES_MASK;
- return parent_rate >> pres;
+ return parent_rate >> PROG_PRES(prog->layout, pckr);
}
static int clk_programmable_determine_rate(struct clk_hw *hw,
@@ -101,36 +102,36 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
- struct at91_pmc *pmc = prog->pmc;
- u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask;
+ unsigned int mask = layout->css_mask;
+ unsigned int pckr = 0;
if (layout->have_slck_mck)
- tmp &= AT91_PMC_CSSMCK_MCK;
+ mask |= AT91_PMC_CSSMCK_MCK;
if (index > layout->css_mask) {
- if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
- tmp |= AT91_PMC_CSSMCK_MCK;
- return 0;
- } else {
+ if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
return -EINVAL;
- }
+
+ pckr |= AT91_PMC_CSSMCK_MCK;
}
- pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index);
+ regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr);
+
return 0;
}
static u8 clk_programmable_get_parent(struct clk_hw *hw)
{
- u32 tmp;
- u8 ret;
struct clk_programmable *prog = to_clk_programmable(hw);
- struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
+ unsigned int pckr;
+ u8 ret;
+
+ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
+
+ ret = pckr & layout->css_mask;
- tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
- ret = tmp & layout->css_mask;
- if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
+ if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
ret = PROG_MAX_RM9200_CSS + 1;
return ret;
@@ -140,26 +141,27 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_programmable *prog = to_clk_programmable(hw);
- struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout;
unsigned long div = parent_rate / rate;
+ unsigned int pckr;
int shift = 0;
- u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) &
- ~(PROG_PRES_MASK << layout->pres_shift);
+
+ regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
if (!div)
return -EINVAL;
shift = fls(div) - 1;
- if (div != (1<<shift))
+ if (div != (1 << shift))
return -EINVAL;
if (shift >= PROG_PRES_MASK)
return -EINVAL;
- pmc_write(pmc, AT91_PMC_PCKR(prog->id),
- tmp | (shift << layout->pres_shift));
+ regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
+ PROG_PRES_MASK << layout->pres_shift,
+ shift << layout->pres_shift);
return 0;
}
@@ -173,7 +175,7 @@ static const struct clk_ops programmable_ops = {
};
static struct clk * __init
-at91_clk_register_programmable(struct at91_pmc *pmc,
+at91_clk_register_programmable(struct regmap *regmap,
const char *name, const char **parent_names,
u8 num_parents, u8 id,
const struct clk_programmable_layout *layout)
@@ -198,7 +200,7 @@ at91_clk_register_programmable(struct at91_pmc *pmc,
prog->id = id;
prog->layout = layout;
prog->hw.init = &init;
- prog->pmc = pmc;
+ prog->regmap = regmap;
clk = clk_register(NULL, &prog->hw);
if (IS_ERR(clk))
@@ -226,7 +228,7 @@ static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
};
static void __init
-of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
+of_at91_clk_prog_setup(struct device_node *np,
const struct clk_programmable_layout *layout)
{
int num;
@@ -236,6 +238,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
const char *parent_names[PROG_SOURCE_MAX];
const char *name;
struct device_node *progclknp;
+ struct regmap *regmap;
num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
@@ -247,6 +250,10 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (!num || num > (PROG_ID_MAX + 1))
return;
+ regmap = syscon_node_to_regmap(of_get_parent(np));
+ if (IS_ERR(regmap))
+ return;
+
for_each_child_of_node(np, progclknp) {
if (of_property_read_u32(progclknp, "reg", &id))
continue;
@@ -254,7 +261,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name;
- clk = at91_clk_register_programmable(pmc, name,
+ clk = at91_clk_register_programmable(regmap, name,
parent_names, num_parents,
id, layout);
if (IS_ERR(clk))
@@ -265,20 +272,23 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
}
-void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc)
+static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
{
- of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout);
+ of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
}
+CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
+ of_at91rm9200_clk_prog_setup);
-void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc)
+static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
{
- of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout);
+ of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
}
+CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
+ of_at91sam9g45_clk_prog_setup);
-void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
- struct at91_pmc *pmc)
+static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
{
- of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout);
+ of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
}
+CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
+ of_at91sam9x5_clk_prog_setup);