devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Wei Ni <wni@nvidia.com>
To: durgadoss.r@intel.com, rui.zhang@intel.com,
	MLongnecker@nvidia.com, khali@linux-fr.org
Cc: devicetree-discuss@lists.ozlabs.org, linux-tegra@vger.kernel.org,
	lm-sensors@lm-sensors.org, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.orgrs.org,
	linux-arm-kernel@lists.infradead.org, Wei Ni <wni@nvidia.com>
Subject: [RFC PATCH 7/9] thermal: tegra30: add tegra30 thermal driver
Date: Mon, 18 Feb 2013 19:30:29 +0800	[thread overview]
Message-ID: <1361187031-3679-8-git-send-email-wni@nvidia.com> (raw)
In-Reply-To: <1361187031-3679-1-git-send-email-wni@nvidia.com>

dd Tegra30 thermal driver support. It create thermal zone with thermal
sensors and cooling device to participate in the linux thermal management.

Signed-off-by: Wei Ni <wni@nvidia.com>
---
 drivers/thermal/Kconfig          |    9 ++
 drivers/thermal/Makefile         |    1 +
 drivers/thermal/tegra3_thermal.c |  289 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 drivers/thermal/tegra3_thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index eadef5b..2403681 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -141,6 +141,15 @@ config INTEL_POWERCLAMP
 	  enforce idle time which results in more package C-state residency. The
 	  user interface is exposed via generic thermal framework.
 
+config TEGRA30_THERMAL
+	tristate "Tegra30 thermal driver"
+	depends on ARCH_TEGRA
+	help
+	  Select this to enable the Tegra30 thermal driver. Adds Tegra30 thermal
+	  implementation according to the thermal management framework. Create
+	  thermal zone with thermal sensors and cooling device to participate
+	  in the linux thermal management.
+
 config THERMAL_TEST
 	tristate "test driver"
 	help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index ee0f687..de0b411 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_EXYNOS_THERMAL)	+= exynos_thermal.o
 obj-$(CONFIG_DB8500_THERMAL)	+= db8500_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+= db8500_cpufreq_cooling.o
 obj-$(CONFIG_INTEL_POWERCLAMP)	+= intel_powerclamp.o
+obj-$(CONFIG_TEGRA30_THERMAL)	+= tegra3_thermal.o
 
 # dummy driver for testing
 obj-$(CONFIG_THERMAL_TEST)	+= thermal_test.o
diff --git a/drivers/thermal/tegra3_thermal.c b/drivers/thermal/tegra3_thermal.c
new file mode 100644
index 0000000..384168f
--- /dev/null
+++ b/drivers/thermal/tegra3_thermal.c
@@ -0,0 +1,289 @@
+/*
+ * Tegra thermal driver.
+ *
+ * Copyright (C) 2010-2013 NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define MAX_THROT_TABLE_SIZE    (64)
+
+struct throttle_table {
+	unsigned int cpu_freq;
+	int core_cap_level;
+};
+
+struct balanced_throttle {
+	struct thermal_cooling_device *cdev;
+	struct list_head node;
+	int is_throttling;
+	int throttle_count;
+	int throttle_index;
+	int throt_tab_size;
+	struct throttle_table throt_tab[MAX_THROT_TABLE_SIZE + 1];
+};
+
+struct tegra_thermal_data {
+	struct thermal_zone *tz;
+	struct node_args np_args;
+	int passive_delay;
+	struct balanced_throttle tj_throttle;
+	struct thermal_trip_point trip_ext;
+};
+
+static DEFINE_MUTEX(cpu_throttle_lock);
+
+static int tegra_throttle_get_max_state(struct thermal_cooling_device *cdev,
+				unsigned long *max_state)
+{
+	struct balanced_throttle *bthrot = cdev->devdata;
+
+	*max_state = bthrot->throt_tab_size;
+
+	return 0;
+}
+
+static int
+tegra_throttle_get_cur_state(struct thermal_cooling_device *cdev,
+				unsigned long *cur_state)
+{
+	struct balanced_throttle *bthrot = cdev->devdata;
+
+	mutex_lock(&cpu_throttle_lock);
+	*cur_state = bthrot->is_throttling ?
+			(bthrot->throt_tab_size - bthrot->throttle_index) :
+			0;
+	mutex_unlock(&cpu_throttle_lock);
+
+	return 0;
+}
+
+static int
+tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev,
+				unsigned long cur_state)
+{
+	struct balanced_throttle *bthrot = cdev->devdata;
+	int index;
+
+	mutex_lock(&cpu_throttle_lock);
+
+	/* TODO: we will handle the dvfs here */
+
+	bthrot->throttle_index = bthrot->throt_tab_size - cur_state;
+	index = bthrot->throttle_index;
+
+	mutex_unlock(&cpu_throttle_lock);
+
+	return 0;
+}
+
+static struct thermal_cooling_device_ops tegra_throttle_cooling_ops = {
+	.get_max_state = tegra_throttle_get_max_state,
+	.get_cur_state = tegra_throttle_get_cur_state,
+	.set_cur_state = tegra_throttle_set_cur_state,
+};
+
+struct thermal_cooling_device *balanced_throttle_register(
+		struct balanced_throttle *bthrot, char *type)
+{
+	bthrot->cdev = thermal_cooling_device_register(type, bthrot,
+						&tegra_throttle_cooling_ops);
+
+	if (IS_ERR(bthrot->cdev)) {
+		bthrot->cdev = NULL;
+		return ERR_PTR(-ENODEV);
+	}
+
+	return bthrot->cdev;
+}
+
+static struct tegra_thermal_data * __devinit thermal_tegra_dt_parse_pdata(
+						struct platform_device *pdev)
+{
+	struct tegra_thermal_data *tdata;
+	struct device_node *np = pdev->dev.of_node;
+	struct of_phandle_args args;
+	u32 val;
+	int ret;
+
+	if (!np)
+		return NULL;
+
+	tdata = devm_kzalloc(&pdev->dev, sizeof(*tdata), GFP_KERNEL);
+	if (!tdata) {
+		dev_err(&pdev->dev, "Can't allocate platform data\n");
+		return NULL;
+	}
+	memset(tdata, 0, sizeof(*tdata));
+
+	ret = of_parse_phandle_with_args(np, "sensors", "#sensor-cells", 0,
+					&args);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't get sensor.\n");
+		return NULL;
+	}
+	tdata->np_args.np = args.np;
+	tdata->np_args.index = args.args[0];
+
+	ret = of_property_read_u32(np, "passive-delay", &val);
+	if (!ret)
+		tdata->passive_delay = val;
+
+	ret = of_property_read_u32(np, "num-passive-trips", &val);
+	if (!ret)
+		tdata->trip_ext.num_passive_trips = val;
+
+	if (tdata->trip_ext.num_passive_trips) {
+		tdata->trip_ext.passive_trips = devm_kzalloc(&pdev->dev,
+						sizeof(int) * val, GFP_KERNEL);
+
+		of_property_read_u32_array(np, "passive-trips",
+				(u32 *)(tdata->trip_ext.passive_trips),
+				tdata->trip_ext.num_passive_trips);
+	}
+
+	ret = of_property_read_u32(np, "num-active-trips", &val);
+	if (!ret)
+		tdata->trip_ext.num_active_trips = val;
+
+	if (tdata->trip_ext.num_active_trips) {
+		tdata->trip_ext.active_trips = devm_kzalloc(&pdev->dev,
+						sizeof(int) * val, GFP_KERNEL);
+
+		of_property_read_u32_array(np, "active-trips",
+				(u32 *)(tdata->trip_ext.active_trips),
+				tdata->trip_ext.num_active_trips);
+	}
+
+	ret = of_property_read_u32(np, "throt-tab-size", &val);
+	if (!ret)
+		tdata->tj_throttle.throt_tab_size = val;
+
+	of_property_read_u32_array(np, "throt-tab",
+				(u32 *)(&tdata->tj_throttle.throt_tab),
+				tdata->tj_throttle.throt_tab_size * 2);
+
+	return tdata;
+}
+
+static int tegra30_thermal_probe(struct platform_device *pdev)
+{
+	struct tegra_thermal_data *pdata = pdev->dev.platform_data;
+	struct thermal_zone *tz;
+	struct thermal_sensor *ts;
+	static struct thermal_cooling_device *cdev;
+	int ret;
+
+	pdata = thermal_tegra_dt_parse_pdata(pdev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "Get platform data failed.\n");
+		return -EINVAL;
+	}
+
+	/* Create a thermal zone */
+	tz = create_thermal_zone("tz_tegra", NULL);
+	if (!tz) {
+		dev_err(&pdev->dev, "Create thermal_zone failed.\n");
+		return -EINVAL;
+	}
+
+	pdata->tz = tz;
+
+	/* Register cooling device */
+	cdev = balanced_throttle_register(&pdata->tj_throttle, "cdev_throttle");
+	if (!cdev) {
+		dev_err(&pdev->dev, "Register cooling device failed.\n");
+		goto exit_remove_thermal_zone;
+	}
+
+	/* Get sensor */
+	ts = get_sensor_by_node(&pdata->np_args);
+	if (!ts) {
+		dev_err(&pdev->dev, "get_sensor_by_node failed.\n");
+		goto exit_unregister_cooling;
+	}
+
+	ret = add_sensor_to_zone(pdata->tz, ts);
+	if (ret) {
+		dev_err(&pdev->dev, "add_sensor_to_zone failed.\n");
+		goto exit_unregister_cooling;
+	}
+
+	ret = add_cdev_to_zone(pdata->tz, cdev);
+	if (ret) {
+		dev_err(&pdev->dev, "add_cdev_to_zone failed.\n");
+		goto exit_unregister_cooling;
+	}
+
+	ret = add_sensor_trip_info(pdata->tz, ts, &pdata->trip_ext);
+	if (ret) {
+		dev_err(&pdev->dev, "add_sensor_trip_info failed.\n");
+		goto exit_unregister_cooling;
+	}
+
+	return 0;
+
+exit_unregister_cooling:
+	thermal_cooling_device_unregister(cdev);
+exit_remove_thermal_zone:
+	remove_thermal_zone(pdata->tz);
+	return -EINVAL;
+
+}
+
+static int tegra30_thermal_remove(struct platform_device *pdev)
+{
+	struct tegra_thermal_data *pdata = pdev->dev.platform_data;
+	int i;
+
+	for (i = 0; i < MAX_CDEVS_PER_ZONE; i++) {
+		if (pdata->tz->cdevs[i])
+			thermal_cooling_device_unregister(pdata->tz->cdevs[i]);
+		else
+			break;
+	}
+
+	remove_thermal_zone(pdata->tz);
+
+	return 0;
+}
+
+static const struct of_device_id tegra30_thermal_id_table[] = {
+	{ .compatible = "nvidia,tegra30-thermal" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, tegra30_thermal_id_table);
+
+static struct platform_driver tegra3_thermal_driver = {
+	.probe = tegra30_thermal_probe,
+	.remove = tegra30_thermal_remove,
+	.driver = {
+		.name = "tegra_thermal",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(tegra30_thermal_id_table),
+	},
+};
+module_platform_driver(tegra3_thermal_driver);
+
+MODULE_AUTHOR("Wei Ni <wni@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 thermal throttle driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


  parent reply	other threads:[~2013-02-18 11:30 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-18 11:30 [RFC PATCH 0/9] Support for tegra30 thermal Wei Ni
2013-02-18 11:30 ` [RFC PATCH 2/9] hwmon: (lm90) split set&show temp as common codes Wei Ni
2013-02-18 22:29   ` Matthew Longnecker
2013-02-19  9:48     ` Wei Ni
2013-02-19  3:31   ` [lm-sensors] " Guenter Roeck
     [not found]     ` <20130219033144.GA25610-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
2013-02-19 10:00       ` Wei Ni
2013-02-19 22:56   ` Stephen Warren
     [not found]     ` <51240331.7080604-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-02-20 12:31       ` Wei Ni
     [not found] ` <1361187031-3679-1-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-18 11:30   ` [RFC PATCH 1/9] ARM: dt: t30 cardhu: add dt entry for lm90 Wei Ni
     [not found]     ` <1361187031-3679-2-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19  3:28       ` Alex Courbot
2013-02-19  9:52         ` Wei Ni
     [not found]         ` <5122F162.9030103-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19 22:48           ` Stephen Warren
2013-02-18 11:30   ` [RFC PATCH 3/9] hwmon: (lm90) add support to handle irq Wei Ni
     [not found]     ` <1361187031-3679-4-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19  3:34       ` [lm-sensors] " Guenter Roeck
2013-02-19 10:43         ` Wei Ni
2013-02-19 23:00     ` Stephen Warren
2013-02-20  3:27       ` Alex Courbot
     [not found]         ` <5124429B.2000404-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-20 10:27           ` Wei Ni
2013-02-18 11:30   ` [RFC PATCH 5/9] Thermal: Support using dt node to get sensor Wei Ni
     [not found]     ` <1361187031-3679-6-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19 23:12       ` Stephen Warren
     [not found]         ` <512406F0.4080708-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-02-20 10:36           ` Wei Ni
2013-02-18 11:30   ` [RFC PATCH 6/9] hwmon: (lm90) Register to the thermal framework Wei Ni
2013-02-19  3:42     ` [lm-sensors] " Guenter Roeck
     [not found]       ` <20130219034205.GC25610-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
2013-02-19 10:47         ` Wei Ni
2013-02-19  5:22     ` Alex Courbot
2013-02-19 10:58       ` Wei Ni
     [not found]     ` <1361187031-3679-7-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19 23:18       ` Stephen Warren
2013-02-20 10:40         ` Wei Ni
2013-02-18 11:30   ` [RFC PATCH 8/9] ARM: dt: t30 cardhu: add dt entry for thermal driver Wei Ni
2013-02-19  3:42     ` Alex Courbot
2013-02-19  9:56       ` Wei Ni
     [not found]     ` <1361187031-3679-9-git-send-email-wni-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19 23:28       ` Stephen Warren
2013-02-20 11:53         ` Wei Ni
     [not found]           ` <5124B934.3020900-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-20 17:18             ` Stephen Warren
2013-02-18 11:30   ` [RFC PATCH 9/9] ARM: tegra: defconfig: enable thermal framework Wei Ni
2013-02-18 11:30 ` [RFC PATCH 4/9] hwmon: (lm90) use macros for the indexes of temp8 and temp11 Wei Ni
2013-02-19  5:39   ` Alex Courbot
     [not found]     ` <5123100A.9050604-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2013-02-19  9:58       ` Wei Ni
2013-02-19 23:02   ` Stephen Warren
     [not found]     ` <51240497.8010909-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2013-02-20 10:29       ` Wei Ni
2013-02-18 11:30 ` Wei Ni [this message]
2013-02-19 23:48   ` [RFC PATCH 7/9] thermal: tegra30: add tegra30 thermal driver Stephen Warren
2013-02-20 12:23     ` Wei Ni
2013-02-19 23:56   ` Russell King - ARM Linux
     [not found]     ` <20130219235629.GU17833-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2013-02-20 12:29       ` Wei Ni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1361187031-3679-8-git-send-email-wni@nvidia.com \
    --to=wni@nvidia.com \
    --cc=MLongnecker@nvidia.com \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=durgadoss.r@intel.com \
    --cc=khali@linux-fr.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.orgrs.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=lm-sensors@lm-sensors.org \
    --cc=rui.zhang@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).