Skip to content

Commit

Permalink
clk: at91: make use of syscon/regmap internally
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Boris Brezillon authored and Alexandre Belloni committed Feb 17, 2016
1 parent 863a81c commit 1bdf023
Show file tree
Hide file tree
Showing 15 changed files with 694 additions and 694 deletions.
93 changes: 54 additions & 39 deletions drivers/clk/at91/clk-generated.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>

#include "pmc.h"

Expand All @@ -28,8 +30,9 @@

struct clk_generated {
struct clk_hw hw;
struct at91_pmc *pmc;
struct regmap *regmap;
struct clk_range range;
spinlock_t *lock;
u32 id;
u32 gckdiv;
u8 parent_id;
Expand All @@ -41,49 +44,52 @@ struct clk_generated {
static int clk_generated_enable(struct clk_hw *hw)
{
struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc;
u32 tmp;
unsigned long flags;

pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
__func__, gck->gckdiv, gck->parent_id);

pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
tmp = pmc_read(pmc, AT91_PMC_PCR) &
~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK);
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id)
| AT91_PMC_PCR_CMD
| AT91_PMC_PCR_GCKDIV(gck->gckdiv)
| AT91_PMC_PCR_GCKEN);
pmc_unlock(pmc);
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
AT91_PMC_PCR_GCKCSS(gck->parent_id) |
AT91_PMC_PCR_CMD |
AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
AT91_PMC_PCR_GCKEN);
spin_unlock_irqrestore(gck->lock, flags);
return 0;
}

static void clk_generated_disable(struct clk_hw *hw)
{
struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc;
u32 tmp;

pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN;
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
pmc_unlock(pmc);
unsigned long flags;

spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
AT91_PMC_PCR_CMD);
spin_unlock_irqrestore(gck->lock, flags);
}

static int clk_generated_is_enabled(struct clk_hw *hw)
{
struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc;
int ret;
unsigned long flags;
unsigned int status;

pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN);
pmc_unlock(pmc);
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_read(gck->regmap, AT91_PMC_PCR, &status);
spin_unlock_irqrestore(gck->lock, flags);

return ret;
return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
}

static unsigned long
Expand Down Expand Up @@ -214,13 +220,14 @@ static const struct clk_ops generated_ops = {
*/
static void clk_generated_startup(struct clk_generated *gck)
{
struct at91_pmc *pmc = gck->pmc;
u32 tmp;
unsigned long flags;

pmc_lock(pmc);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
tmp = pmc_read(pmc, AT91_PMC_PCR);
pmc_unlock(pmc);
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
spin_unlock_irqrestore(gck->lock, flags);

gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
>> AT91_PMC_PCR_GCKCSS_OFFSET;
Expand All @@ -229,8 +236,8 @@ static void clk_generated_startup(struct clk_generated *gck)
}

static struct clk * __init
at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
const char **parent_names, u8 num_parents,
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
*name, const char **parent_names, u8 num_parents,
u8 id, const struct clk_range *range)
{
struct clk_generated *gck;
Expand All @@ -249,7 +256,8 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,

gck->id = id;
gck->hw.init = &init;
gck->pmc = pmc;
gck->regmap = regmap;
gck->lock = lock;
gck->range = *range;

clk = clk_register(NULL, &gck->hw);
Expand All @@ -261,8 +269,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
return clk;
}

void __init of_sama5d2_clk_generated_setup(struct device_node *np,
struct at91_pmc *pmc)
void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
int num;
u32 id;
Expand All @@ -272,6 +279,7 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
const char *parent_names[GENERATED_SOURCE_MAX];
struct device_node *gcknp;
struct clk_range range = CLK_RANGE(0, 0);
struct regmap *regmap;

num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX)
Expand All @@ -283,6 +291,10 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
if (!num || num > PERIPHERAL_MAX)
return;

regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;

for_each_child_of_node(np, gcknp) {
if (of_property_read_u32(gcknp, "reg", &id))
continue;
Expand All @@ -296,11 +308,14 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
&range);

clk = at91_clk_register_generated(pmc, name, parent_names,
num_parents, id, &range);
clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
parent_names, num_parents,
id, &range);
if (IS_ERR(clk))
continue;

of_clk_add_provider(gcknp, of_clk_src_simple_get, clk);
}
}
CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
of_sama5d2_clk_generated_setup);
32 changes: 20 additions & 12 deletions drivers/clk/at91/clk-h32mx.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>

#include "pmc.h"

#define H32MX_MAX_FREQ 90000000

struct clk_sama5d4_h32mx {
struct clk_hw hw;
struct at91_pmc *pmc;
struct regmap *regmap;
};

#define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
Expand All @@ -40,8 +42,10 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
unsigned int mckr;

if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV)
regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr);
if (mckr & AT91_PMC_H32MXDIV)
return parent_rate / 2;

if (parent_rate > H32MX_MAX_FREQ)
Expand Down Expand Up @@ -70,18 +74,16 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
struct at91_pmc *pmc = h32mxclk->pmc;
u32 tmp;
u32 mckr = 0;

if (parent_rate != rate && (parent_rate / 2) != rate)
return -EINVAL;

pmc_lock(pmc);
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV;
if ((parent_rate / 2) == rate)
tmp |= AT91_PMC_H32MXDIV;
pmc_write(pmc, AT91_PMC_MCKR, tmp);
pmc_unlock(pmc);
mckr = AT91_PMC_H32MXDIV;

regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
AT91_PMC_H32MXDIV, mckr);

return 0;
}
Expand All @@ -92,14 +94,18 @@ static const struct clk_ops h32mx_ops = {
.set_rate = clk_sama5d4_h32mx_set_rate,
};

void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
struct at91_pmc *pmc)
static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
{
struct clk_sama5d4_h32mx *h32mxclk;
struct clk_init_data init;
const char *parent_name;
struct regmap *regmap;
struct clk *clk;

regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;

h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
if (!h32mxclk)
return;
Expand All @@ -113,7 +119,7 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
init.flags = CLK_SET_RATE_GATE;

h32mxclk->hw.init = &init;
h32mxclk->pmc = pmc;
h32mxclk->regmap = regmap;

clk = clk_register(NULL, &h32mxclk->hw);
if (!clk) {
Expand All @@ -123,3 +129,5 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,

of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
of_sama5d4_clk_h32mx_setup);
Loading

0 comments on commit 1bdf023

Please sign in to comment.