提交 bec04432 编写于 作者: L Linus Torvalds

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
  ...
* 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.
- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
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
calibration data, e.g. OCOTP on imx6q. The details about calibration data
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:
- clocks : thermal sensor's clock source.
......
......@@ -2,6 +2,7 @@
Required properties:
- compatible : should be "rockchip,<name>-tsadc"
"rockchip,rv1108-tsadc": found on RV1108 SoCs
"rockchip,rk3228-tsadc": found on RK3228 SoCs
"rockchip,rk3288-tsadc": found on RK3288 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: 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
M: Brian Norris <computersforpeace@gmail.com>
M: Kamal Dasu <kdasu.kdev@gmail.com>
......
......@@ -206,6 +206,7 @@ config HISI_THERMAL
config IMX_THERMAL
tristate "Temperature sensor driver for Freescale i.MX SoCs"
depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST
depends on NVMEM || !NVMEM
depends on MFD_SYSCON
depends on OF
help
......@@ -408,7 +409,7 @@ config MTK_THERMAL
controller present in Mediatek SoCs
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"
endmenu
......
......@@ -58,7 +58,7 @@ struct armada_thermal_data {
/* Test for a valid sensor value (optional) */
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_m;
unsigned long coef_div;
......
......@@ -6,6 +6,13 @@ config BCM2835_THERMAL
help
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
tristate "Northstar thermal driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
......
obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
obj-$(CONFIG_BRCMSTB_THERMAL) += brcmstb_thermal.o
obj-$(CONFIG_BCM_NS_THERMAL) += ns-thermal.o
/*
* 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;
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);
}
......
此差异已折叠。
......@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
#define REG_SET 0x4
#define REG_CLR 0x8
......@@ -94,7 +95,7 @@ struct imx_thermal_data {
struct thermal_cooling_device *cdev;
enum thermal_device_mode mode;
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_critical;
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;
/* See imx_get_sensor_data() for formula derivation */
/* See imx_init_calib() for formula derivation */
*temp = data->c2 - n_meas * data->c1;
/* 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,
};
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 regmap *map;
int t1, n1;
int ret;
u32 val;
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) {
dev_err(&pdev->dev, "invalid sensor calibration data\n");
return -EINVAL;
......@@ -405,12 +389,12 @@ static int imx_get_sensor_data(struct platform_device *pdev)
data->c1 = temp64;
data->c2 = n1 * data->c1 + 1000 * t1;
/* use OTP for thermal grade */
ret = regmap_read(map, OCOTP_MEM0, &val);
if (ret) {
dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
return ret;
}
return 0;
}
static void imx_init_temp_grade(struct platform_device *pdev, u32 val)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);
/* The maximum die temp is specified by the Temperature Grade */
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_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;
}
......@@ -514,10 +547,21 @@ static int imx_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
ret = imx_get_sensor_data(pdev);
if (ret) {
dev_err(&pdev->dev, "failed to get sensor data\n");
return ret;
if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
ret = imx_init_from_nvmem_cells(pdev);
if (ret == -EPROBE_DEFER)
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 */
......
......@@ -30,6 +30,10 @@
/* Skylake thermal reporting device */
#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 */
#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_BXTX_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, },
};
......
......@@ -166,7 +166,7 @@ static irqreturn_t pmic_thermal_irq_handler(int irq, void *data)
struct pmic_thermal_data *td;
struct intel_soc_pmic *pmic;
struct regmap *regmap;
u8 reg_val, mask, irq_stat, trip;
u8 reg_val, mask, irq_stat;
u16 reg, evt_stat_reg;
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))
return IRQ_HANDLED;
trip = td->maps[i].trip_config[j].trip_num;
tzd = thermal_zone_get_zone_by_name(td->maps[i].handle);
if (!IS_ERR(tzd))
thermal_zone_device_update(tzd,
......
......@@ -30,6 +30,8 @@
#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
#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 */
#define WPT_TEMP 0x0000 /* Temperature */
......@@ -278,6 +280,7 @@ enum board_ids {
board_hsw,
board_wpt,
board_skl,
board_cnl,
};
static const struct board_info {
......@@ -296,6 +299,10 @@ static const struct board_info {
.name = "pch_skylake",
.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,
......@@ -398,6 +405,10 @@ static const struct pci_device_id intel_pch_thermal_id[] = {
.driver_data = board_skl, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
.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, },
};
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)) {
pr_err("CPU does not support MWAIT");
pr_err("CPU does not support MWAIT\n");
return -ENODEV;
}
/* The goal for idle time alignment is to achieve package cstate. */
if (!has_pkg_state_counter()) {
pr_info("No package C-state available");
pr_info("No package C-state available\n");
return -ENODEV;
}
......
......@@ -125,7 +125,7 @@ static int qpnp_tm_get_temp(void *data, int *temp)
if (!temp)
return -EINVAL;
if (IS_ERR(chip->adc)) {
if (!chip->adc) {
ret = qpnp_tm_update_temp_no_adc(chip);
if (ret < 0)
return ret;
......@@ -224,67 +224,53 @@ static int qpnp_tm_probe(struct platform_device *pdev)
return irq;
/* ADC based measurements are optional */
chip->adc = iio_channel_get(&pdev->dev, "thermal");
if (PTR_ERR(chip->adc) == -EPROBE_DEFER)
return PTR_ERR(chip->adc);
chip->adc = devm_iio_channel_get(&pdev->dev, "thermal");
if (IS_ERR(chip->adc)) {
ret = PTR_ERR(chip->adc);
chip->adc = NULL;
if (ret == -EPROBE_DEFER)
return ret;
}
chip->base = res;
ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
if (ret < 0) {
dev_err(&pdev->dev, "could not read type\n");
goto fail;
return ret;
}
ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);
if (ret < 0) {
dev_err(&pdev->dev, "could not read subtype\n");
goto fail;
return ret;
}
if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
type, subtype);
ret = -ENODEV;
goto fail;
return -ENODEV;
}
ret = qpnp_tm_init(chip);
if (ret < 0) {
dev_err(&pdev->dev, "init failed\n");
goto fail;
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
IRQF_ONESHOT, node->name, chip);
if (ret < 0)
goto fail;
return ret;
chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
&qpnp_tm_sensor_ops);
if (IS_ERR(chip->tz_dev)) {
dev_err(&pdev->dev, "failed to register sensor\n");
ret = PTR_ERR(chip->tz_dev);
goto fail;
return PTR_ERR(chip->tz_dev);
}
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[] = {
......@@ -299,7 +285,6 @@ static struct platform_driver qpnp_tm_driver = {
.of_match_table = qpnp_tm_match_table,
},
.probe = qpnp_tm_probe,
.remove = qpnp_tm_remove,
};
module_platform_driver(qpnp_tm_driver);
......
......@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/sys_soc.h>
#include <linux/thermal.h>
#include "thermal_core.h"
......@@ -90,10 +91,6 @@ struct rcar_gen3_thermal_priv {
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
unsigned int num_tscs;
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);
};
......@@ -278,7 +275,12 @@ static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
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, 0x0);
......@@ -303,7 +305,7 @@ static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
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;
......@@ -324,17 +326,9 @@ static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
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[] = {
{ .compatible = "renesas,r8a7795-thermal", .data = &r8a7795_data},
{ .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
{ .compatible = "renesas,r8a7795-thermal", },
{ .compatible = "renesas,r8a7796-thermal", },
{},
};
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)
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);
......@@ -423,7 +419,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
priv->tscs[i] = tsc;
priv->data->thermal_init(tsc);
priv->thermal_init(tsc);
rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
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++) {
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);
}
......
......@@ -242,6 +242,45 @@ struct tsadc_table {
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[] = {
{0, -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);
}
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 = {
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
.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[] = {
{
.compatible = "rockchip,rv1108-tsadc",
.data = (void *)&rv1108_tsadc_data,
},
{
.compatible = "rockchip,rk3228-tsadc",
.data = (void *)&rk3228_tsadc_data,
......
......@@ -31,8 +31,7 @@
* If the temperature is higher than a trip point,
* a. if the trend is THERMAL_TREND_RAISING, use higher cooling
* state for this trip point
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
* state for this trip point
* b. if the trend is THERMAL_TREND_DROPPING, do nothing
* c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit
* for this trip point
* 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)
next_target = THERMAL_NO_TARGET;
} else {
next_target = cur_state - 1;
if (next_target > instance->upper)
next_target = instance->upper;
if (!throttle) {
next_target = cur_state - 1;
if (next_target > instance->upper)
next_target = instance->upper;
}
}
break;
case THERMAL_TREND_DROP_FULL:
......
......@@ -483,7 +483,7 @@ static int throttrip_program(struct device *dev,
unsigned int throt;
u32 r, reg_off;
if (!dev || !sg || !stc || !stc->init)
if (!sg || !stc || !stc->init)
return -EINVAL;
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;
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)) {
ret = PTR_ERR(gti->channel);
dev_err(&pdev->dev, "IIO channel not found: %d\n", ret);
return ret;
}
gti->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0,
gti, &gadc_thermal_ops);
gti->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, gti,
&gadc_thermal_ops);
if (IS_ERR(gti->tz_dev)) {
ret = PTR_ERR(gti->tz_dev);
dev_err(&pdev->dev, "Thermal zone sensor register failed: %d\n",
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;
}
......@@ -172,7 +157,6 @@ static struct platform_driver gadc_thermal_driver = {
.of_match_table = of_adc_thermal_match,
},
.probe = gadc_thermal_probe,
.remove = gadc_thermal_remove,
};
module_platform_driver(gadc_thermal_driver);
......
......@@ -278,7 +278,8 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
if (data) {
cpufreq_cooling_unregister(data->cool_dev);
cpufreq_cpu_put(data->policy);
if (data->policy)
cpufreq_cpu_put(data->policy);
}
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(
const char *type, int trips, int mask, void *devdata,
struct thermal_zone_device_ops *ops,
const struct thermal_zone_params *tzp,
struct thermal_zone_params *tzp,
int passive_delay, int polling_delay)
{ return ERR_PTR(-ENODEV); }
static inline void thermal_zone_device_unregister(
......
# SPDX-License-Identifier: GPL-2.0
# We need this for the "cc-option" macro.
include ../../../scripts/Kbuild.include
VERSION = 1.0
BINDIR=usr/bin
WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
CFLAGS+= -O1 ${WARNFLAGS} -fstack-protector
CC=$(CROSS_COMPILE)gcc
CFLAGS+= -O1 ${WARNFLAGS}
# 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)\"
LDFLAGS+=
......@@ -19,12 +25,12 @@ STATIC := --static
endif
TMON_LIBS=-lm -lpthread
TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || \
pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
TMON_LIBS += $(shell $(PKG_CONFIG) --libs $(STATIC) panelw ncursesw 2> /dev/null || \
$(PKG_CONFIG) --libs $(STATIC) panel ncurses 2> /dev/null || \
echo -lpanel -lncurses)
CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null)
CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
$(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null)
OBJS = tmon.o tui.o sysfs.o pid.o
OBJS +=
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册