diff mbox series

[6/8] soc: qcom: Add PMIC secure register write helpers

Message ID 20220808073459.396278-7-y.oudjana@protonmail.com
State New
Headers show
Series power: supply: Add driver for Qualcomm SMBCHG | expand

Commit Message

Yassine Oudjana Aug. 8, 2022, 7:34 a.m. UTC
From: Yassine Oudjana <y.oudjana@protonmail.com>

Some peripheral blocks in Qualcomm PMICs such as some in the
switch-mode battery charger and fuel gauge of PMI8994 and later
have secure registers that need to be unlocked first before being
written to. Add some helper functions to do what is needed to
write to those registers.

Signed-off-by: Yassine Oudjana <y.oudjana@protonmail.com>
---
 MAINTAINERS                       |  6 +++
 drivers/soc/qcom/Kconfig          |  4 ++
 drivers/soc/qcom/Makefile         |  1 +
 drivers/soc/qcom/pmic-sec-write.c | 82 +++++++++++++++++++++++++++++++
 include/soc/qcom/pmic-sec-write.h |  9 ++++
 5 files changed, 102 insertions(+)
 create mode 100644 drivers/soc/qcom/pmic-sec-write.c
 create mode 100644 include/soc/qcom/pmic-sec-write.h
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 7e9f5893c0eb..f6cf3a27d132 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16942,6 +16942,12 @@  S:	Maintained
 F:	Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
 F:	drivers/mtd/nand/raw/qcom_nandc.c
 
+QUALCOMM PMIC SECURE WRITE HELPERS
+M:	Yassine Oudjana <y.oudjana@protonmail.com>
+L:	linux-arm-msm@vger.kernel.org
+S:	Maintained
+F:	drivers/soc/qcom/pmic-sec-write.c
+
 QUALCOMM RMNET DRIVER
 M:	Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
 M:	Sean Tranchetti <quic_stranche@quicinc.com>
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index e0d7a5459562..ecc3aeb75ba7 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -91,6 +91,10 @@  config QCOM_PDR_HELPERS
 	tristate
 	select QCOM_QMI_HELPERS
 
+config QCOM_PMIC_SEC_WRITE
+	tristate
+	depends on REGMAP
+
 config QCOM_QMI_HELPERS
 	tristate
 	depends on NET
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index d66604aff2b0..058f499820cd 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -29,3 +29,4 @@  obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=	kryo-l2-accessors.o
 obj-$(CONFIG_QCOM_ICC_BWMON)	+= icc-bwmon.o
+obj-$(CONFIG_QCOM_PMIC_SEC_WRITE)	+= pmic-sec-write.o
diff --git a/drivers/soc/qcom/pmic-sec-write.c b/drivers/soc/qcom/pmic-sec-write.c
new file mode 100644
index 000000000000..8072c6115f2e
--- /dev/null
+++ b/drivers/soc/qcom/pmic-sec-write.c
@@ -0,0 +1,82 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Helper functions for secure register writes on Qualcomm PMICs
+ */
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+
+#define SEC_ACCESS_ADDR		0x00d0
+#define SEC_ACCESS_VALUE	0x00a5
+#define PERPH_BASE_MASK		0xff00
+
+static DEFINE_SPINLOCK(sec_access_lock);
+
+/**
+ * @brief qcom_pmic_sec_write() - Write to a secure register
+ *
+ * @param regmap Pointer to regmap
+ * @param addr   Address of register to write into
+ * @param val    Buffer to write bytes from
+ * @param len    Length of register in bytes
+ * @return 0 on success, -errno on failure
+ *
+ * @details: Some blocks have registers that need to be unlocked first before
+ * being written to. This function unlocks secure registers in the peripheral
+ * block of a given register then writes a given value to the register.
+ */
+int qcom_pmic_sec_write(struct regmap *regmap, u16 addr, u8 *val, int len)
+{
+	unsigned long flags;
+	unsigned int perph_base;
+	int ret;
+
+	spin_lock_irqsave(&sec_access_lock, flags);
+
+	/* Get peripheral base of given register */
+	perph_base = (addr & PERPH_BASE_MASK);
+
+	ret = regmap_write(regmap, perph_base + SEC_ACCESS_ADDR,
+			   SEC_ACCESS_VALUE);
+	if (ret)
+		goto out;
+
+	ret = regmap_bulk_write(regmap, addr, val, len);
+out:
+	spin_unlock_irqrestore(&sec_access_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_pmic_sec_write);
+
+/**
+ * @brief qcom_pmic_sec_masked_write() - Masked write to secure registers
+ *
+ * @param regmap Pointer to regmap
+ * @param addr   Address of register to write into
+ * @param mask   Mask to apply on value
+ * @param val    value to be written
+ * @return 0 on success, -errno on failure
+ *
+ * @details: Masked version of smbchg_sec_write().
+ */
+int qcom_pmic_sec_masked_write(struct regmap *regmap, u16 addr, u8 mask, u8 val)
+{
+	int reg;
+	int ret;
+
+	ret = regmap_read(regmap, addr, &reg);
+	if (ret)
+		return ret;
+
+	reg &= ~mask;
+	reg |= val & mask;
+
+	return qcom_pmic_sec_write(regmap, addr, (u8 *)&reg, 1);
+}
+EXPORT_SYMBOL_GPL(qcom_pmic_sec_masked_write);
+
+MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
+MODULE_DESCRIPTION("Qualcomm PMIC secure write helpers");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/qcom/pmic-sec-write.h b/include/soc/qcom/pmic-sec-write.h
new file mode 100644
index 000000000000..cc2229620ca4
--- /dev/null
+++ b/include/soc/qcom/pmic-sec-write.h
@@ -0,0 +1,9 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_ARCH_QCOM_PMIC_SEC_WRITE_H__
+#define __SOC_ARCH_QCOM_PMIC_SEC_WRITE_H__
+
+int qcom_pmic_sec_write(struct regmap *regmap, u16 addr, u8 *val, int len);
+int qcom_pmic_sec_masked_write(struct regmap *regmap, u16 addr, u8 mask, u8 val);
+
+#endif