From patchwork Tue Nov 20 21:39:41 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 1776031 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 6C4D8DFF38 for ; Tue, 20 Nov 2012 21:41:47 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TavY1-0005UV-QJ; Tue, 20 Nov 2012 21:40:02 +0000 Received: from mail.df.lth.se ([194.47.250.12]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TavXm-0005Q5-Vm for linux-arm-kernel@lists.infradead.org; Tue, 20 Nov 2012 21:39:48 +0000 Received: from mer.df.lth.se (mer.df.lth.se [194.47.250.37]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.df.lth.se (Postfix) with ESMTPS id EE47F65D38; Tue, 20 Nov 2012 22:39:44 +0100 (CET) Received: from mer.df.lth.se (triad@localhost.localdomain [127.0.0.1]) by mer.df.lth.se (8.14.3/8.14.3/Debian-9.4) with ESMTP id qAKLdiex012942; Tue, 20 Nov 2012 22:39:44 +0100 Received: (from triad@localhost) by mer.df.lth.se (8.14.3/8.14.3/Submit) id qAKLdi4f012941; Tue, 20 Nov 2012 22:39:44 +0100 From: Linus Walleij To: Mike Turquette , Mike Turquette Subject: [PATCH 2/3] clk: make ICST driver handle the VCO registers Date: Tue, 20 Nov 2012 22:39:41 +0100 Message-Id: <1353447581-12914-1-git-send-email-linus.walleij@linaro.org> X-Mailer: git-send-email 1.7.2.5 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121120_163947_455556_0B25CF8A X-CRM114-Status: GOOD ( 19.44 ) X-Spam-Score: -3.3 (---) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-3.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [194.47.250.12 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Linus Walleij , arm@kernel.org, Russell King , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 --- drivers/clk/versatile/clk-icst.c | 60 +++++++++++++++++++++++++++++----- drivers/clk/versatile/clk-icst.h | 14 ++++++-- drivers/clk/versatile/clk-integrator.c | 45 +++---------------------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 23d2d7e..67ccf4a 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -17,33 +17,74 @@ #include #include #include +#include #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)) diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index 71b4c56..dad51b6 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -1,10 +1,18 @@ #include +/** + * 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); diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c index 3c816ae..08593b4 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-integrator.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -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"); }