Skip to content

Commit

Permalink
Merge branch 'thermal' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/rzhang/linux into next

Conflicts:
	drivers/thermal/cpu_cooling.c
  • Loading branch information
Zhang Rui committed Apr 15, 2013
2 parents 2fd1db8 + bbf7fc8 commit d13cb03
Show file tree
Hide file tree
Showing 16 changed files with 578 additions and 261 deletions.
22 changes: 22 additions & 0 deletions Documentation/devicetree/bindings/thermal/armada-thermal.txt
Original file line number Diff line number Diff line change
@@ -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";
};
8 changes: 4 additions & 4 deletions Documentation/thermal/exynos_thermal_emulation
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 4 additions & 8 deletions Documentation/thermal/sysfs-api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
*****************************
Expand Down Expand Up @@ -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.
23 changes: 13 additions & 10 deletions drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
10 changes: 6 additions & 4 deletions drivers/thermal/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 changes: 232 additions & 0 deletions drivers/thermal/armada_thermal.c
Original file line number Diff line number Diff line change
@@ -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");
Loading

0 comments on commit d13cb03

Please sign in to comment.