Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a9ad671 authored by Linus Walleij's avatar Linus Walleij Committed by Mike Turquette
Browse files

clk: make ICST driver handle the VCO registers



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: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent 401301cc
Loading
Loading
Loading
Loading
+51 −9
Original line number Diff line number Diff line
@@ -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;
}
@@ -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;
}

@@ -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;
@@ -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))
+11 −3
Original line number Diff line number Diff line
#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);
+5 −40
Original line number Diff line number Diff line
@@ -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>
@@ -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,
@@ -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,
};

/*
@@ -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");
}
+14 −43
Original line number Diff line number Diff line
@@ -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,
@@ -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,
};

/*
@@ -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);
@@ -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");
}