From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752663AbbIRHWh (ORCPT ); Fri, 18 Sep 2015 03:22:37 -0400 Received: from mout.kundenserver.de ([212.227.126.131]:58670 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753011AbbIRHVa (ORCPT ); Fri, 18 Sep 2015 03:21:30 -0400 Subject: Re: [PATCH v2] clk:mxs: Fix bug on frequency divider To: Victorien Vedrine , linux-kernel@vger.kernel.org References: <55BBB1AC.6070102@codeaurora.org> <1441010707-17178-1-git-send-email-victorien.vedrine@ophrys.net> Cc: linux-clk@vger.kernel.org, sboyd@codeaurora.org, mturquette@baylibre.com, shawn.guo@linaro.org, "Fabio.Estevam@freescale.com" , Marek Vasut , Shawn Guo , "linux-arm-kernel@lists.infradead.org" From: Stefan Wahren Message-ID: <55FBBB6D.4010805@i2se.com> Date: Fri, 18 Sep 2015 09:21:17 +0200 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0 MIME-Version: 1.0 In-Reply-To: <1441010707-17178-1-git-send-email-victorien.vedrine@ophrys.net> Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: 7bit X-Provags-ID: V03:K0:3DjLAA/f72Fn9uht45F4VveU31ojizIxKFQSU3lmcwSaV2a5i3n 8Ew1nXKRIstxt/OeyFM2zKxRAYxtKnSvSi741JosULkfowPnI5600p/JB6YBFd3iYCC199R sdIJYXX4Ts69lpnBPuLNCWaHCWKKCSVFJQEhLLARoDg2Eg7EYQ7M9rfGlJnSoe3f1u4zEgF EzcBqHiQetlQOEqazJ7OA== X-UI-Out-Filterresults: notjunk:1;V01:K0:tJ+LmWBZzdU=:gYfYW+qeUwtU8UjfxH4LNG lHvsKk6iZwOOxP8RDHe15Kc073nFtb7WZVE02IPTaxO2J0p0OlJ//zg0lUtOeOzPn1aJZAFZ5 1exx5C3LMLXUJOVNwTKfZf3AuKg/H0++T31PUj4qn3XpIq9ACr9gf0wH11GX8Fjxae+aMc76j VHnkuxsc8F+AYiR+Z6wKNZbEpkobLmv92VGAFbf/WcKvF6OzLvKI310O1w1YkfLltfT0UMiSM zG3keVvSHgA0+Kj20uTtYLiSAozS09jJku5llD7ty1xC5b3wxZIZzpORHCSgjFaT6DjR1VolN jL3avXub/0CZH4hvPNofJQpQfIeE6GLFv5+c3boEMXpYIUsNi7W+bSF8uAfDnp/OK8xLrQ4ay soGMKu24ngQNk4fG0OzmMZlaR0AgGJ+h0/nr0GfW5ZMT3IMCr6qu1mQmzqxfksoqu81DfVLEe 2EfXSX+k3kgx6cNAIbvRB2vraP3OSKPSG579ytHUneR1oPCS2nWaJCrff1BeQQISqR5FRtPNK ZCYm43J4MIvn9zSHSoGuwOsi8ORtHJTdc/lwcrry2Mns1CsB/sm8wnQIM32PQGMLuV2h/CtGr rgWid2uVXlmghk+2+M26YgfMUw0fNiiwe/Tkgb4pIQHo3MrPvQ09g9YQ6nXUNYzptJjxfRK0d 9s54uZMDe6yWHPg+KqMO5DvBCIcVd39GdbaGLhyk9h/3riHzk58mKUsoWvkUetov0fPHFf5Xi 5cjRG3zVtQwkRrqI Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org +Shawn's new address +linux-arm-kernel > On drivers/clk/mxs/clk-frac.c, the function clk_frac_round_rate returned a bad > result. The division before multiplication computes a wrong value ; the > calculation is inverted to fix the problem. The second issue is that the exact > rate have decimals and they are truncate. The consequence is that the function > clk_frac_set_rate (which use the result of clk_frac_round_rate) computes a > wrong value for the register (the rate generated can be closer to the desired > rate). The correction is : if there is decimal to the result, it is rounded to > the next larger integer. > On drivers/clk/mxs/clk-frac.c, the function clk_frac_recalc_rate returned > a bad result. The multiplication is made before the division to compute a > correct value. > > Signed-off-by: Victorien Vedrine > --- > drivers/clk/mxs/clk-frac.c | 12 +++++++++--- > 1 file changed, 9 insertions(+), 3 deletions(-) > > diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c > index e6aa6b5..b3fa7fa 100644 > --- a/drivers/clk/mxs/clk-frac.c > +++ b/drivers/clk/mxs/clk-frac.c > @@ -42,11 +42,13 @@ static unsigned long clk_frac_recalc_rate(struct clk_hw *hw, > { > struct clk_frac *frac = to_clk_frac(hw); > u32 div; > + u64 tmp_rate; > > div = readl_relaxed(frac->reg) >> frac->shift; > div &= (1 << frac->width) - 1; > > - return (parent_rate >> frac->width) * div; > + tmp_rate = (u64)parent_rate * div; > + return tmp_rate >> frac->width; > } > > static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, > @@ -55,7 +57,7 @@ static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, > struct clk_frac *frac = to_clk_frac(hw); > unsigned long parent_rate = *prate; > u32 div; > - u64 tmp; > + u64 tmp, tmp_rate, result; > > if (rate > parent_rate) > return -EINVAL; > @@ -68,7 +70,11 @@ static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate, > if (!div) > return -EINVAL; > > - return (parent_rate >> frac->width) * div; > + tmp_rate = (u64)parent_rate * div; > + result = tmp_rate >> frac->width; > + if ((result << frac->width) < tmp_rate) > + result += 1; > + return result; > } > > static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,