--- /dev/null
+System-EDP Consumers:
+
+Required properties:
+- compatible: "nvidia,tegra124-sysedp"
+- nvidia,margin: This defines the margin when calculating the budget
+ for dynamic capping.
+- nvidia,min_budget: This defines the minimum budget for dynamic capping.
+
+Required nodes:
+- consumers: This node contains a set of subnodes describing different
+ devices on the system and their power consumption states.
+
+Optional subnodes of consumers:
+- consumerX - These nodes define the power consumption state for one
+ consumer device on the system.
+
+Required properties of each consumerX node:
+- nvidia,consumer_name: This property is the name of the consumer.
+- nvidia,states: This property lists the operating power state of the consumer
+ in milliwatts. For example, if "nvidia,states" is set to "<0 300>", then
+ that consumer will consume either 0mW or 300mW depending on the state set
+ by that consumer.
+
+Example:
+ sysedp {
+ compatible = "nvidia,tegra124-sysedp";
+ nvidia,margin = <0>;
+ nvidia,min_budget = <0>;
+
+ consumers {
+ consumer1 {
+ nvidia,consumer_name = "ov5693";
+ nvidia,states = <0 300>;
+ };
+ consumer2 {
+ nvidia,consumer_name = "mt9m114";
+ nvidia,states = <0 150>;
+ };
+ consumer3 {
+ nvidia,consumer_name = "speaker";
+ nvidia,states = <0 1080>;
+ };
+ consumer4 {
+ nvidia,consumer_name = "wifi";
+ nvidia,states = <0 1020>;
+ };
+ consumer5 {
+ nvidia,consumer_name = "pwm-backlight";
+ nvidia,states = <0 125 250 375 500 625 750 875 1000 1125 1250>;
+ };
+ consumer6 {
+ nvidia,consumer_name = "sdhci-tegra.2";
+ nvidia,states = <0 966>;
+ };
+ consumer7 {
+ nvidia,consumer_name = "sdhci-tegra.3";
+ nvidia,states = <0 966>;
+ };
+ consumer8 {
+ nvidia,consumer_name = "as364x";
+ nvidia,states = <0 350 700 1050 1400 1750 2100 2450 2800 3150 3500>;
+ };
+ consumer9 {
+ nvidia,consumer_name = "modem";
+ nvidia,states = <0 4100>;
+ };
+ };
+ };
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/of.h>
#define CREATE_TRACE_POINTS
#include <trace/events/sysedp.h>
}
EXPORT_SYMBOL(sysedp_get_state);
+static void of_sysedp_get_pdata(struct platform_device *pdev,
+ struct sysedp_platform_data **pdata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *np_consumers;
+ struct device_node *child;
+ struct sysedp_platform_data *obj_ptr;
+ int idx = 0;
+ int i;
+ u32 lenp, val;
+ int n;
+ u32 *u32_ptr;
+ const char *c_ptr;
+ const void *ptr;
+ int ret;
+
+ obj_ptr = devm_kzalloc(&pdev->dev, sizeof(struct sysedp_platform_data),
+ GFP_KERNEL);
+ if (!obj_ptr)
+ return;
+
+ np_consumers = of_get_child_by_name(np, "consumers");
+ if (!np_consumers)
+ return;
+
+ obj_ptr->consumer_data_size = of_get_child_count(np_consumers);
+ if (!obj_ptr->consumer_data_size)
+ return;
+
+ obj_ptr->consumer_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct sysedp_consumer_data) *
+ obj_ptr->consumer_data_size, GFP_KERNEL);
+ if (!obj_ptr->consumer_data)
+ return;
+
+ for_each_child_of_node(np_consumers, child) {
+ ptr = of_get_property(child, "nvidia,consumer_name", &lenp);
+ if (!ptr)
+ return;
+ obj_ptr->consumer_data[idx].name = devm_kzalloc(&pdev->dev,
+ sizeof(char) * lenp, GFP_KERNEL);
+ if (!obj_ptr->consumer_data[idx].name)
+ return;
+ ret = of_property_read_string(child, "nvidia,consumer_name",
+ &c_ptr);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "The name of consumer %s is not set\n",
+ child->name);
+ return;
+ }
+ strncpy(obj_ptr->consumer_data[idx].name, c_ptr, lenp);
+
+ ptr = of_get_property(child, "nvidia,states", &lenp);
+ if (!ptr)
+ return;
+ n = lenp / sizeof(u32);
+ if (!n)
+ return;
+ obj_ptr->consumer_data[idx].states = devm_kzalloc(&pdev->dev,
+ sizeof(unsigned int) * n, GFP_KERNEL);
+ if (!obj_ptr->consumer_data[idx].states)
+ return;
+ u32_ptr = kzalloc(sizeof(u32) * n, GFP_KERNEL);
+ if (!u32_ptr)
+ return;
+ ret = of_property_read_u32_array(child, "nvidia,states",
+ u32_ptr, n);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Fail to read states of consumer %s\n",
+ child->name);
+ kfree(u32_ptr);
+ return;
+ }
+ for (i = 0; i < n; ++i)
+ obj_ptr->consumer_data[idx].states[i] = u32_ptr[i];
+ obj_ptr->consumer_data[idx].num_states = n;
+ kfree(u32_ptr);
+
+ ++idx;
+ }
+
+ ret = of_property_read_u32(np, "nvidia,margin", &val);
+ if (!ret)
+ obj_ptr->margin = (s32)val;
+
+ ret = of_property_read_u32(np, "nvidia,min_budget", &val);
+ if (!ret)
+ obj_ptr->min_budget = (s32)val;
+
+ *pdata = obj_ptr;
+
+ return;
+}
static int sysedp_probe(struct platform_device *pdev)
{
- pdata = pdev->dev.platform_data;
+ if (pdev->dev.of_node)
+ of_sysedp_get_pdata(pdev, &pdata);
+ else
+ pdata = pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
return 0;
}
+static const struct of_device_id sysedp_of_match[] = {
+ { .compatible = "nvidia,tegra124-sysedp", },
+};
+MODULE_DEVICE_TABLE(of, sysedp_of_match);
+
static struct platform_driver sysedp_driver = {
.probe = sysedp_probe,
.driver = {
.owner = THIS_MODULE,
- .name = "sysedp"
+ .name = "sysedp",
+ .of_match_table = sysedp_of_match,
}
};