[PATCH 2/2] mfd: syscon: Add syscon-names and phandle args support

From: Orson Zhai
Date: Thu Nov 14 2019 - 07:23:38 EST



There are a lot of global registers used across multiple similar SoCs
from Unisoc. It is not easy to manage all of them very well by current
syscon device tree interfaces.

Add helper functions to get regmap and syscon args by syscon-names all
together.

This patch does not affect original syscon code and usage. It may help
other SoC vendors if they have the same trouble as well.

Signed-off-by: Orson Zhai <orson.zhai@xxxxxxxxxx>
---
drivers/mfd/syscon.c | 65 ++++++++++++++++++++++++++++++++++++++
include/linux/mfd/syscon.h | 22 +++++++++++++
2 files changed, 87 insertions(+)

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 660723276481..7ed1b2e4dba4 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -225,6 +225,71 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
}
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);

+struct regmap *syscon_regmap_lookup_by_name(struct device_node *np,
+ const char *name)
+{
+ struct device_node *syscon_np;
+ struct of_phandle_args args;
+ struct regmap *regmap;
+ int index = 0;
+ int rc;
+
+ if (name)
+ index = of_property_match_string(np, "syscon-names", name);
+
+ if (index < 0)
+ return ERR_PTR(-EINVAL);
+
+ rc = of_parse_phandle_with_args(np, "syscons", "#syscon-cells", index,
+ &args);
+ if (rc)
+ return ERR_PTR(rc);
+
+ syscon_np = args.np;
+
+ if (!syscon_np)
+ return ERR_PTR(-ENODEV);
+
+ regmap = syscon_node_to_regmap(syscon_np);
+
+ of_node_put(syscon_np);
+
+ return regmap;
+}
+EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_name);
+
+int syscon_get_args_by_name(struct device_node *np,
+ const char *name,
+ int arg_count,
+ unsigned int *out_args)
+{
+ struct of_phandle_args args;
+ int index = 0;
+ int rc;
+
+ if (name)
+ index = of_property_match_string(np, "syscon-names", name);
+
+ if (index < 0)
+ return -EINVAL;
+
+ rc = of_parse_phandle_with_args(np, "syscons", "#syscon-cells", index,
+ &args);
+ if (rc)
+ return rc;
+
+ if (arg_count > args.args_count)
+ arg_count = args.args_count;
+
+ for (index = 0; index < arg_count; index++)
+ out_args[index] = args.args[index];
+
+ of_node_put(args.np);
+
+ return arg_count;
+}
+EXPORT_SYMBOL_GPL(syscon_get_args_by_name);
+
static int syscon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
index 112dc66262cc..5584173cd5d4 100644
--- a/include/linux/mfd/syscon.h
+++ b/include/linux/mfd/syscon.h
@@ -23,6 +23,13 @@ extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
extern struct regmap *syscon_regmap_lookup_by_phandle(
struct device_node *np,
const char *property);
+extern struct regmap *syscon_regmap_lookup_by_name(
+ struct device_node *np,
+ const char *name);
+extern int syscon_get_args_by_name(struct device_node *np,
+ const char *name,
+ int arg_count,
+ unsigned int *out_args);
#else
static inline struct regmap *device_node_to_regmap(struct device_node *np)
{
@@ -45,6 +52,21 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle(
{
return ERR_PTR(-ENOTSUPP);
}
+
+static inline struct regmap *syscon_regmap_lookup_by_name(
+ struct device_node *np,
+ const char *name)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+static int syscon_get_args_by_name(struct device_node *np,
+ const char *name,
+ int arg_count,
+ unsigned int *out_args)
+{
+ return -ENOTSUPP;
+}
#endif

#endif /* __LINUX_MFD_SYSCON_H__ */
--
2.18.0