mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
![Dmitry Baryshkov](/assets/img/avatar_default.png)
On recent Qualcomm platforms the QMP PIPE clocks feed into a set of muxes which must be parked to the "safe" source (bi_tcxo) when corresponding GDSC is turned off and on again. Currently this is handcoded in the PCIe driver by reparenting the gcc_pipe_N_clk_src clock. However the same code sequence should be applied in the pcie-qcom endpoint, USB3 and UFS drivers. Rather than copying this sequence over and over again, follow the example of clk_rcg2_shared_ops and implement this parking in the enable() and disable() clock operations. Supplement the regmap-mux with the new clk_regmap_phy_mux type, which implements such multiplexers as a simple gate clocks. This is possible since each of these multiplexers has just two clock sources: one coming from the PHY and a reference (XO) one. If the clock is running off the from-PHY source, report it as enabled. Report it as disabled otherwise (if it uses reference source). This way the PHY will disable the pipe clock before turning off the GDSC, which in turn would lead to disabling corresponding pipe_clk_src (and thus it being parked to a safe, reference clock source). And vice versa, after enabling the GDSC the PHY will enable the pipe clock, which would cause pipe_clk_src to be switched from a safe source to the working one. Reviewed-by: Johan Hovold <johan+linaro@kernel.org> Tested-by: Johan Hovold <johan+linaro@kernel.org> Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Reviewed-by: Stephen Boyd <sboyd@kernel.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lore.kernel.org/r/20220608105238.2973600-2-dmitry.baryshkov@linaro.org
62 lines
1.6 KiB
C
62 lines
1.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2022, Linaro Ltd.
|
|
*/
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/bitfield.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/export.h>
|
|
|
|
#include "clk-regmap.h"
|
|
#include "clk-regmap-phy-mux.h"
|
|
|
|
#define PHY_MUX_MASK GENMASK(1, 0)
|
|
#define PHY_MUX_PHY_SRC 0
|
|
#define PHY_MUX_REF_SRC 2
|
|
|
|
static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
|
|
{
|
|
return container_of(clkr, struct clk_regmap_phy_mux, clkr);
|
|
}
|
|
|
|
static int phy_mux_is_enabled(struct clk_hw *hw)
|
|
{
|
|
struct clk_regmap *clkr = to_clk_regmap(hw);
|
|
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
|
|
unsigned int val;
|
|
|
|
regmap_read(clkr->regmap, phy_mux->reg, &val);
|
|
val = FIELD_GET(PHY_MUX_MASK, val);
|
|
|
|
WARN_ON(val != PHY_MUX_PHY_SRC && val != PHY_MUX_REF_SRC);
|
|
|
|
return val == PHY_MUX_PHY_SRC;
|
|
}
|
|
|
|
static int phy_mux_enable(struct clk_hw *hw)
|
|
{
|
|
struct clk_regmap *clkr = to_clk_regmap(hw);
|
|
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
|
|
|
|
return regmap_update_bits(clkr->regmap, phy_mux->reg,
|
|
PHY_MUX_MASK,
|
|
FIELD_PREP(PHY_MUX_MASK, PHY_MUX_PHY_SRC));
|
|
}
|
|
|
|
static void phy_mux_disable(struct clk_hw *hw)
|
|
{
|
|
struct clk_regmap *clkr = to_clk_regmap(hw);
|
|
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
|
|
|
|
regmap_update_bits(clkr->regmap, phy_mux->reg,
|
|
PHY_MUX_MASK,
|
|
FIELD_PREP(PHY_MUX_MASK, PHY_MUX_REF_SRC));
|
|
}
|
|
|
|
const struct clk_ops clk_regmap_phy_mux_ops = {
|
|
.enable = phy_mux_enable,
|
|
.disable = phy_mux_disable,
|
|
.is_enabled = phy_mux_is_enabled,
|
|
};
|
|
EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
|