b/drivers/clk/clk-fractional-divider.c
@@ -62,6 +62,9 @@ static long clk_fd_round_rate(struct clk_hw *hw,
unsigned long rate,
if (!rate || rate >= *parent_rate)
return *parent_rate;
+ if (fd->approx)
+ fd->approx(hw, rate, 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
@@ -147,6 +150,7 @@ struct clk_hw
*clk_hw_register_fractional_divider(struct device *dev,
fd->nmask = GENMASK(nwidth - 1, 0) << nshift;
fd->flags = clk_divider_flags;
fd->lock = lock;
+ fd->approx = NULL;
fd->hw.init = &init;
hw = &fd->hw;
@@ -160,6 +160,21 @@ static int rockchip_clk_frac_notifier_cb(struct
notifier_block *nb,
return notifier_from_errno(ret);
}
+void rockchip_fractional_special_approx(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hw *p_parent;
+ unsigned long p_rate, p_parent_rate;
+
+ 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;
+ }
+}
+
static struct clk *rockchip_clk_register_frac_branch(
struct rockchip_clk_provider *ctx, const char *name,
const char *const *parent_names, u8 num_parents,
@@ -206,6 +221,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->approx = rockchip_fractional_special_approx;
div_ops = &clk_fractional_divider_ops;
clk = clk_register_composite(NULL, name, parent_names, num_parents,
@@ -513,6 +513,9 @@ struct clk_fractional_divider {
u8 nwidth;
u32 nmask;
u8 flags;
+ void (*approx)(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate);
spinlock_t *lock;
};