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

Merge updates of multiple thermal drivers for 6.16 from Daniel Lezcano:

"- Make the Hisilicon driver to compile by default when ARCH_HISI is
   set (Krzysztof Kozlowski)

 - Cleanup printk format with use of %pC instead of %pCn in the bcm2835
   driver (Luca Ceresoli)

 - Fix variable naming coding style in the AmLogic driver (Enrique
   Isidoro Vazquez Ramos)

 - Fix missing debugfs entry removal on failure by using the devm_
   variant in the LVTS driver (AngeloGioacchino Del Regno)

 - Remove the unused lvts_debugfs_exit() function as the devm variant
   introduced before takes care of removing the debugfs entry in the
   LVTS driver (Arnd Bergmann)

 - Add the Airoha EN7581 thermal sensor support along with its DT
   bindings (Christian Marangi)

 - Add ipq5018 compatible string DT binding, cleanup and add its suppot
   in the QCom Tsens driver driver (Sricharan Ramabadhran and George
   Moussalem)

 - Fix comments typos in the Airoha driver (Christian Marangi)"

* tag 'thermal-v6.16-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/thermal/linux:
  thermal/drivers/airoha: Fix spelling mistake
  thermal/drivers/qcom/tsens: Add support for IPQ5018 tsens
  thermal/drivers/qcom/tsens: Add support for tsens v1 without RPM
  thermal/drivers/qcom/tsens: Update conditions to strictly evaluate for IP v2+
  dt-bindings: thermal: qcom-tsens: Add ipq5018 compatible
  thermal/drivers: Add support for Airoha EN7581 thermal sensor
  dt-bindings: thermal: Add support for Airoha EN7581 thermal sensor
  thermal/drivers/mediatek/lvts: Remove unused lvts_debugfs_exit
  thermal/drivers/mediatek/lvts: Fix debugfs unregister on failure
  thermal/drivers/amlogic: Rename Uptat to uptat to follow kernel coding style
  vsprintf: remove redundant and unused %pCn format specifier
  thermal/drivers/bcm2835: Use %pC instead of %pCn
  thermal/drivers/hisi: Do not enable by default during compile testing
This commit is contained in:
Rafael J. Wysocki
2025-05-19 20:58:39 +02:00
14 changed files with 655 additions and 41 deletions

View File

@@ -571,9 +571,8 @@ struct clk
::
%pC pll1
%pCn pll1
For printing struct clk structures. %pC and %pCn print the name of the clock
For printing struct clk structures. %pC prints the name of the clock
(Common Clock Framework) or a unique 32-bit ID (legacy clock framework).
Passed by reference.

View File

@@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/thermal/airoha,en7581-thermal.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha EN7581 Thermal Sensor and Monitor
maintainers:
- Christian Marangi <ansuelsmth@gmail.com>
properties:
compatible:
const: airoha,en7581-thermal
reg:
maxItems: 1
interrupts:
maxItems: 1
airoha,chip-scu:
description: phandle to the chip SCU syscon
$ref: /schemas/types.yaml#/definitions/phandle
'#thermal-sensor-cells':
const: 0
required:
- compatible
- reg
- interrupts
- airoha,chip-scu
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
thermal-sensor@1efbd800 {
compatible = "airoha,en7581-thermal";
reg = <0x1efbd000 0xd5c>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
airoha,chip-scu = <&chip_scu>;
#thermal-sensor-cells = <0>;
};

View File

@@ -39,6 +39,7 @@ properties:
- description: v1 of TSENS
items:
- enum:
- qcom,ipq5018-tsens
- qcom,msm8937-tsens
- qcom,msm8956-tsens
- qcom,msm8976-tsens
@@ -251,6 +252,7 @@ allOf:
compatible:
contains:
enum:
- qcom,ipq5018-tsens
- qcom,ipq8064-tsens
- qcom,msm8960-tsens
- qcom,tsens-v0_1

View File

@@ -523,9 +523,8 @@ clk结构体
::
%pC pll1
%pCn pll1
用于打印clk结构。%pC 和 %pCn 打印时钟的名称通用时钟框架或唯一的32位
用于打印clk结构。%pC 打印时钟的名称通用时钟框架或唯一的32位
ID传统时钟框架
通过引用传递。

View File

@@ -257,7 +257,7 @@ config HISI_THERMAL
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
default y
default ARCH_HISI
help
Enable this to plug hisilicon's thermal sensor driver into the Linux
thermal framework. cpufreq is used as the cooling device to throttle
@@ -327,6 +327,15 @@ config QORIQ_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
config AIROHA_THERMAL
tristate "Airoha thermal sensor driver"
depends on ARCH_AIROHA || COMPILE_TEST
depends on MFD_SYSCON
depends on OF
help
Enable this to plug the Airoha thermal sensor driver into the Linux
thermal framework.
config SPEAR_THERMAL
tristate "SPEAr thermal sensor driver"
depends on PLAT_SPEAR || COMPILE_TEST

View File

@@ -38,6 +38,7 @@ obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o
# platform thermal drivers
obj-y += broadcom/
obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o
obj-$(CONFIG_AIROHA_THERMAL) += airoha_thermal.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o

View File

@@ -0,0 +1,489 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/module.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
/* SCU regs */
#define EN7581_PLLRG_PROTECT 0x268
#define EN7581_PWD_TADC 0x2ec
#define EN7581_MUX_TADC GENMASK(3, 1)
#define EN7581_DOUT_TADC 0x2f8
#define EN7581_DOUT_TADC_MASK GENMASK(15, 0)
/* PTP_THERMAL regs */
#define EN7581_TEMPMONCTL0 0x800
#define EN7581_SENSE3_EN BIT(3)
#define EN7581_SENSE2_EN BIT(2)
#define EN7581_SENSE1_EN BIT(1)
#define EN7581_SENSE0_EN BIT(0)
#define EN7581_TEMPMONCTL1 0x804
/* period unit calculated in BUS clock * 256 scaling-up */
#define EN7581_PERIOD_UNIT GENMASK(9, 0)
#define EN7581_TEMPMONCTL2 0x808
#define EN7581_FILT_INTERVAL GENMASK(25, 16)
#define EN7581_SEN_INTERVAL GENMASK(9, 0)
#define EN7581_TEMPMONINT 0x80C
#define EN7581_STAGE3_INT_EN BIT(31)
#define EN7581_STAGE2_INT_EN BIT(30)
#define EN7581_STAGE1_INT_EN BIT(29)
#define EN7581_FILTER_INT_EN_3 BIT(28)
#define EN7581_IMMD_INT_EN3 BIT(27)
#define EN7581_NOHOTINTEN3 BIT(26)
#define EN7581_HOFSINTEN3 BIT(25)
#define EN7581_LOFSINTEN3 BIT(24)
#define EN7581_HINTEN3 BIT(23)
#define EN7581_CINTEN3 BIT(22)
#define EN7581_FILTER_INT_EN_2 BIT(21)
#define EN7581_FILTER_INT_EN_1 BIT(20)
#define EN7581_FILTER_INT_EN_0 BIT(19)
#define EN7581_IMMD_INT_EN2 BIT(18)
#define EN7581_IMMD_INT_EN1 BIT(17)
#define EN7581_IMMD_INT_EN0 BIT(16)
#define EN7581_TIME_OUT_INT_EN BIT(15)
#define EN7581_NOHOTINTEN2 BIT(14)
#define EN7581_HOFSINTEN2 BIT(13)
#define EN7581_LOFSINTEN2 BIT(12)
#define EN7581_HINTEN2 BIT(11)
#define EN7581_CINTEN2 BIT(10)
#define EN7581_NOHOTINTEN1 BIT(9)
#define EN7581_HOFSINTEN1 BIT(8)
#define EN7581_LOFSINTEN1 BIT(7)
#define EN7581_HINTEN1 BIT(6)
#define EN7581_CINTEN1 BIT(5)
#define EN7581_NOHOTINTEN0 BIT(4)
/* Similar to COLD and HOT also these seems to be swapped in documentation */
#define EN7581_LOFSINTEN0 BIT(3) /* In documentation: BIT(2) */
#define EN7581_HOFSINTEN0 BIT(2) /* In documentation: BIT(3) */
/* It seems documentation have these swapped as the HW
* - Fire BIT(1) when lower than EN7581_COLD_THRE
* - Fire BIT(0) and BIT(5) when higher than EN7581_HOT2NORMAL_THRE or
* EN7581_HOT_THRE
*/
#define EN7581_CINTEN0 BIT(1) /* In documentation: BIT(0) */
#define EN7581_HINTEN0 BIT(0) /* In documentation: BIT(1) */
#define EN7581_TEMPMONINTSTS 0x810
#define EN7581_STAGE3_INT_STAT BIT(31)
#define EN7581_STAGE2_INT_STAT BIT(30)
#define EN7581_STAGE1_INT_STAT BIT(29)
#define EN7581_FILTER_INT_STAT_3 BIT(28)
#define EN7581_IMMD_INT_STS3 BIT(27)
#define EN7581_NOHOTINTSTS3 BIT(26)
#define EN7581_HOFSINTSTS3 BIT(25)
#define EN7581_LOFSINTSTS3 BIT(24)
#define EN7581_HINTSTS3 BIT(23)
#define EN7581_CINTSTS3 BIT(22)
#define EN7581_FILTER_INT_STAT_2 BIT(21)
#define EN7581_FILTER_INT_STAT_1 BIT(20)
#define EN7581_FILTER_INT_STAT_0 BIT(19)
#define EN7581_IMMD_INT_STS2 BIT(18)
#define EN7581_IMMD_INT_STS1 BIT(17)
#define EN7581_IMMD_INT_STS0 BIT(16)
#define EN7581_TIME_OUT_INT_STAT BIT(15)
#define EN7581_NOHOTINTSTS2 BIT(14)
#define EN7581_HOFSINTSTS2 BIT(13)
#define EN7581_LOFSINTSTS2 BIT(12)
#define EN7581_HINTSTS2 BIT(11)
#define EN7581_CINTSTS2 BIT(10)
#define EN7581_NOHOTINTSTS1 BIT(9)
#define EN7581_HOFSINTSTS1 BIT(8)
#define EN7581_LOFSINTSTS1 BIT(7)
#define EN7581_HINTSTS1 BIT(6)
#define EN7581_CINTSTS1 BIT(5)
#define EN7581_NOHOTINTSTS0 BIT(4)
/* Similar to COLD and HOT also these seems to be swapped in documentation */
#define EN7581_LOFSINTSTS0 BIT(3) /* In documentation: BIT(2) */
#define EN7581_HOFSINTSTS0 BIT(2) /* In documentation: BIT(3) */
/* It seems documentation have these swapped as the HW
* - Fire BIT(1) when lower than EN7581_COLD_THRE
* - Fire BIT(0) and BIT(5) when higher than EN7581_HOT2NORMAL_THRE or
* EN7581_HOT_THRE
*
* To clear things, we swap the define but we keep them documented here.
*/
#define EN7581_CINTSTS0 BIT(1) /* In documentation: BIT(0) */
#define EN7581_HINTSTS0 BIT(0) /* In documentation: BIT(1)*/
/* Monitor will take the bigger threshold between HOT2NORMAL and HOT
* and will fire both HOT2NORMAL and HOT interrupt when higher than the 2
*
* It has also been observed that not setting HOT2NORMAL makes the monitor
* treat COLD threshold as HOT2NORMAL.
*/
#define EN7581_TEMPH2NTHRE 0x824
/* It seems HOT2NORMAL is actually NORMAL2HOT */
#define EN7581_HOT2NORMAL_THRE GENMASK(11, 0)
#define EN7581_TEMPHTHRE 0x828
#define EN7581_HOT_THRE GENMASK(11, 0)
/* Monitor will use this as HOT2NORMAL (fire interrupt when lower than...)*/
#define EN7581_TEMPCTHRE 0x82c
#define EN7581_COLD_THRE GENMASK(11, 0)
/* Also LOW and HIGH offset register are swapped */
#define EN7581_TEMPOFFSETL 0x830 /* In documentation: 0x834 */
#define EN7581_LOW_OFFSET GENMASK(11, 0)
#define EN7581_TEMPOFFSETH 0x834 /* In documentation: 0x830 */
#define EN7581_HIGH_OFFSET GENMASK(11, 0)
#define EN7581_TEMPMSRCTL0 0x838
#define EN7581_MSRCTL3 GENMASK(11, 9)
#define EN7581_MSRCTL2 GENMASK(8, 6)
#define EN7581_MSRCTL1 GENMASK(5, 3)
#define EN7581_MSRCTL0 GENMASK(2, 0)
#define EN7581_TEMPADCVALIDADDR 0x878
#define EN7581_ADC_VALID_ADDR GENMASK(31, 0)
#define EN7581_TEMPADCVOLTADDR 0x87c
#define EN7581_ADC_VOLT_ADDR GENMASK(31, 0)
#define EN7581_TEMPRDCTRL 0x880
/*
* NOTICE: AHB have this set to 0 by default. Means that
* the same addr is used for ADC volt and valid reading.
* In such case, VALID ADDR is used and volt addr is ignored.
*/
#define EN7581_RD_CTRL_DIFF BIT(0)
#define EN7581_TEMPADCVALIDMASK 0x884
#define EN7581_ADV_RD_VALID_POLARITY BIT(5)
#define EN7581_ADV_RD_VALID_POS GENMASK(4, 0)
#define EN7581_TEMPADCVOLTAGESHIFT 0x888
#define EN7581_ADC_VOLTAGE_SHIFT GENMASK(4, 0)
/*
* Same values for each CTL.
* Can operate in:
* - 1 sample
* - 2 sample and make average of them
* - 4,6,10,16 sample, drop max and min and make average of them
*/
#define EN7581_MSRCTL_1SAMPLE 0x0
#define EN7581_MSRCTL_AVG2SAMPLE 0x1
#define EN7581_MSRCTL_4SAMPLE_MAX_MIX_AVG2 0x2
#define EN7581_MSRCTL_6SAMPLE_MAX_MIX_AVG4 0x3
#define EN7581_MSRCTL_10SAMPLE_MAX_MIX_AVG8 0x4
#define EN7581_MSRCTL_18SAMPLE_MAX_MIX_AVG16 0x5
#define EN7581_TEMPAHBPOLL 0x840
#define EN7581_ADC_POLL_INTVL GENMASK(31, 0)
/* PTPSPARE0,2 reg are used to store efuse info for calibrated temp offset */
#define EN7581_EFUSE_TEMP_OFFSET_REG 0xf20 /* PTPSPARE0 */
#define EN7581_EFUSE_TEMP_OFFSET GENMASK(31, 16)
#define EN7581_PTPSPARE1 0xf24 /* PTPSPARE1 */
#define EN7581_EFUSE_TEMP_CPU_SENSOR_REG 0xf28 /* PTPSPARE2 */
#define EN7581_SLOPE_X100_DIO_DEFAULT 5645
#define EN7581_SLOPE_X100_DIO_AVS 5645
#define EN7581_INIT_TEMP_CPK_X10 300
#define EN7581_INIT_TEMP_FTK_X10 620
#define EN7581_INIT_TEMP_NONK_X10 550
#define EN7581_SCU_THERMAL_PROTECT_KEY 0x12
#define EN7581_SCU_THERMAL_MUX_DIODE1 0x7
/* Convert temp to raw value as read from ADC ((((temp / 100) - init) * slope) / 1000) + offset */
#define TEMP_TO_RAW(priv, temp) ((((((temp) / 100) - (priv)->init_temp) * \
(priv)->default_slope) / 1000) + \
(priv)->default_offset)
/* Convert raw to temp ((((temp - offset) * 1000) / slope + init) * 100) */
#define RAW_TO_TEMP(priv, raw) (((((raw) - (priv)->default_offset) * 1000) / \
(priv)->default_slope + \
(priv)->init_temp) * 100)
#define AIROHA_MAX_SAMPLES 6
struct airoha_thermal_priv {
void __iomem *base;
struct regmap *chip_scu;
struct resource scu_adc_res;
struct thermal_zone_device *tz;
int init_temp;
int default_slope;
int default_offset;
};
static int airoha_get_thermal_ADC(struct airoha_thermal_priv *priv)
{
u32 val;
regmap_read(priv->chip_scu, EN7581_DOUT_TADC, &val);
return FIELD_GET(EN7581_DOUT_TADC_MASK, val);
}
static void airoha_init_thermal_ADC_mode(struct airoha_thermal_priv *priv)
{
u32 adc_mux, pllrg;
/* Save PLLRG current value */
regmap_read(priv->chip_scu, EN7581_PLLRG_PROTECT, &pllrg);
/* Give access to thermal regs */
regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, EN7581_SCU_THERMAL_PROTECT_KEY);
adc_mux = FIELD_PREP(EN7581_MUX_TADC, EN7581_SCU_THERMAL_MUX_DIODE1);
regmap_write(priv->chip_scu, EN7581_PWD_TADC, adc_mux);
/* Restore PLLRG value on exit */
regmap_write(priv->chip_scu, EN7581_PLLRG_PROTECT, pllrg);
}
static int airoha_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
int min_value, max_value, avg_value, value;
int i;
avg_value = 0;
min_value = INT_MAX;
max_value = INT_MIN;
for (i = 0; i < AIROHA_MAX_SAMPLES; i++) {
value = airoha_get_thermal_ADC(priv);
min_value = min(value, min_value);
max_value = max(value, max_value);
avg_value += value;
}
/* Drop min and max and average for the remaining sample */
avg_value -= (min_value + max_value);
avg_value /= AIROHA_MAX_SAMPLES - 2;
*temp = RAW_TO_TEMP(priv, avg_value);
return 0;
}
static int airoha_thermal_set_trips(struct thermal_zone_device *tz, int low,
int high)
{
struct airoha_thermal_priv *priv = thermal_zone_device_priv(tz);
bool enable_monitor = false;
if (high != INT_MAX) {
/* Validate high and clamp it a supported value */
high = clamp_t(int, high, RAW_TO_TEMP(priv, 0),
RAW_TO_TEMP(priv, FIELD_MAX(EN7581_DOUT_TADC_MASK)));
/* We offset the high temp of 1°C to trigger correct event */
writel(TEMP_TO_RAW(priv, high) >> 4,
priv->base + EN7581_TEMPOFFSETH);
enable_monitor = true;
}
if (low != -INT_MAX) {
/* Validate low and clamp it to a supported value */
low = clamp_t(int, high, RAW_TO_TEMP(priv, 0),
RAW_TO_TEMP(priv, FIELD_MAX(EN7581_DOUT_TADC_MASK)));
/* We offset the low temp of 1°C to trigger correct event */
writel(TEMP_TO_RAW(priv, low) >> 4,
priv->base + EN7581_TEMPOFFSETL);
enable_monitor = true;
}
/* Enable sensor 0 monitor after trip are set */
if (enable_monitor)
writel(EN7581_SENSE0_EN, priv->base + EN7581_TEMPMONCTL0);
return 0;
}
static const struct thermal_zone_device_ops thdev_ops = {
.get_temp = airoha_thermal_get_temp,
.set_trips = airoha_thermal_set_trips,
};
static irqreturn_t airoha_thermal_irq(int irq, void *data)
{
struct airoha_thermal_priv *priv = data;
enum thermal_notify_event event;
bool update = false;
u32 status;
status = readl(priv->base + EN7581_TEMPMONINTSTS);
switch (status & (EN7581_HOFSINTSTS0 | EN7581_LOFSINTSTS0)) {
case EN7581_HOFSINTSTS0:
event = THERMAL_TRIP_VIOLATED;
update = true;
break;
case EN7581_LOFSINTSTS0:
event = THERMAL_EVENT_UNSPECIFIED;
update = true;
break;
default:
/* Should be impossible as we enable only these Interrupt */
break;
}
/* Reset Interrupt */
writel(status, priv->base + EN7581_TEMPMONINTSTS);
if (update)
thermal_zone_device_update(priv->tz, event);
return IRQ_HANDLED;
}
static void airoha_thermal_setup_adc_val(struct device *dev,
struct airoha_thermal_priv *priv)
{
u32 efuse_calib_info, cpu_sensor;
/* Setup thermal sensor to ADC mode and setup the mux to DIODE1 */
airoha_init_thermal_ADC_mode(priv);
/* sleep 10 ms for ADC to enable */
usleep_range(10 * USEC_PER_MSEC, 11 * USEC_PER_MSEC);
efuse_calib_info = readl(priv->base + EN7581_EFUSE_TEMP_OFFSET_REG);
if (efuse_calib_info) {
priv->default_offset = FIELD_GET(EN7581_EFUSE_TEMP_OFFSET, efuse_calib_info);
/* Different slope are applied if the sensor is used for CPU or for package */
cpu_sensor = readl(priv->base + EN7581_EFUSE_TEMP_CPU_SENSOR_REG);
if (cpu_sensor) {
priv->default_slope = EN7581_SLOPE_X100_DIO_DEFAULT;
priv->init_temp = EN7581_INIT_TEMP_FTK_X10;
} else {
priv->default_slope = EN7581_SLOPE_X100_DIO_AVS;
priv->init_temp = EN7581_INIT_TEMP_CPK_X10;
}
} else {
priv->default_offset = airoha_get_thermal_ADC(priv);
priv->default_slope = EN7581_SLOPE_X100_DIO_DEFAULT;
priv->init_temp = EN7581_INIT_TEMP_NONK_X10;
dev_info(dev, "missing thermal calibrarion EFUSE, using non calibrated value\n");
}
}
static void airoha_thermal_setup_monitor(struct airoha_thermal_priv *priv)
{
/* Set measure mode */
writel(FIELD_PREP(EN7581_MSRCTL0, EN7581_MSRCTL_6SAMPLE_MAX_MIX_AVG4),
priv->base + EN7581_TEMPMSRCTL0);
/*
* Configure ADC valid reading addr
* The AHB temp monitor system doesn't have direct access to the
* thermal sensor. It does instead work by providing various
* addresses to configure how to access and setup an ADC for the
* sensor. EN7581 supports only one sensor hence the
* implementation is greatly simplified but the AHB supports
* up to 4 different sensors from the same ADC that can be
* switched by tuning the ADC mux or writing address.
*
* We set valid instead of volt as we don't enable valid/volt
* split reading and AHB read valid addr in such case.
*/
writel(priv->scu_adc_res.start + EN7581_DOUT_TADC,
priv->base + EN7581_TEMPADCVALIDADDR);
/*
* Configure valid bit on a fake value of bit 16. The ADC outputs
* max of 2 bytes for voltage.
*/
writel(FIELD_PREP(EN7581_ADV_RD_VALID_POS, 16),
priv->base + EN7581_TEMPADCVALIDMASK);
/*
* AHB supports max 12 bytes for ADC voltage. Shift the read
* value 4 bit to the right. Precision lost by this is minimal
* in the order of half a °C and is acceptable in the context
* of triggering interrupt in critical condition.
*/
writel(FIELD_PREP(EN7581_ADC_VOLTAGE_SHIFT, 4),
priv->base + EN7581_TEMPADCVOLTAGESHIFT);
/* BUS clock is 300MHz counting unit is 3 * 68.64 * 256 = 52.715us */
writel(FIELD_PREP(EN7581_PERIOD_UNIT, 3),
priv->base + EN7581_TEMPMONCTL1);
/*
* filt interval is 1 * 52.715us = 52.715us,
* sen interval is 379 * 52.715us = 19.97ms
*/
writel(FIELD_PREP(EN7581_FILT_INTERVAL, 1) |
FIELD_PREP(EN7581_FILT_INTERVAL, 379),
priv->base + EN7581_TEMPMONCTL2);
/* AHB poll is set to 146 * 68.64 = 10.02us */
writel(FIELD_PREP(EN7581_ADC_POLL_INTVL, 146),
priv->base + EN7581_TEMPAHBPOLL);
}
static int airoha_thermal_probe(struct platform_device *pdev)
{
struct airoha_thermal_priv *priv;
struct device_node *chip_scu_np;
struct device *dev = &pdev->dev;
int irq, ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
chip_scu_np = of_parse_phandle(dev->of_node, "airoha,chip-scu", 0);
if (!chip_scu_np)
return -EINVAL;
priv->chip_scu = syscon_node_to_regmap(chip_scu_np);
if (IS_ERR(priv->chip_scu))
return PTR_ERR(priv->chip_scu);
of_address_to_resource(chip_scu_np, 0, &priv->scu_adc_res);
of_node_put(chip_scu_np);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
airoha_thermal_irq, IRQF_ONESHOT,
pdev->name, priv);
if (ret) {
dev_err(dev, "Can't get interrupt working.\n");
return ret;
}
airoha_thermal_setup_monitor(priv);
airoha_thermal_setup_adc_val(dev, priv);
/* register of thermal sensor and get info from DT */
priv->tz = devm_thermal_of_zone_register(dev, 0, priv, &thdev_ops);
if (IS_ERR(priv->tz)) {
dev_err(dev, "register thermal zone sensor failed\n");
return PTR_ERR(priv->tz);
}
platform_set_drvdata(pdev, priv);
/* Enable LOW and HIGH interrupt */
writel(EN7581_HOFSINTEN0 | EN7581_LOFSINTEN0,
priv->base + EN7581_TEMPMONINT);
return 0;
}
static const struct of_device_id airoha_thermal_match[] = {
{ .compatible = "airoha,en7581-thermal" },
{},
};
MODULE_DEVICE_TABLE(of, airoha_thermal_match);
static struct platform_driver airoha_thermal_driver = {
.driver = {
.name = "airoha-thermal",
.of_match_table = airoha_thermal_match,
},
.probe = airoha_thermal_probe,
};
module_platform_driver(airoha_thermal_driver);
MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
MODULE_DESCRIPTION("Airoha thermal driver");
MODULE_LICENSE("GPL");

View File

@@ -7,10 +7,10 @@
*
* Register value to celsius temperature formulas:
* Read_Val m * U
* U = ---------, Uptat = ---------
* U = ---------, uptat = ---------
* 2^16 1 + n * U
*
* Temperature = A * ( Uptat + u_efuse / 2^16 )- B
* Temperature = A * ( uptat + u_efuse / 2^16 )- B
*
* A B m n : calibration parameters
* u_efuse : fused calibration value, it's a signed 16 bits value
@@ -112,7 +112,7 @@ static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
const struct amlogic_thermal_soc_calib_data *param =
pdata->data->calibration_parameters;
int temp;
s64 factor, Uptat, uefuse;
s64 factor, uptat, uefuse;
uefuse = pdata->trim_info & TSENSOR_TRIM_SIGN_MASK ?
~(pdata->trim_info & TSENSOR_TRIM_TEMP_MASK) + 1 :
@@ -121,12 +121,12 @@ static int amlogic_thermal_code_to_millicelsius(struct amlogic_thermal *pdata,
factor = param->n * temp_code;
factor = div_s64(factor, 100);
Uptat = temp_code * param->m;
Uptat = div_s64(Uptat, 100);
Uptat = Uptat * BIT(16);
Uptat = div_s64(Uptat, BIT(16) + factor);
uptat = temp_code * param->m;
uptat = div_s64(uptat, 100);
uptat = uptat * BIT(16);
uptat = div_s64(uptat, BIT(16) + factor);
temp = (Uptat + uefuse) * param->A;
temp = (uptat + uefuse) * param->A;
temp = div_s64(temp, BIT(16));
temp = (temp - param->B) * 100;

View File

@@ -192,7 +192,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
rate = clk_get_rate(data->clk);
if ((rate < 1920000) || (rate > 5000000))
dev_warn(dev,
"Clock %pCn running at %lu Hz is outside of the recommended range: 1.92 to 5MHz\n",
"Clock %pC running at %lu Hz is outside of the recommended range: 1.92 to 5MHz\n",
data->clk, rate);
/* register of thermal sensor and get info from DT */

View File

@@ -213,6 +213,13 @@ static const struct debugfs_reg32 lvts_regs[] = {
LVTS_DEBUG_FS_REGS(LVTS_CLKEN),
};
static void lvts_debugfs_exit(void *data)
{
struct lvts_domain *lvts_td = data;
debugfs_remove_recursive(lvts_td->dom_dentry);
}
static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
{
struct debugfs_regset32 *regset;
@@ -245,12 +252,7 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
debugfs_create_regset32("registers", 0400, dentry, regset);
}
return 0;
}
static void lvts_debugfs_exit(struct lvts_domain *lvts_td)
{
debugfs_remove_recursive(lvts_td->dom_dentry);
return devm_add_action_or_reset(dev, lvts_debugfs_exit, lvts_td);
}
#else
@@ -261,8 +263,6 @@ static inline int lvts_debugfs_init(struct device *dev,
return 0;
}
static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { }
#endif
static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
@@ -1374,8 +1374,6 @@ static void lvts_remove(struct platform_device *pdev)
for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
lvts_debugfs_exit(lvts_td);
}
static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {

View File

@@ -79,6 +79,17 @@ static struct tsens_features tsens_v1_feat = {
.trip_max_temp = 120000,
};
static struct tsens_features tsens_v1_no_rpm_feat = {
.ver_major = VER_1_X_NO_RPM,
.crit_int = 0,
.combo_int = 0,
.adc = 1,
.srot_split = 1,
.max_sensors = 11,
.trip_min_temp = -40000,
.trip_max_temp = 120000,
};
static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
/* ----- SROT ------ */
/* VERSION */
@@ -150,6 +161,43 @@ static int __init init_8956(struct tsens_priv *priv) {
return init_common(priv);
}
static int __init init_tsens_v1_no_rpm(struct tsens_priv *priv)
{
int i, ret;
u32 mask = 0;
ret = init_common(priv);
if (ret < 0) {
dev_err(priv->dev, "Init common failed %d\n", ret);
return ret;
}
ret = regmap_field_write(priv->rf[TSENS_SW_RST], 1);
if (ret) {
dev_err(priv->dev, "Reset failed\n");
return ret;
}
for (i = 0; i < priv->num_sensors; i++)
mask |= BIT(priv->sensor[i].hw_id);
ret = regmap_field_update_bits(priv->rf[SENSOR_EN], mask, mask);
if (ret) {
dev_err(priv->dev, "Sensor Enable failed\n");
return ret;
}
ret = regmap_field_write(priv->rf[TSENS_EN], 1);
if (ret) {
dev_err(priv->dev, "Enable failed\n");
return ret;
}
ret = regmap_field_write(priv->rf[TSENS_SW_RST], 0);
return ret;
}
static const struct tsens_ops ops_generic_v1 = {
.init = init_common,
.calibrate = calibrate_v1,
@@ -194,3 +242,17 @@ struct tsens_plat_data data_8976 = {
.feat = &tsens_v1_feat,
.fields = tsens_v1_regfields,
};
const struct tsens_ops ops_ipq5018 = {
.init = init_tsens_v1_no_rpm,
.calibrate = tsens_calibrate_common,
.get_temp = get_temp_tsens_valid,
};
const struct tsens_plat_data data_ipq5018 = {
.num_sensors = 5,
.ops = &ops_ipq5018,
.hw_ids = (unsigned int []){0, 1, 2, 3, 4},
.feat = &tsens_v1_no_rpm_feat,
.fields = tsens_v1_regfields,
};

View File

@@ -447,7 +447,7 @@ static void tsens_set_interrupt(struct tsens_priv *priv, u32 hw_id,
dev_dbg(priv->dev, "[%u] %s: %s -> %s\n", hw_id, __func__,
irq_type ? ((irq_type == 1) ? "UP" : "CRITICAL") : "LOW",
enable ? "en" : "dis");
if (tsens_version(priv) > VER_1_X)
if (tsens_version(priv) >= VER_2_X)
tsens_set_interrupt_v2(priv, hw_id, irq_type, enable);
else
tsens_set_interrupt_v1(priv, hw_id, irq_type, enable);
@@ -499,7 +499,7 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
ret = regmap_field_read(priv->rf[LOW_INT_CLEAR_0 + hw_id], &d->low_irq_clear);
if (ret)
return ret;
if (tsens_version(priv) > VER_1_X) {
if (tsens_version(priv) >= VER_2_X) {
ret = regmap_field_read(priv->rf[UP_INT_MASK_0 + hw_id], &d->up_irq_mask);
if (ret)
return ret;
@@ -543,7 +543,7 @@ static int tsens_read_irq_state(struct tsens_priv *priv, u32 hw_id,
static inline u32 masked_irq(u32 hw_id, u32 mask, enum tsens_ver ver)
{
if (ver > VER_1_X)
if (ver >= VER_2_X)
return mask & (1 << hw_id);
/* v1, v0.1 don't have a irq mask register */
@@ -733,7 +733,7 @@ static int tsens_set_trips(struct thermal_zone_device *tz, int low, int high)
static int tsens_enable_irq(struct tsens_priv *priv)
{
int ret;
int val = tsens_version(priv) > VER_1_X ? 7 : 1;
int val = tsens_version(priv) >= VER_2_X ? 7 : 1;
ret = regmap_field_write(priv->rf[INT_EN], val);
if (ret < 0)
@@ -975,10 +975,16 @@ int __init init_common(struct tsens_priv *priv)
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
if (ret)
goto err_put_device;
if (!enabled && (tsens_version(priv) != VER_2_X_NO_RPM)) {
dev_err(dev, "%s: device not enabled\n", __func__);
ret = -ENODEV;
goto err_put_device;
if (!enabled) {
switch (tsens_version(priv)) {
case VER_1_X_NO_RPM:
case VER_2_X_NO_RPM:
break;
default:
dev_err(dev, "%s: device not enabled\n", __func__);
ret = -ENODEV;
goto err_put_device;
}
}
priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
@@ -1040,7 +1046,7 @@ int __init init_common(struct tsens_priv *priv)
}
}
if (tsens_version(priv) > VER_1_X && ver_minor > 2) {
if (tsens_version(priv) >= VER_2_X && ver_minor > 2) {
/* Watchdog is present only on v2.3+ */
priv->feat->has_watchdog = 1;
for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) {
@@ -1102,6 +1108,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
static const struct of_device_id tsens_table[] = {
{
.compatible = "qcom,ipq5018-tsens",
.data = &data_ipq5018,
}, {
.compatible = "qcom,ipq5332-tsens",
.data = &data_ipq5332,
}, {

View File

@@ -34,6 +34,7 @@ enum tsens_ver {
VER_0 = 0,
VER_0_1,
VER_1_X,
VER_1_X_NO_RPM,
VER_2_X,
VER_2_X_NO_RPM,
};
@@ -651,6 +652,9 @@ extern struct tsens_plat_data data_8226, data_8909, data_8916, data_8939, data_8
/* TSENS v1 targets */
extern struct tsens_plat_data data_tsens_v1, data_8937, data_8976, data_8956;
/* TSENS v1 with no RPM targets */
extern const struct tsens_plat_data data_ipq5018;
/* TSENS v2 targets */
extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2;
extern const struct tsens_plat_data data_ipq5332, data_ipq5424;

View File

@@ -1981,15 +1981,11 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
if (check_pointer(&buf, end, clk, spec))
return buf;
switch (fmt[1]) {
case 'n':
default:
#ifdef CONFIG_COMMON_CLK
return string(buf, end, __clk_get_name(clk), spec);
return string(buf, end, __clk_get_name(clk), spec);
#else
return ptr_to_id(buf, end, clk, spec);
return ptr_to_id(buf, end, clk, spec);
#endif
}
}
static
@@ -2391,8 +2387,6 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
* T time64_t
* - 'C' For a clock, it prints the name (Common Clock Framework) or address
* (legacy clock framework) of the clock
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
* (legacy clock framework) of the clock
* - 'G' For flags to be printed as a collection of symbolic strings that would
* construct the specific value. Supported flags given by option:
* p page flags (see struct page) given as pointer to unsigned long