From patchwork Fri Feb 28 23:34:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Soren Brinkmann X-Patchwork-Id: 3745201 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E730ABF13A for ; Fri, 28 Feb 2014 23:36:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E4B612022D for ; Fri, 28 Feb 2014 23:36:41 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CA34320225 for ; Fri, 28 Feb 2014 23:36:40 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WJWyS-0007nk-97; Fri, 28 Feb 2014 23:36:12 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WJWyJ-000161-90; Fri, 28 Feb 2014 23:36:03 +0000 Received: from mail-qc0-x235.google.com ([2607:f8b0:400d:c01::235]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WJWy4-00011n-16 for linux-arm-kernel@lists.infradead.org; Fri, 28 Feb 2014 23:35:55 +0000 Received: by mail-qc0-f181.google.com with SMTP id c9so1533902qcz.26 for ; Fri, 28 Feb 2014 15:35:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=Gc+yOMw7nEv2t42qRk2ccvDSFtVP+FTudyD9a6f9jkc=; b=T5ACWxGkY6RfdtNHu5nudmIr5dvBH2Zk2uRAEchaw3gac5PTXygpsov6Bnr6HO9TPI NPsBHWpqKbXIgWOhmXi4kQNUP0wSei01EA0tsEXpa/Uh8ILKATsqeIb1KoFcVEhpnF2F iwdv/e0B4FKGB1i/HHGKWHd9n/boJrxQhUMlHwrTBVW6tcU/IKMiPwQdpNrxSIO2d9YH 2tUKPqCaBLnj/OWb10rDUKn51++ftJ+c0fJ0JXmHCbMoiolXgq7sKVfS9Em+lwQjJVoQ P5nQsCet6HFMBQmmf+wVROhjPcJIt+V2f8AMHhXpy2+emd4fAO+dMmh1QSHWMyWrk/13 R0Jw== X-Received: by 10.224.56.5 with SMTP id w5mr7447275qag.60.1393630522218; Fri, 28 Feb 2014 15:35:22 -0800 (PST) Received: from localhost ([149.199.62.254]) by mx.google.com with ESMTPSA id v92sm4516438qge.6.2014.02.28.15.35.20 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 28 Feb 2014 15:35:21 -0800 (PST) From: Soren Brinkmann To: Mike Turquette , Stephen Boyd , Gerhard Sittig Subject: [PATCH RFC 2/3] clk/i2c-div: Allow custom divider accessors Date: Fri, 28 Feb 2014 15:34:54 -0800 Message-Id: <1393630495-29689-3-git-send-email-soren.brinkmann@xilinx.com> X-Mailer: git-send-email 1.9.0.1.g4196000 In-Reply-To: <1393630495-29689-1-git-send-email-soren.brinkmann@xilinx.com> References: <1393630495-29689-1-git-send-email-soren.brinkmann@xilinx.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140228_183548_292382_DB97303E X-CRM114-Status: GOOD ( 13.88 ) X-Spam-Score: -1.9 (-) Cc: =?UTF-8?q?S=C3=B6ren=20Brinkmann?= , Michal Simek , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Allow to provide custom accessors to read/write the divider from/to HW since some I2C dividers spread dividers across multiple registers. Signed-off-by: Soren Brinkmann --- drivers/clk/clk-i2c-divider.c | 64 ++++++++++++++++++++++++++++++++----------- include/linux/clk-provider.h | 15 ++++++++-- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/drivers/clk/clk-i2c-divider.c b/drivers/clk/clk-i2c-divider.c index 690eae191072..086fb7935ccb 100644 --- a/drivers/clk/clk-i2c-divider.c +++ b/drivers/clk/clk-i2c-divider.c @@ -99,14 +99,23 @@ static unsigned int _get_val(struct clk_i2c_divider *divider, u8 div) return div - 1; } +static unsigned int clk_i2c_divider_get_div(struct clk_i2c_divider *divider) +{ + unsigned int div; + + div = clk_i2c_readb(divider->regmap, divider->reg) >> divider->shift; + div &= div_mask(divider); + + return div; +} + static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_i2c_divider *divider = to_clk_i2c_divider(hw); unsigned int div, val; - val = clk_i2c_readb(divider->regmap, divider->reg) >> divider->shift; - val &= div_mask(divider); + val = divider->get_div(divider); div = _get_div(divider, val); if (!div) { @@ -211,16 +220,10 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, return *prate / div; } -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int clk_i2c_divider_set_div(unsigned int value, + struct clk_i2c_divider *divider) { - struct clk_i2c_divider *divider = to_clk_i2c_divider(hw); - unsigned int div, value; - unsigned long flags = 0; - u32 val; - - div = parent_rate / rate; - value = _get_val(divider, div); + unsigned int val; if (value > div_mask(divider)) value = div_mask(divider); @@ -237,6 +240,18 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_i2c_divider *divider = to_clk_i2c_divider(hw); + unsigned int div, value; + + div = parent_rate / rate; + value = _get_val(divider, div); + + return divider->set_div(value, divider); +} + const struct clk_ops clk_i2c_divider_ops = { .recalc_rate = clk_divider_recalc_rate, .round_rate = clk_divider_round_rate, @@ -247,7 +262,9 @@ EXPORT_SYMBOL_GPL(clk_i2c_divider_ops); static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table) + u8 clk_divider_flags, const struct clk_div_table *table, + unsigned int (*get_div)(struct clk_i2c_divider *), + int (*set_div)(unsigned int val, struct clk_i2c_divider *)) { struct clk_i2c_divider *div; struct clk *clk; @@ -286,6 +303,15 @@ static struct clk *_register_divider(struct device *dev, const char *name, div->flags = clk_divider_flags; div->hw.init = &init; div->table = table; + if (get_div) + div->get_div = get_div; + else + div->get_div = clk_i2c_divider_get_div; + + if (set_div) + div->set_div = set_div; + else + div->set_div = clk_i2c_divider_set_div; /* register the clock */ clk = devm_clk_register(dev, &div->hw); @@ -311,10 +337,13 @@ static struct clk *_register_divider(struct device *dev, const char *name, struct clk *clk_i2c_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u8 width, - u8 clk_divider_flags) + u8 clk_divider_flags, + unsigned int (*get_div)(struct clk_i2c_divider *), + int (*set_div)(unsigned int val, struct clk_i2c_divider *)) { return _register_divider(dev, name, parent_name, flags, regmap, reg, - shift, width, clk_divider_flags, NULL); + shift, width, clk_divider_flags, NULL, get_div, + set_div); } EXPORT_SYMBOL_GPL(clk_i2c_register_divider); @@ -335,9 +364,12 @@ EXPORT_SYMBOL_GPL(clk_i2c_register_divider); struct clk *clk_i2c_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table) + u8 clk_divider_flags, const struct clk_div_table *table, + unsigned int (*get_div)(struct clk_i2c_divider *), + int (*set_div)(unsigned int val, struct clk_i2c_divider *)) { return _register_divider(dev, name, parent_name, flags, regmap, reg, - shift, width, clk_divider_flags, table); + shift, width, clk_divider_flags, table, get_div, + set_div); } EXPORT_SYMBOL_GPL(clk_i2c_register_divider_table); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index d86bb6ec4232..bccb711b0ea1 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -353,6 +353,8 @@ struct clk_i2c_divider { u8 width; u8 flags; const struct clk_div_table *table; + unsigned int (*get_div)(struct clk_i2c_divider *); + int (*set_div)(unsigned int, struct clk_i2c_divider *); }; #define CLK_DIVIDER_ONE_BASED BIT(0) @@ -655,14 +657,21 @@ struct clk *clk_i2c_register_mux_table(struct device *dev, const char *name, const char **parent_names, u8 num_parents, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table); + struct clk *clk_i2c_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u8 width, - u8 clk_divider_flags); -struct clk *clk_i2c_register_divider_table(struct device *dev, const char *name, + u8 clk_divider_flags, unsigned int (*get_div)(struct + clk_i2c_divider *), int (*set_div)(unsigned int val, + struct clk_i2c_divider *)); + +struct clk *clk_i2c_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct regmap *regmap, unsigned int reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table); + u8 clk_divider_flags, const struct clk_div_table *table, + unsigned int (*get_div)(struct clk_i2c_divider *), + int (*set_div)(unsigned int val, struct clk_i2c_divider *)); + #endif /* CONFIG_COMMON_CLK_I2C */ #endif /* CONFIG_COMMON_CLK */