--- /dev/null
+From 987810fdd237206e07c8df6a183a0f874a0cec63 Mon Sep 17 00:00:00 2001
+From: Katsuhiro Suzuki <katsuhiro@katsuster.net>
+Date: Mon, 11 Feb 2019 00:38:06 +0900
+Subject: clk: fractional-divider: check parent rate only if flag is set
+
+[ Upstream commit d13501a2bedfbea0983cc868d3f1dc692627f60d ]
+
+Custom approximation of fractional-divider may not need parent clock
+rate checking. For example Rockchip SoCs work fine using grand parent
+clock rate even if target rate is greater than parent.
+
+This patch checks parent clock rate only if CLK_SET_RATE_PARENT flag
+is set.
+
+For detailed example, clock tree of Rockchip I2S audio hardware.
+ - Clock rate of CPLL is 1.2GHz, GPLL is 491.52MHz.
+ - i2s1_div is integer divider can divide N (N is 1~128).
+ Input clock is CPLL or GPLL. Initial divider value is N = 1.
+ Ex) PLL = CPLL, N = 10, i2s1_div output rate is
+ CPLL / 10 = 1.2GHz / 10 = 120MHz
+ - i2s1_frac is fractional divider can divide input to x/y, x and
+ y are 16bit integer.
+
+CPLL --> | selector | ---> i2s1_div -+--> | selector | --> I2S1 MCLK
+GPLL --> | | ,--------------' | |
+ `--> i2s1_frac ---> | |
+
+Clock mux system try to choose suitable one from i2s1_div and
+i2s1_frac for master clock (MCLK) of I2S1.
+
+Bad scenario as follows:
+ - Try to set MCLK to 8.192MHz (32kHz audio replay)
+ Candidate setting is
+ - i2s1_div: GPLL / 60 = 8.192MHz
+ i2s1_div candidate is exactly same as target clock rate, so mux
+ choose this clock source. i2s1_div output rate is changed
+ 491.52MHz -> 8.192MHz
+
+ - After that try to set to 11.2896MHz (44.1kHz audio replay)
+ Candidate settings are
+ - i2s1_div : CPLL / 107 = 11.214945MHz
+ - i2s1_frac: i2s1_div = 8.192MHz
+ This is because clk_fd_round_rate() thinks target rate
+ (11.2896MHz) is higher than parent rate (i2s1_div = 8.192MHz)
+ and returns parent clock rate.
+
+Above is current upstreamed behavior. Clock mux system choose
+i2s1_div, but this clock rate is not acceptable for I2S driver, so
+users cannot replay audio.
+
+Expected behavior is:
+ - Try to set master clock to 11.2896MHz (44.1kHz audio replay)
+ Candidate settings are
+ - i2s1_div : CPLL / 107 = 11.214945MHz
+ - i2s1_frac: i2s1_div * 147/6400 = 11.2896MHz
+ Change i2s1_div to GPLL / 1 = 491.52MHz at same
+ time.
+
+If apply this commit, clk_fd_round_rate() calls custom approximate
+function of Rockchip even if target rate is higher than parent.
+Custom function changes both grand parent (i2s1_div) and parent
+(i2s_frac) settings at same time. Clock mux system can choose
+i2s1_frac and audio works fine.
+
+Signed-off-by: Katsuhiro Suzuki <katsuhiro@katsuster.net>
+Reviewed-by: Heiko Stuebner <heiko@sntech.de>
+[sboyd@kernel.org: Make function into a macro instead]
+Signed-off-by: Stephen Boyd <sboyd@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/clk/clk-fractional-divider.c | 2 +-
+ include/linux/clk-provider.h | 3 +++
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
+index fdf625fb10fa..083daa293280 100644
+--- a/drivers/clk/clk-fractional-divider.c
++++ b/drivers/clk/clk-fractional-divider.c
+@@ -77,7 +77,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long m, n;
+ u64 ret;
+
+- if (!rate || rate >= *parent_rate)
++ if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate))
+ return *parent_rate;
+
+ if (fd->approximation)
+diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
+index 2f4e79fe7b86..3eb3376f1cc8 100644
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -743,6 +743,9 @@ unsigned int __clk_get_enable_count(struct clk *clk);
+ unsigned long clk_hw_get_rate(const struct clk_hw *hw);
+ unsigned long __clk_get_flags(struct clk *clk);
+ unsigned long clk_hw_get_flags(const struct clk_hw *hw);
++#define clk_hw_can_set_rate_parent(hw) \
++ (clk_hw_get_flags((hw)) & CLK_SET_RATE_PARENT)
++
+ bool clk_hw_is_prepared(const struct clk_hw *hw);
+ bool clk_hw_is_enabled(const struct clk_hw *hw);
+ bool __clk_is_enabled(struct clk *clk);
+--
+2.19.1
+