Skip to content

Commit

Permalink
clk: make ICST driver handle the VCO registers
Browse files Browse the repository at this point in the history
It turns out that all platforms using the ICST VCO are really
just touching two registers, and in the same way as well: one
register with the VCO configuration as such, and one lock register
that makes it possible to write to the VCO.

Factor this register read/write into the ICST driver so we can
reuse it in the IM-PD1 driver.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
  • Loading branch information
Linus Walleij authored and Mike Turquette committed Nov 21, 2012
1 parent 401301c commit 7a9ad67
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 95 deletions.
60 changes: 51 additions & 9 deletions drivers/clk/versatile/clk-icst.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,74 @@
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>

#include "clk-icst.h"

/**
* struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry
* @vcoreg: VCO register address
* @lockreg: VCO lock register address
* @params: parameters for this ICST instance
* @rate: current rate
* @setvco: function to commit ICST settings to hardware
*/
struct clk_icst {
struct clk_hw hw;
void __iomem *vcoreg;
void __iomem *lockreg;
const struct icst_params *params;
unsigned long rate;
struct icst_vco (*getvco)(void);
void (*setvco)(struct icst_vco);
};

#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)

/**
* vco_get() - get ICST VCO settings from a certain register
* @vcoreg: register containing the VCO settings
*/
static struct icst_vco vco_get(void __iomem *vcoreg)
{
u32 val;
struct icst_vco vco;

val = readl(vcoreg);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}

/**
* vco_set() - commit changes to an ICST VCO
* @locreg: register to poke to unlock the VCO for writing
* @vcoreg: register containing the VCO settings
* @vco: ICST VCO parameters to commit
*/
static void vco_set(void __iomem *lockreg,
void __iomem *vcoreg,
struct icst_vco vco)
{
u32 val;

val = readl(vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);

/* This magic unlocks the VCO so it can be controlled */
writel(0xa05f, lockreg);
writel(val, vcoreg);
/* This locks the VCO again */
writel(0, lockreg);
}


static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;

vco = icst->getvco();
vco = vco_get(icst->vcoreg);
icst->rate = icst_hz(icst->params, vco);
return icst->rate;
}
Expand All @@ -66,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,

vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco);
icst->setvco(vco);
vco_set(icst->vcoreg, icst->lockreg, vco);
return 0;
}

Expand All @@ -76,8 +117,9 @@ static const struct clk_ops icst_ops = {
.set_rate = icst_set_rate,
};

struct clk * __init icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc)
struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc,
void __iomem *base)
{
struct clk *clk;
struct clk_icst *icst;
Expand All @@ -95,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev,
init.num_parents = 0;
icst->hw.init = &init;
icst->params = desc->params;
icst->getvco = desc->getvco;
icst->setvco = desc->setvco;
icst->vcoreg = base + desc->vco_offset;
icst->lockreg = base + desc->lock_offset;

clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk))
Expand Down
14 changes: 11 additions & 3 deletions drivers/clk/versatile/clk-icst.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#include <asm/hardware/icst.h>

/**
* struct clk_icst_desc - descriptor for the ICST VCO
* @params: ICST parameters
* @vco_offset: offset to the ICST VCO from the provided memory base
* @lock_offset: offset to the ICST VCO locking register from the provided
* memory base
*/
struct clk_icst_desc {
const struct icst_params *params;
struct icst_vco (*getvco)(void);
void (*setvco)(struct icst_vco);
u32 vco_offset;
u32 lock_offset;
};

struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc);
const struct clk_icst_desc *desc,
void __iomem *base);
45 changes: 5 additions & 40 deletions drivers/clk/versatile/clk-integrator.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_data/clk-integrator.h>

#include <mach/hardware.h>
#include <mach/platform.h>
Expand All @@ -22,42 +22,6 @@
* Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/
#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)

/**
* cp_auxvco_get() - get ICST VCO settings for the Integrator/CP
* @vco: ICST VCO parameters to update with hardware status
*/
static struct icst_vco cp_auxvco_get(void)
{
u32 val;
struct icst_vco vco;

val = readl(CM_AUXOSC);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}

/**
* cp_auxvco_set() - commit changes to Integrator/CP ICST VCO
* @vco: ICST VCO parameters to commit
*/
static void cp_auxvco_set(struct icst_vco vco)
{
u32 val;

val = readl(CM_AUXOSC) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);

/* This magic unlocks the CM VCO so it can be controlled */
writel(0xa05f, CM_LOCK);
writel(val, CM_AUXOSC);
/* This locks the CM again */
writel(0, CM_LOCK);
}

static const struct icst_params cp_auxvco_params = {
.ref = 24000000,
Expand All @@ -73,8 +37,8 @@ static const struct icst_params cp_auxvco_params = {

static const struct clk_icst_desc __initdata cp_icst_desc = {
.params = &cp_auxvco_params,
.getvco = cp_auxvco_get,
.setvco = cp_auxvco_set,
.vco_offset = 0x1c,
.lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
};

/*
Expand Down Expand Up @@ -114,6 +78,7 @@ void __init integrator_clk_init(bool is_cp)
clk_register_clkdev(clk, NULL, "sp804");

/* ICST VCO clock used on the Integrator/CP CLCD */
clk = icst_clk_register(NULL, &cp_icst_desc);
clk = icst_clk_register(NULL, &cp_icst_desc,
__io_address(INTEGRATOR_HDR_BASE));
clk_register_clkdev(clk, NULL, "clcd");
}
57 changes: 14 additions & 43 deletions drivers/clk/versatile/clk-realview.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,6 @@
* Implementation of the ARM RealView clock trees.
*/

static void __iomem *sys_lock;
static void __iomem *sys_vcoreg;

/**
* realview_oscvco_get() - get ICST OSC settings for the RealView
*/
static struct icst_vco realview_oscvco_get(void)
{
u32 val;
struct icst_vco vco;

val = readl(sys_vcoreg);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}

static void realview_oscvco_set(struct icst_vco vco)
{
u32 val;

val = readl(sys_vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);

/* This magic unlocks the CM VCO so it can be controlled */
writel(0xa05f, sys_lock);
writel(val, sys_vcoreg);
/* This locks the CM again */
writel(0, sys_lock);
}

static const struct icst_params realview_oscvco_params = {
.ref = 24000000,
.vco_max = ICST307_VCO_MAX,
Expand All @@ -65,10 +33,16 @@ static const struct icst_params realview_oscvco_params = {
.idx2s = icst307_idx2s,
};

static const struct clk_icst_desc __initdata realview_icst_desc = {
static const struct clk_icst_desc __initdata realview_osc0_desc = {
.params = &realview_oscvco_params,
.getvco = realview_oscvco_get,
.setvco = realview_oscvco_set,
.vco_offset = REALVIEW_SYS_OSC0_OFFSET,
.lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};

static const struct clk_icst_desc __initdata realview_osc4_desc = {
.params = &realview_oscvco_params,
.vco_offset = REALVIEW_SYS_OSC4_OFFSET,
.lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};

/*
Expand All @@ -78,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
{
struct clk *clk;

sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
if (is_pb1176)
sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
else
sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;


/* APB clock dummy */
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL);
Expand Down Expand Up @@ -116,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
clk_register_clkdev(clk, NULL, "sp804");

/* ICST VCO clock */
clk = icst_clk_register(NULL, &realview_icst_desc);
if (is_pb1176)
clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase);
else
clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase);

clk_register_clkdev(clk, NULL, "dev:clcd");
clk_register_clkdev(clk, NULL, "issp:clcd");
}

0 comments on commit 7a9ad67

Please sign in to comment.