More thermal control updates for 6.6-rc1

- Check if the Tegra BPMP supports the trip points in order to set the
     .set_trips callback (Mikko Perttunen).
 
   - Add new Loongson-2 thermal sensor along with the DT bindings (Yinbo
     Zhu).
 
   - Use IS_ERR_OR_NULL() helper to replace a double test on the TI
     bandgap sensor (Li Zetao).
 
   - Remove redundant platform_set_drvdata() calls, as there are no
     corresponding calls to platform_get_drvdata(), from a bunch of
     drivers (Andrei Coardos).
 
   - Switch the Mediatek LVTS mode to filtered in order to enable
     interrupts (Nícolas F. R. A. Prado).
 
   - Fix Wvoid-pointer-to-enum-cast warning on the Exynos TMU (Krzysztof
     Kozlowski).
 
   - Remove redundant dev_err_probe(), because the underlying function
     already called it, from the Mediatek sensor (Chen Jiahao).
 
    - Free calibration nvmem after reading it on sun8i (Mark Brown).
 
    - Remove useless comment from the sun8i driver (Yangtao Li).
 
    - Make tsens_xxxx_nvmem static to fix a sparse warning on QCom
      tsens (Min-Hua Chen).
 
    - Remove error message at probe deferral on imx8mm (Ahmad Fatoum).
 
    - Fix parameter check in lvts_debugfs_init() with IS_ERR() on
      Mediatek LVTS (Minjie Du).
 
    - Fix interrupt routine and configuratoin for Mediatek LVTS (Nícolas
      F. R. A. Prado).
 
    - Drop unused .get_trip_type(), .get_trip_temp() and .get_trip_hyst()
      thermal zone callbacks from the core and rework the .get_trend()
      one to take a trip point pointer as an argument (Rafael Wysocki).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmT2DnQSHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRxB5MQAIcrHQWoI7dTwLIchSbWhsfkm3dAy4nS
 CyLexkli5wCxbsdg2B2ATqBP4ttyB3Jbe7rWqI6+a/CUrtvyOxM0wmNp/wXI1u/C
 YC3T2uRMhODRvxueQrbrrSA/t/u7QiFCdyXuMyRYzwyxibc4bMKuyLcZ6VrckTRH
 fy3QvnIIXhBsox97KccXsqaKWzZgi2BaJVA+29l8ikH8IcTwdfGmTrty2z3KiVc8
 jk8WiMSkITPWST/CbCCFojjYABbBSQ1tKnDBDCYdDos2BFqiPDr7cdaVa6iTt+BD
 baa5ZseMcCdxSMqi2uvnwI3OCkVRGL4WKCYthTNOKjxfqyKhMI91R5Yayqn3B73P
 qYcEujVYoeFRzSrQh4luLBr+vcOatvl5woO5PpfSL18d0sPVM3bbwCcm5ovSXUJy
 YWp1Wi7ra/bP7EHiMQHII6Y+vGi386GbAunKdV/548r+aoy2wS/WKghsT3pbq4LQ
 E93r4jPcefP9Q9Re3IHE77TE1BvQ01wD/ZBwFy07oUGYD9a1CSA0vm90KHEb/5kr
 8Ub29RPsP3ltvRFj35abHu1fBtdIoBwT8J2GblwzYpJJ1v29h1elzuUXcJh1pTvZ
 HgbgBs4dj3jWIg81WVnoTKMqAuNyGNFTzzYk1yX+tCMx10/TLBj6HmxwI/HXyipC
 +0WFLGpURP1F
 =I19o
 -----END PGP SIGNATURE-----

Merge tag 'thermal-6.6-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull more thermal control updates from Rafael Wysocki:
 "These are mostly updates of thermal control drivers for ARM platforms,
  new thermal control support for Loongson-2 and a couple of core
  cleanups made possible by recent changes merged previously.

  Specifics:

   - Check if the Tegra BPMP supports the trip points in order to set
     the .set_trips callback (Mikko Perttunen)

   - Add new Loongson-2 thermal sensor along with the DT bindings (Yinbo
     Zhu)

   - Use IS_ERR_OR_NULL() helper to replace a double test on the TI
     bandgap sensor (Li Zetao)

   - Remove redundant platform_set_drvdata() calls, as there are no
     corresponding calls to platform_get_drvdata(), from a bunch of
     drivers (Andrei Coardos)

   - Switch the Mediatek LVTS mode to filtered in order to enable
     interrupts (Nícolas F. R. A. Prado)

   - Fix Wvoid-pointer-to-enum-cast warning on the Exynos TMU (Krzysztof
     Kozlowski)

   - Remove redundant dev_err_probe(), because the underlying function
     already called it, from the Mediatek sensor (Chen Jiahao)

   - Free calibration nvmem after reading it on sun8i (Mark Brown)

   - Remove useless comment from the sun8i driver (Yangtao Li)

   - Make tsens_xxxx_nvmem static to fix a sparse warning on QCom tsens
     (Min-Hua Chen)

   - Remove error message at probe deferral on imx8mm (Ahmad Fatoum)

   - Fix parameter check in lvts_debugfs_init() with IS_ERR() on
     Mediatek LVTS (Minjie Du)

   - Fix interrupt routine and configuratoin for Mediatek LVTS (Nícolas
     F. R. A. Prado)

   - Drop unused .get_trip_type(), .get_trip_temp() and .get_trip_hyst()
     thermal zone callbacks from the core and rework the .get_trend()
     one to take a trip point pointer as an argument (Rafael Wysocki)"

* tag 'thermal-6.6-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (29 commits)
  thermal: core: Rework .get_trend() thermal zone callback
  thermal: core: Drop unused .get_trip_*() callbacks
  thermal/drivers/tegra-bpmp: Check if BPMP supports trip points
  thermal: dt-bindings: add loongson-2 thermal
  thermal/drivers/loongson-2: Add thermal management support
  thermal/drivers/ti-soc-thermal: Use helper function IS_ERR_OR_NULL()
  thermal/drivers/generic-adc: Removed unneeded call to platform_set_drvdata()
  thermal/drivers/max77620_thermal: Removed unneeded call to platform_set_drvdata()
  thermal/drivers/mediatek/auxadc_thermal: Removed call to platform_set_drvdata()
  thermal/drivers/sun8i_thermal: Remove unneeded call to platform_set_drvdata()
  thermal/drivers/broadcom/brcstb_thermal: Removed unneeded platform_set_drvdata()
  thermal/drivers/mediatek/lvts_thermal: Make readings valid in filtered mode
  thermal/drivers/k3_bandgap: Remove unneeded call to platform_set_drvdata()
  thermal/drivers/k3_j72xx_bandgap: Removed unneeded call to platform_set_drvdata()
  thermal/drivers/broadcom/sr-thermal: Removed call to platform_set_drvdata()
  thermal/drivers/samsung: Fix Wvoid-pointer-to-enum-cast warning
  thermal/drivers/db8500: Remove redundant of_match_ptr()
  thermal/drivers/mediatek: Clean up redundant dev_err_probe()
  thermal/drivers/sun8i: Free calibration nvmem after reading it
  thermal/drivers/sun8i: Remove unneeded comments
  ...
This commit is contained in:
Linus Torvalds 2023-09-04 15:17:28 -07:00
commit 0ca4080a88
28 changed files with 472 additions and 144 deletions

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/loongson,ls2k-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Thermal sensors on Loongson-2 SoCs
maintainers:
- zhanghongchen <zhanghongchen@loongson.cn>
- Yinbo Zhu <zhuyinbo@loongson.cn>
properties:
compatible:
oneOf:
- enum:
- loongson,ls2k1000-thermal
- items:
- enum:
- loongson,ls2k2000-thermal
- const: loongson,ls2k1000-thermal
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
thermal: thermal-sensor@1fe01500 {
compatible = "loongson,ls2k1000-thermal";
reg = <0x1fe01500 0x30>;
interrupt-parent = <&liointc0>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
};

View File

@ -12390,6 +12390,14 @@ S: Maintained
F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k-pinctrl.yaml
F: drivers/pinctrl/pinctrl-loongson2.c
LOONGSON-2 SOC SERIES THERMAL DRIVER
M: zhanghongchen <zhanghongchen@loongson.cn>
M: Yinbo Zhu <zhuyinbo@loongson.cn>
L: linux-pm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
F: drivers/thermal/loongson2_thermal.c
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Sathya Prakash <sathya.prakash@broadcom.com>
M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>

View File

@ -492,26 +492,22 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
}
static int thermal_get_trend(struct thermal_zone_device *thermal,
int trip_index, enum thermal_trend *trend)
struct thermal_trip *trip,
enum thermal_trend *trend)
{
struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
struct acpi_thermal_trip *acpi_trip;
int t, i;
int t;
if (!tz || trip_index < 0)
if (!tz || !trip)
return -EINVAL;
if (tz->trips.critical.valid)
trip_index--;
if (tz->trips.hot.valid)
trip_index--;
if (trip_index < 0)
acpi_trip = trip->priv;
if (!acpi_trip || !acpi_trip->valid)
return -EINVAL;
acpi_trip = &tz->trips.passive.trip;
if (acpi_trip->valid && !trip_index--) {
switch (trip->type) {
case THERMAL_TRIP_PASSIVE:
t = tz->trips.passive.tc1 * (tz->temperature -
tz->last_temperature) +
tz->trips.passive.tc2 * (tz->temperature -
@ -524,19 +520,18 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
*trend = THERMAL_TREND_STABLE;
return 0;
}
t = acpi_thermal_temp(tz, tz->temperature);
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
acpi_trip = &tz->trips.active[i].trip;
if (acpi_trip->valid && !trip_index--) {
if (t > acpi_thermal_temp(tz, acpi_trip->temperature)) {
*trend = THERMAL_TREND_RAISING;
return 0;
}
case THERMAL_TRIP_ACTIVE:
t = acpi_thermal_temp(tz, tz->temperature);
if (t <= trip->temperature)
break;
}
*trend = THERMAL_TREND_RAISING;
return 0;
default:
break;
}
return -EINVAL;

View File

@ -510,4 +510,16 @@ config KHADAS_MCU_FAN_THERMAL
If you say yes here you get support for the FAN controlled
by the Microcontroller found on the Khadas VIM boards.
config LOONGSON2_THERMAL
tristate "Loongson-2 SoC series thermal driver"
depends on LOONGARCH || COMPILE_TEST
depends on OF
help
Support for Thermal driver found on Loongson-2 SoC series platforms.
The thermal driver realizes get_temp and set_trips function, which
are used to obtain the temperature of the current node and set the
temperature range to trigger the interrupt. When the input temperature
is higher than the high temperature threshold or lower than the low
temperature threshold, the interrupt will occur.
endif

View File

@ -63,3 +63,4 @@ obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o

View File

@ -334,7 +334,6 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
return PTR_ERR(priv->tmon_base);
priv->dev = &pdev->dev;
platform_set_drvdata(pdev, priv);
of_ops = priv->temp_params->of_ops;
thermal = devm_thermal_of_zone_register(&pdev->dev, 0, priv,

View File

@ -91,7 +91,6 @@ static int sr_thermal_probe(struct platform_device *pdev)
dev_dbg(dev, "thermal sensor %d registered\n", i);
}
platform_set_drvdata(pdev, sr_thermal);
return 0;
}

View File

@ -229,7 +229,7 @@ MODULE_DEVICE_TABLE(of, db8500_thermal_match);
static struct platform_driver db8500_thermal_driver = {
.driver = {
.name = "db8500-thermal",
.of_match_table = of_match_ptr(db8500_thermal_match),
.of_match_table = db8500_thermal_match,
},
.probe = db8500_thermal_probe,
.suspend = db8500_thermal_suspend,

View File

@ -178,10 +178,8 @@ static int imx8mm_tmu_probe_set_calib_v1(struct platform_device *pdev,
int ret;
ret = nvmem_cell_read_u32(&pdev->dev, "calib", &ana0);
if (ret) {
dev_warn(dev, "Failed to read OCOTP nvmem cell (%d).\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to read OCOTP nvmem cell\n");
writel(FIELD_PREP(TASR_BUF_VREF_MASK,
FIELD_GET(ANA0_BUF_VREF_MASK, ana0)) |

View File

@ -225,7 +225,6 @@ static int k3_bandgap_probe(struct platform_device *pdev)
devm_thermal_add_hwmon_sysfs(dev, data[id].tzd);
}
platform_set_drvdata(pdev, bgp);
return 0;

View File

@ -502,8 +502,6 @@ static int k3_j72xx_bandgap_probe(struct platform_device *pdev)
writel(K3_VTM_ANYMAXT_OUTRG_ALERT_EN, data[0].bgp->cfg2_base +
K3_VTM_MISC_CTRL_OFFSET);
platform_set_drvdata(pdev, bgp);
print_look_up_table(dev, ref_table);
/*
* Now that the derived_table has the appropriate look up values

View File

@ -0,0 +1,169 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Author: zhanghongchen <zhanghongchen@loongson.cn>
* Yinbo Zhu <zhuyinbo@loongson.cn>
* Copyright (C) 2022-2023 Loongson Technology Corporation Limited
*/
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/units.h>
#include "thermal_hwmon.h"
#define LOONGSON2_MAX_SENSOR_SEL_NUM 3
#define LOONGSON2_THSENS_CTRL_HI_REG 0x0
#define LOONGSON2_THSENS_CTRL_LOW_REG 0x8
#define LOONGSON2_THSENS_STATUS_REG 0x10
#define LOONGSON2_THSENS_OUT_REG 0x14
#define LOONGSON2_THSENS_INT_LO BIT(0)
#define LOONGSON2_THSENS_INT_HIGH BIT(1)
#define LOONGSON2_THSENS_OUT_MASK 0xFF
struct loongson2_thermal_chip_data {
unsigned int thermal_sensor_sel;
};
struct loongson2_thermal_data {
void __iomem *regs;
const struct loongson2_thermal_chip_data *chip_data;
};
static int loongson2_thermal_set(struct loongson2_thermal_data *data,
int low, int high, bool enable)
{
u64 reg_ctrl = 0;
int reg_off = data->chip_data->thermal_sensor_sel * 2;
low = clamp(-40, low, high);
high = clamp(125, low, high);
low += HECTO;
high += HECTO;
reg_ctrl = low;
reg_ctrl |= enable ? 0x100 : 0;
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_LOW_REG + reg_off);
reg_ctrl = high;
reg_ctrl |= enable ? 0x100 : 0;
writew(reg_ctrl, data->regs + LOONGSON2_THSENS_CTRL_HI_REG + reg_off);
return 0;
}
static int loongson2_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
u32 reg_val;
struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
reg_val = readl(data->regs + LOONGSON2_THSENS_OUT_REG);
*temp = ((reg_val & LOONGSON2_THSENS_OUT_MASK) - HECTO) * KILO;
return 0;
}
static irqreturn_t loongson2_thermal_irq_thread(int irq, void *dev)
{
struct thermal_zone_device *tzd = dev;
struct loongson2_thermal_data *data = thermal_zone_device_priv(tzd);
writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +
LOONGSON2_THSENS_STATUS_REG);
thermal_zone_device_update(tzd, THERMAL_EVENT_UNSPECIFIED);
return IRQ_HANDLED;
}
static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low, int high)
{
struct loongson2_thermal_data *data = thermal_zone_device_priv(tz);
return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
}
static const struct thermal_zone_device_ops loongson2_of_thermal_ops = {
.get_temp = loongson2_thermal_get_temp,
.set_trips = loongson2_thermal_set_trips,
};
static int loongson2_thermal_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct loongson2_thermal_data *data;
struct thermal_zone_device *tzd;
int ret, irq, i;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->chip_data = device_get_match_data(dev);
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs))
return PTR_ERR(data->regs);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
writeb(LOONGSON2_THSENS_INT_LO | LOONGSON2_THSENS_INT_HIGH, data->regs +
LOONGSON2_THSENS_STATUS_REG);
loongson2_thermal_set(data, 0, 0, false);
for (i = 0; i <= LOONGSON2_MAX_SENSOR_SEL_NUM; i++) {
tzd = devm_thermal_of_zone_register(dev, i, data,
&loongson2_of_thermal_ops);
if (!IS_ERR(tzd))
break;
if (PTR_ERR(tzd) != ENODEV)
continue;
return dev_err_probe(dev, PTR_ERR(tzd), "failed to register");
}
ret = devm_request_threaded_irq(dev, irq, NULL, loongson2_thermal_irq_thread,
IRQF_ONESHOT, "loongson2_thermal", tzd);
if (ret < 0)
return dev_err_probe(dev, ret, "failed to request alarm irq\n");
devm_thermal_add_hwmon_sysfs(dev, tzd);
return 0;
}
static const struct loongson2_thermal_chip_data loongson2_thermal_ls2k1000_data = {
.thermal_sensor_sel = 0,
};
static const struct of_device_id of_loongson2_thermal_match[] = {
{
.compatible = "loongson,ls2k1000-thermal",
.data = &loongson2_thermal_ls2k1000_data,
},
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_loongson2_thermal_match);
static struct platform_driver loongson2_thermal_driver = {
.driver = {
.name = "loongson2_thermal",
.of_match_table = of_loongson2_thermal_match,
},
.probe = loongson2_thermal_probe,
};
module_platform_driver(loongson2_thermal_driver);
MODULE_DESCRIPTION("Loongson2 thermal driver");
MODULE_LICENSE("GPL");

View File

@ -139,8 +139,6 @@ static int max77620_thermal_probe(struct platform_device *pdev)
return ret;
}
platform_set_drvdata(pdev, mtherm);
return 0;
}

View File

@ -1282,8 +1282,6 @@ static int mtk_thermal_probe(struct platform_device *pdev)
mtk_thermal_init_bank(mt, i, apmixed_phys_base,
auxadc_phys_base, ctrl_id);
platform_set_drvdata(pdev, mt);
tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
&mtk_thermal_ops);
if (IS_ERR(tzdev))

View File

@ -58,14 +58,19 @@
#define LVTS_PROTTC(__base) (__base + 0x00CC)
#define LVTS_CLKEN(__base) (__base + 0x00E4)
#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38))
#define LVTS_GROUP_INTERVAL 1
#define LVTS_FILTER_INTERVAL 1
#define LVTS_SENSOR_INTERVAL 1
#define LVTS_HW_FILTER 0x2
#define LVTS_PERIOD_UNIT 0
#define LVTS_GROUP_INTERVAL 0
#define LVTS_FILTER_INTERVAL 0
#define LVTS_SENSOR_INTERVAL 0
#define LVTS_HW_FILTER 0x0
#define LVTS_TSSEL_CONF 0x13121110
#define LVTS_CALSCALE_CONF 0x300
#define LVTS_MONINT_CONF 0x9FBF7BDE
#define LVTS_MONINT_CONF 0x8300318C
#define LVTS_MONINT_OFFSET_SENSOR0 0xC
#define LVTS_MONINT_OFFSET_SENSOR1 0x180
#define LVTS_MONINT_OFFSET_SENSOR2 0x3000
#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000
#define LVTS_INT_SENSOR0 0x0009001F
#define LVTS_INT_SENSOR1 0x001203E0
@ -81,8 +86,13 @@
#define LVTS_MSR_IMMEDIATE_MODE 0
#define LVTS_MSR_FILTERED_MODE 1
#define LVTS_MSR_READ_TIMEOUT_US 400
#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
#define LVTS_HW_SHUTDOWN_MT8195 105000
#define LVTS_MINIMUM_THRESHOLD 20000
static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
static int coeff_b = LVTS_COEFF_B;
@ -110,6 +120,8 @@ struct lvts_sensor {
void __iomem *base;
int id;
int dt_id;
int low_thresh;
int high_thresh;
};
struct lvts_ctrl {
@ -119,6 +131,8 @@ struct lvts_ctrl {
int num_lvts_sensor;
int mode;
void __iomem *base;
int low_thresh;
int high_thresh;
};
struct lvts_domain {
@ -190,7 +204,7 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
int i;
lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL);
if (!lvts_td->dom_dentry)
if (IS_ERR(lvts_td->dom_dentry))
return 0;
for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
@ -257,6 +271,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
void __iomem *msr = lvts_sensor->msr;
u32 value;
int rc;
/*
* Measurement registers:
@ -269,7 +284,8 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
* 16 : Valid temperature
* 15-0 : Raw temperature
*/
value = readl(msr);
rc = readl_poll_timeout(msr, value, value & BIT(16),
LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US);
/*
* As the thermal zone temperature will read before the
@ -282,7 +298,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
* functionning temperature and directly jump to a system
* shutdown.
*/
if (!(value & BIT(16)))
if (rc)
return -EAGAIN;
*temp = lvts_raw_to_temp(value & 0xFFFF);
@ -290,32 +306,84 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
return 0;
}
static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl)
{
u32 masks[] = {
LVTS_MONINT_OFFSET_SENSOR0,
LVTS_MONINT_OFFSET_SENSOR1,
LVTS_MONINT_OFFSET_SENSOR2,
LVTS_MONINT_OFFSET_SENSOR3,
};
u32 value = 0;
int i;
value = readl(LVTS_MONINT(lvts_ctrl->base));
for (i = 0; i < ARRAY_SIZE(masks); i++) {
if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
&& lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
value |= masks[i];
else
value &= ~masks[i];
}
writel(value, LVTS_MONINT(lvts_ctrl->base));
}
static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
{
int i;
if (high > lvts_ctrl->high_thresh)
return true;
for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++)
if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh
&& lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh)
return false;
return true;
}
static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
{
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
void __iomem *base = lvts_sensor->base;
u32 raw_low = lvts_temp_to_raw(low);
u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
u32 raw_high = lvts_temp_to_raw(high);
bool should_update_thresh;
lvts_sensor->low_thresh = low;
lvts_sensor->high_thresh = high;
should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high);
if (should_update_thresh) {
lvts_ctrl->high_thresh = high;
lvts_ctrl->low_thresh = low;
}
lvts_update_irq_mask(lvts_ctrl);
if (!should_update_thresh)
return 0;
/*
* Hot to normal temperature threshold
* Low offset temperature threshold
*
* LVTS_H2NTHRE
* LVTS_OFFSETL
*
* Bits:
*
* 14-0 : Raw temperature for threshold
*/
if (low != -INT_MAX) {
pr_debug("%s: Setting low limit temperature interrupt: %d\n",
thermal_zone_device_type(tz), low);
writel(raw_low, LVTS_H2NTHRE(base));
}
pr_debug("%s: Setting low limit temperature interrupt: %d\n",
thermal_zone_device_type(tz), low);
writel(raw_low, LVTS_OFFSETL(base));
/*
* Hot temperature threshold
* High offset temperature threshold
*
* LVTS_HTHRE
* LVTS_OFFSETH
*
* Bits:
*
@ -323,7 +391,7 @@ static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
*/
pr_debug("%s: Setting high limit temperature interrupt: %d\n",
thermal_zone_device_type(tz), high);
writel(raw_high, LVTS_HTHRE(base));
writel(raw_high, LVTS_OFFSETH(base));
return 0;
}
@ -451,7 +519,7 @@ static irqreturn_t lvts_irq_handler(int irq, void *data)
for (i = 0; i < lvts_td->num_lvts_ctrl; i++) {
aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl);
aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]);
if (aux != IRQ_HANDLED)
continue;
@ -521,6 +589,9 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
*/
lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ?
imm_regs[i] : msr_regs[i];
lvts_sensor[i].low_thresh = INT_MIN;
lvts_sensor[i].high_thresh = INT_MIN;
};
lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor;
@ -688,6 +759,9 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
*/
lvts_ctrl[i].hw_tshut_raw_temp =
lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
lvts_ctrl[i].low_thresh = INT_MIN;
lvts_ctrl[i].high_thresh = INT_MIN;
}
/*
@ -896,24 +970,6 @@ static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl)
LVTS_HW_FILTER << 3 | LVTS_HW_FILTER;
writel(value, LVTS_MSRCTL0(lvts_ctrl->base));
/*
* LVTS_MSRCTL1 : Measurement control
*
* Bits:
*
* 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
* 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
* 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
* 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
*
* That configuration will ignore the filtering and the delays
* introduced below in MONCTL1 and MONCTL2
*/
if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
value = BIT(9) | BIT(6) | BIT(5) | BIT(4);
writel(value, LVTS_MSRCTL1(lvts_ctrl->base));
}
/*
* LVTS_MONCTL1 : Period unit and group interval configuration
*
@ -979,6 +1035,15 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
struct thermal_zone_device *tz;
u32 sensor_map = 0;
int i;
/*
* Bitmaps to enable each sensor on immediate and filtered modes, as
* described in MSRCTL1 and MONCTL0 registers below, respectively.
*/
u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) };
u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) };
u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ?
sensor_imm_bitmap : sensor_filt_bitmap;
for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) {
@ -1016,20 +1081,38 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl)
* map, so we can enable the temperature monitoring in
* the hardware thermal controller.
*/
sensor_map |= BIT(i);
sensor_map |= sensor_bitmap[i];
}
/*
* Bits:
* 9: Single point access flow
* 0-3: Enable sensing point 0-3
*
* The initialization of the thermal zones give us
* which sensor point to enable. If any thermal zone
* was not described in the device tree, it won't be
* enabled here in the sensor map.
*/
writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) {
/*
* LVTS_MSRCTL1 : Measurement control
*
* Bits:
*
* 9: Ignore MSRCTL0 config and do immediate measurement on sensor3
* 6: Ignore MSRCTL0 config and do immediate measurement on sensor2
* 5: Ignore MSRCTL0 config and do immediate measurement on sensor1
* 4: Ignore MSRCTL0 config and do immediate measurement on sensor0
*
* That configuration will ignore the filtering and the delays
* introduced in MONCTL1 and MONCTL2
*/
writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base));
} else {
/*
* Bits:
* 9: Single point access flow
* 0-3: Enable sensing point 0-3
*/
writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base));
}
return 0;
}
@ -1138,7 +1221,7 @@ static int lvts_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return dev_err_probe(dev, irq, "No irq resource\n");
return irq;
ret = lvts_domain_init(dev, lvts_td, lvts_data);
if (ret)

View File

@ -23,7 +23,7 @@
#define BIT_APPEND 0x3
struct tsens_legacy_calibration_format tsens_8916_nvmem = {
static struct tsens_legacy_calibration_format tsens_8916_nvmem = {
.base_len = 7,
.base_shift = 3,
.sp_len = 5,
@ -39,7 +39,7 @@ struct tsens_legacy_calibration_format tsens_8916_nvmem = {
},
};
struct tsens_legacy_calibration_format tsens_8974_nvmem = {
static struct tsens_legacy_calibration_format tsens_8974_nvmem = {
.base_len = 8,
.base_shift = 2,
.sp_len = 6,
@ -61,7 +61,7 @@ struct tsens_legacy_calibration_format tsens_8974_nvmem = {
},
};
struct tsens_legacy_calibration_format tsens_8974_backup_nvmem = {
static struct tsens_legacy_calibration_format tsens_8974_backup_nvmem = {
.base_len = 8,
.base_shift = 2,
.sp_len = 6,

View File

@ -21,7 +21,7 @@
#define TM_HIGH_LOW_INT_STATUS_OFF 0x0088
#define TM_HIGH_LOW_Sn_INT_THRESHOLD_OFF 0x0090
struct tsens_legacy_calibration_format tsens_qcs404_nvmem = {
static struct tsens_legacy_calibration_format tsens_qcs404_nvmem = {
.base_len = 8,
.base_shift = 2,
.sp_len = 6,

View File

@ -887,7 +887,7 @@ static int exynos_map_dt_data(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}
data->soc = (enum soc_type)of_device_get_match_data(&pdev->dev);
data->soc = (uintptr_t)of_device_get_match_data(&pdev->dev);
switch (data->soc) {
case SOC_ARCH_EXYNOS4210:

View File

@ -56,8 +56,6 @@
#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
#define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x)
/* millidegree celsius */
struct tsensor {
struct ths_device *tmdev;
struct thermal_zone_device *tzd;
@ -286,7 +284,7 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev)
size_t callen;
int ret = 0;
calcell = devm_nvmem_cell_get(dev, "calibration");
calcell = nvmem_cell_get(dev, "calibration");
if (IS_ERR(calcell)) {
if (PTR_ERR(calcell) == -EPROBE_DEFER)
return -EPROBE_DEFER;
@ -316,6 +314,8 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev)
kfree(caldata);
out:
if (!IS_ERR(calcell))
nvmem_cell_put(calcell);
return ret;
}
@ -489,8 +489,6 @@ static int sun8i_ths_probe(struct platform_device *pdev)
if (!tmdev->chip)
return -EINVAL;
platform_set_drvdata(pdev, tmdev);
ret = sun8i_ths_resource_init(tmdev);
if (ret)
return ret;

View File

@ -167,19 +167,69 @@ static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
return 0;
}
static int tegra_bpmp_thermal_trips_supported(struct tegra_bpmp *bpmp, bool *supported)
{
struct mrq_thermal_host_to_bpmp_request req;
union mrq_thermal_bpmp_to_host_response reply;
struct tegra_bpmp_message msg;
int err;
memset(&req, 0, sizeof(req));
req.type = CMD_THERMAL_QUERY_ABI;
req.query_abi.type = CMD_THERMAL_SET_TRIP;
memset(&msg, 0, sizeof(msg));
msg.mrq = MRQ_THERMAL;
msg.tx.data = &req;
msg.tx.size = sizeof(req);
msg.rx.data = &reply;
msg.rx.size = sizeof(reply);
err = tegra_bpmp_transfer(bpmp, &msg);
if (err)
return err;
if (msg.rx.ret == 0) {
*supported = true;
return 0;
} else if (msg.rx.ret == -BPMP_ENODEV) {
*supported = false;
return 0;
} else {
return -EINVAL;
}
}
static const struct thermal_zone_device_ops tegra_bpmp_of_thermal_ops = {
.get_temp = tegra_bpmp_thermal_get_temp,
.set_trips = tegra_bpmp_thermal_set_trips,
};
static const struct thermal_zone_device_ops tegra_bpmp_of_thermal_ops_notrips = {
.get_temp = tegra_bpmp_thermal_get_temp,
};
static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
{
struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
const struct thermal_zone_device_ops *thermal_ops;
struct tegra_bpmp_thermal *tegra;
struct thermal_zone_device *tzd;
unsigned int i, max_num_zones;
bool supported;
int err;
err = tegra_bpmp_thermal_trips_supported(bpmp, &supported);
if (err) {
dev_err(&pdev->dev, "failed to determine if trip points are supported\n");
return err;
}
if (supported)
thermal_ops = &tegra_bpmp_of_thermal_ops;
else
thermal_ops = &tegra_bpmp_of_thermal_ops_notrips;
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
if (!tegra)
return -ENOMEM;
@ -222,7 +272,7 @@ static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
}
tzd = devm_thermal_of_zone_register(
&pdev->dev, i, zone, &tegra_bpmp_of_thermal_ops);
&pdev->dev, i, zone, thermal_ops);
if (IS_ERR(tzd)) {
if (PTR_ERR(tzd) == -EPROBE_DEFER)
return -EPROBE_DEFER;

View File

@ -142,7 +142,6 @@ static int gadc_thermal_probe(struct platform_device *pdev)
return ret;
gti->dev = &pdev->dev;
platform_set_drvdata(pdev, gti);
gti->tz_dev = devm_thermal_of_zone_register(&pdev->dev, 0, gti,
&gadc_thermal_ops);

View File

@ -1266,7 +1266,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
return ERR_PTR(-EINVAL);
}
if (num_trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp) && !trips)
if (num_trips > 0 && !trips)
return ERR_PTR(-EINVAL);
if (!thermal_class)

View File

@ -70,7 +70,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
void thermal_cdev_update(struct thermal_cooling_device *);
void __thermal_cdev_update(struct thermal_cooling_device *cdev);
int get_tz_trend(struct thermal_zone_device *tz, int trip);
int get_tz_trend(struct thermal_zone_device *tz, int trip_index);
struct thermal_instance *
get_thermal_instance(struct thermal_zone_device *tz,

View File

@ -22,8 +22,9 @@
#include "thermal_core.h"
#include "thermal_trace.h"
int get_tz_trend(struct thermal_zone_device *tz, int trip)
int get_tz_trend(struct thermal_zone_device *tz, int trip_index)
{
struct thermal_trip *trip = tz->trips ? &tz->trips[trip_index] : NULL;
enum thermal_trend trend;
if (tz->emul_temperature || !tz->ops->get_trend ||

View File

@ -101,29 +101,11 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
struct thermal_trip *trip)
{
int ret;
if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip)
if (!tz || !tz->trips || trip_id < 0 || trip_id >= tz->num_trips || !trip)
return -EINVAL;
if (tz->trips) {
*trip = tz->trips[trip_id];
return 0;
}
if (tz->ops->get_trip_hyst) {
ret = tz->ops->get_trip_hyst(tz, trip_id, &trip->hysteresis);
if (ret)
return ret;
} else {
trip->hysteresis = 0;
}
ret = tz->ops->get_trip_temp(tz, trip_id, &trip->temperature);
if (ret)
return ret;
return tz->ops->get_trip_type(tz, trip_id, &trip->type);
*trip = tz->trips[trip_id];
return 0;
}
EXPORT_SYMBOL_GPL(__thermal_zone_get_trip);

View File

@ -314,7 +314,7 @@ int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
*/
static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
{
if (!bgp || IS_ERR(bgp)) {
if (IS_ERR_OR_NULL(bgp)) {
pr_err("%s: invalid bandgap pointer\n", __func__);
return -EINVAL;
}

View File

@ -109,7 +109,8 @@ static inline int __ti_thermal_get_temp(struct thermal_zone_device *tz, int *tem
return ret;
}
static int __ti_thermal_get_trend(struct thermal_zone_device *tz, int trip, enum thermal_trend *trend)
static int __ti_thermal_get_trend(struct thermal_zone_device *tz,
struct thermal_trip *trip, enum thermal_trend *trend)
{
struct ti_thermal_data *data = thermal_zone_device_priv(tz);
struct ti_bandgap *bgp;

View File

@ -53,29 +53,6 @@ enum thermal_notify_event {
THERMAL_EVENT_KEEP_ALIVE, /* Request for user space handler to respond */
};
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*get_temp) (struct thermal_zone_device *, int *);
int (*set_trips) (struct thermal_zone_device *, int, int);
int (*change_mode) (struct thermal_zone_device *,
enum thermal_device_mode);
int (*get_trip_type) (struct thermal_zone_device *, int,
enum thermal_trip_type *);
int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
int (*set_trip_temp) (struct thermal_zone_device *, int, int);
int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
int (*get_crit_temp) (struct thermal_zone_device *, int *);
int (*set_emul_temp) (struct thermal_zone_device *, int);
int (*get_trend) (struct thermal_zone_device *, int,
enum thermal_trend *);
void (*hot)(struct thermal_zone_device *);
void (*critical)(struct thermal_zone_device *);
};
/**
* struct thermal_trip - representation of a point in temperature domain
* @temperature: temperature value in miliCelsius
@ -90,6 +67,25 @@ struct thermal_trip {
void *priv;
};
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*get_temp) (struct thermal_zone_device *, int *);
int (*set_trips) (struct thermal_zone_device *, int, int);
int (*change_mode) (struct thermal_zone_device *,
enum thermal_device_mode);
int (*set_trip_temp) (struct thermal_zone_device *, int, int);
int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
int (*get_crit_temp) (struct thermal_zone_device *, int *);
int (*set_emul_temp) (struct thermal_zone_device *, int);
int (*get_trend) (struct thermal_zone_device *, struct thermal_trip *,
enum thermal_trend *);
void (*hot)(struct thermal_zone_device *);
void (*critical)(struct thermal_zone_device *);
};
struct thermal_cooling_device_ops {
int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);