spmi: spmi-pmic-arb-debug: add clock management support
Add support to enable and disable the clock used by the SPMI PMIC
arbiter debug bus. This is needed to avoid unclocked accesses.
Change-Id: If9eee1317a88c143452d8b46b89aff89d1e956b7
Signed-off-by: David Collins <collinsd@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
index ceac719..2131c33 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt
@@ -35,6 +35,19 @@
the corresponding addresses are specified in the reg
property.
+- clocks
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Clock tuple consisting of a phandle to a clock controller
+ device and the clock ID number for the SPMI debug controller
+ clock.
+
+- clock-names
+ Usage: required if clocks property is specified
+ Value type: <string>
+ Definition: Defines the name of the clock defined in the "clocks"
+ property. This must be "core_clk".
+
- #address-cells
Usage: required
Value type: <u32>
@@ -57,6 +70,8 @@
compatible = "qcom,spmi-pmic-arb-debug";
reg = <0x6b22000 0x60>, <0x7820A8 4>;
reg-names = "core", "fuse";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "core_clk";
qcom,fuse-disable-bit = <12>;
#address-cells = <2>;
#size-cells = <0>;
diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c
index c5a31a9..2c90bef 100644
--- a/drivers/spmi/spmi-pmic-arb-debug.c
+++ b/drivers/spmi/spmi-pmic-arb-debug.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -69,6 +70,7 @@
struct spmi_pmic_arb_debug {
void __iomem *addr;
raw_spinlock_t lock;
+ struct clk *clock;
};
static inline void pmic_arb_debug_write(struct spmi_pmic_arb_debug *pa,
@@ -181,6 +183,12 @@
else
return -EINVAL;
+ rc = clk_prepare_enable(pa->clock);
+ if (rc) {
+ pr_err("%s: failed to enable core clock, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
raw_spin_lock_irqsave(&pa->lock, flags);
rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
@@ -192,6 +200,7 @@
buf[i] = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_RDATA(i));
done:
raw_spin_unlock_irqrestore(&pa->lock, flags);
+ clk_disable_unprepare(pa->clock);
return rc;
}
@@ -221,6 +230,12 @@
else
return -EINVAL;
+ rc = clk_prepare_enable(pa->clock);
+ if (rc) {
+ pr_err("%s: failed to enable core clock, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
raw_spin_lock_irqsave(&pa->lock, flags);
/* Write data to FIFO */
@@ -230,6 +245,7 @@
rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len);
raw_spin_unlock_irqrestore(&pa->lock, flags);
+ clk_disable_unprepare(pa->clock);
return rc;
}
@@ -293,6 +309,17 @@
goto err_put_ctrl;
}
+ if (of_find_property(pdev->dev.of_node, "clock-names", NULL)) {
+ pa->clock = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(pa->clock)) {
+ rc = PTR_ERR(pa->clock);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "unable to request core clock, rc=%d\n",
+ rc);
+ goto err_put_ctrl;
+ }
+ }
+
platform_set_drvdata(pdev, ctrl);
raw_spin_lock_init(&pa->lock);