summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-08-19 05:29:02 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-08-19 05:29:01 -0700
commitd9868b6515b4f367127670ed6830064967520ecb (patch)
tree4498bb0728ee5e2a7c3c6772cfdbe16820cb2430 /drivers
parent391337e863b5649d46a0cc066c4c5b72a956f148 (diff)
parent221bd201287d302791aa6698a3747d8b7919851e (diff)
Merge "clk: qcom: Add support for gate clocks"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/qcom/clk-branch.c41
-rw-r--r--drivers/clk/qcom/clk-branch.h22
2 files changed, 61 insertions, 2 deletions
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 26f7af315066..76310e249fb2 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.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
@@ -83,6 +83,9 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
if (br->halt_check == BRANCH_HALT_DELAY || (!enabling && voted)) {
udelay(10);
+ } else if ((br->halt_check == BRANCH_HALT_NO_CHECK_ON_DISABLE) &&
+ !enabling) {
+ return 0;
} else if (br->halt_check == BRANCH_HALT_ENABLE ||
br->halt_check == BRANCH_HALT ||
(enabling && voted)) {
@@ -151,6 +154,42 @@ const struct clk_ops clk_branch2_ops = {
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);
+static int clk_gate_toggle(struct clk_hw *hw, bool en)
+{
+ struct clk_gate2 *gt = to_clk_gate2(hw);
+ int ret = 0;
+
+ if (en) {
+ ret = clk_enable_regmap(hw);
+ if (ret)
+ return ret;
+ } else {
+ clk_disable_regmap(hw);
+ }
+
+ if (gt->udelay)
+ udelay(gt->udelay);
+
+ return ret;
+}
+
+static int clk_gate2_enable(struct clk_hw *hw)
+{
+ return clk_gate_toggle(hw, true);
+}
+
+static void clk_gate2_disable(struct clk_hw *hw)
+{
+ clk_gate_toggle(hw, false);
+}
+
+const struct clk_ops clk_gate2_ops = {
+ .enable = clk_gate2_enable,
+ .disable = clk_gate2_disable,
+ .is_enabled = clk_is_enabled_regmap,
+};
+EXPORT_SYMBOL_GPL(clk_gate2_ops);
+
const struct clk_ops clk_branch_simple_ops = {
.enable = clk_enable_regmap,
.disable = clk_disable_regmap,
diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h
index 284df3f3c55f..915c54f9351f 100644
--- a/drivers/clk/qcom/clk-branch.h
+++ b/drivers/clk/qcom/clk-branch.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
@@ -42,15 +42,35 @@ struct clk_branch {
#define BRANCH_HALT_ENABLE 1 /* pol: 0 = halt */
#define BRANCH_HALT_ENABLE_VOTED (BRANCH_HALT_ENABLE | BRANCH_VOTED)
#define BRANCH_HALT_DELAY 2 /* No bit to check; just delay */
+/* No halt check during clk disable for the clocks controlled by other masters
+ * via voting registers like SMMU clocks.
+ */
+#define BRANCH_HALT_NO_CHECK_ON_DISABLE 4
struct clk_regmap clkr;
};
+/**
+ * struct clk_gate2 - gating clock with status bit and dynamic hardware gating
+ * @udelay: halt delay in microseconds on clock branch Enable/Disable
+ * @clkr: handle between common and hardware-specific interfaces
+ *
+ * Clock which can gate its output.
+ */
+struct clk_gate2 {
+ u32 udelay;
+ struct clk_regmap clkr;
+};
+
extern const struct clk_ops clk_branch_ops;
extern const struct clk_ops clk_branch2_ops;
+extern const struct clk_ops clk_gate2_ops;
extern const struct clk_ops clk_branch_simple_ops;
#define to_clk_branch(_hw) \
container_of(to_clk_regmap(_hw), struct clk_branch, clkr)
+#define to_clk_gate2(_hw) \
+ container_of(to_clk_regmap(_hw), struct clk_gate2, clkr)
+
#endif