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>
This commit is contained in:

committed by
Alexandre Belloni

parent
863a81c3be
commit
1bdf02326b
@@ -20,6 +20,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
@@ -58,7 +60,7 @@ struct clk_pll_layout {
|
||||
|
||||
struct clk_pll {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
u8 id;
|
||||
@@ -79,10 +81,19 @@ static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline bool clk_pll_ready(struct regmap *regmap, int id)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return status & PLL_STATUS_MASK(id) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int clk_pll_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
struct at91_pmc *pmc = pll->pmc;
|
||||
struct regmap *regmap = pll->regmap;
|
||||
const struct clk_pll_layout *layout = pll->layout;
|
||||
const struct clk_pll_characteristics *characteristics =
|
||||
pll->characteristics;
|
||||
@@ -90,38 +101,36 @@ static int clk_pll_prepare(struct clk_hw *hw)
|
||||
u32 mask = PLL_STATUS_MASK(id);
|
||||
int offset = PLL_REG(id);
|
||||
u8 out = 0;
|
||||
u32 pllr, icpr;
|
||||
unsigned int pllr;
|
||||
unsigned int status;
|
||||
u8 div;
|
||||
u16 mul;
|
||||
|
||||
pllr = pmc_read(pmc, offset);
|
||||
regmap_read(regmap, offset, &pllr);
|
||||
div = PLL_DIV(pllr);
|
||||
mul = PLL_MUL(pllr, layout);
|
||||
|
||||
if ((pmc_read(pmc, AT91_PMC_SR) & mask) &&
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
if ((status & mask) &&
|
||||
(div == pll->div && mul == pll->mul))
|
||||
return 0;
|
||||
|
||||
if (characteristics->out)
|
||||
out = characteristics->out[pll->range];
|
||||
if (characteristics->icpll) {
|
||||
icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id);
|
||||
icpr |= (characteristics->icpll[pll->range] <<
|
||||
PLL_ICPR_SHIFT(id));
|
||||
pmc_write(pmc, AT91_PMC_PLLICPR, icpr);
|
||||
}
|
||||
|
||||
pllr &= ~layout->pllr_mask;
|
||||
pllr |= layout->pllr_mask &
|
||||
(pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
|
||||
(out << PLL_OUT_SHIFT) |
|
||||
((pll->mul & layout->mul_mask) << layout->mul_shift));
|
||||
pmc_write(pmc, offset, pllr);
|
||||
if (characteristics->icpll)
|
||||
regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
|
||||
characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
|
||||
regmap_update_bits(regmap, offset, layout->pllr_mask,
|
||||
pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
|
||||
(out << PLL_OUT_SHIFT) |
|
||||
((pll->mul & layout->mul_mask) << layout->mul_shift));
|
||||
|
||||
while (!clk_pll_ready(regmap, pll->id)) {
|
||||
enable_irq(pll->irq);
|
||||
wait_event(pll->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & mask);
|
||||
clk_pll_ready(regmap, pll->id));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -130,32 +139,35 @@ static int clk_pll_prepare(struct clk_hw *hw)
|
||||
static int clk_pll_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
struct at91_pmc *pmc = pll->pmc;
|
||||
|
||||
return !!(pmc_read(pmc, AT91_PMC_SR) &
|
||||
PLL_STATUS_MASK(pll->id));
|
||||
return clk_pll_ready(pll->regmap, pll->id);
|
||||
}
|
||||
|
||||
static void clk_pll_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
struct at91_pmc *pmc = pll->pmc;
|
||||
const struct clk_pll_layout *layout = pll->layout;
|
||||
int offset = PLL_REG(pll->id);
|
||||
u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
|
||||
unsigned int mask = pll->layout->pllr_mask;
|
||||
|
||||
pmc_write(pmc, offset, tmp);
|
||||
regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
|
||||
}
|
||||
|
||||
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
unsigned int pllr;
|
||||
u16 mul;
|
||||
u8 div;
|
||||
|
||||
if (!pll->div || !pll->mul)
|
||||
regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
|
||||
|
||||
div = PLL_DIV(pllr);
|
||||
mul = PLL_MUL(pllr, pll->layout);
|
||||
|
||||
if (!div || !mul)
|
||||
return 0;
|
||||
|
||||
return (parent_rate / pll->div) * (pll->mul + 1);
|
||||
return (parent_rate / div) * (mul + 1);
|
||||
}
|
||||
|
||||
static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
|
||||
@@ -308,7 +320,7 @@ static const struct clk_ops pll_ops = {
|
||||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
|
||||
at91_clk_register_pll(struct regmap *regmap, unsigned int irq, const char *name,
|
||||
const char *parent_name, u8 id,
|
||||
const struct clk_pll_layout *layout,
|
||||
const struct clk_pll_characteristics *characteristics)
|
||||
@@ -318,7 +330,7 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
int offset = PLL_REG(id);
|
||||
u32 tmp;
|
||||
unsigned int pllr;
|
||||
|
||||
if (id > PLL_MAX_ID)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -337,11 +349,11 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
|
||||
pll->hw.init = &init;
|
||||
pll->layout = layout;
|
||||
pll->characteristics = characteristics;
|
||||
pll->pmc = pmc;
|
||||
pll->regmap = regmap;
|
||||
pll->irq = irq;
|
||||
tmp = pmc_read(pmc, offset) & layout->pllr_mask;
|
||||
pll->div = PLL_DIV(tmp);
|
||||
pll->mul = PLL_MUL(tmp, layout);
|
||||
regmap_read(regmap, offset, &pllr);
|
||||
pll->div = PLL_DIV(pllr);
|
||||
pll->mul = PLL_MUL(pllr, layout);
|
||||
init_waitqueue_head(&pll->wait);
|
||||
irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
|
||||
ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
|
||||
@@ -483,12 +495,13 @@ out_free_characteristics:
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
|
||||
of_at91_clk_pll_setup(struct device_node *np,
|
||||
const struct clk_pll_layout *layout)
|
||||
{
|
||||
u32 id;
|
||||
unsigned int irq;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct clk_pll_characteristics *characteristics;
|
||||
@@ -500,6 +513,10 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
characteristics = of_at91_clk_pll_get_characteristics(np);
|
||||
if (!characteristics)
|
||||
return;
|
||||
@@ -508,7 +525,7 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout,
|
||||
clk = at91_clk_register_pll(regmap, irq, name, parent_name, id, layout,
|
||||
characteristics);
|
||||
if (IS_ERR(clk))
|
||||
goto out_free_characteristics;
|
||||
@@ -520,26 +537,30 @@ out_free_characteristics:
|
||||
kfree(characteristics);
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
|
||||
of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
|
||||
of_at91rm9200_clk_pll_setup);
|
||||
|
||||
void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
|
||||
of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
|
||||
of_at91sam9g45_clk_pll_setup);
|
||||
|
||||
void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
|
||||
of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
|
||||
of_at91sam9g20_clk_pllb_setup);
|
||||
|
||||
void __init of_sama5d3_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
|
||||
of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
|
||||
}
|
||||
CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
|
||||
of_sama5d3_clk_pll_setup);
|
||||
|
Reference in New Issue
Block a user