Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
b82ddd48
Commit
b82ddd48
authored
Mar 15, 2016
by
Zhang Rui
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'thermal-core', 'thermal-intel' and 'thermal-soc' into next
parents
d0b45880
4cba7d23
032f4a1e
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1037 additions
and
118 deletions
+1037
-118
Documentation/devicetree/bindings/thermal/exynos-thermal.txt
Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+15
-3
Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
...entation/devicetree/bindings/thermal/mediatek-thermal.txt
+43
-0
Documentation/thermal/sysfs-api.txt
Documentation/thermal/sysfs-api.txt
+68
-0
drivers/thermal/Kconfig
drivers/thermal/Kconfig
+19
-2
drivers/thermal/Makefile
drivers/thermal/Makefile
+1
-0
drivers/thermal/intel_pch_thermal.c
drivers/thermal/intel_pch_thermal.c
+6
-0
drivers/thermal/mtk_thermal.c
drivers/thermal/mtk_thermal.c
+625
-0
drivers/thermal/of-thermal.c
drivers/thermal/of-thermal.c
+81
-0
drivers/thermal/rcar_thermal.c
drivers/thermal/rcar_thermal.c
+1
-2
drivers/thermal/rockchip_thermal.c
drivers/thermal/rockchip_thermal.c
+136
-103
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/Kconfig
+1
-0
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/samsung/exynos_tmu.c
+18
-1
drivers/thermal/tegra_soctherm.c
drivers/thermal/tegra_soctherm.c
+1
-1
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
+4
-6
include/linux/thermal.h
include/linux/thermal.h
+18
-0
No files found.
Documentation/devicetree/bindings/thermal/exynos-thermal.txt
View file @
b82ddd48
...
...
@@ -11,6 +11,7 @@
"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,exynos5433-tmu"
"samsung,exynos5440-tmu"
"samsung,exynos7-tmu"
- interrupt-parent : The phandle for the interrupt controller
...
...
@@ -40,9 +41,14 @@
for current TMU channel
-- "tmu_sclk" clock for functional operation of the 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.
The Exynos TMU supports generating interrupts when reaching given
temperature thresholds. Number of supported thermal trip points depends
on the SoC (only first trip points defined in DT will be configured):
- most of SoC: 4
- samsung,exynos5433-tmu: 8
- samsung,exynos7-tmu: 8
Following properties are mandatory (depending on SoC):
- samsung,tmu_gain: Gain value for internal TMU operation.
- samsung,tmu_reference_voltage: Value of TMU IP block's reference voltage
...
...
@@ -56,6 +62,12 @@ Following properties are mandatory (depending on SoC):
- samsung,tmu_default_temp_offset: Default temperature offset
- samsung,tmu_cal_type: Callibration type
** Optional properties:
- 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.
Example 1):
tmu@100C0000 {
...
...
Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
0 → 100644
View file @
b82ddd48
* Mediatek Thermal
This describes the device tree binding for the Mediatek thermal controller
which measures the on-SoC temperatures. This device does not have its own ADC,
instead it directly controls the AUXADC via AHB bus accesses. For this reason
this device needs phandles to the AUXADC. Also it controls a mux in the
apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS
is also needed.
Required properties:
- compatible: "mediatek,mt8173-thermal"
- reg: Address range of the thermal controller
- interrupts: IRQ for the thermal controller
- clocks, clock-names: Clocks needed for the thermal controller. required
clocks are:
"therm": Main clock needed for register access
"auxadc": The AUXADC clock
- resets: Reference to the reset controller controlling the thermal controller.
- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses
- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller.
- #thermal-sensor-cells : Should be 0. See ./thermal.txt for a description.
Optional properties:
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
unspecified default values shall be used.
- nvmem-cell-names: Should be "calibration-data"
Example:
thermal: thermal@1100b000 {
#thermal-sensor-cells = <1>;
compatible = "mediatek,mt8173-thermal";
reg = <0 0x1100b000 0 0x1000>;
interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
clock-names = "therm", "auxadc";
resets = <&pericfg MT8173_PERI_THERM_SW_RST>;
reset-names = "therm";
mediatek,auxadc = <&auxadc>;
mediatek,apmixedsys = <&apmixedsys>;
nvmem-cells = <&thermal_calibration_data>;
nvmem-cell-names = "calibration-data";
};
Documentation/thermal/sysfs-api.txt
View file @
b82ddd48
...
...
@@ -72,6 +72,74 @@ temperature) and throttle appropriate devices.
It deletes the corresponding entry form /sys/class/thermal folder and
unbind all the thermal cooling devices it uses.
1.1.3 struct thermal_zone_device *thermal_zone_of_sensor_register(
struct device *dev, int sensor_id, void *data,
const struct thermal_zone_of_device_ops *ops)
This interface adds a new sensor to a DT thermal zone.
This function will search the list of thermal zones described in
device tree and look for the zone that refer to the sensor device
pointed by dev->of_node as temperature providers. For the zone
pointing to the sensor node, the sensor will be added to the DT
thermal zone device.
The parameters for this interface are:
dev: Device node of sensor containing valid node pointer in
dev->of_node.
sensor_id: a sensor identifier, in case the sensor IP has more
than one sensors
data: a private pointer (owned by the caller) that will be
passed back, when a temperature reading is needed.
ops: struct thermal_zone_of_device_ops *.
get_temp: a pointer to a function that reads the
sensor temperature. This is mandatory
callback provided by sensor driver.
get_trend: a pointer to a function that reads the
sensor temperature trend.
set_emul_temp: a pointer to a function that sets
sensor emulated temperature.
The thermal zone temperature is provided by the get_temp() function
pointer of thermal_zone_of_device_ops. When called, it will
have the private pointer @data back.
It returns error pointer if fails otherwise valid thermal zone device
handle. Caller should check the return handle with IS_ERR() for finding
whether success or not.
1.1.4 void thermal_zone_of_sensor_unregister(struct device *dev,
struct thermal_zone_device *tzd)
This interface unregisters a sensor from a DT thermal zone which was
successfully added by interface thermal_zone_of_sensor_register().
This function removes the sensor callbacks and private data from the
thermal zone device registered with thermal_zone_of_sensor_register()
interface. It will also silent the zone by remove the .get_temp() and
get_trend() thermal zone device callbacks.
1.1.5 struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
struct device *dev, int sensor_id,
void *data, const struct thermal_zone_of_device_ops *ops)
This interface is resource managed version of
thermal_zone_of_sensor_register().
All details of thermal_zone_of_sensor_register() described in
section 1.1.3 is applicable here.
The benefit of using this interface to register sensor is that it
is not require to explicitly call thermal_zone_of_sensor_unregister()
in error path or during driver unbinding as this is done by driver
resource manager.
1.1.6 void devm_thermal_zone_of_sensor_unregister(struct device *dev,
struct thermal_zone_device *tzd)
This interface is resource managed version of
thermal_zone_of_sensor_unregister().
All details of thermal_zone_of_sensor_unregister() described in
section 1.1.4 is applicable here.
Normally this function will not need to be called and the resource
management code will ensure that the resource is freed.
1.2 thermal cooling device interface
1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
void *devdata, struct thermal_cooling_device_ops *)
...
...
drivers/thermal/Kconfig
View file @
b82ddd48
...
...
@@ -178,6 +178,7 @@ config THERMAL_EMULATION
config HISI_THERMAL
tristate "Hisilicon thermal driver"
depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST
depends on HAS_IOMEM
help
Enable this to plug hisilicon's thermal sensor driver into the Linux
thermal framework. cpufreq is used as the cooling device to throttle
...
...
@@ -197,6 +198,7 @@ config IMX_THERMAL
config SPEAR_THERMAL
tristate "SPEAr thermal sensor driver"
depends on PLAT_SPEAR || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Enable this to plug the SPEAr thermal sensor driver into the Linux
...
...
@@ -206,6 +208,7 @@ config ROCKCHIP_THERMAL
tristate "Rockchip thermal driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on RESET_CONTROLLER
depends on HAS_IOMEM
help
Rockchip thermal driver provides support for Temperature sensor
ADC (TS-ADC) found on Rockchip SoCs. It supports one critical
...
...
@@ -214,7 +217,7 @@ config ROCKCHIP_THERMAL
config RCAR_THERMAL
tristate "Renesas R-Car thermal driver"
depends on ARCH_
SHMOBILE
|| COMPILE_TEST
depends on ARCH_
RENESAS
|| COMPILE_TEST
depends on HAS_IOMEM
help
Enable this to plug the R-Car thermal sensor driver into the Linux
...
...
@@ -223,6 +226,7 @@ config RCAR_THERMAL
config KIRKWOOD_THERMAL
tristate "Temperature sensor on Marvell Kirkwood SoCs"
depends on MACH_KIRKWOOD || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Support for the Kirkwood thermal sensor driver into the Linux thermal
...
...
@@ -231,6 +235,7 @@ config KIRKWOOD_THERMAL
config DOVE_THERMAL
tristate "Temperature sensor on Marvell Dove SoCs"
depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Support for the Dove thermal sensor driver in the Linux thermal
...
...
@@ -249,6 +254,7 @@ config DB8500_THERMAL
config ARMADA_THERMAL
tristate "Armada 370/XP thermal management"
depends on ARCH_MVEBU || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
Enable this option if you want to have support for thermal management
...
...
@@ -266,7 +272,8 @@ config TEGRA_SOCTHERM
config DB8500_CPUFREQ_COOLING
tristate "DB8500 cpufreq cooling"
depends on ARCH_U8500
depends on ARCH_U8500 || COMPILE_TEST
depends on HAS_IOMEM
depends on CPU_THERMAL
default y
help
...
...
@@ -365,8 +372,18 @@ config INTEL_PCH_THERMAL
Thermal reporting device will provide temperature reading,
programmable trip points and other information.
config MTK_THERMAL
tristate "Temperature sensor driver for mediatek SoCs"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM
default y
help
Enable this option if you want to have support for thermal management
controller present in Mediatek SoCs
menu "Texas Instruments thermal drivers"
depends on ARCH_HAS_BANDGAP || COMPILE_TEST
depends on HAS_IOMEM
source "drivers/thermal/ti-soc-thermal/Kconfig"
endmenu
...
...
drivers/thermal/Makefile
View file @
b82ddd48
...
...
@@ -48,3 +48,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
obj-$(CONFIG_ST_THERMAL)
+=
st/
obj-$(CONFIG_TEGRA_SOCTHERM)
+=
tegra_soctherm.o
obj-$(CONFIG_HISI_THERMAL)
+=
hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL)
+=
mtk_thermal.o
drivers/thermal/intel_pch_thermal.c
View file @
b82ddd48
...
...
@@ -24,6 +24,7 @@
/* Intel PCH thermal Device IDs */
#define PCH_THERMAL_DID_WPT 0x9CA4
/* Wildcat Point */
#define PCH_THERMAL_DID_SKL 0x9D31
/* Skylake PCH */
/* Wildcat Point-LP PCH Thermal registers */
#define WPT_TEMP 0x0000
/* Temperature */
...
...
@@ -201,6 +202,10 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev,
ptd
->
ops
=
&
pch_dev_ops_wpt
;
dev_name
=
"pch_wildcat_point"
;
break
;
case
PCH_THERMAL_DID_SKL
:
ptd
->
ops
=
&
pch_dev_ops_wpt
;
dev_name
=
"pch_skylake"
;
break
;
default:
dev_err
(
&
pdev
->
dev
,
"unknown pch thermal device
\n
"
);
return
-
ENODEV
;
...
...
@@ -266,6 +271,7 @@ static void intel_pch_thermal_remove(struct pci_dev *pdev)
static
struct
pci_device_id
intel_pch_thermal_id
[]
=
{
{
PCI_DEVICE
(
PCI_VENDOR_ID_INTEL
,
PCH_THERMAL_DID_WPT
)
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_INTEL
,
PCH_THERMAL_DID_SKL
)
},
{
0
,
},
};
MODULE_DEVICE_TABLE
(
pci
,
intel_pch_thermal_id
);
...
...
drivers/thermal/mtk_thermal.c
0 → 100644
View file @
b82ddd48
/*
* Copyright (c) 2015 MediaTek Inc.
* Author: Hanyi Wu <hanyi.wu@mediatek.com>
* Sascha Hauer <s.hauer@pengutronix.de>
*
* 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/thermal.h>
#include <linux/reset.h>
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
/* AUXADC Registers */
#define AUXADC_CON0_V 0x000
#define AUXADC_CON1_V 0x004
#define AUXADC_CON1_SET_V 0x008
#define AUXADC_CON1_CLR_V 0x00c
#define AUXADC_CON2_V 0x010
#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
#define AUXADC_MISC_V 0x094
#define AUXADC_CON1_CHANNEL(x) BIT(x)
#define APMIXED_SYS_TS_CON1 0x604
/* Thermal Controller Registers */
#define TEMP_MONCTL0 0x000
#define TEMP_MONCTL1 0x004
#define TEMP_MONCTL2 0x008
#define TEMP_MONIDET0 0x014
#define TEMP_MONIDET1 0x018
#define TEMP_MSRCTL0 0x038
#define TEMP_AHBPOLL 0x040
#define TEMP_AHBTO 0x044
#define TEMP_ADCPNP0 0x048
#define TEMP_ADCPNP1 0x04c
#define TEMP_ADCPNP2 0x050
#define TEMP_ADCPNP3 0x0b4
#define TEMP_ADCMUX 0x054
#define TEMP_ADCEN 0x060
#define TEMP_PNPMUXADDR 0x064
#define TEMP_ADCMUXADDR 0x068
#define TEMP_ADCENADDR 0x074
#define TEMP_ADCVALIDADDR 0x078
#define TEMP_ADCVOLTADDR 0x07c
#define TEMP_RDCTRL 0x080
#define TEMP_ADCVALIDMASK 0x084
#define TEMP_ADCVOLTAGESHIFT 0x088
#define TEMP_ADCWRITECTRL 0x08c
#define TEMP_MSR0 0x090
#define TEMP_MSR1 0x094
#define TEMP_MSR2 0x098
#define TEMP_MSR3 0x0B8
#define TEMP_SPARE0 0x0f0
#define PTPCORESEL 0x400
#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff)
#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16)
#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff)
#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x)
#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0)
#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1)
#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5)
#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit)
#define MT8173_TS1 0
#define MT8173_TS2 1
#define MT8173_TS3 2
#define MT8173_TS4 3
#define MT8173_TSABB 4
/* AUXADC channel 11 is used for the temperature sensors */
#define MT8173_TEMP_AUXADC_CHANNEL 11
/* The total number of temperature sensors in the MT8173 */
#define MT8173_NUM_SENSORS 5
/* The number of banks in the MT8173 */
#define MT8173_NUM_ZONES 4
/* The number of sensing points per bank */
#define MT8173_NUM_SENSORS_PER_ZONE 4
/* Layout of the fuses providing the calibration data */
#define MT8173_CALIB_BUF0_VALID BIT(0)
#define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff)
#define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff)
#define MT8173_CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff)
#define MT8173_CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff)
#define MT8173_CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff)
#define MT8173_CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff)
#define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f)
#define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f)
#define THERMAL_NAME "mtk-thermal"
struct
mtk_thermal
;
struct
mtk_thermal_bank
{
struct
mtk_thermal
*
mt
;
int
id
;
};
struct
mtk_thermal
{
struct
device
*
dev
;
void
__iomem
*
thermal_base
;
struct
clk
*
clk_peri_therm
;
struct
clk
*
clk_auxadc
;
struct
mtk_thermal_bank
banks
[
MT8173_NUM_ZONES
];
/* lock: for getting and putting banks */
struct
mutex
lock
;
/* Calibration values */
s32
adc_ge
;
s32
degc_cali
;
s32
o_slope
;
s32
vts
[
MT8173_NUM_SENSORS
];
struct
thermal_zone_device
*
tzd
;
};
struct
mtk_thermal_bank_cfg
{
unsigned
int
num_sensors
;
unsigned
int
sensors
[
MT8173_NUM_SENSORS_PER_ZONE
];
};
static
const
int
sensor_mux_values
[
MT8173_NUM_SENSORS
]
=
{
0
,
1
,
2
,
3
,
16
};
/*
* The MT8173 thermal controller has four banks. Each bank can read up to
* four temperature sensors simultaneously. The MT8173 has a total of 5
* temperature sensors. We use each bank to measure a certain area of the
* SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
* areas, hence is used in different banks.
*
* The thermal core only gets the maximum temperature of all banks, so
* the bank concept wouldn't be necessary here. However, the SVS (Smart
* Voltage Scaling) unit makes its decisions based on the same bank
* data, and this indeed needs the temperatures of the individual banks
* for making better decisions.
*/
static
const
struct
mtk_thermal_bank_cfg
bank_data
[]
=
{
{
.
num_sensors
=
2
,
.
sensors
=
{
MT8173_TS2
,
MT8173_TS3
},
},
{
.
num_sensors
=
2
,
.
sensors
=
{
MT8173_TS2
,
MT8173_TS4
},
},
{
.
num_sensors
=
3
,
.
sensors
=
{
MT8173_TS1
,
MT8173_TS2
,
MT8173_TSABB
},
},
{
.
num_sensors
=
1
,
.
sensors
=
{
MT8173_TS2
},
},
};
struct
mtk_thermal_sense_point
{
int
msr
;
int
adcpnp
;
};
static
const
struct
mtk_thermal_sense_point
sensing_points
[
MT8173_NUM_SENSORS_PER_ZONE
]
=
{
{
.
msr
=
TEMP_MSR0
,
.
adcpnp
=
TEMP_ADCPNP0
,
},
{
.
msr
=
TEMP_MSR1
,
.
adcpnp
=
TEMP_ADCPNP1
,
},
{
.
msr
=
TEMP_MSR2
,
.
adcpnp
=
TEMP_ADCPNP2
,
},
{
.
msr
=
TEMP_MSR3
,
.
adcpnp
=
TEMP_ADCPNP3
,
},
};
/**
* raw_to_mcelsius - convert a raw ADC value to mcelsius
* @mt: The thermal controller
* @raw: raw ADC value
*
* This converts the raw ADC value to mcelsius using the SoC specific
* calibration constants
*/
static
int
raw_to_mcelsius
(
struct
mtk_thermal
*
mt
,
int
sensno
,
s32
raw
)
{
s32
tmp
;
raw
&=
0xfff
;
tmp
=
203450520
<<
3
;
tmp
/=
165
+
mt
->
o_slope
;
tmp
/=
10000
+
mt
->
adc_ge
;
tmp
*=
raw
-
mt
->
vts
[
sensno
]
-
3350
;
tmp
>>=
3
;
return
mt
->
degc_cali
*
500
-
tmp
;
}
/**
* mtk_thermal_get_bank - get bank
* @bank: The bank
*
* The bank registers are banked, we have to select a bank in the
* PTPCORESEL register to access it.
*/
static
void
mtk_thermal_get_bank
(
struct
mtk_thermal_bank
*
bank
)
{
struct
mtk_thermal
*
mt
=
bank
->
mt
;
u32
val
;
mutex_lock
(
&
mt
->
lock
);
val
=
readl
(
mt
->
thermal_base
+
PTPCORESEL
);
val
&=
~
0xf
;
val
|=
bank
->
id
;
writel
(
val
,
mt
->
thermal_base
+
PTPCORESEL
);
}
/**
* mtk_thermal_put_bank - release bank
* @bank: The bank
*
* release a bank previously taken with mtk_thermal_get_bank,
*/
static
void
mtk_thermal_put_bank
(
struct
mtk_thermal_bank
*
bank
)
{
struct
mtk_thermal
*
mt
=
bank
->
mt
;
mutex_unlock
(
&
mt
->
lock
);
}
/**
* mtk_thermal_bank_temperature - get the temperature of a bank
* @bank: The bank
*
* The temperature of a bank is considered the maximum temperature of
* the sensors associated to the bank.
*/
static
int
mtk_thermal_bank_temperature
(
struct
mtk_thermal_bank
*
bank
)
{
struct
mtk_thermal
*
mt
=
bank
->
mt
;
int
i
,
temp
=
INT_MIN
,
max
=
INT_MIN
;
u32
raw
;
for
(
i
=
0
;
i
<
bank_data
[
bank
->
id
].
num_sensors
;
i
++
)
{
raw
=
readl
(
mt
->
thermal_base
+
sensing_points
[
i
].
msr
);
temp
=
raw_to_mcelsius
(
mt
,
bank_data
[
bank
->
id
].
sensors
[
i
],
raw
);
/*
* The first read of a sensor often contains very high bogus
* temperature value. Filter these out so that the system does
* not immediately shut down.
*/
if
(
temp
>
200000
)
temp
=
0
;
if
(
temp
>
max
)
max
=
temp
;
}
return
max
;
}
static
int
mtk_read_temp
(
void
*
data
,
int
*
temperature
)
{
struct
mtk_thermal
*
mt
=
data
;
int
i
;
int
tempmax
=
INT_MIN
;
for
(
i
=
0
;
i
<
MT8173_NUM_ZONES
;
i
++
)
{
struct
mtk_thermal_bank
*
bank
=
&
mt
->
banks
[
i
];
mtk_thermal_get_bank
(
bank
);
tempmax
=
max
(
tempmax
,
mtk_thermal_bank_temperature
(
bank
));
mtk_thermal_put_bank
(
bank
);
}
*
temperature
=
tempmax
;
return
0
;
}
static
const
struct
thermal_zone_of_device_ops
mtk_thermal_ops
=
{
.
get_temp
=
mtk_read_temp
,
};
static
void
mtk_thermal_init_bank
(
struct
mtk_thermal
*
mt
,
int
num
,
u32
apmixed_phys_base
,
u32
auxadc_phys_base
)
{
struct
mtk_thermal_bank
*
bank
=
&
mt
->
banks
[
num
];
const
struct
mtk_thermal_bank_cfg
*
cfg
=
&
bank_data
[
num
];
int
i
;
bank
->
id
=
num
;
bank
->
mt
=
mt
;
mtk_thermal_get_bank
(
bank
);
/* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
writel
(
TEMP_MONCTL1_PERIOD_UNIT
(
12
),
mt
->
thermal_base
+
TEMP_MONCTL1
);
/*
* filt interval is 1 * 46.540us = 46.54us,
* sen interval is 429 * 46.540us = 19.96ms
*/
writel
(
TEMP_MONCTL2_FILTER_INTERVAL
(
1
)
|
TEMP_MONCTL2_SENSOR_INTERVAL
(
429
),
mt
->
thermal_base
+
TEMP_MONCTL2
);
/* poll is set to 10u */
writel
(
TEMP_AHBPOLL_ADC_POLL_INTERVAL
(
768
),
mt
->
thermal_base
+
TEMP_AHBPOLL
);
/* temperature sampling control, 1 sample */
writel
(
0x0
,
mt
->
thermal_base
+
TEMP_MSRCTL0
);
/* exceed this polling time, IRQ would be inserted */
writel
(
0xffffffff
,
mt
->
thermal_base
+
TEMP_AHBTO
);
/* number of interrupts per event, 1 is enough */
writel
(
0x0
,
mt
->
thermal_base
+
TEMP_MONIDET0
);
writel
(
0x0
,
mt
->
thermal_base
+
TEMP_MONIDET1
);
/*
* The MT8173 thermal controller does not have its own ADC. Instead it
* uses AHB bus accesses to control the AUXADC. To do this the thermal
* controller has to be programmed with the physical addresses of the
* AUXADC registers and with the various bit positions in the AUXADC.
* Also the thermal controller controls a mux in the APMIXEDSYS register
* space.
*/
/*
* this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
* automatically by hw
*/
writel
(
BIT
(
MT8173_TEMP_AUXADC_CHANNEL
),
mt
->
thermal_base
+
TEMP_ADCMUX
);
/* AHB address for auxadc mux selection */
writel
(
auxadc_phys_base
+
AUXADC_CON1_CLR_V
,
mt
->
thermal_base
+
TEMP_ADCMUXADDR
);
/* AHB address for pnp sensor mux selection */
writel
(
apmixed_phys_base
+
APMIXED_SYS_TS_CON1
,
mt
->
thermal_base
+
TEMP_PNPMUXADDR
);
/* AHB value for auxadc enable */
writel
(
BIT
(
MT8173_TEMP_AUXADC_CHANNEL
),
mt
->
thermal_base
+
TEMP_ADCEN
);
/* AHB address for auxadc enable (channel 0 immediate mode selected) */
writel
(
auxadc_phys_base
+
AUXADC_CON1_SET_V
,
mt
->
thermal_base
+
TEMP_ADCENADDR
);
/* AHB address for auxadc valid bit */
writel
(
auxadc_phys_base
+
AUXADC_DATA
(
MT8173_TEMP_AUXADC_CHANNEL
),
mt
->
thermal_base
+
TEMP_ADCVALIDADDR
);
/* AHB address for auxadc voltage output */
writel
(
auxadc_phys_base
+
AUXADC_DATA
(
MT8173_TEMP_AUXADC_CHANNEL
),
mt
->
thermal_base
+
TEMP_ADCVOLTADDR
);
/* read valid & voltage are at the same register */
writel
(
0x0
,
mt
->
thermal_base
+
TEMP_RDCTRL
);
/* indicate where the valid bit is */
writel
(
TEMP_ADCVALIDMASK_VALID_HIGH
|
TEMP_ADCVALIDMASK_VALID_POS
(
12
),
mt
->
thermal_base
+
TEMP_ADCVALIDMASK
);
/* no shift */
writel
(
0x0
,
mt
->
thermal_base
+
TEMP_ADCVOLTAGESHIFT
);
/* enable auxadc mux write transaction */
writel
(
TEMP_ADCWRITECTRL_ADC_MUX_WRITE
,
mt
->
thermal_base
+
TEMP_ADCWRITECTRL
);
for
(
i
=
0
;
i
<
cfg
->
num_sensors
;
i
++
)
writel
(
sensor_mux_values
[
cfg
->
sensors
[
i
]],
mt
->
thermal_base
+
sensing_points
[
i
].
adcpnp
);
writel
((
1
<<
cfg
->
num_sensors
)
-
1
,
mt
->
thermal_base
+
TEMP_MONCTL0
);
writel
(
TEMP_ADCWRITECTRL_ADC_PNP_WRITE
|
TEMP_ADCWRITECTRL_ADC_MUX_WRITE
,
mt
->
thermal_base
+
TEMP_ADCWRITECTRL
);
mtk_thermal_put_bank
(
bank
);
}
static
u64
of_get_phys_base
(
struct
device_node
*
np
)
{
u64
size64
;
const
__be32
*
regaddr_p
;
regaddr_p
=
of_get_address
(
np
,
0
,
&
size64
,
NULL
);
if
(
!
regaddr_p
)
return
OF_BAD_ADDR
;
return
of_translate_address
(
np
,
regaddr_p
);
}
static
int
mtk_thermal_get_calibration_data
(
struct
device
*
dev
,
struct
mtk_thermal
*
mt
)
{
struct
nvmem_cell
*
cell
;
u32
*
buf
;
size_t
len
;
int
i
,
ret
=
0
;
/* Start with default values */
mt
->
adc_ge
=
512
;
for
(
i
=
0
;
i
<
MT8173_NUM_SENSORS
;
i
++
)
mt
->
vts
[
i
]
=
260
;
mt
->
degc_cali
=
40
;
mt
->
o_slope
=
0
;
cell
=
nvmem_cell_get
(
dev
,
"calibration-data"
);
if
(
IS_ERR
(
cell
))
{
if
(
PTR_ERR
(
cell
)
==
-
EPROBE_DEFER
)
return
PTR_ERR
(
cell
);
return
0
;
}
buf
=
(
u32
*
)
nvmem_cell_read
(
cell
,
&
len
);
nvmem_cell_put
(
cell
);
if
(
IS_ERR
(
buf
))
return
PTR_ERR
(
buf
);
if
(
len
<
3
*
sizeof
(
u32
))
{
dev_warn
(
dev
,
"invalid calibration data
\n
"
);
ret
=
-
EINVAL
;
goto
out
;
}
if
(
buf
[
0
]
&
MT8173_CALIB_BUF0_VALID
)
{
mt
->
adc_ge
=
MT8173_CALIB_BUF1_ADC_GE
(
buf
[
1
]);
mt
->
vts
[
MT8173_TS1
]
=
MT8173_CALIB_BUF0_VTS_TS1
(
buf
[
0
]);
mt
->
vts
[
MT8173_TS2
]
=
MT8173_CALIB_BUF0_VTS_TS2
(
buf
[
0
]);
mt
->
vts
[
MT8173_TS3
]
=
MT8173_CALIB_BUF1_VTS_TS3
(
buf
[
1
]);
mt
->
vts
[
MT8173_TS4
]
=
MT8173_CALIB_BUF2_VTS_TS4
(
buf
[
2
]);
mt
->
vts
[
MT8173_TSABB
]
=
MT8173_CALIB_BUF2_VTS_TSABB
(
buf
[
2
]);
mt
->
degc_cali
=
MT8173_CALIB_BUF0_DEGC_CALI
(
buf
[
0
]);
mt
->
o_slope
=
MT8173_CALIB_BUF0_O_SLOPE
(
buf
[
0
]);
}
else
{
dev_info
(
dev
,
"Device not calibrated, using default calibration values
\n
"
);
}
out:
kfree
(
buf
);
return
ret
;
}
static
int
mtk_thermal_probe
(
struct
platform_device
*
pdev
)
{
int
ret
,
i
;
struct
device_node
*
auxadc
,
*
apmixedsys
,
*
np
=
pdev
->
dev
.
of_node
;
struct
mtk_thermal
*
mt
;
struct
resource
*
res
;
u64
auxadc_phys_base
,
apmixed_phys_base
;
mt
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
mt
),
GFP_KERNEL
);
if
(
!
mt
)
return
-
ENOMEM
;
mt
->
clk_peri_therm
=
devm_clk_get
(
&
pdev
->
dev
,
"therm"
);
if
(
IS_ERR
(
mt
->
clk_peri_therm
))
return
PTR_ERR
(
mt
->
clk_peri_therm
);
mt
->
clk_auxadc
=
devm_clk_get
(
&
pdev
->
dev
,
"auxadc"
);
if
(
IS_ERR
(
mt
->
clk_auxadc
))
return
PTR_ERR
(
mt
->
clk_auxadc
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
mt
->
thermal_base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
mt
->
thermal_base
))
return
PTR_ERR
(
mt
->
thermal_base
);
ret
=
mtk_thermal_get_calibration_data
(
&
pdev
->
dev
,
mt
);
if
(
ret
)
return
ret
;
mutex_init
(
&
mt
->
lock
);
mt
->
dev
=
&
pdev
->
dev
;
auxadc
=
of_parse_phandle
(
np
,
"mediatek,auxadc"
,
0
);
if
(
!
auxadc
)
{
dev_err
(
&
pdev
->
dev
,
"missing auxadc node
\n
"
);
return
-
ENODEV
;
}
auxadc_phys_base
=
of_get_phys_base
(
auxadc
);
of_node_put
(
auxadc
);
if
(
auxadc_phys_base
==
OF_BAD_ADDR
)
{
dev_err
(
&
pdev
->
dev
,
"Can't get auxadc phys address
\n
"
);
return
-
EINVAL
;
}
apmixedsys
=
of_parse_phandle
(
np
,
"mediatek,apmixedsys"
,
0
);
if
(
!
apmixedsys
)
{
dev_err
(
&
pdev
->
dev
,
"missing apmixedsys node
\n
"
);
return
-
ENODEV
;
}
apmixed_phys_base
=
of_get_phys_base
(
apmixedsys
);
of_node_put
(
apmixedsys
);
if
(
apmixed_phys_base
==
OF_BAD_ADDR
)
{
dev_err
(
&
pdev
->
dev
,
"Can't get auxadc phys address
\n
"
);
return
-
EINVAL
;
}
ret
=
clk_prepare_enable
(
mt
->
clk_auxadc
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Can't enable auxadc clk: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
device_reset
(
&
pdev
->
dev
);
if
(
ret
)
goto
err_disable_clk_auxadc
;
ret
=
clk_prepare_enable
(
mt
->
clk_peri_therm
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Can't enable peri clk: %d
\n
"
,
ret
);
goto
err_disable_clk_auxadc
;
}
for
(
i
=
0
;
i
<
MT8173_NUM_ZONES
;
i
++
)
mtk_thermal_init_bank
(
mt
,
i
,
apmixed_phys_base
,
auxadc_phys_base
);
platform_set_drvdata
(
pdev
,
mt
);
mt
->
tzd
=
thermal_zone_of_sensor_register
(
&
pdev
->
dev
,
0
,
mt
,
&
mtk_thermal_ops
);
if
(
IS_ERR
(
mt
->
tzd
))
goto
err_register
;
return
0
;
err_register:
clk_disable_unprepare
(
mt
->
clk_peri_therm
);
err_disable_clk_auxadc:
clk_disable_unprepare
(
mt
->
clk_auxadc
);
return
ret
;
}
static
int
mtk_thermal_remove
(
struct
platform_device
*
pdev
)
{
struct
mtk_thermal
*
mt
=
platform_get_drvdata
(
pdev
);
thermal_zone_of_sensor_unregister
(
&
pdev
->
dev
,
mt
->
tzd
);
clk_disable_unprepare
(
mt
->
clk_peri_therm
);
clk_disable_unprepare
(
mt
->
clk_auxadc
);
return
0
;
}
static
const
struct
of_device_id
mtk_thermal_of_match
[]
=
{
{
.
compatible
=
"mediatek,mt8173-thermal"
,
},
{
},
};
static
struct
platform_driver
mtk_thermal_driver
=
{
.
probe
=
mtk_thermal_probe
,
.
remove
=
mtk_thermal_remove
,
.
driver
=
{
.
name
=
THERMAL_NAME
,
.
of_match_table
=
mtk_thermal_of_match
,
},
};
module_platform_driver
(
mtk_thermal_driver
);
MODULE_AUTHOR
(
"Sascha Hauer <s.hauer@pengutronix.de"
);
MODULE_AUTHOR
(
"Hanyi Wu <hanyi.wu@mediatek.com>"
);
MODULE_DESCRIPTION
(
"Mediatek thermal driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/thermal/of-thermal.c
View file @
b82ddd48
...
...
@@ -555,6 +555,87 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
}
EXPORT_SYMBOL_GPL
(
thermal_zone_of_sensor_unregister
);
static
void
devm_thermal_zone_of_sensor_release
(
struct
device
*
dev
,
void
*
res
)
{
thermal_zone_of_sensor_unregister
(
dev
,
*
(
struct
thermal_zone_device
**
)
res
);
}
static
int
devm_thermal_zone_of_sensor_match
(
struct
device
*
dev
,
void
*
res
,
void
*
data
)
{
struct
thermal_zone_device
**
r
=
res
;
if
(
WARN_ON
(
!
r
||
!*
r
))
return
0
;
return
*
r
==
data
;
}
/**
* devm_thermal_zone_of_sensor_register - Resource managed version of
* thermal_zone_of_sensor_register()
* @dev: a valid struct device pointer of a sensor device. Must contain
* a valid .of_node, for the sensor node.
* @sensor_id: a sensor identifier, in case the sensor IP has more
* than one sensors
* @data: a private pointer (owned by the caller) that will be passed
* back, when a temperature reading is needed.
* @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
*
* Refer thermal_zone_of_sensor_register() for more details.
*
* Return: On success returns a valid struct thermal_zone_device,
* otherwise, it returns a corresponding ERR_PTR(). Caller must
* check the return value with help of IS_ERR() helper.
* Registered hermal_zone_device device will automatically be
* released when device is unbounded.
*/
struct
thermal_zone_device
*
devm_thermal_zone_of_sensor_register
(
struct
device
*
dev
,
int
sensor_id
,
void
*
data
,
const
struct
thermal_zone_of_device_ops
*
ops
)
{
struct
thermal_zone_device
**
ptr
,
*
tzd
;
ptr
=
devres_alloc
(
devm_thermal_zone_of_sensor_release
,
sizeof
(
*
ptr
),
GFP_KERNEL
);
if
(
!
ptr
)
return
ERR_PTR
(
-
ENOMEM
);
tzd
=
thermal_zone_of_sensor_register
(
dev
,
sensor_id
,
data
,
ops
);
if
(
IS_ERR
(
tzd
))
{
devres_free
(
ptr
);
return
tzd
;
}
*
ptr
=
tzd
;
devres_add
(
dev
,
ptr
);
return
tzd
;
}
EXPORT_SYMBOL_GPL
(
devm_thermal_zone_of_sensor_register
);
/**
* devm_thermal_zone_of_sensor_unregister - Resource managed version of
* thermal_zone_of_sensor_unregister().
* @dev: Device for which which resource was allocated.
* @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
*
* This function removes the sensor callbacks and private data from the
* thermal zone device registered with devm_thermal_zone_of_sensor_register()
* API. It will also silent the zone by remove the .get_temp() and .get_trend()
* thermal zone device callbacks.
* Normally this function will not need to be called and the resource
* management code will ensure that the resource is freed.
*/
void
devm_thermal_zone_of_sensor_unregister
(
struct
device
*
dev
,
struct
thermal_zone_device
*
tzd
)
{
WARN_ON
(
devres_release
(
dev
,
devm_thermal_zone_of_sensor_release
,
devm_thermal_zone_of_sensor_match
,
tzd
));
}
EXPORT_SYMBOL_GPL
(
devm_thermal_zone_of_sensor_unregister
);
/*** functions parsing device tree nodes ***/
/**
...
...
drivers/thermal/rcar_thermal.c
View file @
b82ddd48
...
...
@@ -430,8 +430,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
struct
rcar_thermal_priv
*
priv
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
resource
*
res
,
*
irq
;
const
struct
of_device_id
*
of_id
=
of_match_device
(
rcar_thermal_dt_ids
,
dev
);
unsigned
long
of_data
=
(
unsigned
long
)
of_id
->
data
;
unsigned
long
of_data
=
(
unsigned
long
)
of_device_get_match_data
(
dev
);
int
mres
=
0
;
int
i
;
int
ret
=
-
ENODEV
;
...
...
drivers/thermal/rockchip_thermal.c
View file @
b82ddd48
...
...
@@ -58,8 +58,8 @@ enum sensor_id {
/**
* The conversion table has the adc value and temperature.
* ADC_DECREMENT: the adc value is of diminishing.(e.g.
v2
_code_table)
* ADC_INCREMENT: the adc value is incremental.(e.g.
v3
_code_table)
* ADC_DECREMENT: the adc value is of diminishing.(e.g.
rk3288
_code_table)
* ADC_INCREMENT: the adc value is incremental.(e.g.
rk3368
_code_table)
*/
enum
adc_sort_mode
{
ADC_DECREMENT
=
0
,
...
...
@@ -135,7 +135,13 @@ struct rockchip_thermal_data {
enum
tshut_polarity
tshut_polarity
;
};
/* TSADC Sensor info define: */
/**
* TSADC Sensor Register description:
*
* TSADCV2_* are used for RK3288 SoCs, the other chips can reuse it.
* TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399)
*
*/
#define TSADCV2_AUTO_CON 0x04
#define TSADCV2_INT_EN 0x08
#define TSADCV2_INT_PD 0x0c
...
...
@@ -149,13 +155,20 @@ struct rockchip_thermal_data {
#define TSADCV2_AUTO_EN BIT(0)
#define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn))
#define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8)
/**
* TSADCV1_AUTO_Q_SEL_EN:
* whether select (1024 - tsadc_q) as output
* 1'b0:use tsadc_q as output(temperature-code is rising sequence)
* 1'b1:use(1024 - tsadc_q) as output (temperature-code is falling sequence)
*/
#define TSADCV3_AUTO_Q_SEL_EN BIT(1)
#define TSADCV2_INT_SRC_EN(chn) BIT(chn)
#define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn))
#define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn))
#define TSADCV1_INT_PD_CLEAR_MASK ~BIT(16)
#define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8)
#define TSADCV3_INT_PD_CLEAR_MASK ~BIT(16)
#define TSADCV2_DATA_MASK 0xfff
#define TSADCV3_DATA_MASK 0x3ff
...
...
@@ -177,45 +190,46 @@ struct tsadc_table {
* linearly interpolated.
* Code to Temperature mapping should be updated based on sillcon results.
*/
static
const
struct
tsadc_table
v1_code_table
[]
=
{
{
TSADCV3_DATA_MASK
,
-
40000
},
{
436
,
-
40000
},
{
431
,
-
35000
},
{
426
,
-
30000
},
{
421
,
-
25000
},
{
416
,
-
20000
},
{
411
,
-
15000
},
{
406
,
-
10000
},
{
401
,
-
5000
},
{
395
,
0
},
{
390
,
5000
},
{
385
,
10000
},
{
380
,
15000
},
{
375
,
20000
},
{
370
,
25000
},
{
364
,
30000
},
{
359
,
35000
},
{
354
,
40000
},
{
349
,
45000
},
{
343
,
50000
},
{
338
,
55000
},
{
333
,
60000
},
{
328
,
65000
},
{
322
,
70000
},
{
317
,
75000
},
{
312
,
80000
},
{
307
,
85000
},
{
301
,
90000
},
{
296
,
95000
},
{
291
,
100000
},
{
286
,
105000
},
{
280
,
110000
},
{
275
,
115000
},
{
270
,
120000
},
{
264
,
125000
},
static
const
struct
tsadc_table
rk3228_code_table
[]
=
{
{
0
,
-
40000
},
{
588
,
-
40000
},
{
593
,
-
35000
},
{
598
,
-
30000
},
{
603
,
-
25000
},
{
608
,
-
20000
},
{
613
,
-
15000
},
{
618
,
-
10000
},
{
623
,
-
5000
},
{
629
,
0
},
{
634
,
5000
},
{
639
,
10000
},
{
644
,
15000
},
{
649
,
20000
},
{
654
,
25000
},
{
660
,
30000
},
{
665
,
35000
},
{
670
,
40000
},
{
675
,
45000
},
{
681
,
50000
},
{
686
,
55000
},
{
691
,
60000
},
{
696
,
65000
},
{
702
,
70000
},
{
707
,
75000
},
{
712
,
80000
},
{
717
,
85000
},
{
723
,
90000
},
{
728
,
95000
},
{
733
,
100000
},
{
738
,
105000
},
{
744
,
110000
},
{
749
,
115000
},
{
754
,
120000
},
{
760
,
125000
},
{
TSADCV2_DATA_MASK
,
125000
},
};
static
const
struct
tsadc_table
v2
_code_table
[]
=
{
static
const
struct
tsadc_table
rk3288
_code_table
[]
=
{
{
TSADCV2_DATA_MASK
,
-
40000
},
{
3800
,
-
40000
},
{
3792
,
-
35000
},
...
...
@@ -253,7 +267,7 @@ static const struct tsadc_table v2_code_table[] = {
{
3421
,
125000
},
};
static
const
struct
tsadc_table
v3
_code_table
[]
=
{
static
const
struct
tsadc_table
rk3368
_code_table
[]
=
{
{
0
,
-
40000
},
{
106
,
-
40000
},
{
108
,
-
35000
},
...
...
@@ -292,42 +306,43 @@ static const struct tsadc_table v3_code_table[] = {
{
TSADCV3_DATA_MASK
,
125000
},
};
static
const
struct
tsadc_table
v4_code_table
[]
=
{
{
TSADCV3_DATA_MASK
,
-
40000
},
{
431
,
-
40000
},
{
426
,
-
35000
},
{
421
,
-
30000
},
{
415
,
-
25000
},
{
410
,
-
20000
},
{
405
,
-
15000
},
{
399
,
-
10000
},
{
394
,
-
5000
},
{
389
,
0
},
{
383
,
5000
},
{
378
,
10000
},
{
373
,
15000
},
{
367
,
20000
},
{
362
,
25000
},
{
357
,
30000
},
{
351
,
35000
},
{
346
,
40000
},
{
340
,
45000
},
{
335
,
50000
},
{
330
,
55000
},
{
324
,
60000
},
{
319
,
65000
},
{
313
,
70000
},
{
308
,
75000
},
{
302
,
80000
},
{
297
,
85000
},
{
291
,
90000
},
{
286
,
95000
},
{
281
,
100000
},
{
275
,
105000
},
{
270
,
110000
},
{
264
,
115000
},
{
259
,
120000
},
{
253
,
125000
},
static
const
struct
tsadc_table
rk3399_code_table
[]
=
{
{
0
,
-
40000
},
{
593
,
-
40000
},
{
598
,
-
35000
},
{
603
,
-
30000
},
{
609
,
-
25000
},
{
614
,
-
20000
},
{
619
,
-
15000
},
{
625
,
-
10000
},
{
630
,
-
5000
},
{
635
,
0
},
{
641
,
5000
},
{
646
,
10000
},
{
651
,
15000
},
{
657
,
20000
},
{
662
,
25000
},
{
667
,
30000
},
{
673
,
35000
},
{
678
,
40000
},
{
684
,
45000
},
{
689
,
50000
},
{
694
,
55000
},
{
700
,
60000
},
{
705
,
65000
},
{
711
,
70000
},
{
716
,
75000
},
{
722
,
80000
},
{
727
,
85000
},
{
733
,
90000
},
{
738
,
95000
},
{
743
,
100000
},
{
749
,
105000
},
{
754
,
110000
},
{
760
,
115000
},
{
765
,
120000
},
{
771
,
125000
},
{
TSADCV3_DATA_MASK
,
125000
},
};
static
u32
rk_tsadcv2_temp_to_code
(
struct
chip_tsadc_table
table
,
...
...
@@ -411,7 +426,7 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
* temperature between 2 table entries is linear and interpolate
* to produce less granular result.
*/
num
=
table
.
id
[
mid
].
temp
-
v2_code_table
[
mid
-
1
].
temp
;
num
=
table
.
id
[
mid
].
temp
-
table
.
id
[
mid
-
1
].
temp
;
num
*=
abs
(
table
.
id
[
mid
-
1
].
code
-
code
);
denom
=
abs
(
table
.
id
[
mid
-
1
].
code
-
table
.
id
[
mid
].
code
);
*
temp
=
table
.
id
[
mid
-
1
].
temp
+
(
num
/
denom
);
...
...
@@ -453,20 +468,20 @@ static void rk_tsadcv2_initialize(void __iomem *regs,
regs
+
TSADCV2_HIGHT_TSHUT_DEBOUNCE
);
}
static
void
rk_tsadcv
1
_irq_ack
(
void
__iomem
*
regs
)
static
void
rk_tsadcv
2
_irq_ack
(
void
__iomem
*
regs
)
{
u32
val
;
val
=
readl_relaxed
(
regs
+
TSADCV2_INT_PD
);
writel_relaxed
(
val
&
TSADCV
1
_INT_PD_CLEAR_MASK
,
regs
+
TSADCV2_INT_PD
);
writel_relaxed
(
val
&
TSADCV
2
_INT_PD_CLEAR_MASK
,
regs
+
TSADCV2_INT_PD
);
}
static
void
rk_tsadcv
2
_irq_ack
(
void
__iomem
*
regs
)
static
void
rk_tsadcv
3
_irq_ack
(
void
__iomem
*
regs
)
{
u32
val
;
val
=
readl_relaxed
(
regs
+
TSADCV2_INT_PD
);
writel_relaxed
(
val
&
TSADCV
2
_INT_PD_CLEAR_MASK
,
regs
+
TSADCV2_INT_PD
);
writel_relaxed
(
val
&
TSADCV
3
_INT_PD_CLEAR_MASK
,
regs
+
TSADCV2_INT_PD
);
}
static
void
rk_tsadcv2_control
(
void
__iomem
*
regs
,
bool
enable
)
...
...
@@ -482,6 +497,25 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable)
writel_relaxed
(
val
,
regs
+
TSADCV2_AUTO_CON
);
}
/**
* @rk_tsadcv3_control:
* TSADC controller works at auto mode, and some SoCs need set the tsadc_q_sel
* bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output adc value if
* setting this bit to enable.
*/
static
void
rk_tsadcv3_control
(
void
__iomem
*
regs
,
bool
enable
)
{
u32
val
;
val
=
readl_relaxed
(
regs
+
TSADCV2_AUTO_CON
);
if
(
enable
)
val
|=
TSADCV2_AUTO_EN
|
TSADCV3_AUTO_Q_SEL_EN
;
else
val
&=
~
TSADCV2_AUTO_EN
;
writel_relaxed
(
val
,
regs
+
TSADCV2_AUTO_CON
);
}
static
int
rk_tsadcv2_get_temp
(
struct
chip_tsadc_table
table
,
int
chn
,
void
__iomem
*
regs
,
int
*
temp
)
{
...
...
@@ -531,17 +565,17 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
.
tshut_temp
=
95000
,
.
initialize
=
rk_tsadcv2_initialize
,
.
irq_ack
=
rk_tsadcv
1
_irq_ack
,
.
control
=
rk_tsadcv
2
_control
,
.
irq_ack
=
rk_tsadcv
3
_irq_ack
,
.
control
=
rk_tsadcv
3
_control
,
.
get_temp
=
rk_tsadcv2_get_temp
,
.
set_tshut_temp
=
rk_tsadcv2_tshut_temp
,
.
set_tshut_mode
=
rk_tsadcv2_tshut_mode
,
.
table
=
{
.
id
=
v1
_code_table
,
.
length
=
ARRAY_SIZE
(
v1
_code_table
),
.
id
=
rk3228
_code_table
,
.
length
=
ARRAY_SIZE
(
rk3228
_code_table
),
.
data_mask
=
TSADCV3_DATA_MASK
,
.
mode
=
ADC_
DE
CREMENT
,
.
mode
=
ADC_
IN
CREMENT
,
},
};
...
...
@@ -562,8 +596,8 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
.
set_tshut_mode
=
rk_tsadcv2_tshut_mode
,
.
table
=
{
.
id
=
v2
_code_table
,
.
length
=
ARRAY_SIZE
(
v2
_code_table
),
.
id
=
rk3288
_code_table
,
.
length
=
ARRAY_SIZE
(
rk3288
_code_table
),
.
data_mask
=
TSADCV2_DATA_MASK
,
.
mode
=
ADC_DECREMENT
,
},
...
...
@@ -586,8 +620,8 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
.
set_tshut_mode
=
rk_tsadcv2_tshut_mode
,
.
table
=
{
.
id
=
v3
_code_table
,
.
length
=
ARRAY_SIZE
(
v3
_code_table
),
.
id
=
rk3368
_code_table
,
.
length
=
ARRAY_SIZE
(
rk3368
_code_table
),
.
data_mask
=
TSADCV3_DATA_MASK
,
.
mode
=
ADC_INCREMENT
,
},
...
...
@@ -603,17 +637,17 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
.
tshut_temp
=
95000
,
.
initialize
=
rk_tsadcv2_initialize
,
.
irq_ack
=
rk_tsadcv
1
_irq_ack
,
.
control
=
rk_tsadcv
2
_control
,
.
irq_ack
=
rk_tsadcv
3
_irq_ack
,
.
control
=
rk_tsadcv
3
_control
,
.
get_temp
=
rk_tsadcv2_get_temp
,
.
set_tshut_temp
=
rk_tsadcv2_tshut_temp
,
.
set_tshut_mode
=
rk_tsadcv2_tshut_mode
,
.
table
=
{
.
id
=
v4
_code_table
,
.
length
=
ARRAY_SIZE
(
v4
_code_table
),
.
id
=
rk3399
_code_table
,
.
length
=
ARRAY_SIZE
(
rk3399
_code_table
),
.
data_mask
=
TSADCV3_DATA_MASK
,
.
mode
=
ADC_
DE
CREMENT
,
.
mode
=
ADC_
IN
CREMENT
,
},
};
...
...
@@ -693,15 +727,14 @@ static int rockchip_configure_from_dt(struct device *dev,
thermal
->
chip
->
tshut_temp
);
thermal
->
tshut_temp
=
thermal
->
chip
->
tshut_temp
;
}
else
{
if
(
shut_temp
>
INT_MAX
)
{
dev_err
(
dev
,
"Invalid tshut temperature specified: %d
\n
"
,
shut_temp
);
return
-
ERANGE
;
}
thermal
->
tshut_temp
=
shut_temp
;
}
if
(
thermal
->
tshut_temp
>
INT_MAX
)
{
dev_err
(
dev
,
"Invalid tshut temperature specified: %d
\n
"
,
thermal
->
tshut_temp
);
return
-
ERANGE
;
}
if
(
of_property_read_u32
(
np
,
"rockchip,hw-tshut-mode"
,
&
tshut_mode
))
{
dev_warn
(
dev
,
"Missing tshut mode property, using default (%s)
\n
"
,
...
...
drivers/thermal/samsung/Kconfig
View file @
b82ddd48
config EXYNOS_THERMAL
tristate "Exynos thermal management unit driver"
depends on THERMAL_OF
depends on HAS_IOMEM
help
If you say yes here you get support for the TMU (Thermal Management
Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
...
...
drivers/thermal/samsung/exynos_tmu.c
View file @
b82ddd48
...
...
@@ -184,6 +184,7 @@
* @temp_error2: fused value of the second point trim.
* @regulator: pointer to the TMU regulator structure.
* @reg_conf: pointer to structure to register with core thermal.
* @ntrip: number of supported trip points.
* @tmu_initialize: SoC specific TMU initialization method
* @tmu_control: SoC specific TMU control method
* @tmu_read: SoC specific TMU temperature read method
...
...
@@ -203,6 +204,7 @@ struct exynos_tmu_data {
u16
temp_error1
,
temp_error2
;
struct
regulator
*
regulator
;
struct
thermal_zone_device
*
tzd
;
unsigned
int
ntrip
;
int
(
*
tmu_initialize
)(
struct
platform_device
*
pdev
);
void
(
*
tmu_control
)(
struct
platform_device
*
pdev
,
bool
on
);
...
...
@@ -346,6 +348,14 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
struct
exynos_tmu_data
*
data
=
platform_get_drvdata
(
pdev
);
int
ret
;
if
(
of_thermal_get_ntrips
(
data
->
tzd
)
>
data
->
ntrip
)
{
dev_info
(
&
pdev
->
dev
,
"More trip points than supported by this TMU.
\n
"
);
dev_info
(
&
pdev
->
dev
,
"%d trip points should be configured in polling mode.
\n
"
,
(
of_thermal_get_ntrips
(
data
->
tzd
)
-
data
->
ntrip
));
}
mutex_lock
(
&
data
->
lock
);
clk_enable
(
data
->
clk
);
if
(
!
IS_ERR
(
data
->
clk_sec
))
...
...
@@ -1210,6 +1220,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data
->
tmu_control
=
exynos4210_tmu_control
;
data
->
tmu_read
=
exynos4210_tmu_read
;
data
->
tmu_clear_irqs
=
exynos4210_tmu_clear_irqs
;
data
->
ntrip
=
4
;
break
;
case
SOC_ARCH_EXYNOS3250
:
case
SOC_ARCH_EXYNOS4412
:
...
...
@@ -1222,6 +1233,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data
->
tmu_read
=
exynos4412_tmu_read
;
data
->
tmu_set_emulation
=
exynos4412_tmu_set_emulation
;
data
->
tmu_clear_irqs
=
exynos4210_tmu_clear_irqs
;
data
->
ntrip
=
4
;
break
;
case
SOC_ARCH_EXYNOS5433
:
data
->
tmu_initialize
=
exynos5433_tmu_initialize
;
...
...
@@ -1229,6 +1241,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data
->
tmu_read
=
exynos4412_tmu_read
;
data
->
tmu_set_emulation
=
exynos4412_tmu_set_emulation
;
data
->
tmu_clear_irqs
=
exynos4210_tmu_clear_irqs
;
data
->
ntrip
=
8
;
break
;
case
SOC_ARCH_EXYNOS5440
:
data
->
tmu_initialize
=
exynos5440_tmu_initialize
;
...
...
@@ -1236,6 +1249,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data
->
tmu_read
=
exynos5440_tmu_read
;
data
->
tmu_set_emulation
=
exynos5440_tmu_set_emulation
;
data
->
tmu_clear_irqs
=
exynos5440_tmu_clear_irqs
;
data
->
ntrip
=
4
;
break
;
case
SOC_ARCH_EXYNOS7
:
data
->
tmu_initialize
=
exynos7_tmu_initialize
;
...
...
@@ -1243,6 +1257,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data
->
tmu_read
=
exynos7_tmu_read
;
data
->
tmu_set_emulation
=
exynos4412_tmu_set_emulation
;
data
->
tmu_clear_irqs
=
exynos4210_tmu_clear_irqs
;
data
->
ntrip
=
8
;
break
;
default:
dev_err
(
&
pdev
->
dev
,
"Platform not supported
\n
"
);
...
...
@@ -1295,7 +1310,7 @@ static int exynos_tmu_probe(struct platform_device *pdev)
* TODO: Add regulator as an SOC feature, so that regulator enable
* is a compulsory call.
*/
data
->
regulator
=
devm_regulator_get
(
&
pdev
->
dev
,
"vtmu"
);
data
->
regulator
=
devm_regulator_get
_optional
(
&
pdev
->
dev
,
"vtmu"
);
if
(
!
IS_ERR
(
data
->
regulator
))
{
ret
=
regulator_enable
(
data
->
regulator
);
if
(
ret
)
{
...
...
@@ -1303,6 +1318,8 @@ static int exynos_tmu_probe(struct platform_device *pdev)
return
ret
;
}
}
else
{
if
(
PTR_ERR
(
data
->
regulator
)
==
-
EPROBE_DEFER
)
return
-
EPROBE_DEFER
;
dev_info
(
&
pdev
->
dev
,
"Regulator node (vtmu) not found
\n
"
);
}
...
...
drivers/thermal/tegra_soctherm.c
View file @
b82ddd48
...
...
@@ -57,7 +57,7 @@
#define READBACK_VALUE_MASK 0xff00
#define READBACK_VALUE_SHIFT 8
#define READBACK_ADD_HALF BIT(7)
#define READBACK_NEGATE BIT(
1
)
#define READBACK_NEGATE BIT(
0
)
#define FUSE_TSENSOR8_CALIB 0x180
#define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc
...
...
drivers/thermal/ti-soc-thermal/ti-bandgap.c
View file @
b82ddd48
...
...
@@ -1265,7 +1265,7 @@ static
int
ti_bandgap_probe
(
struct
platform_device
*
pdev
)
{
struct
ti_bandgap
*
bgp
;
int
clk_rate
,
ret
=
0
,
i
;
int
clk_rate
,
ret
,
i
;
bgp
=
ti_bandgap_build
(
pdev
);
if
(
IS_ERR
(
bgp
))
{
...
...
@@ -1288,16 +1288,14 @@ int ti_bandgap_probe(struct platform_device *pdev)
}
bgp
->
fclock
=
clk_get
(
NULL
,
bgp
->
conf
->
fclock_name
);
ret
=
IS_ERR
(
bgp
->
fclock
);
if
(
ret
)
{
if
(
IS_ERR
(
bgp
->
fclock
))
{
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
(
bgp
->
div_clk
);
if
(
ret
)
{
if
(
IS_ERR
(
bgp
->
div_clk
))
{
dev_err
(
&
pdev
->
dev
,
"failed to request div_ts_ck clock ref
\n
"
);
ret
=
PTR_ERR
(
bgp
->
div_clk
);
goto
free_irqs
;
...
...
@@ -1314,7 +1312,7 @@ int ti_bandgap_probe(struct platform_device *pdev)
* may not be accurate
*/
val
=
ti_bandgap_readl
(
bgp
,
tsr
->
bgap_efuse
);
if
(
ret
||
!
val
)
if
(
!
val
)
dev_info
(
&
pdev
->
dev
,
"Non-trimmed BGAP, Temp not accurate
\n
"
);
}
...
...
include/linux/thermal.h
View file @
b82ddd48
...
...
@@ -362,6 +362,11 @@ thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
const
struct
thermal_zone_of_device_ops
*
ops
);
void
thermal_zone_of_sensor_unregister
(
struct
device
*
dev
,
struct
thermal_zone_device
*
tz
);
struct
thermal_zone_device
*
devm_thermal_zone_of_sensor_register
(
struct
device
*
dev
,
int
id
,
void
*
data
,
const
struct
thermal_zone_of_device_ops
*
ops
);
void
devm_thermal_zone_of_sensor_unregister
(
struct
device
*
dev
,
struct
thermal_zone_device
*
tz
);
#else
static
inline
struct
thermal_zone_device
*
thermal_zone_of_sensor_register
(
struct
device
*
dev
,
int
id
,
void
*
data
,
...
...
@@ -376,6 +381,19 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
{
}
static
inline
struct
thermal_zone_device
*
devm_thermal_zone_of_sensor_register
(
struct
device
*
dev
,
int
id
,
void
*
data
,
const
struct
thermal_zone_of_device_ops
*
ops
)
{
return
ERR_PTR
(
-
ENODEV
);
}
static
inline
void
devm_thermal_zone_of_sensor_unregister
(
struct
device
*
dev
,
struct
thermal_zone_device
*
tz
)
{
}
#endif
#if IS_ENABLED(CONFIG_THERMAL)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment