Commit 83e8de89 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge tag 'thermal-v5.16-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux

Pull thermal core and ARM thermal driver updates for v5.16 from
Daniel Lezcano:

 - Constify a variable in thermal mmio driver (Rikard Falkeborn)

 - Add the current temperature in the netlink message when crossing a
   trip point in order to prevent useless back and forth reading from
   userspace (Daniel Lezcano)

 - Add support for the 'HC' variant on PM8998 pmic in order to support
   vadc channels on recent QCom boards (Bjorn Andersson)

 - Add support of calibration values from hardware when they are fused
   (Niklas Söderlund)

 - Fix NULL pointer dereference from the thermal_release callback when
   an error occured in the thermal_zone_device_register() function
   (Yuanzheng Song)

 - Fix use after free call in the __thermal_cooling_device_register()
   function in the error path (Ziyang Xuan)

 - Fix compilation error for the LMh driver when CONFIG_QCOM_SCM is not
   set (Jackie Liu)

 - Add a timeout when reading a register which can block forever under
   certain circumstances in the tsens driver (Ansuel Smith)

 - Add DT binding for the reset lines and use them in the rockchip
   sensor driver (Johan Jonker)

 - Add new uniphier NX1 SoC temperature sensor (Kunihiko Hayashi)

 - Save and restore the TCC value in the int340x driver (Antoine
   Tenart)

 - Deprecate the cooling device state sysfs file writable and the user
   space governor (Daniel Lezcano)

* tag 'thermal-v5.16-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux:
  thermal/core: Deprecate changing cooling device state from userspace
  thermal/core: Make the userspace governor deprecated
  thermal/drivers/int340x: Improve the tcc offset saving for suspend/resume
  thermal/drivers/uniphier: Add compatible string for NX1 SoC
  dt-bindings: thermal: uniphier: Add binding for NX1 SoC
  thermal/drivers/rockchip_thermal: Allow more resets for tsadc node
  dt-bindings: thermal: remove redundant comments from rockchip-thermal.yaml
  dt-bindings: thermal: allow more resets for tsadc node in rockchip-thermal.yaml
  thermal/drivers/tsens: Add timeout to get_temp_tsens_valid
  thermal/drivers/qcom/lmh: make QCOM_LMH depends on QCOM_SCM
  thermal/core: fix a UAF bug in __thermal_cooling_device_register()
  thermal/core: Fix null pointer dereference in thermal_release()
  thermal: rcar_gen3_thermal: Read calibration from hardware
  thermal: rcar_gen3_thermal: Store thcode and ptat in priv data
  thermal/drivers/qcom/spmi-adc-tm5: Add support for HC variant
  dt-bindings: thermal: qcom: add HC variant of adc-thermal monitor bindings
  thermal/drivers/netlink: Add the temperature when crossing a trip point
  thermal/drivers/thermal_mmio: Constify static struct thermal_mmio_ops
parents 3906fe9b a67a46af
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/qcom-spmi-adc-tm-hc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm's SPMI PMIC ADC HC Thermal Monitoring
maintainers:
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
properties:
compatible:
const: qcom,spmi-adc-tm-hc
reg:
maxItems: 1
interrupts:
maxItems: 1
"#thermal-sensor-cells":
const: 1
description:
Number of cells required to uniquely identify the thermal sensors. Since
we have multiple sensors this is set to 1
"#address-cells":
const: 1
"#size-cells":
const: 0
qcom,avg-samples:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of samples to be used for measurement.
enum:
- 1
- 2
- 4
- 8
- 16
default: 1
qcom,decimation:
$ref: /schemas/types.yaml#/definitions/uint32
description: This parameter is used to decrease ADC sampling rate.
Quicker measurements can be made by reducing decimation ratio.
enum:
- 256
- 512
- 1024
default: 1024
patternProperties:
"^([-a-z0-9]*)@[0-7]$":
type: object
description:
Represent one thermal sensor.
properties:
reg:
description: Specify the sensor channel. There are 8 channels in PMIC5's ADC TM
minimum: 0
maximum: 7
io-channels:
description:
From common IIO binding. Used to pipe PMIC ADC channel to thermal monitor
qcom,ratiometric:
$ref: /schemas/types.yaml#/definitions/flag
description:
Channel calibration type.
If this property is specified VADC will use the VDD reference
(1.875V) and GND for channel calibration. If property is not found,
channel will be calibrated with 0V and 1.25V reference channels,
also known as absolute calibration.
qcom,hw-settle-time-us:
description: Time between AMUX getting configured and the ADC starting conversion.
enum: [0, 100, 200, 300, 400, 500, 600, 700, 1000, 2000, 4000, 6000, 8000, 10000]
qcom,pre-scaling:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: Used for scaling the channel input signal before the
signal is fed to VADC. The configuration for this node is to know the
pre-determined ratio and use it for post scaling. It is a pair of
integers, denoting the numerator and denominator of the fraction by
which input signal is multiplied. For example, <1 3> indicates the
signal is scaled down to 1/3 of its value before ADC measurement. If
property is not found default value depending on chip will be used.
items:
- const: 1
- enum: [ 1, 3, 4, 6, 20, 8, 10 ]
required:
- reg
- io-channels
additionalProperties:
false
required:
- compatible
- reg
- interrupts
- "#address-cells"
- "#size-cells"
- "#thermal-sensor-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/interrupt-controller/irq.h>
spmi_bus {
#address-cells = <1>;
#size-cells = <0>;
pm8998_adc: adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc-rev2";
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
/* Other propreties are omitted */
adc-chan@4c {
reg = <ADC5_XO_THERM_100K_PU>;
};
};
pm8998_adc_tm: adc-tm@3400 {
compatible = "qcom,spmi-adc-tm-hc";
reg = <0x3400>;
interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
#thermal-sensor-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
thermistor@1 {
reg = <1>;
io-channels = <&pm8998_adc ADC5_XO_THERM_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time-us = <200>;
};
};
};
...
......@@ -12,14 +12,14 @@ maintainers:
properties:
compatible:
enum:
- rockchip,px30-tsadc # PX30 SoCs
- rockchip,rv1108-tsadc # RV1108 SoCs
- rockchip,rk3228-tsadc # RK3228 SoCs
- rockchip,rk3288-tsadc # RK3288 SoCs
- rockchip,rk3328-tsadc # RK3328 SoCs
- rockchip,rk3368-tsadc # RK3368 SoCs
- rockchip,rk3399-tsadc # RK3399 SoCs
- rockchip,rk3568-tsadc # RK3568 SoCs
- rockchip,px30-tsadc
- rockchip,rk3228-tsadc
- rockchip,rk3288-tsadc
- rockchip,rk3328-tsadc
- rockchip,rk3368-tsadc
- rockchip,rk3399-tsadc
- rockchip,rk3568-tsadc
- rockchip,rv1108-tsadc
reg:
maxItems: 1
......@@ -37,11 +37,15 @@ properties:
- const: apb_pclk
resets:
maxItems: 1
minItems: 1
maxItems: 3
reset-names:
minItems: 1
items:
- const: tsadc-apb
- const: tsadc
- const: tsadc-phy
"#thermal-sensor-cells":
const: 1
......@@ -71,7 +75,6 @@ required:
- clocks
- clock-names
- resets
- reset-names
- "#thermal-sensor-cells"
additionalProperties: false
......
......@@ -20,6 +20,7 @@ properties:
- socionext,uniphier-pxs2-thermal
- socionext,uniphier-ld20-thermal
- socionext,uniphier-pxs3-thermal
- socionext,uniphier-nx1-thermal
interrupts:
maxItems: 1
......
......@@ -15,6 +15,14 @@
#include "thermal_core.h"
static int user_space_bind(struct thermal_zone_device *tz)
{
pr_warn("Userspace governor deprecated: use thermal netlink " \
"notification instead\n");
return 0;
}
/**
* notify_user_space - Notifies user space about thermal events
* @tz: thermal_zone_device
......@@ -43,5 +51,6 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
static struct thermal_governor thermal_gov_user_space = {
.name = "user_space",
.throttle = notify_user_space,
.bind_to_tz = user_space_bind,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space);
......@@ -44,15 +44,21 @@ static int int3401_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int int3401_thermal_suspend(struct device *dev)
{
return proc_thermal_suspend(dev);
}
static int int3401_thermal_resume(struct device *dev)
{
return proc_thermal_resume(dev);
}
#else
#define int3401_thermal_suspend NULL
#define int3401_thermal_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, NULL, int3401_thermal_resume);
static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend,
int3401_thermal_resume);
static struct platform_driver int3401_driver = {
.probe = int3401_add,
......
......@@ -68,8 +68,7 @@ static const struct attribute_group power_limit_attribute_group = {
.name = "power_limits"
};
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
struct device_attribute *attr, char *buf)
static int tcc_get_offset(void)
{
u64 val;
int err;
......@@ -78,8 +77,20 @@ static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
if (err)
return err;
val = (val >> 24) & 0x3f;
return sprintf(buf, "%d\n", (int)val);
return (val >> 24) & 0x3f;
}
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int tcc;
tcc = tcc_get_offset();
if (tcc < 0)
return tcc;
return sprintf(buf, "%d\n", tcc);
}
static int tcc_offset_update(unsigned int tcc)
......@@ -107,8 +118,6 @@ static int tcc_offset_update(unsigned int tcc)
return 0;
}
static int tcc_offset_save = -1;
static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
......@@ -131,8 +140,6 @@ static ssize_t tcc_offset_degree_celsius_store(struct device *dev,
if (err)
return err;
tcc_offset_save = tcc;
return count;
}
......@@ -345,6 +352,18 @@ void proc_thermal_remove(struct proc_thermal_device *proc_priv)
}
EXPORT_SYMBOL_GPL(proc_thermal_remove);
static int tcc_offset_save = -1;
int proc_thermal_suspend(struct device *dev)
{
tcc_offset_save = tcc_get_offset();
if (tcc_offset_save < 0)
dev_warn(dev, "failed to save offset (%d)\n", tcc_offset_save);
return 0;
}
EXPORT_SYMBOL_GPL(proc_thermal_suspend);
int proc_thermal_resume(struct device *dev)
{
struct proc_thermal_device *proc_dev;
......@@ -352,6 +371,7 @@ int proc_thermal_resume(struct device *dev)
proc_dev = dev_get_drvdata(dev);
proc_thermal_read_ppcc(proc_dev);
/* Do not update if saving failed */
if (tcc_offset_save >= 0)
tcc_offset_update(tcc_offset_save);
......
......@@ -83,6 +83,7 @@ void proc_thermal_mbox_remove(struct pci_dev *pdev);
int processor_thermal_send_mbox_cmd(struct pci_dev *pdev, u16 cmd_id, u32 cmd_data, u32 *cmd_resp);
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
int proc_thermal_suspend(struct device *dev);
int proc_thermal_resume(struct device *dev);
int proc_thermal_mmio_add(struct pci_dev *pdev,
struct proc_thermal_device *proc_priv,
......
......@@ -314,6 +314,20 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int proc_thermal_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct proc_thermal_device *proc_priv;
struct proc_thermal_pci *pci_info;
proc_priv = pci_get_drvdata(pdev);
pci_info = proc_priv->priv_data;
if (!pci_info->no_legacy)
return proc_thermal_suspend(dev);
return 0;
}
static int proc_thermal_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
......@@ -335,10 +349,12 @@ static int proc_thermal_pci_resume(struct device *dev)
return 0;
}
#else
#define proc_thermal_pci_suspend NULL
#define proc_thermal_pci_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
proc_thermal_pci_resume);
static const struct pci_device_id proc_thermal_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
......
......@@ -107,15 +107,21 @@ static void proc_thermal_pci_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int proc_thermal_pci_suspend(struct device *dev)
{
return proc_thermal_suspend(dev);
}
static int proc_thermal_pci_resume(struct device *dev)
{
return proc_thermal_resume(dev);
}
#else
#define proc_thermal_pci_suspend NULL
#define proc_thermal_pci_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, NULL, proc_thermal_pci_resume);
static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
proc_thermal_pci_resume);
static const struct pci_device_id proc_thermal_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
......
......@@ -34,7 +34,7 @@ config QCOM_SPMI_TEMP_ALARM
config QCOM_LMH
tristate "Qualcomm Limits Management Hardware"
depends on ARCH_QCOM
depends on ARCH_QCOM && QCOM_SCM
help
This enables initialization of Qualcomm limits management
hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on
......
......@@ -82,6 +82,7 @@ struct adc_tm5_data {
const u32 full_scale_code_volt;
unsigned int *decimation;
unsigned int *hw_settle;
bool is_hc;
};
enum adc_tm5_cal_method {
......@@ -146,6 +147,14 @@ static const struct adc_tm5_data adc_tm5_data_pmic = {
64000, 128000 },
};
static const struct adc_tm5_data adc_tm_hc_data_pmic = {
.full_scale_code_volt = 0x70e4,
.decimation = (unsigned int []) { 256, 512, 1024 },
.hw_settle = (unsigned int []) { 0, 100, 200, 300, 400, 500, 600, 700,
1000, 2000, 4000, 6000, 8000, 10000 },
.is_hc = true,
};
static int adc_tm5_read(struct adc_tm5_chip *adc_tm, u16 offset, u8 *data, int len)
{
return regmap_bulk_read(adc_tm->regmap, adc_tm->base + offset, data, len);
......@@ -375,6 +384,29 @@ static int adc_tm5_register_tzd(struct adc_tm5_chip *adc_tm)
return 0;
}
static int adc_tm_hc_init(struct adc_tm5_chip *chip)
{
unsigned int i;
u8 buf[2];
int ret;
for (i = 0; i < chip->nchannels; i++) {
if (chip->channels[i].channel >= ADC_TM5_NUM_CHANNELS) {
dev_err(chip->dev, "Invalid channel %d\n", chip->channels[i].channel);
return -EINVAL;
}
}
buf[0] = chip->decimation;
buf[1] = chip->avg_samples | ADC_TM5_FAST_AVG_EN;
ret = adc_tm5_write(chip, ADC_TM5_ADC_DIG_PARAM, buf, sizeof(buf));
if (ret)
dev_err(chip->dev, "block write failed: %d\n", ret);
return ret;
}
static int adc_tm5_init(struct adc_tm5_chip *chip)
{
u8 buf[4], channels_available;
......@@ -591,7 +623,10 @@ static int adc_tm5_probe(struct platform_device *pdev)
return ret;
}
ret = adc_tm5_init(adc_tm);
if (adc_tm->data->is_hc)
ret = adc_tm_hc_init(adc_tm);
else
ret = adc_tm5_init(adc_tm);
if (ret) {
dev_err(dev, "adc-tm init failed\n");
return ret;
......@@ -612,6 +647,10 @@ static const struct of_device_id adc_tm5_match_table[] = {
.compatible = "qcom,spmi-adc-tm5",
.data = &adc_tm5_data_pmic,
},
{
.compatible = "qcom,spmi-adc-tm-hc",
.data = &adc_tm_hc_data_pmic,
},
{ }
};
MODULE_DEVICE_TABLE(of, adc_tm5_match_table);
......
......@@ -603,22 +603,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
int ret;
/* VER_0 doesn't have VALID bit */
if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], &valid);
if (ret)
return ret;
while (!valid) {
/* Valid bit is 0 for 6 AHB clock cycles.
* At 19.2MHz, 1 AHB clock is ~60ns.
* We should enter this loop very, very rarely.
*/
ndelay(400);
ret = regmap_field_read(priv->rf[valid_idx], &valid);
if (ret)
return ret;
}
}
if (tsens_version(priv) == VER_0)
goto get_temp;
/* Valid bit is 0 for 6 AHB clock cycles.
* At 19.2MHz, 1 AHB clock is ~60ns.
* We should enter this loop very, very rarely.
* Wait 1 us since it's the min of poll_timeout macro.
* Old value was 400 ns.
*/
ret = regmap_field_read_poll_timeout(priv->rf[valid_idx], valid,
valid, 1, 20 * USEC_PER_MSEC);
if (ret)
return ret;
get_temp:
/* Valid bit is set, OK to read the temperature */
*temp = tsens_hw_to_mC(s, temp_idx);
......
......@@ -34,6 +34,10 @@
#define REG_GEN3_THCODE1 0x50
#define REG_GEN3_THCODE2 0x54
#define REG_GEN3_THCODE3 0x58
#define REG_GEN3_PTAT1 0x5c
#define REG_GEN3_PTAT2 0x60
#define REG_GEN3_PTAT3 0x64
#define REG_GEN3_THSCP 0x68
/* IRQ{STR,MSK,EN} bits */
#define IRQ_TEMP1 BIT(0)
......@@ -55,6 +59,9 @@
#define THCTR_PONM BIT(6)
#define THCTR_THSST BIT(0)
/* THSCP bits */
#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14))
#define CTEMP_MASK 0xFFF
#define MCELSIUS(temp) ((temp) * 1000)
......@@ -62,15 +69,6 @@
#define TSC_MAX_NUM 5
/* default THCODE values if FUSEs are missing */
static const int thcodes[TSC_MAX_NUM][3] = {
{ 3397, 2800, 2221 },
{ 3393, 2795, 2216 },
{ 3389, 2805, 2237 },
{ 3415, 2694, 2195 },
{ 3356, 2724, 2244 },
};
/* Structure for thermal temperature calculation */
struct equation_coefs {
int a1;
......@@ -84,13 +82,14 @@ struct rcar_gen3_thermal_tsc {
struct thermal_zone_device *zone;
struct equation_coefs coef;
int tj_t;
unsigned int id; /* thermal channel id */
int thcode[3];
};
struct rcar_gen3_thermal_priv {
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
unsigned int num_tscs;
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
int ptat[3];
};
static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
......@@ -133,8 +132,8 @@ static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
/* no idea where these constants come from */
#define TJ_3 -41
static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
int *ptat, const int *thcode,
static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_priv *priv,
struct rcar_gen3_thermal_tsc *tsc,
int ths_tj_1)
{
/* TODO: Find documentation and document constant calculation formula */
......@@ -143,16 +142,16 @@ static void rcar_gen3_thermal_calc_coefs(struct rcar_gen3_thermal_tsc *tsc,
* Division is not scaled in BSP and if scaled it might overflow
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
*/
tsc->tj_t = (FIXPT_INT((ptat[1] - ptat[2]) * (ths_tj_1 - TJ_3))
/ (ptat[0] - ptat[2])) + FIXPT_INT(TJ_3);
tsc->tj_t = (FIXPT_INT((priv->ptat[1] - priv->ptat[2]) * (ths_tj_1 - TJ_3))
/ (priv->ptat[0] - priv->ptat[2])) + FIXPT_INT(TJ_3);
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
tsc->coef.a1 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[2]),
tsc->tj_t - FIXPT_INT(TJ_3));
tsc->coef.b1 = FIXPT_INT(thcode[2]) - tsc->coef.a1 * TJ_3;
tsc->coef.b1 = FIXPT_INT(tsc->thcode[2]) - tsc->coef.a1 * TJ_3;
tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
tsc->coef.a2 = FIXPT_DIV(FIXPT_INT(tsc->thcode[1] - tsc->thcode[0]),
tsc->tj_t - FIXPT_INT(ths_tj_1));
tsc->coef.b2 = FIXPT_INT(thcode[0]) - tsc->coef.a2 * ths_tj_1;
tsc->coef.b2 = FIXPT_INT(tsc->thcode[0]) - tsc->coef.a2 * ths_tj_1;
}
static int rcar_gen3_thermal_round(int temp)
......@@ -174,7 +173,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
/* Read register and convert to mili Celsius */
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
if (reg <= thcodes[tsc->id][1])
if (reg <= tsc->thcode[1])
val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
tsc->coef.a1);
else
......@@ -253,6 +252,64 @@ static const struct soc_device_attribute r8a7795es1[] = {
{ /* sentinel */ }
};
static bool rcar_gen3_thermal_read_fuses(struct rcar_gen3_thermal_priv *priv)
{
unsigned int i;
u32 thscp;
/* If fuses are not set, fallback to pseudo values. */
thscp = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_THSCP);
if ((thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) {
/* Default THCODE values in case FUSEs are not set. */
static const int thcodes[TSC_MAX_NUM][3] = {
{ 3397, 2800, 2221 },
{ 3393, 2795, 2216 },
{ 3389, 2805, 2237 },
{ 3415, 2694, 2195 },
{ 3356, 2724, 2244 },
};
priv->ptat[0] = 2631;
priv->ptat[1] = 1509;
priv->ptat[2] = 435;
for (i = 0; i < priv->num_tscs; i++) {
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
tsc->thcode[0] = thcodes[i][0];
tsc->thcode[1] = thcodes[i][1];
tsc->thcode[2] = thcodes[i][2];
}
return false;
}
/*
* Set the pseudo calibration points with fused values.
* PTAT is shared between all TSCs but only fused for the first
* TSC while THCODEs are fused for each TSC.
*/
priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT1) &
GEN3_FUSE_MASK;
priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT2) &
GEN3_FUSE_MASK;
priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT3) &
GEN3_FUSE_MASK;
for (i = 0; i < priv->num_tscs; i++) {
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE1) &
GEN3_FUSE_MASK;
tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE2) &
GEN3_FUSE_MASK;
tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE3) &
GEN3_FUSE_MASK;
}
return true;
}
static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
{
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
......@@ -401,10 +458,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
unsigned int i;
int ret;
/* default values if FUSEs are missing */
/* TODO: Read values from hardware on supported platforms */
int ptat[3] = { 2631, 1509, 435 };
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......@@ -439,9 +492,17 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
ret = PTR_ERR(tsc->base);
goto error_unregister;
}
tsc->id = i;
priv->tscs[i] = tsc;
}
priv->num_tscs = i;
if (!rcar_gen3_thermal_read_fuses(priv))
dev_info(dev, "No calibration values fused, fallback to driver values\n");
for (i = 0; i < priv->num_tscs; i++) {
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
&rcar_gen3_tz_of_ops);
......@@ -453,7 +514,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
tsc->zone = zone;
priv->thermal_init(tsc);
rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1);
rcar_gen3_thermal_calc_coefs(priv, tsc, *ths_tj_1);
tsc->zone->tzp->no_hwmon = false;
ret = thermal_add_hwmon_sysfs(tsc->zone);
......@@ -471,8 +532,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret);
}
priv->num_tscs = i;
if (!priv->num_tscs) {
ret = -ENODEV;
goto error_unregister;
......
......@@ -1383,7 +1383,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
if (IS_ERR(thermal->regs))
return PTR_ERR(thermal->regs);
thermal->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb");
thermal->reset = devm_reset_control_array_get(&pdev->dev, false, false);
if (IS_ERR(thermal->reset)) {
error = PTR_ERR(thermal->reset);
dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error);
......
......@@ -375,10 +375,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
if (tz->last_temperature != THERMAL_TEMP_INVALID) {
if (tz->last_temperature < trip_temp &&
tz->temperature >= trip_temp)
thermal_notify_tz_trip_up(tz->id, trip);
thermal_notify_tz_trip_up(tz->id, trip,
tz->temperature);
if (tz->last_temperature >= trip_temp &&
tz->temperature < (trip_temp - hyst))
thermal_notify_tz_trip_down(tz->id, trip);
thermal_notify_tz_trip_down(tz->id, trip,
tz->temperature);
}
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
......@@ -887,7 +889,7 @@ __thermal_cooling_device_register(struct device_node *np,
{
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos = NULL;
int ret;
int id, ret;
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
!ops->set_cur_state)
......@@ -901,6 +903,11 @@ __thermal_cooling_device_register(struct device_node *np,
if (ret < 0)
goto out_kfree_cdev;
cdev->id = ret;
id = ret;
ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
if (ret)
goto out_ida_remove;
cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
if (!cdev->type) {
......@@ -916,7 +923,6 @@ __thermal_cooling_device_register(struct device_node *np,
cdev->device.class = &thermal_class;
cdev->devdata = devdata;
thermal_cooling_device_setup_sysfs(cdev);
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
ret = device_register(&cdev->device);
if (ret)
goto out_kfree_type;
......@@ -941,8 +947,9 @@ __thermal_cooling_device_register(struct device_node *np,
out_kfree_type:
kfree(cdev->type);
put_device(&cdev->device);
cdev = NULL;
out_ida_remove:
ida_simple_remove(&thermal_cdev_ida, cdev->id);
ida_simple_remove(&thermal_cdev_ida, id);
out_kfree_cdev:
kfree(cdev);
return ERR_PTR(ret);
......@@ -1227,6 +1234,10 @@ thermal_zone_device_register(const char *type, int trips, int mask,
tz->id = id;
strlcpy(tz->type, type, sizeof(tz->type));
result = dev_set_name(&tz->device, "thermal_zone%d", tz->id);
if (result)
goto remove_id;
if (!ops->critical)
ops->critical = thermal_zone_device_critical;
......@@ -1248,7 +1259,6 @@ thermal_zone_device_register(const char *type, int trips, int mask,
/* A new thermal zone needs to be updated anyway. */
atomic_set(&tz->need_update, 1);
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
result = device_register(&tz->device);
if (result)
goto release_device;
......
......@@ -34,7 +34,7 @@ static int thermal_mmio_get_temperature(void *private, int *temp)
return 0;
}
static struct thermal_zone_of_device_ops thermal_mmio_ops = {
static const struct thermal_zone_of_device_ops thermal_mmio_ops = {
.get_temp = thermal_mmio_get_temperature,
};
......
......@@ -121,7 +121,8 @@ static int thermal_genl_event_tz(struct param *p)
static int thermal_genl_event_tz_trip_up(struct param *p)
{
if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp))
return -EMSGSIZE;
return 0;
......@@ -285,16 +286,16 @@ int thermal_notify_tz_disable(int tz_id)
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
}
int thermal_notify_tz_trip_down(int tz_id, int trip_id)
int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp)
{
struct param p = { .tz_id = tz_id, .trip_id = trip_id };
struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
}
int thermal_notify_tz_trip_up(int tz_id, int trip_id)
int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp)
{
struct param p = { .tz_id = tz_id, .trip_id = trip_id };
struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
}
......
......@@ -11,8 +11,8 @@ int thermal_notify_tz_create(int tz_id, const char *name);
int thermal_notify_tz_delete(int tz_id);
int thermal_notify_tz_enable(int tz_id);
int thermal_notify_tz_disable(int tz_id);
int thermal_notify_tz_trip_down(int tz_id, int id);
int thermal_notify_tz_trip_up(int tz_id, int id);
int thermal_notify_tz_trip_down(int tz_id, int id, int temp);
int thermal_notify_tz_trip_up(int tz_id, int id, int temp);
int thermal_notify_tz_trip_delete(int tz_id, int id);
int thermal_notify_tz_trip_add(int tz_id, int id, int type,
int temp, int hyst);
......@@ -49,12 +49,12 @@ static inline int thermal_notify_tz_disable(int tz_id)
return 0;
}
static inline int thermal_notify_tz_trip_down(int tz_id, int id)
static inline int thermal_notify_tz_trip_down(int tz_id, int id, int temp)
{
return 0;
}
static inline int thermal_notify_tz_trip_up(int tz_id, int id)
static inline int thermal_notify_tz_trip_up(int tz_id, int id, int temp)
{
return 0;
}
......
......@@ -610,6 +610,9 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
unsigned long state;
int result;
dev_warn_once(&cdev->device,
"Setting cooling device state is deprecated\n");
if (sscanf(buf, "%ld\n", &state) != 1)
return -EINVAL;
......
......@@ -358,6 +358,10 @@ static const struct of_device_id uniphier_tm_dt_ids[] = {
.compatible = "socionext,uniphier-pxs3-thermal",
.data = &uniphier_ld20_tm_data,
},
{
.compatible = "socionext,uniphier-nx1-thermal",
.data = &uniphier_ld20_tm_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment