From af5845029b4bec1eea4fec13b505a051465debde Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Wed, 19 Jun 2019 14:41:18 +0530 Subject: [PATCH] clk: qcom: Use regmap_update_bits() to update the clock flags Currently clk_cbcr_set_flags() reads the CBCR register content, modifies the flags and writes back the updated value into it. Sometimes clk_set_flags() gets invoked for the same clock while clk_enable() is in progress causing the CLK_ENABLE bit getting updated outside of clk_enable() path. Therefore, use regmap_update_bits() to update the flags in CBCR register. Also add a barrier in clock enable/disable path to make sure that register write goes through. Change-Id: I8018f8033d05273320fd92cc7d21fcdce0885dfc Signed-off-by: Odelu Kukatla --- drivers/clk/qcom/clk-branch.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 8963c4a691ef6..dcb9f7ef5ee3c 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -125,6 +125,12 @@ static int clk_branch_toggle(struct clk_hw *hw, bool en, clk_disable_regmap(hw); } + /* + * Make sure enable/disable request goes through before waiting + * for CLK_OFF status to get updated. + */ + mb(); + return clk_branch_wait(br, en, check_halt); } @@ -136,34 +142,36 @@ static int clk_branch_enable(struct clk_hw *hw) static int clk_cbcr_set_flags(struct regmap *regmap, unsigned int reg, unsigned long flags) { - u32 cbcr_val; - - regmap_read(regmap, reg, &cbcr_val); + u32 cbcr_val = 0; + u32 cbcr_mask; + int ret; switch (flags) { case CLKFLAG_PERIPH_OFF_SET: - cbcr_val |= BIT(12); + cbcr_val = cbcr_mask = BIT(12); break; case CLKFLAG_PERIPH_OFF_CLEAR: - cbcr_val &= ~BIT(12); + cbcr_mask = BIT(12); break; case CLKFLAG_RETAIN_PERIPH: - cbcr_val |= BIT(13); + cbcr_val = cbcr_mask = BIT(13); break; case CLKFLAG_NORETAIN_PERIPH: - cbcr_val &= ~BIT(13); + cbcr_mask = BIT(13); break; case CLKFLAG_RETAIN_MEM: - cbcr_val |= BIT(14); + cbcr_val = cbcr_mask = BIT(14); break; case CLKFLAG_NORETAIN_MEM: - cbcr_val &= ~BIT(14); + cbcr_mask = BIT(14); break; default: return -EINVAL; } - regmap_write(regmap, reg, cbcr_val); + ret = regmap_update_bits(regmap, reg, cbcr_mask, cbcr_val); + if (ret) + return ret; /* Make sure power is enabled/disabled before returning. */ mb();