summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2021-04-07 21:11:28 +0200
committerDaniel Lezcano <daniel.lezcano@linaro.org>2021-06-29 00:06:38 +0200
commit7525abb234695d07a0094b2f511d5fe8bea0a979 (patch)
tree43b369c43dcf794311b6c3369d4711223bff5db0
parenta0d4daeccca8ee82b36fd7c18c7570065013ec5a (diff)
downloadlinux-7525abb234695d07a0094b2f511d5fe8bea0a979.tar.gz
powercap: DT parsing
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--drivers/powercap/Makefile2
-rw-r--r--drivers/powercap/dtpm.c5
-rw-r--r--drivers/powercap/dtpm_of.c177
-rw-r--r--include/linux/dtpm.h14
4 files changed, 195 insertions, 3 deletions
diff --git a/drivers/powercap/Makefile b/drivers/powercap/Makefile
index fabcf388a8d3..616aa10c929f 100644
--- a/drivers/powercap/Makefile
+++ b/drivers/powercap/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_DTPM) += dtpm.o
+obj-$(CONFIG_DTPM) += dtpm.o dtpm_of.o
obj-$(CONFIG_DTPM_CPU) += dtpm_cpu.o
obj-$(CONFIG_POWERCAP) += powercap_sys.o
obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o
diff --git a/drivers/powercap/dtpm.c b/drivers/powercap/dtpm.c
index 4789c397d31a..61978fd9d3cb 100644
--- a/drivers/powercap/dtpm.c
+++ b/drivers/powercap/dtpm.c
@@ -465,7 +465,7 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent)
}
EXPORT_SYMBOL_GPL(dtpm_register);
-int __init dtpm_probe(void)
+int dtpm_probe(void)
{
struct dtpm_descr *dtpm_descr;
@@ -480,4 +480,5 @@ int __init dtpm_probe(void)
return 0;
}
-late_initcall(dtpm_probe);
+EXPORT_SYMBOL_GPL(dtpm_probe);
+
diff --git a/drivers/powercap/dtpm_of.c b/drivers/powercap/dtpm_of.c
new file mode 100644
index 000000000000..b8e384cf30ca
--- /dev/null
+++ b/drivers/powercap/dtpm_of.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2021 Linaro Limited
+ *
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dtpm.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct dtpm_node {
+ int method;
+ struct device_node *np;
+ struct dtpm *dtpm;
+ struct list_head node;
+};
+
+static LIST_HEAD(dtpm_list);
+
+static DEFINE_MUTEX(dtpm_lock);
+
+static struct dtpm *__dtpm_find(struct device_node *np, int method)
+{
+ struct dtpm_node *node;
+
+ list_for_each_entry(node, &dtpm_list, node) {
+ if (np == node->np && method == node->method)
+ return node->dtpm;
+ }
+
+ return NULL;
+}
+
+struct dtpm *dtpm_of_find(struct device_node *np, int method)
+{
+ struct dtpm *dtpm;
+
+ mutex_lock(&dtpm_lock);
+ dtpm = __dtpm_find(np, method);
+ mutex_unlock(&dtpm_lock);
+
+ return dtpm;
+}
+
+/**
+ * dtpm_of_add - Add the dtpm in the dtpm list
+ * @name: a name used as an identifier
+ * @dtpm: the dtpm node to be registered
+ *
+ * Stores the dtpm device in a list. The list contains all the devices
+ * which are power capable in terms of limitation and power
+ * consumption measurements. Even if conceptually, a power capable
+ * device won't register itself twice, the function will check if it
+ * was already registered in order to prevent a misuse of the API.
+ *
+ * Return: 0 on success, -EEXIST if the device name is already present
+ * in the list, -ENOMEM in case of memory allocation failure.
+ */
+int dtpm_of_add(struct device *dev, int method, struct dtpm *dtpm)
+{
+ struct dtpm_node *node;
+ int ret;
+
+ WARN_ON(!dev);
+
+ mutex_lock(&dtpm_lock);
+
+ ret = -EEXIST;
+ if (__dtpm_find(dev_of_node(dev), method))
+ goto out_unlock;
+
+ ret = -ENOMEM;
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ goto out_unlock;
+
+ node->np = dev_of_node(dev);
+ node->method = method;
+ node->dtpm = dtpm;
+
+ list_add(&node->node, &dtpm_list);
+
+ pr_debug("Registered dtpm device '%pOF'\n", node);
+
+ ret = 0;
+out_unlock:
+ mutex_unlock(&dtpm_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dtpm_of_add);
+
+/**
+ * dtpm_of_del - Remove the dtpm device from the list
+ * @name: the dtpm device name to be removed
+ *
+ * Remove the dtpm device from the list of the registered devices.
+ */
+void dtpm_of_del(struct device *dev, int method)
+{
+ struct dtpm_node *node;
+
+ mutex_lock(&dtpm_lock);
+
+ list_for_each_entry(node, &dtpm_list, node) {
+
+ if (dev_of_node(dev) != node->np ||
+ method != node->method)
+ continue;
+
+ list_del(&node->node);
+ kfree(node);
+
+ break;
+ }
+
+ mutex_unlock(&dtpm_lock);
+}
+EXPORT_SYMBOL_GPL(dtpm_of_del);
+
+/**
+ * dtpm_of_for_each - Browse all powerzone properties
+ * @name: the property name to act on
+ * @parent: the parent to hook the new dtpm zones
+ * @cb: user specific callback in charge of the dtpm setup
+ *
+ * This function will find all the powerzone properties matching @name
+ * and will call the @cb with the corresponding device tree node. The
+ * callback is responsible of creating the dtpm node and attach it to
+ * the @parent.
+ *
+ * Return: 0 on success, -EINVAL, -ENODATA, -EILSEQ conforming to the
+ * of_property_read_string_index return code or any value non zero
+ * returned by the callback.
+ */
+int dtpm_of_for_each(const char *name, struct dtpm *parent, dtpm_of_cb cb)
+{
+ struct device_node *node;
+ int ret = 0;
+
+ for_each_node_with_property(node, "powerzone") {
+
+ const char *prop_name;
+ int i, nr_strings;
+
+ nr_strings = of_property_count_strings(node, "powerzone");
+
+ for (i = 0; i < nr_strings; i++) {
+
+ ret = of_property_read_string_index(node, "powerzone",
+ i, &prop_name);
+ if (ret)
+ goto out_err;
+
+ pr_debug("Found powerzone property '%s'\n", prop_name);
+
+ if (strcmp(name, prop_name))
+ continue;
+
+ ret = cb(node, name, parent);
+ if (ret)
+ goto out_err;
+ }
+
+ of_node_put(node);
+ }
+
+ return 0;
+
+out_err:
+ of_node_put(node);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dtpm_of_for_each);
diff --git a/include/linux/dtpm.h b/include/linux/dtpm.h
index 50679c48adab..aa574b26778a 100644
--- a/include/linux/dtpm.h
+++ b/include/linux/dtpm.h
@@ -33,11 +33,17 @@ struct dtpm_ops {
};
typedef int (*dtpm_init_t)(void);
+typedef int (*dtpm_of_cb)(struct device_node *node, const char *name,
+ struct dtpm *parent);
struct dtpm_descr {
dtpm_init_t init;
};
+enum {
+ DTPM_EM_DVFS,
+};
+
/* Init section thermal table */
extern struct dtpm_descr __dtpm_table[];
extern struct dtpm_descr __dtpm_table_end[];
@@ -74,4 +80,12 @@ int dtpm_register(const char *name, struct dtpm *dtpm, struct dtpm *parent);
int dtpm_register_cpu(struct dtpm *parent);
+int dtpm_of_add(struct device *dev, int method, struct dtpm *dtpm);
+
+void dtpm_of_del(struct device *dev, int method);
+
+struct dtpm *dtpm_of_find(struct device_node *np, int method);
+
+int dtpm_of_for_each(const char *name, struct dtpm *parent, dtpm_of_cb cb);
+
#endif