diff --git a/MAINTAINERS b/MAINTAINERS
index c788ff0506c3..9eeb749ef234 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21997,6 +21997,7 @@ R:	Laxman Dewangan <ldewangan@nvidia.com>
 R:	Krishna Yarlagadda <kyarlagadda@nvidia.com>
 S:	Supported
 F:	Documentation/misc-devices/tegra-cfg.rst
+F:	drivers/soc/tegra/tegra-cfg.c
 
 TEGRA PWM DRIVER
 M:	Thierry Reding <thierry.reding@gmail.com>
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index 01059619e764..8d0c8dc62c8c 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
 obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
 obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
 obj-$(CONFIG_ARCH_TEGRA_186_SOC) += ari-tegra186.o
+obj-y += tegra-cfg.o
diff --git a/drivers/soc/tegra/tegra-cfg.c b/drivers/soc/tegra/tegra-cfg.c
new file mode 100644
index 000000000000..53d181bff40a
--- /dev/null
+++ b/drivers/soc/tegra/tegra-cfg.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include <soc/tegra/tegra-cfg.h>
+
+static int tegra_cfg_update_reg_info(struct device_node *cfg_node,
+				     const struct tegra_cfg_field_desc *field,
+				     struct tegra_cfg_reg *regs,
+				     struct tegra_cfg *cfg)
+{
+	int ret;
+	unsigned int k, value = 0;
+
+	ret = of_property_read_u32(cfg_node, field->name, &value);
+	if (ret)
+		return ret;
+
+	/*
+	 * Find matching register for this field in register info. Field info
+	 * has details of register offset.
+	 */
+	for (k = 0; k < cfg->num_regs; ++k) {
+		if (regs[k].offset == field->offset)
+			break;
+	}
+
+	/* If register not found, add new at end of list */
+	if (k == cfg->num_regs) {
+		cfg->num_regs++;
+		regs[k].offset = field->offset;
+	}
+
+	/* add field value to register */
+	value = value << __ffs(field->mask);
+	regs[k].value |= value & field->mask;
+	regs[k].mask |= field->mask;
+
+	return 0;
+}
+
+/*
+ * Initialize config list. Parse config node for properties (register fields).
+ * Get list of configs and value of fields populated in tegra_cfg_desc.
+ * Consolidate field data in reg offset, mask & value format in tegra_cfg.
+ * Repeat for each config and store in tegra_cfg_list.
+ */
+static struct tegra_cfg_list *tegra_cfg_init(struct device *dev,
+					     const struct device_node *np,
+					     const struct tegra_cfg_desc *cfg_desc)
+{
+	struct device_node *np_cfg = NULL, *child;
+	struct tegra_cfg_reg *regs;
+	struct tegra_cfg_list *list;
+	struct tegra_cfg *cfg;
+	const struct tegra_cfg_field_desc *fields;
+	unsigned int count, i;
+	int ret;
+
+	if (np)
+		np_cfg = of_get_child_by_name(np, "config");
+	if (!np_cfg)
+		return ERR_PTR(-ENODEV);
+
+	count = of_get_child_count(np_cfg);
+	if (count <= 0) {
+		dev_dbg(dev, "Node %s: No child node for config settings\n",
+			np->name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL);
+	if (!list)
+		return ERR_PTR(-ENOMEM);
+	list->num_cfg = 0;
+	list->cfg = NULL;
+
+	/* allocate mem for all configurations */
+	list->cfg = devm_kcalloc(dev, count, sizeof(*list->cfg),
+				 GFP_KERNEL);
+	if (!list->cfg)
+		return ERR_PTR(-ENOMEM);
+
+	fields = cfg_desc->fields;
+	count = 0;
+	/*
+	 * Iterate through all configurations.
+	 */
+	for_each_available_child_of_node(np_cfg, child) {
+		cfg = &list->cfg[count];
+
+		regs = devm_kcalloc(dev, cfg_desc->num_regs,
+				    sizeof(*regs), GFP_KERNEL);
+		if (!regs)
+			return ERR_PTR(-ENOMEM);
+
+		cfg->name = child->name;
+		cfg->regs = regs;
+		cfg->num_regs = 0;
+
+		/* Look for all fields in 'child' config */
+		for (i = 0; i < cfg_desc->num_fields; i++) {
+			ret = tegra_cfg_update_reg_info(child, &fields[i],
+							regs, cfg);
+			if (ret < 0)
+				continue;
+		}
+		count++;
+	}
+
+	list->num_cfg = count;
+
+	return list;
+}
+
+struct tegra_cfg *
+tegra_cfg_get_by_name(struct device *dev,
+		      const struct tegra_cfg_list *list,
+		      const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < list->num_cfg; ++i) {
+		if (!strcmp(list->cfg[i].name, name))
+			return &list->cfg[i];
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(tegra_cfg_get_by_name);
+
+struct tegra_cfg_list *tegra_cfg_get(struct device *dev,
+				     const struct device_node *np,
+				     const struct tegra_cfg_desc *cfg_desc)
+{
+	return tegra_cfg_init(dev, np, cfg_desc);
+}
+EXPORT_SYMBOL(tegra_cfg_get);
diff --git a/include/soc/tegra/tegra-cfg.h b/include/soc/tegra/tegra-cfg.h
new file mode 100644
index 000000000000..ece6f63a83c1
--- /dev/null
+++ b/include/soc/tegra/tegra-cfg.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#ifndef __SOC_TEGRA_CFG_H__
+#define __SOC_TEGRA_CFG_H__
+
+#include <linux/types.h>
+
+/**
+ * Config settings are a list of DT properties holding each field's recommended
+ * value. Field info is held in tegra_cfg_field and tegra_cfg_desc.
+ * Data of all fields in a single register are parsed and stored in
+ * tegra_cfg_reg. Struct tegra_cfg_list contains list of configurations
+ * and each config tegra_cfg contains register list.
+ * Client drivers provide field and register data through tegra_cfg_desc.
+ */
+
+/**
+ * Register field and DT property mapping.
+ * @name: device property name of the field.
+ * @offset: offset of register from base.
+ * @mask: mask of field within register.
+ */
+struct tegra_cfg_field_desc {
+	const char *name;
+	u32 offset;
+	u32 mask;
+};
+
+#define TEGRA_CFG_FIELD(fname, roffset, fmask)	\
+{						\
+	.name = fname,				\
+	.offset = roffset,			\
+	.mask = fmask,				\
+}
+
+/**
+ * Configuration setting from controller where it passes the total number of
+ * registers having config, and their register field names.
+ */
+struct tegra_cfg_desc {
+	unsigned int num_regs;
+	unsigned int num_fields;
+	const struct tegra_cfg_field_desc *fields;
+};
+
+/**
+ * Configuration register info generated by combining all field config settings
+ * in device tree of a register.
+ * @offset: offset of register from base.
+ * @mask: generated mask from aggregate of all field settings read from dt.
+ * @value: generated value by combining all field properties read from dt.
+ */
+struct tegra_cfg_reg {
+	u32 offset;
+	u32 mask;
+	u32 value;
+};
+
+/**
+ * Per config info of all registers.
+ */
+struct tegra_cfg {
+	const char *name;
+	unsigned int num_regs;
+	struct tegra_cfg_reg *regs;
+};
+
+/**
+ * Config settings list.
+ */
+struct tegra_cfg_list {
+	unsigned int num_cfg;
+	struct tegra_cfg *cfg;
+};
+
+struct tegra_cfg *
+tegra_cfg_get_by_name(struct device *dev,
+		      const struct tegra_cfg_list *list,
+		      const char *cfg_name);
+
+struct tegra_cfg_list *tegra_cfg_get(struct device *dev,
+				     const struct device_node *np,
+				     const struct tegra_cfg_desc *cfg_dev);
+#endif /* __SOC_TEGRA_CFG_H__ */
