mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
Thermal control updates for 6.17-rc1
- Convert EAGAIN into ENODATA in temp_show() to prevent user space from
polling the sysfs file in vain after a failing O_NONBLOCK read under
the assumption that the read would have blocked (Hsin-Te Yuan)
- Add Wildcat Lake PCI ID to the int340x Intel processor thermal driver
(Srinivas Pandruvada)
- Add debugfs interface to override the temperature set by the firmware
in the Intel platform temperature control (PTC) interface and add a
new sysfs control attribute called thermal_tolerance to it (Srinivas
Pandruvada)
- Enable the stage 2 shutdown in the qcom-spmi-temp-alarm thermal
driver and add support for more SPMI variants to it (Anjelique
Melendez)
- Constify the thermal_zone_device_ops structure where possible in
several assorted thermal drivers (Christophe Jaillet)
- Use the dev_fwnode() helper instead of of_fwnode_handle(), as it is
more adequate, wherever possible in thermal drivers (Jiri Slaby)
- Implement and document One-Time Programmable fuse support in the
Rockchip thermal driver in order to increase the precision of the
measurements (Nicolas Frattaroli)
- Change the way the Mediatek LTVS thermal driver stores the
initialization data sequence to support different sequences
matching different platforms. Introduce mt7988 support with
a new initialization sequence (Mason Chang)
- Document the QCom TSens Milos Temperature Sensor DT bindings (Luca
Weiss)
- Add the fallback compatible string for MT7981 and MT8516 DT bindings
(Aleksander Jan Bajkowski)
- Add the compatible string for the Tegra210B01 SOC_THERM driver (Aaron
Kling)
-----BEGIN PGP SIGNATURE-----
iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmh/j4ESHHJqd0Byand5
c29ja2kubmV0AAoJEO5fvZ0v1OO1r54IAImMVSzbSfMvvB0b1PDa2nEbBVt8xNEg
2BPwZv1CrdJXq95VJQDJQRmsdZVzzNIL0gRruyaXnSDa4zhyoNb3nXhjY7eNqhlP
2CBANscs7zgQ3DiAFuz3VJ7ns10KCAAEj2r3gdTxkm0MveOrDhOn3bLdr9+NN7P8
n0zo9p4W2RDXXXjTMJul0qliZpJoadDqN+fl2V/u7vPLcjlp1JBV84sZPKt8mGIe
o44Sp9NSjZ20GDpOPzXKJnK9RRQsxxs40x4d3C3kpmiagzMjyV3ku1K2e0FAucUv
Y0V91HiHCgdNSLa/Z4laIdFJc6Wa8tsEb7mItg96cPFmSCaFvcZPucM=
=ysPD
-----END PGP SIGNATURE-----
Merge tag 'thermal-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull thermal control updates from Rafael Wysocki:
"These update the thermal control sysfs interface and multiple thermal
control drivers:
- Convert EAGAIN into ENODATA in temp_show() to prevent user space
from polling the sysfs file in vain after a failing O_NONBLOCK read
under the assumption that the read would have blocked (Hsin-Te
Yuan)
- Add Wildcat Lake PCI ID to the int340x Intel processor thermal
driver (Srinivas Pandruvada)
- Add debugfs interface to override the temperature set by the
firmware in the Intel platform temperature control (PTC) interface
and add a new sysfs control attribute called thermal_tolerance to
it (Srinivas Pandruvada)
- Enable the stage 2 shutdown in the qcom-spmi-temp-alarm thermal
driver and add support for more SPMI variants to it (Anjelique
Melendez)
- Constify the thermal_zone_device_ops structure where possible in
several assorted thermal drivers (Christophe Jaillet)
- Use the dev_fwnode() helper instead of of_fwnode_handle(), as it is
more adequate, wherever possible in thermal drivers (Jiri Slaby)
- Implement and document One-Time Programmable fuse support in the
Rockchip thermal driver in order to increase the precision of the
measurements (Nicolas Frattaroli)
- Change the way the Mediatek LTVS thermal driver stores the
initialization data sequence to support different sequences
matching different platforms. Introduce mt7988 support with a new
initialization sequence (Mason Chang)
- Document the QCom TSens Milos Temperature Sensor DT bindings (Luca
Weiss)
- Add the fallback compatible string for MT7981 and MT8516 DT
bindings (Aleksander Jan Bajkowski)
- Add the compatible string for the Tegra210B01 SOC_THERM driver
(Aaron Kling)"
* tag 'thermal-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (23 commits)
dt-bindings: thermal: tegra: Document Tegra210B01
dt-bindings: thermal: mediatek: Add fallback compatible string for MT7981 and MT8516
dt-bindings: thermal: qcom-tsens: document the Milos Temperature Sensor
thermal/drivers/mediatek/lvts_thermal: Add mt7988 lvts commands
thermal/drivers/mediatek/lvts_thermal: Add lvts commands and their sizes to driver data
thermal/drivers/mediatek/lvts_thermal: Change lvts commands array to static const
thermal/drivers/rockchip: Support reading trim values from OTP
dt-bindings: thermal: rockchip: document otp thermal trim
thermal/drivers/rockchip: Support RK3576 SoC in the thermal driver
dt-bindings: rockchip-thermal: Add RK3576 compatible
thermal/drivers/rockchip: Rename rk_tsadcv3_tshut_mode
thermal: Use dev_fwnode()
thermal: Constify struct thermal_zone_device_ops
thermal/drivers/loongson2: Constify struct thermal_zone_device_ops
thermal/drivers/qcom-spmi-temp-alarm: Add support for LITE PMIC peripherals
thermal/drivers/qcom-spmi-temp-alarm: Add support for GEN2 rev 2 PMIC peripherals
thermal/drivers/qcom-spmi-temp-alarm: Prepare to support additional Temp Alarm subtypes
thermal/drivers/qcom-spmi-temp-alarm: Add temp alarm data struct based on HW subtype
thermal/drivers/qcom-spmi-temp-alarm: Enable stage 2 shutdown when required
thermal: sysfs: Return ENODATA instead of EAGAIN for reads
...
This commit is contained in:
commit
e30fc09082
|
|
@ -20,16 +20,23 @@ allOf:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-thermal
|
||||
- mediatek,mt2712-thermal
|
||||
- mediatek,mt7622-thermal
|
||||
- mediatek,mt7981-thermal
|
||||
- mediatek,mt7986-thermal
|
||||
- mediatek,mt8173-thermal
|
||||
- mediatek,mt8183-thermal
|
||||
- mediatek,mt8365-thermal
|
||||
- mediatek,mt8516-thermal
|
||||
oneOf:
|
||||
- enum:
|
||||
- mediatek,mt2701-thermal
|
||||
- mediatek,mt2712-thermal
|
||||
- mediatek,mt7622-thermal
|
||||
- mediatek,mt7986-thermal
|
||||
- mediatek,mt8173-thermal
|
||||
- mediatek,mt8183-thermal
|
||||
- mediatek,mt8365-thermal
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8516-thermal
|
||||
- const: mediatek,mt2701-thermal
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt7981-thermal
|
||||
- const: mediatek,mt7986-thermal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- nvidia,tegra124-soctherm
|
||||
- nvidia,tegra132-soctherm
|
||||
- nvidia,tegra210-soctherm
|
||||
- nvidia,tegra210b01-soctherm
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
|
@ -207,6 +208,7 @@ allOf:
|
|||
enum:
|
||||
- nvidia,tegra124-soctherm
|
||||
- nvidia,tegra210-soctherm
|
||||
- nvidia,tegra210b01-soctherm
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ properties:
|
|||
- description: v2 of TSENS
|
||||
items:
|
||||
- enum:
|
||||
- qcom,milos-tsens
|
||||
- qcom,msm8953-tsens
|
||||
- qcom,msm8996-tsens
|
||||
- qcom,msm8998-tsens
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- rockchip,rk3368-tsadc
|
||||
- rockchip,rk3399-tsadc
|
||||
- rockchip,rk3568-tsadc
|
||||
- rockchip,rk3576-tsadc
|
||||
- rockchip,rk3588-tsadc
|
||||
- rockchip,rv1108-tsadc
|
||||
|
||||
|
|
@ -39,6 +40,17 @@ properties:
|
|||
- const: tsadc
|
||||
- const: apb_pclk
|
||||
|
||||
nvmem-cells:
|
||||
items:
|
||||
- description: cell handle to where the trim's base temperature is stored
|
||||
- description:
|
||||
cell handle to where the trim's tenths of Celsius base value is stored
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: trim_base
|
||||
- const: trim_base_frac
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
|
@ -50,6 +62,12 @@ properties:
|
|||
- const: tsadc
|
||||
- const: tsadc-phy
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 1
|
||||
|
||||
|
|
@ -71,6 +89,27 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$":
|
||||
type: object
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: sensor ID, a.k.a. channel number
|
||||
|
||||
nvmem-cells:
|
||||
items:
|
||||
- description: handle of cell containing calibration data
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: trim
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
@ -79,6 +118,29 @@ required:
|
|||
- clock-names
|
||||
- resets
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: rockchip,rk3568-tsadc
|
||||
then:
|
||||
properties:
|
||||
nvmem-cells: false
|
||||
nvmem-cell-names: false
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- rockchip,rk3568-tsadc
|
||||
- rockchip,rk3576-tsadc
|
||||
then:
|
||||
patternProperties:
|
||||
"@[0-9a-f]+$": false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -206,6 +206,15 @@ All these controls needs admin privilege to update.
|
|||
Update a new temperature target in milli degree celsius for hardware to
|
||||
use for the temperature control.
|
||||
|
||||
``thermal_tolerance`` (RW)
|
||||
This attribute ranges from 0 to 7, where 0 represents
|
||||
the most aggressive control to avoid any temperature overshoots, and
|
||||
7 represents a more graceful approach, favoring performance even at
|
||||
the expense of temperature overshoots.
|
||||
Note: This level may not scale linearly. For example, a value of 3 does
|
||||
not necessarily imply a 50% improvement in performance compared to a
|
||||
value of 0.
|
||||
|
||||
Given that this is platform temperature control, it is expected that a
|
||||
single user-level manager owns and manages the controls. If multiple
|
||||
user-level software applications attempt to write different targets, it
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ static int armada_get_temp_legacy(struct thermal_zone_device *thermal,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops legacy_ops = {
|
||||
static const struct thermal_zone_device_ops legacy_ops = {
|
||||
.get_temp = armada_get_temp_legacy,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops da9062_thermal_ops = {
|
||||
static const struct thermal_zone_device_ops da9062_thermal_ops = {
|
||||
.get_temp = da9062_thermal_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static int dove_get_temp(struct thermal_zone_device *thermal,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops ops = {
|
||||
static const struct thermal_zone_device_ops ops = {
|
||||
.get_temp = dove_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ static bool imx_should_bind(struct thermal_zone_device *tz,
|
|||
return trip->type == THERMAL_TRIP_PASSIVE;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops imx_tz_ops = {
|
||||
static const struct thermal_zone_device_ops imx_tz_ops = {
|
||||
.should_bind = imx_should_bind,
|
||||
.get_temp = imx_get_temp,
|
||||
.change_mode = imx_change_mode,
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
|
|||
return result;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops int3400_thermal_ops = {
|
||||
static const struct thermal_zone_device_ops int3400_thermal_ops = {
|
||||
.get_temp = int3400_thermal_get_temp,
|
||||
.change_mode = int3400_thermal_change_mode,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pci.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
|
|
@ -49,14 +50,16 @@ struct mmio_reg {
|
|||
};
|
||||
|
||||
#define MAX_ATTR_GROUP_NAME_LEN 32
|
||||
#define PTC_MAX_ATTRS 3
|
||||
#define PTC_MAX_ATTRS 4
|
||||
|
||||
struct ptc_data {
|
||||
u32 offset;
|
||||
struct pci_dev *pdev;
|
||||
struct attribute_group ptc_attr_group;
|
||||
struct attribute *ptc_attrs[PTC_MAX_ATTRS];
|
||||
struct device_attribute temperature_target_attr;
|
||||
struct device_attribute enable_attr;
|
||||
struct device_attribute thermal_tolerance_attr;
|
||||
char group_name[MAX_ATTR_GROUP_NAME_LEN];
|
||||
};
|
||||
|
||||
|
|
@ -78,6 +81,7 @@ static u32 ptc_offsets[PTC_MAX_INSTANCES] = {0x5B20, 0x5B28, 0x5B30};
|
|||
static const char * const ptc_strings[] = {
|
||||
"temperature_target",
|
||||
"enable",
|
||||
"thermal_tolerance",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -177,6 +181,8 @@ PTC_SHOW(temperature_target);
|
|||
PTC_STORE(temperature_target);
|
||||
PTC_SHOW(enable);
|
||||
PTC_STORE(enable);
|
||||
PTC_SHOW(thermal_tolerance);
|
||||
PTC_STORE(thermal_tolerance);
|
||||
|
||||
#define ptc_init_attribute(_name)\
|
||||
do {\
|
||||
|
|
@ -193,9 +199,11 @@ static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data
|
|||
|
||||
ptc_init_attribute(temperature_target);
|
||||
ptc_init_attribute(enable);
|
||||
ptc_init_attribute(thermal_tolerance);
|
||||
|
||||
data->ptc_attrs[index++] = &data->temperature_target_attr.attr;
|
||||
data->ptc_attrs[index++] = &data->enable_attr.attr;
|
||||
data->ptc_attrs[index++] = &data->thermal_tolerance_attr.attr;
|
||||
data->ptc_attrs[index] = NULL;
|
||||
|
||||
snprintf(data->group_name, MAX_ATTR_GROUP_NAME_LEN,
|
||||
|
|
@ -209,6 +217,63 @@ static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data
|
|||
}
|
||||
|
||||
static struct ptc_data ptc_instance[PTC_MAX_INSTANCES];
|
||||
static struct dentry *ptc_debugfs;
|
||||
|
||||
#define PTC_TEMP_OVERRIDE_ENABLE_INDEX 4
|
||||
#define PTC_TEMP_OVERRIDE_INDEX 5
|
||||
|
||||
static ssize_t ptc_temperature_write(struct file *file, const char __user *data,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ptc_data *ptc_instance = file->private_data;
|
||||
struct pci_dev *pdev = ptc_instance->pdev;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
u32 value;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, data, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (kstrtouint(buf, 0, &value))
|
||||
return -EINVAL;
|
||||
|
||||
if (ptc_mmio_regs[PTC_TEMP_OVERRIDE_INDEX].units)
|
||||
value /= ptc_mmio_regs[PTC_TEMP_OVERRIDE_INDEX].units;
|
||||
|
||||
if (value > ptc_mmio_regs[PTC_TEMP_OVERRIDE_INDEX].mask)
|
||||
return -EINVAL;
|
||||
|
||||
if (!value) {
|
||||
ptc_mmio_write(pdev, ptc_instance->offset, PTC_TEMP_OVERRIDE_ENABLE_INDEX, 0);
|
||||
} else {
|
||||
ptc_mmio_write(pdev, ptc_instance->offset, PTC_TEMP_OVERRIDE_INDEX, value);
|
||||
ptc_mmio_write(pdev, ptc_instance->offset, PTC_TEMP_OVERRIDE_ENABLE_INDEX, 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ptc_fops = {
|
||||
.open = simple_open,
|
||||
.write = ptc_temperature_write,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static void ptc_create_debugfs(void)
|
||||
{
|
||||
ptc_debugfs = debugfs_create_dir("platform_temperature_control", NULL);
|
||||
|
||||
debugfs_create_file("temperature_0", 0200, ptc_debugfs, &ptc_instance[0], &ptc_fops);
|
||||
debugfs_create_file("temperature_1", 0200, ptc_debugfs, &ptc_instance[1], &ptc_fops);
|
||||
debugfs_create_file("temperature_2", 0200, ptc_debugfs, &ptc_instance[2], &ptc_fops);
|
||||
}
|
||||
|
||||
static void ptc_delete_debugfs(void)
|
||||
{
|
||||
debugfs_remove_recursive(ptc_debugfs);
|
||||
}
|
||||
|
||||
int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
|
|
@ -217,8 +282,11 @@ int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_
|
|||
|
||||
for (i = 0; i < PTC_MAX_INSTANCES; i++) {
|
||||
ptc_instance[i].offset = ptc_offsets[i];
|
||||
ptc_instance[i].pdev = pdev;
|
||||
ptc_create_groups(pdev, i, &ptc_instance[i]);
|
||||
}
|
||||
|
||||
ptc_create_debugfs();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -234,6 +302,8 @@ void proc_thermal_ptc_remove(struct pci_dev *pdev)
|
|||
|
||||
for (i = 0; i < PTC_MAX_INSTANCES; i++)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &ptc_instance[i].ptc_attr_group);
|
||||
|
||||
ptc_delete_debugfs();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_ptc_remove);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#define PCI_DEVICE_ID_INTEL_SKL_THERMAL 0x1903
|
||||
#define PCI_DEVICE_ID_INTEL_TGL_THERMAL 0x9A03
|
||||
#define PCI_DEVICE_ID_INTEL_PTL_THERMAL 0xB01D
|
||||
#define PCI_DEVICE_ID_INTEL_WCL_THERMAL 0xFD1D
|
||||
|
||||
struct power_config {
|
||||
u32 index;
|
||||
|
|
|
|||
|
|
@ -499,6 +499,10 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
|
|||
PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_DVFS |
|
||||
PROC_THERMAL_FEATURE_MSI_SUPPORT | PROC_THERMAL_FEATURE_WT_HINT |
|
||||
PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) },
|
||||
{ PCI_DEVICE_DATA(INTEL, WCL_THERMAL, PROC_THERMAL_FEATURE_MSI_SUPPORT |
|
||||
PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_DLVR |
|
||||
PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_HINT |
|
||||
PROC_THERMAL_FEATURE_POWER_FLOOR | PROC_THERMAL_FEATURE_PTC) },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -442,6 +442,7 @@ int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc
|
|||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_LNLM_THERMAL:
|
||||
case PCI_DEVICE_ID_INTEL_PTL_THERMAL:
|
||||
case PCI_DEVICE_ID_INTEL_WCL_THERMAL:
|
||||
dlvr_mmio_regs_table = lnl_dlvr_mmio_regs;
|
||||
dlvr_mapping = lnl_dlvr_mapping;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static int kirkwood_get_temp(struct thermal_zone_device *thermal,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops ops = {
|
||||
static const struct thermal_zone_device_ops ops = {
|
||||
.get_temp = kirkwood_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -112,13 +112,19 @@ static int loongson2_thermal_set_trips(struct thermal_zone_device *tz, int low,
|
|||
return loongson2_thermal_set(data, low/MILLI, high/MILLI, true);
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops loongson2_of_thermal_ops = {
|
||||
static const struct thermal_zone_device_ops loongson2_2k1000_of_thermal_ops = {
|
||||
.get_temp = loongson2_2k1000_get_temp,
|
||||
.set_trips = loongson2_thermal_set_trips,
|
||||
};
|
||||
|
||||
static const struct thermal_zone_device_ops loongson2_2k2000_of_thermal_ops = {
|
||||
.get_temp = loongson2_2k2000_get_temp,
|
||||
.set_trips = loongson2_thermal_set_trips,
|
||||
};
|
||||
|
||||
static int loongson2_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct thermal_zone_device_ops *thermal_ops;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct loongson2_thermal_data *data;
|
||||
struct thermal_zone_device *tzd;
|
||||
|
|
@ -140,7 +146,9 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(data->temp_reg))
|
||||
return PTR_ERR(data->temp_reg);
|
||||
|
||||
loongson2_of_thermal_ops.get_temp = loongson2_2k2000_get_temp;
|
||||
thermal_ops = &loongson2_2k2000_of_thermal_ops;
|
||||
} else {
|
||||
thermal_ops = &loongson2_2k1000_of_thermal_ops;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
|
@ -152,8 +160,7 @@ static int loongson2_thermal_probe(struct platform_device *pdev)
|
|||
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);
|
||||
tzd = devm_thermal_of_zone_register(dev, i, data, thermal_ops);
|
||||
|
||||
if (!IS_ERR(tzd))
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -125,7 +125,11 @@ struct lvts_ctrl_data {
|
|||
|
||||
struct lvts_data {
|
||||
const struct lvts_ctrl_data *lvts_ctrl;
|
||||
const u32 *conn_cmd;
|
||||
const u32 *init_cmd;
|
||||
int num_lvts_ctrl;
|
||||
int num_conn_cmd;
|
||||
int num_init_cmd;
|
||||
int temp_factor;
|
||||
int temp_offset;
|
||||
int gt_calib_bit_offset;
|
||||
|
|
@ -571,7 +575,7 @@ static irqreturn_t lvts_irq_handler(int irq, void *data)
|
|||
return iret;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops lvts_ops = {
|
||||
static const struct thermal_zone_device_ops lvts_ops = {
|
||||
.get_temp = lvts_get_temp,
|
||||
.set_trips = lvts_set_trips,
|
||||
};
|
||||
|
|
@ -902,7 +906,7 @@ static void lvts_ctrl_monitor_enable(struct device *dev, struct lvts_ctrl *lvts_
|
|||
* each write in the configuration register must be separated by a
|
||||
* delay of 2 us.
|
||||
*/
|
||||
static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, u32 *cmds, int nr_cmds)
|
||||
static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, const u32 *cmds, int nr_cmds)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -985,9 +989,10 @@ static int lvts_ctrl_set_enable(struct lvts_ctrl *lvts_ctrl, int enable)
|
|||
|
||||
static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl)
|
||||
{
|
||||
u32 id, cmds[] = { 0xC103FFFF, 0xC502FF55 };
|
||||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
u32 id;
|
||||
|
||||
lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
|
||||
lvts_write_config(lvts_ctrl, lvts_data->conn_cmd, lvts_data->num_conn_cmd);
|
||||
|
||||
/*
|
||||
* LVTS_ID : Get ID and status of the thermal controller
|
||||
|
|
@ -1006,17 +1011,9 @@ static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl)
|
|||
|
||||
static int lvts_ctrl_initialize(struct device *dev, struct lvts_ctrl *lvts_ctrl)
|
||||
{
|
||||
/*
|
||||
* Write device mask: 0xC1030000
|
||||
*/
|
||||
u32 cmds[] = {
|
||||
0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1,
|
||||
0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300,
|
||||
0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC,
|
||||
0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
|
||||
};
|
||||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
|
||||
lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds));
|
||||
lvts_write_config(lvts_ctrl, lvts_data->init_cmd, lvts_data->num_init_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1445,6 +1442,25 @@ static int lvts_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const u32 default_conn_cmds[] = { 0xC103FFFF, 0xC502FF55 };
|
||||
static const u32 mt7988_conn_cmds[] = { 0xC103FFFF, 0xC502FC55 };
|
||||
|
||||
/*
|
||||
* Write device mask: 0xC1030000
|
||||
*/
|
||||
static const u32 default_init_cmds[] = {
|
||||
0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1,
|
||||
0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300,
|
||||
0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC,
|
||||
0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1
|
||||
};
|
||||
|
||||
static const u32 mt7988_init_cmds[] = {
|
||||
0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC,
|
||||
0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01,
|
||||
0xC10306B8
|
||||
};
|
||||
|
||||
/*
|
||||
* The MT8186 calibration data is stored as packed 3-byte little-endian
|
||||
* values using a weird layout that makes sense only when viewed as a 32-bit
|
||||
|
|
@ -1739,7 +1755,11 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
|
|||
|
||||
static const struct lvts_data mt7988_lvts_ap_data = {
|
||||
.lvts_ctrl = mt7988_lvts_ap_data_ctrl,
|
||||
.conn_cmd = mt7988_conn_cmds,
|
||||
.init_cmd = mt7988_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(mt7988_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(mt7988_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
@ -1747,7 +1767,11 @@ static const struct lvts_data mt7988_lvts_ap_data = {
|
|||
|
||||
static const struct lvts_data mt8186_lvts_data = {
|
||||
.lvts_ctrl = mt8186_lvts_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8186_lvts_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
@ -1756,7 +1780,11 @@ static const struct lvts_data mt8186_lvts_data = {
|
|||
|
||||
static const struct lvts_data mt8188_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8188_lvts_mcu_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_mcu_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
|
|
@ -1765,7 +1793,11 @@ static const struct lvts_data mt8188_lvts_mcu_data = {
|
|||
|
||||
static const struct lvts_data mt8188_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8188_lvts_ap_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8188_lvts_ap_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 20,
|
||||
|
|
@ -1774,7 +1806,11 @@ static const struct lvts_data mt8188_lvts_ap_data = {
|
|||
|
||||
static const struct lvts_data mt8192_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8192_lvts_mcu_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
@ -1783,7 +1819,11 @@ static const struct lvts_data mt8192_lvts_mcu_data = {
|
|||
|
||||
static const struct lvts_data mt8192_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8192_lvts_ap_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
@ -1792,7 +1832,11 @@ static const struct lvts_data mt8192_lvts_ap_data = {
|
|||
|
||||
static const struct lvts_data mt8195_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
@ -1801,7 +1845,11 @@ static const struct lvts_data mt8195_lvts_mcu_data = {
|
|||
|
||||
static const struct lvts_data mt8195_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8195_lvts_ap_data_ctrl,
|
||||
.conn_cmd = default_conn_cmds,
|
||||
.init_cmd = default_init_cmds,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
|
||||
.num_conn_cmd = ARRAY_SIZE(default_conn_cmds),
|
||||
.num_init_cmd = ARRAY_SIZE(default_init_cmds),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
.gt_calib_bit_offset = 24,
|
||||
|
|
|
|||
|
|
@ -209,8 +209,7 @@ static int lmh_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
lmh_data->irq = platform_get_irq(pdev, 0);
|
||||
lmh_data->domain = irq_domain_create_linear(of_fwnode_handle(np), 1, &lmh_irq_ops,
|
||||
lmh_data);
|
||||
lmh_data->domain = irq_domain_create_linear(dev_fwnode(dev), 1, &lmh_irq_ops, lmh_data);
|
||||
if (!lmh_data->domain) {
|
||||
dev_err(dev, "Error adding irq_domain\n");
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2015, 2017, 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
|
@ -16,31 +18,51 @@
|
|||
|
||||
#include "../thermal_hwmon.h"
|
||||
|
||||
#define QPNP_TM_REG_DIG_MINOR 0x00
|
||||
#define QPNP_TM_REG_DIG_MAJOR 0x01
|
||||
#define QPNP_TM_REG_TYPE 0x04
|
||||
#define QPNP_TM_REG_SUBTYPE 0x05
|
||||
#define QPNP_TM_REG_STATUS 0x08
|
||||
#define QPNP_TM_REG_IRQ_STATUS 0x10
|
||||
#define QPNP_TM_REG_SHUTDOWN_CTRL1 0x40
|
||||
#define QPNP_TM_REG_ALARM_CTRL 0x46
|
||||
|
||||
/* TEMP_DAC_STGx registers are only present for TEMP_GEN2 v2.0 */
|
||||
#define QPNP_TM_REG_TEMP_DAC_STG1 0x47
|
||||
#define QPNP_TM_REG_TEMP_DAC_STG2 0x48
|
||||
#define QPNP_TM_REG_TEMP_DAC_STG3 0x49
|
||||
#define QPNP_TM_REG_LITE_TEMP_CFG1 0x50
|
||||
#define QPNP_TM_REG_LITE_TEMP_CFG2 0x51
|
||||
|
||||
#define QPNP_TM_TYPE 0x09
|
||||
#define QPNP_TM_SUBTYPE_GEN1 0x08
|
||||
#define QPNP_TM_SUBTYPE_GEN2 0x09
|
||||
#define QPNP_TM_SUBTYPE_LITE 0xC0
|
||||
|
||||
#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0)
|
||||
#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)
|
||||
#define STATUS_GEN2_STATE_SHIFT 4
|
||||
|
||||
#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6)
|
||||
/* IRQ status only needed for TEMP_ALARM_LITE */
|
||||
#define IRQ_STATUS_MASK BIT(0)
|
||||
|
||||
#define SHUTDOWN_CTRL1_OVERRIDE_STAGE2 BIT(6)
|
||||
#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
|
||||
|
||||
#define SHUTDOWN_CTRL1_RATE_25HZ BIT(3)
|
||||
|
||||
#define ALARM_CTRL_FORCE_ENABLE BIT(7)
|
||||
|
||||
#define LITE_TEMP_CFG_THRESHOLD_MASK GENMASK(3, 2)
|
||||
|
||||
#define THRESH_COUNT 4
|
||||
#define STAGE_COUNT 3
|
||||
|
||||
enum overtemp_stage {
|
||||
STAGE1 = 0,
|
||||
STAGE2,
|
||||
STAGE3,
|
||||
};
|
||||
|
||||
/* Over-temperature trip point values in mC */
|
||||
static const long temp_map_gen1[THRESH_COUNT][STAGE_COUNT] = {
|
||||
{ 105000, 125000, 145000 },
|
||||
|
|
@ -63,24 +85,68 @@ static const long temp_map_gen2_v1[THRESH_COUNT][STAGE_COUNT] = {
|
|||
|
||||
#define TEMP_STAGE_HYSTERESIS 2000
|
||||
|
||||
/*
|
||||
* For TEMP_GEN2 v2.0, TEMP_DAC_STG1/2/3 registers are used to set the threshold
|
||||
* for each stage independently.
|
||||
* TEMP_DAC_STG* = 0 --> 80 C
|
||||
* Each 8 step increase in TEMP_DAC_STG* value corresponds to 5 C (5000 mC).
|
||||
*/
|
||||
#define TEMP_DAC_MIN 80000
|
||||
#define TEMP_DAC_SCALE_NUM 8
|
||||
#define TEMP_DAC_SCALE_DEN 5000
|
||||
|
||||
#define TEMP_DAC_TEMP_TO_REG(temp) \
|
||||
(((temp) - TEMP_DAC_MIN) * TEMP_DAC_SCALE_NUM / TEMP_DAC_SCALE_DEN)
|
||||
#define TEMP_DAC_REG_TO_TEMP(reg) \
|
||||
(TEMP_DAC_MIN + (reg) * TEMP_DAC_SCALE_DEN / TEMP_DAC_SCALE_NUM)
|
||||
|
||||
static const long temp_dac_max[STAGE_COUNT] = {
|
||||
119375, 159375, 159375
|
||||
};
|
||||
|
||||
/*
|
||||
* TEMP_ALARM_LITE has two stages: warning and shutdown with independently
|
||||
* configured threshold temperatures.
|
||||
*/
|
||||
|
||||
static const long temp_lite_warning_map[THRESH_COUNT] = {
|
||||
115000, 125000, 135000, 145000
|
||||
};
|
||||
|
||||
static const long temp_lite_shutdown_map[THRESH_COUNT] = {
|
||||
135000, 145000, 160000, 175000
|
||||
};
|
||||
|
||||
/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
|
||||
#define DEFAULT_TEMP 37000
|
||||
|
||||
struct qpnp_tm_chip;
|
||||
|
||||
struct spmi_temp_alarm_data {
|
||||
const struct thermal_zone_device_ops *ops;
|
||||
const long (*temp_map)[THRESH_COUNT][STAGE_COUNT];
|
||||
int (*sync_thresholds)(struct qpnp_tm_chip *chip);
|
||||
int (*get_temp_stage)(struct qpnp_tm_chip *chip);
|
||||
int (*configure_trip_temps)(struct qpnp_tm_chip *chip);
|
||||
};
|
||||
|
||||
struct qpnp_tm_chip {
|
||||
struct regmap *map;
|
||||
struct device *dev;
|
||||
struct thermal_zone_device *tz_dev;
|
||||
const struct spmi_temp_alarm_data *data;
|
||||
unsigned int subtype;
|
||||
long temp;
|
||||
unsigned int thresh;
|
||||
unsigned int stage;
|
||||
unsigned int base;
|
||||
unsigned int ntrips;
|
||||
/* protects .thresh, .stage and chip registers */
|
||||
struct mutex lock;
|
||||
bool initialized;
|
||||
bool require_stage2_shutdown;
|
||||
long temp_thresh_map[STAGE_COUNT];
|
||||
|
||||
struct iio_channel *adc;
|
||||
const long (*temp_map)[THRESH_COUNT][STAGE_COUNT];
|
||||
};
|
||||
|
||||
/* This array maps from GEN2 alarm state to GEN1 alarm stage */
|
||||
|
|
@ -114,34 +180,66 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
|
|||
*/
|
||||
static long qpnp_tm_decode_temp(struct qpnp_tm_chip *chip, unsigned int stage)
|
||||
{
|
||||
if (!chip->temp_map || chip->thresh >= THRESH_COUNT || stage == 0 ||
|
||||
stage > STAGE_COUNT)
|
||||
if (stage == 0 || stage > STAGE_COUNT)
|
||||
return 0;
|
||||
|
||||
return (*chip->temp_map)[chip->thresh][stage - 1];
|
||||
return chip->temp_thresh_map[stage - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* qpnp_tm_get_temp_stage() - return over-temperature stage
|
||||
* qpnp_tm_gen1_get_temp_stage() - return over-temperature stage
|
||||
* @chip: Pointer to the qpnp_tm chip
|
||||
*
|
||||
* Return: stage (GEN1) or state (GEN2) on success, or errno on failure.
|
||||
* Return: stage on success, or errno on failure.
|
||||
*/
|
||||
static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
|
||||
static int qpnp_tm_gen1_get_temp_stage(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
u8 reg = 0;
|
||||
u8 reg;
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
|
||||
ret = reg & STATUS_GEN1_STAGE_MASK;
|
||||
else
|
||||
ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT;
|
||||
return FIELD_GET(STATUS_GEN1_STAGE_MASK, reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/**
|
||||
* qpnp_tm_gen2_get_temp_stage() - return over-temperature stage
|
||||
* @chip: Pointer to the qpnp_tm chip
|
||||
*
|
||||
* Return: stage on success, or errno on failure.
|
||||
*/
|
||||
static int qpnp_tm_gen2_get_temp_stage(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
u8 reg;
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = FIELD_GET(STATUS_GEN2_STATE_MASK, reg);
|
||||
|
||||
return alarm_state_map[ret];
|
||||
}
|
||||
|
||||
/**
|
||||
* qpnp_tm_lite_get_temp_stage() - return over-temperature stage
|
||||
* @chip: Pointer to the qpnp_tm chip
|
||||
*
|
||||
* Return: alarm interrupt state on success, or errno on failure.
|
||||
*/
|
||||
static int qpnp_tm_lite_get_temp_stage(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
u8 reg = 0;
|
||||
int ret;
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_IRQ_STATUS, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(IRQ_STATUS_MASK, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -150,23 +248,16 @@ static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
|
|||
*/
|
||||
static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
unsigned int stage, stage_new, stage_old;
|
||||
unsigned int stage_new, stage_old;
|
||||
int ret;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&chip->lock));
|
||||
|
||||
ret = qpnp_tm_get_temp_stage(chip);
|
||||
ret = chip->data->get_temp_stage(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
stage = ret;
|
||||
|
||||
if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
|
||||
stage_new = stage;
|
||||
stage_old = chip->stage;
|
||||
} else {
|
||||
stage_new = alarm_state_map[stage];
|
||||
stage_old = alarm_state_map[chip->stage];
|
||||
}
|
||||
stage_new = ret;
|
||||
stage_old = chip->stage;
|
||||
|
||||
if (stage_new > stage_old) {
|
||||
/* increasing stage, use lower bound */
|
||||
|
|
@ -178,7 +269,7 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
|
|||
- TEMP_STAGE_HYSTERESIS;
|
||||
}
|
||||
|
||||
chip->stage = stage;
|
||||
chip->stage = stage_new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -218,35 +309,35 @@ static int qpnp_tm_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
|
||||
int temp)
|
||||
{
|
||||
long stage2_threshold_min = (*chip->temp_map)[THRESH_MIN][1];
|
||||
long stage2_threshold_max = (*chip->temp_map)[THRESH_MAX][1];
|
||||
bool disable_s2_shutdown = false;
|
||||
u8 reg;
|
||||
long stage2_threshold_min = (*chip->data->temp_map)[THRESH_MIN][STAGE2];
|
||||
long stage2_threshold_max = (*chip->data->temp_map)[THRESH_MAX][STAGE2];
|
||||
bool disable_stage2_shutdown = false;
|
||||
u8 reg, threshold;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&chip->lock));
|
||||
|
||||
/*
|
||||
* Default: S2 and S3 shutdown enabled, thresholds at
|
||||
* Default: Stage 2 and Stage 3 shutdown enabled, thresholds at
|
||||
* lowest threshold set, monitoring at 25Hz
|
||||
*/
|
||||
reg = SHUTDOWN_CTRL1_RATE_25HZ;
|
||||
|
||||
if (temp == THERMAL_TEMP_INVALID ||
|
||||
temp < stage2_threshold_min) {
|
||||
chip->thresh = THRESH_MIN;
|
||||
threshold = THRESH_MIN;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (temp <= stage2_threshold_max) {
|
||||
chip->thresh = THRESH_MAX -
|
||||
threshold = THRESH_MAX -
|
||||
((stage2_threshold_max - temp) /
|
||||
TEMP_THRESH_STEP);
|
||||
disable_s2_shutdown = true;
|
||||
disable_stage2_shutdown = true;
|
||||
} else {
|
||||
chip->thresh = THRESH_MAX;
|
||||
threshold = THRESH_MAX;
|
||||
|
||||
if (chip->adc)
|
||||
disable_s2_shutdown = true;
|
||||
disable_stage2_shutdown = true;
|
||||
else
|
||||
dev_warn(chip->dev,
|
||||
"No ADC is configured and critical temperature %d mC is above the maximum stage 2 threshold of %ld mC! Configuring stage 2 shutdown at %ld mC.\n",
|
||||
|
|
@ -254,9 +345,11 @@ static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
|
|||
}
|
||||
|
||||
skip:
|
||||
reg |= chip->thresh;
|
||||
if (disable_s2_shutdown)
|
||||
reg |= SHUTDOWN_CTRL1_OVERRIDE_S2;
|
||||
memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
reg |= threshold;
|
||||
if (disable_stage2_shutdown && !chip->require_stage2_shutdown)
|
||||
reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2;
|
||||
|
||||
return qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
|
||||
}
|
||||
|
|
@ -282,6 +375,146 @@ static const struct thermal_zone_device_ops qpnp_tm_sensor_ops = {
|
|||
.set_trip_temp = qpnp_tm_set_trip_temp,
|
||||
};
|
||||
|
||||
static int qpnp_tm_gen2_rev2_set_temp_thresh(struct qpnp_tm_chip *chip, unsigned int trip, int temp)
|
||||
{
|
||||
int ret, temp_cfg;
|
||||
u8 reg;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&chip->lock));
|
||||
|
||||
if (trip >= STAGE_COUNT) {
|
||||
dev_err(chip->dev, "invalid TEMP_DAC trip = %d\n", trip);
|
||||
return -EINVAL;
|
||||
} else if (temp < TEMP_DAC_MIN || temp > temp_dac_max[trip]) {
|
||||
dev_err(chip->dev, "invalid TEMP_DAC temp = %d\n", temp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = TEMP_DAC_TEMP_TO_REG(temp);
|
||||
temp_cfg = TEMP_DAC_REG_TO_TEMP(reg);
|
||||
|
||||
ret = qpnp_tm_write(chip, QPNP_TM_REG_TEMP_DAC_STG1 + trip, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "TEMP_DAC_STG write failed, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->temp_thresh_map[trip] = temp_cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_tm_gen2_rev2_set_trip_temp(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip, int temp)
|
||||
{
|
||||
unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);
|
||||
struct qpnp_tm_chip *chip = thermal_zone_device_priv(tz);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
ret = qpnp_tm_gen2_rev2_set_temp_thresh(chip, trip_index, temp);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops qpnp_tm_gen2_rev2_sensor_ops = {
|
||||
.get_temp = qpnp_tm_get_temp,
|
||||
.set_trip_temp = qpnp_tm_gen2_rev2_set_trip_temp,
|
||||
};
|
||||
|
||||
static int qpnp_tm_lite_set_temp_thresh(struct qpnp_tm_chip *chip, unsigned int trip, int temp)
|
||||
{
|
||||
int ret, temp_cfg, i;
|
||||
const long *temp_map;
|
||||
u8 reg, thresh;
|
||||
u16 addr;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&chip->lock));
|
||||
|
||||
if (trip >= STAGE_COUNT) {
|
||||
dev_err(chip->dev, "invalid TEMP_LITE trip = %d\n", trip);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (trip) {
|
||||
case 0:
|
||||
temp_map = temp_lite_warning_map;
|
||||
addr = QPNP_TM_REG_LITE_TEMP_CFG1;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* The second trip point is purely in software to facilitate
|
||||
* a controlled shutdown after the warning threshold is crossed
|
||||
* but before the automatic hardware shutdown threshold is
|
||||
* crossed.
|
||||
*/
|
||||
return 0;
|
||||
case 2:
|
||||
temp_map = temp_lite_shutdown_map;
|
||||
addr = QPNP_TM_REG_LITE_TEMP_CFG2;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (temp < temp_map[THRESH_MIN] || temp > temp_map[THRESH_MAX]) {
|
||||
dev_err(chip->dev, "invalid TEMP_LITE temp = %d\n", temp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
thresh = 0;
|
||||
temp_cfg = temp_map[thresh];
|
||||
for (i = THRESH_MAX; i >= THRESH_MIN; i--) {
|
||||
if (temp >= temp_map[i]) {
|
||||
thresh = i;
|
||||
temp_cfg = temp_map[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp_cfg == chip->temp_thresh_map[trip])
|
||||
return 0;
|
||||
|
||||
ret = qpnp_tm_read(chip, addr, ®);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "LITE_TEMP_CFG read failed, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg &= ~LITE_TEMP_CFG_THRESHOLD_MASK;
|
||||
reg |= FIELD_PREP(LITE_TEMP_CFG_THRESHOLD_MASK, thresh);
|
||||
|
||||
ret = qpnp_tm_write(chip, addr, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "LITE_TEMP_CFG write failed, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
chip->temp_thresh_map[trip] = temp_cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_tm_lite_set_trip_temp(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip, int temp)
|
||||
{
|
||||
unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);
|
||||
struct qpnp_tm_chip *chip = thermal_zone_device_priv(tz);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
ret = qpnp_tm_lite_set_temp_thresh(chip, trip_index, temp);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops qpnp_tm_lite_sensor_ops = {
|
||||
.get_temp = qpnp_tm_get_temp,
|
||||
.set_trip_temp = qpnp_tm_lite_set_trip_temp,
|
||||
};
|
||||
|
||||
static irqreturn_t qpnp_tm_isr(int irq, void *data)
|
||||
{
|
||||
struct qpnp_tm_chip *chip = data;
|
||||
|
|
@ -291,49 +524,227 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the internal temp value based on only the
|
||||
* current thermal stage and threshold. Setup threshold control and
|
||||
* disable shutdown override.
|
||||
*/
|
||||
static int qpnp_tm_init(struct qpnp_tm_chip *chip)
|
||||
/* Read the hardware default stage threshold temperatures */
|
||||
static int qpnp_tm_sync_thresholds(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
unsigned int stage;
|
||||
u8 reg, threshold;
|
||||
int ret;
|
||||
u8 reg = 0;
|
||||
int crit_temp;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
|
||||
chip->temp = DEFAULT_TEMP;
|
||||
threshold = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
|
||||
memcpy(chip->temp_thresh_map, chip->data->temp_map[threshold],
|
||||
sizeof(chip->temp_thresh_map));
|
||||
|
||||
ret = qpnp_tm_get_temp_stage(chip);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
chip->stage = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
|
||||
? chip->stage : alarm_state_map[chip->stage];
|
||||
|
||||
if (stage)
|
||||
chip->temp = qpnp_tm_decode_temp(chip, stage);
|
||||
|
||||
mutex_unlock(&chip->lock);
|
||||
static int qpnp_tm_configure_trip_temp(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int crit_temp, ret;
|
||||
|
||||
ret = thermal_zone_get_crit_temp(chip->tz_dev, &crit_temp);
|
||||
if (ret)
|
||||
crit_temp = THERMAL_TEMP_INVALID;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
||||
ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure TEMP_DAC registers based on DT thermal_zone trips */
|
||||
static int qpnp_tm_gen2_rev2_configure_trip_temps_cb(struct thermal_trip *trip, void *data)
|
||||
{
|
||||
struct qpnp_tm_chip *chip = data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
trip->priv = THERMAL_INT_TO_TRIP_PRIV(chip->ntrips);
|
||||
ret = qpnp_tm_gen2_rev2_set_temp_thresh(chip, chip->ntrips, trip->temperature);
|
||||
chip->ntrips++;
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qpnp_tm_gen2_rev2_configure_trip_temps(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = thermal_zone_for_each_trip(chip->tz_dev,
|
||||
qpnp_tm_gen2_rev2_configure_trip_temps_cb, chip);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
/* Verify that trips are strictly increasing. */
|
||||
for (i = 1; i < STAGE_COUNT; i++) {
|
||||
if (chip->temp_thresh_map[i] <= chip->temp_thresh_map[i - 1]) {
|
||||
dev_err(chip->dev, "Threshold %d=%ld <= threshold %d=%ld\n",
|
||||
i, chip->temp_thresh_map[i], i - 1,
|
||||
chip->temp_thresh_map[i - 1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the hardware default TEMP_DAC stage threshold temperatures */
|
||||
static int qpnp_tm_gen2_rev2_sync_thresholds(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret, i;
|
||||
u8 reg = 0;
|
||||
|
||||
for (i = 0; i < STAGE_COUNT; i++) {
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_TEMP_DAC_STG1 + i, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
chip->temp_thresh_map[i] = TEMP_DAC_REG_TO_TEMP(reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configure TEMP_LITE registers based on DT thermal_zone trips */
|
||||
static int qpnp_tm_lite_configure_trip_temps_cb(struct thermal_trip *trip, void *data)
|
||||
{
|
||||
struct qpnp_tm_chip *chip = data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
trip->priv = THERMAL_INT_TO_TRIP_PRIV(chip->ntrips);
|
||||
ret = qpnp_tm_lite_set_temp_thresh(chip, chip->ntrips, trip->temperature);
|
||||
chip->ntrips++;
|
||||
mutex_unlock(&chip->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qpnp_tm_lite_configure_trip_temps(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = thermal_zone_for_each_trip(chip->tz_dev, qpnp_tm_lite_configure_trip_temps_cb, chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Verify that trips are strictly increasing. */
|
||||
if (chip->temp_thresh_map[2] <= chip->temp_thresh_map[0]) {
|
||||
dev_err(chip->dev, "Threshold 2=%ld <= threshold 0=%ld\n",
|
||||
chip->temp_thresh_map[2], chip->temp_thresh_map[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the hardware default TEMP_LITE stage threshold temperatures */
|
||||
static int qpnp_tm_lite_sync_thresholds(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret, thresh;
|
||||
u8 reg = 0;
|
||||
|
||||
/*
|
||||
* Store the warning trip temp in temp_thresh_map[0] and the shutdown trip
|
||||
* temp in temp_thresh_map[2]. The second trip point is purely in software
|
||||
* to facilitate a controlled shutdown after the warning threshold is
|
||||
* crossed but before the automatic hardware shutdown threshold is
|
||||
* crossed. Thus, there is no register to read for the second trip
|
||||
* point.
|
||||
*/
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_LITE_TEMP_CFG1, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
thresh = FIELD_GET(LITE_TEMP_CFG_THRESHOLD_MASK, reg);
|
||||
chip->temp_thresh_map[0] = temp_lite_warning_map[thresh];
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_LITE_TEMP_CFG2, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
thresh = FIELD_GET(LITE_TEMP_CFG_THRESHOLD_MASK, reg);
|
||||
chip->temp_thresh_map[2] = temp_lite_shutdown_map[thresh];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spmi_temp_alarm_data spmi_temp_alarm_data = {
|
||||
.ops = &qpnp_tm_sensor_ops,
|
||||
.temp_map = &temp_map_gen1,
|
||||
.sync_thresholds = qpnp_tm_sync_thresholds,
|
||||
.configure_trip_temps = qpnp_tm_configure_trip_temp,
|
||||
.get_temp_stage = qpnp_tm_gen1_get_temp_stage,
|
||||
};
|
||||
|
||||
static const struct spmi_temp_alarm_data spmi_temp_alarm_gen2_data = {
|
||||
.ops = &qpnp_tm_sensor_ops,
|
||||
.temp_map = &temp_map_gen1,
|
||||
.sync_thresholds = qpnp_tm_sync_thresholds,
|
||||
.configure_trip_temps = qpnp_tm_configure_trip_temp,
|
||||
.get_temp_stage = qpnp_tm_gen2_get_temp_stage,
|
||||
};
|
||||
|
||||
static const struct spmi_temp_alarm_data spmi_temp_alarm_gen2_rev1_data = {
|
||||
.ops = &qpnp_tm_sensor_ops,
|
||||
.temp_map = &temp_map_gen2_v1,
|
||||
.sync_thresholds = qpnp_tm_sync_thresholds,
|
||||
.configure_trip_temps = qpnp_tm_configure_trip_temp,
|
||||
.get_temp_stage = qpnp_tm_gen2_get_temp_stage,
|
||||
};
|
||||
|
||||
static const struct spmi_temp_alarm_data spmi_temp_alarm_gen2_rev2_data = {
|
||||
.ops = &qpnp_tm_gen2_rev2_sensor_ops,
|
||||
.sync_thresholds = qpnp_tm_gen2_rev2_sync_thresholds,
|
||||
.configure_trip_temps = qpnp_tm_gen2_rev2_configure_trip_temps,
|
||||
.get_temp_stage = qpnp_tm_gen2_get_temp_stage,
|
||||
};
|
||||
|
||||
static const struct spmi_temp_alarm_data spmi_temp_alarm_lite_data = {
|
||||
.ops = &qpnp_tm_lite_sensor_ops,
|
||||
.sync_thresholds = qpnp_tm_lite_sync_thresholds,
|
||||
.configure_trip_temps = qpnp_tm_lite_configure_trip_temps,
|
||||
.get_temp_stage = qpnp_tm_lite_get_temp_stage,
|
||||
};
|
||||
|
||||
/*
|
||||
* This function initializes the internal temp value based on only the
|
||||
* current thermal stage and threshold.
|
||||
*/
|
||||
static int qpnp_tm_threshold_init(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = chip->data->sync_thresholds(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = chip->data->get_temp_stage(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
chip->stage = ret;
|
||||
chip->temp = DEFAULT_TEMP;
|
||||
|
||||
if (chip->stage)
|
||||
chip->temp = qpnp_tm_decode_temp(chip, chip->stage);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function initializes threshold control and disables shutdown override. */
|
||||
static int qpnp_tm_init(struct qpnp_tm_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
u8 reg;
|
||||
|
||||
ret = chip->data->configure_trip_temps(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable the thermal alarm PMIC module in always-on mode. */
|
||||
reg = ALARM_CTRL_FORCE_ENABLE;
|
||||
|
|
@ -341,8 +752,6 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
|
|||
|
||||
chip->initialized = true;
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -350,8 +759,8 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct qpnp_tm_chip *chip;
|
||||
struct device_node *node;
|
||||
u8 type, subtype, dig_major;
|
||||
u32 res;
|
||||
u8 type, subtype, dig_major, dig_minor;
|
||||
u32 res, dig_revision;
|
||||
int ret, irq;
|
||||
|
||||
node = pdev->dev.of_node;
|
||||
|
|
@ -402,18 +811,53 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
|||
return dev_err_probe(&pdev->dev, ret,
|
||||
"could not read dig_major\n");
|
||||
|
||||
ret = qpnp_tm_read(chip, QPNP_TM_REG_DIG_MINOR, &dig_minor);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"could not read dig_minor\n");
|
||||
|
||||
if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
|
||||
&& subtype != QPNP_TM_SUBTYPE_GEN2)) {
|
||||
&& subtype != QPNP_TM_SUBTYPE_GEN2
|
||||
&& subtype != QPNP_TM_SUBTYPE_LITE)) {
|
||||
dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
|
||||
type, subtype);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip->subtype = subtype;
|
||||
if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 1)
|
||||
chip->temp_map = &temp_map_gen2_v1;
|
||||
if (subtype == QPNP_TM_SUBTYPE_GEN1)
|
||||
chip->data = &spmi_temp_alarm_data;
|
||||
else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major == 0)
|
||||
chip->data = &spmi_temp_alarm_gen2_data;
|
||||
else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major == 1)
|
||||
chip->data = &spmi_temp_alarm_gen2_rev1_data;
|
||||
else if (subtype == QPNP_TM_SUBTYPE_GEN2 && dig_major >= 2)
|
||||
chip->data = &spmi_temp_alarm_gen2_rev2_data;
|
||||
else if (subtype == QPNP_TM_SUBTYPE_LITE)
|
||||
chip->data = &spmi_temp_alarm_lite_data;
|
||||
else
|
||||
chip->temp_map = &temp_map_gen1;
|
||||
return -ENODEV;
|
||||
|
||||
if (chip->subtype == QPNP_TM_SUBTYPE_GEN2) {
|
||||
dig_revision = (dig_major << 8) | dig_minor;
|
||||
/*
|
||||
* Check if stage 2 automatic partial shutdown must remain
|
||||
* enabled to avoid potential repeated faults upon reaching
|
||||
* over-temperature stage 3.
|
||||
*/
|
||||
switch (dig_revision) {
|
||||
case 0x0001:
|
||||
case 0x0002:
|
||||
case 0x0100:
|
||||
case 0x0101:
|
||||
chip->require_stage2_shutdown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = qpnp_tm_threshold_init(chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "threshold init failed\n");
|
||||
|
||||
/*
|
||||
* Register the sensor before initializing the hardware to be able to
|
||||
|
|
@ -421,7 +865,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
|
|||
* before the hardware initialization is completed.
|
||||
*/
|
||||
chip->tz_dev = devm_thermal_of_zone_register(
|
||||
&pdev->dev, 0, chip, &qpnp_tm_sensor_ops);
|
||||
&pdev->dev, 0, chip, chip->data->ops);
|
||||
if (IS_ERR(chip->tz_dev))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(chip->tz_dev),
|
||||
"failed to register sensor\n");
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
|
|||
return rcar_thermal_get_current_temp(priv, temp);
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
|
||||
static const struct thermal_zone_device_ops rcar_thermal_zone_ops = {
|
||||
.get_temp = rcar_thermal_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
|
@ -69,16 +70,18 @@ struct chip_tsadc_table {
|
|||
* struct rockchip_tsadc_chip - hold the private data of tsadc chip
|
||||
* @chn_offset: the channel offset of the first channel
|
||||
* @chn_num: the channel number of tsadc chip
|
||||
* @tshut_temp: the hardware-controlled shutdown temperature value
|
||||
* @trim_slope: used to convert the trim code to a temperature in millicelsius
|
||||
* @tshut_temp: the hardware-controlled shutdown temperature value, with no trim
|
||||
* @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO)
|
||||
* @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH)
|
||||
* @initialize: SoC special initialize tsadc controller method
|
||||
* @irq_ack: clear the interrupt
|
||||
* @control: enable/disable method for the tsadc controller
|
||||
* @get_temp: get the temperature
|
||||
* @get_temp: get the raw temperature, unadjusted by trim
|
||||
* @set_alarm_temp: set the high temperature interrupt
|
||||
* @set_tshut_temp: set the hardware-controlled shutdown temperature
|
||||
* @set_tshut_mode: set the hardware-controlled shutdown mode
|
||||
* @get_trim_code: convert a hardware temperature code to one adjusted for by trim
|
||||
* @table: the chip-specific conversion table
|
||||
*/
|
||||
struct rockchip_tsadc_chip {
|
||||
|
|
@ -86,6 +89,9 @@ struct rockchip_tsadc_chip {
|
|||
int chn_offset;
|
||||
int chn_num;
|
||||
|
||||
/* Used to convert trim code to trim temp */
|
||||
int trim_slope;
|
||||
|
||||
/* The hardware-controlled tshut property */
|
||||
int tshut_temp;
|
||||
enum tshut_mode tshut_mode;
|
||||
|
|
@ -105,6 +111,8 @@ struct rockchip_tsadc_chip {
|
|||
int (*set_tshut_temp)(const struct chip_tsadc_table *table,
|
||||
int chn, void __iomem *reg, int temp);
|
||||
void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
|
||||
int (*get_trim_code)(const struct chip_tsadc_table *table,
|
||||
int code, int trim_base, int trim_base_frac);
|
||||
|
||||
/* Per-table methods */
|
||||
struct chip_tsadc_table table;
|
||||
|
|
@ -114,12 +122,16 @@ struct rockchip_tsadc_chip {
|
|||
* struct rockchip_thermal_sensor - hold the information of thermal sensor
|
||||
* @thermal: pointer to the platform/configuration data
|
||||
* @tzd: pointer to a thermal zone
|
||||
* @of_node: pointer to the device_node representing this sensor, if any
|
||||
* @id: identifier of the thermal sensor
|
||||
* @trim_temp: per-sensor trim temperature value
|
||||
*/
|
||||
struct rockchip_thermal_sensor {
|
||||
struct rockchip_thermal_data *thermal;
|
||||
struct thermal_zone_device *tzd;
|
||||
struct device_node *of_node;
|
||||
int id;
|
||||
int trim_temp;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -132,7 +144,11 @@ struct rockchip_thermal_sensor {
|
|||
* @pclk: the advanced peripherals bus clock
|
||||
* @grf: the general register file will be used to do static set by software
|
||||
* @regs: the base address of tsadc controller
|
||||
* @tshut_temp: the hardware-controlled shutdown temperature value
|
||||
* @trim_base: major component of sensor trim value, in Celsius
|
||||
* @trim_base_frac: minor component of sensor trim value, in Decicelsius
|
||||
* @trim: fallback thermal trim value for each channel
|
||||
* @tshut_temp: the hardware-controlled shutdown temperature value, with no trim
|
||||
* @trim_temp: the fallback trim temperature for the whole sensor
|
||||
* @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO)
|
||||
* @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH)
|
||||
*/
|
||||
|
|
@ -149,7 +165,12 @@ struct rockchip_thermal_data {
|
|||
struct regmap *grf;
|
||||
void __iomem *regs;
|
||||
|
||||
int trim_base;
|
||||
int trim_base_frac;
|
||||
int trim;
|
||||
|
||||
int tshut_temp;
|
||||
int trim_temp;
|
||||
enum tshut_mode tshut_mode;
|
||||
enum tshut_polarity tshut_polarity;
|
||||
};
|
||||
|
|
@ -249,6 +270,9 @@ struct rockchip_thermal_data {
|
|||
|
||||
#define GRF_CON_TSADC_CH_INV (0x10001 << 1)
|
||||
|
||||
|
||||
#define RK_MAX_TEMP (180000)
|
||||
|
||||
/**
|
||||
* struct tsadc_table - code to temperature conversion table
|
||||
* @code: the value of adc channel
|
||||
|
|
@ -1045,7 +1069,7 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
|
|||
writel_relaxed(val, regs + TSADCV2_INT_EN);
|
||||
}
|
||||
|
||||
static void rk_tsadcv3_tshut_mode(int chn, void __iomem *regs,
|
||||
static void rk_tsadcv4_tshut_mode(int chn, void __iomem *regs,
|
||||
enum tshut_mode mode)
|
||||
{
|
||||
u32 val_gpio, val_cru;
|
||||
|
|
@ -1061,6 +1085,15 @@ static void rk_tsadcv3_tshut_mode(int chn, void __iomem *regs,
|
|||
writel_relaxed(val_cru, regs + TSADCV3_HSHUT_CRU_INT_EN);
|
||||
}
|
||||
|
||||
static int rk_tsadcv2_get_trim_code(const struct chip_tsadc_table *table,
|
||||
int code, int trim_base, int trim_base_frac)
|
||||
{
|
||||
int temp = trim_base * 1000 + trim_base_frac * 100;
|
||||
u32 base_code = rk_tsadcv2_temp_to_code(table, temp);
|
||||
|
||||
return code - base_code;
|
||||
}
|
||||
|
||||
static const struct rockchip_tsadc_chip px30_tsadc_data = {
|
||||
/* cpu, gpu */
|
||||
.chn_offset = 0,
|
||||
|
|
@ -1284,6 +1317,30 @@ static const struct rockchip_tsadc_chip rk3568_tsadc_data = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_tsadc_chip rk3576_tsadc_data = {
|
||||
/* top, big_core, little_core, ddr, npu, gpu */
|
||||
.chn_offset = 0,
|
||||
.chn_num = 6, /* six channels for tsadc */
|
||||
.tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
|
||||
.tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
|
||||
.tshut_temp = 95000,
|
||||
.initialize = rk_tsadcv8_initialize,
|
||||
.irq_ack = rk_tsadcv4_irq_ack,
|
||||
.control = rk_tsadcv4_control,
|
||||
.get_temp = rk_tsadcv4_get_temp,
|
||||
.set_alarm_temp = rk_tsadcv3_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv3_tshut_temp,
|
||||
.set_tshut_mode = rk_tsadcv4_tshut_mode,
|
||||
.get_trim_code = rk_tsadcv2_get_trim_code,
|
||||
.trim_slope = 923,
|
||||
.table = {
|
||||
.id = rk3588_code_table,
|
||||
.length = ARRAY_SIZE(rk3588_code_table),
|
||||
.data_mask = TSADCV4_DATA_MASK,
|
||||
.mode = ADC_INCREMENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_tsadc_chip rk3588_tsadc_data = {
|
||||
/* top, big_core0, big_core1, little_core, center, gpu, npu */
|
||||
.chn_offset = 0,
|
||||
|
|
@ -1297,7 +1354,7 @@ static const struct rockchip_tsadc_chip rk3588_tsadc_data = {
|
|||
.get_temp = rk_tsadcv4_get_temp,
|
||||
.set_alarm_temp = rk_tsadcv3_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv3_tshut_temp,
|
||||
.set_tshut_mode = rk_tsadcv3_tshut_mode,
|
||||
.set_tshut_mode = rk_tsadcv4_tshut_mode,
|
||||
.table = {
|
||||
.id = rk3588_code_table,
|
||||
.length = ARRAY_SIZE(rk3588_code_table),
|
||||
|
|
@ -1342,6 +1399,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
|
|||
.compatible = "rockchip,rk3568-tsadc",
|
||||
.data = (void *)&rk3568_tsadc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3576-tsadc",
|
||||
.data = (void *)&rk3576_tsadc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3588-tsadc",
|
||||
.data = (void *)&rk3588_tsadc_data,
|
||||
|
|
@ -1387,7 +1448,7 @@ static int rockchip_thermal_set_trips(struct thermal_zone_device *tz, int low, i
|
|||
__func__, sensor->id, low, high);
|
||||
|
||||
return tsadc->set_alarm_temp(&tsadc->table,
|
||||
sensor->id, thermal->regs, high);
|
||||
sensor->id, thermal->regs, high + sensor->trim_temp);
|
||||
}
|
||||
|
||||
static int rockchip_thermal_get_temp(struct thermal_zone_device *tz, int *out_temp)
|
||||
|
|
@ -1399,6 +1460,8 @@ static int rockchip_thermal_get_temp(struct thermal_zone_device *tz, int *out_te
|
|||
|
||||
retval = tsadc->get_temp(&tsadc->table,
|
||||
sensor->id, thermal->regs, out_temp);
|
||||
*out_temp -= sensor->trim_temp;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1407,6 +1470,104 @@ static const struct thermal_zone_device_ops rockchip_of_thermal_ops = {
|
|||
.set_trips = rockchip_thermal_set_trips,
|
||||
};
|
||||
|
||||
/**
|
||||
* rockchip_get_efuse_value - read an OTP cell from a device node
|
||||
* @np: pointer to the device node with the nvmem-cells property
|
||||
* @cell_name: name of cell that should be read
|
||||
* @value: pointer to where the read value will be placed
|
||||
*
|
||||
* Return: Negative errno on failure, during which *value will not be touched,
|
||||
* or 0 on success.
|
||||
*/
|
||||
static int rockchip_get_efuse_value(struct device_node *np, const char *cell_name,
|
||||
int *value)
|
||||
{
|
||||
struct nvmem_cell *cell;
|
||||
int ret = 0;
|
||||
size_t len;
|
||||
u8 *buf;
|
||||
int i;
|
||||
|
||||
cell = of_nvmem_cell_get(np, cell_name);
|
||||
if (IS_ERR(cell))
|
||||
return PTR_ERR(cell);
|
||||
|
||||
buf = nvmem_cell_read(cell, &len);
|
||||
|
||||
nvmem_cell_put(cell);
|
||||
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
if (len > sizeof(*value)) {
|
||||
ret = -ERANGE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Copy with implicit endian conversion */
|
||||
*value = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
*value |= (int) buf[i] << (8 * i);
|
||||
|
||||
exit:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_get_trim_configuration(struct device *dev, struct device_node *np,
|
||||
struct rockchip_thermal_data *thermal)
|
||||
{
|
||||
const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
int trim_base = 0, trim_base_frac = 0, trim = 0;
|
||||
int trim_code;
|
||||
int ret;
|
||||
|
||||
thermal->trim_base = 0;
|
||||
thermal->trim_base_frac = 0;
|
||||
thermal->trim = 0;
|
||||
|
||||
if (!tsadc->get_trim_code)
|
||||
return 0;
|
||||
|
||||
ret = rockchip_get_efuse_value(np, "trim_base", &trim_base);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT) {
|
||||
trim_base = 30;
|
||||
dev_dbg(dev, "trim_base is absent, defaulting to 30\n");
|
||||
} else {
|
||||
dev_err(dev, "failed reading nvmem value of trim_base: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = rockchip_get_efuse_value(np, "trim_base_frac", &trim_base_frac);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT) {
|
||||
dev_dbg(dev, "trim_base_frac is absent, defaulting to 0\n");
|
||||
} else {
|
||||
dev_err(dev, "failed reading nvmem value of trim_base_frac: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
thermal->trim_base = trim_base;
|
||||
thermal->trim_base_frac = trim_base_frac;
|
||||
|
||||
/*
|
||||
* If the tsadc node contains the trim property, then it is used in the
|
||||
* absence of per-channel trim values
|
||||
*/
|
||||
if (!rockchip_get_efuse_value(np, "trim", &trim))
|
||||
thermal->trim = trim;
|
||||
if (trim) {
|
||||
trim_code = tsadc->get_trim_code(&tsadc->table, trim,
|
||||
trim_base, trim_base_frac);
|
||||
thermal->trim_temp = thermal->chip->trim_slope * trim_code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_configure_from_dt(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct rockchip_thermal_data *thermal)
|
||||
|
|
@ -1467,6 +1628,8 @@ static int rockchip_configure_from_dt(struct device *dev,
|
|||
if (IS_ERR(thermal->grf))
|
||||
dev_warn(dev, "Missing rockchip,grf property\n");
|
||||
|
||||
rockchip_get_trim_configuration(dev, np, thermal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1477,23 +1640,50 @@ rockchip_thermal_register_sensor(struct platform_device *pdev,
|
|||
int id)
|
||||
{
|
||||
const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
struct device *dev = &pdev->dev;
|
||||
int trim = thermal->trim;
|
||||
int trim_code, tshut_temp;
|
||||
int trim_temp = 0;
|
||||
int error;
|
||||
|
||||
if (thermal->trim_temp)
|
||||
trim_temp = thermal->trim_temp;
|
||||
|
||||
if (tsadc->get_trim_code && sensor->of_node) {
|
||||
error = rockchip_get_efuse_value(sensor->of_node, "trim", &trim);
|
||||
if (error < 0 && error != -ENOENT) {
|
||||
dev_err(dev, "failed reading trim of sensor %d: %pe\n",
|
||||
id, ERR_PTR(error));
|
||||
return error;
|
||||
}
|
||||
if (trim) {
|
||||
trim_code = tsadc->get_trim_code(&tsadc->table, trim,
|
||||
thermal->trim_base,
|
||||
thermal->trim_base_frac);
|
||||
trim_temp = thermal->chip->trim_slope * trim_code;
|
||||
}
|
||||
}
|
||||
|
||||
sensor->trim_temp = trim_temp;
|
||||
|
||||
dev_dbg(dev, "trim of sensor %d is %d\n", id, sensor->trim_temp);
|
||||
|
||||
tshut_temp = min(thermal->tshut_temp + sensor->trim_temp, RK_MAX_TEMP);
|
||||
|
||||
tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
|
||||
|
||||
error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs,
|
||||
thermal->tshut_temp);
|
||||
error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs, tshut_temp);
|
||||
if (error)
|
||||
dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
__func__, thermal->tshut_temp, error);
|
||||
dev_err(dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
__func__, tshut_temp, error);
|
||||
|
||||
sensor->thermal = thermal;
|
||||
sensor->id = id;
|
||||
sensor->tzd = devm_thermal_of_zone_register(&pdev->dev, id, sensor,
|
||||
sensor->tzd = devm_thermal_of_zone_register(dev, id, sensor,
|
||||
&rockchip_of_thermal_ops);
|
||||
if (IS_ERR(sensor->tzd)) {
|
||||
error = PTR_ERR(sensor->tzd);
|
||||
dev_err(&pdev->dev, "failed to register sensor %d: %d\n",
|
||||
dev_err(dev, "failed to register sensor %d: %d\n",
|
||||
id, error);
|
||||
return error;
|
||||
}
|
||||
|
|
@ -1516,9 +1706,11 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct rockchip_thermal_data *thermal;
|
||||
struct device_node *child;
|
||||
int irq;
|
||||
int i;
|
||||
int error;
|
||||
u32 chn;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
|
@ -1569,6 +1761,18 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
|||
thermal->chip->initialize(thermal->grf, thermal->regs,
|
||||
thermal->tshut_polarity);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
if (!of_property_read_u32(child, "reg", &chn)) {
|
||||
if (chn < thermal->chip->chn_num)
|
||||
thermal->sensors[chn].of_node = child;
|
||||
else
|
||||
dev_warn(&pdev->dev,
|
||||
"sensor address (%d) too large, ignoring its trim\n",
|
||||
chn);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < thermal->chip->chn_num; i++) {
|
||||
error = rockchip_thermal_register_sensor(pdev, thermal,
|
||||
&thermal->sensors[i],
|
||||
|
|
@ -1638,8 +1842,11 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
|
|||
static int __maybe_unused rockchip_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct rockchip_thermal_data *thermal = dev_get_drvdata(dev);
|
||||
int i;
|
||||
const struct rockchip_tsadc_chip *tsadc = thermal->chip;
|
||||
struct rockchip_thermal_sensor *sensor;
|
||||
int tshut_temp;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
error = clk_enable(thermal->clk);
|
||||
if (error)
|
||||
|
|
@ -1653,21 +1860,23 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
|
|||
|
||||
rockchip_thermal_reset_controller(thermal->reset);
|
||||
|
||||
thermal->chip->initialize(thermal->grf, thermal->regs,
|
||||
thermal->tshut_polarity);
|
||||
tsadc->initialize(thermal->grf, thermal->regs, thermal->tshut_polarity);
|
||||
|
||||
for (i = 0; i < thermal->chip->chn_num; i++) {
|
||||
int id = thermal->sensors[i].id;
|
||||
sensor = &thermal->sensors[i];
|
||||
|
||||
thermal->chip->set_tshut_mode(id, thermal->regs,
|
||||
tshut_temp = min(thermal->tshut_temp + sensor->trim_temp,
|
||||
RK_MAX_TEMP);
|
||||
|
||||
tsadc->set_tshut_mode(sensor->id, thermal->regs,
|
||||
thermal->tshut_mode);
|
||||
|
||||
error = thermal->chip->set_tshut_temp(&thermal->chip->table,
|
||||
id, thermal->regs,
|
||||
thermal->tshut_temp);
|
||||
error = tsadc->set_tshut_temp(&thermal->chip->table,
|
||||
sensor->id, thermal->regs,
|
||||
tshut_temp);
|
||||
if (error)
|
||||
dev_err(dev, "%s: invalid tshut=%d, error=%d\n",
|
||||
__func__, thermal->tshut_temp, error);
|
||||
__func__, tshut_temp, error);
|
||||
}
|
||||
|
||||
thermal->chip->control(thermal->regs, true);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static inline int thermal_get_temp(struct thermal_zone_device *thermal,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops ops = {
|
||||
static const struct thermal_zone_device_ops ops = {
|
||||
.get_temp = thermal_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ static int st_thermal_get_temp(struct thermal_zone_device *th, int *temperature)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops st_tz_ops = {
|
||||
static const struct thermal_zone_device_ops st_tz_ops = {
|
||||
.get_temp = st_thermal_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1206,7 +1206,7 @@ static const struct irq_domain_ops soctherm_oc_domain_ops = {
|
|||
/**
|
||||
* soctherm_oc_int_init() - Initial enabling of the over
|
||||
* current interrupts
|
||||
* @np: The devicetree node for soctherm
|
||||
* @fwnode: The devicetree node for soctherm
|
||||
* @num_irqs: The number of new interrupt requests
|
||||
*
|
||||
* Sets the over current interrupt request chip data
|
||||
|
|
@ -1215,7 +1215,7 @@ static const struct irq_domain_ops soctherm_oc_domain_ops = {
|
|||
* -ENOMEM (out of memory), or irq_base if the function failed to
|
||||
* allocate the irqs
|
||||
*/
|
||||
static int soctherm_oc_int_init(struct device_node *np, int num_irqs)
|
||||
static int soctherm_oc_int_init(struct fwnode_handle *fwnode, int num_irqs)
|
||||
{
|
||||
if (!num_irqs) {
|
||||
pr_info("%s(): OC interrupts are not enabled\n", __func__);
|
||||
|
|
@ -1234,10 +1234,8 @@ static int soctherm_oc_int_init(struct device_node *np, int num_irqs)
|
|||
soc_irq_cdata.irq_chip.irq_set_type = soctherm_oc_irq_set_type;
|
||||
soc_irq_cdata.irq_chip.irq_set_wake = NULL;
|
||||
|
||||
soc_irq_cdata.domain = irq_domain_create_linear(of_fwnode_handle(np), num_irqs,
|
||||
&soctherm_oc_domain_ops,
|
||||
&soc_irq_cdata);
|
||||
|
||||
soc_irq_cdata.domain = irq_domain_create_linear(fwnode, num_irqs, &soctherm_oc_domain_ops,
|
||||
&soc_irq_cdata);
|
||||
if (!soc_irq_cdata.domain) {
|
||||
pr_err("%s: Failed to create IRQ domain\n", __func__);
|
||||
return -ENOMEM;
|
||||
|
|
@ -1968,10 +1966,9 @@ static void tegra_soctherm_throttle(struct device *dev)
|
|||
static int soctherm_interrupts_init(struct platform_device *pdev,
|
||||
struct tegra_soctherm *tegra)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
ret = soctherm_oc_int_init(np, TEGRA_SOC_OC_IRQ_MAX);
|
||||
ret = soctherm_oc_int_init(dev_fwnode(&pdev->dev), TEGRA_SOC_OC_IRQ_MAX);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "soctherm_oc_int_init failed\n");
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ static int tt_zone_get_temp(struct thermal_zone_device *tz, int *temp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_device_ops tt_zone_ops = {
|
||||
static const struct thermal_zone_device_ops tt_zone_ops = {
|
||||
.get_temp = tt_zone_get_temp,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,10 +40,13 @@ temp_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
ret = thermal_zone_get_temp(tz, &temperature);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!ret)
|
||||
return sprintf(buf, "%d\n", temperature);
|
||||
|
||||
return sprintf(buf, "%d\n", temperature);
|
||||
if (ret == -EAGAIN)
|
||||
return -ENODATA;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user