Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752011AbdHBDpw (ORCPT ); Tue, 1 Aug 2017 23:45:52 -0400 Received: from regular1.263xmail.com ([211.150.99.133]:53233 "EHLO regular1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751768AbdHBDpu (ORCPT ); Tue, 1 Aug 2017 23:45:50 -0400 X-263anti-spam: KSV:0; X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-RL-SENDER: zhangqing@rock-chips.com X-FST-TO: xf@rock-chips.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: zhangqing@rock-chips.com X-UNIQUE-TAG: <4e5f390308960c5a7b0c8319d9e201b1> X-ATTACHMENT-NUM: 0 X-DNS-TYPE: 0 Message-ID: <59814A7B.5080200@rock-chips.com> Date: Wed, 02 Aug 2017 11:43:55 +0800 From: Elaine Zhang User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Heiko Stuebner CC: mturquette@baylibre.com, sboyd@codeaurora.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, huangtao@rock-chips.com, cl@rock-chips.com, xxx@rock-chips.com, xf@rock-chips.com Subject: Re: [PATCH 2/2] clk: rockchip: add special approximation to fix up fractional clk's jitter References: <1500624187-12165-1-git-send-email-zhangqing@rock-chips.com> <5990882.df1suBpf8V@phil> <3942563.TMEkxTS0ar@phil> In-Reply-To: <3942563.TMEkxTS0ar@phil> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3018 Lines: 84 On 08/02/2017 12:22 AM, Heiko Stuebner wrote: > From: Elaine Zhang > >>From Rockchips fractional divider description: > 3.1.9 Fractional divider usage > To get specific frequency, clocks of I2S, SPDIF, UARTcan be generated by > fractional divider. Generally you must set that denominator is 20 times > larger than numerator to generate precise clock frequency. So the > fractional divider applies only to generate low frequency clock like > I2S, UART. > > Therefore add a special approximation function that handles this > special requirement. > > Signed-off-by: Elaine Zhang > --- > drivers/clk/rockchip/clk.c | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c > index fe1d393cf678..b6db79a00602 100644 > --- a/drivers/clk/rockchip/clk.c > +++ b/drivers/clk/rockchip/clk.c > @@ -29,6 +29,7 @@ > #include > #include > #include > +#include > #include "clk.h" > > /** > @@ -164,6 +165,40 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb, > return notifier_from_errno(ret); > } > > +/** > + * fractional divider must set that denominator is 20 times larger than > + * numerator to generate precise clock frequency. > + */ > +void rockchip_fractional_approximation(struct clk_hw *hw, > + unsigned long rate, unsigned long *parent_rate, > + unsigned long *m, unsigned long *n) > +{ > + struct clk_fractional_divider *fd = to_clk_fd(hw); > + unsigned long p_rate, p_parent_rate; > + struct clk_hw *p_parent; > + unsigned long scale; > + > + p_rate = clk_hw_get_rate(clk_hw_get_parent(hw)); > + if ((rate * 20 > p_rate) && (p_rate % rate != 0)) { > + p_parent = clk_hw_get_parent(clk_hw_get_parent(hw)); > + p_parent_rate = clk_hw_get_rate(p_parent); > + *parent_rate = p_parent_rate; > + } > + > + /* > + * Get rate closer to *parent_rate to guarantee there is no overflow > + * for m and n. In the result it will be the nearest rate left shifted > + * by (scale - fd->nwidth) bits. > + */ > + scale = fls_long(*parent_rate / rate - 1); > + if (scale > fd->nwidth) > + rate <<= scale - fd->nwidth; > + > + rational_best_approximation(rate, *parent_rate, > + GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), > + m, n); > +} > + > static struct clk *rockchip_clk_register_frac_branch( > struct rockchip_clk_provider *ctx, const char *name, > const char *const *parent_names, u8 num_parents, > @@ -210,6 +245,7 @@ static struct clk *rockchip_clk_register_frac_branch( > div->nwidth = 16; > div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift; > div->lock = lock; > + div->approximation = rockchip_fractional_approximation; > div_ops = &clk_fractional_divider_ops; > > clk = clk_register_composite(NULL, name, parent_names, num_parents, > Tested-by: Elaine Zhang