summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt (renamed from drivers/staging/ti-soc-thermal/ti_soc_thermal.txt)21
-rw-r--r--Documentation/thermal/x86_pkg_temperature_thermal47
-rw-r--r--MAINTAINERS5
-rw-r--r--arch/x86/include/asm/mce.h7
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c63
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/thermal/Kconfig15
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/armada_thermal.c3
-rw-r--r--drivers/thermal/cpu_cooling.c2
-rw-r--r--drivers/thermal/dove_thermal.c10
-rw-r--r--drivers/thermal/exynos_thermal.c3
-rw-r--r--drivers/thermal/kirkwood_thermal.c10
-rw-r--r--drivers/thermal/rcar_thermal.c10
-rw-r--r--drivers/thermal/spear_thermal.c20
-rw-r--r--drivers/thermal/thermal_core.c11
-rw-r--r--drivers/thermal/ti-soc-thermal/Kconfig (renamed from drivers/staging/ti-soc-thermal/Kconfig)12
-rw-r--r--drivers/thermal/ti-soc-thermal/Makefile (renamed from drivers/staging/ti-soc-thermal/Makefile)1
-rw-r--r--drivers/thermal/ti-soc-thermal/TODO (renamed from drivers/staging/ti-soc-thermal/TODO)0
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-bandgap.h280
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-thermal-data.c476
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap4-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap5-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.c)36
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.h (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.h)5
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c (renamed from drivers/staging/ti-soc-thermal/ti-thermal-common.c)15
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal.h (renamed from drivers/staging/ti-soc-thermal/ti-thermal.h)6
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c642
-rw-r--r--include/linux/cpu_cooling.h4
32 files changed, 1627 insertions, 83 deletions
diff --git a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
index 1629652372b6..0c9222d27fae 100644
--- a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
@@ -17,8 +17,9 @@ Required properties:
- interrupts : this entry should indicate which interrupt line
the talert signal is routed to;
Specific:
-- ti,tshut-gpio : this entry should be used to inform which GPIO
-line the tshut signal is routed to;
+- gpios : this entry should be used to inform which GPIO
+line the tshut signal is routed to. The informed GPIO will
+be treated as an IRQ;
- regs : this entry must also be specified and it is specific
to each bandgap version, because the mapping may change from
soc to soc, apart of depending on available features.
@@ -37,7 +38,7 @@ bandgap {
0x4a002378 0x18>;
compatible = "ti,omap4460-bandgap";
interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
+ gpios = <&gpio3 22 0>; /* tshut */
};
OMAP4470:
@@ -47,7 +48,7 @@ bandgap {
0x4a002378 0x18>;
compatible = "ti,omap4470-bandgap";
interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
+ gpios = <&gpio3 22 0>; /* tshut */
};
OMAP5430:
@@ -59,3 +60,15 @@ bandgap {
compatible = "ti,omap5430-bandgap";
interrupts = <0 126 4>; /* talert */
};
+
+DRA752:
+bandgap {
+ reg = <0x4a0021e0 0xc
+ 0x4a00232c 0xc
+ 0x4a002380 0x2c
+ 0x4a0023C0 0x3c
+ 0x4a002564 0x8
+ 0x4a002574 0x50>;
+ compatible = "ti,dra752-bandgap";
+ interrupts = <0 126 4>; /* talert */
+};
diff --git a/Documentation/thermal/x86_pkg_temperature_thermal b/Documentation/thermal/x86_pkg_temperature_thermal
new file mode 100644
index 000000000000..17a3a4c0a0ca
--- /dev/null
+++ b/Documentation/thermal/x86_pkg_temperature_thermal
@@ -0,0 +1,47 @@
+Kernel driver: x86_pkg_temp_thermal
+===================
+
+Supported chips:
+* x86: with package level thermal management
+(Verify using: CPUID.06H:EAX[bit 6] =1)
+
+Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+Reference
+---
+Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan, 2013):
+Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
+
+Description
+---------
+
+This driver register CPU digital temperature package level sensor as a thermal
+zone with maximum two user mode configurable trip points. Number of trip points
+depends on the capability of the package. Once the trip point is violated,
+user mode can receive notification via thermal notification mechanism and can
+take any action to control temperature.
+
+
+Threshold management
+--------------------
+Each package will register as a thermal zone under /sys/class/thermal.
+Example:
+/sys/class/thermal/thermal_zone1
+
+This contains two trip points:
+- trip_point_0_temp
+- trip_point_1_temp
+
+User can set any temperature between 0 to TJ-Max temperature. Temperature units
+are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.txt" for
+thermal sys-fs details.
+
+Any value other than 0 in these trip points, can trigger thermal notifications.
+Setting 0, stops sending thermal notifications.
+
+Thermal notifications: To get kobject-uevent notifications, set the thermal zone
+policy to "user_space". For example: echo -n "user_space" > policy
+
+
+
+
diff --git a/MAINTAINERS b/MAINTAINERS
index cbd4f66bc677..3a81b6d08833 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8159,6 +8159,7 @@ M: Zhang Rui <rui.zhang@intel.com>
M: Eduardo Valentin <eduardo.valentin@ti.com>
L: linux-pm@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
Q: https://patchwork.kernel.org/project/linux-pm/list/
S: Supported
F: drivers/thermal/
@@ -8183,8 +8184,8 @@ F: drivers/platform/x86/thinkpad_acpi.c
TI BANDGAP AND THERMAL DRIVER
M: Eduardo Valentin <eduardo.valentin@ti.com>
L: linux-pm@vger.kernel.org
-S: Maintained
-F: drivers/staging/omap-thermal/
+S: Supported
+F: drivers/thermal/ti-soc-thermal/
TI FLASH MEDIA INTERFACE DRIVER
M: Alex Dubov <oakad@yahoo.com>
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 6b52980c29c1..29e3093bbd21 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -214,6 +214,13 @@ void mce_log_therm_throt_event(__u64 status);
/* Interrupt Handler for core thermal thresholds */
extern int (*platform_thermal_notify)(__u64 msr_val);
+/* Interrupt Handler for package thermal thresholds */
+extern int (*platform_thermal_package_notify)(__u64 msr_val);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+extern bool (*platform_thermal_package_rate_control)(void);
+
#ifdef CONFIG_X86_THERMAL_VECTOR
extern void mcheck_intel_therm_init(void);
#else
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index 98f2083832eb..41e8e00a6637 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -55,12 +55,24 @@ struct thermal_state {
struct _thermal_state package_power_limit;
struct _thermal_state core_thresh0;
struct _thermal_state core_thresh1;
+ struct _thermal_state pkg_thresh0;
+ struct _thermal_state pkg_thresh1;
};
/* Callback to handle core threshold interrupts */
int (*platform_thermal_notify)(__u64 msr_val);
EXPORT_SYMBOL(platform_thermal_notify);
+/* Callback to handle core package threshold_interrupts */
+int (*platform_thermal_package_notify)(__u64 msr_val);
+EXPORT_SYMBOL_GPL(platform_thermal_package_notify);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+bool (*platform_thermal_package_rate_control)(void);
+EXPORT_SYMBOL_GPL(platform_thermal_package_rate_control);
+
+
static DEFINE_PER_CPU(struct thermal_state, thermal_state);
static atomic_t therm_throt_en = ATOMIC_INIT(0);
@@ -195,19 +207,25 @@ static int therm_throt_process(bool new_event, int event, int level)
return 0;
}
-static int thresh_event_valid(int event)
+static int thresh_event_valid(int level, int event)
{
struct _thermal_state *state;
unsigned int this_cpu = smp_processor_id();
struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
u64 now = get_jiffies_64();
- state = (event == 0) ? &pstate->core_thresh0 : &pstate->core_thresh1;
+ if (level == PACKAGE_LEVEL)
+ state = (event == 0) ? &pstate->pkg_thresh0 :
+ &pstate->pkg_thresh1;
+ else
+ state = (event == 0) ? &pstate->core_thresh0 :
+ &pstate->core_thresh1;
if (time_before64(now, state->next_check))
return 0;
state->next_check = now + CHECK_INTERVAL;
+
return 1;
}
@@ -322,6 +340,39 @@ device_initcall(thermal_throttle_init_device);
#endif /* CONFIG_SYSFS */
+static void notify_package_thresholds(__u64 msr_val)
+{
+ bool notify_thres_0 = false;
+ bool notify_thres_1 = false;
+
+ if (!platform_thermal_package_notify)
+ return;
+
+ /* lower threshold check */
+ if (msr_val & THERM_LOG_THRESHOLD0)
+ notify_thres_0 = true;
+ /* higher threshold check */
+ if (msr_val & THERM_LOG_THRESHOLD1)
+ notify_thres_1 = true;
+
+ if (!notify_thres_0 && !notify_thres_1)
+ return;
+
+ if (platform_thermal_package_rate_control &&
+ platform_thermal_package_rate_control()) {
+ /* Rate control is implemented in callback */
+ platform_thermal_package_notify(msr_val);
+ return;
+ }
+
+ /* lower threshold reached */
+ if (notify_thres_0 && thresh_event_valid(PACKAGE_LEVEL, 0))
+ platform_thermal_package_notify(msr_val);
+ /* higher threshold reached */
+ if (notify_thres_1 && thresh_event_valid(PACKAGE_LEVEL, 1))
+ platform_thermal_package_notify(msr_val);
+}
+
static void notify_thresholds(__u64 msr_val)
{
/* check whether the interrupt handler is defined;
@@ -331,10 +382,12 @@ static void notify_thresholds(__u64 msr_val)
return;
/* lower threshold reached */
- if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0))
+ if ((msr_val & THERM_LOG_THRESHOLD0) &&
+ thresh_event_valid(CORE_LEVEL, 0))
platform_thermal_notify(msr_val);
/* higher threshold reached */
- if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1))
+ if ((msr_val & THERM_LOG_THRESHOLD1) &&
+ thresh_event_valid(CORE_LEVEL, 1))
platform_thermal_notify(msr_val);
}
@@ -360,6 +413,8 @@ static void intel_thermal_interrupt(void)
if (this_cpu_has(X86_FEATURE_PTS)) {
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ /* check violations of package thermal thresholds */
+ notify_package_thresholds(msr_val);
therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
THERMAL_THROTTLING_EVENT,
PACKAGE_LEVEL);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index f64b662c74db..3227ebeae3f1 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -120,8 +120,6 @@ source "drivers/staging/gdm72xx/Kconfig"
source "drivers/staging/csr/Kconfig"
-source "drivers/staging/ti-soc-thermal/Kconfig"
-
source "drivers/staging/silicom/Kconfig"
source "drivers/staging/ced1401/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 1fb58a1562cb..4d79ebe2de06 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,7 +53,6 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_CSR_WIFI) += csr/
-obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5e3c02554d99..e988c81d763c 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -169,4 +169,19 @@ config INTEL_POWERCLAMP
enforce idle time which results in more package C-state residency. The
user interface is exposed via generic thermal framework.
+config X86_PKG_TEMP_THERMAL
+ tristate "X86 package temperature thermal driver"
+ depends on X86_THERMAL_VECTOR
+ select THERMAL_GOV_USER_SPACE
+ default m
+ help
+ Enable this to register CPU digital sensor for package temperature as
+ thermal zone. Each package will have its own thermal zone. There are
+ two trip points which can be set by user to get notifications via thermal
+ notification methods.
+
+menu "Texas Instruments thermal drivers"
+source "drivers/thermal/ti-soc-thermal/Kconfig"
+endmenu
+
endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c054d410ac3f..67184a293e3f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -23,4 +23,5 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
-
+obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
+obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 54ffd64ca3f7..5e53212b984f 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -200,7 +200,6 @@ static int armada_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(armada_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -211,7 +210,7 @@ static struct platform_driver armada_thermal_driver = {
.driver = {
.name = "armada_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(armada_thermal_id_table),
+ .of_match_table = armada_thermal_id_table,
},
};
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index c94bf2e5de62..82e15dbb3ac7 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -167,7 +167,7 @@ static int get_property(unsigned int cpu, unsigned long input,
continue;
/* get the frequency order */
- if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
+ if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
descend = !!(freq > table[i].frequency);
freq = table[i].frequency;
diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
index a088d1365ca5..828f5e345c30 100644
--- a/drivers/thermal/dove_thermal.c
+++ b/drivers/thermal/dove_thermal.c
@@ -134,16 +134,11 @@ static int dove_thermal_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
@@ -178,7 +173,6 @@ static int dove_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(dove_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -191,7 +185,7 @@ static struct platform_driver dove_thermal_driver = {
.driver = {
.name = "dove_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(dove_thermal_id_table),
+ .of_match_table = dove_thermal_id_table,
},
};
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 4cbe3eea6deb..9af4b93c9f86 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -997,7 +997,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
return 0;
err_clk:
- platform_set_drvdata(pdev, NULL);
clk_unprepare(data->clk);
return ret;
}
@@ -1012,8 +1011,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
clk_unprepare(data->clk);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c
index dfeceaffbc03..3b034a0dfc94 100644
--- a/drivers/thermal/kirkwood_thermal.c
+++ b/drivers/thermal/kirkwood_thermal.c
@@ -75,16 +75,11 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
struct kirkwood_thermal_priv *priv;
struct resource *res;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
@@ -108,7 +103,6 @@ static int kirkwood_thermal_exit(struct platform_device *pdev)
platform_get_drvdata(pdev);
thermal_zone_device_unregister(kirkwood_thermal);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -121,7 +115,7 @@ static struct platform_driver kirkwood_thermal_driver = {
.driver = {
.name = "kirkwood_thermal",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(kirkwood_thermal_id_table),
+ .of_match_table = kirkwood_thermal_id_table,
},
};
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 8d7edd4c8228..88f92e1a9944 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -389,11 +389,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
* platform has IRQ support.
* Then, drier use common register
*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
- if (!res) {
- dev_err(dev, "Could not get platform resource\n");
- return -ENODEV;
- }
ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
dev_name(dev), common);
@@ -405,6 +400,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
/*
* rcar_has_irq_support() will be enabled
*/
+ res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
common->base = devm_ioremap_resource(dev, res);
if (IS_ERR(common->base))
return PTR_ERR(common->base);
@@ -458,7 +454,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, common);
- dev_info(dev, "%d sensor proved\n", i);
+ dev_info(dev, "%d sensor probed\n", i);
return 0;
@@ -487,8 +483,6 @@ static int rcar_thermal_remove(struct platform_device *pdev)
rcar_thermal_irq_disable(priv);
}
- platform_set_drvdata(pdev, NULL);
-
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index 3c5ee5607977..ab79ea4701d9 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -104,7 +104,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
struct thermal_zone_device *spear_thermal = NULL;
struct spear_thermal_dev *stdev;
struct device_node *np = pdev->dev.of_node;
- struct resource *stres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *res;
int ret = 0, val;
if (!np || !of_property_read_u32(np, "st,thermal-flags", &val)) {
@@ -112,11 +112,6 @@ static int spear_thermal_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!stres) {
- dev_err(&pdev->dev, "memory resource missing\n");
- return -ENODEV;
- }
-
stdev = devm_kzalloc(&pdev->dev, sizeof(*stdev), GFP_KERNEL);
if (!stdev) {
dev_err(&pdev->dev, "kzalloc fail\n");
@@ -124,12 +119,10 @@ static int spear_thermal_probe(struct platform_device *pdev)
}
/* Enable thermal sensor */
- stdev->thermal_base = devm_ioremap(&pdev->dev, stres->start,
- resource_size(stres));
- if (!stdev->thermal_base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ stdev->thermal_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(stdev->thermal_base))
+ return PTR_ERR(stdev->thermal_base);
stdev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(stdev->clk)) {
@@ -174,7 +167,6 @@ static int spear_thermal_exit(struct platform_device *pdev)
struct spear_thermal_dev *stdev = spear_thermal->devdata;
thermal_zone_device_unregister(spear_thermal);
- platform_set_drvdata(pdev, NULL);
/* Disable SPEAr Thermal Sensor */
actual_mask = readl_relaxed(stdev->thermal_base);
@@ -198,7 +190,7 @@ static struct platform_driver spear_thermal_driver = {
.name = "spear_thermal",
.owner = THIS_MODULE,
.pm = &spear_thermal_pm_ops,
- .of_match_table = of_match_ptr(spear_thermal_id_table),
+ .of_match_table = spear_thermal_id_table,
},
};
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index d755440791b7..1f02e8edb45c 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -33,6 +33,7 @@
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/reboot.h>
+#include <linux/string.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -155,7 +156,8 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip)
{
enum thermal_trend trend;
- if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+ if (tz->emul_temperature || !tz->ops->get_trend ||
+ tz->ops->get_trend(tz, trip, &trend)) {
if (tz->temperature > tz->last_temperature)
trend = THERMAL_TREND_RAISING;
else if (tz->temperature < tz->last_temperature)
@@ -713,10 +715,13 @@ policy_store(struct device *dev, struct device_attribute *attr,
int ret = -EINVAL;
struct thermal_zone_device *tz = to_thermal_zone(dev);
struct thermal_governor *gov;
+ char name[THERMAL_NAME_LENGTH];
+
+ snprintf(name, sizeof(name), "%s", buf);
mutex_lock(&thermal_governor_lock);
- gov = __find_governor(buf);
+ gov = __find_governor(strim(name));
if (!gov)
goto exit;
@@ -1624,7 +1629,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
if (!ops || !ops->get_temp)
return ERR_PTR(-EINVAL);
- if (trips > 0 && !ops->get_trip_type)
+ if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
return ERR_PTR(-EINVAL);
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
diff --git a/drivers/staging/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
index e81375fb2155..bd4c7beba679 100644
--- a/drivers/staging/ti-soc-thermal/Kconfig
+++ b/drivers/thermal/ti-soc-thermal/Kconfig
@@ -46,3 +46,15 @@ config OMAP5_THERMAL
This includes alert interrupts generation and also the TSHUT
support.
+
+config DRA752_THERMAL
+ bool "Texas Instruments DRA752 thermal support"
+ depends on TI_SOC_THERMAL
+ depends on SOC_DRA7XX
+ help
+ If you say yes here you get thermal support for the Texas Instruments
+ DRA752 SoC family. The current chip supported are:
+ - DRA752
+
+ This includes alert interrupts generation and also the TSHUT
+ support.
diff --git a/drivers/staging/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile
index 0ca034fb419d..1226b2484e55 100644
--- a/drivers/staging/ti-soc-thermal/Makefile
+++ b/drivers/thermal/ti-soc-thermal/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o
ti-soc-thermal-y := ti-bandgap.o
ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o
+ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/staging/ti-soc-thermal/TODO b/drivers/thermal/ti-soc-thermal/TODO
index 7da787d19241..7da787d19241 100644
--- a/drivers/staging/ti-soc-thermal/TODO
+++ b/drivers/thermal/ti-soc-thermal/TODO
diff --git a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
new file mode 100644
index 000000000000..6b0f2b1160f7
--- /dev/null
+++ b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h
@@ -0,0 +1,280 @@
+/*
+ * DRA752 bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This is an auto generated file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef __DRA752_BANDGAP_H
+#define __DRA752_BANDGAP_H
+
+/**
+ * *** DRA752 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for DRA752.
+ */
+
+/**
+ * DRA752 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP_GPU on DRA752.
+ * DRA752_BANDGAP_BASE 0x4a0021e0
+ *
+ * Register below are grouped by domain (not necessarily in offset order)
+ */
+
+
+/* DRA752.common register offsets */
+#define DRA752_BANDGAP_CTRL_1_OFFSET 0x1a0
+#define DRA752_BANDGAP_STATUS_1_OFFSET 0x1c8
+#define DRA752_BANDGAP_CTRL_2_OFFSET 0x39c
+#define DRA752_BANDGAP_STATUS_2_OFFSET 0x3b8
+
+/* DRA752.core register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET 0x8
+#define DRA752_TEMP_SENSOR_CORE_OFFSET 0x154
+#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
+#define DRA752_BANDGAP_TSHUT_CORE_OFFSET 0x1b8
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
+#define DRA752_DTEMP_CORE_0_OFFSET 0x208
+#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
+#define DRA752_DTEMP_CORE_2_OFFSET 0x210
+#define DRA752_DTEMP_CORE_3_OFFSET 0x214
+#define DRA752_DTEMP_CORE_4_OFFSET 0x218
+
+/* DRA752.iva register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
+#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
+#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
+#define DRA752_BANDGAP_TSHUT_IVA_OFFSET 0x3ac
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
+#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
+#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
+#define DRA752_DTEMP_IVA_2_OFFSET 0x3d8
+#define DRA752_DTEMP_IVA_3_OFFSET 0x3dc
+#define DRA752_DTEMP_IVA_4_OFFSET 0x3e0
+
+/* DRA752.mpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
+#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
+#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
+#define DRA752_BANDGAP_TSHUT_MPU_OFFSET 0x1b0
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
+#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
+#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
+#define DRA752_DTEMP_MPU_2_OFFSET 0x1e8
+#define DRA752_DTEMP_MPU_3_OFFSET 0x1ec
+#define DRA752_DTEMP_MPU_4_OFFSET 0x1f0
+
+/* DRA752.dspeve register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
+#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
+#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
+#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET 0x3a8
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
+#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
+#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
+#define DRA752_DTEMP_DSPEVE_2_OFFSET 0x3c4
+#define DRA752_DTEMP_DSPEVE_3_OFFSET 0x3c8
+#define DRA752_DTEMP_DSPEVE_4_OFFSET 0x3cc
+
+/* DRA752.gpu register offsets */
+#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
+#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
+#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
+#define DRA752_BANDGAP_TSHUT_GPU_OFFSET 0x1b4
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
+#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
+#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
+#define DRA752_DTEMP_GPU_2_OFFSET 0x1fc
+#define DRA752_DTEMP_GPU_3_OFFSET 0x200
+#define DRA752_DTEMP_GPU_4_OFFSET 0x204
+
+/**
+ * Register bitfields for DRA752
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on DRA752. Bit defines are
+ * grouped by register.
+ */
+
+/* DRA752.BANDGAP_STATUS_1 */
+#define DRA752_BANDGAP_STATUS_1_ALERT_MASK BIT(31)
+#define DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK BIT(5)
+#define DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK BIT(4)
+#define DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK BIT(3)
+#define DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK BIT(2)
+#define DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK BIT(1)
+#define DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK BIT(0)
+
+/* DRA752.BANDGAP_CTRL_2 */
+#define DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK BIT(22)
+#define DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK BIT(21)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK BIT(19)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK BIT(18)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK BIT(16)
+#define DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK BIT(15)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK BIT(3)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK BIT(2)
+#define DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK BIT(1)
+#define DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK BIT(0)
+
+/* DRA752.BANDGAP_STATUS_2 */
+#define DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK BIT(3)
+#define DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK BIT(2)
+#define DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK BIT(1)
+#define DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK BIT(0)
+
+/* DRA752.BANDGAP_CTRL_1 */
+#define DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK (0x3 << 30)
+#define DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK (0x7 << 27)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK BIT(23)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK BIT(22)
+#define DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK BIT(21)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK BIT(20)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK BIT(19)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK BIT(18)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK BIT(17)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK BIT(16)
+#define DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK BIT(15)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK BIT(5)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK BIT(4)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK BIT(3)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK BIT(2)
+#define DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK BIT(1)
+#define DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK BIT(0)
+
+/* DRA752.TEMP_SENSOR */
+#define DRA752_TEMP_SENSOR_TMPSOFF_MASK BIT(11)
+#define DRA752_TEMP_SENSOR_EOCZ_MASK BIT(10)
+#define DRA752_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* DRA752.BANDGAP_THRESHOLD */
+#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
+#define DRA752_BANDGAP_THRESHOLD_COLD_MASK (0x3ff << 0)
+
+/* DRA752.TSHUT_THRESHOLD */
+#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK BIT(31)
+#define DRA752_TSHUT_THRESHOLD_HOT_MASK (0x3ff << 16)
+#define DRA752_TSHUT_THRESHOLD_COLD_MASK (0x3ff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_IVA */
+#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_MPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_DSPEVE */
+#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_MASK (0xffffffff << 0)
+
+/* DRA752.BANDGAP_CUMUL_DTEMP_GPU */
+#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_MASK (0xffffffff << 0)
+
+/**
+ * Temperature limits and thresholds for DRA752
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for DRA752. Definitions are grouped
+ * by temperature domain.
+ */
+
+/* DRA752.common temperature definitions */
+/* ADC conversion table limits */
+#define DRA752_ADC_START_VALUE 540
+#define DRA752_ADC_END_VALUE 945
+
+/* DRA752.GPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_GPU_MAX_FREQ 1500000
+#define DRA752_GPU_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_GPU_MIN_TEMP -40000
+#define DRA752_GPU_MAX_TEMP 125000
+#define DRA752_GPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_GPU_TSHUT_HOT 915
+#define DRA752_GPU_TSHUT_COLD 900
+#define DRA752_GPU_T_HOT 800
+#define DRA752_GPU_T_COLD 795
+
+/* DRA752.MPU temperature definitions */
+/* bandgap clock limits */
+#define DRA752_MPU_MAX_FREQ 1500000
+#define DRA752_MPU_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_MPU_MIN_TEMP -40000
+#define DRA752_MPU_MAX_TEMP 125000
+#define DRA752_MPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_MPU_TSHUT_HOT 915
+#define DRA752_MPU_TSHUT_COLD 900
+#define DRA752_MPU_T_HOT 800
+#define DRA752_MPU_T_COLD 795
+
+/* DRA752.CORE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_CORE_MAX_FREQ 1500000
+#define DRA752_CORE_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_CORE_MIN_TEMP -40000
+#define DRA752_CORE_MAX_TEMP 125000
+#define DRA752_CORE_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_CORE_TSHUT_HOT 915
+#define DRA752_CORE_TSHUT_COLD 900
+#define DRA752_CORE_T_HOT 800
+#define DRA752_CORE_T_COLD 795
+
+/* DRA752.DSPEVE temperature definitions */
+/* bandgap clock limits */
+#define DRA752_DSPEVE_MAX_FREQ 1500000
+#define DRA752_DSPEVE_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_DSPEVE_MIN_TEMP -40000
+#define DRA752_DSPEVE_MAX_TEMP 125000
+#define DRA752_DSPEVE_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_DSPEVE_TSHUT_HOT 915
+#define DRA752_DSPEVE_TSHUT_COLD 900
+#define DRA752_DSPEVE_T_HOT 800
+#define DRA752_DSPEVE_T_COLD 795
+
+/* DRA752.IVA temperature definitions */
+/* bandgap clock limits */
+#define DRA752_IVA_MAX_FREQ 1500000
+#define DRA752_IVA_MIN_FREQ 1000000
+/* sensor limits */
+#define DRA752_IVA_MIN_TEMP -40000
+#define DRA752_IVA_MAX_TEMP 125000
+#define DRA752_IVA_HYST_VAL 5000
+/* interrupts thresholds */
+#define DRA752_IVA_TSHUT_HOT 915
+#define DRA752_IVA_TSHUT_COLD 900
+#define DRA752_IVA_T_HOT 800
+#define DRA752_IVA_T_COLD 795
+
+#endif /* __DRA752_BANDGAP_H */
diff --git a/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
new file mode 100644
index 000000000000..e5d8326a54d6
--- /dev/null
+++ b/drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
@@ -0,0 +1,476 @@
+/*
+ * DRA752 thermal data.
+ *
+ * Copyright (C) 2013 Texas Instruments Inc.
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@ti.com>
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This file is partially autogenerated.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+#include "dra752-bandgap.h"
+
+/*
+ * DRA752 has five instances of thermal sensor: MPU, GPU, CORE,
+ * IVA and DSPEVE need to describe the individual registers and
+ * bit fields.
+ */
+
+/*
+ * DRA752 CORE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_core_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_CORE_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_CORE_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_CORE_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_CORE_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_CORE_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_CORE_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_CORE_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET,
+};
+
+/*
+ * DRA752 IVA thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_iva_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_IVA_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_IVA_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_IVA_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_IVA_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_IVA_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_IVA_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_IVA_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET,
+};
+
+/*
+ * DRA752 MPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_mpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_MPU_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_MPU_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_MPU_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_MPU_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_MPU_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_MPU_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_MPU_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET,
+};
+
+/*
+ * DRA752 DSPEVE thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_dspeve_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_DSPEVE_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_2_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_2_COLD_DSPEVE_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_DSPEVE_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_DSPEVE_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_DSPEVE_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_DSPEVE_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_DSPEVE_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET,
+};
+
+/*
+ * DRA752 GPU thermal sensor register offsets and bit-fields
+ */
+static struct temp_sensor_registers
+dra752_gpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = DRA752_TEMP_SENSOR_GPU_OFFSET,
+ .bgap_tempsoff_mask = DRA752_TEMP_SENSOR_TMPSOFF_MASK,
+ .bgap_eocz_mask = DRA752_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = DRA752_TEMP_SENSOR_DTEMP_MASK,
+ .bgap_mask_ctrl = DRA752_BANDGAP_CTRL_1_OFFSET,
+ .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK,
+ .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK,
+ .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+ .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK,
+ .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK,
+ .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK,
+ .bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
+ .threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
+ .threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
+ .tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
+ .tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
+ .tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
+ .bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
+ .status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
+ .status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
+ .status_cold_mask = DRA752_BANDGAP_STATUS_1_COLD_GPU_MASK,
+ .bgap_cumul_dtemp = DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET,
+ .ctrl_dtemp_0 = DRA752_DTEMP_GPU_0_OFFSET,
+ .ctrl_dtemp_1 = DRA752_DTEMP_GPU_1_OFFSET,
+ .ctrl_dtemp_2 = DRA752_DTEMP_GPU_2_OFFSET,
+ .ctrl_dtemp_3 = DRA752_DTEMP_GPU_3_OFFSET,
+ .ctrl_dtemp_4 = DRA752_DTEMP_GPU_4_OFFSET,
+ .bgap_efuse = DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET,
+};
+
+/* Thresholds and limits for DRA752 MPU temperature sensor */
+static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
+ .tshut_hot = DRA752_MPU_TSHUT_HOT,
+ .tshut_cold = DRA752_MPU_TSHUT_COLD,
+ .t_hot = DRA752_MPU_T_HOT,
+ .t_cold = DRA752_MPU_T_COLD,
+ .min_freq = DRA752_MPU_MIN_FREQ,
+ .max_freq = DRA752_MPU_MAX_FREQ,
+ .max_temp = DRA752_MPU_MAX_TEMP,
+ .min_temp = DRA752_MPU_MIN_TEMP,
+ .hyst_val = DRA752_MPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 GPU temperature sensor */
+static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
+ .tshut_hot = DRA752_GPU_TSHUT_HOT,
+ .tshut_cold = DRA752_GPU_TSHUT_COLD,
+ .t_hot = DRA752_GPU_T_HOT,
+ .t_cold = DRA752_GPU_T_COLD,
+ .min_freq = DRA752_GPU_MIN_FREQ,
+ .max_freq = DRA752_GPU_MAX_FREQ,
+ .max_temp = DRA752_GPU_MAX_TEMP,
+ .min_temp = DRA752_GPU_MIN_TEMP,
+ .hyst_val = DRA752_GPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 CORE temperature sensor */
+static struct temp_sensor_data dra752_core_temp_sensor_data = {
+ .tshut_hot = DRA752_CORE_TSHUT_HOT,
+ .tshut_cold = DRA752_CORE_TSHUT_COLD,
+ .t_hot = DRA752_CORE_T_HOT,
+ .t_cold = DRA752_CORE_T_COLD,
+ .min_freq = DRA752_CORE_MIN_FREQ,
+ .max_freq = DRA752_CORE_MAX_FREQ,
+ .max_temp = DRA752_CORE_MAX_TEMP,
+ .min_temp = DRA752_CORE_MIN_TEMP,
+ .hyst_val = DRA752_CORE_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
+static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
+ .tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
+ .tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
+ .t_hot = DRA752_DSPEVE_T_HOT,
+ .t_cold = DRA752_DSPEVE_T_COLD,
+ .min_freq = DRA752_DSPEVE_MIN_FREQ,
+ .max_freq = DRA752_DSPEVE_MAX_FREQ,
+ .max_temp = DRA752_DSPEVE_MAX_TEMP,
+ .min_temp = DRA752_DSPEVE_MIN_TEMP,
+ .hyst_val = DRA752_DSPEVE_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for DRA752 IVA temperature sensor */
+static struct temp_sensor_data dra752_iva_temp_sensor_data = {
+ .tshut_hot = DRA752_IVA_TSHUT_HOT,
+ .tshut_cold = DRA752_IVA_TSHUT_COLD,
+ .t_hot = DRA752_IVA_T_HOT,
+ .t_cold = DRA752_IVA_T_COLD,
+ .min_freq = DRA752_IVA_MIN_FREQ,
+ .max_freq = DRA752_IVA_MAX_FREQ,
+ .max_temp = DRA752_IVA_MAX_TEMP,
+ .min_temp = DRA752_IVA_MIN_TEMP,
+ .hyst_val = DRA752_IVA_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/*
+ * DRA752 : Temperature values in milli degree celsius
+ * ADC code values from 540 to 945
+ */
+static
+int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
+ /* Index 540 - 549 */
+ -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
+ -37800,
+ /* Index 550 - 559 */
+ -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
+ -33400,
+ /* Index 560 - 569 */
+ -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
+ -29400,
+ /* Index 570 - 579 */
+ -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
+ -25000,
+ /* Index 580 - 589 */
+ -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21800, -21400,
+ -21000,
+ /* Index 590 - 599 */
+ -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
+ -16600,
+ /* Index 600 - 609 */
+ -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
+ -12500,
+ /* Index 610 - 619 */
+ -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
+ -8200,
+ /* Index 620 - 629 */
+ -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500,
+ -3900,
+ /* Index 630 - 639 */
+ -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200,
+ 200,
+ /* Index 640 - 649 */
+ 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900,
+ 4500,
+ /* Index 650 - 659 */
+ 5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200,
+ 8600,
+ /* Index 660 - 669 */
+ 9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200,
+ 12700,
+ /* Index 670 - 679 */
+ 13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600,
+ 17000,
+ /* Index 680 - 689 */
+ 17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600,
+ 21000,
+ /* Index 690 - 699 */
+ 21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000,
+ 25400,
+ /* Index 700 - 709 */
+ 25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000,
+ 29400,
+ /* Index 710 - 719 */
+ 29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400,
+ 33800,
+ /* Index 720 - 729 */
+ 34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400,
+ 37800,
+ /* Index 730 - 739 */
+ 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400,
+ 41800,
+ /* Index 740 - 749 */
+ 42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800,
+ 46200,
+ /* Index 750 - 759 */
+ 46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800,
+ 50200,
+ /* Index 760 - 769 */
+ 50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800,
+ 54200,
+ /* Index 770 - 779 */
+ 54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200,
+ 58600,
+ /* Index 780 - 789 */
+ 59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200,
+ 62600,
+ /* Index 790 - 799 */
+ 63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200,
+ 66600,
+ /* Index 800 - 809 */
+ 67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200,
+ 70600,
+ /* Index 810 - 819 */
+ 71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600,
+ 75000,
+ /* Index 820 - 829 */
+ 75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600,
+ 79000,
+ /* Index 830 - 839 */
+ 79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600,
+ 83000,
+ /* Index 840 - 849 */
+ 83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600,
+ 87000,
+ /* Index 850 - 859 */
+ 87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600,
+ 91000,
+ /* Index 860 - 869 */
+ 91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600,
+ 95000,
+ /* Index 870 - 879 */
+ 95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000,
+ 99400,
+ /* Index 880 - 889 */
+ 99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
+ 103400,
+ /* Index 890 - 899 */
+ 103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
+ 107400,
+ /* Index 900 - 909 */
+ 107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
+ 111400,
+ /* Index 910 - 919 */
+ 111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
+ 115400,
+ /* Index 920 - 929 */
+ 115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
+ 119400,
+ /* Index 930 - 939 */
+ 119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
+ 123400,
+ /* Index 940 - 945 */
+ 123800, 124200, 124600, 124900, 125000, 125000,
+};
+
+/* DRA752 data */
+const struct ti_bandgap_data dra752_data = {
+ .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+ TI_BANDGAP_FEATURE_FREEZE_BIT |
+ TI_BANDGAP_FEATURE_TALERT |
+ TI_BANDGAP_FEATURE_COUNTER_DELAY |
+ TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+ .fclock_name = "l3instr_ts_gclk_div",
+ .div_ck_name = "l3instr_ts_gclk_div",
+ .conv_table = dra752_adc_to_temp,
+ .adc_start_val = DRA752_ADC_START_VALUE,
+ .adc_end_val = DRA752_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+ .sensors = {
+ {
+ .registers = &dra752_mpu_temp_sensor_registers,
+ .ts_data = &dra752_mpu_temp_sensor_data,
+ .domain = "cpu",
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_gpu_temp_sensor_registers,
+ .ts_data = &dra752_gpu_temp_sensor_data,
+ .domain = "gpu",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_core_temp_sensor_registers,
+ .ts_data = &dra752_core_temp_sensor_data,
+ .domain = "core",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_dspeve_temp_sensor_registers,
+ .ts_data = &dra752_dspeve_temp_sensor_data,
+ .domain = "dspeve",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ {
+ .registers = &dra752_iva_temp_sensor_registers,
+ .ts_data = &dra752_iva_temp_sensor_data,
+ .domain = "iva",
+ .slope = DRA752_GRADIENT_SLOPE,
+ .constant = DRA752_GRADIENT_CONST,
+ .slope_pcb = DRA752_GRADIENT_SLOPE_W_PCB,
+ .constant_pcb = DRA752_GRADIENT_CONST_W_PCB,
+ },
+ },
+ .sensor_count = 5,
+};
diff --git a/drivers/staging/ti-soc-thermal/omap4-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
index d255d33da9eb..d255d33da9eb 100644
--- a/drivers/staging/ti-soc-thermal/omap4-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/omap4-thermal-data.c
diff --git a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
index 6f2de3a3356d..6f2de3a3356d 100644
--- a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h
diff --git a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
index eff0c80fd4af..eff0c80fd4af 100644
--- a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c
+++ b/drivers/thermal/ti-soc-thermal/omap5-thermal-data.c
diff --git a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
index 400b55dffadd..400b55dffadd 100644
--- a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
index f20c1cfe9800..9dfd47196e63 100644
--- a/drivers/staging/ti-soc-thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
@@ -38,6 +38,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
#include <linux/io.h>
#include "ti-bandgap.h"
@@ -469,7 +470,7 @@ static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
{
int ret = 0;
- if (IS_ERR_OR_NULL(bgp)) {
+ if (!bgp || IS_ERR(bgp)) {
pr_err("%s: invalid bandgap pointer\n", __func__);
ret = -EINVAL;
goto exit;
@@ -992,9 +993,12 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
goto exit;
}
+ spin_lock(&bgp->lock);
+
tsr = bgp->conf->sensors[id].registers;
/* Freeze and read the last 2 valid readings */
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
reg1 = tsr->ctrl_dtemp_1;
reg2 = tsr->ctrl_dtemp_2;
@@ -1008,22 +1012,25 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
/* Convert from adc values to mCelsius temperature */
ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
if (ret)
- goto exit;
+ goto unfreeze;
ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
if (ret)
- goto exit;
+ goto unfreeze;
/* Fetch the update interval */
ret = ti_bandgap_read_update_interval(bgp, id, &interval);
if (ret || !interval)
- goto exit;
+ goto unfreeze;
*trend = (t1 - t2) / interval;
dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
t1, t2, *trend);
+unfreeze:
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
+ spin_unlock(&bgp->lock);
exit:
return ret;
}
@@ -1123,7 +1130,6 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
const struct of_device_id *of_id;
struct ti_bandgap *bgp;
struct resource *res;
- u32 prop;
int i;
/* just for the sake */
@@ -1167,11 +1173,7 @@ static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
} while (res);
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
- if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
- dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
- return ERR_PTR(-EINVAL);
- }
- bgp->tshut_gpio = prop;
+ bgp->tshut_gpio = of_get_gpio(node, 0);
if (!gpio_is_valid(bgp->tshut_gpio)) {
dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
bgp->tshut_gpio);
@@ -1191,7 +1193,7 @@ int ti_bandgap_probe(struct platform_device *pdev)
int clk_rate, ret = 0, i;
bgp = ti_bandgap_build(pdev);
- if (IS_ERR_OR_NULL(bgp)) {
+ if (IS_ERR(bgp)) {
dev_err(&pdev->dev, "failed to fetch platform data\n");
return PTR_ERR(bgp);
}
@@ -1207,17 +1209,19 @@ int ti_bandgap_probe(struct platform_device *pdev)
}
bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
- ret = IS_ERR_OR_NULL(bgp->fclock);
+ ret = IS_ERR(bgp->fclock);
if (ret) {
dev_err(&pdev->dev, "failed to request fclock reference\n");
+ ret = PTR_ERR(bgp->fclock);
goto free_irqs;
}
bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);
- ret = IS_ERR_OR_NULL(bgp->div_clk);
+ ret = IS_ERR(bgp->div_clk);
if (ret) {
dev_err(&pdev->dev,
"failed to request div_ts_ck clock ref\n");
+ ret = PTR_ERR(bgp->div_clk);
goto free_irqs;
}
@@ -1523,6 +1527,12 @@ static const struct of_device_id of_ti_bandgap_match[] = {
.data = (void *)&omap5430_data,
},
#endif
+#ifdef CONFIG_DRA752_THERMAL
+ {
+ .compatible = "ti,dra752-bandgap",
+ .data = (void *)&dra752_data,
+ },
+#endif
/* Sentinel */
{ },
};
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
index 5f4794abf583..b3adf72f252d 100644
--- a/drivers/staging/ti-soc-thermal/ti-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
@@ -400,4 +400,9 @@ extern const struct ti_bandgap_data omap5430_data;
#define omap5430_data NULL
#endif
+#ifdef CONFIG_DRA752_THERMAL
+extern const struct ti_bandgap_data dra752_data;
+#else
+#define dra752_data NULL
+#endif
#endif
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 8e67ebf98404..4c5f55c37349 100644
--- a/drivers/staging/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -101,7 +101,7 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
pcb_tz = data->pcb_tz;
/* In case pcb zone is available, use the extrapolation rule with it */
- if (!IS_ERR_OR_NULL(pcb_tz)) {
+ if (!IS_ERR(pcb_tz)) {
ret = thermal_zone_get_temp(pcb_tz, &pcb_temp);
if (!ret) {
tmp -= pcb_temp; /* got a valid PCB temp */
@@ -124,7 +124,7 @@ static int ti_thermal_bind(struct thermal_zone_device *thermal,
struct ti_thermal_data *data = thermal->devdata;
int id;
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
return -ENODEV;
/* check if this is the cooling device we registered */
@@ -146,7 +146,7 @@ static int ti_thermal_unbind(struct thermal_zone_device *thermal,
{
struct ti_thermal_data *data = thermal->devdata;
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
return -ENODEV;
/* check if this is the cooling device we registered */
@@ -282,6 +282,7 @@ static struct ti_thermal_data
data->sensor_id = id;
data->bgp = bgp;
data->mode = THERMAL_DEVICE_ENABLED;
+ /* pcb_tz will be either valid or PTR_ERR() */
data->pcb_tz = thermal_zone_get_zone_by_name("pcb");
INIT_WORK(&data->thermal_wq, ti_thermal_work);
@@ -295,7 +296,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
data = ti_bandgap_get_sensor_data(bgp, id);
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
data = ti_thermal_build_data(bgp, id);
if (!data)
@@ -306,7 +307,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
NULL, FAST_TEMP_MONITORING_RATE,
FAST_TEMP_MONITORING_RATE);
- if (IS_ERR_OR_NULL(data->ti_thermal)) {
+ if (IS_ERR(data->ti_thermal)) {
dev_err(bgp->dev, "thermal zone device is NULL\n");
return PTR_ERR(data->ti_thermal);
}
@@ -343,7 +344,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
struct ti_thermal_data *data;
data = ti_bandgap_get_sensor_data(bgp, id);
- if (IS_ERR_OR_NULL(data))
+ if (!data || IS_ERR(data))
data = ti_thermal_build_data(bgp, id);
if (!data)
@@ -356,7 +357,7 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
/* Register cooling device */
data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
- if (IS_ERR_OR_NULL(data->cool_dev)) {
+ if (IS_ERR(data->cool_dev)) {
dev_err(bgp->dev,
"Failed to register cpufreq cooling device\n");
return PTR_ERR(data->cool_dev);
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal.h b/drivers/thermal/ti-soc-thermal/ti-thermal.h
index 5055777727cc..f8b7ffea6194 100644
--- a/drivers/staging/ti-soc-thermal/ti-thermal.h
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal.h
@@ -38,6 +38,9 @@
#define OMAP_GRADIENT_SLOPE_5430_GPU 117
#define OMAP_GRADIENT_CONST_5430_GPU -2992
+#define DRA752_GRADIENT_SLOPE 0
+#define DRA752_GRADIENT_CONST 2000
+
/* PCB sensor calculation constants */
#define OMAP_GRADIENT_SLOPE_W_PCB_4430 0
#define OMAP_GRADIENT_CONST_W_PCB_4430 20000
@@ -51,6 +54,9 @@
#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 464
#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU -5102
+#define DRA752_GRADIENT_SLOPE_W_PCB 0
+#define DRA752_GRADIENT_CONST_W_PCB 2000
+
/* trip points of interest in milicelsius (at hotspot level) */
#define OMAP_TRIP_COLD 100000
#define OMAP_TRIP_HOT 110000
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
new file mode 100644
index 000000000000..5de56f671a9d
--- /dev/null
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -0,0 +1,642 @@
+/*
+ * x86_pkg_temp_thermal driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * 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, write to the Free Software Foundation, Inc.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/thermal.h>
+#include <linux/debugfs.h>
+#include <asm/cpu_device_id.h>
+#include <asm/mce.h>
+
+/*
+* Rate control delay: Idea is to introduce denounce effect
+* This should be long enough to avoid reduce events, when
+* threshold is set to a temperature, which is constantly
+* violated, but at the short enough to take any action.
+* The action can be remove threshold or change it to next
+* interesting setting. Based on experiments, in around
+* every 5 seconds under load will give us a significant
+* temperature change.
+*/
+#define PKG_TEMP_THERMAL_NOTIFY_DELAY 5000
+static int notify_delay_ms = PKG_TEMP_THERMAL_NOTIFY_DELAY;
+module_param(notify_delay_ms, int, 0644);
+MODULE_PARM_DESC(notify_delay_ms,
+ "User space notification delay in milli seconds.");
+
+/* Number of trip points in thermal zone. Currently it can't
+* be more than 2. MSR can allow setting and getting notifications
+* for only 2 thresholds. This define enforces this, if there
+* is some wrong values returned by cpuid for number of thresholds.
+*/
+#define MAX_NUMBER_OF_TRIPS 2
+
+struct phy_dev_entry {
+ struct list_head list;
+ u16 phys_proc_id;
+ u16 first_cpu;
+ u32 tj_max;
+ int ref_cnt;
+ u32 start_pkg_therm_low;
+ u32 start_pkg_therm_high;
+ struct thermal_zone_device *tzone;
+};
+
+/* List maintaining number of package instances */
+static LIST_HEAD(phy_dev_list);
+static DEFINE_MUTEX(phy_dev_list_mutex);
+
+/* Interrupt to work function schedule queue */
+static DEFINE_PER_CPU(struct delayed_work, pkg_temp_thermal_threshold_work);
+
+/* To track if the work is already scheduled on a package */
+static u8 *pkg_work_scheduled;
+
+/* Spin lock to prevent races with pkg_work_scheduled */
+static spinlock_t pkg_work_lock;
+static u16 max_phy_id;
+
+/* Debug counters to show using debugfs */
+static struct dentry *debugfs;
+static unsigned int pkg_interrupt_cnt;
+static unsigned int pkg_work_cnt;
+
+static int pkg_temp_debugfs_init(void)
+{
+ struct dentry *d;
+
+ debugfs = debugfs_create_dir("pkg_temp_thermal", NULL);
+ if (!debugfs)
+ return -ENOENT;
+
+ d = debugfs_create_u32("pkg_thres_interrupt", S_IRUGO, debugfs,
+ (u32 *)&pkg_interrupt_cnt);
+ if (!d)
+ goto err_out;
+
+ d = debugfs_create_u32("pkg_thres_work", S_IRUGO, debugfs,
+ (u32 *)&pkg_work_cnt);
+ if (!d)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(debugfs);
+ return -ENOENT;
+}
+
+static struct phy_dev_entry
+ *pkg_temp_thermal_get_phy_entry(unsigned int cpu)
+{
+ u16 phys_proc_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phy_ptr;
+
+ mutex_lock(&phy_dev_list_mutex);
+
+ list_for_each_entry(phy_ptr, &phy_dev_list, list)
+ if (phy_ptr->phys_proc_id == phys_proc_id) {
+ mutex_unlock(&phy_dev_list_mutex);
+ return phy_ptr;
+ }
+
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return NULL;
+}
+
+/*
+* tj-max is is interesting because threshold is set relative to this
+* temperature.
+*/
+static int get_tj_max(int cpu, u32 *tj_max)
+{
+ u32 eax, edx;
+ u32 val;
+ int err;
+
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (err)
+ goto err_ret;
+ else {
+ val = (eax >> 16) & 0xff;
+ if (val)
+ *tj_max = val * 1000;
+ else {
+ err = -EINVAL;
+ goto err_ret;
+ }
+ }
+
+ return 0;
+err_ret:
+ *tj_max = 0;
+ return err;
+}
+
+static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+{
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+
+ phy_dev_entry = tzd->devdata;
+ rdmsr_on_cpu(phy_dev_entry->first_cpu, MSR_IA32_PACKAGE_THERM_STATUS,
+ &eax, &edx);
+ if (eax & 0x80000000) {
+ *temp = phy_dev_entry->tj_max -
+ ((eax >> 16) & 0x7f) * 1000;
+ pr_debug("sys_get_curr_temp %ld\n", *temp);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int sys_get_trip_temp(struct thermal_zone_device *tzd,
+ int trip, unsigned long *temp)
+{
+ u32 eax, edx;
+ struct phy_dev_entry *phy_dev_entry;
+ u32 mask, shift;
+ unsigned long thres_reg_value;
+ int ret;
+
+ if (trip >= MAX_NUMBER_OF_TRIPS)
+ return -EINVAL;
+
+ phy_dev_entry = tzd->devdata;
+
+ if (trip) {
+ mask = THERM_MASK_THRESHOLD1;
+ shift = THERM_SHIFT_THRESHOLD1;
+ } else {
+ mask = THERM_MASK_THRESHOLD0;
+ shift = THERM_SHIFT_THRESHOLD0;
+ }
+
+ ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT, &eax, &edx);
+ if (ret < 0)
+ return -EINVAL;
+
+ thres_reg_value = (eax & mask) >> shift;
+ if (thres_reg_value)
+ *temp = phy_dev_entry->tj_max - thres_reg_value * 1000;
+ else
+ *temp = 0;
+ pr_debug("sys_get_trip_temp %ld\n", *temp);
+
+ return 0;
+}
+
+int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
+ unsigned long temp)
+{
+ u32 l, h;
+ struct phy_dev_entry *phy_dev_entry;
+ u32 mask, shift, intr;
+ int ret;
+
+ phy_dev_entry = tzd->devdata;
+
+ if (trip >= MAX_NUMBER_OF_TRIPS || temp >= phy_dev_entry->tj_max)
+ return -EINVAL;
+
+ ret = rdmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ &l, &h);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (trip) {
+ mask = THERM_MASK_THRESHOLD1;
+ shift = THERM_SHIFT_THRESHOLD1;
+ intr = THERM_INT_THRESHOLD1_ENABLE;
+ } else {
+ mask = THERM_MASK_THRESHOLD0;
+ shift = THERM_SHIFT_THRESHOLD0;
+ intr = THERM_INT_THRESHOLD0_ENABLE;
+ }
+ l &= ~mask;
+ /*
+ * When users space sets a trip temperature == 0, which is indication
+ * that, it is no longer interested in receiving notifications.
+ */
+ if (!temp)
+ l &= ~intr;
+ else {
+ l |= (phy_dev_entry->tj_max - temp)/1000 << shift;
+ l |= intr;
+ }
+
+ return wrmsr_on_cpu(phy_dev_entry->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l, h);
+}
+
+static int sys_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_type *type)
+{
+
+ *type = THERMAL_TRIP_PASSIVE;
+
+ return 0;
+}
+
+/* Thermal zone callback registry */
+static struct thermal_zone_device_ops tzone_ops = {
+ .get_temp = sys_get_curr_temp,
+ .get_trip_temp = sys_get_trip_temp,
+ .get_trip_type = sys_get_trip_type,
+ .set_trip_temp = sys_set_trip_temp,
+};
+
+static bool pkg_temp_thermal_platform_thermal_rate_control(void)
+{
+ return true;
+}
+
+/* Enable threshold interrupt on local package/cpu */
+static inline void enable_pkg_thres_interrupt(void)
+{
+ u32 l, h;
+ u8 thres_0, thres_1;
+
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ /* only enable/disable if it had valid threshold value */
+ thres_0 = (l & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0;
+ thres_1 = (l & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1;
+ if (thres_0)
+ l |= THERM_INT_THRESHOLD0_ENABLE;
+ if (thres_1)
+ l |= THERM_INT_THRESHOLD1_ENABLE;
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+}
+
+/* Disable threshold interrupt on local package/cpu */
+static inline void disable_pkg_thres_interrupt(void)
+{
+ u32 l, h;
+ rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l & (~THERM_INT_THRESHOLD0_ENABLE) &
+ (~THERM_INT_THRESHOLD1_ENABLE), h);
+}
+
+static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
+{
+ __u64 msr_val;
+ int cpu = smp_processor_id();
+ int phy_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+ bool notify = false;
+
+ if (!phdev)
+ return;
+
+ spin_lock(&pkg_work_lock);
+ ++pkg_work_cnt;
+ if (unlikely(phy_id > max_phy_id)) {
+ spin_unlock(&pkg_work_lock);
+ return;
+ }
+ pkg_work_scheduled[phy_id] = 0;
+ spin_unlock(&pkg_work_lock);
+
+ enable_pkg_thres_interrupt();
+ rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ if (msr_val & THERM_LOG_THRESHOLD0) {
+ wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+ msr_val & ~THERM_LOG_THRESHOLD0);
+ notify = true;
+ }
+ if (msr_val & THERM_LOG_THRESHOLD1) {
+ wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS,
+ msr_val & ~THERM_LOG_THRESHOLD1);
+ notify = true;
+ }
+ if (notify) {
+ pr_debug("thermal_zone_device_update\n");
+ thermal_zone_device_update(phdev->tzone);
+ }
+}
+
+static int pkg_temp_thermal_platform_thermal_notify(__u64 msr_val)
+{
+ unsigned long flags;
+ int cpu = smp_processor_id();
+ int phy_id = topology_physical_package_id(cpu);
+
+ /*
+ * When a package is in interrupted state, all CPU's in that package
+ * are in the same interrupt state. So scheduling on any one CPU in
+ * the package is enough and simply return for others.
+ */
+ spin_lock_irqsave(&pkg_work_lock, flags);
+ ++pkg_interrupt_cnt;
+ if (unlikely(phy_id > max_phy_id) || unlikely(!pkg_work_scheduled) ||
+ pkg_work_scheduled[phy_id]) {
+ disable_pkg_thres_interrupt();
+ spin_unlock_irqrestore(&pkg_work_lock, flags);
+ return -EINVAL;
+ }
+ pkg_work_scheduled[phy_id] = 1;
+ spin_unlock_irqrestore(&pkg_work_lock, flags);
+
+ disable_pkg_thres_interrupt();
+ schedule_delayed_work_on(cpu,
+ &per_cpu(pkg_temp_thermal_threshold_work, cpu),
+ msecs_to_jiffies(notify_delay_ms));
+ return 0;
+}
+
+static int find_siblings_cpu(int cpu)
+{
+ int i;
+ int id = topology_physical_package_id(cpu);
+
+ for_each_online_cpu(i)
+ if (i != cpu && topology_physical_package_id(i) == id)
+ return i;
+
+ return 0;
+}
+
+static int pkg_temp_thermal_device_add(unsigned int cpu)
+{
+ int err;
+ u32 tj_max;
+ struct phy_dev_entry *phy_dev_entry;
+ char buffer[30];
+ int thres_count;
+ u32 eax, ebx, ecx, edx;
+
+ cpuid(6, &eax, &ebx, &ecx, &edx);
+ thres_count = ebx & 0x07;
+ if (!thres_count)
+ return -ENODEV;
+
+ thres_count = clamp_val(thres_count, 0, MAX_NUMBER_OF_TRIPS);
+
+ err = get_tj_max(cpu, &tj_max);
+ if (err)
+ goto err_ret;
+
+ mutex_lock(&phy_dev_list_mutex);
+
+ phy_dev_entry = kzalloc(sizeof(*phy_dev_entry), GFP_KERNEL);
+ if (!phy_dev_entry) {
+ err = -ENOMEM;
+ goto err_ret_unlock;
+ }
+
+ spin_lock(&pkg_work_lock);
+ if (topology_physical_package_id(cpu) > max_phy_id)
+ max_phy_id = topology_physical_package_id(cpu);
+ pkg_work_scheduled = krealloc(pkg_work_scheduled,
+ (max_phy_id+1) * sizeof(u8), GFP_ATOMIC);
+ if (!pkg_work_scheduled) {
+ spin_unlock(&pkg_work_lock);
+ err = -ENOMEM;
+ goto err_ret_free;
+ }
+ pkg_work_scheduled[topology_physical_package_id(cpu)] = 0;
+ spin_unlock(&pkg_work_lock);
+
+ phy_dev_entry->phys_proc_id = topology_physical_package_id(cpu);
+ phy_dev_entry->first_cpu = cpu;
+ phy_dev_entry->tj_max = tj_max;
+ phy_dev_entry->ref_cnt = 1;
+ snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
+ phy_dev_entry->phys_proc_id);
+ phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+ thres_count,
+ (thres_count == MAX_NUMBER_OF_TRIPS) ?
+ 0x03 : 0x01,
+ phy_dev_entry, &tzone_ops, NULL, 0, 0);
+ if (IS_ERR(phy_dev_entry->tzone)) {
+ err = PTR_ERR(phy_dev_entry->tzone);
+ goto err_ret_free;
+ }
+ /* Store MSR value for package thermal interrupt, to restore at exit */
+ rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ &phy_dev_entry->start_pkg_therm_low,
+ &phy_dev_entry->start_pkg_therm_high);
+
+ list_add_tail(&phy_dev_entry->list, &phy_dev_list);
+ pr_debug("pkg_temp_thermal_device_add :phy_id %d cpu %d\n",
+ phy_dev_entry->phys_proc_id, cpu);
+
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return 0;
+
+err_ret_free:
+ kfree(phy_dev_entry);
+err_ret_unlock:
+ mutex_unlock(&phy_dev_list_mutex);
+
+err_ret:
+ return err;
+}
+
+static int pkg_temp_thermal_device_remove(unsigned int cpu)
+{
+ struct phy_dev_entry *n;
+ u16 phys_proc_id = topology_physical_package_id(cpu);
+ struct phy_dev_entry *phdev =
+ pkg_temp_thermal_get_phy_entry(cpu);
+
+ if (!phdev)
+ return -ENODEV;
+
+ mutex_lock(&phy_dev_list_mutex);
+ /* If we are loosing the first cpu for this package, we need change */
+ if (phdev->first_cpu == cpu) {
+ phdev->first_cpu = find_siblings_cpu(cpu);
+ pr_debug("thermal_device_remove: first cpu switched %d\n",
+ phdev->first_cpu);
+ }
+ /*
+ * It is possible that no siblings left as this was the last cpu
+ * going offline. We don't need to worry about this assignment
+ * as the phydev entry will be removed in this case and
+ * thermal zone is removed.
+ */
+ --phdev->ref_cnt;
+ pr_debug("thermal_device_remove: pkg: %d cpu %d ref_cnt %d\n",
+ phys_proc_id, cpu, phdev->ref_cnt);
+ if (!phdev->ref_cnt)
+ list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+ if (phdev->phys_proc_id == phys_proc_id) {
+ thermal_zone_device_unregister(phdev->tzone);
+ list_del(&phdev->list);
+ kfree(phdev);
+ break;
+ }
+ }
+ mutex_unlock(&phy_dev_list_mutex);
+
+ return 0;
+}
+
+static int get_core_online(unsigned int cpu)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ struct phy_dev_entry *phdev = pkg_temp_thermal_get_phy_entry(cpu);
+
+ /* Check if there is already an instance for this package */
+ if (!phdev) {
+ if (!cpu_has(c, X86_FEATURE_DTHERM) &&
+ !cpu_has(c, X86_FEATURE_PTS))
+ return -ENODEV;
+ if (pkg_temp_thermal_device_add(cpu))
+ return -ENODEV;
+ } else {
+ mutex_lock(&phy_dev_list_mutex);
+ ++phdev->ref_cnt;
+ pr_debug("get_core_online: cpu %d ref_cnt %d\n",
+ cpu, phdev->ref_cnt);
+ mutex_unlock(&phy_dev_list_mutex);
+ }
+ INIT_DELAYED_WORK(&per_cpu(pkg_temp_thermal_threshold_work, cpu),
+ pkg_temp_thermal_threshold_work_fn);
+
+ pr_debug("get_core_online: cpu %d successful\n", cpu);
+
+ return 0;
+}
+
+static void put_core_offline(unsigned int cpu)
+{
+ if (!pkg_temp_thermal_device_remove(cpu))
+ cancel_delayed_work_sync(
+ &per_cpu(pkg_temp_thermal_threshold_work, cpu));
+
+ pr_debug("put_core_offline: cpu %d\n", cpu);
+}
+
+static int pkg_temp_thermal_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ get_core_online(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ put_core_offline(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block pkg_temp_thermal_notifier __refdata = {
+ .notifier_call = pkg_temp_thermal_cpu_callback,
+};
+
+static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
+ { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
+
+static int __init pkg_temp_thermal_init(void)
+{
+ int i;
+
+ if (!x86_match_cpu(pkg_temp_thermal_ids))
+ return -ENODEV;
+
+ spin_lock_init(&pkg_work_lock);
+ platform_thermal_package_notify =
+ pkg_temp_thermal_platform_thermal_notify;
+ platform_thermal_package_rate_control =
+ pkg_temp_thermal_platform_thermal_rate_control;
+
+ get_online_cpus();
+ for_each_online_cpu(i)
+ if (get_core_online(i))
+ goto err_ret;
+ register_hotcpu_notifier(&pkg_temp_thermal_notifier);
+ put_online_cpus();
+
+ pkg_temp_debugfs_init(); /* Don't care if fails */
+
+ return 0;
+
+err_ret:
+ get_online_cpus();
+ for_each_online_cpu(i)
+ put_core_offline(i);
+ put_online_cpus();
+ kfree(pkg_work_scheduled);
+ platform_thermal_package_notify = NULL;
+ platform_thermal_package_rate_control = NULL;
+
+ return -ENODEV;
+}
+
+static void __exit pkg_temp_thermal_exit(void)
+{
+ struct phy_dev_entry *phdev, *n;
+ int i;
+
+ get_online_cpus();
+ unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
+ mutex_lock(&phy_dev_list_mutex);
+ list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
+ /* Retore old MSR value for package thermal interrupt */
+ wrmsr_on_cpu(phdev->first_cpu,
+ MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ phdev->start_pkg_therm_low,
+ phdev->start_pkg_therm_high);
+ thermal_zone_device_unregister(phdev->tzone);
+ list_del(&phdev->list);
+ kfree(phdev);
+ }
+ mutex_unlock(&phy_dev_list_mutex);
+ platform_thermal_package_notify = NULL;
+ platform_thermal_package_rate_control = NULL;
+ for_each_online_cpu(i)
+ cancel_delayed_work_sync(
+ &per_cpu(pkg_temp_thermal_threshold_work, i));
+ put_online_cpus();
+
+ kfree(pkg_work_scheduled);
+
+ debugfs_remove_recursive(debugfs);
+}
+
+module_init(pkg_temp_thermal_init)
+module_exit(pkg_temp_thermal_exit)
+
+MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 282e27028418..a5d52eea8232 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -41,7 +41,7 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus);
*/
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
-unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int);
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq);
#else /* !CONFIG_CPU_THERMAL */
static inline struct thermal_cooling_device *
cpufreq_cooling_register(const struct cpumask *clip_cpus)
@@ -54,7 +54,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
return;
}
static inline
-unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int)
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
{
return THERMAL_CSTATE_INVALID;
}