1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal

Pull thermal SoC updates from Zhang Rui:
 "Thermal SoC management updates:

   - imx thermal driver now supports i.MX7 thermal sensor (Anson Huang)

   - exynos thermal driver dropped support for exynos 5440 (Krzysztof
     Kozlowski)

   - rcar_thermal now supports r8a77995 (Yoshihiro Kaneko)

   - rcar_gen3_thermal now supports r8a77965 (Niklas Söderlund)

   - qcom-spmi-temp-alarm now supports GEN2 PMIC peripherals (David
     Collins)

   - uniphier thermal now supports UniPhier PXs3 (Kunihiko Hayashi)

   - mediatek thermal now supports MT7622 SoC (Sean Wang)

   - considerable refactoring of exynos driver (Bartlomiej
     Zolnierkiewicz)

   - small fixes all over the place on different drivers"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal: (50 commits)
  thermal: qcom: tsens: Allow number of sensors to come from DT
  thermal: tegra: soctherm: add const to struct thermal_cooling_device_ops
  thermal: exynos: Reduce severity of too early temperature read
  thermal: imx: Switch to SPDX identifier
  thermal: qcom-spmi-temp-alarm: add support for GEN2 PMIC peripherals
  thermal: ti-soc-thermal: fix incorrect entry in omap5430_adc_to_temp[]
  thermal: rcar_thermal: add r8a77995 support
  dt-bindings: thermal: rcar-thermal: add R8A77995 support
  thermal: mediatek: use of_device_get_match_data()
  thermal: exynos: remove trip reporting to user-space
  thermal: exynos: remove unused defines for Exynos5433
  thermal: exynos: cleanup code for enabling threshold interrupts
  thermal: exynos: check return values of ->get_trip_[temp, hyst] methods
  thermal: exynos: move trips setting to exynos_tmu_initialize()
  thermal: exynos: set trips in ascending order in exynos7_tmu_initialize()
  thermal: exynos: do not use trips structure directly in ->tmu_initialize
  thermal: exynos: add exynos*_tmu_set_[trip,hyst]() helpers
  thermal: exynos: move IRQs clearing to exynos_tmu_initialize()
  thermal: exynos: clear IRQs later in exynos4412_tmu_initialize()
  thermal: exynos: make ->tmu_initialize method void
  ...
This commit is contained in:
Linus Torvalds 2018-06-12 13:23:51 -07:00
commit 19785cf93b
18 changed files with 880 additions and 910 deletions

View file

@ -12,7 +12,6 @@
"samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4 "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
Exynos5420 (Must pass triminfo base and triminfo clock) Exynos5420 (Must pass triminfo base and triminfo clock)
"samsung,exynos5433-tmu" "samsung,exynos5433-tmu"
"samsung,exynos5440-tmu"
"samsung,exynos7-tmu" "samsung,exynos7-tmu"
- interrupt-parent : The phandle for the interrupt controller - interrupt-parent : The phandle for the interrupt controller
- reg : Address range of the thermal registers. For soc's which has multiple - reg : Address range of the thermal registers. For soc's which has multiple
@ -68,18 +67,7 @@ Example 1):
#thermal-sensor-cells = <0>; #thermal-sensor-cells = <0>;
}; };
Example 2): Example 2): (In case of Exynos5420 "with misplaced TRIMINFO register")
tmuctrl_0: tmuctrl@160118 {
compatible = "samsung,exynos5440-tmu";
reg = <0x160118 0x230>, <0x160368 0x10>;
interrupts = <0 58 0>;
clocks = <&clock 21>;
clock-names = "tmu_apbif";
#thermal-sensor-cells = <0>;
};
Example 3): (In case of Exynos5420 "with misplaced TRIMINFO register")
tmu_cpu2: tmu@10068000 { tmu_cpu2: tmu@10068000 {
compatible = "samsung,exynos5420-tmu-ext-triminfo"; compatible = "samsung,exynos5420-tmu-ext-triminfo";
reg = <0x10068000 0x100>, <0x1006c000 0x4>; reg = <0x10068000 0x100>, <0x1006c000 0x4>;

View file

@ -1,8 +1,13 @@
* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs * Temperature Monitor (TEMPMON) on Freescale i.MX SoCs
Required properties: Required properties:
- compatible : "fsl,imx6q-tempmon" for i.MX6Q, "fsl,imx6sx-tempmon" for i.MX6SX. - compatible : must be one of following:
i.MX6SX has two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC, - "fsl,imx6q-tempmon" for i.MX6Q,
- "fsl,imx6sx-tempmon" for i.MX6SX,
- "fsl,imx7d-tempmon" for i.MX7S/D.
- interrupts : the interrupt output of the controller:
i.MX6Q has one IRQ which will be triggered when temperature is higher than high threshold,
i.MX6SX and i.MX7S/D have two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC,
when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature
is higher than panic threshold, system will auto reboot by SRC module. is higher than panic threshold, system will auto reboot by SRC module.
- fsl,tempmon : phandle pointer to system controller that contains TEMPMON - fsl,tempmon : phandle pointer to system controller that contains TEMPMON

View file

@ -12,6 +12,7 @@ Required properties:
- "mediatek,mt8173-thermal" : For MT8173 family of SoCs - "mediatek,mt8173-thermal" : For MT8173 family of SoCs
- "mediatek,mt2701-thermal" : For MT2701 family of SoCs - "mediatek,mt2701-thermal" : For MT2701 family of SoCs
- "mediatek,mt2712-thermal" : For MT2712 family of SoCs - "mediatek,mt2712-thermal" : For MT2712 family of SoCs
- "mediatek,mt7622-thermal" : For MT7622 SoC
- reg: Address range of the thermal controller - reg: Address range of the thermal controller
- interrupts: IRQ for the thermal controller - interrupts: IRQ for the thermal controller
- clocks, clock-names: Clocks needed for the thermal controller. required - clocks, clock-names: Clocks needed for the thermal controller. required

View file

@ -8,6 +8,7 @@ Required properties:
- reg: Address range of the thermal registers - reg: Address range of the thermal registers
- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
- #qcom,sensors: Number of sensors in tsens block
- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify - Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
nvmem cells nvmem cells

View file

@ -9,6 +9,7 @@ Required properties:
Examples with soctypes are: Examples with soctypes are:
- "renesas,r8a7795-thermal" (R-Car H3) - "renesas,r8a7795-thermal" (R-Car H3)
- "renesas,r8a7796-thermal" (R-Car M3-W) - "renesas,r8a7796-thermal" (R-Car M3-W)
- "renesas,r8a77965-thermal" (R-Car M3-N)
- reg : Address ranges of the thermal registers. Each sensor - reg : Address ranges of the thermal registers. Each sensor
needs one address range. Sorting must be done in needs one address range. Sorting must be done in
increasing order according to datasheet, i.e. increasing order according to datasheet, i.e.
@ -18,7 +19,7 @@ Required properties:
Optional properties: Optional properties:
- interrupts : interrupts routed to the TSC (3 for H3 and M3-W) - interrupts : interrupts routed to the TSC (3 for H3, M3-W and M3-N)
- power-domain : Must contain a reference to the power domain. This - power-domain : Must contain a reference to the power domain. This
property is mandatory if the thermal sensor instance property is mandatory if the thermal sensor instance
is part of a controllable power domain. is part of a controllable power domain.

View file

@ -3,7 +3,8 @@
Required properties: Required properties:
- compatible : "renesas,thermal-<soctype>", - compatible : "renesas,thermal-<soctype>",
"renesas,rcar-gen2-thermal" (with thermal-zone) or "renesas,rcar-gen2-thermal" (with thermal-zone) or
"renesas,rcar-thermal" (without thermal-zone) as fallback. "renesas,rcar-thermal" (without thermal-zone) as
fallback except R-Car D3.
Examples with soctypes are: Examples with soctypes are:
- "renesas,thermal-r8a73a4" (R-Mobile APE6) - "renesas,thermal-r8a73a4" (R-Mobile APE6)
- "renesas,thermal-r8a7743" (RZ/G1M) - "renesas,thermal-r8a7743" (RZ/G1M)
@ -12,13 +13,15 @@ Required properties:
- "renesas,thermal-r8a7791" (R-Car M2-W) - "renesas,thermal-r8a7791" (R-Car M2-W)
- "renesas,thermal-r8a7792" (R-Car V2H) - "renesas,thermal-r8a7792" (R-Car V2H)
- "renesas,thermal-r8a7793" (R-Car M2-N) - "renesas,thermal-r8a7793" (R-Car M2-N)
- "renesas,thermal-r8a77995" (R-Car D3)
- reg : Address range of the thermal registers. - reg : Address range of the thermal registers.
The 1st reg will be recognized as common register The 1st reg will be recognized as common register
if it has "interrupts". if it has "interrupts".
Option properties: Option properties:
- interrupts : use interrupt - interrupts : If present should contain 3 interrupts for
R-Car D3 or 1 interrupt otherwise.
Example (non interrupt support): Example (non interrupt support):

View file

@ -8,6 +8,7 @@ Required properties:
- compatible : - compatible :
- "socionext,uniphier-pxs2-thermal" : For UniPhier PXs2 SoC - "socionext,uniphier-pxs2-thermal" : For UniPhier PXs2 SoC
- "socionext,uniphier-ld20-thermal" : For UniPhier LD20 SoC - "socionext,uniphier-ld20-thermal" : For UniPhier LD20 SoC
- "socionext,uniphier-pxs3-thermal" : For UniPhier PXs3 SoC
- interrupts : IRQ for the temperature alarm - interrupts : IRQ for the temperature alarm
- #thermal-sensor-cells : Should be 0. See ./thermal.txt for details. - #thermal-sensor-cells : Should be 0. See ./thermal.txt for details.

View file

@ -1,11 +1,6 @@
/* // SPDX-License-Identifier: GPL-2.0
* Copyright 2013 Freescale Semiconductor, Inc. //
* // Copyright 2013 Freescale Semiconductor, Inc.
* 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.
*
*/
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
@ -31,35 +26,57 @@
#define REG_CLR 0x8 #define REG_CLR 0x8
#define REG_TOG 0xc #define REG_TOG 0xc
#define MISC0 0x0150 /* i.MX6 specific */
#define MISC0_REFTOP_SELBIASOFF (1 << 3) #define IMX6_MISC0 0x0150
#define MISC1 0x0160 #define IMX6_MISC0_REFTOP_SELBIASOFF (1 << 3)
#define MISC1_IRQ_TEMPHIGH (1 << 29) #define IMX6_MISC1 0x0160
#define IMX6_MISC1_IRQ_TEMPHIGH (1 << 29)
/* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */ /* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */
#define MISC1_IRQ_TEMPLOW (1 << 28) #define IMX6_MISC1_IRQ_TEMPLOW (1 << 28)
#define MISC1_IRQ_TEMPPANIC (1 << 27) #define IMX6_MISC1_IRQ_TEMPPANIC (1 << 27)
#define TEMPSENSE0 0x0180 #define IMX6_TEMPSENSE0 0x0180
#define TEMPSENSE0_ALARM_VALUE_SHIFT 20 #define IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT 20
#define TEMPSENSE0_ALARM_VALUE_MASK (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT) #define IMX6_TEMPSENSE0_ALARM_VALUE_MASK (0xfff << 20)
#define TEMPSENSE0_TEMP_CNT_SHIFT 8 #define IMX6_TEMPSENSE0_TEMP_CNT_SHIFT 8
#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) #define IMX6_TEMPSENSE0_TEMP_CNT_MASK (0xfff << 8)
#define TEMPSENSE0_FINISHED (1 << 2) #define IMX6_TEMPSENSE0_FINISHED (1 << 2)
#define TEMPSENSE0_MEASURE_TEMP (1 << 1) #define IMX6_TEMPSENSE0_MEASURE_TEMP (1 << 1)
#define TEMPSENSE0_POWER_DOWN (1 << 0) #define IMX6_TEMPSENSE0_POWER_DOWN (1 << 0)
#define TEMPSENSE1 0x0190 #define IMX6_TEMPSENSE1 0x0190
#define TEMPSENSE1_MEASURE_FREQ 0xffff #define IMX6_TEMPSENSE1_MEASURE_FREQ 0xffff
/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */ #define IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT 0
#define TEMPSENSE2 0x0290
#define TEMPSENSE2_LOW_VALUE_SHIFT 0
#define TEMPSENSE2_LOW_VALUE_MASK 0xfff
#define TEMPSENSE2_PANIC_VALUE_SHIFT 16
#define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
#define OCOTP_MEM0 0x0480 #define OCOTP_MEM0 0x0480
#define OCOTP_ANA1 0x04e0 #define OCOTP_ANA1 0x04e0
/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */
#define IMX6_TEMPSENSE2 0x0290
#define IMX6_TEMPSENSE2_LOW_VALUE_SHIFT 0
#define IMX6_TEMPSENSE2_LOW_VALUE_MASK 0xfff
#define IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT 16
#define IMX6_TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
/* i.MX7 specific */
#define IMX7_ANADIG_DIGPROG 0x800
#define IMX7_TEMPSENSE0 0x300
#define IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT 18
#define IMX7_TEMPSENSE0_PANIC_ALARM_MASK (0x1ff << 18)
#define IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT 9
#define IMX7_TEMPSENSE0_HIGH_ALARM_MASK (0x1ff << 9)
#define IMX7_TEMPSENSE0_LOW_ALARM_SHIFT 0
#define IMX7_TEMPSENSE0_LOW_ALARM_MASK 0x1ff
#define IMX7_TEMPSENSE1 0x310
#define IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT 16
#define IMX7_TEMPSENSE1_MEASURE_FREQ_MASK (0xffff << 16)
#define IMX7_TEMPSENSE1_FINISHED (1 << 11)
#define IMX7_TEMPSENSE1_MEASURE_TEMP (1 << 10)
#define IMX7_TEMPSENSE1_POWER_DOWN (1 << 9)
#define IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT 0
#define IMX7_TEMPSENSE1_TEMP_VALUE_MASK 0x1ff
/* The driver supports 1 passive trip point and 1 critical trip point */ /* The driver supports 1 passive trip point and 1 critical trip point */
enum imx_thermal_trip { enum imx_thermal_trip {
IMX_TRIP_PASSIVE, IMX_TRIP_PASSIVE,
@ -72,17 +89,114 @@ enum imx_thermal_trip {
#define TEMPMON_IMX6Q 1 #define TEMPMON_IMX6Q 1
#define TEMPMON_IMX6SX 2 #define TEMPMON_IMX6SX 2
#define TEMPMON_IMX7D 3
struct thermal_soc_data { struct thermal_soc_data {
u32 version; u32 version;
u32 sensor_ctrl;
u32 power_down_mask;
u32 measure_temp_mask;
u32 measure_freq_ctrl;
u32 measure_freq_mask;
u32 measure_freq_shift;
u32 temp_data;
u32 temp_value_mask;
u32 temp_value_shift;
u32 temp_valid_mask;
u32 panic_alarm_ctrl;
u32 panic_alarm_mask;
u32 panic_alarm_shift;
u32 high_alarm_ctrl;
u32 high_alarm_mask;
u32 high_alarm_shift;
u32 low_alarm_ctrl;
u32 low_alarm_mask;
u32 low_alarm_shift;
}; };
static struct thermal_soc_data thermal_imx6q_data = { static struct thermal_soc_data thermal_imx6q_data = {
.version = TEMPMON_IMX6Q, .version = TEMPMON_IMX6Q,
.sensor_ctrl = IMX6_TEMPSENSE0,
.power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
.measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
.measure_freq_ctrl = IMX6_TEMPSENSE1,
.measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
.measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
.temp_data = IMX6_TEMPSENSE0,
.temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
.temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
.temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
.high_alarm_ctrl = IMX6_TEMPSENSE0,
.high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
.high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
}; };
static struct thermal_soc_data thermal_imx6sx_data = { static struct thermal_soc_data thermal_imx6sx_data = {
.version = TEMPMON_IMX6SX, .version = TEMPMON_IMX6SX,
.sensor_ctrl = IMX6_TEMPSENSE0,
.power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
.measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
.measure_freq_ctrl = IMX6_TEMPSENSE1,
.measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
.measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
.temp_data = IMX6_TEMPSENSE0,
.temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
.temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
.temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
.high_alarm_ctrl = IMX6_TEMPSENSE0,
.high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
.high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
.panic_alarm_ctrl = IMX6_TEMPSENSE2,
.panic_alarm_mask = IMX6_TEMPSENSE2_PANIC_VALUE_MASK,
.panic_alarm_shift = IMX6_TEMPSENSE2_PANIC_VALUE_SHIFT,
.low_alarm_ctrl = IMX6_TEMPSENSE2,
.low_alarm_mask = IMX6_TEMPSENSE2_LOW_VALUE_MASK,
.low_alarm_shift = IMX6_TEMPSENSE2_LOW_VALUE_SHIFT,
};
static struct thermal_soc_data thermal_imx7d_data = {
.version = TEMPMON_IMX7D,
.sensor_ctrl = IMX7_TEMPSENSE1,
.power_down_mask = IMX7_TEMPSENSE1_POWER_DOWN,
.measure_temp_mask = IMX7_TEMPSENSE1_MEASURE_TEMP,
.measure_freq_ctrl = IMX7_TEMPSENSE1,
.measure_freq_shift = IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT,
.measure_freq_mask = IMX7_TEMPSENSE1_MEASURE_FREQ_MASK,
.temp_data = IMX7_TEMPSENSE1,
.temp_value_mask = IMX7_TEMPSENSE1_TEMP_VALUE_MASK,
.temp_value_shift = IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT,
.temp_valid_mask = IMX7_TEMPSENSE1_FINISHED,
.panic_alarm_ctrl = IMX7_TEMPSENSE1,
.panic_alarm_mask = IMX7_TEMPSENSE0_PANIC_ALARM_MASK,
.panic_alarm_shift = IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT,
.high_alarm_ctrl = IMX7_TEMPSENSE0,
.high_alarm_mask = IMX7_TEMPSENSE0_HIGH_ALARM_MASK,
.high_alarm_shift = IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT,
.low_alarm_ctrl = IMX7_TEMPSENSE0,
.low_alarm_mask = IMX7_TEMPSENSE0_LOW_ALARM_MASK,
.low_alarm_shift = IMX7_TEMPSENSE0_LOW_ALARM_SHIFT,
}; };
struct imx_thermal_data { struct imx_thermal_data {
@ -107,31 +221,42 @@ struct imx_thermal_data {
static void imx_set_panic_temp(struct imx_thermal_data *data, static void imx_set_panic_temp(struct imx_thermal_data *data,
int panic_temp) int panic_temp)
{ {
const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
int critical_value; int critical_value;
critical_value = (data->c2 - panic_temp) / data->c1; critical_value = (data->c2 - panic_temp) / data->c1;
regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK);
regmap_write(map, TEMPSENSE2 + REG_SET, critical_value << regmap_write(map, soc_data->panic_alarm_ctrl + REG_CLR,
TEMPSENSE2_PANIC_VALUE_SHIFT); soc_data->panic_alarm_mask);
regmap_write(map, soc_data->panic_alarm_ctrl + REG_SET,
critical_value << soc_data->panic_alarm_shift);
} }
static void imx_set_alarm_temp(struct imx_thermal_data *data, static void imx_set_alarm_temp(struct imx_thermal_data *data,
int alarm_temp) int alarm_temp)
{ {
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
const struct thermal_soc_data *soc_data = data->socdata;
int alarm_value; int alarm_value;
data->alarm_temp = alarm_temp; data->alarm_temp = alarm_temp;
if (data->socdata->version == TEMPMON_IMX7D)
alarm_value = alarm_temp / 1000 + data->c1 - 25;
else
alarm_value = (data->c2 - alarm_temp) / data->c1; alarm_value = (data->c2 - alarm_temp) / data->c1;
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value << regmap_write(map, soc_data->high_alarm_ctrl + REG_CLR,
TEMPSENSE0_ALARM_VALUE_SHIFT); soc_data->high_alarm_mask);
regmap_write(map, soc_data->high_alarm_ctrl + REG_SET,
alarm_value << soc_data->high_alarm_shift);
} }
static int imx_get_temp(struct thermal_zone_device *tz, int *temp) static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
{ {
struct imx_thermal_data *data = tz->devdata; struct imx_thermal_data *data = tz->devdata;
const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
unsigned int n_meas; unsigned int n_meas;
bool wait; bool wait;
@ -139,16 +264,18 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
if (data->mode == THERMAL_DEVICE_ENABLED) { if (data->mode == THERMAL_DEVICE_ENABLED) {
/* Check if a measurement is currently in progress */ /* Check if a measurement is currently in progress */
regmap_read(map, TEMPSENSE0, &val); regmap_read(map, soc_data->temp_data, &val);
wait = !(val & TEMPSENSE0_FINISHED); wait = !(val & soc_data->temp_valid_mask);
} else { } else {
/* /*
* Every time we measure the temperature, we will power on the * Every time we measure the temperature, we will power on the
* temperature sensor, enable measurements, take a reading, * temperature sensor, enable measurements, take a reading,
* disable measurements, power off the temperature sensor. * disable measurements, power off the temperature sensor.
*/ */
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->measure_temp_mask);
wait = true; wait = true;
} }
@ -160,21 +287,27 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
if (wait) if (wait)
usleep_range(20, 50); usleep_range(20, 50);
regmap_read(map, TEMPSENSE0, &val); regmap_read(map, soc_data->temp_data, &val);
if (data->mode != THERMAL_DEVICE_ENABLED) { if (data->mode != THERMAL_DEVICE_ENABLED) {
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
} }
if ((val & TEMPSENSE0_FINISHED) == 0) { if ((val & soc_data->temp_valid_mask) == 0) {
dev_dbg(&tz->device, "temp measurement never finished\n"); dev_dbg(&tz->device, "temp measurement never finished\n");
return -EAGAIN; return -EAGAIN;
} }
n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT; n_meas = (val & soc_data->temp_value_mask)
>> soc_data->temp_value_shift;
/* See imx_init_calib() for formula derivation */ /* See imx_init_calib() for formula derivation */
if (data->socdata->version == TEMPMON_IMX7D)
*temp = (n_meas - data->c1 + 25) * 1000;
else
*temp = data->c2 - n_meas * data->c1; *temp = data->c2 - n_meas * data->c1;
/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */ /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
@ -219,21 +352,26 @@ static int imx_set_mode(struct thermal_zone_device *tz,
{ {
struct imx_thermal_data *data = tz->devdata; struct imx_thermal_data *data = tz->devdata;
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
const struct thermal_soc_data *soc_data = data->socdata;
if (mode == THERMAL_DEVICE_ENABLED) { if (mode == THERMAL_DEVICE_ENABLED) {
tz->polling_delay = IMX_POLLING_DELAY; tz->polling_delay = IMX_POLLING_DELAY;
tz->passive_delay = IMX_PASSIVE_DELAY; tz->passive_delay = IMX_PASSIVE_DELAY;
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->measure_temp_mask);
if (!data->irq_enabled) { if (!data->irq_enabled) {
data->irq_enabled = true; data->irq_enabled = true;
enable_irq(data->irq); enable_irq(data->irq);
} }
} else { } else {
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
tz->polling_delay = 0; tz->polling_delay = 0;
tz->passive_delay = 0; tz->passive_delay = 0;
@ -354,6 +492,15 @@ static int imx_init_calib(struct platform_device *pdev, u32 ocotp_ana1)
return -EINVAL; return -EINVAL;
} }
/*
* On i.MX7D, we only use the calibration data at 25C to get the temp,
* Tmeas = ( Nmeas - n1) + 25; n1 is the fuse value for 25C.
*/
if (data->socdata->version == TEMPMON_IMX7D) {
data->c1 = (ocotp_ana1 >> 9) & 0x1ff;
return 0;
}
/* /*
* The sensor is calibrated at 25 °C (aka T1) and the value measured * The sensor is calibrated at 25 °C (aka T1) and the value measured
* (aka N1) at this temperature is provided in bits [31:20] in the * (aka N1) at this temperature is provided in bits [31:20] in the
@ -492,6 +639,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
static const struct of_device_id of_imx_thermal_match[] = { static const struct of_device_id of_imx_thermal_match[] = {
{ .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, }, { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
{ .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, }, { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
{ .compatible = "fsl,imx7d-tempmon", .data = &thermal_imx7d_data, },
{ /* end */ } { /* end */ }
}; };
MODULE_DEVICE_TABLE(of, of_imx_thermal_match); MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
@ -523,14 +671,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */ /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
if (data->socdata->version == TEMPMON_IMX6SX) { if (data->socdata->version == TEMPMON_IMX6SX) {
regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH | regmap_write(map, IMX6_MISC1 + REG_CLR,
MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC); IMX6_MISC1_IRQ_TEMPHIGH | IMX6_MISC1_IRQ_TEMPLOW
| IMX6_MISC1_IRQ_TEMPPANIC);
/* /*
* reset value of LOW ALARM is incorrect, set it to lowest * reset value of LOW ALARM is incorrect, set it to lowest
* value to avoid false trigger of low alarm. * value to avoid false trigger of low alarm.
*/ */
regmap_write(map, TEMPSENSE2 + REG_SET, regmap_write(map, data->socdata->low_alarm_ctrl + REG_SET,
TEMPSENSE2_LOW_VALUE_MASK); data->socdata->low_alarm_mask);
} }
data->irq = platform_get_irq(pdev, 0); data->irq = platform_get_irq(pdev, 0);
@ -557,11 +706,17 @@ static int imx_thermal_probe(struct platform_device *pdev)
} }
/* Make sure sensor is in known good state for measurements */ /* Make sure sensor is in known good state for measurements */
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); data->socdata->power_down_mask);
regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); data->socdata->measure_temp_mask);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
data->socdata->measure_freq_mask);
if (data->socdata->version != TEMPMON_IMX7D)
regmap_write(map, IMX6_MISC0 + REG_SET,
IMX6_MISC0_REFTOP_SELBIASOFF);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->power_down_mask);
data->policy = cpufreq_cpu_get(0); data->policy = cpufreq_cpu_get(0);
if (!data->policy) { if (!data->policy) {
@ -626,16 +781,20 @@ static int imx_thermal_probe(struct platform_device *pdev)
data->temp_passive / 1000); data->temp_passive / 1000);
/* Enable measurements at ~ 10 Hz */ /* Enable measurements at ~ 10 Hz */
regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
data->socdata->measure_freq_mask);
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); regmap_write(map, data->socdata->measure_freq_ctrl + REG_SET,
measure_freq << data->socdata->measure_freq_shift);
imx_set_alarm_temp(data, data->temp_passive); imx_set_alarm_temp(data, data->temp_passive);
if (data->socdata->version == TEMPMON_IMX6SX) if (data->socdata->version == TEMPMON_IMX6SX)
imx_set_panic_temp(data, data->temp_critical); imx_set_panic_temp(data, data->temp_critical);
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); data->socdata->power_down_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->measure_temp_mask);
data->irq_enabled = true; data->irq_enabled = true;
data->mode = THERMAL_DEVICE_ENABLED; data->mode = THERMAL_DEVICE_ENABLED;
@ -661,7 +820,8 @@ static int imx_thermal_remove(struct platform_device *pdev)
struct regmap *map = data->tempmon; struct regmap *map = data->tempmon;
/* Disable measurements */ /* Disable measurements */
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->power_down_mask);
if (!IS_ERR(data->thermal_clk)) if (!IS_ERR(data->thermal_clk))
clk_disable_unprepare(data->thermal_clk); clk_disable_unprepare(data->thermal_clk);
@ -684,8 +844,10 @@ static int imx_thermal_suspend(struct device *dev)
* temperature will be read as the thermal sensor is powered * temperature will be read as the thermal sensor is powered
* down. * down.
*/ */
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); data->socdata->measure_temp_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->power_down_mask);
data->mode = THERMAL_DEVICE_DISABLED; data->mode = THERMAL_DEVICE_DISABLED;
clk_disable_unprepare(data->thermal_clk); clk_disable_unprepare(data->thermal_clk);
@ -702,8 +864,10 @@ static int imx_thermal_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
/* Enabled thermal sensor after resume */ /* Enabled thermal sensor after resume */
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); data->socdata->power_down_mask);
regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
data->socdata->measure_temp_mask);
data->mode = THERMAL_DEVICE_ENABLED; data->mode = THERMAL_DEVICE_ENABLED;
return 0; return 0;

View file

@ -153,6 +153,12 @@
/* The number of sensing points per bank */ /* The number of sensing points per bank */
#define MT2712_NUM_SENSORS_PER_ZONE 4 #define MT2712_NUM_SENSORS_PER_ZONE 4
#define MT7622_TEMP_AUXADC_CHANNEL 11
#define MT7622_NUM_SENSORS 1
#define MT7622_NUM_ZONES 1
#define MT7622_NUM_SENSORS_PER_ZONE 1
#define MT7622_TS1 0
struct mtk_thermal; struct mtk_thermal;
struct thermal_bank_cfg { struct thermal_bank_cfg {
@ -242,6 +248,12 @@ static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 }; static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
/* MT7622 thermal sensor data */
static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
/** /**
* The MT8173 thermal controller has four banks. Each bank can read up to * The MT8173 thermal controller has four banks. Each bank can read up to
* four temperature sensors simultaneously. The MT8173 has a total of 5 * four temperature sensors simultaneously. The MT8173 has a total of 5
@ -329,6 +341,25 @@ static const struct mtk_thermal_data mt2712_thermal_data = {
.sensor_mux_values = mt2712_mux_values, .sensor_mux_values = mt2712_mux_values,
}; };
/*
* MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
* access.
*/
static const struct mtk_thermal_data mt7622_thermal_data = {
.auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
.num_banks = MT7622_NUM_ZONES,
.num_sensors = MT7622_NUM_SENSORS,
.bank_data = {
{
.num_sensors = 1,
.sensors = mt7622_bank_data,
},
},
.msr = mt7622_msr,
.adcpnp = mt7622_adcpnp,
.sensor_mux_values = mt7622_mux_values,
};
/** /**
* raw_to_mcelsius - convert a raw ADC value to mcelsius * raw_to_mcelsius - convert a raw ADC value to mcelsius
* @mt: The thermal controller * @mt: The thermal controller
@ -631,6 +662,10 @@ static const struct of_device_id mtk_thermal_of_match[] = {
{ {
.compatible = "mediatek,mt2712-thermal", .compatible = "mediatek,mt2712-thermal",
.data = (void *)&mt2712_thermal_data, .data = (void *)&mt2712_thermal_data,
},
{
.compatible = "mediatek,mt7622-thermal",
.data = (void *)&mt7622_thermal_data,
}, { }, {
}, },
}; };
@ -642,7 +677,6 @@ static int mtk_thermal_probe(struct platform_device *pdev)
struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
struct mtk_thermal *mt; struct mtk_thermal *mt;
struct resource *res; struct resource *res;
const struct of_device_id *of_id;
u64 auxadc_phys_base, apmixed_phys_base; u64 auxadc_phys_base, apmixed_phys_base;
struct thermal_zone_device *tzdev; struct thermal_zone_device *tzdev;
@ -650,9 +684,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
if (!mt) if (!mt)
return -ENOMEM; return -ENOMEM;
of_id = of_match_device(mtk_thermal_of_match, &pdev->dev); mt->conf = of_device_get_match_data(&pdev->dev);
if (of_id)
mt->conf = (const struct mtk_thermal_data *)of_id->data;
mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
if (IS_ERR(mt->clk_peri_therm)) if (IS_ERR(mt->clk_peri_therm))

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -11,6 +11,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/iio/consumer.h> #include <linux/iio/consumer.h>
@ -29,13 +30,17 @@
#define QPNP_TM_REG_ALARM_CTRL 0x46 #define QPNP_TM_REG_ALARM_CTRL 0x46
#define QPNP_TM_TYPE 0x09 #define QPNP_TM_TYPE 0x09
#define QPNP_TM_SUBTYPE 0x08 #define QPNP_TM_SUBTYPE_GEN1 0x08
#define QPNP_TM_SUBTYPE_GEN2 0x09
#define STATUS_STAGE_MASK 0x03 #define STATUS_GEN1_STAGE_MASK GENMASK(1, 0)
#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)
#define STATUS_GEN2_STATE_SHIFT 4
#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x03 #define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6)
#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
#define ALARM_CTRL_FORCE_ENABLE 0x80 #define ALARM_CTRL_FORCE_ENABLE BIT(7)
/* /*
* Trip point values based on threshold control * Trip point values based on threshold control
@ -58,6 +63,7 @@
struct qpnp_tm_chip { struct qpnp_tm_chip {
struct regmap *map; struct regmap *map;
struct thermal_zone_device *tz_dev; struct thermal_zone_device *tz_dev;
unsigned int subtype;
long temp; long temp;
unsigned int thresh; unsigned int thresh;
unsigned int stage; unsigned int stage;
@ -66,6 +72,9 @@ struct qpnp_tm_chip {
struct iio_channel *adc; struct iio_channel *adc;
}; };
/* This array maps from GEN2 alarm state to GEN1 alarm stage */
static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};
static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data) static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data)
{ {
unsigned int val; unsigned int val;
@ -84,13 +93,14 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
return regmap_write(chip->map, chip->base + addr, data); return regmap_write(chip->map, chip->base + addr, data);
} }
/* /**
* This function updates the internal temp value based on the * qpnp_tm_get_temp_stage() - return over-temperature stage
* current thermal stage and threshold as well as the previous stage * @chip: Pointer to the qpnp_tm chip
*
* Return: stage (GEN1) or state (GEN2) on success, or errno on failure.
*/ */
static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
{ {
unsigned int stage;
int ret; int ret;
u8 reg = 0; u8 reg = 0;
@ -98,16 +108,44 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
if (ret < 0) if (ret < 0)
return ret; return ret;
stage = reg & STATUS_STAGE_MASK; if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
ret = reg & STATUS_GEN1_STAGE_MASK;
else
ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT;
if (stage > chip->stage) { return ret;
}
/*
* This function updates the internal temp value based on the
* current thermal stage and threshold as well as the previous stage
*/
static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
{
unsigned int stage, stage_new, stage_old;
int ret;
ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
return ret;
stage = ret;
if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
stage_new = stage;
stage_old = chip->stage;
} else {
stage_new = alarm_state_map[stage];
stage_old = alarm_state_map[chip->stage];
}
if (stage_new > stage_old) {
/* increasing stage, use lower bound */ /* increasing stage, use lower bound */
chip->temp = (stage - 1) * TEMP_STAGE_STEP + chip->temp = (stage_new - 1) * TEMP_STAGE_STEP +
chip->thresh * TEMP_THRESH_STEP + chip->thresh * TEMP_THRESH_STEP +
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
} else if (stage < chip->stage) { } else if (stage_new < stage_old) {
/* decreasing stage, use upper bound */ /* decreasing stage, use upper bound */
chip->temp = stage * TEMP_STAGE_STEP + chip->temp = stage_new * TEMP_STAGE_STEP +
chip->thresh * TEMP_THRESH_STEP - chip->thresh * TEMP_THRESH_STEP -
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
} }
@ -162,28 +200,37 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
*/ */
static int qpnp_tm_init(struct qpnp_tm_chip *chip) static int qpnp_tm_init(struct qpnp_tm_chip *chip)
{ {
unsigned int stage;
int ret; int ret;
u8 reg; u8 reg = 0;
chip->thresh = THRESH_MIN; ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg);
chip->temp = DEFAULT_TEMP;
ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
if (ret < 0) if (ret < 0)
return ret; return ret;
chip->stage = reg & STATUS_STAGE_MASK; chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
chip->temp = DEFAULT_TEMP;
if (chip->stage) ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
return ret;
chip->stage = ret;
stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
? chip->stage : alarm_state_map[chip->stage];
if (stage)
chip->temp = chip->thresh * TEMP_THRESH_STEP + chip->temp = chip->thresh * TEMP_THRESH_STEP +
(chip->stage - 1) * TEMP_STAGE_STEP + (stage - 1) * TEMP_STAGE_STEP +
TEMP_THRESH_MIN; TEMP_THRESH_MIN;
/* /*
* Set threshold and disable software override of stage 2 and 3 * Set threshold and disable software override of stage 2 and 3
* shutdowns. * shutdowns.
*/ */
reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; chip->thresh = THRESH_MIN;
reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK);
reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -246,12 +293,15 @@ static int qpnp_tm_probe(struct platform_device *pdev)
return ret; return ret;
} }
if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) { if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
&& subtype != QPNP_TM_SUBTYPE_GEN2)) {
dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n", dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
type, subtype); type, subtype);
return -ENODEV; return -ENODEV;
} }
chip->subtype = subtype;
ret = qpnp_tm_init(chip); ret = qpnp_tm_init(chip);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "init failed\n"); dev_err(&pdev->dev, "init failed\n");

View file

@ -115,6 +115,7 @@ static int tsens_probe(struct platform_device *pdev)
struct tsens_device *tmdev; struct tsens_device *tmdev;
const struct tsens_data *data; const struct tsens_data *data;
const struct of_device_id *id; const struct of_device_id *id;
u32 num_sensors;
if (pdev->dev.of_node) if (pdev->dev.of_node)
dev = &pdev->dev; dev = &pdev->dev;
@ -129,19 +130,24 @@ static int tsens_probe(struct platform_device *pdev)
else else
data = &data_8960; data = &data_8960;
if (data->num_sensors <= 0) { num_sensors = data->num_sensors;
if (np)
of_property_read_u32(np, "#qcom,sensors", &num_sensors);
if (num_sensors <= 0) {
dev_err(dev, "invalid number of sensors\n"); dev_err(dev, "invalid number of sensors\n");
return -EINVAL; return -EINVAL;
} }
tmdev = devm_kzalloc(dev, tmdev = devm_kzalloc(dev,
struct_size(tmdev, sensor, data->num_sensors), struct_size(tmdev, sensor, num_sensors),
GFP_KERNEL); GFP_KERNEL);
if (!tmdev) if (!tmdev)
return -ENOMEM; return -ENOMEM;
tmdev->dev = dev; tmdev->dev = dev;
tmdev->num_sensors = data->num_sensors; tmdev->num_sensors = num_sensors;
tmdev->ops = data->ops; tmdev->ops = data->ops;
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < tmdev->num_sensors; i++) {
if (data->hw_ids) if (data->hw_ids)

View file

@ -132,7 +132,7 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */ #define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
/* no idea where these constants come from */ /* no idea where these constants come from */
#define TJ_1 96 #define TJ_1 116
#define TJ_3 -41 #define TJ_3 -41
static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef, static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
@ -146,7 +146,7 @@ static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
* Division is not scaled in BSP and if scaled it might overflow * Division is not scaled in BSP and if scaled it might overflow
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled * the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
*/ */
tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137) tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 157)
/ (ptat[0] - ptat[2])) - FIXPT_INT(41); / (ptat[0] - ptat[2])) - FIXPT_INT(41);
coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]), coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
@ -207,8 +207,8 @@ static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high)
{ {
struct rcar_gen3_thermal_tsc *tsc = devdata; struct rcar_gen3_thermal_tsc *tsc = devdata;
low = clamp_val(low, -40000, 125000); low = clamp_val(low, -40000, 120000);
high = clamp_val(high, -40000, 125000); high = clamp_val(high, -40000, 120000);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
@ -329,6 +329,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
{ .compatible = "renesas,r8a7795-thermal", }, { .compatible = "renesas,r8a7795-thermal", },
{ .compatible = "renesas,r8a7796-thermal", }, { .compatible = "renesas,r8a7796-thermal", },
{ .compatible = "renesas,r8a77965-thermal", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
@ -354,11 +355,11 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
/* default values if FUSEs are missing */ /* default values if FUSEs are missing */
/* TODO: Read values from hardware on supported platforms */ /* TODO: Read values from hardware on supported platforms */
int ptat[3] = { 2351, 1509, 435 }; int ptat[3] = { 2631, 1509, 435 };
int thcode[TSC_MAX_NUM][3] = { int thcode[TSC_MAX_NUM][3] = {
{ 3248, 2800, 2221 }, { 3397, 2800, 2221 },
{ 3245, 2795, 2216 }, { 3393, 2795, 2216 },
{ 3250, 2805, 2237 }, { 3389, 2805, 2237 },
}; };
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);

View file

@ -58,10 +58,47 @@ struct rcar_thermal_common {
spinlock_t lock; spinlock_t lock;
}; };
struct rcar_thermal_chip {
unsigned int use_of_thermal : 1;
unsigned int has_filonoff : 1;
unsigned int irq_per_ch : 1;
unsigned int needs_suspend_resume : 1;
unsigned int nirqs;
};
static const struct rcar_thermal_chip rcar_thermal = {
.use_of_thermal = 0,
.has_filonoff = 1,
.irq_per_ch = 0,
.needs_suspend_resume = 0,
.nirqs = 1,
};
static const struct rcar_thermal_chip rcar_gen2_thermal = {
.use_of_thermal = 1,
.has_filonoff = 1,
.irq_per_ch = 0,
.needs_suspend_resume = 0,
.nirqs = 1,
};
static const struct rcar_thermal_chip rcar_gen3_thermal = {
.use_of_thermal = 1,
.has_filonoff = 0,
.irq_per_ch = 1,
.needs_suspend_resume = 1,
/*
* The Gen3 chip has 3 interrupts, but this driver uses only 2
* interrupts to detect a temperature change, rise or fall.
*/
.nirqs = 2,
};
struct rcar_thermal_priv { struct rcar_thermal_priv {
void __iomem *base; void __iomem *base;
struct rcar_thermal_common *common; struct rcar_thermal_common *common;
struct thermal_zone_device *zone; struct thermal_zone_device *zone;
const struct rcar_thermal_chip *chip;
struct delayed_work work; struct delayed_work work;
struct mutex lock; struct mutex lock;
struct list_head list; struct list_head list;
@ -77,13 +114,20 @@ struct rcar_thermal_priv {
#define rcar_priv_to_dev(priv) ((priv)->common->dev) #define rcar_priv_to_dev(priv) ((priv)->common->dev)
#define rcar_has_irq_support(priv) ((priv)->common->base) #define rcar_has_irq_support(priv) ((priv)->common->base)
#define rcar_id_to_shift(priv) ((priv)->id * 8) #define rcar_id_to_shift(priv) ((priv)->id * 8)
#define rcar_of_data(dev) ((unsigned long)of_device_get_match_data(dev))
#define rcar_use_of_thermal(dev) (rcar_of_data(dev) == USE_OF_THERMAL)
#define USE_OF_THERMAL 1
static const struct of_device_id rcar_thermal_dt_ids[] = { static const struct of_device_id rcar_thermal_dt_ids[] = {
{ .compatible = "renesas,rcar-thermal", }, {
{ .compatible = "renesas,rcar-gen2-thermal", .data = (void *)USE_OF_THERMAL }, .compatible = "renesas,rcar-thermal",
.data = &rcar_thermal,
},
{
.compatible = "renesas,rcar-gen2-thermal",
.data = &rcar_gen2_thermal,
},
{
.compatible = "renesas,thermal-r8a77995",
.data = &rcar_gen3_thermal,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids); MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
@ -190,6 +234,7 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
* enable IRQ * enable IRQ
*/ */
if (rcar_has_irq_support(priv)) { if (rcar_has_irq_support(priv)) {
if (priv->chip->has_filonoff)
rcar_thermal_write(priv, FILONOFF, 0); rcar_thermal_write(priv, FILONOFF, 0);
/* enable Rising/Falling edge interrupt */ /* enable Rising/Falling edge interrupt */
@ -420,7 +465,7 @@ static int rcar_thermal_remove(struct platform_device *pdev)
rcar_thermal_for_each_priv(priv, common) { rcar_thermal_for_each_priv(priv, common) {
rcar_thermal_irq_disable(priv); rcar_thermal_irq_disable(priv);
if (rcar_use_of_thermal(dev)) if (priv->chip->use_of_thermal)
thermal_remove_hwmon_sysfs(priv->zone); thermal_remove_hwmon_sysfs(priv->zone);
else else
thermal_zone_device_unregister(priv->zone); thermal_zone_device_unregister(priv->zone);
@ -438,6 +483,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
struct rcar_thermal_priv *priv; struct rcar_thermal_priv *priv;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res, *irq; struct resource *res, *irq;
const struct rcar_thermal_chip *chip = of_device_get_match_data(dev);
int mres = 0; int mres = 0;
int i; int i;
int ret = -ENODEV; int ret = -ENODEV;
@ -457,14 +503,18 @@ static int rcar_thermal_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
for (i = 0; i < chip->nirqs; i++) {
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq) { if (!irq)
continue;
if (!common->base) {
/* /*
* platform has IRQ support. * platform has IRQ support.
* Then, driver uses common registers * Then, driver uses common registers
* rcar_has_irq_support() will be enabled * rcar_has_irq_support() will be enabled
*/ */
res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); res = platform_get_resource(pdev, IORESOURCE_MEM,
mres++);
common->base = devm_ioremap_resource(dev, res); common->base = devm_ioremap_resource(dev, res);
if (IS_ERR(common->base)) if (IS_ERR(common->base))
return PTR_ERR(common->base); return PTR_ERR(common->base);
@ -472,6 +522,18 @@ static int rcar_thermal_probe(struct platform_device *pdev)
idle = 0; /* polling delay is not needed */ idle = 0; /* polling delay is not needed */
} }
ret = devm_request_irq(dev, irq->start, rcar_thermal_irq,
IRQF_SHARED, dev_name(dev), common);
if (ret) {
dev_err(dev, "irq request failed\n ");
goto error_unregister;
}
/* update ENR bits */
if (chip->irq_per_ch)
enr_bits |= 1 << i;
}
for (i = 0;; i++) { for (i = 0;; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
if (!res) if (!res)
@ -491,6 +553,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
priv->common = common; priv->common = common;
priv->id = i; priv->id = i;
priv->chip = chip;
mutex_init(&priv->lock); mutex_init(&priv->lock);
INIT_LIST_HEAD(&priv->list); INIT_LIST_HEAD(&priv->list);
INIT_DELAYED_WORK(&priv->work, rcar_thermal_work); INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
@ -498,7 +561,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto error_unregister; goto error_unregister;
if (rcar_use_of_thermal(dev)) if (chip->use_of_thermal)
priv->zone = devm_thermal_zone_of_sensor_register( priv->zone = devm_thermal_zone_of_sensor_register(
dev, i, priv, dev, i, priv,
&rcar_thermal_zone_of_ops); &rcar_thermal_zone_of_ops);
@ -515,7 +578,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
goto error_unregister; goto error_unregister;
} }
if (rcar_use_of_thermal(dev)) { if (chip->use_of_thermal) {
/* /*
* thermal_zone doesn't enable hwmon as default, * thermal_zone doesn't enable hwmon as default,
* but, enable it here to keep compatible * but, enable it here to keep compatible
@ -531,20 +594,12 @@ static int rcar_thermal_probe(struct platform_device *pdev)
list_move_tail(&priv->list, &common->head); list_move_tail(&priv->list, &common->head);
/* update ENR bits */ /* update ENR bits */
if (!chip->irq_per_ch)
enr_bits |= 3 << (i * 8); enr_bits |= 3 << (i * 8);
} }
/* enable temperature comparation */ if (enr_bits)
if (irq) {
ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
dev_name(dev), common);
if (ret) {
dev_err(dev, "irq request failed\n ");
goto error_unregister;
}
rcar_thermal_common_write(common, ENR, enr_bits); rcar_thermal_common_write(common, ENR, enr_bits);
}
dev_info(dev, "%d sensor probed\n", i); dev_info(dev, "%d sensor probed\n", i);
@ -556,9 +611,48 @@ error_unregister:
return ret; return ret;
} }
#ifdef CONFIG_PM_SLEEP
static int rcar_thermal_suspend(struct device *dev)
{
struct rcar_thermal_common *common = dev_get_drvdata(dev);
struct rcar_thermal_priv *priv = list_first_entry(&common->head,
typeof(*priv), list);
if (priv->chip->needs_suspend_resume) {
rcar_thermal_common_write(common, ENR, 0);
rcar_thermal_irq_disable(priv);
rcar_thermal_bset(priv, THSCR, CPCTL, 0);
}
return 0;
}
static int rcar_thermal_resume(struct device *dev)
{
struct rcar_thermal_common *common = dev_get_drvdata(dev);
struct rcar_thermal_priv *priv = list_first_entry(&common->head,
typeof(*priv), list);
int ret;
if (priv->chip->needs_suspend_resume) {
ret = rcar_thermal_update_temp(priv);
if (ret < 0)
return ret;
rcar_thermal_irq_enable(priv);
rcar_thermal_common_write(common, ENR, 0x03);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend,
rcar_thermal_resume);
static struct platform_driver rcar_thermal_driver = { static struct platform_driver rcar_thermal_driver = {
.driver = { .driver = {
.name = "rcar_thermal", .name = "rcar_thermal",
.pm = &rcar_thermal_pm_ops,
.of_match_table = rcar_thermal_dt_ids, .of_match_table = rcar_thermal_dt_ids,
}, },
.probe = rcar_thermal_probe, .probe = rcar_thermal_probe,

File diff suppressed because it is too large Load diff

View file

@ -1,75 +0,0 @@
/*
* exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
* Amit Daniel Kachhap <amit.daniel@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _EXYNOS_TMU_H
#define _EXYNOS_TMU_H
#include <linux/cpu_cooling.h>
#include <dt-bindings/thermal/thermal_exynos.h>
enum soc_type {
SOC_ARCH_EXYNOS3250 = 1,
SOC_ARCH_EXYNOS4210,
SOC_ARCH_EXYNOS4412,
SOC_ARCH_EXYNOS5250,
SOC_ARCH_EXYNOS5260,
SOC_ARCH_EXYNOS5420,
SOC_ARCH_EXYNOS5420_TRIMINFO,
SOC_ARCH_EXYNOS5433,
SOC_ARCH_EXYNOS5440,
SOC_ARCH_EXYNOS7,
};
/**
* struct exynos_tmu_platform_data
* @gain: gain of amplifier in the positive-TC generator block
* 0 < gain <= 15
* @reference_voltage: reference voltage of amplifier
* in the positive-TC generator block
* 0 < reference_voltage <= 31
* @noise_cancel_mode: noise cancellation mode
* 000, 100, 101, 110 and 111 can be different modes
* @type: determines the type of SOC
* @efuse_value: platform defined fuse value
* @min_efuse_value: minimum valid trimming data
* @max_efuse_value: maximum valid trimming data
* @default_temp_offset: default temperature offset in case of no trimming
* @cal_type: calibration type for temperature
*
* This structure is required for configuration of exynos_tmu driver.
*/
struct exynos_tmu_platform_data {
u8 gain;
u8 reference_voltage;
u8 noise_cancel_mode;
u32 efuse_value;
u32 min_efuse_value;
u32 max_efuse_value;
u8 first_point_trim;
u8 second_point_trim;
u8 default_temp_offset;
enum soc_type type;
u32 cal_type;
};
#endif /* _EXYNOS_TMU_H */

View file

@ -240,31 +240,6 @@ struct tegra_soctherm {
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
}; };
/**
* clk_writel() - writes a value to a CAR register
* @ts: pointer to a struct tegra_soctherm
* @v: the value to write
* @reg: the register offset
*
* Writes @v to @reg. No return value.
*/
static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg)
{
writel(value, (ts->clk_regs + reg));
}
/**
* clk_readl() - reads specified register from CAR IP block
* @ts: pointer to a struct tegra_soctherm
* @reg: register address to be read
*
* Return: the value of the register
*/
static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg)
{
return readl(ts->clk_regs + reg);
}
/** /**
* ccroc_writel() - writes a value to a CCROC register * ccroc_writel() - writes a value to a CCROC register
* @ts: pointer to a struct tegra_soctherm * @ts: pointer to a struct tegra_soctherm
@ -926,7 +901,7 @@ static int throt_set_cdev_state(struct thermal_cooling_device *cdev,
return 0; return 0;
} }
static struct thermal_cooling_device_ops throt_cooling_ops = { static const struct thermal_cooling_device_ops throt_cooling_ops = {
.get_max_state = throt_get_cdev_max_state, .get_max_state = throt_get_cdev_max_state,
.get_cur_state = throt_get_cdev_cur_state, .get_cur_state = throt_get_cdev_cur_state,
.set_cur_state = throt_set_cdev_state, .set_cur_state = throt_set_cdev_state,
@ -1207,9 +1182,9 @@ static void tegra_soctherm_throttle(struct device *dev)
} else { } else {
writel(v, ts->regs + THROT_GLOBAL_CFG); writel(v, ts->regs + THROT_GLOBAL_CFG);
v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); v = readl(ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER);
v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);
clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); writel(v, ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER);
} }
/* initialize stats collection */ /* initialize stats collection */

View file

@ -310,7 +310,7 @@ omap5430_adc_to_temp[
119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000, 119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000,
123400, 123400,
/* Index 940 - 945 */ /* Index 940 - 945 */
123800, 1242000, 124600, 124900, 125000, 125000, 123800, 124200, 124600, 124900, 125000, 125000,
}; };
/* OMAP54xx ES2.0 data */ /* OMAP54xx ES2.0 data */

View file

@ -365,6 +365,10 @@ static const struct of_device_id uniphier_tm_dt_ids[] = {
.compatible = "socionext,uniphier-ld20-thermal", .compatible = "socionext,uniphier-ld20-thermal",
.data = &uniphier_ld20_tm_data, .data = &uniphier_ld20_tm_data,
}, },
{
.compatible = "socionext,uniphier-pxs3-thermal",
.data = &uniphier_ld20_tm_data,
},
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids); MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids);