From ac987c7a71dcd839261c8c2aaf60d860a14168aa Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Mon, 26 Sep 2016 10:58:14 +0530 Subject: [PATCH] clk: qcom: Add support to force enable/disable the RCG Some RCGs would be expected to be enabled/disabled using the root enable bit of the RCGR. These RCGs would have to indicate the force enable using the FORCE_ENABLE_RCGR flag. Change-Id: Ia1eaba2728d06066612739ff48f7e5e44322e96b Signed-off-by: Amit Nischal --- drivers/clk/qcom/clk-rcg.h | 7 ++++- drivers/clk/qcom/clk-rcg2.c | 57 ++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b904c335cda4..e3760969848d 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -158,6 +158,8 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @freq_tbl: frequency table * @current_freq: last cached frequency when using branches with shared RCGs * @clkr: regmap clock handle + * @flags: set if RCG needs to be force enabled/disabled during + * power sequence. * */ struct clk_rcg2 { @@ -168,6 +170,9 @@ struct clk_rcg2 { const struct freq_tbl *freq_tbl; unsigned long current_freq; struct clk_regmap clkr; + +#define FORCE_ENABLE_RCGR BIT(0) + u8 flags; }; #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index a071bba8018c..4d5081c2b6d1 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -60,6 +60,57 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw) return (cmd & CMD_ROOT_OFF) == 0; } +static int clk_rcg_set_force_enable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const char *name = clk_hw_get_name(hw); + int ret = 0, count; + + /* force enable RCG */ + ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, + CMD_ROOT_EN, CMD_ROOT_EN); + if (ret) + return ret; + + /* wait for RCG to turn ON */ + for (count = 500; count > 0; count--) { + ret = clk_rcg2_is_enabled(hw); + if (ret) { + ret = 0; + break; + } + udelay(1); + } + if (!count) + pr_err("%s: RCG did not turn on after force enable\n", name); + + return ret; +} + +static int clk_rcg2_enable(struct clk_hw *hw) +{ + int ret = 0; + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + if (rcg->flags & FORCE_ENABLE_RCGR) + ret = clk_rcg_set_force_enable(hw); + + return ret; +} + +static void clk_rcg2_disable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + if (rcg->flags & FORCE_ENABLE_RCGR) { + /* force disable RCG - clear CMD_ROOT_EN bit */ + regmap_update_bits(rcg->clkr.regmap, + rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0); + /* Add a delay to disable the RCG */ + udelay(100); + } +} + static u8 clk_rcg2_get_parent(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); @@ -290,6 +341,8 @@ static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw, } const struct clk_ops clk_rcg2_ops = { + .enable = clk_rcg2_enable, + .disable = clk_rcg2_disable, .is_enabled = clk_rcg2_is_enabled, .get_parent = clk_rcg2_get_parent, .set_parent = clk_rcg2_set_parent, @@ -801,6 +854,8 @@ static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate, } const struct clk_ops clk_gfx3d_ops = { + .enable = clk_rcg2_enable, + .disable = clk_rcg2_disable, .is_enabled = clk_rcg2_is_enabled, .get_parent = clk_rcg2_get_parent, .set_parent = clk_rcg2_set_parent,