diff --git a/Documentation/devicetree/bindings/soc/qcom/qfprom.txt b/Documentation/devicetree/bindings/soc/qcom/qfprom.txt
new file mode 100644
index 0000000..3ed7309
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qfprom.txt
@@ -0,0 +1,29 @@
+QCOM QFPROM
+
+QFPROM is basically some efuses where things like calibration data, speed bins,
+etc are stored. This data is accessed by various drivers like the cpufreq,
+thermal, etc.
+
+Required properties:
+- compatible: must contain "qcom,qfprom" followed by "syscon"
+- reg: Address range for QFPROM
+- stride : register address stride.
+	1 for byte.
+	2 for 2 bytes
+	3 for 3 bytes
+	4 for a word.
+	
+
+Example:
+	qfprom: qfprom@00700000 {
+		compatible 	= "qcom,qfprom", "syscon";
+		reg		= <0x00700000 0x1000>;
+		stride		= <1>;
+	};
+
+	tsens@34000 {
+		compatible = "qcom,tsens-apq8064";
+		reg = <0x34000 0x1000>;
+		qcom,qfprom = <&qfprom 0x18 0x10>, <&qfprom 0x28 0x10>;
+		qcom,qfprom-names = "calib", "backup_calib";
+	};
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 012fb37..389ec3e 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -19,3 +19,10 @@ config QCOM_PM
 	  QCOM Platform specific power driver to manage cores and L2 low power
 	  modes. It interface with various system drivers to put the cores in
 	  low power modes.
+
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Interface"
+        depends on ARCH_QCOM && OF
+        help
+          Say y here to enable QFPROM support. The QFPROM provides access
+          functions for QFPROM data to rest of the drivers via syscon wrappers.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 20b329f..f5aff0a 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
 obj-$(CONFIG_QCOM_PM)	+=	spm.o
+obj-$(CONFIG_QCOM_QFPROM) +=	qfprom.o
 CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
 obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o
diff --git a/drivers/soc/qcom/qfprom.c b/drivers/soc/qcom/qfprom.c
new file mode 100644
index 0000000..d00ed25
--- /dev/null
+++ b/drivers/soc/qcom/qfprom.c
@@ -0,0 +1,134 @@
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/soc/qcom/qfprom.h>
+#include <linux/slab.h>
+
+#define QFPROM_MAX_ARGS	2
+
+static char *__qfprom_get_data(struct device *dev,
+				bool devm, int idx, int *len)
+{
+	struct device_node *syscon_np, *np = dev->of_node;
+	struct regmap *rm;
+	struct of_phandle_args args;
+	int rc, stride = 4;
+	u32 offset, size;
+	char *data;
+
+	if (!np)
+		return ERR_PTR(-EINVAL);
+
+	rc = of_parse_phandle_with_fixed_args(np, "qcom,qfprom",
+					      QFPROM_MAX_ARGS, idx, &args);
+	if (rc)
+		return ERR_PTR(rc);
+
+	syscon_np = args.np;
+
+	of_property_read_u32(syscon_np, "stride", &stride);
+
+	if (stride >= 4)
+		stride = 4;
+
+	if (args.args_count < QFPROM_MAX_ARGS) {
+		dev_err(dev, "Insufficient qfprom arguments %d\n",
+			args.args_count);
+		return ERR_PTR(-EINVAL);
+	}
+
+	rm = syscon_node_to_regmap(syscon_np);
+	if (IS_ERR(rm))
+		return ERR_CAST(rm);
+
+	offset = args.args[0];
+	size = args.args[1];
+
+	of_node_put(syscon_np);
+
+	if (devm)
+		data = devm_kzalloc(dev, size, GFP_KERNEL | GFP_ATOMIC);
+	else
+		data = kzalloc(size, GFP_KERNEL | GFP_ATOMIC);
+
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	rc = regmap_bulk_read(rm, offset, data, size/stride);
+	if (rc < 0) {
+		if (devm)
+			devm_kfree(dev, data);
+		else
+			kfree(data);
+
+		return ERR_PTR(rc);
+	}
+
+	*len = size;
+
+	return data;
+}
+
+static char *__qfprom_get_data_byname(struct device *dev,
+				       bool devm, const char *name, int *len)
+{
+	int index = 0;
+
+	if (name)
+		index = of_property_match_string(dev->of_node,
+						 "qcom,qfprom-names", name);
+
+	return __qfprom_get_data(dev, devm, index, len);
+}
+
+char *devm_qfprom_get_data_byname(struct device *dev,
+					  const char *name, int *len)
+{
+	return __qfprom_get_data_byname(dev, true, name, len);
+}
+EXPORT_SYMBOL_GPL(devm_qfprom_get_data_byname);
+
+char *devm_qfprom_get_data(struct device *dev,
+				   int index, int *len)
+{
+	return __qfprom_get_data(dev, true, index, len);
+}
+EXPORT_SYMBOL_GPL(devm_qfprom_get_data);
+
+/**
+ * qfprom_get_data_byname(): Reads qfprom data by name
+ *
+ * @dev: device which is requesting qfprom data
+ * @index: name of qfprom resources specified "qcom,qfprom-names" DT property.
+ * @len: length of data read from qfprom.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a data buffer. The buffer should be freed by the user once its
+ * finished working with it kfree.
+ **/
+char *qfprom_get_data_byname(struct device *dev,
+				     const char *name, int *len)
+{
+	return __qfprom_get_data_byname(dev, false, name, len);
+}
+EXPORT_SYMBOL_GPL(qfprom_get_data_byname);
+
+/**
+ * qfprom_get_data(): Reads qfprom data from the index
+ *
+ * @dev: device which is requesting qfprom data
+ * @index: index into qfprom resources specified "qcom,qfprom" DT property.
+ * @len: length of data read from qfprom.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a data buffer. The buffer should be freed by the user once its
+ * finished working with it kfree.
+ **/
+char *qfprom_get_data(struct device *dev,
+				   int index, int *len)
+{
+	return __qfprom_get_data(dev, false, index, len);
+}
+EXPORT_SYMBOL_GPL(qfprom_get_data);
