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;