summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/utils/regmap/Kconfig6
-rw-r--r--lib/utils/regmap/fdt_regmap.c94
-rw-r--r--lib/utils/regmap/fdt_regmap_drivers.carray3
-rw-r--r--lib/utils/regmap/objects.mk3
4 files changed, 106 insertions, 0 deletions
diff --git a/lib/utils/regmap/Kconfig b/lib/utils/regmap/Kconfig
index 8db5c8b8..b1ff501b 100644
--- a/lib/utils/regmap/Kconfig
+++ b/lib/utils/regmap/Kconfig
@@ -2,6 +2,12 @@
menu "Regmap Support"
+config FDT_REGMAP
+ bool "FDT based regmap drivers"
+ depends on FDT
+ select REGMAP
+ default n
+
config REGMAP
bool "Regmap support"
default n
diff --git a/lib/utils/regmap/fdt_regmap.c b/lib/utils/regmap/fdt_regmap.c
new file mode 100644
index 00000000..fffac1de
--- /dev/null
+++ b/lib/utils/regmap/fdt_regmap.c
@@ -0,0 +1,94 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <[email protected]>
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_error.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/regmap/fdt_regmap.h>
+
+/* List of FDT regmap drivers generated at compile time */
+extern struct fdt_regmap *fdt_regmap_drivers[];
+extern unsigned long fdt_regmap_drivers_size;
+
+static int fdt_regmap_init(void *fdt, int nodeoff, u32 phandle)
+{
+ int pos, rc;
+ struct fdt_regmap *drv;
+ const struct fdt_match *match;
+
+ /* Try all I2C drivers one-by-one */
+ for (pos = 0; pos < fdt_regmap_drivers_size; pos++) {
+ drv = fdt_regmap_drivers[pos];
+ match = fdt_match_node(fdt, nodeoff, drv->match_table);
+ if (match && drv->init) {
+ rc = drv->init(fdt, nodeoff, phandle, match);
+ if (rc == SBI_ENODEV)
+ continue;
+ if (rc)
+ return rc;
+ return 0;
+ }
+ }
+
+ return SBI_ENOSYS;
+}
+
+static int fdt_regmap_find(void *fdt, int nodeoff, u32 phandle,
+ struct regmap **out_rmap)
+{
+ int rc;
+ struct regmap *rmap = regmap_find(phandle);
+
+ if (!rmap) {
+ /* Regmap not found so initialize matching driver */
+ rc = fdt_regmap_init(fdt, nodeoff, phandle);
+ if (rc)
+ return rc;
+
+ /* Try to find regmap again */
+ rmap = regmap_find(phandle);
+ if (!rmap)
+ return SBI_ENOSYS;
+ }
+
+ if (out_rmap)
+ *out_rmap = rmap;
+
+ return 0;
+}
+
+int fdt_regmap_get_by_phandle(void *fdt, u32 phandle,
+ struct regmap **out_rmap)
+{
+ int pnodeoff;
+
+ if (!fdt || !out_rmap)
+ return SBI_EINVAL;
+
+ pnodeoff = fdt_node_offset_by_phandle(fdt, phandle);
+ if (pnodeoff < 0)
+ return pnodeoff;
+
+ return fdt_regmap_find(fdt, pnodeoff, phandle, out_rmap);
+}
+
+int fdt_regmap_get(void *fdt, int nodeoff, struct regmap **out_rmap)
+{
+ int len;
+ const fdt32_t *val;
+
+ if (!fdt || (nodeoff < 0) || !out_rmap)
+ return SBI_EINVAL;
+
+ val = fdt_getprop(fdt, nodeoff, "regmap", &len);
+ if (!val)
+ return SBI_ENOENT;
+
+ return fdt_regmap_get_by_phandle(fdt, fdt32_to_cpu(*val), out_rmap);
+}
diff --git a/lib/utils/regmap/fdt_regmap_drivers.carray b/lib/utils/regmap/fdt_regmap_drivers.carray
new file mode 100644
index 00000000..c2f1c9d0
--- /dev/null
+++ b/lib/utils/regmap/fdt_regmap_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/regmap/fdt_regmap.h
+TYPE: struct fdt_regmap
+NAME: fdt_regmap_drivers
diff --git a/lib/utils/regmap/objects.mk b/lib/utils/regmap/objects.mk
index 5d1bead0..5ce2373e 100644
--- a/lib/utils/regmap/objects.mk
+++ b/lib/utils/regmap/objects.mk
@@ -7,4 +7,7 @@
# Anup Patel <[email protected]>
#
+libsbiutils-objs-$(CONFIG_FDT_REGMAP) += regmap/fdt_regmap.o
+libsbiutils-objs-$(CONFIG_FDT_REGMAP) += regmap/fdt_regmap_drivers.o
+
libsbiutils-objs-$(CONFIG_REGMAP) += regmap/regmap.o