mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Merge branch 'thermal' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux into next
Conflicts: drivers/thermal/cpu_cooling.c
This commit is contained in:
commit
d13cb03aef
22
Documentation/devicetree/bindings/thermal/armada-thermal.txt
Normal file
22
Documentation/devicetree/bindings/thermal/armada-thermal.txt
Normal file
@ -0,0 +1,22 @@
|
||||
* Marvell Armada 370/XP thermal management
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be set to one of the following:
|
||||
marvell,armada370-thermal
|
||||
marvell,armadaxp-thermal
|
||||
|
||||
- reg: Device's register space.
|
||||
Two entries are expected, see the examples below.
|
||||
The first one is required for the sensor register;
|
||||
the second one is required for the control register
|
||||
to be used for sensor initialization (a.k.a. calibration).
|
||||
|
||||
Example:
|
||||
|
||||
thermal@d0018300 {
|
||||
compatible = "marvell,armada370-thermal";
|
||||
reg = <0xd0018300 0x4
|
||||
0xd0018304 0x4>;
|
||||
status = "okay";
|
||||
};
|
@ -13,11 +13,11 @@ Thermal emulation mode supports software debug for TMU's operation. User can set
|
||||
manually with software code and TMU will read current temperature from user value not from
|
||||
sensor's value.
|
||||
|
||||
Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available.
|
||||
When it's enabled, sysfs node will be created under
|
||||
/sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'.
|
||||
Enabling CONFIG_THERMAL_EMULATION option will make this support available.
|
||||
When it's enabled, sysfs node will be created as
|
||||
/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
|
||||
|
||||
The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any
|
||||
The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any
|
||||
temperature you want to update to sysfs node, it automatically enable emulation mode and
|
||||
current temperature will be changed into it.
|
||||
(Exynos also supports user changable delay time which would be used to delay of
|
||||
|
@ -265,6 +265,10 @@ emul_temp
|
||||
Unit: millidegree Celsius
|
||||
WO, Optional
|
||||
|
||||
WARNING: Be careful while enabling this option on production systems,
|
||||
because userland can easily disable the thermal policy by simply
|
||||
flooding this sysfs node with low temperature values.
|
||||
|
||||
*****************************
|
||||
* Cooling device attributes *
|
||||
*****************************
|
||||
@ -375,11 +379,3 @@ platform data is provided, this uses the step_wise throttling policy.
|
||||
This function serves as an arbitrator to set the state of a cooling
|
||||
device. It sets the cooling device to the deepest cooling state if
|
||||
possible.
|
||||
|
||||
5.5:thermal_register_governor:
|
||||
This function lets the various thermal governors to register themselves
|
||||
with the Thermal framework. At run time, depending on a zone's platform
|
||||
data, a particular governor is used for throttling.
|
||||
|
||||
5.6:thermal_unregister_governor:
|
||||
This function unregisters a governor from the thermal framework.
|
||||
|
@ -67,7 +67,7 @@ config THERMAL_GOV_USER_SPACE
|
||||
Enable this to let the user space manage the platform thermals.
|
||||
|
||||
config CPU_THERMAL
|
||||
tristate "generic cpu cooling support"
|
||||
bool "generic cpu cooling support"
|
||||
depends on CPU_FREQ
|
||||
select CPU_FREQ_TABLE
|
||||
help
|
||||
@ -86,6 +86,10 @@ config THERMAL_EMULATION
|
||||
user can manually input temperature and test the different trip
|
||||
threshold behaviour for simulation purpose.
|
||||
|
||||
WARNING: Be careful while enabling this option on production systems,
|
||||
because userland can easily disable the thermal policy by simply
|
||||
flooding this sysfs node with low temperature values.
|
||||
|
||||
config SPEAR_THERMAL
|
||||
bool "SPEAr thermal sensor driver"
|
||||
depends on PLAT_SPEAR
|
||||
@ -117,15 +121,6 @@ config EXYNOS_THERMAL
|
||||
If you say yes here you get support for TMU (Thermal Management
|
||||
Unit) on SAMSUNG EXYNOS series of SoC.
|
||||
|
||||
config EXYNOS_THERMAL_EMUL
|
||||
bool "EXYNOS TMU emulation mode support"
|
||||
depends on EXYNOS_THERMAL
|
||||
help
|
||||
Exynos 4412 and 4414 and 5 series has emulation mode on TMU.
|
||||
Enable this option will be make sysfs node in exynos thermal platform
|
||||
device directory to support emulation mode. With emulation mode sysfs
|
||||
node, you can manually input temperature to TMU for simulation purpose.
|
||||
|
||||
config DOVE_THERMAL
|
||||
tristate "Temperature sensor on Marvell Dove SoCs"
|
||||
depends on ARCH_DOVE
|
||||
@ -144,6 +139,14 @@ config DB8500_THERMAL
|
||||
created. Cooling devices can be bound to the trip points to cool this
|
||||
thermal zone if trip points reached.
|
||||
|
||||
config ARMADA_THERMAL
|
||||
tristate "Armada 370/XP thermal management"
|
||||
depends on ARCH_MVEBU
|
||||
depends on OF
|
||||
help
|
||||
Enable this option if you want to have support for thermal management
|
||||
controller present in Armada 370 and Armada XP SoC.
|
||||
|
||||
config DB8500_CPUFREQ_COOLING
|
||||
tristate "DB8500 cpufreq cooling"
|
||||
depends on ARCH_U8500
|
||||
|
@ -3,14 +3,15 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_THERMAL) += thermal_sys.o
|
||||
thermal_sys-y += thermal_core.o
|
||||
|
||||
# governors
|
||||
obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
|
||||
obj-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
|
||||
obj-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
|
||||
thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
|
||||
thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
|
||||
thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
|
||||
|
||||
# cpufreq cooling
|
||||
obj-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
|
||||
thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
|
||||
|
||||
# platform thermal drivers
|
||||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||
@ -19,6 +20,7 @@ obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
||||
obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
|
||||
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
||||
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
|
||||
|
||||
|
232
drivers/thermal/armada_thermal.c
Normal file
232
drivers/thermal/armada_thermal.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Marvell Armada 370/XP thermal sensor driver
|
||||
*
|
||||
* Copyright (C) 2013 Marvell
|
||||
*
|
||||
* 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 <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#define THERMAL_VALID_OFFSET 9
|
||||
#define THERMAL_VALID_MASK 0x1
|
||||
#define THERMAL_TEMP_OFFSET 10
|
||||
#define THERMAL_TEMP_MASK 0x1ff
|
||||
|
||||
/* Thermal Manager Control and Status Register */
|
||||
#define PMU_TDC0_SW_RST_MASK (0x1 << 1)
|
||||
#define PMU_TM_DISABLE_OFFS 0
|
||||
#define PMU_TM_DISABLE_MASK (0x1 << PMU_TM_DISABLE_OFFS)
|
||||
#define PMU_TDC0_REF_CAL_CNT_OFFS 11
|
||||
#define PMU_TDC0_REF_CAL_CNT_MASK (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS)
|
||||
#define PMU_TDC0_OTF_CAL_MASK (0x1 << 30)
|
||||
#define PMU_TDC0_START_CAL_MASK (0x1 << 25)
|
||||
|
||||
struct armada_thermal_ops;
|
||||
|
||||
/* Marvell EBU Thermal Sensor Dev Structure */
|
||||
struct armada_thermal_priv {
|
||||
void __iomem *sensor;
|
||||
void __iomem *control;
|
||||
struct armada_thermal_ops *ops;
|
||||
};
|
||||
|
||||
struct armada_thermal_ops {
|
||||
/* Initialize the sensor */
|
||||
void (*init_sensor)(struct armada_thermal_priv *);
|
||||
|
||||
/* Test for a valid sensor value (optional) */
|
||||
bool (*is_valid)(struct armada_thermal_priv *);
|
||||
};
|
||||
|
||||
static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
reg = readl_relaxed(priv->control);
|
||||
reg |= PMU_TDC0_OTF_CAL_MASK;
|
||||
writel(reg, priv->control);
|
||||
|
||||
/* Reference calibration value */
|
||||
reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
|
||||
reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
|
||||
writel(reg, priv->control);
|
||||
|
||||
/* Reset the sensor */
|
||||
reg = readl_relaxed(priv->control);
|
||||
writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
|
||||
|
||||
writel(reg, priv->control);
|
||||
|
||||
/* Enable the sensor */
|
||||
reg = readl_relaxed(priv->sensor);
|
||||
reg &= ~PMU_TM_DISABLE_MASK;
|
||||
writel(reg, priv->sensor);
|
||||
}
|
||||
|
||||
static void armada370_init_sensor(struct armada_thermal_priv *priv)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
reg = readl_relaxed(priv->control);
|
||||
reg |= PMU_TDC0_OTF_CAL_MASK;
|
||||
writel(reg, priv->control);
|
||||
|
||||
/* Reference calibration value */
|
||||
reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
|
||||
reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
|
||||
writel(reg, priv->control);
|
||||
|
||||
reg &= ~PMU_TDC0_START_CAL_MASK;
|
||||
writel(reg, priv->control);
|
||||
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
static bool armada_is_valid(struct armada_thermal_priv *priv)
|
||||
{
|
||||
unsigned long reg = readl_relaxed(priv->sensor);
|
||||
|
||||
return (reg >> THERMAL_VALID_OFFSET) & THERMAL_VALID_MASK;
|
||||
}
|
||||
|
||||
static int armada_get_temp(struct thermal_zone_device *thermal,
|
||||
unsigned long *temp)
|
||||
{
|
||||
struct armada_thermal_priv *priv = thermal->devdata;
|
||||
unsigned long reg;
|
||||
|
||||
/* Valid check */
|
||||
if (priv->ops->is_valid && !priv->ops->is_valid(priv)) {
|
||||
dev_err(&thermal->device,
|
||||
"Temperature sensor reading not valid\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
reg = readl_relaxed(priv->sensor);
|
||||
reg = (reg >> THERMAL_TEMP_OFFSET) & THERMAL_TEMP_MASK;
|
||||
*temp = (3153000000UL - (10000000UL*reg)) / 13825;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops ops = {
|
||||
.get_temp = armada_get_temp,
|
||||
};
|
||||
|
||||
static const struct armada_thermal_ops armadaxp_ops = {
|
||||
.init_sensor = armadaxp_init_sensor,
|
||||
};
|
||||
|
||||
static const struct armada_thermal_ops armada370_ops = {
|
||||
.is_valid = armada_is_valid,
|
||||
.init_sensor = armada370_init_sensor,
|
||||
};
|
||||
|
||||
static const struct of_device_id armada_thermal_id_table[] = {
|
||||
{
|
||||
.compatible = "marvell,armadaxp-thermal",
|
||||
.data = &armadaxp_ops,
|
||||
},
|
||||
{
|
||||
.compatible = "marvell,armada370-thermal",
|
||||
.data = &armada370_ops,
|
||||
},
|
||||
{
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
|
||||
|
||||
static int armada_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct thermal_zone_device *thermal;
|
||||
const struct of_device_id *match;
|
||||
struct armada_thermal_priv *priv;
|
||||
struct resource *res;
|
||||
|
||||
match = of_match_device(armada_thermal_id_table, &pdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Failed to get platform resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->sensor))
|
||||
return PTR_ERR(priv->sensor);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Failed to get platform resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->control = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->control))
|
||||
return PTR_ERR(priv->control);
|
||||
|
||||
priv->ops = (struct armada_thermal_ops *)match->data;
|
||||
priv->ops->init_sensor(priv);
|
||||
|
||||
thermal = thermal_zone_device_register("armada_thermal", 0, 0,
|
||||
priv, &ops, NULL, 0, 0);
|
||||
if (IS_ERR(thermal)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register thermal zone device\n");
|
||||
return PTR_ERR(thermal);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, thermal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct thermal_zone_device *armada_thermal =
|
||||
platform_get_drvdata(pdev);
|
||||
|
||||
thermal_zone_device_unregister(armada_thermal);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver armada_thermal_driver = {
|
||||
.probe = armada_thermal_probe,
|
||||
.remove = armada_thermal_exit,
|
||||
.driver = {
|
||||
.name = "armada_thermal",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(armada_thermal_id_table),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(armada_thermal_driver);
|
||||
|
||||
MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Armada 370/XP thermal driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -108,6 +108,105 @@ static int is_cpufreq_valid(int cpu)
|
||||
return !cpufreq_get_policy(&policy, cpu);
|
||||
}
|
||||
|
||||
enum cpufreq_cooling_property {
|
||||
GET_LEVEL,
|
||||
GET_FREQ,
|
||||
GET_MAXL,
|
||||
};
|
||||
|
||||
/*
|
||||
* this is the common function to
|
||||
* 1. get maximum cpu cooling states
|
||||
* 2. translate frequency to cooling state
|
||||
* 3. translate cooling state to frequency
|
||||
* Note that the code may be not in good shape
|
||||
* but it is written in this way in order to:
|
||||
* a) reduce duplicate code as most of the code can be shared.
|
||||
* b) make sure the logic is consistent when translating between
|
||||
* cooling states and frequencies.
|
||||
*/
|
||||
static int get_property(unsigned int cpu, unsigned long input,
|
||||
unsigned int* output, enum cpufreq_cooling_property property)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long max_level = 0, level;
|
||||
unsigned int freq = CPUFREQ_ENTRY_INVALID;
|
||||
int descend = -1;
|
||||
struct cpufreq_frequency_table *table =
|
||||
cpufreq_frequency_get_table(cpu);
|
||||
|
||||
if (!output)
|
||||
return -EINVAL;
|
||||
|
||||
if (!table)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
/* ignore invalid entries */
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
|
||||
/* ignore duplicate entry */
|
||||
if (freq == table[i].frequency)
|
||||
continue;
|
||||
|
||||
/* get the frequency order */
|
||||
if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
|
||||
descend = !!(freq > table[i].frequency);
|
||||
|
||||
freq = table[i].frequency;
|
||||
max_level++;
|
||||
}
|
||||
|
||||
/* get max level */
|
||||
if (property == GET_MAXL) {
|
||||
*output = (unsigned int)max_level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (property == GET_FREQ)
|
||||
level = descend ? input : (max_level - input -1);
|
||||
|
||||
|
||||
for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
/* ignore invalid entry */
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
|
||||
/* ignore duplicate entry */
|
||||
if (freq == table[i].frequency)
|
||||
continue;
|
||||
|
||||
/* now we have a valid frequency entry */
|
||||
freq = table[i].frequency;
|
||||
|
||||
if (property == GET_LEVEL && (unsigned int)input == freq) {
|
||||
/* get level by frequency */
|
||||
*output = descend ? j : (max_level - j - 1);
|
||||
return 0;
|
||||
}
|
||||
if (property == GET_FREQ && level == j) {
|
||||
/* get frequency by level */
|
||||
*output = freq;
|
||||
return 0;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
|
||||
return THERMAL_CSTATE_INVALID;
|
||||
return (unsigned long)val;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(cpufreq_cooling_get_level);
|
||||
|
||||
/**
|
||||
* get_cpu_frequency - get the absolute value of frequency from level.
|
||||
* @cpu: cpu for which frequency is fetched.
|
||||
@ -116,46 +215,13 @@ static int is_cpufreq_valid(int cpu)
|
||||
*/
|
||||
static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
unsigned long level_index;
|
||||
bool descend = false;
|
||||
struct cpufreq_frequency_table *table =
|
||||
cpufreq_frequency_get_table(cpu);
|
||||
if (!table)
|
||||
return ret;
|
||||
int ret = 0;
|
||||
unsigned int freq;
|
||||
|
||||
while (table[i].frequency != CPUFREQ_TABLE_END) {
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
|
||||
/*check if table in ascending or descending order*/
|
||||
if ((table[i + 1].frequency != CPUFREQ_TABLE_END) &&
|
||||
(table[i + 1].frequency < table[i].frequency)
|
||||
&& !descend) {
|
||||
descend = true;
|
||||
}
|
||||
|
||||
/*return if level matched and table in descending order*/
|
||||
if (descend && i == level)
|
||||
return table[i].frequency;
|
||||
i++;
|
||||
}
|
||||
i--;
|
||||
|
||||
if (level > i || descend)
|
||||
return ret;
|
||||
level_index = i - level;
|
||||
|
||||
/*Scan the table in reverse order and match the level*/
|
||||
while (i >= 0) {
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
/*return if level matched*/
|
||||
if (i == level_index)
|
||||
return table[i].frequency;
|
||||
i--;
|
||||
}
|
||||
return ret;
|
||||
ret = get_property(cpu, level, &freq, GET_FREQ);
|
||||
if (ret)
|
||||
return 0;
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,29 +303,17 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
|
||||
struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
|
||||
struct cpumask *mask = &cpufreq_device->allowed_cpus;
|
||||
unsigned int cpu;
|
||||
struct cpufreq_frequency_table *table;
|
||||
unsigned long count = 0;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
cpu = cpumask_any(mask);
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (!table) {
|
||||
*state = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
ret = get_property(cpu, 0, (unsigned int *)&count, GET_MAXL);
|
||||
|
||||
if (count > 0) {
|
||||
*state = --count;
|
||||
return 0;
|
||||
}
|
||||
if (count > 0)
|
||||
*state = count;
|
||||
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,8 +39,6 @@
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
|
||||
/* Exynos generic registers */
|
||||
#define EXYNOS_TMU_REG_TRIMINFO 0x0
|
||||
#define EXYNOS_TMU_REG_CONTROL 0x20
|
||||
@ -100,13 +98,13 @@
|
||||
#define IDLE_INTERVAL 10000
|
||||
#define MCELSIUS 1000
|
||||
|
||||
#ifdef CONFIG_EXYNOS_THERMAL_EMUL
|
||||
#ifdef CONFIG_THERMAL_EMULATION
|
||||
#define EXYNOS_EMUL_TIME 0x57F0
|
||||
#define EXYNOS_EMUL_TIME_SHIFT 16
|
||||
#define EXYNOS_EMUL_DATA_SHIFT 8
|
||||
#define EXYNOS_EMUL_DATA_MASK 0xFF
|
||||
#define EXYNOS_EMUL_ENABLE 0x1
|
||||
#endif /* CONFIG_EXYNOS_THERMAL_EMUL */
|
||||
#endif /* CONFIG_THERMAL_EMULATION */
|
||||
|
||||
/* CPU Zone information */
|
||||
#define PANIC_ZONE 4
|
||||
@ -145,6 +143,7 @@ struct thermal_cooling_conf {
|
||||
struct thermal_sensor_conf {
|
||||
char name[SENSOR_NAME_LEN];
|
||||
int (*read_temperature)(void *data);
|
||||
int (*write_emul_temp)(void *drv_data, unsigned long temp);
|
||||
struct thermal_trip_point_conf trip_data;
|
||||
struct thermal_cooling_conf cooling_data;
|
||||
void *private_data;
|
||||
@ -242,26 +241,6 @@ static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_get_frequency_level(unsigned int cpu, unsigned int freq)
|
||||
{
|
||||
int i = 0, ret = -EINVAL;
|
||||
struct cpufreq_frequency_table *table = NULL;
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
#endif
|
||||
if (!table)
|
||||
return ret;
|
||||
|
||||
while (table[i].frequency != CPUFREQ_TABLE_END) {
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
if (table[i].frequency == freq)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Bind callback functions for thermal zone */
|
||||
static int exynos_bind(struct thermal_zone_device *thermal,
|
||||
struct thermal_cooling_device *cdev)
|
||||
@ -288,8 +267,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
|
||||
/* Bind the thermal zone to the cpufreq cooling device */
|
||||
for (i = 0; i < tab_size; i++) {
|
||||
clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
|
||||
level = exynos_get_frequency_level(0, clip_data->freq_clip_max);
|
||||
if (level < 0)
|
||||
level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
|
||||
if (level == THERMAL_CSTATE_INVALID)
|
||||
return 0;
|
||||
switch (GET_ZONE(i)) {
|
||||
case MONITOR_ZONE:
|
||||
@ -369,6 +348,23 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get temperature callback functions for thermal zone */
|
||||
static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
|
||||
unsigned long temp)
|
||||
{
|
||||
void *data;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!th_zone->sensor_conf) {
|
||||
pr_info("Temperature sensor not initialised\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
data = th_zone->sensor_conf->private_data;
|
||||
if (th_zone->sensor_conf->write_emul_temp)
|
||||
ret = th_zone->sensor_conf->write_emul_temp(data, temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the temperature trend */
|
||||
static int exynos_get_trend(struct thermal_zone_device *thermal,
|
||||
int trip, enum thermal_trend *trend)
|
||||
@ -392,6 +388,7 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
|
||||
.bind = exynos_bind,
|
||||
.unbind = exynos_unbind,
|
||||
.get_temp = exynos_get_temp,
|
||||
.set_emul_temp = exynos_set_emul_temp,
|
||||
.get_trend = exynos_get_trend,
|
||||
.get_mode = exynos_get_mode,
|
||||
.set_mode = exynos_set_mode,
|
||||
@ -714,6 +711,47 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
|
||||
return temp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THERMAL_EMULATION
|
||||
static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
|
||||
{
|
||||
struct exynos_tmu_data *data = drv_data;
|
||||
unsigned int reg;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (data->soc == SOC_ARCH_EXYNOS4210)
|
||||
goto out;
|
||||
|
||||
if (temp && temp < MCELSIUS)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
clk_enable(data->clk);
|
||||
|
||||
reg = readl(data->base + EXYNOS_EMUL_CON);
|
||||
|
||||
if (temp) {
|
||||
temp /= MCELSIUS;
|
||||
|
||||
reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
|
||||
(temp_to_code(data, temp)
|
||||
<< EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
|
||||
} else {
|
||||
reg &= ~EXYNOS_EMUL_ENABLE;
|
||||
}
|
||||
|
||||
writel(reg, data->base + EXYNOS_EMUL_CON);
|
||||
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
|
||||
{ return -EINVAL; }
|
||||
#endif/*CONFIG_THERMAL_EMULATION*/
|
||||
|
||||
static void exynos_tmu_work(struct work_struct *work)
|
||||
{
|
||||
struct exynos_tmu_data *data = container_of(work,
|
||||
@ -747,6 +785,7 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
|
||||
static struct thermal_sensor_conf exynos_sensor_conf = {
|
||||
.name = "exynos-therm",
|
||||
.read_temperature = (int (*)(void *))exynos_tmu_read,
|
||||
.write_emul_temp = exynos_tmu_set_emulation,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_CPU_EXYNOS4210)
|
||||
@ -853,93 +892,6 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXYNOS_THERMAL_EMUL
|
||||
static ssize_t exynos_tmu_emulation_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct platform_device *pdev = container_of(dev,
|
||||
struct platform_device, dev);
|
||||
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
||||
unsigned int reg;
|
||||
u8 temp_code;
|
||||
int temp = 0;
|
||||
|
||||
if (data->soc == SOC_ARCH_EXYNOS4210)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
clk_enable(data->clk);
|
||||
reg = readl(data->base + EXYNOS_EMUL_CON);
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
if (reg & EXYNOS_EMUL_ENABLE) {
|
||||
reg >>= EXYNOS_EMUL_DATA_SHIFT;
|
||||
temp_code = reg & EXYNOS_EMUL_DATA_MASK;
|
||||
temp = code_to_temp(data, temp_code);
|
||||
}
|
||||
out:
|
||||
return sprintf(buf, "%d\n", temp * MCELSIUS);
|
||||
}
|
||||
|
||||
static ssize_t exynos_tmu_emulation_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct platform_device *pdev = container_of(dev,
|
||||
struct platform_device, dev);
|
||||
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
||||
unsigned int reg;
|
||||
int temp;
|
||||
|
||||
if (data->soc == SOC_ARCH_EXYNOS4210)
|
||||
goto out;
|
||||
|
||||
if (!sscanf(buf, "%d\n", &temp) || temp < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
clk_enable(data->clk);
|
||||
|
||||
reg = readl(data->base + EXYNOS_EMUL_CON);
|
||||
|
||||
if (temp) {
|
||||
/* Both CELSIUS and MCELSIUS type are available for input */
|
||||
if (temp > MCELSIUS)
|
||||
temp /= MCELSIUS;
|
||||
|
||||
reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
|
||||
(temp_to_code(data, (temp / MCELSIUS))
|
||||
<< EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
|
||||
} else {
|
||||
reg &= ~EXYNOS_EMUL_ENABLE;
|
||||
}
|
||||
|
||||
writel(reg, data->base + EXYNOS_EMUL_CON);
|
||||
|
||||
clk_disable(data->clk);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
|
||||
exynos_tmu_emulation_store);
|
||||
static int create_emulation_sysfs(struct device *dev)
|
||||
{
|
||||
return device_create_file(dev, &dev_attr_emulation);
|
||||
}
|
||||
static void remove_emulation_sysfs(struct device *dev)
|
||||
{
|
||||
device_remove_file(dev, &dev_attr_emulation);
|
||||
}
|
||||
#else
|
||||
static inline int create_emulation_sysfs(struct device *dev) { return 0; }
|
||||
static inline void remove_emulation_sysfs(struct device *dev) {}
|
||||
#endif
|
||||
|
||||
static int exynos_tmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_tmu_data *data;
|
||||
@ -1039,10 +991,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = create_emulation_sysfs(&pdev->dev);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
|
||||
|
||||
return 0;
|
||||
err_clk:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
@ -1054,8 +1002,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
remove_emulation_sysfs(&pdev->dev);
|
||||
|
||||
exynos_tmu_control(pdev, false);
|
||||
|
||||
exynos_unregister_thermal();
|
||||
|
@ -22,9 +22,6 @@
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
@ -111,23 +108,15 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
|
||||
static struct thermal_governor thermal_gov_fair_share = {
|
||||
.name = "fair_share",
|
||||
.throttle = fair_share_throttle,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init thermal_gov_fair_share_init(void)
|
||||
int thermal_gov_fair_share_register(void)
|
||||
{
|
||||
return thermal_register_governor(&thermal_gov_fair_share);
|
||||
}
|
||||
|
||||
static void __exit thermal_gov_fair_share_exit(void)
|
||||
void thermal_gov_fair_share_unregister(void)
|
||||
{
|
||||
thermal_unregister_governor(&thermal_gov_fair_share);
|
||||
}
|
||||
|
||||
/* This should load after thermal framework */
|
||||
fs_initcall(thermal_gov_fair_share_init);
|
||||
module_exit(thermal_gov_fair_share_exit);
|
||||
|
||||
MODULE_AUTHOR("Durgadoss R");
|
||||
MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -377,6 +378,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&common->lock);
|
||||
common->dev = dev;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (irq) {
|
||||
int ret;
|
||||
@ -419,12 +423,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(dev, "Could not allocate priv\n");
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
priv->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
if (IS_ERR(priv->base)) {
|
||||
ret = PTR_ERR(priv->base);
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
priv->common = common;
|
||||
priv->id = i;
|
||||
@ -443,10 +450,10 @@ static int rcar_thermal_probe(struct platform_device *pdev)
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
list_move_tail(&priv->list, &common->head);
|
||||
|
||||
if (rcar_has_irq_support(priv))
|
||||
rcar_thermal_irq_enable(priv);
|
||||
|
||||
list_move_tail(&priv->list, &common->head);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, common);
|
||||
@ -456,8 +463,14 @@ static int rcar_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
error_unregister:
|
||||
rcar_thermal_for_each_priv(priv, common)
|
||||
rcar_thermal_for_each_priv(priv, common) {
|
||||
thermal_zone_device_unregister(priv->zone);
|
||||
if (rcar_has_irq_support(priv))
|
||||
rcar_thermal_irq_disable(priv);
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -465,13 +478,20 @@ error_unregister:
|
||||
static int rcar_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_thermal_common *common = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_thermal_priv *priv;
|
||||
|
||||
rcar_thermal_for_each_priv(priv, common)
|
||||
rcar_thermal_for_each_priv(priv, common) {
|
||||
thermal_zone_device_unregister(priv->zone);
|
||||
if (rcar_has_irq_support(priv))
|
||||
rcar_thermal_irq_disable(priv);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,6 @@
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
@ -59,9 +56,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||
|
||||
switch (trend) {
|
||||
case THERMAL_TREND_RAISING:
|
||||
if (throttle)
|
||||
if (throttle) {
|
||||
cur_state = cur_state < instance->upper ?
|
||||
(cur_state + 1) : instance->upper;
|
||||
if (cur_state < instance->lower)
|
||||
cur_state = instance->lower;
|
||||
}
|
||||
break;
|
||||
case THERMAL_TREND_RAISE_FULL:
|
||||
if (throttle)
|
||||
@ -71,8 +71,11 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||
if (cur_state == instance->lower) {
|
||||
if (!throttle)
|
||||
cur_state = -1;
|
||||
} else
|
||||
} else {
|
||||
cur_state -= 1;
|
||||
if (cur_state > instance->upper)
|
||||
cur_state = instance->upper;
|
||||
}
|
||||
break;
|
||||
case THERMAL_TREND_DROP_FULL:
|
||||
if (cur_state == instance->lower) {
|
||||
@ -180,23 +183,14 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
|
||||
static struct thermal_governor thermal_gov_step_wise = {
|
||||
.name = "step_wise",
|
||||
.throttle = step_wise_throttle,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init thermal_gov_step_wise_init(void)
|
||||
int thermal_gov_step_wise_register(void)
|
||||
{
|
||||
return thermal_register_governor(&thermal_gov_step_wise);
|
||||
}
|
||||
|
||||
static void __exit thermal_gov_step_wise_exit(void)
|
||||
void thermal_gov_step_wise_unregister(void)
|
||||
{
|
||||
thermal_unregister_governor(&thermal_gov_step_wise);
|
||||
}
|
||||
|
||||
/* This should load after thermal framework */
|
||||
fs_initcall(thermal_gov_step_wise_init);
|
||||
module_exit(thermal_gov_step_wise_exit);
|
||||
|
||||
MODULE_AUTHOR("Durgadoss R");
|
||||
MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -99,7 +99,6 @@ int thermal_register_governor(struct thermal_governor *governor)
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_register_governor);
|
||||
|
||||
void thermal_unregister_governor(struct thermal_governor *governor)
|
||||
{
|
||||
@ -127,7 +126,6 @@ exit:
|
||||
mutex_unlock(&thermal_governor_lock);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_unregister_governor);
|
||||
|
||||
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
|
||||
{
|
||||
@ -1858,30 +1856,69 @@ static inline int genetlink_init(void) { return 0; }
|
||||
static inline void genetlink_exit(void) {}
|
||||
#endif /* !CONFIG_NET */
|
||||
|
||||
static int __init thermal_register_governors(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = thermal_gov_step_wise_register();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = thermal_gov_fair_share_register();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return thermal_gov_user_space_register();
|
||||
}
|
||||
|
||||
static void thermal_unregister_governors(void)
|
||||
{
|
||||
thermal_gov_step_wise_unregister();
|
||||
thermal_gov_fair_share_unregister();
|
||||
thermal_gov_user_space_unregister();
|
||||
}
|
||||
|
||||
static int __init thermal_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
int result;
|
||||
|
||||
result = thermal_register_governors();
|
||||
if (result)
|
||||
goto error;
|
||||
|
||||
result = class_register(&thermal_class);
|
||||
if (result) {
|
||||
idr_destroy(&thermal_tz_idr);
|
||||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
return result;
|
||||
}
|
||||
if (result)
|
||||
goto unregister_governors;
|
||||
|
||||
result = genetlink_init();
|
||||
if (result)
|
||||
goto unregister_class;
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_governors:
|
||||
thermal_unregister_governors();
|
||||
unregister_class:
|
||||
class_unregister(&thermal_class);
|
||||
error:
|
||||
idr_destroy(&thermal_tz_idr);
|
||||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
mutex_destroy(&thermal_governor_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit thermal_exit(void)
|
||||
{
|
||||
genetlink_exit();
|
||||
class_unregister(&thermal_class);
|
||||
thermal_unregister_governors();
|
||||
idr_destroy(&thermal_tz_idr);
|
||||
idr_destroy(&thermal_cdev_idr);
|
||||
mutex_destroy(&thermal_idr_lock);
|
||||
mutex_destroy(&thermal_list_lock);
|
||||
genetlink_exit();
|
||||
mutex_destroy(&thermal_governor_lock);
|
||||
}
|
||||
|
||||
fs_initcall(thermal_init);
|
@ -50,4 +50,31 @@ struct thermal_instance {
|
||||
struct list_head cdev_node; /* node in cdev->thermal_instances */
|
||||
};
|
||||
|
||||
int thermal_register_governor(struct thermal_governor *);
|
||||
void thermal_unregister_governor(struct thermal_governor *);
|
||||
|
||||
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
|
||||
int thermal_gov_step_wise_register(void);
|
||||
void thermal_gov_step_wise_unregister(void);
|
||||
#else
|
||||
static inline int thermal_gov_step_wise_register(void) { return 0; }
|
||||
static inline void thermal_gov_step_wise_unregister(void) {}
|
||||
#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
|
||||
|
||||
#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
|
||||
int thermal_gov_fair_share_register(void);
|
||||
void thermal_gov_fair_share_unregister(void);
|
||||
#else
|
||||
static inline int thermal_gov_fair_share_register(void) { return 0; }
|
||||
static inline void thermal_gov_fair_share_unregister(void) {}
|
||||
#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
|
||||
|
||||
#ifdef CONFIG_THERMAL_GOV_USER_SPACE
|
||||
int thermal_gov_user_space_register(void);
|
||||
void thermal_gov_user_space_unregister(void);
|
||||
#else
|
||||
static inline int thermal_gov_user_space_register(void) { return 0; }
|
||||
static inline void thermal_gov_user_space_unregister(void) {}
|
||||
#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
|
||||
|
||||
#endif /* __THERMAL_CORE_H__ */
|
||||
|
@ -22,9 +22,6 @@
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
@ -46,23 +43,15 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
|
||||
static struct thermal_governor thermal_gov_user_space = {
|
||||
.name = "user_space",
|
||||
.throttle = notify_user_space,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init thermal_gov_user_space_init(void)
|
||||
int thermal_gov_user_space_register(void)
|
||||
{
|
||||
return thermal_register_governor(&thermal_gov_user_space);
|
||||
}
|
||||
|
||||
static void __exit thermal_gov_user_space_exit(void)
|
||||
void thermal_gov_user_space_unregister(void)
|
||||
{
|
||||
thermal_unregister_governor(&thermal_gov_user_space);
|
||||
}
|
||||
|
||||
/* This should load after thermal framework */
|
||||
fs_initcall(thermal_gov_user_space_init);
|
||||
module_exit(thermal_gov_user_space_exit);
|
||||
|
||||
MODULE_AUTHOR("Durgadoss R");
|
||||
MODULE_DESCRIPTION("A user space Thermal notifier");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -29,7 +29,7 @@
|
||||
#define CPUFREQ_COOLING_START 0
|
||||
#define CPUFREQ_COOLING_STOP 1
|
||||
|
||||
#if defined(CONFIG_CPU_THERMAL) || defined(CONFIG_CPU_THERMAL_MODULE)
|
||||
#ifdef CONFIG_CPU_THERMAL
|
||||
/**
|
||||
* cpufreq_cooling_register - function to create cpufreq cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
@ -42,6 +42,8 @@ struct thermal_cooling_device *cpufreq_cooling_register(
|
||||
* @cdev: thermal cooling device pointer.
|
||||
*/
|
||||
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
|
||||
|
||||
unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int);
|
||||
#else /* !CONFIG_CPU_THERMAL */
|
||||
static inline struct thermal_cooling_device *cpufreq_cooling_register(
|
||||
const struct cpumask *clip_cpus)
|
||||
@ -53,6 +55,11 @@ static inline void cpufreq_cooling_unregister(
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline unsigned long cpufreq_cooling_get_level(unsigned int,
|
||||
unsigned int)
|
||||
{
|
||||
return THERMAL_CSTATE_INVALID;
|
||||
}
|
||||
#endif /* CONFIG_CPU_THERMAL */
|
||||
|
||||
#endif /* __CPU_COOLING_H__ */
|
||||
|
@ -33,8 +33,11 @@
|
||||
#define THERMAL_MAX_TRIPS 12
|
||||
#define THERMAL_NAME_LENGTH 20
|
||||
|
||||
/* invalid cooling state */
|
||||
#define THERMAL_CSTATE_INVALID -1UL
|
||||
|
||||
/* No upper/lower limit requirement */
|
||||
#define THERMAL_NO_LIMIT -1UL
|
||||
#define THERMAL_NO_LIMIT THERMAL_CSTATE_INVALID
|
||||
|
||||
/* Unit conversion macros */
|
||||
#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
|
||||
@ -184,7 +187,6 @@ struct thermal_governor {
|
||||
char name[THERMAL_NAME_LENGTH];
|
||||
int (*throttle)(struct thermal_zone_device *tz, int trip);
|
||||
struct list_head governor_list;
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
/* Structure that holds binding parameters for a zone */
|
||||
@ -244,9 +246,6 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
|
||||
void thermal_cdev_update(struct thermal_cooling_device *);
|
||||
void notify_thermal_framework(struct thermal_zone_device *, int);
|
||||
|
||||
int thermal_register_governor(struct thermal_governor *);
|
||||
void thermal_unregister_governor(struct thermal_governor *);
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
|
||||
enum events event);
|
||||
|
Loading…
Reference in New Issue
Block a user