Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal management updates from Zhang Rui: - introduce brcmstb AVS TMON thermal driver (Brian Norris) - add Rockchip RV1108 support in rockchip thermal driver (Rocky Hao) - major rework on HISI driver plus additional support of hisi3660 (Daniel Lezcano) - add nvmem-cells binding on imx6sx (Leonard Crestez) - fix a NULL pointer dereference on ti thermal driver unloading (Tony Lindgren) - improve tmon tool to make it easier to cross-compile tmon (Markus Mayer) - add Coffee Lake and Cannon Lake support for intel processor and pch thermal drivers (Srinivas Pandruvada) - other small fixes and cleanups (Arvind Yadav, Colin Ian King, Allen Wild, Nicolin Chen, Baruch SiachNiklas Söderlund, Arnd Bergmann) * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (44 commits) thermal: pch: Add Cannon Lake support thermal: int340x: processor_thermal: Add Coffee Lake support thermal: int340x: processor_thermal: Add Cannon Lake support thermal: bxt: remove redundant variable trip thermal: cpu_cooling: pr_err() strings should end with newlines thermal: add brcmstb AVS TMON driver Documentation: devicetree: add binding for Broadcom STB AVS TMON thermal/drivers/hisi: Add support for hi3660 SoC thermal/drivers/hisi: Prepare to add support for other hisi platforms thermal/drivers/hisi: Add platform prefix to function name thermal/drivers/hisi: Put platform code together thermal/drivers/qcom-spmi: Use devm_iio_channel_get thermal/drivers/generic-iio-adc: Switch tz request to devm version thermal/drivers/step_wise: Fix temperature regulation misbehavior thermal/drivers/hisi: Use round up step value thermal/drivers/hisi: Move the clk setup in the corresponding functions thermal/drivers/hisi: Remove mutex_lock in the code thermal/drivers/hisi: Remove thermal data back pointer thermal/drivers/hisi: Convert long to int thermal/drivers/hisi: Rename and remove unused field ...hifive-unleashed-5.1
commit
bec04432cb
|
@ -0,0 +1,20 @@
|
||||||
|
* Broadcom STB thermal management
|
||||||
|
|
||||||
|
Thermal management core, provided by the AVS TMON hardware block.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: must be "brcm,avs-tmon" and/or "brcm,avs-tmon-bcm7445"
|
||||||
|
- reg: address range for the AVS TMON registers
|
||||||
|
- interrupts: temperature monitor interrupt, for high/low threshold triggers
|
||||||
|
- interrupt-names: should be "tmon"
|
||||||
|
- interrupt-parent: the parent interrupt controller
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
thermal@f04d1500 {
|
||||||
|
compatible = "brcm,avs-tmon-bcm7445", "brcm,avs-tmon";
|
||||||
|
reg = <0xf04d1500 0x28>;
|
||||||
|
interrupts = <0x6>;
|
||||||
|
interrupt-names = "tmon";
|
||||||
|
interrupt-parent = <&avs_host_l2_intc>;
|
||||||
|
};
|
|
@ -7,10 +7,17 @@ Required properties:
|
||||||
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
|
||||||
control registers, e.g. ANATOP on imx6q.
|
control registers, e.g. ANATOP on imx6q.
|
||||||
|
- nvmem-cells: A phandle to the calibration cells provided by ocotp.
|
||||||
|
- nvmem-cell-names: Should be "calib", "temp_grade".
|
||||||
|
|
||||||
|
Deprecated properties:
|
||||||
- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
|
- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
|
||||||
calibration data, e.g. OCOTP on imx6q. The details about calibration data
|
calibration data, e.g. OCOTP on imx6q. The details about calibration data
|
||||||
can be found in SoC Reference Manual.
|
can be found in SoC Reference Manual.
|
||||||
|
|
||||||
|
Direct access to OCOTP via fsl,tempmon-data is incorrect on some newer chips
|
||||||
|
because it does not handle OCOTP clock requirements.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- clocks : thermal sensor's clock source.
|
- clocks : thermal sensor's clock source.
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible : should be "rockchip,<name>-tsadc"
|
- compatible : should be "rockchip,<name>-tsadc"
|
||||||
|
"rockchip,rv1108-tsadc": found on RV1108 SoCs
|
||||||
"rockchip,rk3228-tsadc": found on RK3228 SoCs
|
"rockchip,rk3228-tsadc": found on RK3228 SoCs
|
||||||
"rockchip,rk3288-tsadc": found on RK3288 SoCs
|
"rockchip,rk3288-tsadc": found on RK3288 SoCs
|
||||||
"rockchip,rk3328-tsadc": found on RK3328 SoCs
|
"rockchip,rk3328-tsadc": found on RK3328 SoCs
|
||||||
|
|
|
@ -2986,6 +2986,14 @@ S: Maintained
|
||||||
F: Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
|
F: Documentation/devicetree/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt
|
||||||
F: drivers/cpufreq/brcmstb*
|
F: drivers/cpufreq/brcmstb*
|
||||||
|
|
||||||
|
BROADCOM STB AVS TMON DRIVER
|
||||||
|
M: Markus Mayer <mmayer@broadcom.com>
|
||||||
|
M: bcm-kernel-feedback-list@broadcom.com
|
||||||
|
L: linux-pm@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/thermal/brcm,avs-tmon.txt
|
||||||
|
F: drivers/thermal/broadcom/brcmstb*
|
||||||
|
|
||||||
BROADCOM STB NAND FLASH DRIVER
|
BROADCOM STB NAND FLASH DRIVER
|
||||||
M: Brian Norris <computersforpeace@gmail.com>
|
M: Brian Norris <computersforpeace@gmail.com>
|
||||||
M: Kamal Dasu <kdasu.kdev@gmail.com>
|
M: Kamal Dasu <kdasu.kdev@gmail.com>
|
||||||
|
|
|
@ -206,6 +206,7 @@ config HISI_THERMAL
|
||||||
config IMX_THERMAL
|
config IMX_THERMAL
|
||||||
tristate "Temperature sensor driver for Freescale i.MX SoCs"
|
tristate "Temperature sensor driver for Freescale i.MX SoCs"
|
||||||
depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST
|
depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST
|
||||||
|
depends on NVMEM || !NVMEM
|
||||||
depends on MFD_SYSCON
|
depends on MFD_SYSCON
|
||||||
depends on OF
|
depends on OF
|
||||||
help
|
help
|
||||||
|
@ -408,7 +409,7 @@ config MTK_THERMAL
|
||||||
controller present in Mediatek SoCs
|
controller present in Mediatek SoCs
|
||||||
|
|
||||||
menu "Broadcom thermal drivers"
|
menu "Broadcom thermal drivers"
|
||||||
depends on ARCH_BCM || COMPILE_TEST
|
depends on ARCH_BCM || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
|
||||||
source "drivers/thermal/broadcom/Kconfig"
|
source "drivers/thermal/broadcom/Kconfig"
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ struct armada_thermal_data {
|
||||||
/* Test for a valid sensor value (optional) */
|
/* Test for a valid sensor value (optional) */
|
||||||
bool (*is_valid)(struct armada_thermal_priv *);
|
bool (*is_valid)(struct armada_thermal_priv *);
|
||||||
|
|
||||||
/* Formula coeficients: temp = (b + m * reg) / div */
|
/* Formula coeficients: temp = (b - m * reg) / div */
|
||||||
unsigned long coef_b;
|
unsigned long coef_b;
|
||||||
unsigned long coef_m;
|
unsigned long coef_m;
|
||||||
unsigned long coef_div;
|
unsigned long coef_div;
|
||||||
|
|
|
@ -6,6 +6,13 @@ config BCM2835_THERMAL
|
||||||
help
|
help
|
||||||
Support for thermal sensors on Broadcom bcm2835 SoCs.
|
Support for thermal sensors on Broadcom bcm2835 SoCs.
|
||||||
|
|
||||||
|
config BRCMSTB_THERMAL
|
||||||
|
tristate "Broadcom STB AVS TMON thermal driver"
|
||||||
|
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Enable this driver if you have a Broadcom STB SoC and would like
|
||||||
|
thermal framework support.
|
||||||
|
|
||||||
config BCM_NS_THERMAL
|
config BCM_NS_THERMAL
|
||||||
tristate "Northstar thermal driver"
|
tristate "Northstar thermal driver"
|
||||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
|
obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
|
||||||
|
obj-$(CONFIG_BRCMSTB_THERMAL) += brcmstb_thermal.o
|
||||||
obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o
|
obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
/*
|
||||||
|
* Broadcom STB AVS TMON thermal sensor driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2017 Broadcom
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DRV_NAME "brcmstb_thermal"
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) DRV_NAME ": " fmt
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/irqreturn.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/thermal.h>
|
||||||
|
|
||||||
|
#define AVS_TMON_STATUS 0x00
|
||||||
|
#define AVS_TMON_STATUS_valid_msk BIT(11)
|
||||||
|
#define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
|
||||||
|
#define AVS_TMON_STATUS_data_shift 1
|
||||||
|
|
||||||
|
#define AVS_TMON_EN_OVERTEMP_RESET 0x04
|
||||||
|
#define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
|
||||||
|
|
||||||
|
#define AVS_TMON_RESET_THRESH 0x08
|
||||||
|
#define AVS_TMON_RESET_THRESH_msk GENMASK(10, 1)
|
||||||
|
#define AVS_TMON_RESET_THRESH_shift 1
|
||||||
|
|
||||||
|
#define AVS_TMON_INT_IDLE_TIME 0x10
|
||||||
|
|
||||||
|
#define AVS_TMON_EN_TEMP_INT_SRCS 0x14
|
||||||
|
#define AVS_TMON_EN_TEMP_INT_SRCS_high BIT(1)
|
||||||
|
#define AVS_TMON_EN_TEMP_INT_SRCS_low BIT(0)
|
||||||
|
|
||||||
|
#define AVS_TMON_INT_THRESH 0x18
|
||||||
|
#define AVS_TMON_INT_THRESH_high_msk GENMASK(26, 17)
|
||||||
|
#define AVS_TMON_INT_THRESH_high_shift 17
|
||||||
|
#define AVS_TMON_INT_THRESH_low_msk GENMASK(10, 1)
|
||||||
|
#define AVS_TMON_INT_THRESH_low_shift 1
|
||||||
|
|
||||||
|
#define AVS_TMON_TEMP_INT_CODE 0x1c
|
||||||
|
#define AVS_TMON_TP_TEST_ENABLE 0x20
|
||||||
|
|
||||||
|
/* Default coefficients */
|
||||||
|
#define AVS_TMON_TEMP_SLOPE -487
|
||||||
|
#define AVS_TMON_TEMP_OFFSET 410040
|
||||||
|
|
||||||
|
/* HW related temperature constants */
|
||||||
|
#define AVS_TMON_TEMP_MAX 0x3ff
|
||||||
|
#define AVS_TMON_TEMP_MIN -88161
|
||||||
|
#define AVS_TMON_TEMP_MASK AVS_TMON_TEMP_MAX
|
||||||
|
|
||||||
|
enum avs_tmon_trip_type {
|
||||||
|
TMON_TRIP_TYPE_LOW = 0,
|
||||||
|
TMON_TRIP_TYPE_HIGH,
|
||||||
|
TMON_TRIP_TYPE_RESET,
|
||||||
|
TMON_TRIP_TYPE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct avs_tmon_trip {
|
||||||
|
/* HW bit to enable the trip */
|
||||||
|
u32 enable_offs;
|
||||||
|
u32 enable_mask;
|
||||||
|
|
||||||
|
/* HW field to read the trip temperature */
|
||||||
|
u32 reg_offs;
|
||||||
|
u32 reg_msk;
|
||||||
|
int reg_shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct avs_tmon_trip avs_tmon_trips[] = {
|
||||||
|
/* Trips when temperature is below threshold */
|
||||||
|
[TMON_TRIP_TYPE_LOW] = {
|
||||||
|
.enable_offs = AVS_TMON_EN_TEMP_INT_SRCS,
|
||||||
|
.enable_mask = AVS_TMON_EN_TEMP_INT_SRCS_low,
|
||||||
|
.reg_offs = AVS_TMON_INT_THRESH,
|
||||||
|
.reg_msk = AVS_TMON_INT_THRESH_low_msk,
|
||||||
|
.reg_shift = AVS_TMON_INT_THRESH_low_shift,
|
||||||
|
},
|
||||||
|
/* Trips when temperature is above threshold */
|
||||||
|
[TMON_TRIP_TYPE_HIGH] = {
|
||||||
|
.enable_offs = AVS_TMON_EN_TEMP_INT_SRCS,
|
||||||
|
.enable_mask = AVS_TMON_EN_TEMP_INT_SRCS_high,
|
||||||
|
.reg_offs = AVS_TMON_INT_THRESH,
|
||||||
|
.reg_msk = AVS_TMON_INT_THRESH_high_msk,
|
||||||
|
.reg_shift = AVS_TMON_INT_THRESH_high_shift,
|
||||||
|
},
|
||||||
|
/* Automatically resets chip when above threshold */
|
||||||
|
[TMON_TRIP_TYPE_RESET] = {
|
||||||
|
.enable_offs = AVS_TMON_EN_OVERTEMP_RESET,
|
||||||
|
.enable_mask = AVS_TMON_EN_OVERTEMP_RESET_msk,
|
||||||
|
.reg_offs = AVS_TMON_RESET_THRESH,
|
||||||
|
.reg_msk = AVS_TMON_RESET_THRESH_msk,
|
||||||
|
.reg_shift = AVS_TMON_RESET_THRESH_shift,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct brcmstb_thermal_priv {
|
||||||
|
void __iomem *tmon_base;
|
||||||
|
struct device *dev;
|
||||||
|
struct thermal_zone_device *thermal;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
|
||||||
|
int *offset)
|
||||||
|
{
|
||||||
|
*slope = thermal_zone_get_slope(tz);
|
||||||
|
*offset = thermal_zone_get_offset(tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a HW code to a temperature reading (millidegree celsius) */
|
||||||
|
static inline int avs_tmon_code_to_temp(struct thermal_zone_device *tz,
|
||||||
|
u32 code)
|
||||||
|
{
|
||||||
|
const int val = code & AVS_TMON_TEMP_MASK;
|
||||||
|
int slope, offset;
|
||||||
|
|
||||||
|
avs_tmon_get_coeffs(tz, &slope, &offset);
|
||||||
|
|
||||||
|
return slope * val + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a temperature value (millidegree celsius) to a HW code
|
||||||
|
*
|
||||||
|
* @temp: temperature to convert
|
||||||
|
* @low: if true, round toward the low side
|
||||||
|
*/
|
||||||
|
static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
|
||||||
|
int temp, bool low)
|
||||||
|
{
|
||||||
|
int slope, offset;
|
||||||
|
|
||||||
|
if (temp < AVS_TMON_TEMP_MIN)
|
||||||
|
return AVS_TMON_TEMP_MAX; /* Maximum code value */
|
||||||
|
|
||||||
|
avs_tmon_get_coeffs(tz, &slope, &offset);
|
||||||
|
|
||||||
|
if (temp >= offset)
|
||||||
|
return 0; /* Minimum code value */
|
||||||
|
|
||||||
|
if (low)
|
||||||
|
return (u32)(DIV_ROUND_UP(offset - temp, abs(slope)));
|
||||||
|
else
|
||||||
|
return (u32)((offset - temp) / abs(slope));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcmstb_get_temp(void *data, int *temp)
|
||||||
|
{
|
||||||
|
struct brcmstb_thermal_priv *priv = data;
|
||||||
|
u32 val;
|
||||||
|
long t;
|
||||||
|
|
||||||
|
val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
|
||||||
|
|
||||||
|
if (!(val & AVS_TMON_STATUS_valid_msk)) {
|
||||||
|
dev_err(priv->dev, "reading not valid\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
|
||||||
|
|
||||||
|
t = avs_tmon_code_to_temp(priv->thermal, val);
|
||||||
|
if (t < 0)
|
||||||
|
*temp = 0;
|
||||||
|
else
|
||||||
|
*temp = t;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avs_tmon_trip_enable(struct brcmstb_thermal_priv *priv,
|
||||||
|
enum avs_tmon_trip_type type, int en)
|
||||||
|
{
|
||||||
|
struct avs_tmon_trip *trip = &avs_tmon_trips[type];
|
||||||
|
u32 val = __raw_readl(priv->tmon_base + trip->enable_offs);
|
||||||
|
|
||||||
|
dev_dbg(priv->dev, "%sable trip, type %d\n", en ? "en" : "dis", type);
|
||||||
|
|
||||||
|
if (en)
|
||||||
|
val |= trip->enable_mask;
|
||||||
|
else
|
||||||
|
val &= ~trip->enable_mask;
|
||||||
|
|
||||||
|
__raw_writel(val, priv->tmon_base + trip->enable_offs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avs_tmon_get_trip_temp(struct brcmstb_thermal_priv *priv,
|
||||||
|
enum avs_tmon_trip_type type)
|
||||||
|
{
|
||||||
|
struct avs_tmon_trip *trip = &avs_tmon_trips[type];
|
||||||
|
u32 val = __raw_readl(priv->tmon_base + trip->reg_offs);
|
||||||
|
|
||||||
|
val &= trip->reg_msk;
|
||||||
|
val >>= trip->reg_shift;
|
||||||
|
|
||||||
|
return avs_tmon_code_to_temp(priv->thermal, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avs_tmon_set_trip_temp(struct brcmstb_thermal_priv *priv,
|
||||||
|
enum avs_tmon_trip_type type,
|
||||||
|
int temp)
|
||||||
|
{
|
||||||
|
struct avs_tmon_trip *trip = &avs_tmon_trips[type];
|
||||||
|
u32 val, orig;
|
||||||
|
|
||||||
|
dev_dbg(priv->dev, "set temp %d to %d\n", type, temp);
|
||||||
|
|
||||||
|
/* round toward low temp for the low interrupt */
|
||||||
|
val = avs_tmon_temp_to_code(priv->thermal, temp,
|
||||||
|
type == TMON_TRIP_TYPE_LOW);
|
||||||
|
|
||||||
|
val <<= trip->reg_shift;
|
||||||
|
val &= trip->reg_msk;
|
||||||
|
|
||||||
|
orig = __raw_readl(priv->tmon_base + trip->reg_offs);
|
||||||
|
orig &= ~trip->reg_msk;
|
||||||
|
orig |= val;
|
||||||
|
__raw_writel(orig, priv->tmon_base + trip->reg_offs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avs_tmon_get_intr_temp(struct brcmstb_thermal_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = __raw_readl(priv->tmon_base + AVS_TMON_TEMP_INT_CODE);
|
||||||
|
return avs_tmon_code_to_temp(priv->thermal, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t brcmstb_tmon_irq_thread(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct brcmstb_thermal_priv *priv = data;
|
||||||
|
int low, high, intr;
|
||||||
|
|
||||||
|
low = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_LOW);
|
||||||
|
high = avs_tmon_get_trip_temp(priv, TMON_TRIP_TYPE_HIGH);
|
||||||
|
intr = avs_tmon_get_intr_temp(priv);
|
||||||
|
|
||||||
|
dev_dbg(priv->dev, "low/intr/high: %d/%d/%d\n",
|
||||||
|
low, intr, high);
|
||||||
|
|
||||||
|
/* Disable high-temp until next threshold shift */
|
||||||
|
if (intr >= high)
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
|
||||||
|
/* Disable low-temp until next threshold shift */
|
||||||
|
if (intr <= low)
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notify using the interrupt temperature, in case the temperature
|
||||||
|
* changes before it can next be read out
|
||||||
|
*/
|
||||||
|
thermal_zone_device_update(priv->thermal, intr);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcmstb_set_trips(void *data, int low, int high)
|
||||||
|
{
|
||||||
|
struct brcmstb_thermal_priv *priv = data;
|
||||||
|
|
||||||
|
dev_dbg(priv->dev, "set trips %d <--> %d\n", low, high);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable low-temp if "low" is too small. As per thermal framework
|
||||||
|
* API, we use -INT_MAX rather than INT_MIN.
|
||||||
|
*/
|
||||||
|
if (low <= -INT_MAX) {
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 0);
|
||||||
|
} else {
|
||||||
|
avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_LOW, low);
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_LOW, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable high-temp if "high" is too big. */
|
||||||
|
if (high == INT_MAX) {
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 0);
|
||||||
|
} else {
|
||||||
|
avs_tmon_set_trip_temp(priv, TMON_TRIP_TYPE_HIGH, high);
|
||||||
|
avs_tmon_trip_enable(priv, TMON_TRIP_TYPE_HIGH, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct thermal_zone_of_device_ops of_ops = {
|
||||||
|
.get_temp = brcmstb_get_temp,
|
||||||
|
.set_trips = brcmstb_set_trips,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id brcmstb_thermal_id_table[] = {
|
||||||
|
{ .compatible = "brcm,avs-tmon" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
|
||||||
|
|
||||||
|
static int brcmstb_thermal_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct thermal_zone_device *thermal;
|
||||||
|
struct brcmstb_thermal_priv *priv;
|
||||||
|
struct resource *res;
|
||||||
|
int irq, ret;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->tmon_base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(priv->tmon_base))
|
||||||
|
return PTR_ERR(priv->tmon_base);
|
||||||
|
|
||||||
|
priv->dev = &pdev->dev;
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
|
||||||
|
if (IS_ERR(thermal)) {
|
||||||
|
ret = PTR_ERR(thermal);
|
||||||
|
dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->thermal = thermal;
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0) {
|
||||||
|
dev_err(&pdev->dev, "could not get IRQ\n");
|
||||||
|
ret = irq;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
|
brcmstb_tmon_irq_thread, IRQF_ONESHOT,
|
||||||
|
DRV_NAME, priv);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
thermal_zone_of_sensor_unregister(&pdev->dev, thermal);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brcmstb_thermal_exit(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct brcmstb_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
struct thermal_zone_device *thermal = priv->thermal;
|
||||||
|
|
||||||
|
if (thermal)
|
||||||
|
thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver brcmstb_thermal_driver = {
|
||||||
|
.probe = brcmstb_thermal_probe,
|
||||||
|
.remove = brcmstb_thermal_exit,
|
||||||
|
.driver = {
|
||||||
|
.name = DRV_NAME,
|
||||||
|
.of_match_table = brcmstb_thermal_id_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(brcmstb_thermal_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Brian Norris");
|
||||||
|
MODULE_DESCRIPTION("Broadcom STB AVS TMON thermal driver");
|
|
@ -696,7 +696,7 @@ __cpufreq_cooling_register(struct device_node *np,
|
||||||
bool first;
|
bool first;
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(policy)) {
|
if (IS_ERR_OR_NULL(policy)) {
|
||||||
pr_err("%s: cpufreq policy isn't valid: %p", __func__, policy);
|
pr_err("%s: cpufreq policy isn't valid: %p\n", __func__, policy);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,186 +23,423 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
#include "thermal_core.h"
|
#include "thermal_core.h"
|
||||||
|
|
||||||
#define TEMP0_TH (0x4)
|
#define HI6220_TEMP0_LAG (0x0)
|
||||||
#define TEMP0_RST_TH (0x8)
|
#define HI6220_TEMP0_TH (0x4)
|
||||||
#define TEMP0_CFG (0xC)
|
#define HI6220_TEMP0_RST_TH (0x8)
|
||||||
#define TEMP0_EN (0x10)
|
#define HI6220_TEMP0_CFG (0xC)
|
||||||
#define TEMP0_INT_EN (0x14)
|
#define HI6220_TEMP0_CFG_SS_MSK (0xF000)
|
||||||
#define TEMP0_INT_CLR (0x18)
|
#define HI6220_TEMP0_CFG_HDAK_MSK (0x30)
|
||||||
#define TEMP0_RST_MSK (0x1C)
|
#define HI6220_TEMP0_EN (0x10)
|
||||||
#define TEMP0_VALUE (0x28)
|
#define HI6220_TEMP0_INT_EN (0x14)
|
||||||
|
#define HI6220_TEMP0_INT_CLR (0x18)
|
||||||
|
#define HI6220_TEMP0_RST_MSK (0x1C)
|
||||||
|
#define HI6220_TEMP0_VALUE (0x28)
|
||||||
|
|
||||||
#define HISI_TEMP_BASE (-60)
|
#define HI3660_OFFSET(chan) ((chan) * 0x40)
|
||||||
#define HISI_TEMP_RESET (100000)
|
#define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C)
|
||||||
|
#define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20)
|
||||||
|
#define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28)
|
||||||
|
#define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C)
|
||||||
|
#define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30)
|
||||||
|
|
||||||
#define HISI_MAX_SENSORS 4
|
#define HI6220_TEMP_BASE (-60000)
|
||||||
|
#define HI6220_TEMP_RESET (100000)
|
||||||
|
#define HI6220_TEMP_STEP (785)
|
||||||
|
#define HI6220_TEMP_LAG (3500)
|
||||||
|
|
||||||
|
#define HI3660_TEMP_BASE (-63780)
|
||||||
|
#define HI3660_TEMP_STEP (205)
|
||||||
|
#define HI3660_TEMP_LAG (4000)
|
||||||
|
|
||||||
|
#define HI6220_DEFAULT_SENSOR 2
|
||||||
|
#define HI3660_DEFAULT_SENSOR 1
|
||||||
|
|
||||||
struct hisi_thermal_sensor {
|
struct hisi_thermal_sensor {
|
||||||
struct hisi_thermal_data *thermal;
|
|
||||||
struct thermal_zone_device *tzd;
|
struct thermal_zone_device *tzd;
|
||||||
|
|
||||||
long sensor_temp;
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t thres_temp;
|
uint32_t thres_temp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hisi_thermal_data {
|
struct hisi_thermal_data {
|
||||||
struct mutex thermal_lock; /* protects register data */
|
int (*get_temp)(struct hisi_thermal_data *data);
|
||||||
|
int (*enable_sensor)(struct hisi_thermal_data *data);
|
||||||
|
int (*disable_sensor)(struct hisi_thermal_data *data);
|
||||||
|
int (*irq_handler)(struct hisi_thermal_data *data);
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct hisi_thermal_sensor sensors[HISI_MAX_SENSORS];
|
struct hisi_thermal_sensor sensor;
|
||||||
|
|
||||||
int irq, irq_bind_sensor;
|
|
||||||
bool irq_enabled;
|
|
||||||
|
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* in millicelsius */
|
/*
|
||||||
static inline int _step_to_temp(int step)
|
* The temperature computation on the tsensor is as follow:
|
||||||
|
* Unit: millidegree Celsius
|
||||||
|
* Step: 200/255 (0.7843)
|
||||||
|
* Temperature base: -60°C
|
||||||
|
*
|
||||||
|
* The register is programmed in temperature steps, every step is 785
|
||||||
|
* millidegree and begins at -60 000 m°C
|
||||||
|
*
|
||||||
|
* The temperature from the steps:
|
||||||
|
*
|
||||||
|
* Temp = TempBase + (steps x 785)
|
||||||
|
*
|
||||||
|
* and the steps from the temperature:
|
||||||
|
*
|
||||||
|
* steps = (Temp - TempBase) / 785
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline int hi6220_thermal_step_to_temp(int step)
|
||||||
{
|
{
|
||||||
/*
|
return HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP);
|
||||||
* Every step equals (1 * 200) / 255 celsius, and finally
|
|
||||||
* need convert to millicelsius.
|
|
||||||
*/
|
|
||||||
return (HISI_TEMP_BASE * 1000 + (step * 200000 / 255));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline long _temp_to_step(long temp)
|
static inline int hi6220_thermal_temp_to_step(int temp)
|
||||||
{
|
{
|
||||||
return ((temp - HISI_TEMP_BASE * 1000) * 255) / 200000;
|
return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long hisi_thermal_get_sensor_temp(struct hisi_thermal_data *data,
|
/*
|
||||||
struct hisi_thermal_sensor *sensor)
|
* for Hi3660,
|
||||||
|
* Step: 189/922 (0.205)
|
||||||
|
* Temperature base: -63.780°C
|
||||||
|
*
|
||||||
|
* The register is programmed in temperature steps, every step is 205
|
||||||
|
* millidegree and begins at -63 780 m°C
|
||||||
|
*/
|
||||||
|
static inline int hi3660_thermal_step_to_temp(int step)
|
||||||
{
|
{
|
||||||
long val;
|
return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&data->thermal_lock);
|
static inline int hi3660_thermal_temp_to_step(int temp)
|
||||||
|
{
|
||||||
|
return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP);
|
||||||
|
}
|
||||||
|
|
||||||
/* disable interrupt */
|
/*
|
||||||
writel(0x0, data->regs + TEMP0_INT_EN);
|
* The lag register contains 5 bits encoding the temperature in steps.
|
||||||
writel(0x1, data->regs + TEMP0_INT_CLR);
|
*
|
||||||
|
* Each time the temperature crosses the threshold boundary, an
|
||||||
|
* interrupt is raised. It could be when the temperature is going
|
||||||
|
* above the threshold or below. However, if the temperature is
|
||||||
|
* fluctuating around this value due to the load, we can receive
|
||||||
|
* several interrupts which may not desired.
|
||||||
|
*
|
||||||
|
* We can setup a temperature representing the delta between the
|
||||||
|
* threshold and the current temperature when the temperature is
|
||||||
|
* decreasing.
|
||||||
|
*
|
||||||
|
* For instance: the lag register is 5°C, the threshold is 65°C, when
|
||||||
|
* the temperature reaches 65°C an interrupt is raised and when the
|
||||||
|
* temperature decrease to 65°C - 5°C another interrupt is raised.
|
||||||
|
*
|
||||||
|
* A very short lag can lead to an interrupt storm, a long lag
|
||||||
|
* increase the latency to react to the temperature changes. In our
|
||||||
|
* case, that is not really a problem as we are polling the
|
||||||
|
* temperature.
|
||||||
|
*
|
||||||
|
* [0:4] : lag register
|
||||||
|
*
|
||||||
|
* The temperature is coded in steps, cf. HI6220_TEMP_STEP.
|
||||||
|
*
|
||||||
|
* Min : 0x00 : 0.0 °C
|
||||||
|
* Max : 0x1F : 24.3 °C
|
||||||
|
*
|
||||||
|
* The 'value' parameter is in milliCelsius.
|
||||||
|
*/
|
||||||
|
static inline void hi6220_thermal_set_lag(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F,
|
||||||
|
addr + HI6220_TEMP0_LAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI6220_TEMP0_INT_CLR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI6220_TEMP0_INT_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp)
|
||||||
|
{
|
||||||
|
writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00,
|
||||||
|
addr + HI6220_TEMP0_TH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp)
|
||||||
|
{
|
||||||
|
writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI6220_TEMP0_RST_MSK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi6220_thermal_enable(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI6220_TEMP0_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hi6220_thermal_get_temperature(void __iomem *addr)
|
||||||
|
{
|
||||||
|
return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [0:6] lag register
|
||||||
|
*
|
||||||
|
* The temperature is coded in steps, cf. HI3660_TEMP_STEP.
|
||||||
|
*
|
||||||
|
* Min : 0x00 : 0.0 °C
|
||||||
|
* Max : 0x7F : 26.0 °C
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void hi3660_thermal_set_lag(void __iomem *addr,
|
||||||
|
int id, int value)
|
||||||
|
{
|
||||||
|
writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F,
|
||||||
|
addr + HI3660_LAG(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi3660_thermal_alarm_clear(void __iomem *addr,
|
||||||
|
int id, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI3660_INT_CLR(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi3660_thermal_alarm_enable(void __iomem *addr,
|
||||||
|
int id, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI3660_INT_EN(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hi3660_thermal_alarm_set(void __iomem *addr,
|
||||||
|
int id, int value)
|
||||||
|
{
|
||||||
|
writel(value, addr + HI3660_TH(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id)
|
||||||
|
{
|
||||||
|
return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temperature configuration register - Sensor selection
|
||||||
|
*
|
||||||
|
* Bits [19:12]
|
||||||
|
*
|
||||||
|
* 0x0: local sensor (default)
|
||||||
|
* 0x1: remote sensor 1 (ACPU cluster 1)
|
||||||
|
* 0x2: remote sensor 2 (ACPU cluster 0)
|
||||||
|
* 0x3: remote sensor 3 (G3D)
|
||||||
|
*/
|
||||||
|
static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor)
|
||||||
|
{
|
||||||
|
writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) |
|
||||||
|
(sensor << 12), addr + HI6220_TEMP0_CFG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temperature configuration register - Hdak conversion polling interval
|
||||||
|
*
|
||||||
|
* Bits [5:4]
|
||||||
|
*
|
||||||
|
* 0x0 : 0.768 ms
|
||||||
|
* 0x1 : 6.144 ms
|
||||||
|
* 0x2 : 49.152 ms
|
||||||
|
* 0x3 : 393.216 ms
|
||||||
|
*/
|
||||||
|
static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
|
||||||
|
{
|
||||||
|
writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) |
|
||||||
|
(value << 4), addr + HI6220_TEMP0_CFG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6220_thermal_irq_handler(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
hi6220_thermal_alarm_clear(data->regs, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi3660_thermal_irq_handler(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
hi3660_thermal_alarm_clear(data->regs, data->sensor.id, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6220_thermal_get_temp(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
return hi6220_thermal_get_temperature(data->regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi3660_thermal_get_temp(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
return hi3660_thermal_get_temperature(data->regs, data->sensor.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
/* disable sensor module */
|
||||||
|
hi6220_thermal_enable(data->regs, 0);
|
||||||
|
hi6220_thermal_alarm_enable(data->regs, 0);
|
||||||
|
hi6220_thermal_reset_enable(data->regs, 0);
|
||||||
|
|
||||||
|
clk_disable_unprepare(data->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi3660_thermal_disable_sensor(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
/* disable sensor module */
|
||||||
|
hi3660_thermal_alarm_enable(data->regs, data->sensor.id, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
struct hisi_thermal_sensor *sensor = &data->sensor;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* enable clock for tsensor */
|
||||||
|
ret = clk_prepare_enable(data->clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* disable module firstly */
|
/* disable module firstly */
|
||||||
writel(0x0, data->regs + TEMP0_EN);
|
hi6220_thermal_reset_enable(data->regs, 0);
|
||||||
|
hi6220_thermal_enable(data->regs, 0);
|
||||||
|
|
||||||
/* select sensor id */
|
/* select sensor id */
|
||||||
writel((sensor->id << 12), data->regs + TEMP0_CFG);
|
hi6220_thermal_sensor_select(data->regs, sensor->id);
|
||||||
|
|
||||||
/* enable module */
|
|
||||||
writel(0x1, data->regs + TEMP0_EN);
|
|
||||||
|
|
||||||
usleep_range(3000, 5000);
|
|
||||||
|
|
||||||
val = readl(data->regs + TEMP0_VALUE);
|
|
||||||
val = _step_to_temp(val);
|
|
||||||
|
|
||||||
mutex_unlock(&data->thermal_lock);
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hisi_thermal_enable_bind_irq_sensor
|
|
||||||
(struct hisi_thermal_data *data)
|
|
||||||
{
|
|
||||||
struct hisi_thermal_sensor *sensor;
|
|
||||||
|
|
||||||
mutex_lock(&data->thermal_lock);
|
|
||||||
|
|
||||||
sensor = &data->sensors[data->irq_bind_sensor];
|
|
||||||
|
|
||||||
/* setting the hdak time */
|
/* setting the hdak time */
|
||||||
writel(0x0, data->regs + TEMP0_CFG);
|
hi6220_thermal_hdak_set(data->regs, 0);
|
||||||
|
|
||||||
/* disable module firstly */
|
/* setting lag value between current temp and the threshold */
|
||||||
writel(0x0, data->regs + TEMP0_RST_MSK);
|
hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG);
|
||||||
writel(0x0, data->regs + TEMP0_EN);
|
|
||||||
|
|
||||||
/* select sensor id */
|
|
||||||
writel((sensor->id << 12), data->regs + TEMP0_CFG);
|
|
||||||
|
|
||||||
/* enable for interrupt */
|
/* enable for interrupt */
|
||||||
writel(_temp_to_step(sensor->thres_temp) | 0x0FFFFFF00,
|
hi6220_thermal_alarm_set(data->regs, sensor->thres_temp);
|
||||||
data->regs + TEMP0_TH);
|
|
||||||
|
|
||||||
writel(_temp_to_step(HISI_TEMP_RESET), data->regs + TEMP0_RST_TH);
|
hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET);
|
||||||
|
|
||||||
/* enable module */
|
/* enable module */
|
||||||
writel(0x1, data->regs + TEMP0_RST_MSK);
|
hi6220_thermal_reset_enable(data->regs, 1);
|
||||||
writel(0x1, data->regs + TEMP0_EN);
|
hi6220_thermal_enable(data->regs, 1);
|
||||||
|
|
||||||
writel(0x0, data->regs + TEMP0_INT_CLR);
|
hi6220_thermal_alarm_clear(data->regs, 0);
|
||||||
writel(0x1, data->regs + TEMP0_INT_EN);
|
hi6220_thermal_alarm_enable(data->regs, 1);
|
||||||
|
|
||||||
usleep_range(3000, 5000);
|
return 0;
|
||||||
|
|
||||||
mutex_unlock(&data->thermal_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data)
|
static int hi3660_thermal_enable_sensor(struct hisi_thermal_data *data)
|
||||||
{
|
{
|
||||||
mutex_lock(&data->thermal_lock);
|
unsigned int value;
|
||||||
|
struct hisi_thermal_sensor *sensor = &data->sensor;
|
||||||
|
|
||||||
/* disable sensor module */
|
/* disable interrupt */
|
||||||
writel(0x0, data->regs + TEMP0_INT_EN);
|
hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
|
||||||
writel(0x0, data->regs + TEMP0_RST_MSK);
|
|
||||||
writel(0x0, data->regs + TEMP0_EN);
|
|
||||||
|
|
||||||
mutex_unlock(&data->thermal_lock);
|
/* setting lag value between current temp and the threshold */
|
||||||
|
hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG);
|
||||||
|
|
||||||
|
/* set interrupt threshold */
|
||||||
|
value = hi3660_thermal_temp_to_step(sensor->thres_temp);
|
||||||
|
hi3660_thermal_alarm_set(data->regs, sensor->id, value);
|
||||||
|
|
||||||
|
/* enable interrupt */
|
||||||
|
hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
|
||||||
|
hi3660_thermal_alarm_enable(data->regs, sensor->id, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hisi_thermal_get_temp(void *_sensor, int *temp)
|
static int hi6220_thermal_probe(struct hisi_thermal_data *data)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_sensor *sensor = _sensor;
|
struct platform_device *pdev = data->pdev;
|
||||||
struct hisi_thermal_data *data = sensor->thermal;
|
struct device *dev = &pdev->dev;
|
||||||
|
struct resource *res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
int sensor_id = -1, i;
|
data->get_temp = hi6220_thermal_get_temp;
|
||||||
long max_temp = 0;
|
data->enable_sensor = hi6220_thermal_enable_sensor;
|
||||||
|
data->disable_sensor = hi6220_thermal_disable_sensor;
|
||||||
|
data->irq_handler = hi6220_thermal_irq_handler;
|
||||||
|
|
||||||
*temp = hisi_thermal_get_sensor_temp(data, sensor);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
data->regs = devm_ioremap_resource(dev, res);
|
||||||
sensor->sensor_temp = *temp;
|
if (IS_ERR(data->regs)) {
|
||||||
|
dev_err(dev, "failed to get io address\n");
|
||||||
for (i = 0; i < HISI_MAX_SENSORS; i++) {
|
return PTR_ERR(data->regs);
|
||||||
if (!data->sensors[i].tzd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (data->sensors[i].sensor_temp >= max_temp) {
|
|
||||||
max_temp = data->sensors[i].sensor_temp;
|
|
||||||
sensor_id = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no sensor has been enabled, then skip to enable irq */
|
data->clk = devm_clk_get(dev, "thermal_clk");
|
||||||
if (sensor_id == -1)
|
if (IS_ERR(data->clk)) {
|
||||||
return 0;
|
ret = PTR_ERR(data->clk);
|
||||||
|
if (ret != -EPROBE_DEFER)
|
||||||
mutex_lock(&data->thermal_lock);
|
dev_err(dev, "failed to get thermal clk: %d\n", ret);
|
||||||
data->irq_bind_sensor = sensor_id;
|
return ret;
|
||||||
mutex_unlock(&data->thermal_lock);
|
|
||||||
|
|
||||||
dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n",
|
|
||||||
sensor->id, data->irq_enabled, *temp, sensor->thres_temp);
|
|
||||||
/*
|
|
||||||
* Bind irq to sensor for two cases:
|
|
||||||
* Reenable alarm IRQ if temperature below threshold;
|
|
||||||
* if irq has been enabled, always set it;
|
|
||||||
*/
|
|
||||||
if (data->irq_enabled) {
|
|
||||||
hisi_thermal_enable_bind_irq_sensor(data);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_temp < sensor->thres_temp) {
|
data->irq = platform_get_irq(pdev, 0);
|
||||||
data->irq_enabled = true;
|
if (data->irq < 0)
|
||||||
hisi_thermal_enable_bind_irq_sensor(data);
|
return data->irq;
|
||||||
enable_irq(data->irq);
|
|
||||||
|
data->sensor.id = HI6220_DEFAULT_SENSOR;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi3660_thermal_probe(struct hisi_thermal_data *data)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = data->pdev;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
data->get_temp = hi3660_thermal_get_temp;
|
||||||
|
data->enable_sensor = hi3660_thermal_enable_sensor;
|
||||||
|
data->disable_sensor = hi3660_thermal_disable_sensor;
|
||||||
|
data->irq_handler = hi3660_thermal_irq_handler;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
data->regs = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(data->regs)) {
|
||||||
|
dev_err(dev, "failed to get io address\n");
|
||||||
|
return PTR_ERR(data->regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->irq = platform_get_irq(pdev, 0);
|
||||||
|
if (data->irq < 0)
|
||||||
|
return data->irq;
|
||||||
|
|
||||||
|
data->sensor.id = HI3660_DEFAULT_SENSOR;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hisi_thermal_get_temp(void *__data, int *temp)
|
||||||
|
{
|
||||||
|
struct hisi_thermal_data *data = __data;
|
||||||
|
struct hisi_thermal_sensor *sensor = &data->sensor;
|
||||||
|
|
||||||
|
*temp = data->get_temp(data);
|
||||||
|
|
||||||
|
dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n",
|
||||||
|
sensor->id, *temp, sensor->thres_temp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,35 +447,26 @@ static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
|
||||||
.get_temp = hisi_thermal_get_temp,
|
.get_temp = hisi_thermal_get_temp,
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t hisi_thermal_alarm_irq(int irq, void *dev)
|
|
||||||
{
|
|
||||||
struct hisi_thermal_data *data = dev;
|
|
||||||
|
|
||||||
disable_irq_nosync(irq);
|
|
||||||
data->irq_enabled = false;
|
|
||||||
|
|
||||||
return IRQ_WAKE_THREAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
|
static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_data *data = dev;
|
struct hisi_thermal_data *data = dev;
|
||||||
struct hisi_thermal_sensor *sensor;
|
struct hisi_thermal_sensor *sensor = &data->sensor;
|
||||||
int i;
|
int temp = 0;
|
||||||
|
|
||||||
mutex_lock(&data->thermal_lock);
|
data->irq_handler(data);
|
||||||
sensor = &data->sensors[data->irq_bind_sensor];
|
|
||||||
|
|
||||||
dev_crit(&data->pdev->dev, "THERMAL ALARM: T > %d\n",
|
hisi_thermal_get_temp(data, &temp);
|
||||||
sensor->thres_temp / 1000);
|
|
||||||
mutex_unlock(&data->thermal_lock);
|
|
||||||
|
|
||||||
for (i = 0; i < HISI_MAX_SENSORS; i++) {
|
if (temp >= sensor->thres_temp) {
|
||||||
if (!data->sensors[i].tzd)
|
dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n",
|
||||||
continue;
|
temp, sensor->thres_temp);
|
||||||
|
|
||||||
thermal_zone_device_update(data->sensors[i].tzd,
|
thermal_zone_device_update(data->sensor.tzd,
|
||||||
THERMAL_EVENT_UNSPECIFIED);
|
THERMAL_EVENT_UNSPECIFIED);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
dev_crit(&data->pdev->dev, "THERMAL ALARM stopped: %d < %d\n",
|
||||||
|
temp, sensor->thres_temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -246,17 +474,14 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
|
||||||
|
|
||||||
static int hisi_thermal_register_sensor(struct platform_device *pdev,
|
static int hisi_thermal_register_sensor(struct platform_device *pdev,
|
||||||
struct hisi_thermal_data *data,
|
struct hisi_thermal_data *data,
|
||||||
struct hisi_thermal_sensor *sensor,
|
struct hisi_thermal_sensor *sensor)
|
||||||
int index)
|
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
const struct thermal_trip *trip;
|
const struct thermal_trip *trip;
|
||||||
|
|
||||||
sensor->id = index;
|
|
||||||
sensor->thermal = data;
|
|
||||||
|
|
||||||
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
|
sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
|
||||||
sensor->id, sensor, &hisi_of_thermal_ops);
|
sensor->id, data,
|
||||||
|
&hisi_of_thermal_ops);
|
||||||
if (IS_ERR(sensor->tzd)) {
|
if (IS_ERR(sensor->tzd)) {
|
||||||
ret = PTR_ERR(sensor->tzd);
|
ret = PTR_ERR(sensor->tzd);
|
||||||
sensor->tzd = NULL;
|
sensor->tzd = NULL;
|
||||||
|
@ -278,7 +503,14 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id of_hisi_thermal_match[] = {
|
static const struct of_device_id of_hisi_thermal_match[] = {
|
||||||
{ .compatible = "hisilicon,tsensor" },
|
{
|
||||||
|
.compatible = "hisilicon,tsensor",
|
||||||
|
.data = hi6220_thermal_probe
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "hisilicon,hi3660-tsensor",
|
||||||
|
.data = hi3660_thermal_probe
|
||||||
|
},
|
||||||
{ /* end */ }
|
{ /* end */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
|
MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
|
||||||
|
@ -295,88 +527,63 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
|
||||||
static int hisi_thermal_probe(struct platform_device *pdev)
|
static int hisi_thermal_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_data *data;
|
struct hisi_thermal_data *data;
|
||||||
struct resource *res;
|
int const (*platform_probe)(struct hisi_thermal_data *);
|
||||||
int i;
|
struct device *dev = &pdev->dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mutex_init(&data->thermal_lock);
|
|
||||||
data->pdev = pdev;
|
data->pdev = pdev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
data->regs = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(data->regs)) {
|
|
||||||
dev_err(&pdev->dev, "failed to get io address\n");
|
|
||||||
return PTR_ERR(data->regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->irq = platform_get_irq(pdev, 0);
|
|
||||||
if (data->irq < 0)
|
|
||||||
return data->irq;
|
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, data->irq,
|
|
||||||
hisi_thermal_alarm_irq,
|
|
||||||
hisi_thermal_alarm_irq_thread,
|
|
||||||
0, "hisi_thermal", data);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, data);
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
data->clk = devm_clk_get(&pdev->dev, "thermal_clk");
|
platform_probe = of_device_get_match_data(dev);
|
||||||
if (IS_ERR(data->clk)) {
|
if (!platform_probe) {
|
||||||
ret = PTR_ERR(data->clk);
|
dev_err(dev, "failed to get probe func\n");
|
||||||
if (ret != -EPROBE_DEFER)
|
return -EINVAL;
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"failed to get thermal clk: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable clock for thermal */
|
ret = platform_probe(data);
|
||||||
ret = clk_prepare_enable(data->clk);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = hisi_thermal_register_sensor(pdev, data,
|
||||||
|
&data->sensor);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
|
dev_err(dev, "failed to register thermal sensor: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
hisi_thermal_enable_bind_irq_sensor(data);
|
ret = data->enable_sensor(data);
|
||||||
irq_get_irqchip_state(data->irq, IRQCHIP_STATE_MASKED,
|
if (ret) {
|
||||||
&data->irq_enabled);
|
dev_err(dev, "Failed to setup the sensor: %d\n", ret);
|
||||||
|
return ret;
|
||||||
for (i = 0; i < HISI_MAX_SENSORS; ++i) {
|
|
||||||
ret = hisi_thermal_register_sensor(pdev, data,
|
|
||||||
&data->sensors[i], i);
|
|
||||||
if (ret)
|
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"failed to register thermal sensor: %d\n", ret);
|
|
||||||
else
|
|
||||||
hisi_thermal_toggle_sensor(&data->sensors[i], true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->irq) {
|
||||||
|
ret = devm_request_threaded_irq(dev, data->irq, NULL,
|
||||||
|
hisi_thermal_alarm_irq_thread,
|
||||||
|
IRQF_ONESHOT, "hisi_thermal", data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "failed to request alarm irq: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hisi_thermal_toggle_sensor(&data->sensor, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hisi_thermal_remove(struct platform_device *pdev)
|
static int hisi_thermal_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_data *data = platform_get_drvdata(pdev);
|
struct hisi_thermal_data *data = platform_get_drvdata(pdev);
|
||||||
int i;
|
struct hisi_thermal_sensor *sensor = &data->sensor;
|
||||||
|
|
||||||
for (i = 0; i < HISI_MAX_SENSORS; i++) {
|
hisi_thermal_toggle_sensor(sensor, false);
|
||||||
struct hisi_thermal_sensor *sensor = &data->sensors[i];
|
|
||||||
|
|
||||||
if (!sensor->tzd)
|
data->disable_sensor(data);
|
||||||
continue;
|
|
||||||
|
|
||||||
hisi_thermal_toggle_sensor(sensor, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
hisi_thermal_disable_sensor(data);
|
|
||||||
clk_disable_unprepare(data->clk);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -386,10 +593,7 @@ static int hisi_thermal_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_data *data = dev_get_drvdata(dev);
|
struct hisi_thermal_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
hisi_thermal_disable_sensor(data);
|
data->disable_sensor(data);
|
||||||
data->irq_enabled = false;
|
|
||||||
|
|
||||||
clk_disable_unprepare(data->clk);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -397,16 +601,8 @@ static int hisi_thermal_suspend(struct device *dev)
|
||||||
static int hisi_thermal_resume(struct device *dev)
|
static int hisi_thermal_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct hisi_thermal_data *data = dev_get_drvdata(dev);
|
struct hisi_thermal_data *data = dev_get_drvdata(dev);
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(data->clk);
|
return data->enable_sensor(data);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
data->irq_enabled = true;
|
|
||||||
hisi_thermal_enable_bind_irq_sensor(data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/nvmem-consumer.h>
|
||||||
|
|
||||||
#define REG_SET 0x4
|
#define REG_SET 0x4
|
||||||
#define REG_CLR 0x8
|
#define REG_CLR 0x8
|
||||||
|
@ -94,7 +95,7 @@ struct imx_thermal_data {
|
||||||
struct thermal_cooling_device *cdev;
|
struct thermal_cooling_device *cdev;
|
||||||
enum thermal_device_mode mode;
|
enum thermal_device_mode mode;
|
||||||
struct regmap *tempmon;
|
struct regmap *tempmon;
|
||||||
u32 c1, c2; /* See formula in imx_get_sensor_data() */
|
u32 c1, c2; /* See formula in imx_init_calib() */
|
||||||
int temp_passive;
|
int temp_passive;
|
||||||
int temp_critical;
|
int temp_critical;
|
||||||
int temp_max;
|
int temp_max;
|
||||||
|
@ -177,7 +178,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||||
|
|
||||||
n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
|
n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
|
||||||
|
|
||||||
/* See imx_get_sensor_data() for formula derivation */
|
/* See imx_init_calib() for formula derivation */
|
||||||
*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 */
|
||||||
|
@ -346,29 +347,12 @@ static struct thermal_zone_device_ops imx_tz_ops = {
|
||||||
.set_trip_temp = imx_set_trip_temp,
|
.set_trip_temp = imx_set_trip_temp,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int imx_get_sensor_data(struct platform_device *pdev)
|
static int imx_init_calib(struct platform_device *pdev, u32 val)
|
||||||
{
|
{
|
||||||
struct imx_thermal_data *data = platform_get_drvdata(pdev);
|
struct imx_thermal_data *data = platform_get_drvdata(pdev);
|
||||||
struct regmap *map;
|
|
||||||
int t1, n1;
|
int t1, n1;
|
||||||
int ret;
|
|
||||||
u32 val;
|
|
||||||
u64 temp64;
|
u64 temp64;
|
||||||
|
|
||||||
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
|
||||||
"fsl,tempmon-data");
|
|
||||||
if (IS_ERR(map)) {
|
|
||||||
ret = PTR_ERR(map);
|
|
||||||
dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = regmap_read(map, OCOTP_ANA1, &val);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == 0 || val == ~0) {
|
if (val == 0 || val == ~0) {
|
||||||
dev_err(&pdev->dev, "invalid sensor calibration data\n");
|
dev_err(&pdev->dev, "invalid sensor calibration data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -405,12 +389,12 @@ static int imx_get_sensor_data(struct platform_device *pdev)
|
||||||
data->c1 = temp64;
|
data->c1 = temp64;
|
||||||
data->c2 = n1 * data->c1 + 1000 * t1;
|
data->c2 = n1 * data->c1 + 1000 * t1;
|
||||||
|
|
||||||
/* use OTP for thermal grade */
|
return 0;
|
||||||
ret = regmap_read(map, OCOTP_MEM0, &val);
|
}
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
|
static void imx_init_temp_grade(struct platform_device *pdev, u32 val)
|
||||||
return ret;
|
{
|
||||||
}
|
struct imx_thermal_data *data = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
/* The maximum die temp is specified by the Temperature Grade */
|
/* The maximum die temp is specified by the Temperature Grade */
|
||||||
switch ((val >> 6) & 0x3) {
|
switch ((val >> 6) & 0x3) {
|
||||||
|
@ -438,6 +422,55 @@ static int imx_get_sensor_data(struct platform_device *pdev)
|
||||||
*/
|
*/
|
||||||
data->temp_critical = data->temp_max - (1000 * 5);
|
data->temp_critical = data->temp_max - (1000 * 5);
|
||||||
data->temp_passive = data->temp_max - (1000 * 10);
|
data->temp_passive = data->temp_max - (1000 * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_init_from_tempmon_data(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct regmap *map;
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||||
|
"fsl,tempmon-data");
|
||||||
|
if (IS_ERR(map)) {
|
||||||
|
ret = PTR_ERR(map);
|
||||||
|
dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_read(map, OCOTP_ANA1, &val);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = imx_init_calib(pdev, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_read(map, OCOTP_MEM0, &val);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
imx_init_temp_grade(pdev, val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_init_from_nvmem_cells(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
ret = nvmem_cell_read_u32(&pdev->dev, "calib", &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
imx_init_calib(pdev, val);
|
||||||
|
|
||||||
|
ret = nvmem_cell_read_u32(&pdev->dev, "temp_grade", &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
imx_init_temp_grade(pdev, val);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -514,10 +547,21 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
platform_set_drvdata(pdev, data);
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
ret = imx_get_sensor_data(pdev);
|
if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
|
||||||
if (ret) {
|
ret = imx_init_from_nvmem_cells(pdev);
|
||||||
dev_err(&pdev->dev, "failed to get sensor data\n");
|
if (ret == -EPROBE_DEFER)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to init from nvmem: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = imx_init_from_tempmon_data(pdev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to init from from fsl,tempmon-data\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure sensor is in known good state for measurements */
|
/* Make sure sensor is in known good state for measurements */
|
||||||
|
|
|
@ -30,6 +30,10 @@
|
||||||
/* Skylake thermal reporting device */
|
/* Skylake thermal reporting device */
|
||||||
#define PCI_DEVICE_ID_PROC_SKL_THERMAL 0x1903
|
#define PCI_DEVICE_ID_PROC_SKL_THERMAL 0x1903
|
||||||
|
|
||||||
|
/* CannonLake thermal reporting device */
|
||||||
|
#define PCI_DEVICE_ID_PROC_CNL_THERMAL 0x5a03
|
||||||
|
#define PCI_DEVICE_ID_PROC_CFL_THERMAL 0x3E83
|
||||||
|
|
||||||
/* Braswell thermal reporting device */
|
/* Braswell thermal reporting device */
|
||||||
#define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC
|
#define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC
|
||||||
|
|
||||||
|
@ -461,6 +465,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXT1_THERMAL)},
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTX_THERMAL)},
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTX_THERMAL)},
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)},
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BXTP_THERMAL)},
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CNL_THERMAL)},
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_CFL_THERMAL)},
|
||||||
{ 0, },
|
{ 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ static irqreturn_t pmic_thermal_irq_handler(int irq, void *data)
|
||||||
struct pmic_thermal_data *td;
|
struct pmic_thermal_data *td;
|
||||||
struct intel_soc_pmic *pmic;
|
struct intel_soc_pmic *pmic;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
u8 reg_val, mask, irq_stat, trip;
|
u8 reg_val, mask, irq_stat;
|
||||||
u16 reg, evt_stat_reg;
|
u16 reg, evt_stat_reg;
|
||||||
int i, j, ret;
|
int i, j, ret;
|
||||||
|
|
||||||
|
@ -201,7 +201,6 @@ static irqreturn_t pmic_thermal_irq_handler(int irq, void *data)
|
||||||
if (regmap_read(regmap, evt_stat_reg, &ret))
|
if (regmap_read(regmap, evt_stat_reg, &ret))
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
trip = td->maps[i].trip_config[j].trip_num;
|
|
||||||
tzd = thermal_zone_get_zone_by_name(td->maps[i].handle);
|
tzd = thermal_zone_get_zone_by_name(td->maps[i].handle);
|
||||||
if (!IS_ERR(tzd))
|
if (!IS_ERR(tzd))
|
||||||
thermal_zone_device_update(tzd,
|
thermal_zone_device_update(tzd,
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
|
#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
|
||||||
#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
|
#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
|
||||||
#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
|
#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
|
||||||
|
#define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */
|
||||||
|
#define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */
|
||||||
|
|
||||||
/* Wildcat Point-LP PCH Thermal registers */
|
/* Wildcat Point-LP PCH Thermal registers */
|
||||||
#define WPT_TEMP 0x0000 /* Temperature */
|
#define WPT_TEMP 0x0000 /* Temperature */
|
||||||
|
@ -278,6 +280,7 @@ enum board_ids {
|
||||||
board_hsw,
|
board_hsw,
|
||||||
board_wpt,
|
board_wpt,
|
||||||
board_skl,
|
board_skl,
|
||||||
|
board_cnl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct board_info {
|
static const struct board_info {
|
||||||
|
@ -296,6 +299,10 @@ static const struct board_info {
|
||||||
.name = "pch_skylake",
|
.name = "pch_skylake",
|
||||||
.ops = &pch_dev_ops_wpt,
|
.ops = &pch_dev_ops_wpt,
|
||||||
},
|
},
|
||||||
|
[board_cnl] = {
|
||||||
|
.name = "pch_cannonlake",
|
||||||
|
.ops = &pch_dev_ops_wpt,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int intel_pch_thermal_probe(struct pci_dev *pdev,
|
static int intel_pch_thermal_probe(struct pci_dev *pdev,
|
||||||
|
@ -398,6 +405,10 @@ static const struct pci_device_id intel_pch_thermal_id[] = {
|
||||||
.driver_data = board_skl, },
|
.driver_data = board_skl, },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
|
||||||
.driver_data = board_skl, },
|
.driver_data = board_skl, },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL),
|
||||||
|
.driver_data = board_cnl, },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H),
|
||||||
|
.driver_data = board_cnl, },
|
||||||
{ 0, },
|
{ 0, },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
|
MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
|
||||||
|
|
|
@ -675,13 +675,13 @@ static int __init powerclamp_probe(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!x86_match_cpu(intel_powerclamp_ids)) {
|
if (!x86_match_cpu(intel_powerclamp_ids)) {
|
||||||
pr_err("CPU does not support MWAIT");
|
pr_err("CPU does not support MWAIT\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The goal for idle time alignment is to achieve package cstate. */
|
/* The goal for idle time alignment is to achieve package cstate. */
|
||||||
if (!has_pkg_state_counter()) {
|
if (!has_pkg_state_counter()) {
|
||||||
pr_info("No package C-state available");
|
pr_info("No package C-state available\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ static int qpnp_tm_get_temp(void *data, int *temp)
|
||||||
if (!temp)
|
if (!temp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (IS_ERR(chip->adc)) {
|
if (!chip->adc) {
|
||||||
ret = qpnp_tm_update_temp_no_adc(chip);
|
ret = qpnp_tm_update_temp_no_adc(chip);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -224,67 +224,53 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
||||||
return irq;
|
return irq;
|
||||||
|
|
||||||
/* ADC based measurements are optional */
|
/* ADC based measurements are optional */
|
||||||
chip->adc = iio_channel_get(&pdev->dev, "thermal");
|
chip->adc = devm_iio_channel_get(&pdev->dev, "thermal");
|
||||||
if (PTR_ERR(chip->adc) == -EPROBE_DEFER)
|
if (IS_ERR(chip->adc)) {
|
||||||
return PTR_ERR(chip->adc);
|
ret = PTR_ERR(chip->adc);
|
||||||
|
chip->adc = NULL;
|
||||||
|
if (ret == -EPROBE_DEFER)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
chip->base = res;
|
chip->base = res;
|
||||||
|
|
||||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
|
ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "could not read type\n");
|
dev_err(&pdev->dev, "could not read type\n");
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);
|
ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "could not read subtype\n");
|
dev_err(&pdev->dev, "could not read subtype\n");
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
|
if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
|
||||||
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);
|
||||||
ret = -ENODEV;
|
return -ENODEV;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
|
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
|
||||||
IRQF_ONESHOT, node->name, chip);
|
IRQF_ONESHOT, node->name, chip);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
return ret;
|
||||||
|
|
||||||
chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
|
chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
|
||||||
&qpnp_tm_sensor_ops);
|
&qpnp_tm_sensor_ops);
|
||||||
if (IS_ERR(chip->tz_dev)) {
|
if (IS_ERR(chip->tz_dev)) {
|
||||||
dev_err(&pdev->dev, "failed to register sensor\n");
|
dev_err(&pdev->dev, "failed to register sensor\n");
|
||||||
ret = PTR_ERR(chip->tz_dev);
|
return PTR_ERR(chip->tz_dev);
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
|
||||||
if (!IS_ERR(chip->adc))
|
|
||||||
iio_channel_release(chip->adc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qpnp_tm_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (!IS_ERR(chip->adc))
|
|
||||||
iio_channel_release(chip->adc);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id qpnp_tm_match_table[] = {
|
static const struct of_device_id qpnp_tm_match_table[] = {
|
||||||
|
@ -299,7 +285,6 @@ static struct platform_driver qpnp_tm_driver = {
|
||||||
.of_match_table = qpnp_tm_match_table,
|
.of_match_table = qpnp_tm_match_table,
|
||||||
},
|
},
|
||||||
.probe = qpnp_tm_probe,
|
.probe = qpnp_tm_probe,
|
||||||
.remove = qpnp_tm_remove,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(qpnp_tm_driver);
|
module_platform_driver(qpnp_tm_driver);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/sys_soc.h>
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
|
|
||||||
#include "thermal_core.h"
|
#include "thermal_core.h"
|
||||||
|
@ -90,10 +91,6 @@ struct rcar_gen3_thermal_priv {
|
||||||
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
||||||
unsigned int num_tscs;
|
unsigned int num_tscs;
|
||||||
spinlock_t lock; /* Protect interrupts on and off */
|
spinlock_t lock; /* Protect interrupts on and off */
|
||||||
const struct rcar_gen3_thermal_data *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rcar_gen3_thermal_data {
|
|
||||||
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -278,7 +275,12 @@ static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
static const struct soc_device_attribute r8a7795es1[] = {
|
||||||
|
{ .soc_id = "r8a7795", .revision = "ES1.*" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
{
|
{
|
||||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
|
||||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, 0x0);
|
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, 0x0);
|
||||||
|
@ -303,7 +305,7 @@ static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
usleep_range(1000, 2000);
|
usleep_range(1000, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
{
|
{
|
||||||
u32 reg_val;
|
u32 reg_val;
|
||||||
|
|
||||||
|
@ -324,17 +326,9 @@ static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||||
usleep_range(1000, 2000);
|
usleep_range(1000, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rcar_gen3_thermal_data r8a7795_data = {
|
|
||||||
.thermal_init = r8a7795_thermal_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct rcar_gen3_thermal_data r8a7796_data = {
|
|
||||||
.thermal_init = r8a7796_thermal_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
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", .data = &r8a7795_data},
|
{ .compatible = "renesas,r8a7795-thermal", },
|
||||||
{ .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
|
{ .compatible = "renesas,r8a7796-thermal", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
||||||
|
@ -371,7 +365,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
priv->data = of_device_get_match_data(dev);
|
priv->thermal_init = rcar_gen3_thermal_init;
|
||||||
|
if (soc_device_match(r8a7795es1))
|
||||||
|
priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
|
||||||
|
|
||||||
spin_lock_init(&priv->lock);
|
spin_lock_init(&priv->lock);
|
||||||
|
|
||||||
|
@ -423,7 +419,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
priv->tscs[i] = tsc;
|
priv->tscs[i] = tsc;
|
||||||
|
|
||||||
priv->data->thermal_init(tsc);
|
priv->thermal_init(tsc);
|
||||||
rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
|
rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
|
||||||
|
|
||||||
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
||||||
|
@ -476,7 +472,7 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
|
||||||
for (i = 0; i < priv->num_tscs; i++) {
|
for (i = 0; i < priv->num_tscs; i++) {
|
||||||
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
|
||||||
|
|
||||||
priv->data->thermal_init(tsc);
|
priv->thermal_init(tsc);
|
||||||
rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
|
rcar_gen3_thermal_set_trips(tsc, tsc->low, tsc->high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,45 @@ struct tsadc_table {
|
||||||
int temp;
|
int temp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct tsadc_table rv1108_table[] = {
|
||||||
|
{0, -40000},
|
||||||
|
{374, -40000},
|
||||||
|
{382, -35000},
|
||||||
|
{389, -30000},
|
||||||
|
{397, -25000},
|
||||||
|
{405, -20000},
|
||||||
|
{413, -15000},
|
||||||
|
{421, -10000},
|
||||||
|
{429, -5000},
|
||||||
|
{436, 0},
|
||||||
|
{444, 5000},
|
||||||
|
{452, 10000},
|
||||||
|
{460, 15000},
|
||||||
|
{468, 20000},
|
||||||
|
{476, 25000},
|
||||||
|
{483, 30000},
|
||||||
|
{491, 35000},
|
||||||
|
{499, 40000},
|
||||||
|
{507, 45000},
|
||||||
|
{515, 50000},
|
||||||
|
{523, 55000},
|
||||||
|
{531, 60000},
|
||||||
|
{539, 65000},
|
||||||
|
{547, 70000},
|
||||||
|
{555, 75000},
|
||||||
|
{562, 80000},
|
||||||
|
{570, 85000},
|
||||||
|
{578, 90000},
|
||||||
|
{586, 95000},
|
||||||
|
{594, 100000},
|
||||||
|
{602, 105000},
|
||||||
|
{610, 110000},
|
||||||
|
{618, 115000},
|
||||||
|
{626, 120000},
|
||||||
|
{634, 125000},
|
||||||
|
{TSADCV2_DATA_MASK, 125000},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct tsadc_table rk3228_code_table[] = {
|
static const struct tsadc_table rk3228_code_table[] = {
|
||||||
{0, -40000},
|
{0, -40000},
|
||||||
{588, -40000},
|
{588, -40000},
|
||||||
|
@ -779,6 +818,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
|
||||||
writel_relaxed(val, regs + TSADCV2_INT_EN);
|
writel_relaxed(val, regs + TSADCV2_INT_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rockchip_tsadc_chip rv1108_tsadc_data = {
|
||||||
|
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
||||||
|
.chn_num = 1, /* one channel for tsadc */
|
||||||
|
|
||||||
|
.tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
|
||||||
|
.tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
|
||||||
|
.tshut_temp = 95000,
|
||||||
|
|
||||||
|
.initialize = rk_tsadcv2_initialize,
|
||||||
|
.irq_ack = rk_tsadcv3_irq_ack,
|
||||||
|
.control = rk_tsadcv3_control,
|
||||||
|
.get_temp = rk_tsadcv2_get_temp,
|
||||||
|
.set_alarm_temp = rk_tsadcv2_alarm_temp,
|
||||||
|
.set_tshut_temp = rk_tsadcv2_tshut_temp,
|
||||||
|
.set_tshut_mode = rk_tsadcv2_tshut_mode,
|
||||||
|
|
||||||
|
.table = {
|
||||||
|
.id = rv1108_table,
|
||||||
|
.length = ARRAY_SIZE(rv1108_table),
|
||||||
|
.data_mask = TSADCV2_DATA_MASK,
|
||||||
|
.mode = ADC_INCREMENT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
|
static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
|
||||||
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
||||||
.chn_num = 1, /* one channel for tsadc */
|
.chn_num = 1, /* one channel for tsadc */
|
||||||
|
@ -927,6 +990,10 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id of_rockchip_thermal_match[] = {
|
static const struct of_device_id of_rockchip_thermal_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "rockchip,rv1108-tsadc",
|
||||||
|
.data = (void *)&rv1108_tsadc_data,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "rockchip,rk3228-tsadc",
|
.compatible = "rockchip,rk3228-tsadc",
|
||||||
.data = (void *)&rk3228_tsadc_data,
|
.data = (void *)&rk3228_tsadc_data,
|
||||||
|
|
|
@ -31,8 +31,7 @@
|
||||||
* If the temperature is higher than a trip point,
|
* If the temperature is higher than a trip point,
|
||||||
* a. if the trend is THERMAL_TREND_RAISING, use higher cooling
|
* a. if the trend is THERMAL_TREND_RAISING, use higher cooling
|
||||||
* state for this trip point
|
* state for this trip point
|
||||||
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
|
* b. if the trend is THERMAL_TREND_DROPPING, do nothing
|
||||||
* state for this trip point
|
|
||||||
* c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit
|
* c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit
|
||||||
* for this trip point
|
* for this trip point
|
||||||
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
|
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
|
||||||
|
@ -94,9 +93,11 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||||
if (!throttle)
|
if (!throttle)
|
||||||
next_target = THERMAL_NO_TARGET;
|
next_target = THERMAL_NO_TARGET;
|
||||||
} else {
|
} else {
|
||||||
next_target = cur_state - 1;
|
if (!throttle) {
|
||||||
if (next_target > instance->upper)
|
next_target = cur_state - 1;
|
||||||
next_target = instance->upper;
|
if (next_target > instance->upper)
|
||||||
|
next_target = instance->upper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case THERMAL_TREND_DROP_FULL:
|
case THERMAL_TREND_DROP_FULL:
|
||||||
|
|
|
@ -483,7 +483,7 @@ static int throttrip_program(struct device *dev,
|
||||||
unsigned int throt;
|
unsigned int throt;
|
||||||
u32 r, reg_off;
|
u32 r, reg_off;
|
||||||
|
|
||||||
if (!dev || !sg || !stc || !stc->init)
|
if (!sg || !stc || !stc->init)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;
|
temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;
|
||||||
|
|
|
@ -126,37 +126,22 @@ static int gadc_thermal_probe(struct platform_device *pdev)
|
||||||
gti->dev = &pdev->dev;
|
gti->dev = &pdev->dev;
|
||||||
platform_set_drvdata(pdev, gti);
|
platform_set_drvdata(pdev, gti);
|
||||||
|
|
||||||
gti->channel = iio_channel_get(&pdev->dev, "sensor-channel");
|
gti->channel = devm_iio_channel_get(&pdev->dev, "sensor-channel");
|
||||||
if (IS_ERR(gti->channel)) {
|
if (IS_ERR(gti->channel)) {
|
||||||
ret = PTR_ERR(gti->channel);
|
ret = PTR_ERR(gti->channel);
|
||||||
dev_err(&pdev->dev, "IIO channel not found: %d\n", ret);
|
dev_err(&pdev->dev, "IIO channel not found: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gti->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0,
|
gti->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, gti,
|
||||||
gti, &gadc_thermal_ops);
|
&gadc_thermal_ops);
|
||||||
if (IS_ERR(gti->tz_dev)) {
|
if (IS_ERR(gti->tz_dev)) {
|
||||||
ret = PTR_ERR(gti->tz_dev);
|
ret = PTR_ERR(gti->tz_dev);
|
||||||
dev_err(&pdev->dev, "Thermal zone sensor register failed: %d\n",
|
dev_err(&pdev->dev, "Thermal zone sensor register failed: %d\n",
|
||||||
ret);
|
ret);
|
||||||
goto sensor_fail;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sensor_fail:
|
|
||||||
iio_channel_release(gti->channel);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gadc_thermal_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct gadc_thermal_info *gti = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
thermal_zone_of_sensor_unregister(&pdev->dev, gti->tz_dev);
|
|
||||||
iio_channel_release(gti->channel);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +157,6 @@ static struct platform_driver gadc_thermal_driver = {
|
||||||
.of_match_table = of_adc_thermal_match,
|
.of_match_table = of_adc_thermal_match,
|
||||||
},
|
},
|
||||||
.probe = gadc_thermal_probe,
|
.probe = gadc_thermal_probe,
|
||||||
.remove = gadc_thermal_remove,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(gadc_thermal_driver);
|
module_platform_driver(gadc_thermal_driver);
|
||||||
|
|
|
@ -278,7 +278,8 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
cpufreq_cooling_unregister(data->cool_dev);
|
cpufreq_cooling_unregister(data->cool_dev);
|
||||||
cpufreq_cpu_put(data->policy);
|
if (data->policy)
|
||||||
|
cpufreq_cpu_put(data->policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -488,7 +488,7 @@ static inline int power_actor_set_power(struct thermal_cooling_device *cdev,
|
||||||
static inline struct thermal_zone_device *thermal_zone_device_register(
|
static inline struct thermal_zone_device *thermal_zone_device_register(
|
||||||
const char *type, int trips, int mask, void *devdata,
|
const char *type, int trips, int mask, void *devdata,
|
||||||
struct thermal_zone_device_ops *ops,
|
struct thermal_zone_device_ops *ops,
|
||||||
const struct thermal_zone_params *tzp,
|
struct thermal_zone_params *tzp,
|
||||||
int passive_delay, int polling_delay)
|
int passive_delay, int polling_delay)
|
||||||
{ return ERR_PTR(-ENODEV); }
|
{ return ERR_PTR(-ENODEV); }
|
||||||
static inline void thermal_zone_device_unregister(
|
static inline void thermal_zone_device_unregister(
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
# We need this for the "cc-option" macro.
|
||||||
|
include ../../../scripts/Kbuild.include
|
||||||
|
|
||||||
VERSION = 1.0
|
VERSION = 1.0
|
||||||
|
|
||||||
BINDIR=usr/bin
|
BINDIR=usr/bin
|
||||||
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
|
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
|
||||||
CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
|
CFLAGS+= -O1 ${WARNFLAGS}
|
||||||
CC=$(CROSS_COMPILE)gcc
|
# Add "-fstack-protector" only if toolchain supports it.
|
||||||
|
CFLAGS+= $(call cc-option,-fstack-protector)
|
||||||
|
CC?= $(CROSS_COMPILE)gcc
|
||||||
|
PKG_CONFIG?= pkg-config
|
||||||
|
|
||||||
CFLAGS+=-D VERSION=\"$(VERSION)\"
|
CFLAGS+=-D VERSION=\"$(VERSION)\"
|
||||||
LDFLAGS+=
|
LDFLAGS+=
|
||||||
|
@ -19,12 +25,12 @@ STATIC := --static
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TMON_LIBS=-lm -lpthread
|
TMON_LIBS=-lm -lpthread
|
||||||
TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
|
TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null || \
|
||||||
pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
|
$(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
|
||||||
echo -lpanel -lncurses)
|
echo -lpanel -lncurses)
|
||||||
|
|
||||||
CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
|
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
|
||||||
pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null)
|
$(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
|
||||||
|
|
||||||
OBJS = tmon.o tui.o sysfs.o pid.o
|
OBJS = tmon.o tui.o sysfs.o pid.o
|
||||||
OBJS +=
|
OBJS +=
|
||||||
|
|
Loading…
Reference in New Issue