From patchwork Mon May 7 05:08:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Turquette X-Patchwork-Id: 8423 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 9C8A423E00 for ; Mon, 7 May 2012 05:14:14 +0000 (UTC) Received: from mail-ob0-f180.google.com (mail-ob0-f180.google.com [209.85.214.180]) by fiordland.canonical.com (Postfix) with ESMTP id 35CE7A18679 for ; Mon, 7 May 2012 05:14:14 +0000 (UTC) Received: by obbup16 with SMTP id up16so10137768obb.11 for ; Sun, 06 May 2012 22:14:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:x-gm-message-state; bh=jqNSjvfm+FrrpYCFHQofcOQgfchnbvboeMG12neefwE=; b=DvomvEBZd4ZEp+Whd2nNeBbG9uUsJPaynxLeHFP7zEqbxdPMprPl6IAz1c75On/1yt g3TrPoJstxXUZm3Cih38Xb8RWMdBZcFswW/H/816xmFUiAZNfnre7oOjt4w1xNIHviIj LI8SrZ56ylj3lqChBGzfoqJngYtftMAcRZx1k5efVX/ZW/VZtBhJ428vGptcI8d0NTF5 RdwmfP5oAjfkN0eEFuMLPCb7y9zZGKFy4uDo6oE6Cryss8C320YcsVATDDqAYqqZe86T f/C1CEIm5f8k7Zb9NCbT3aYmXr2ph8b8qKlo/5njNb8S0f8Utj7EB1Vc7BvcDN/ULXhX unkg== Received: by 10.50.89.168 with SMTP id bp8mr7410061igb.3.1336367653401; Sun, 06 May 2012 22:14:13 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.73.147 with SMTP id q19csp102860ibj; Sun, 6 May 2012 22:14:12 -0700 (PDT) Received: by 10.60.14.169 with SMTP id q9mr3247058oec.19.1336367652283; Sun, 06 May 2012 22:14:12 -0700 (PDT) Received: from devils.ext.ti.com (devils.ext.ti.com. [198.47.26.153]) by mx.google.com with ESMTPS id bl9si9184516obb.145.2012.05.06.22.14.11 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 06 May 2012 22:14:12 -0700 (PDT) Received-SPF: neutral (google.com: 198.47.26.153 is neither permitted nor denied by best guess record for domain of mturquette@linaro.org) client-ip=198.47.26.153; Authentication-Results: mx.google.com; spf=neutral (google.com: 198.47.26.153 is neither permitted nor denied by best guess record for domain of mturquette@linaro.org) smtp.mail=mturquette@linaro.org Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id q475E8rl016952; Mon, 7 May 2012 00:14:08 -0500 Received: from DFLE71.ent.ti.com (dfle71.ent.ti.com [128.247.5.62]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q475E8Nq022416; Mon, 7 May 2012 00:14:08 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by dfle71.ent.ti.com (128.247.5.62) with Microsoft SMTP Server id 14.1.323.3; Mon, 7 May 2012 00:14:08 -0500 Received: from nucleus.nsc.com (nucleus.nsc.com [10.188.36.112]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q475DxRr028783; Mon, 7 May 2012 00:14:07 -0500 From: Mike Turquette To: CC: , , , , , , , , , , , , , Mike Turquette Subject: [PATCH 5/5] clk: add a fixed factor clock Date: Sun, 6 May 2012 22:08:30 -0700 Message-ID: <1336367310-5140-6-git-send-email-mturquette@linaro.org> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1336367310-5140-1-git-send-email-mturquette@linaro.org> References: <1336367310-5140-1-git-send-email-mturquette@linaro.org> MIME-Version: 1.0 X-Gm-Message-State: ALoCoQnsEeuNQVF2NnP5ot/mlok6dSjd4ei3peyWe3h69enFveZCsillqQhaFGQacwSAlZbDGTtK From: Sascha Hauer Having fixed factors/dividers in hardware is a common pattern, so add a basic clock type doing this. It basically describes a fixed factor clock using a nominator and a denominator. Signed-off-by: Sascha Hauer Reviewed-by: Viresh Kumar [mturquette@linaro.org: constify parent_names in static init macro] [mturquette@linaro.org: copy/paste bug from mux in static init macro] [mturquette@linaro.org: fix error handling in clk_register_fixed_factor] Signed-off-by: Mike Turquette --- drivers/clk/Makefile | 2 +- drivers/clk/clk-fixed-factor.c | 95 ++++++++++++++++++++++++++++++++++++++++ include/linux/clk-private.h | 20 ++++++++ include/linux/clk-provider.h | 23 ++++++++++ 4 files changed, 139 insertions(+), 1 deletions(-) create mode 100644 drivers/clk/clk-fixed-factor.c diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 1f736bc..24aa714 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ - clk-mux.o clk-divider.o + clk-mux.o clk-divider.o clk-fixed-factor.o diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c new file mode 100644 index 0000000..1f2da01 --- /dev/null +++ b/drivers/clk/clk-fixed-factor.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Standard functionality for the common clock API. + */ +#include +#include +#include +#include + +/* + * DOC: basic fixed multiplier and divider clock that cannot gate + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is fixed. clk->rate = parent->rate / div * mult + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) + +static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + return (parent_rate / fix->div) * fix->mult; +} + +static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { + unsigned long best_parent; + + best_parent = (rate / fix->mult) * fix->div; + *prate = __clk_round_rate(__clk_get_parent(hw->clk), + best_parent); + } + + return (*prate / fix->div) * fix->mult; +} + +static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +struct clk_ops clk_fixed_factor_ops = { + .round_rate = clk_factor_round_rate, + .set_rate = clk_factor_set_rate, + .recalc_rate = clk_factor_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); + +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + struct clk_fixed_factor *fix; + struct clk_init_data init; + struct clk *clk; + + fix = kmalloc(sizeof(*fix), GFP_KERNEL); + if (!fix) { + pr_err("%s: could not allocate fixed factor clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + /* struct clk_fixed_factor assignments */ + fix->mult = mult; + fix->div = div; + fix->hw.init = &init; + + init.name = name; + init.ops = &clk_fixed_factor_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk = clk_register(dev, &fix->hw); + + if (IS_ERR(clk)) + kfree(fix); + + return clk; +} diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index b258532..eb3f84b 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -143,6 +143,26 @@ struct clk { DEFINE_CLK(_name, clk_mux_ops, _flags, _parent_names, \ _parents); +#define DEFINE_CLK_FIXED_FACTOR(_name, _parent_name, \ + _parent_ptr, _flags, \ + _mult, _div) \ + static struct clk _name; \ + static const char *_name##_parent_names[] = { \ + _parent_name, \ + }; \ + static struct clk *_name##_parents[] = { \ + _parent_ptr, \ + }; \ + static struct clk_fixed_factor _name##_hw = { \ + .hw = { \ + .clk = &_name, \ + }, \ + .mult = _mult, \ + .div = _div, \ + }; \ + DEFINE_CLK(_name, clk_fixed_factor_ops, _flags, \ + _name##_parent_names, _name##_parents); + /** * __clk_init - initialize the data structures in a struct clk * @dev: device initializing this clk, placeholder for now diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5db3412..c1c23b9 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -277,6 +277,29 @@ struct clk *clk_register_mux(struct device *dev, const char *name, u8 clk_mux_flags, spinlock_t *lock); /** + * struct clk_fixed_factor - fixed multiplier and divider clock + * + * @hw: handle between common and hardware-specific interfaces + * @mult: multiplier + * @div: divider + * + * Clock with a fixed multiplier and divider. The output frequency is the + * parent clock rate divided by div and multiplied by mult. + * Implements .recalc_rate, .set_rate and .round_rate + */ + +struct clk_fixed_factor { + struct clk_hw hw; + unsigned int mult; + unsigned int div; +}; + +extern struct clk_ops clk_fixed_factor_ops; +struct clk *clk_register_fixed_factor(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div); + +/** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock * @hw: link to hardware-specific clock data