Skip to content

Commit

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

Pull thermal management update from Zhang Rui:
 "Specifics:

   - fix a bug in Exynos thermal driver, which overwrites the hardware
     trip point threshold when updating software trigger levels and
     results in emergency shutdown.  From: Tushar Behera.

   - add thermal sensor support for Armada 375 and 38x SoCs.  From
     Ezequiel Garcia.

   - add TMU (Thermal Management Unit) support for Exynos5260 and
     Exynos5420 SoCs.  From Naveen Krishna Chatradhi.

   - add support for the additional digital temperature sensors in the
     Intel SoCs like Bay Trail.  From: Srinivas Pandruvada.

   - a couple of cleanups and small fixes from Jingoo Han, Bartlomiej
     Zolnierkiewicz, Geert Uytterhoeven, Jacob Pan, Paul Walmsley and
     Lan,Tianyu"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (21 commits)
  thermal: spear: remove unnecessary OOM messages
  thermal: exynos: remove unnecessary OOM messages
  thermal: rcar: remove unnecessary OOM messages
  thermal: armada: Support Armada 380 SoC
  thermal: armada: Support Armada 375 SoC
  thermal: armada: Allow to specify an 'inverted readout' sensor
  thermal: armada: Pass the platform_device to init_sensor()
  thermal: armada: Add generic infrastructure to handle the sensor
  thermal: armada: Add infrastructure to support generic formulas
  thermal: armada: Rename armada_thermal_ops struct
  thermal/intel_powerclamp: add newer cpu ids
  thermal: rcar: Use pm_runtime_put() i.s.o. pm_runtime_put_sync()
  thermal: samsung: Only update available threshold limits
  Thermal/int3403: Fix thermal hysteresis unit conversion
  thermal: Intel SoC DTS thermal
  thermal: samsung: Add TMU support for Exynos5260 SoCs
  thermal: samsung: Add TMU support for Exynos5420 SoCs
  thermal: samsung: change base_common to more meaningful base_second
  thermal: samsung: replace inten_ bit fields with intclr_
  thermal: offer Samsung thermal support only when ARCH_EXYNOS is defined
  ...
  • Loading branch information
Linus Torvalds committed Jun 11, 2014
2 parents 7f33e72 + 63745aa commit c31c24b
Show file tree
Hide file tree
Showing 15 changed files with 1,015 additions and 75 deletions.
12 changes: 11 additions & 1 deletion Documentation/devicetree/bindings/thermal/armada-thermal.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
* Marvell Armada 370/XP thermal management
* Marvell Armada 370/375/380/XP thermal management

Required properties:

- compatible: Should be set to one of the following:
marvell,armada370-thermal
marvell,armada375-thermal
marvell,armada375-z1-thermal
marvell,armada380-thermal
marvell,armadaxp-thermal

Note: As the name suggests, "marvell,armada375-z1-thermal"
applies for the SoC Z1 stepping only. On such stepping
some quirks need to be done and the register offset differs
from the one in the A0 stepping.
The operating system may auto-detect the SoC stepping and
update the compatible and register offsets at runtime.

- reg: Device's register space.
Two entries are expected, see the examples below.
The first one is required for the sensor register;
Expand Down
50 changes: 47 additions & 3 deletions Documentation/devicetree/bindings/thermal/exynos-thermal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,35 @@
"samsung,exynos4412-tmu"
"samsung,exynos4210-tmu"
"samsung,exynos5250-tmu"
"samsung,exynos5260-tmu"
"samsung,exynos5420-tmu" for TMU channel 0, 1 on Exynos5420
"samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
Exynos5420 (Must pass triminfo base and triminfo clock)
"samsung,exynos5440-tmu"
- interrupt-parent : The phandle for the interrupt controller
- reg : Address range of the thermal registers. For soc's which has multiple
instances of TMU and some registers are shared across all TMU's like
interrupt related then 2 set of register has to supplied. First set
belongs to each instance of TMU and second set belongs to common TMU
registers.
belongs to register set of TMU instance and second set belongs to
registers shared with the TMU instance.

NOTE: On Exynos5420, the TRIMINFO register is misplaced for TMU
channels 2, 3 and 4
Use "samsung,exynos5420-tmu-ext-triminfo" in cases, there is a misplaced
register, also provide clock to access that base.

TRIMINFO at 0x1006c000 contains data for TMU channel 3
TRIMINFO at 0x100a0000 contains data for TMU channel 4
TRIMINFO at 0x10068000 contains data for TMU channel 2

- interrupts : Should contain interrupt for thermal system
- clocks : The main clock for TMU device
- clocks : The main clocks for TMU device
-- 1. operational clock for TMU channel
-- 2. optional clock to access the shared registers of TMU channel
- clock-names : Thermal system clock name
-- "tmu_apbif" operational clock for current TMU channel
-- "tmu_triminfo_apbif" clock to access the shared triminfo register
for current TMU channel
- vtmu-supply: This entry is optional and provides the regulator node supplying
voltage to TMU. If needed this entry can be placed inside
board/platform specific dts file.
Expand Down Expand Up @@ -43,6 +62,31 @@ Example 2):
clock-names = "tmu_apbif";
};

Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register")
tmu_cpu2: tmu@10068000 {
compatible = "samsung,exynos5420-tmu-ext-triminfo";
reg = <0x10068000 0x100>, <0x1006c000 0x4>;
interrupts = <0 184 0>;
clocks = <&clock 318>, <&clock 318>;
clock-names = "tmu_apbif", "tmu_triminfo_apbif";
};

tmu_cpu3: tmu@1006c000 {
compatible = "samsung,exynos5420-tmu-ext-triminfo";
reg = <0x1006c000 0x100>, <0x100a0000 0x4>;
interrupts = <0 185 0>;
clocks = <&clock 318>, <&clock 319>;
clock-names = "tmu_apbif", "tmu_triminfo_apbif";
};

tmu_gpu: tmu@100a0000 {
compatible = "samsung,exynos5420-tmu-ext-triminfo";
reg = <0x100a0000 0x100>, <0x10068000 0x4>;
interrupts = <0 215 0>;
clocks = <&clock 319>, <&clock 318>;
clock-names = "tmu_apbif", "tmu_triminfo_apbif";
};

Note: For multi-instance tmu each instance should have an alias correctly
numbered in "aliases" node.

Expand Down
14 changes: 13 additions & 1 deletion drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,24 @@ config ACPI_INT3403_THERMAL
the Intel Thermal Daemon can use this information to allow the user
to select his laptop to run without turning on the fans.

config INTEL_SOC_DTS_THERMAL
tristate "Intel SoCs DTS thermal driver"
depends on X86 && IOSF_MBI
help
Enable this to register Intel SoCs (e.g. Bay Trail) platform digital
temperature sensor (DTS). These SoCs have two additional DTSs in
addition to DTSs on CPU cores. Each DTS will be registered as a
thermal zone. There are two trip points. One of the trip point can
be set by user mode programs to get notifications via Linux thermal
notification methods.The other trip is a critical trip point, which
was set by the driver based on the TJ MAX temperature.

menu "Texas Instruments thermal drivers"
source "drivers/thermal/ti-soc-thermal/Kconfig"
endmenu

menu "Samsung thermal drivers"
depends on PLAT_SAMSUNG
depends on ARCH_EXYNOS
source "drivers/thermal/samsung/Kconfig"
endmenu

Expand Down
1 change: 1 addition & 0 deletions drivers/thermal/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ obj-$(CONFIG_IMX_THERMAL) += imx_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_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o
158 changes: 139 additions & 19 deletions drivers/thermal/armada_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@
#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)
Expand All @@ -38,24 +35,47 @@
#define PMU_TDC0_OTF_CAL_MASK (0x1 << 30)
#define PMU_TDC0_START_CAL_MASK (0x1 << 25)

struct armada_thermal_ops;
#define A375_Z1_CAL_RESET_LSB 0x8011e214
#define A375_Z1_CAL_RESET_MSB 0x30a88019
#define A375_Z1_WORKAROUND_BIT BIT(9)

#define A375_UNIT_CONTROL_SHIFT 27
#define A375_UNIT_CONTROL_MASK 0x7
#define A375_READOUT_INVERT BIT(15)
#define A375_HW_RESETn BIT(8)
#define A380_HW_RESET BIT(8)

struct armada_thermal_data;

/* Marvell EBU Thermal Sensor Dev Structure */
struct armada_thermal_priv {
void __iomem *sensor;
void __iomem *control;
struct armada_thermal_ops *ops;
struct armada_thermal_data *data;
};

struct armada_thermal_ops {
struct armada_thermal_data {
/* Initialize the sensor */
void (*init_sensor)(struct armada_thermal_priv *);
void (*init_sensor)(struct platform_device *pdev,
struct armada_thermal_priv *);

/* Test for a valid sensor value (optional) */
bool (*is_valid)(struct armada_thermal_priv *);

/* Formula coeficients: temp = (b + m * reg) / div */
unsigned long coef_b;
unsigned long coef_m;
unsigned long coef_div;
bool inverted;

/* Register shift and mask to access the sensor temperature */
unsigned int temp_shift;
unsigned int temp_mask;
unsigned int is_valid_shift;
};

static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
static void armadaxp_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
unsigned long reg;

Expand All @@ -80,7 +100,8 @@ static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
writel(reg, priv->sensor);
}

static void armada370_init_sensor(struct armada_thermal_priv *priv)
static void armada370_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
unsigned long reg;

Expand All @@ -99,53 +120,152 @@ static void armada370_init_sensor(struct armada_thermal_priv *priv)
mdelay(10);
}

static void armada375_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
unsigned long reg;
bool quirk_needed =
!!of_device_is_compatible(pdev->dev.of_node,
"marvell,armada375-z1-thermal");

if (quirk_needed) {
/* Ensure these registers have the default (reset) values */
writel(A375_Z1_CAL_RESET_LSB, priv->control);
writel(A375_Z1_CAL_RESET_MSB, priv->control + 0x4);
}

reg = readl(priv->control + 4);
reg &= ~(A375_UNIT_CONTROL_MASK << A375_UNIT_CONTROL_SHIFT);
reg &= ~A375_READOUT_INVERT;
reg &= ~A375_HW_RESETn;

if (quirk_needed)
reg |= A375_Z1_WORKAROUND_BIT;

writel(reg, priv->control + 4);
mdelay(20);

reg |= A375_HW_RESETn;
writel(reg, priv->control + 4);
mdelay(50);
}

static void armada380_init_sensor(struct platform_device *pdev,
struct armada_thermal_priv *priv)
{
unsigned long reg = readl_relaxed(priv->control);

/* Reset hardware once */
if (!(reg & A380_HW_RESET)) {
reg |= A380_HW_RESET;
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;
return (reg >> priv->data->is_valid_shift) & 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;
unsigned long m, b, div;

/* Valid check */
if (priv->ops->is_valid && !priv->ops->is_valid(priv)) {
if (priv->data->is_valid && !priv->data->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;
reg = (reg >> priv->data->temp_shift) & priv->data->temp_mask;

/* Get formula coeficients */
b = priv->data->coef_b;
m = priv->data->coef_m;
div = priv->data->coef_div;

if (priv->data->inverted)
*temp = ((m * reg) - b) / div;
else
*temp = (b - (m * reg)) / div;
return 0;
}

static struct thermal_zone_device_ops ops = {
.get_temp = armada_get_temp,
};

static const struct armada_thermal_ops armadaxp_ops = {
static const struct armada_thermal_data armadaxp_data = {
.init_sensor = armadaxp_init_sensor,
.temp_shift = 10,
.temp_mask = 0x1ff,
.coef_b = 3153000000UL,
.coef_m = 10000000UL,
.coef_div = 13825,
};

static const struct armada_thermal_ops armada370_ops = {
static const struct armada_thermal_data armada370_data = {
.is_valid = armada_is_valid,
.init_sensor = armada370_init_sensor,
.is_valid_shift = 9,
.temp_shift = 10,
.temp_mask = 0x1ff,
.coef_b = 3153000000UL,
.coef_m = 10000000UL,
.coef_div = 13825,
};

static const struct armada_thermal_data armada375_data = {
.is_valid = armada_is_valid,
.init_sensor = armada375_init_sensor,
.is_valid_shift = 10,
.temp_shift = 0,
.temp_mask = 0x1ff,
.coef_b = 3171900000UL,
.coef_m = 10000000UL,
.coef_div = 13616,
};

static const struct armada_thermal_data armada380_data = {
.is_valid = armada_is_valid,
.init_sensor = armada380_init_sensor,
.is_valid_shift = 10,
.temp_shift = 0,
.temp_mask = 0x3ff,
.coef_b = 1169498786UL,
.coef_m = 2000000UL,
.coef_div = 4289,
.inverted = true,
};

static const struct of_device_id armada_thermal_id_table[] = {
{
.compatible = "marvell,armadaxp-thermal",
.data = &armadaxp_ops,
.data = &armadaxp_data,
},
{
.compatible = "marvell,armada370-thermal",
.data = &armada370_ops,
.data = &armada370_data,
},
{
.compatible = "marvell,armada375-thermal",
.data = &armada375_data,
},
{
.compatible = "marvell,armada375-z1-thermal",
.data = &armada375_data,
},
{
.compatible = "marvell,armada380-thermal",
.data = &armada380_data,
},
{
/* sentinel */
Expand Down Expand Up @@ -178,8 +298,8 @@ static int armada_thermal_probe(struct platform_device *pdev)
if (IS_ERR(priv->control))
return PTR_ERR(priv->control);

priv->ops = (struct armada_thermal_ops *)match->data;
priv->ops->init_sensor(priv);
priv->data = (struct armada_thermal_data *)match->data;
priv->data->init_sensor(pdev, priv);

thermal = thermal_zone_device_register("armada_thermal", 0, 0,
priv, &ops, NULL, 0, 0);
Expand Down
8 changes: 7 additions & 1 deletion drivers/thermal/int3403_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
if (ACPI_FAILURE(status))
return -EIO;

*temp = DECI_KELVIN_TO_MILLI_CELSIUS(hyst, KELVIN_OFFSET);
/*
* Thermal hysteresis represents a temperature difference.
* Kelvin and Celsius have same degree size. So the
* conversion here between tenths of degree Kelvin unit
* and Milli-Celsius unit is just to multiply 100.
*/
*temp = hyst * 100;

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/thermal/intel_powerclamp.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,10 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
{ X86_VENDOR_INTEL, 6, 0x2d},
{ X86_VENDOR_INTEL, 6, 0x2e},
{ X86_VENDOR_INTEL, 6, 0x2f},
{ X86_VENDOR_INTEL, 6, 0x37},
{ X86_VENDOR_INTEL, 6, 0x3a},
{ X86_VENDOR_INTEL, 6, 0x3c},
{ X86_VENDOR_INTEL, 6, 0x3d},
{ X86_VENDOR_INTEL, 6, 0x3e},
{ X86_VENDOR_INTEL, 6, 0x3f},
{ X86_VENDOR_INTEL, 6, 0x45},
Expand Down
Loading

0 comments on commit c31c24b

Please sign in to comment.