From c1a61a70dcdc3d0ba83e3ecb72aa66f0b519bb5c Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Tue, 24 Sep 2019 14:49:52 +0800 Subject: [PATCH] clk: composite: Add support to change brother clock rate Some composite clocks may have the same parent clock, if one clock change the parent clock rate, the other clock rate may too large, so add a brother clock in composite that the other clock also can be changed when parent rate is changed. Change-Id: I2c6749e578b76d6780cecdcd9ff1b5fd4f25a0ba Signed-off-by: Finley Xiao Signed-off-by: Elaine Zhang --- drivers/clk/clk-composite.c | 25 +++++++++++++++++++++++++ include/linux/clk-provider.h | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 2e7fedff527b..3d83fc40d07d 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -3,6 +3,7 @@ * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved. */ +#include #include #include #include @@ -149,8 +150,32 @@ static int clk_composite_set_rate_and_parent(struct clk_hw *hw, const struct clk_ops *mux_ops = composite->mux_ops; struct clk_hw *rate_hw = composite->rate_hw; struct clk_hw *mux_hw = composite->mux_hw; + struct clk_hw *brother_hw = composite->brother_hw; unsigned long temp_rate; + if (brother_hw) { + struct clk_composite *bcomposite = to_clk_composite(brother_hw); + const struct clk_ops *brate_ops = bcomposite->rate_ops; + struct clk_hw *brate_hw = bcomposite->rate_hw; + struct clk_hw *parent_hw = clk_hw_get_parent(brother_hw); + struct clk_hw *new_parent_hw = clk_hw_get_parent(hw); + + __clk_hw_set_clk(brate_hw, brother_hw); + + temp_rate = brate_ops->recalc_rate(brate_hw, parent_rate); + if (temp_rate > rate) + brate_ops->set_rate(brate_hw, rate, parent_rate); + if (clk_hw_is_prepared(brother_hw)) { + clk_prepare_enable(new_parent_hw->clk); + clk_enable(brother_hw->clk); + } + clk_hw_reparent(brother_hw, new_parent_hw); + if (clk_hw_is_prepared(brother_hw)) { + clk_disable(brother_hw->clk); + clk_disable_unprepare(parent_hw->clk); + } + } + __clk_hw_set_clk(rate_hw, hw); __clk_hw_set_clk(mux_hw, hw); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 1759bea2f18d..90fe290299cd 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1035,6 +1035,9 @@ extern const struct clk_ops clk_multiplier_ops; * @mux_hw: handle between composite and hardware-specific mux clock * @rate_hw: handle between composite and hardware-specific rate clock * @gate_hw: handle between composite and hardware-specific gate clock + * @brother_hw: a member of clk_composite who has the common parent clocks + * with another clk_composite, and it's also a handle between + * common and hardware-specific interfaces * @mux_ops: clock ops for mux * @rate_ops: clock ops for rate * @gate_ops: clock ops for gate @@ -1046,6 +1049,7 @@ struct clk_composite { struct clk_hw *mux_hw; struct clk_hw *rate_hw; struct clk_hw *gate_hw; + struct clk_hw *brother_hw; const struct clk_ops *mux_ops; const struct clk_ops *rate_ops;