Merge "clk: qcom: gdsc-regulator: Add support to skip GDSC disable"
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index 4ef8d7a..a6b0cdd 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -72,7 +72,9 @@
  - qcom,en-rest-wait-val: Input value for EN_REST_WAIT controls state transition
 			  delay after receiving ack signal (gds_enr_ack) from the
 			  longest en_rest power switch chain.
-
+ - qcom,skip-disable-before-sw-enable: Presence denotes a hardware requirement
+					to leave the GDSC on that has been
+					enabled by an entity external to HLOS.
 Example:
 	gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
 		compatible = "qcom,gdsc";
diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c
index 15a93cd..1ffb341 100644
--- a/drivers/clk/qcom/gdsc-regulator.c
+++ b/drivers/clk/qcom/gdsc-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -92,6 +92,7 @@
 	int			root_clk_idx;
 	u32			gds_timeout;
 	u32			flags;
+	bool			skip_disable_before_enable;
 };
 
 enum gdscr_status {
@@ -379,6 +380,7 @@
 		clk_disable_unprepare(sc->clocks[sc->root_clk_idx]);
 
 	sc->is_gdsc_enabled = true;
+	sc->skip_disable_before_enable = false;
 
 	mutex_unlock(&gdsc_seq_lock);
 
@@ -391,6 +393,16 @@
 	uint32_t regval;
 	int i, ret = 0;
 
+	/*
+	 * Protect GDSC against late_init disabling when the GDSC is enabled
+	 * by an entity outside external to HLOS.
+	 */
+	if (sc->skip_disable_before_enable) {
+		dev_dbg(&rdev->dev, "Skip Disabling: %s\n", sc->rdesc.name);
+		sc->skip_disable_before_enable = false;
+		return 0;
+	}
+
 	mutex_lock(&gdsc_seq_lock);
 
 	if (sc->force_root_en)
@@ -827,6 +839,9 @@
 			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
 	}
 
+	sc->skip_disable_before_enable = of_property_read_bool(
+		pdev->dev.of_node, "qcom,skip-disable-before-sw-enable");
+
 	reg_config.dev = &pdev->dev;
 	reg_config.init_data = init_data;
 	reg_config.driver_data = sc;