]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
edp: add DT support for sysedp consumers
authorKerwin Wan <kerwinw@nvidia.com>
Tue, 10 Dec 2013 06:38:01 +0000 (14:38 +0800)
committerTimo Alho <talho@nvidia.com>
Thu, 12 Jun 2014 19:37:54 +0000 (12:37 -0700)
Bug 1391872

Change-Id: I1e681a998bd68576d1ebdb23e6d5afecc4fa931a
Signed-off-by: Steve Rogers <srogers@nvidia.com>
Reviewed-on: http://git-master/r/340280
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Timo Alho <talho@nvidia.com>
Documentation/devicetree/bindings/edp/nvidia,tegra124-sysedp.txt [new file with mode: 0644]
drivers/edp/sysedp.c

diff --git a/Documentation/devicetree/bindings/edp/nvidia,tegra124-sysedp.txt b/Documentation/devicetree/bindings/edp/nvidia,tegra124-sysedp.txt
new file mode 100644 (file)
index 0000000..2efe681
--- /dev/null
@@ -0,0 +1,68 @@
+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>;
+                       };
+               };
+       };
index bae90673fb72b82d7ac7f9f5ad2fc7044730e6d9..3ee8fe9baeafa4c0924cbdec94f2536545b6dfec 100644 (file)
@@ -21,6 +21,7 @@
 #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>
 
@@ -236,10 +237,108 @@ unsigned int sysedp_get_state(struct sysedp_consumer *consumer)
 }
 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;
 
@@ -250,11 +349,17 @@ static int sysedp_probe(struct platform_device *pdev)
        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,
        }
 };