aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-06 18:10:55 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-06 18:10:55 -0700
commit96e3f3c16b7aedcd71502ccfc5778dddfc2e7b15 (patch)
tree26ca6eb47ec408e69e7225f41f784c58ec660c95 /drivers/thermal
parentMerge tag 'auxdisplay-for-linus-v5.9-rc1' of git://github.com/ojeda/linux (diff)
parentthermal: intel: intel_pch_thermal: Add Cannon Lake Low Power PCH support (diff)
downloadlinux-dev-96e3f3c16b7aedcd71502ccfc5778dddfc2e7b15.tar.xz
linux-dev-96e3f3c16b7aedcd71502ccfc5778dddfc2e7b15.zip
Merge tag 'thermal-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux
Pull thermal updates from Daniel Lezcano: - Add support to enable/disable the thermal zones resulting on core code and drivers cleanup (Andrzej Pietrasiewicz) - Add generic netlink support for userspace notifications: events, temperature and discovery commands (Daniel Lezcano) - Fix redundant initialization for a ret variable (Colin Ian King) - Remove the clock cooling code as it is used nowhere (Amit Kucheria) - Add the rcar_gen3_thermal's r8a774e1 support (Marian-Cristian Rotariu) - Replace all references to thermal.txt in the documentation to the corresponding yaml files (Amit Kucheria) - Add maintainer entry for the IPA (Lukasz Luba) - Add support for MSM8939 for the tsens (Shawn Guo) - Update power allocator and devfreq cooling to SPDX licensing (Lukasz Luba) - Add Cannon Lake Low Power PCH support (Sumeet Pawnikar) - Add tsensor support for V2 mediatek thermal system (Henry Yen) - Fix thermal zone lookup by ID for the core code (Thierry Reding) * tag 'thermal-v5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (40 commits) thermal: intel: intel_pch_thermal: Add Cannon Lake Low Power PCH support thermal: mediatek: Add tsensor support for V2 thermal system thermal: mediatek: Prepare to add support for other platforms thermal: Update power allocator and devfreq cooling to SPDX licensing MAINTAINERS: update entry to thermal governors file name prefixing thermal: core: Add thermal zone enable/disable notification thermal: qcom: tsens-v0_1: Add support for MSM8939 dt-bindings: tsens: qcom: Document MSM8939 compatible thermal: core: Fix thermal zone lookup by ID thermal: int340x: processor_thermal: fix: update Jasper Lake PCI id thermal: imx8mm: Support module autoloading thermal: ti-soc-thermal: Fix reversed condition in ti_thermal_expose_sensor() MAINTAINERS: Add maintenance information for IPA thermal: rcar_gen3_thermal: Do not shadow thcode variable dt-bindings: thermal: Get rid of thermal.txt and replace references thermal: core: Move initialization after core initcall thermal: netlink: Improve the initcall ordering net: genetlink: Move initialization to core_initcall thermal: rcar_gen3_thermal: Add r8a774e1 support thermal/drivers/clock_cooling: Remove clock_cooling code ...
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig20
-rw-r--r--drivers/thermal/Makefile6
-rw-r--r--drivers/thermal/armada_thermal.c6
-rw-r--r--drivers/thermal/clock_cooling.c445
-rw-r--r--drivers/thermal/da9062-thermal.c16
-rw-r--r--drivers/thermal/devfreq_cooling.c10
-rw-r--r--drivers/thermal/dove_thermal.c6
-rw-r--r--drivers/thermal/gov_power_allocator.c9
-rw-r--r--drivers/thermal/hisi_thermal.c6
-rw-r--r--drivers/thermal/imx8mm_thermal.c1
-rw-r--r--drivers/thermal/imx_thermal.c60
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3400_thermal.c38
-rw-r--r--drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c5
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device.c2
-rw-r--r--drivers/thermal/intel/intel_pch_thermal.c8
-rw-r--r--drivers/thermal/intel/intel_quark_dts_thermal.c34
-rw-r--r--drivers/thermal/intel/intel_soc_dts_iosf.c3
-rw-r--r--drivers/thermal/intel/x86_pkg_temp_thermal.c6
-rw-r--r--drivers/thermal/kirkwood_thermal.c7
-rw-r--r--drivers/thermal/mtk_thermal.c234
-rw-r--r--drivers/thermal/qcom/tsens-v0_1.c144
-rw-r--r--drivers/thermal/qcom/tsens.c3
-rw-r--r--drivers/thermal/qcom/tsens.h2
-rw-r--r--drivers/thermal/rcar_gen3_thermal.c10
-rw-r--r--drivers/thermal/rcar_thermal.c9
-rw-r--r--drivers/thermal/rockchip_thermal.c6
-rw-r--r--drivers/thermal/spear_thermal.c7
-rw-r--r--drivers/thermal/sprd_thermal.c6
-rw-r--r--drivers/thermal/st/st_thermal.c5
-rw-r--r--drivers/thermal/thermal_core.c174
-rw-r--r--drivers/thermal/thermal_core.h15
-rw-r--r--drivers/thermal/thermal_helpers.c13
-rw-r--r--drivers/thermal/thermal_netlink.c647
-rw-r--r--drivers/thermal/thermal_netlink.h104
-rw-r--r--drivers/thermal/thermal_of.c41
-rw-r--r--drivers/thermal/thermal_sysfs.c52
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c2
37 files changed, 1424 insertions, 738 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 3eb2348e5242..13991d68c844 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -17,6 +17,16 @@ menuconfig THERMAL
if THERMAL
+config THERMAL_NETLINK
+ bool "Thermal netlink management"
+ depends on NET
+ default y
+ help
+ The thermal framework has a netlink interface to do thermal
+ zones discovery, temperature readings and events such as
+ trip point crossed, cooling device update or governor
+ change. It is recommended to enable the feature.
+
config THERMAL_STATISTICS
bool "Thermal state transition statistics"
help
@@ -180,16 +190,6 @@ config CPU_IDLE_THERMAL
idle cycle.
endif
-config CLOCK_THERMAL
- bool "Generic clock cooling support"
- depends on COMMON_CLK
- depends on PM_OPP
- help
- This entry implements the generic clock cooling mechanism through
- frequency clipping. Typically used to cool off co-processors. The
- device that is configured to use this cooling mechanism will be
- controlled to reduce clock frequency whenever temperature is high.
-
config DEVFREQ_THERMAL
bool "Generic device cooling support"
depends on PM_DEVFREQ
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 0c8b84a09b9a..b8d96d26f9ec 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,6 +7,9 @@ obj-$(CONFIG_THERMAL) += thermal_sys.o
thermal_sys-y += thermal_core.o thermal_sysfs.o \
thermal_helpers.o
+# netlink interface to manage the thermal framework
+thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
+
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o
@@ -22,9 +25,6 @@ thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += gov_power_allocator.o
thermal_sys-$(CONFIG_CPU_FREQ_THERMAL) += cpufreq_cooling.o
thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o
-# clock cooling
-thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o
-
# devfreq cooling
thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 7c447cd149e7..c2ebfb5be4b3 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -874,6 +874,12 @@ static int armada_thermal_probe(struct platform_device *pdev)
return PTR_ERR(tz);
}
+ ret = thermal_zone_device_enable(tz);
+ if (ret) {
+ thermal_zone_device_unregister(tz);
+ return ret;
+ }
+
drvdata->type = LEGACY;
drvdata->data.tz = tz;
platform_set_drvdata(pdev, drvdata);
diff --git a/drivers/thermal/clock_cooling.c b/drivers/thermal/clock_cooling.c
deleted file mode 100644
index 56cb1f46a428..000000000000
--- a/drivers/thermal/clock_cooling.c
+++ /dev/null
@@ -1,445 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * drivers/thermal/clock_cooling.c
- *
- * Copyright (C) 2014 Eduardo Valentin <edubezval@gmail.com>
- *
- * Copyright (C) 2013 Texas Instruments Inc.
- * Contact: Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * Highly based on cpufreq_cooling.c.
- * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
- * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org>
- */
-#include <linux/clk.h>
-#include <linux/clock_cooling.h>
-#include <linux/cpufreq.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/idr.h>
-#include <linux/mutex.h>
-#include <linux/pm_opp.h>
-#include <linux/slab.h>
-#include <linux/thermal.h>
-
-/**
- * struct clock_cooling_device - data for cooling device with clock
- * @id: unique integer value corresponding to each clock_cooling_device
- * registered.
- * @dev: struct device pointer to the device being used to cool off using
- * clock frequencies.
- * @cdev: thermal_cooling_device pointer to keep track of the
- * registered cooling device.
- * @clk_rate_change_nb: reference to notifier block used to receive clock
- * rate changes.
- * @freq_table: frequency table used to keep track of available frequencies.
- * @clock_state: integer value representing the current state of clock
- * cooling devices.
- * @clock_val: integer value representing the absolute value of the clipped
- * frequency.
- * @clk: struct clk reference used to enforce clock limits.
- * @lock: mutex lock to protect this struct.
- *
- * This structure is required for keeping information of each
- * clock_cooling_device registered. In order to prevent corruption of this a
- * mutex @lock is used.
- */
-struct clock_cooling_device {
- int id;
- struct device *dev;
- struct thermal_cooling_device *cdev;
- struct notifier_block clk_rate_change_nb;
- struct cpufreq_frequency_table *freq_table;
- unsigned long clock_state;
- unsigned long clock_val;
- struct clk *clk;
- struct mutex lock; /* lock to protect the content of this struct */
-};
-#define to_clock_cooling_device(x) \
- container_of(x, struct clock_cooling_device, clk_rate_change_nb)
-static DEFINE_IDA(clock_ida);
-
-/* Below code defines functions to be used for clock as cooling device */
-
-enum clock_cooling_property {
- GET_LEVEL,
- GET_FREQ,
- GET_MAXL,
-};
-
-/**
- * clock_cooling_get_property - fetch a property of interest for a give cpu.
- * @ccdev: clock cooling device reference
- * @input: query parameter
- * @output: query return
- * @property: type of query (frequency, level, max level)
- *
- * This is the common function to
- * 1. get maximum clock cooling states
- * 2. translate frequency to cooling state
- * 3. translate cooling state to frequency
- * Note that the code may be not in good shape
- * but it is written in this way in order to:
- * a) reduce duplicate code as most of the code can be shared.
- * b) make sure the logic is consistent when translating between
- * cooling states and frequencies.
- *
- * Return: 0 on success, -EINVAL when invalid parameters are passed.
- */
-static int clock_cooling_get_property(struct clock_cooling_device *ccdev,
- unsigned long input,
- unsigned long *output,
- enum clock_cooling_property property)
-{
- int i;
- unsigned long max_level = 0, level = 0;
- unsigned int freq = CPUFREQ_ENTRY_INVALID;
- int descend = -1;
- struct cpufreq_frequency_table *pos, *table = ccdev->freq_table;
-
- if (!output)
- return -EINVAL;
-
- if (!table)
- return -EINVAL;
-
- cpufreq_for_each_valid_entry(pos, table) {
- /* ignore duplicate entry */
- if (freq == pos->frequency)
- continue;
-
- /* get the frequency order */
- if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
- descend = freq > pos->frequency;
-
- freq = pos->frequency;
- max_level++;
- }
-
- /* No valid cpu frequency entry */
- if (max_level == 0)
- return -EINVAL;
-
- /* max_level is an index, not a counter */
- max_level--;
-
- /* get max level */
- if (property == GET_MAXL) {
- *output = max_level;
- return 0;
- }
-
- if (property == GET_FREQ)
- level = descend ? input : (max_level - input);
-
- i = 0;
- cpufreq_for_each_valid_entry(pos, table) {
- /* ignore duplicate entry */
- if (freq == pos->frequency)
- continue;
-
- /* now we have a valid frequency entry */
- freq = pos->frequency;
-
- if (property == GET_LEVEL && (unsigned int)input == freq) {
- /* get level by frequency */
- *output = descend ? i : (max_level - i);
- return 0;
- }
- if (property == GET_FREQ && level == i) {
- /* get frequency by level */
- *output = freq;
- return 0;
- }
- i++;
- }
-
- return -EINVAL;
-}
-
-/**
- * clock_cooling_get_level - return the cooling level of given clock cooling.
- * @cdev: reference of a thermal cooling device of used as clock cooling device
- * @freq: the frequency of interest
- *
- * This function will match the cooling level corresponding to the
- * requested @freq and return it.
- *
- * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID
- * otherwise.
- */
-unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev,
- unsigned long freq)
-{
- struct clock_cooling_device *ccdev = cdev->devdata;
- unsigned long val;
-
- if (clock_cooling_get_property(ccdev, (unsigned long)freq, &val,
- GET_LEVEL))
- return THERMAL_CSTATE_INVALID;
-
- return val;
-}
-EXPORT_SYMBOL_GPL(clock_cooling_get_level);
-
-/**
- * clock_cooling_get_frequency - get the absolute value of frequency from level.
- * @ccdev: clock cooling device reference
- * @level: cooling level
- *
- * This function matches cooling level with frequency. Based on a cooling level
- * of frequency, equals cooling state of cpu cooling device, it will return
- * the corresponding frequency.
- * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
- *
- * Return: 0 on error, the corresponding frequency otherwise.
- */
-static unsigned long
-clock_cooling_get_frequency(struct clock_cooling_device *ccdev,
- unsigned long level)
-{
- int ret = 0;
- unsigned long freq;
-
- ret = clock_cooling_get_property(ccdev, level, &freq, GET_FREQ);
- if (ret)
- return 0;
-
- return freq;
-}
-
-/**
- * clock_cooling_apply - function to apply frequency clipping.
- * @ccdev: clock_cooling_device pointer containing frequency clipping data.
- * @cooling_state: value of the cooling state.
- *
- * Function used to make sure the clock layer is aware of current thermal
- * limits. The limits are applied by updating the clock rate in case it is
- * higher than the corresponding frequency based on the requested cooling_state.
- *
- * Return: 0 on success, an error code otherwise (-EINVAL in case wrong
- * cooling state).
- */
-static int clock_cooling_apply(struct clock_cooling_device *ccdev,
- unsigned long cooling_state)
-{
- unsigned long clip_freq, cur_freq;
- int ret = 0;
-
- /* Here we write the clipping */
- /* Check if the old cooling action is same as new cooling action */
- if (ccdev->clock_state == cooling_state)
- return 0;
-
- clip_freq = clock_cooling_get_frequency(ccdev, cooling_state);
- if (!clip_freq)
- return -EINVAL;
-
- cur_freq = clk_get_rate(ccdev->clk);
-
- mutex_lock(&ccdev->lock);
- ccdev->clock_state = cooling_state;
- ccdev->clock_val = clip_freq;
- /* enforce clock level */
- if (cur_freq > clip_freq)
- ret = clk_set_rate(ccdev->clk, clip_freq);
- mutex_unlock(&ccdev->lock);
-
- return ret;
-}
-
-/**
- * clock_cooling_clock_notifier - notifier callback on clock rate changes.
- * @nb: struct notifier_block * with callback info.
- * @event: value showing clock event for which this function invoked.
- * @data: callback-specific data
- *
- * Callback to hijack the notification on clock transition.
- * Every time there is a clock change, we intercept all pre change events
- * and block the transition in case the new rate infringes thermal limits.
- *
- * Return: NOTIFY_DONE (success) or NOTIFY_BAD (new_rate > thermal limit).
- */
-static int clock_cooling_clock_notifier(struct notifier_block *nb,
- unsigned long event, void *data)
-{
- struct clk_notifier_data *ndata = data;
- struct clock_cooling_device *ccdev = to_clock_cooling_device(nb);
-
- switch (event) {
- case PRE_RATE_CHANGE:
- /*
- * checks on current state
- * TODO: current method is not best we can find as it
- * allows possibly voltage transitions, in case DVFS
- * layer is also hijacking clock pre notifications.
- */
- if (ndata->new_rate > ccdev->clock_val)
- return NOTIFY_BAD;
- /* fall through */
- case POST_RATE_CHANGE:
- case ABORT_RATE_CHANGE:
- default:
- return NOTIFY_DONE;
- }
-}
-
-/* clock cooling device thermal callback functions are defined below */
-
-/**
- * clock_cooling_get_max_state - callback function to get the max cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: fill this variable with the max cooling state.
- *
- * Callback for the thermal cooling device to return the clock
- * max cooling state.
- *
- * Return: 0 on success, an error code otherwise.
- */
-static int clock_cooling_get_max_state(struct thermal_cooling_device *cdev,
- unsigned long *state)
-{
- struct clock_cooling_device *ccdev = cdev->devdata;
- unsigned long count = 0;
- int ret;
-
- ret = clock_cooling_get_property(ccdev, 0, &count, GET_MAXL);
- if (!ret)
- *state = count;
-
- return ret;
-}
-
-/**
- * clock_cooling_get_cur_state - function to get the current cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: fill this variable with the current cooling state.
- *
- * Callback for the thermal cooling device to return the clock
- * current cooling state.
- *
- * Return: 0 (success)
- */
-static int clock_cooling_get_cur_state(struct thermal_cooling_device *cdev,
- unsigned long *state)
-{
- struct clock_cooling_device *ccdev = cdev->devdata;
-
- *state = ccdev->clock_state;
-
- return 0;
-}
-
-/**
- * clock_cooling_set_cur_state - function to set the current cooling state.
- * @cdev: thermal cooling device pointer.
- * @state: set this variable to the current cooling state.
- *
- * Callback for the thermal cooling device to change the clock cooling
- * current cooling state.
- *
- * Return: 0 on success, an error code otherwise.
- */
-static int clock_cooling_set_cur_state(struct thermal_cooling_device *cdev,
- unsigned long state)
-{
- struct clock_cooling_device *clock_device = cdev->devdata;
-
- return clock_cooling_apply(clock_device, state);
-}
-
-/* Bind clock callbacks to thermal cooling device ops */
-static struct thermal_cooling_device_ops const clock_cooling_ops = {
- .get_max_state = clock_cooling_get_max_state,
- .get_cur_state = clock_cooling_get_cur_state,
- .set_cur_state = clock_cooling_set_cur_state,
-};
-
-/**
- * clock_cooling_register - function to create clock cooling device.
- * @dev: struct device pointer to the device used as clock cooling device.
- * @clock_name: string containing the clock used as cooling mechanism.
- *
- * This interface function registers the clock cooling device with the name
- * "thermal-clock-%x". The cooling device is based on clock frequencies.
- * The struct device is assumed to be capable of DVFS transitions.
- * The OPP layer is used to fetch and fill the available frequencies for
- * the referred device. The ordered frequency table is used to control
- * the clock cooling device cooling states and to limit clock transitions
- * based on the cooling state requested by the thermal framework.
- *
- * Return: a valid struct thermal_cooling_device pointer on success,
- * on failure, it returns a corresponding ERR_PTR().
- */
-struct thermal_cooling_device *
-clock_cooling_register(struct device *dev, const char *clock_name)
-{
- struct thermal_cooling_device *cdev;
- struct clock_cooling_device *ccdev = NULL;
- char dev_name[THERMAL_NAME_LENGTH];
- int ret = 0;
-
- ccdev = devm_kzalloc(dev, sizeof(*ccdev), GFP_KERNEL);
- if (!ccdev)
- return ERR_PTR(-ENOMEM);
-
- mutex_init(&ccdev->lock);
- ccdev->dev = dev;
- ccdev->clk = devm_clk_get(dev, clock_name);
- if (IS_ERR(ccdev->clk))
- return ERR_CAST(ccdev->clk);
-
- ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL);
- if (ret < 0)
- return ERR_PTR(ret);
- ccdev->id = ret;
-
- snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
-
- cdev = thermal_cooling_device_register(dev_name, ccdev,
- &clock_cooling_ops);
- if (IS_ERR(cdev)) {
- ida_simple_remove(&clock_ida, ccdev->id);
- return ERR_PTR(-EINVAL);
- }
- ccdev->cdev = cdev;
- ccdev->clk_rate_change_nb.notifier_call = clock_cooling_clock_notifier;
-
- /* Assuming someone has already filled the opp table for this device */
- ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
- if (ret) {
- ida_simple_remove(&clock_ida, ccdev->id);
- return ERR_PTR(ret);
- }
- ccdev->clock_state = 0;
- ccdev->clock_val = clock_cooling_get_frequency(ccdev, 0);
-
- clk_notifier_register(ccdev->clk, &ccdev->clk_rate_change_nb);
-
- return cdev;
-}
-EXPORT_SYMBOL_GPL(clock_cooling_register);
-
-/**
- * clock_cooling_unregister - function to remove clock cooling device.
- * @cdev: thermal cooling device pointer.
- *
- * This interface function unregisters the "thermal-clock-%x" cooling device.
- */
-void clock_cooling_unregister(struct thermal_cooling_device *cdev)
-{
- struct clock_cooling_device *ccdev;
-
- if (!cdev)
- return;
-
- ccdev = cdev->devdata;
-
- clk_notifier_unregister(ccdev->clk, &ccdev->clk_rate_change_nb);
- dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
-
- thermal_cooling_device_unregister(ccdev->cdev);
- ida_simple_remove(&clock_ida, ccdev->id);
-}
-EXPORT_SYMBOL_GPL(clock_cooling_unregister);
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..4d74994f160a 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
struct da9062 *hw;
struct delayed_work work;
struct thermal_zone_device *zone;
- enum thermal_device_mode mode;
struct mutex lock; /* protection for da9062_thermal temperature */
int temperature;
int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
- enum thermal_device_mode *mode)
-{
- struct da9062_thermal *thermal = z->devdata;
- *mode = thermal->mode;
- return 0;
-}
-
static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
int trip,
enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
static struct thermal_zone_device_ops da9062_thermal_ops = {
.get_temp = da9062_thermal_get_temp,
- .get_mode = da9062_thermal_get_mode,
.get_trip_type = da9062_thermal_get_trip_type,
.get_trip_temp = da9062_thermal_get_trip_temp,
};
@@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
thermal->config = match->data;
thermal->hw = chip;
- thermal->mode = THERMAL_DEVICE_ENABLED;
thermal->dev = &pdev->dev;
INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
@@ -248,6 +237,11 @@ static int da9062_thermal_probe(struct platform_device *pdev)
ret = PTR_ERR(thermal->zone);
goto err;
}
+ ret = thermal_zone_device_enable(thermal->zone);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot enable thermal zone device\n");
+ goto err_zone;
+ }
dev_dbg(&pdev->dev,
"TJUNC temperature polling period set at %d ms\n",
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index f7f32e98331b..a12d29096229 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* devfreq_cooling: Thermal cooling device implementation for devices using
* devfreq
*
* Copyright (C) 2014-2015 ARM Limited
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* TODO:
* - If OPPs are added or removed after devfreq cooling has
* registered, the devfreq cooling won't react to it.
diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
index 75901ced4a62..73182eb94bc0 100644
--- a/drivers/thermal/dove_thermal.c
+++ b/drivers/thermal/dove_thermal.c
@@ -153,6 +153,12 @@ static int dove_thermal_probe(struct platform_device *pdev)
return PTR_ERR(thermal);
}
+ ret = thermal_zone_device_enable(thermal);
+ if (ret) {
+ thermal_zone_device_unregister(thermal);
+ return ret;
+ }
+
platform_set_drvdata(pdev, thermal);
return 0;
diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c
index 44636475b2a3..5cb518d8f156 100644
--- a/drivers/thermal/gov_power_allocator.c
+++ b/drivers/thermal/gov_power_allocator.c
@@ -1,16 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* A power allocator to manage temperature
*
* Copyright (C) 2014 ARM Ltd.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) "Power allocator: " fmt
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 2d26ae80e202..ee05950afd2f 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
{
struct thermal_zone_device *tzd = sensor->tzd;
- tzd->ops->set_mode(tzd,
- on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+ if (on)
+ thermal_zone_device_enable(tzd);
+ else
+ thermal_zone_device_disable(tzd);
}
static int hisi_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
index e6061e26d4ac..f5124f14cf81 100644
--- a/drivers/thermal/imx8mm_thermal.c
+++ b/drivers/thermal/imx8mm_thermal.c
@@ -220,6 +220,7 @@ static const struct of_device_id imx8mm_tmu_table[] = {
{ .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
{ },
};
+MODULE_DEVICE_TABLE(of, imx8mm_tmu_table);
static struct platform_driver imx8mm_tmu = {
.driver = {
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 1b84ea674edb..3f74ab4c1ab9 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
struct cpufreq_policy *policy;
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
- enum thermal_device_mode mode;
struct regmap *tempmon;
u32 c1, c2; /* See formula in imx_init_calib() */
int temp_passive;
@@ -253,10 +252,11 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
unsigned int n_meas;
- bool wait;
+ bool wait, run_measurement;
u32 val;
- if (data->mode == THERMAL_DEVICE_ENABLED) {
+ run_measurement = !data->irq_enabled;
+ if (!run_measurement) {
/* Check if a measurement is currently in progress */
regmap_read(map, soc_data->temp_data, &val);
wait = !(val & soc_data->temp_valid_mask);
@@ -283,7 +283,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
regmap_read(map, soc_data->temp_data, &val);
- if (data->mode != THERMAL_DEVICE_ENABLED) {
+ if (run_measurement) {
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->measure_temp_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,27 +331,14 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
return 0;
}
-static int imx_get_mode(struct thermal_zone_device *tz,
- enum thermal_device_mode *mode)
-{
- struct imx_thermal_data *data = tz->devdata;
-
- *mode = data->mode;
-
- return 0;
-}
-
-static int imx_set_mode(struct thermal_zone_device *tz,
- enum thermal_device_mode mode)
+static int imx_change_mode(struct thermal_zone_device *tz,
+ enum thermal_device_mode mode)
{
struct imx_thermal_data *data = tz->devdata;
struct regmap *map = data->tempmon;
const struct thermal_soc_data *soc_data = data->socdata;
if (mode == THERMAL_DEVICE_ENABLED) {
- tz->polling_delay = IMX_POLLING_DELAY;
- tz->passive_delay = IMX_PASSIVE_DELAY;
-
regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
soc_data->power_down_mask);
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -367,18 +354,12 @@ static int imx_set_mode(struct thermal_zone_device *tz,
regmap_write(map, soc_data->sensor_ctrl + REG_SET,
soc_data->power_down_mask);
- tz->polling_delay = 0;
- tz->passive_delay = 0;
-
if (data->irq_enabled) {
disable_irq(data->irq);
data->irq_enabled = false;
}
}
- data->mode = mode;
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
return 0;
}
@@ -467,8 +448,7 @@ static struct thermal_zone_device_ops imx_tz_ops = {
.bind = imx_bind,
.unbind = imx_unbind,
.get_temp = imx_get_temp,
- .get_mode = imx_get_mode,
- .set_mode = imx_set_mode,
+ .change_mode = imx_change_mode,
.get_trip_type = imx_get_trip_type,
.get_trip_temp = imx_get_trip_temp,
.get_crit_temp = imx_get_crit_temp,
@@ -832,7 +812,9 @@ static int imx_thermal_probe(struct platform_device *pdev)
data->socdata->measure_temp_mask);
data->irq_enabled = true;
- data->mode = THERMAL_DEVICE_ENABLED;
+ ret = thermal_zone_device_enable(data->tz);
+ if (ret)
+ goto thermal_zone_unregister;
ret = devm_request_threaded_irq(&pdev->dev, data->irq,
imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -874,19 +856,18 @@ static int imx_thermal_remove(struct platform_device *pdev)
static int __maybe_unused imx_thermal_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
- struct regmap *map = data->tempmon;
+ int ret;
/*
* Need to disable thermal sensor, otherwise, when thermal core
* try to get temperature before thermal sensor resume, a wrong
* temperature will be read as the thermal sensor is powered
- * down.
+ * down. This is done in change_mode() operation called from
+ * thermal_zone_device_disable()
*/
- regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
- data->socdata->measure_temp_mask);
- regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
- data->socdata->power_down_mask);
- data->mode = THERMAL_DEVICE_DISABLED;
+ ret = thermal_zone_device_disable(data->tz);
+ if (ret)
+ return ret;
clk_disable_unprepare(data->thermal_clk);
return 0;
@@ -895,18 +876,15 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
static int __maybe_unused imx_thermal_resume(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
- struct regmap *map = data->tempmon;
int ret;
ret = clk_prepare_enable(data->thermal_clk);
if (ret)
return ret;
/* Enabled thermal sensor after resume */
- regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
- data->socdata->power_down_mask);
- regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
- data->socdata->measure_temp_mask);
- data->mode = THERMAL_DEVICE_ENABLED;
+ ret = thermal_zone_device_enable(data->tz);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index 12448ccd27f1..4f5859d4c780 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -48,7 +48,6 @@ struct int3400_thermal_priv {
struct acpi_device *adev;
struct platform_device *pdev;
struct thermal_zone_device *thermal;
- int mode;
int art_count;
struct art *arts;
int trt_count;
@@ -383,42 +382,20 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
return 0;
}
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
+static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
{
struct int3400_thermal_priv *priv = thermal->devdata;
-
- if (!priv)
- return -EINVAL;
-
- *mode = priv->mode;
-
- return 0;
-}
-
-static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct int3400_thermal_priv *priv = thermal->devdata;
- bool enable;
int result = 0;
if (!priv)
return -EINVAL;
- if (mode == THERMAL_DEVICE_ENABLED)
- enable = true;
- else if (mode == THERMAL_DEVICE_DISABLED)
- enable = false;
- else
- return -EINVAL;
-
- if (enable != priv->mode) {
- priv->mode = enable;
+ if (mode != thermal->mode)
result = int3400_thermal_run_osc(priv->adev->handle,
- priv->current_uuid_index,
- enable);
- }
+ priv->current_uuid_index,
+ mode == THERMAL_DEVICE_ENABLED);
+
evaluate_odvp(priv);
@@ -427,8 +404,7 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
static struct thermal_zone_device_ops int3400_thermal_ops = {
.get_temp = int3400_thermal_get_temp,
- .get_mode = int3400_thermal_get_mode,
- .set_mode = int3400_thermal_set_mode,
+ .change_mode = int3400_thermal_change_mode,
};
static struct thermal_zone_params int3400_thermal_params = {
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
index 432213272f1e..6e479deff76b 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
@@ -259,9 +259,14 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
ret = PTR_ERR(int34x_thermal_zone->zone);
goto err_thermal_zone;
}
+ ret = thermal_zone_device_enable(int34x_thermal_zone->zone);
+ if (ret)
+ goto err_enable;
return int34x_thermal_zone;
+err_enable:
+ thermal_zone_device_unregister(int34x_thermal_zone->zone);
err_thermal_zone:
acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
kfree(int34x_thermal_zone->aux_trips);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
index 297db1d2d960..81e8b15ef405 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c
@@ -43,7 +43,7 @@
#define PCI_DEVICE_ID_PROC_ICL_THERMAL 0x8a03
/* JasperLake thermal reporting device */
-#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4503
+#define PCI_DEVICE_ID_PROC_JSL_THERMAL 0x4E03
/* TigerLake thermal reporting device */
#define PCI_DEVICE_ID_PROC_TGL_THERMAL 0x9A03
diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c
index 56401fd4708d..3b813ebb6ca1 100644
--- a/drivers/thermal/intel/intel_pch_thermal.c
+++ b/drivers/thermal/intel/intel_pch_thermal.c
@@ -24,6 +24,7 @@
#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
#define PCH_THERMAL_DID_CNL 0x9Df9 /* CNL PCH */
#define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */
+#define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */
#define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */
/* Wildcat Point-LP PCH Thermal registers */
@@ -352,9 +353,14 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev,
err = PTR_ERR(ptd->tzd);
goto error_cleanup;
}
+ err = thermal_zone_device_enable(ptd->tzd);
+ if (err)
+ goto err_unregister;
return 0;
+err_unregister:
+ thermal_zone_device_unregister(ptd->tzd);
error_cleanup:
iounmap(ptd->hw_base);
error_release:
@@ -405,6 +411,8 @@ static const struct pci_device_id intel_pch_thermal_id[] = {
.driver_data = board_cnl, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_H),
.driver_data = board_cnl, },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CNL_LP),
+ .driver_data = board_cnl, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H),
.driver_data = board_cml, },
{ 0, },
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..3eafc6b0e6c3 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
bool locked;
u32 store_ptps;
u32 store_dts_enable;
- enum thermal_device_mode mode;
struct thermal_zone_device *tzone;
};
@@ -127,10 +126,8 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
if (ret)
return ret;
- if (out & QRK_DTS_ENABLE_BIT) {
- aux_entry->mode = THERMAL_DEVICE_ENABLED;
+ if (out & QRK_DTS_ENABLE_BIT)
return 0;
- }
if (!aux_entry->locked) {
out |= QRK_DTS_ENABLE_BIT;
@@ -138,10 +135,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
QRK_DTS_REG_OFFSET_ENABLE, out);
if (ret)
return ret;
-
- aux_entry->mode = THERMAL_DEVICE_ENABLED;
} else {
- aux_entry->mode = THERMAL_DEVICE_DISABLED;
pr_info("DTS is locked. Cannot enable DTS\n");
ret = -EPERM;
}
@@ -160,10 +154,8 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
if (ret)
return ret;
- if (!(out & QRK_DTS_ENABLE_BIT)) {
- aux_entry->mode = THERMAL_DEVICE_DISABLED;
+ if (!(out & QRK_DTS_ENABLE_BIT))
return 0;
- }
if (!aux_entry->locked) {
out &= ~QRK_DTS_ENABLE_BIT;
@@ -172,10 +164,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
if (ret)
return ret;
-
- aux_entry->mode = THERMAL_DEVICE_DISABLED;
} else {
- aux_entry->mode = THERMAL_DEVICE_ENABLED;
pr_info("DTS is locked. Cannot disable DTS\n");
ret = -EPERM;
}
@@ -309,16 +298,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
return 0;
}
-static int sys_get_mode(struct thermal_zone_device *tzd,
- enum thermal_device_mode *mode)
-{
- struct soc_sensor_entry *aux_entry = tzd->devdata;
- *mode = aux_entry->mode;
- return 0;
-}
-
-static int sys_set_mode(struct thermal_zone_device *tzd,
- enum thermal_device_mode mode)
+static int sys_change_mode(struct thermal_zone_device *tzd,
+ enum thermal_device_mode mode)
{
int ret;
@@ -338,8 +319,7 @@ static struct thermal_zone_device_ops tzone_ops = {
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
.get_crit_temp = sys_get_crit_temp,
- .get_mode = sys_get_mode,
- .set_mode = sys_set_mode,
+ .change_mode = sys_change_mode,
};
static void free_soc_dts(struct soc_sensor_entry *aux_entry)
@@ -414,9 +394,7 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
goto err_ret;
}
- mutex_lock(&dts_update_mutex);
- err = soc_dts_enable(aux_entry->tzone);
- mutex_unlock(&dts_update_mutex);
+ err = thermal_zone_device_enable(aux_entry->tzone);
if (err)
goto err_aux_status;
diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c
index f75271b669c6..4f1a2f7c016c 100644
--- a/drivers/thermal/intel/intel_soc_dts_iosf.c
+++ b/drivers/thermal/intel/intel_soc_dts_iosf.c
@@ -329,6 +329,9 @@ static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
ret = PTR_ERR(dts->tzone);
goto err_ret;
}
+ ret = thermal_zone_device_enable(dts->tzone);
+ if (ret)
+ goto err_enable;
ret = soc_dts_enable(id);
if (ret)
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index a006b9fd1d72..b81c33202f41 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -363,6 +363,12 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
kfree(zonedev);
return err;
}
+ err = thermal_zone_device_enable(zonedev->tzone);
+ if (err) {
+ thermal_zone_device_unregister(zonedev->tzone);
+ kfree(zonedev);
+ return err;
+ }
/* Store MSR value for package thermal interrupt, to restore at exit */
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, zonedev->msr_pkg_therm_low,
zonedev->msr_pkg_therm_high);
diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c
index 189b675cf14d..7fb6e476c82a 100644
--- a/drivers/thermal/kirkwood_thermal.c
+++ b/drivers/thermal/kirkwood_thermal.c
@@ -65,6 +65,7 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
struct thermal_zone_device *thermal = NULL;
struct kirkwood_thermal_priv *priv;
struct resource *res;
+ int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -82,6 +83,12 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
"Failed to register thermal zone device\n");
return PTR_ERR(thermal);
}
+ ret = thermal_zone_device_enable(thermal);
+ if (ret) {
+ thermal_zone_device_unregister(thermal);
+ dev_err(&pdev->dev, "Failed to enable thermal zone device\n");
+ return ret;
+ }
platform_set_drvdata(pdev, thermal);
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 42c9cd0e5f77..0bd7aa564bc2 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -38,6 +38,7 @@
#define TEMP_MONIDET0 0x014
#define TEMP_MONIDET1 0x018
#define TEMP_MSRCTL0 0x038
+#define TEMP_MSRCTL1 0x03c
#define TEMP_AHBPOLL 0x040
#define TEMP_AHBTO 0x044
#define TEMP_ADCPNP0 0x048
@@ -120,18 +121,32 @@
* MT2701 has 3 sensors and needs 3 VTS calibration data.
* MT2712 has 4 sensors and needs 4 VTS calibration data.
*/
-#define CALIB_BUF0_VALID BIT(0)
-#define CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff)
-#define CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff)
-#define CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff)
-#define CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff)
-#define CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff)
-#define CALIB_BUF2_VTS_TS5(x) (((x) >> 5) & 0x1ff)
-#define CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff)
-#define CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f)
-#define CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f)
-#define CALIB_BUF0_O_SLOPE_SIGN(x) (((x) >> 7) & 0x1)
-#define CALIB_BUF1_ID(x) (((x) >> 9) & 0x1)
+#define CALIB_BUF0_VALID_V1 BIT(0)
+#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff)
+#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff)
+#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff)
+#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff)
+#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff)
+#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff)
+#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff)
+#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1)
+#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1)
+
+/*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT7622.
+ */
+#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff)
+#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff)
+#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f)
+#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff)
+#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff)
+#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff)
+#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1)
+#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1)
enum {
VTS1,
@@ -143,6 +158,11 @@ enum {
MAX_NUM_VTS,
};
+enum mtk_thermal_version {
+ MTK_THERMAL_V1 = 1,
+ MTK_THERMAL_V2,
+};
+
/* MT2701 thermal sensors */
#define MT2701_TS1 0
#define MT2701_TS2 1
@@ -248,6 +268,7 @@ struct mtk_thermal_data {
const int *controller_offset;
bool need_switch_bank;
struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+ enum mtk_thermal_version version;
};
struct mtk_thermal {
@@ -261,8 +282,10 @@ struct mtk_thermal {
/* Calibration values */
s32 adc_ge;
+ s32 adc_oe;
s32 degc_cali;
s32 o_slope;
+ s32 o_slope_sign;
s32 vts[MAX_NUM_VTS];
const struct mtk_thermal_data *conf;
@@ -401,6 +424,7 @@ static const struct mtk_thermal_data mt8173_thermal_data = {
.msr = mt8173_msr,
.adcpnp = mt8173_adcpnp,
.sensor_mux_values = mt8173_mux_values,
+ .version = MTK_THERMAL_V1,
};
/*
@@ -431,6 +455,7 @@ static const struct mtk_thermal_data mt2701_thermal_data = {
.msr = mt2701_msr,
.adcpnp = mt2701_adcpnp,
.sensor_mux_values = mt2701_mux_values,
+ .version = MTK_THERMAL_V1,
};
/*
@@ -461,6 +486,7 @@ static const struct mtk_thermal_data mt2712_thermal_data = {
.msr = mt2712_msr,
.adcpnp = mt2712_adcpnp,
.sensor_mux_values = mt2712_mux_values,
+ .version = MTK_THERMAL_V1,
};
/*
@@ -485,6 +511,7 @@ static const struct mtk_thermal_data mt7622_thermal_data = {
.msr = mt7622_msr,
.adcpnp = mt7622_adcpnp,
.sensor_mux_values = mt7622_mux_values,
+ .version = MTK_THERMAL_V2,
};
/*
@@ -517,6 +544,7 @@ static const struct mtk_thermal_data mt8183_thermal_data = {
.msr = mt8183_msr,
.adcpnp = mt8183_adcpnp,
.sensor_mux_values = mt8183_mux_values,
+ .version = MTK_THERMAL_V1,
};
/**
@@ -528,7 +556,7 @@ static const struct mtk_thermal_data mt8183_thermal_data = {
* This converts the raw ADC value to mcelsius using the SoC specific
* calibration constants
*/
-static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw)
+static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
{
s32 tmp;
@@ -543,6 +571,36 @@ static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw)
return mt->degc_cali * 500 - tmp;
}
+static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
+{
+ s32 format_1 = 0;
+ s32 format_2 = 0;
+ s32 g_oe = 1;
+ s32 g_gain = 1;
+ s32 g_x_roomt = 0;
+ s32 tmp = 0;
+
+ if (raw == 0)
+ return 0;
+
+ raw &= 0xfff;
+ g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
+ g_oe = mt->adc_oe - 512;
+ format_1 = mt->vts[VTS2] + 3105 - g_oe;
+ format_2 = (mt->degc_cali * 10) >> 1;
+ g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
+
+ tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
+ tmp = tmp * 10 * 100 / 11;
+
+ if (mt->o_slope_sign == 0)
+ tmp = tmp / (165 - mt->o_slope);
+ else
+ tmp = tmp / (165 + mt->o_slope);
+
+ return (format_2 - tmp) * 100;
+}
+
/**
* mtk_thermal_get_bank - get bank
* @bank: The bank
@@ -596,9 +654,13 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
raw = readl(mt->thermal_base + conf->msr[i]);
- temp = raw_to_mcelsius(mt,
- conf->bank_data[bank->id].sensors[i],
- raw);
+ if (mt->conf->version == MTK_THERMAL_V1) {
+ temp = raw_to_mcelsius_v1(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+ } else {
+ temp = raw_to_mcelsius_v2(
+ mt, conf->bank_data[bank->id].sensors[i], raw);
+ }
/*
* The first read of a sensor often contains very high bogus
@@ -700,9 +762,11 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
controller_base + TEMP_ADCMUXADDR);
- /* AHB address for pnp sensor mux selection */
- writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
- controller_base + TEMP_PNPMUXADDR);
+ if (mt->conf->version == MTK_THERMAL_V1) {
+ /* AHB address for pnp sensor mux selection */
+ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
+ controller_base + TEMP_PNPMUXADDR);
+ }
/* AHB value for auxadc enable */
writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
@@ -759,6 +823,68 @@ static u64 of_get_phys_base(struct device_node *np)
return of_translate_address(np, regaddr_p);
}
+static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
+{
+ int i;
+
+ if (!(buf[0] & CALIB_BUF0_VALID_V1))
+ return -EINVAL;
+
+ mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
+
+ for (i = 0; i < mt->conf->num_sensors; i++) {
+ switch (mt->conf->vts_index[i]) {
+ case VTS1:
+ mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
+ break;
+ case VTS2:
+ mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
+ break;
+ case VTS3:
+ mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
+ break;
+ case VTS4:
+ mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
+ break;
+ case VTS5:
+ mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
+ break;
+ case VTSABB:
+ mt->vts[VTSABB] =
+ CALIB_BUF2_VTS_TSABB_V1(buf[2]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
+ if (CALIB_BUF1_ID_V1(buf[1]) &
+ CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
+ mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
+ else
+ mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
+
+ return 0;
+}
+
+static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
+{
+ if (!CALIB_BUF1_VALID_V2(buf[1]))
+ return -EINVAL;
+
+ mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
+ mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
+ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
+ mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
+ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
+ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
+ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
+ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
+
+ return 0;
+}
+
static int mtk_thermal_get_calibration_data(struct device *dev,
struct mtk_thermal *mt)
{
@@ -794,42 +920,14 @@ static int mtk_thermal_get_calibration_data(struct device *dev,
goto out;
}
- if (buf[0] & CALIB_BUF0_VALID) {
- mt->adc_ge = CALIB_BUF1_ADC_GE(buf[1]);
-
- for (i = 0; i < mt->conf->num_sensors; i++) {
- switch (mt->conf->vts_index[i]) {
- case VTS1:
- mt->vts[VTS1] = CALIB_BUF0_VTS_TS1(buf[0]);
- break;
- case VTS2:
- mt->vts[VTS2] = CALIB_BUF0_VTS_TS2(buf[0]);
- break;
- case VTS3:
- mt->vts[VTS3] = CALIB_BUF1_VTS_TS3(buf[1]);
- break;
- case VTS4:
- mt->vts[VTS4] = CALIB_BUF2_VTS_TS4(buf[2]);
- break;
- case VTS5:
- mt->vts[VTS5] = CALIB_BUF2_VTS_TS5(buf[2]);
- break;
- case VTSABB:
- mt->vts[VTSABB] = CALIB_BUF2_VTS_TSABB(buf[2]);
- break;
- default:
- break;
- }
- }
+ if (mt->conf->version == MTK_THERMAL_V1)
+ ret = mtk_thermal_extract_efuse_v1(mt, buf);
+ else
+ ret = mtk_thermal_extract_efuse_v2(mt, buf);
- mt->degc_cali = CALIB_BUF0_DEGC_CALI(buf[0]);
- if (CALIB_BUF1_ID(buf[1]) &
- CALIB_BUF0_O_SLOPE_SIGN(buf[0]))
- mt->o_slope = -CALIB_BUF0_O_SLOPE(buf[0]);
- else
- mt->o_slope = CALIB_BUF0_O_SLOPE(buf[0]);
- } else {
+ if (ret) {
dev_info(dev, "Device not calibrated, using default calibration values\n");
+ ret = 0;
}
out:
@@ -863,6 +961,28 @@ static const struct of_device_id mtk_thermal_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
+{
+ int tmp;
+
+ tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+ tmp &= ~(0x37);
+ tmp |= 0x1;
+ writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
+ udelay(200);
+}
+
+static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
+ void __iomem *auxadc_base)
+{
+ int tmp;
+
+ writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
+ writel(0x1, mt->thermal_base + TEMP_MONCTL0);
+ tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
+ writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
+}
+
static int mtk_thermal_probe(struct platform_device *pdev)
{
int ret, i, ctrl_id;
@@ -871,6 +991,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
struct resource *res;
u64 auxadc_phys_base, apmixed_phys_base;
struct thermal_zone_device *tzdev;
+ void __iomem *apmixed_base, *auxadc_base;
mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
if (!mt)
@@ -905,6 +1026,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
return -ENODEV;
}
+ auxadc_base = of_iomap(auxadc, 0);
auxadc_phys_base = of_get_phys_base(auxadc);
of_node_put(auxadc);
@@ -920,6 +1042,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
return -ENODEV;
}
+ apmixed_base = of_iomap(apmixedsys, 0);
apmixed_phys_base = of_get_phys_base(apmixedsys);
of_node_put(apmixedsys);
@@ -945,6 +1068,11 @@ static int mtk_thermal_probe(struct platform_device *pdev)
goto err_disable_clk_auxadc;
}
+ if (mt->conf->version == MTK_THERMAL_V2) {
+ mtk_thermal_turn_on_buffer(apmixed_base);
+ mtk_thermal_release_periodic_ts(mt, auxadc_base);
+ }
+
for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
for (i = 0; i < mt->conf->num_banks; i++)
mtk_thermal_init_bank(mt, i, apmixed_phys_base,
diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c
index 959a9371d205..e64db5f80d90 100644
--- a/drivers/thermal/qcom/tsens-v0_1.c
+++ b/drivers/thermal/qcom/tsens-v0_1.c
@@ -48,6 +48,63 @@
#define MSM8916_CAL_SEL_MASK 0xe0000000
#define MSM8916_CAL_SEL_SHIFT 29
+/* eeprom layout data for 8939 */
+#define MSM8939_BASE0_MASK 0x000000ff
+#define MSM8939_BASE1_MASK 0xff000000
+#define MSM8939_BASE0_SHIFT 0
+#define MSM8939_BASE1_SHIFT 24
+
+#define MSM8939_S0_P1_MASK 0x000001f8
+#define MSM8939_S1_P1_MASK 0x001f8000
+#define MSM8939_S2_P1_MASK_0_4 0xf8000000
+#define MSM8939_S2_P1_MASK_5 0x00000001
+#define MSM8939_S3_P1_MASK 0x00001f80
+#define MSM8939_S4_P1_MASK 0x01f80000
+#define MSM8939_S5_P1_MASK 0x00003f00
+#define MSM8939_S6_P1_MASK 0x03f00000
+#define MSM8939_S7_P1_MASK 0x0000003f
+#define MSM8939_S8_P1_MASK 0x0003f000
+#define MSM8939_S9_P1_MASK 0x07e00000
+
+#define MSM8939_S0_P2_MASK 0x00007e00
+#define MSM8939_S1_P2_MASK 0x07e00000
+#define MSM8939_S2_P2_MASK 0x0000007e
+#define MSM8939_S3_P2_MASK 0x0007e000
+#define MSM8939_S4_P2_MASK 0x7e000000
+#define MSM8939_S5_P2_MASK 0x000fc000
+#define MSM8939_S6_P2_MASK 0xfc000000
+#define MSM8939_S7_P2_MASK 0x00000fc0
+#define MSM8939_S8_P2_MASK 0x00fc0000
+#define MSM8939_S9_P2_MASK_0_4 0xf8000000
+#define MSM8939_S9_P2_MASK_5 0x00002000
+
+#define MSM8939_S0_P1_SHIFT 3
+#define MSM8939_S1_P1_SHIFT 15
+#define MSM8939_S2_P1_SHIFT_0_4 27
+#define MSM8939_S2_P1_SHIFT_5 0
+#define MSM8939_S3_P1_SHIFT 7
+#define MSM8939_S4_P1_SHIFT 19
+#define MSM8939_S5_P1_SHIFT 8
+#define MSM8939_S6_P1_SHIFT 20
+#define MSM8939_S7_P1_SHIFT 0
+#define MSM8939_S8_P1_SHIFT 12
+#define MSM8939_S9_P1_SHIFT 21
+
+#define MSM8939_S0_P2_SHIFT 9
+#define MSM8939_S1_P2_SHIFT 21
+#define MSM8939_S2_P2_SHIFT 1
+#define MSM8939_S3_P2_SHIFT 13
+#define MSM8939_S4_P2_SHIFT 25
+#define MSM8939_S5_P2_SHIFT 14
+#define MSM8939_S6_P2_SHIFT 26
+#define MSM8939_S7_P2_SHIFT 6
+#define MSM8939_S8_P2_SHIFT 18
+#define MSM8939_S9_P2_SHIFT_0_4 27
+#define MSM8939_S9_P2_SHIFT_5 13
+
+#define MSM8939_CAL_SEL_MASK 0x7
+#define MSM8939_CAL_SEL_SHIFT 0
+
/* eeprom layout data for 8974 */
#define BASE1_MASK 0xff
#define S0_P1_MASK 0x3f00
@@ -189,6 +246,76 @@ static int calibrate_8916(struct tsens_priv *priv)
return 0;
}
+static int calibrate_8939(struct tsens_priv *priv)
+{
+ int base0 = 0, base1 = 0, i;
+ u32 p1[10], p2[10];
+ int mode = 0;
+ u32 *qfprom_cdata;
+ u32 cdata[6];
+
+ qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
+ if (IS_ERR(qfprom_cdata))
+ return PTR_ERR(qfprom_cdata);
+
+ /* Mapping between qfprom nvmem and calibration data */
+ cdata[0] = qfprom_cdata[12];
+ cdata[1] = qfprom_cdata[13];
+ cdata[2] = qfprom_cdata[0];
+ cdata[3] = qfprom_cdata[1];
+ cdata[4] = qfprom_cdata[22];
+ cdata[5] = qfprom_cdata[21];
+
+ mode = (cdata[0] & MSM8939_CAL_SEL_MASK) >> MSM8939_CAL_SEL_SHIFT;
+ dev_dbg(priv->dev, "calibration mode is %d\n", mode);
+
+ switch (mode) {
+ case TWO_PT_CALIB:
+ base1 = (cdata[3] & MSM8939_BASE1_MASK) >> MSM8939_BASE1_SHIFT;
+ p2[0] = (cdata[0] & MSM8939_S0_P2_MASK) >> MSM8939_S0_P2_SHIFT;
+ p2[1] = (cdata[0] & MSM8939_S1_P2_MASK) >> MSM8939_S1_P2_SHIFT;
+ p2[2] = (cdata[1] & MSM8939_S2_P2_MASK) >> MSM8939_S2_P2_SHIFT;
+ p2[3] = (cdata[1] & MSM8939_S3_P2_MASK) >> MSM8939_S3_P2_SHIFT;
+ p2[4] = (cdata[1] & MSM8939_S4_P2_MASK) >> MSM8939_S4_P2_SHIFT;
+ p2[5] = (cdata[2] & MSM8939_S5_P2_MASK) >> MSM8939_S5_P2_SHIFT;
+ p2[6] = (cdata[2] & MSM8939_S6_P2_MASK) >> MSM8939_S6_P2_SHIFT;
+ p2[7] = (cdata[3] & MSM8939_S7_P2_MASK) >> MSM8939_S7_P2_SHIFT;
+ p2[8] = (cdata[3] & MSM8939_S8_P2_MASK) >> MSM8939_S8_P2_SHIFT;
+ p2[9] = (cdata[4] & MSM8939_S9_P2_MASK_0_4) >> MSM8939_S9_P2_SHIFT_0_4;
+ p2[9] |= ((cdata[5] & MSM8939_S9_P2_MASK_5) >> MSM8939_S9_P2_SHIFT_5) << 5;
+ for (i = 0; i < priv->num_sensors; i++)
+ p2[i] = (base1 + p2[i]) << 2;
+ fallthrough;
+ case ONE_PT_CALIB2:
+ base0 = (cdata[2] & MSM8939_BASE0_MASK) >> MSM8939_BASE0_SHIFT;
+ p1[0] = (cdata[0] & MSM8939_S0_P1_MASK) >> MSM8939_S0_P1_SHIFT;
+ p1[1] = (cdata[0] & MSM8939_S1_P1_MASK) >> MSM8939_S1_P1_SHIFT;
+ p1[2] = (cdata[0] & MSM8939_S2_P1_MASK_0_4) >> MSM8939_S2_P1_SHIFT_0_4;
+ p1[2] |= ((cdata[1] & MSM8939_S2_P1_MASK_5) >> MSM8939_S2_P1_SHIFT_5) << 5;
+ p1[3] = (cdata[1] & MSM8939_S3_P1_MASK) >> MSM8939_S3_P1_SHIFT;
+ p1[4] = (cdata[1] & MSM8939_S4_P1_MASK) >> MSM8939_S4_P1_SHIFT;
+ p1[5] = (cdata[2] & MSM8939_S5_P1_MASK) >> MSM8939_S5_P1_SHIFT;
+ p1[6] = (cdata[2] & MSM8939_S6_P1_MASK) >> MSM8939_S6_P1_SHIFT;
+ p1[7] = (cdata[3] & MSM8939_S7_P1_MASK) >> MSM8939_S7_P1_SHIFT;
+ p1[8] = (cdata[3] & MSM8939_S8_P1_MASK) >> MSM8939_S8_P1_SHIFT;
+ p1[9] = (cdata[4] & MSM8939_S9_P1_MASK) >> MSM8939_S9_P1_SHIFT;
+ for (i = 0; i < priv->num_sensors; i++)
+ p1[i] = ((base0) + p1[i]) << 2;
+ break;
+ default:
+ for (i = 0; i < priv->num_sensors; i++) {
+ p1[i] = 500;
+ p2[i] = 780;
+ }
+ break;
+ }
+
+ compute_intercept_slope(priv, p1, p2, mode);
+ kfree(qfprom_cdata);
+
+ return 0;
+}
+
static int calibrate_8974(struct tsens_priv *priv)
{
int base1 = 0, base2 = 0, i;
@@ -325,7 +452,7 @@ static int calibrate_8974(struct tsens_priv *priv)
return 0;
}
-/* v0.1: 8916, 8974 */
+/* v0.1: 8916, 8939, 8974 */
static struct tsens_features tsens_v0_1_feat = {
.ver_major = VER_0_1,
@@ -386,6 +513,21 @@ struct tsens_plat_data data_8916 = {
.fields = tsens_v0_1_regfields,
};
+static const struct tsens_ops ops_8939 = {
+ .init = init_common,
+ .calibrate = calibrate_8939,
+ .get_temp = get_temp_common,
+};
+
+struct tsens_plat_data data_8939 = {
+ .num_sensors = 10,
+ .ops = &ops_8939,
+ .hw_ids = (unsigned int []){ 0, 1, 2, 4, 5, 6, 7, 8, 9, 10 },
+
+ .feat = &tsens_v0_1_feat,
+ .fields = tsens_v0_1_regfields,
+};
+
static const struct tsens_ops ops_8974 = {
.init = init_common,
.calibrate = calibrate_8974,
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 39c4462e38f6..d8ce3a687b80 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -898,6 +898,9 @@ static const struct of_device_id tsens_table[] = {
.compatible = "qcom,msm8916-tsens",
.data = &data_8916,
}, {
+ .compatible = "qcom,msm8939-tsens",
+ .data = &data_8939,
+ }, {
.compatible = "qcom,msm8974-tsens",
.data = &data_8974,
}, {
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 59d01162c66a..f40b625f897e 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -585,7 +585,7 @@ int get_temp_common(const struct tsens_sensor *s, int *temp);
extern struct tsens_plat_data data_8960;
/* TSENS v0.1 targets */
-extern struct tsens_plat_data data_8916, data_8974;
+extern struct tsens_plat_data data_8916, data_8939, data_8974;
/* TSENS v1 targets */
extern struct tsens_plat_data data_tsens_v1, data_8976;
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index c48c5e9b8f20..0dd47dca3e77 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -63,7 +63,7 @@
#define TSC_MAX_NUM 3
/* default THCODE values if FUSEs are missing */
-static const int thcode[TSC_MAX_NUM][3] = {
+static const int thcodes[TSC_MAX_NUM][3] = {
{ 3397, 2800, 2221 },
{ 3393, 2795, 2216 },
{ 3389, 2805, 2237 },
@@ -172,7 +172,7 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
/* Read register and convert to mili Celsius */
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
- if (reg <= thcode[tsc->id][1])
+ if (reg <= thcodes[tsc->id][1])
val = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1,
tsc->coef.a1);
else
@@ -315,6 +315,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
.data = &rcar_gen3_ths_tj_1,
},
{
+ .compatible = "renesas,r8a774e1-thermal",
+ .data = &rcar_gen3_ths_tj_1,
+ },
+ {
.compatible = "renesas,r8a7795-thermal",
.data = &rcar_gen3_ths_tj_1,
},
@@ -430,7 +434,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
priv->tscs[i] = tsc;
priv->thermal_init(tsc);
- rcar_gen3_thermal_calc_coefs(tsc, ptat, thcode[i],
+ rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i],
*rcar_gen3_ths_tj_1);
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 46aeb28b4e90..787710bb88fe 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -550,12 +550,19 @@ static int rcar_thermal_probe(struct platform_device *pdev)
priv->zone = devm_thermal_zone_of_sensor_register(
dev, i, priv,
&rcar_thermal_zone_of_ops);
- else
+ else {
priv->zone = thermal_zone_device_register(
"rcar_thermal",
1, 0, priv,
&rcar_thermal_zone_ops, NULL, 0,
idle);
+
+ ret = thermal_zone_device_enable(priv->zone);
+ if (ret) {
+ thermal_zone_device_unregister(priv->zone);
+ priv->zone = ERR_PTR(ret);
+ }
+ }
if (IS_ERR(priv->zone)) {
dev_err(dev, "can't register thermal zone\n");
ret = PTR_ERR(priv->zone);
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 15a71ecc916c..aa9e0e31ef98 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
{
struct thermal_zone_device *tzd = sensor->tzd;
- tzd->ops->set_mode(tzd,
- on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+ if (on)
+ thermal_zone_device_enable(tzd);
+ else
+ thermal_zone_device_disable(tzd);
}
static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index f68f581fd669..ee33ed692e4f 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -131,6 +131,11 @@ static int spear_thermal_probe(struct platform_device *pdev)
ret = PTR_ERR(spear_thermal);
goto disable_clk;
}
+ ret = thermal_zone_device_enable(spear_thermal);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot enable thermal zone\n");
+ goto unregister_tzd;
+ }
platform_set_drvdata(pdev, spear_thermal);
@@ -139,6 +144,8 @@ static int spear_thermal_probe(struct platform_device *pdev)
return 0;
+unregister_tzd:
+ thermal_zone_device_unregister(spear_thermal);
disable_clk:
clk_disable(stdev->clk);
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index 4cde70dcf655..3682edb2f466 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
{
struct thermal_zone_device *tzd = sen->tzd;
- tzd->ops->set_mode(tzd,
- on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+ if (on)
+ thermal_zone_device_enable(tzd);
+ else
+ thermal_zone_device_disable(tzd);
}
static int sprd_thm_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c
index b928ca6a289b..1276b95604fe 100644
--- a/drivers/thermal/st/st_thermal.c
+++ b/drivers/thermal/st/st_thermal.c
@@ -246,11 +246,16 @@ int st_thermal_register(struct platform_device *pdev,
ret = PTR_ERR(sensor->thermal_dev);
goto sensor_off;
}
+ ret = thermal_zone_device_enable(sensor->thermal_dev);
+ if (ret)
+ goto tzd_unregister;
platform_set_drvdata(pdev, sensor);
return 0;
+tzd_unregister:
+ thermal_zone_device_unregister(sensor->thermal_dev);
sensor_off:
st_thermal_sensor_off(sensor);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index b71196eaf90e..72bf159bcecc 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -215,6 +215,8 @@ exit:
mutex_unlock(&tz->lock);
mutex_unlock(&thermal_governor_lock);
+ thermal_notify_tz_gov_change(tz->id, policy);
+
return ret;
}
@@ -301,13 +303,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
cancel_delayed_work(&tz->poll_queue);
}
+static inline bool should_stop_polling(struct thermal_zone_device *tz)
+{
+ return !thermal_zone_device_is_enabled(tz);
+}
+
static void monitor_thermal_zone(struct thermal_zone_device *tz)
{
+ bool stop;
+
+ stop = should_stop_polling(tz);
+
mutex_lock(&tz->lock);
- if (tz->passive)
+ if (!stop && tz->passive)
thermal_zone_device_set_polling(tz, tz->passive_delay);
- else if (tz->polling_delay)
+ else if (!stop && tz->polling_delay)
thermal_zone_device_set_polling(tz, tz->polling_delay);
else
thermal_zone_device_set_polling(tz, 0);
@@ -406,12 +417,25 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
+ int trip_temp, hyst = 0;
/* Ignore disabled trip points */
if (test_bit(trip, &tz->trips_disabled))
return;
+ tz->ops->get_trip_temp(tz, trip, &trip_temp);
tz->ops->get_trip_type(tz, trip, &type);
+ if (tz->ops->get_trip_hyst)
+ tz->ops->get_trip_hyst(tz, trip, &hyst);
+
+ if (tz->last_temperature != THERMAL_TEMP_INVALID) {
+ if (tz->last_temperature < trip_temp &&
+ tz->temperature >= trip_temp)
+ thermal_notify_tz_trip_up(tz->id, trip);
+ if (tz->last_temperature >= trip_temp &&
+ tz->temperature < (trip_temp - hyst))
+ thermal_notify_tz_trip_down(tz->id, trip);
+ }
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
handle_critical_trips(tz, trip, type);
@@ -443,6 +467,8 @@ static void update_temperature(struct thermal_zone_device *tz)
mutex_unlock(&tz->lock);
trace_thermal_temperature(tz);
+
+ thermal_genl_sampling_temp(tz->id, temp);
}
static void thermal_zone_device_init(struct thermal_zone_device *tz)
@@ -459,11 +485,71 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
thermal_zone_device_init(tz);
}
+static int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+ enum thermal_device_mode mode)
+{
+ int ret = 0;
+
+ mutex_lock(&tz->lock);
+
+ /* do nothing if mode isn't changing */
+ if (mode == tz->mode) {
+ mutex_unlock(&tz->lock);
+
+ return ret;
+ }
+
+ if (tz->ops->change_mode)
+ ret = tz->ops->change_mode(tz, mode);
+
+ if (!ret)
+ tz->mode = mode;
+
+ mutex_unlock(&tz->lock);
+
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ if (mode == THERMAL_DEVICE_ENABLED)
+ thermal_notify_tz_enable(tz->id);
+ else
+ thermal_notify_tz_disable(tz->id);
+
+ return ret;
+}
+
+int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+ return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_enable);
+
+int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+ return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_disable);
+
+int thermal_zone_device_is_enabled(struct thermal_zone_device *tz)
+{
+ enum thermal_device_mode mode;
+
+ mutex_lock(&tz->lock);
+
+ mode = tz->mode;
+
+ mutex_unlock(&tz->lock);
+
+ return mode == THERMAL_DEVICE_ENABLED;
+}
+
void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event)
{
int count;
+ if (should_stop_polling(tz))
+ return;
+
if (atomic_read(&in_suspend))
return;
@@ -617,6 +703,73 @@ void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz,
mutex_unlock(&thermal_list_lock);
}
+int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
+ void *data)
+{
+ struct thermal_governor *gov;
+ int ret = 0;
+
+ mutex_lock(&thermal_governor_lock);
+ list_for_each_entry(gov, &thermal_governor_list, governor_list) {
+ ret = cb(gov, data);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&thermal_governor_lock);
+
+ return ret;
+}
+
+int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
+ void *), void *data)
+{
+ struct thermal_cooling_device *cdev;
+ int ret = 0;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ ret = cb(cdev, data);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ return ret;
+}
+
+int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *),
+ void *data)
+{
+ struct thermal_zone_device *tz;
+ int ret = 0;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(tz, &thermal_tz_list, node) {
+ ret = cb(tz, data);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ return ret;
+}
+
+struct thermal_zone_device *thermal_zone_get_by_id(int id)
+{
+ struct thermal_zone_device *tz, *match = NULL;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(tz, &thermal_tz_list, node) {
+ if (tz->id == id) {
+ match = tz;
+ break;
+ }
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ return match;
+}
+
void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz,
const char *cdev_type, size_t size)
{
@@ -1340,6 +1493,8 @@ thermal_zone_device_register(const char *type, int trips, int mask,
if (atomic_cmpxchg(&tz->need_update, 1, 0))
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+ thermal_notify_tz_create(tz->id, tz->type);
+
return tz;
unregister:
@@ -1411,6 +1566,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
ida_destroy(&tz->ida);
mutex_destroy(&tz->lock);
device_unregister(&tz->device);
+
+ thermal_notify_tz_delete(tz->id);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
@@ -1456,7 +1613,6 @@ static int thermal_pm_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
{
struct thermal_zone_device *tz;
- enum thermal_device_mode tz_mode;
switch (mode) {
case PM_HIBERNATION_PREPARE:
@@ -1469,11 +1625,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
case PM_POST_SUSPEND:
atomic_set(&in_suspend, 0);
list_for_each_entry(tz, &thermal_tz_list, node) {
- tz_mode = THERMAL_DEVICE_ENABLED;
- if (tz->ops->get_mode)
- tz->ops->get_mode(tz, &tz_mode);
-
- if (tz_mode == THERMAL_DEVICE_DISABLED)
+ if (!thermal_zone_device_is_enabled(tz))
continue;
thermal_zone_device_init(tz);
@@ -1495,6 +1647,10 @@ static int __init thermal_init(void)
{
int result;
+ result = thermal_netlink_init();
+ if (result)
+ goto error;
+
mutex_init(&poweroff_lock);
result = thermal_register_governors();
if (result)
@@ -1527,4 +1683,4 @@ error:
mutex_destroy(&poweroff_lock);
return result;
}
-core_initcall(thermal_init);
+postcore_initcall(thermal_init);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index c95689586e19..e00fc5585ea8 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -12,6 +12,8 @@
#include <linux/device.h>
#include <linux/thermal.h>
+#include "thermal_netlink.h"
+
/* Default Thermal Governor */
#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
#define DEFAULT_THERMAL_GOVERNOR "step_wise"
@@ -41,6 +43,17 @@ extern struct thermal_governor *__governor_thermal_table_end[];
__governor < __governor_thermal_table_end; \
__governor++)
+int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *),
+ void *);
+
+int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *,
+ void *), void *);
+
+int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
+ void *thermal_governor);
+
+struct thermal_zone_device *thermal_zone_get_by_id(int id);
+
struct thermal_attr {
struct device_attribute attr;
char name[THERMAL_NAME_LENGTH];
@@ -166,4 +179,6 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz)
}
#endif
+int thermal_zone_device_is_enabled(struct thermal_zone_device *tz);
+
#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c
index 87b1256fa2f2..c94bc824e5d3 100644
--- a/drivers/thermal/thermal_helpers.c
+++ b/drivers/thermal/thermal_helpers.c
@@ -175,6 +175,16 @@ exit:
mutex_unlock(&tz->lock);
}
+static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
+ int target)
+{
+ if (cdev->ops->set_cur_state(cdev, target))
+ return;
+
+ thermal_notify_cdev_state_update(cdev->id, target);
+ thermal_cooling_device_stats_update(cdev, target);
+}
+
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
struct thermal_instance *instance;
@@ -197,8 +207,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
target = instance->target;
}
- if (!cdev->ops->set_cur_state(cdev, target))
- thermal_cooling_device_stats_update(cdev, target);
+ thermal_cdev_set_cur_state(cdev, target);
cdev->updated = true;
mutex_unlock(&cdev->lock);
diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c
new file mode 100644
index 000000000000..af7b2383e8f6
--- /dev/null
+++ b/drivers/thermal/thermal_netlink.c
@@ -0,0 +1,647 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020 Linaro Limited
+ *
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ * Generic netlink for thermal management framework
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <net/genetlink.h>
+#include <uapi/linux/thermal.h>
+
+#include "thermal_core.h"
+
+static const struct genl_multicast_group thermal_genl_mcgrps[] = {
+ { .name = THERMAL_GENL_SAMPLING_GROUP_NAME, },
+ { .name = THERMAL_GENL_EVENT_GROUP_NAME, },
+};
+
+static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = {
+ /* Thermal zone */
+ [THERMAL_GENL_ATTR_TZ] = { .type = NLA_NESTED },
+ [THERMAL_GENL_ATTR_TZ_ID] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_TEMP] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_TRIP] = { .type = NLA_NESTED },
+ [THERMAL_GENL_ATTR_TZ_TRIP_ID] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_MODE] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_CDEV_WEIGHT] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_TZ_NAME] = { .type = NLA_STRING,
+ .len = THERMAL_NAME_LENGTH },
+ /* Governor(s) */
+ [THERMAL_GENL_ATTR_TZ_GOV] = { .type = NLA_NESTED },
+ [THERMAL_GENL_ATTR_TZ_GOV_NAME] = { .type = NLA_STRING,
+ .len = THERMAL_NAME_LENGTH },
+ /* Cooling devices */
+ [THERMAL_GENL_ATTR_CDEV] = { .type = NLA_NESTED },
+ [THERMAL_GENL_ATTR_CDEV_ID] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },
+ [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING,
+ .len = THERMAL_NAME_LENGTH },
+};
+
+struct param {
+ struct nlattr **attrs;
+ struct sk_buff *msg;
+ const char *name;
+ int tz_id;
+ int cdev_id;
+ int trip_id;
+ int trip_temp;
+ int trip_type;
+ int trip_hyst;
+ int temp;
+ int cdev_state;
+ int cdev_max_state;
+};
+
+typedef int (*cb_t)(struct param *);
+
+static struct genl_family thermal_gnl_family;
+
+/************************** Sampling encoding *******************************/
+
+int thermal_genl_sampling_temp(int id, int temp)
+{
+ struct sk_buff *skb;
+ void *hdr;
+
+ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0,
+ THERMAL_GENL_SAMPLING_TEMP);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_ID, id))
+ goto out_cancel;
+
+ if (nla_put_u32(skb, THERMAL_GENL_ATTR_TZ_TEMP, temp))
+ goto out_cancel;
+
+ genlmsg_end(skb, hdr);
+
+ genlmsg_multicast(&thermal_gnl_family, skb, 0, 0, GFP_KERNEL);
+
+ return 0;
+out_cancel:
+ genlmsg_cancel(skb, hdr);
+ nlmsg_free(skb);
+
+ return -EMSGSIZE;
+}
+
+/**************************** Event encoding *********************************/
+
+static int thermal_genl_event_tz_create(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
+ nla_put_string(p->msg, THERMAL_GENL_ATTR_TZ_NAME, p->name))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_tz(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_tz_trip_up(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_tz_trip_add(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, p->trip_type) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, p->trip_temp) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, p->trip_hyst))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_tz_trip_delete(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_cdev_add(struct param *p)
+{
+ if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
+ p->name) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
+ p->cdev_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_MAX_STATE,
+ p->cdev_max_state))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_cdev_delete(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID, p->cdev_id))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_cdev_state_update(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_ID,
+ p->cdev_id) ||
+ nla_put_u32(p->msg, THERMAL_GENL_ATTR_CDEV_CUR_STATE,
+ p->cdev_state))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_event_gov_change(struct param *p)
+{
+ if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
+ nla_put_string(p->msg, THERMAL_GENL_ATTR_GOV_NAME, p->name))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+int thermal_genl_event_tz_delete(struct param *p)
+ __attribute__((alias("thermal_genl_event_tz")));
+
+int thermal_genl_event_tz_enable(struct param *p)
+ __attribute__((alias("thermal_genl_event_tz")));
+
+int thermal_genl_event_tz_disable(struct param *p)
+ __attribute__((alias("thermal_genl_event_tz")));
+
+int thermal_genl_event_tz_trip_down(struct param *p)
+ __attribute__((alias("thermal_genl_event_tz_trip_up")));
+
+int thermal_genl_event_tz_trip_change(struct param *p)
+ __attribute__((alias("thermal_genl_event_tz_trip_add")));
+
+static cb_t event_cb[] = {
+ [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,
+ [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,
+ [THERMAL_GENL_EVENT_TZ_ENABLE] = thermal_genl_event_tz_enable,
+ [THERMAL_GENL_EVENT_TZ_DISABLE] = thermal_genl_event_tz_disable,
+ [THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up,
+ [THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down,
+ [THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change,
+ [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add,
+ [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete,
+ [THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add,
+ [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete,
+ [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
+ [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,
+};
+
+/*
+ * Generic netlink event encoding
+ */
+static int thermal_genl_send_event(enum thermal_genl_event event,
+ struct param *p)
+{
+ struct sk_buff *msg;
+ int ret = -EMSGSIZE;
+ void *hdr;
+
+ msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ p->msg = msg;
+
+ hdr = genlmsg_put(msg, 0, 0, &thermal_gnl_family, 0, event);
+ if (!hdr)
+ goto out_free_msg;
+
+ ret = event_cb[event](p);
+ if (ret)
+ goto out_cancel_msg;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(&thermal_gnl_family, msg, 0, 1, GFP_KERNEL);
+
+ return 0;
+
+out_cancel_msg:
+ genlmsg_cancel(msg, hdr);
+out_free_msg:
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+int thermal_notify_tz_create(int tz_id, const char *name)
+{
+ struct param p = { .tz_id = tz_id, .name = name };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
+}
+
+int thermal_notify_tz_delete(int tz_id)
+{
+ struct param p = { .tz_id = tz_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
+}
+
+int thermal_notify_tz_enable(int tz_id)
+{
+ struct param p = { .tz_id = tz_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
+}
+
+int thermal_notify_tz_disable(int tz_id)
+{
+ struct param p = { .tz_id = tz_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
+}
+
+int thermal_notify_tz_trip_down(int tz_id, int trip_id)
+{
+ struct param p = { .tz_id = tz_id, .trip_id = trip_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
+}
+
+int thermal_notify_tz_trip_up(int tz_id, int trip_id)
+{
+ struct param p = { .tz_id = tz_id, .trip_id = trip_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
+}
+
+int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type,
+ int trip_temp, int trip_hyst)
+{
+ struct param p = { .tz_id = tz_id, .trip_id = trip_id,
+ .trip_type = trip_type, .trip_temp = trip_temp,
+ .trip_hyst = trip_hyst };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p);
+}
+
+int thermal_notify_tz_trip_delete(int tz_id, int trip_id)
+{
+ struct param p = { .tz_id = tz_id, .trip_id = trip_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p);
+}
+
+int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type,
+ int trip_temp, int trip_hyst)
+{
+ struct param p = { .tz_id = tz_id, .trip_id = trip_id,
+ .trip_type = trip_type, .trip_temp = trip_temp,
+ .trip_hyst = trip_hyst };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
+}
+
+int thermal_notify_cdev_state_update(int cdev_id, int cdev_state)
+{
+ struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
+}
+
+int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state)
+{
+ struct param p = { .cdev_id = cdev_id, .name = name,
+ .cdev_max_state = cdev_max_state };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
+}
+
+int thermal_notify_cdev_delete(int cdev_id)
+{
+ struct param p = { .cdev_id = cdev_id };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
+}
+
+int thermal_notify_tz_gov_change(int tz_id, const char *name)
+{
+ struct param p = { .tz_id = tz_id, .name = name };
+
+ return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
+}
+
+/*************************** Command encoding ********************************/
+
+static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
+ void *data)
+{
+ struct sk_buff *msg = data;
+
+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, tz->id) ||
+ nla_put_string(msg, THERMAL_GENL_ATTR_TZ_NAME, tz->type))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_cmd_tz_get_id(struct param *p)
+{
+ struct sk_buff *msg = p->msg;
+ struct nlattr *start_tz;
+ int ret;
+
+ start_tz = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ);
+ if (!start_tz)
+ return -EMSGSIZE;
+
+ ret = for_each_thermal_zone(__thermal_genl_cmd_tz_get_id, msg);
+ if (ret)
+ goto out_cancel_nest;
+
+ nla_nest_end(msg, start_tz);
+
+ return 0;
+
+out_cancel_nest:
+ nla_nest_cancel(msg, start_tz);
+
+ return ret;
+}
+
+static int thermal_genl_cmd_tz_get_trip(struct param *p)
+{
+ struct sk_buff *msg = p->msg;
+ struct thermal_zone_device *tz;
+ struct nlattr *start_trip;
+ int i, id;
+
+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
+ return -EINVAL;
+
+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
+
+ tz = thermal_zone_get_by_id(id);
+ if (!tz)
+ return -EINVAL;
+
+ start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_TZ_TRIP);
+ if (!start_trip)
+ return -EMSGSIZE;
+
+ mutex_lock(&tz->lock);
+
+ for (i = 0; i < tz->trips; i++) {
+
+ enum thermal_trip_type type;
+ int temp, hyst;
+
+ tz->ops->get_trip_type(tz, i, &type);
+ tz->ops->get_trip_temp(tz, i, &temp);
+ tz->ops->get_trip_hyst(tz, i, &hyst);
+
+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) ||
+ nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) ||
+ nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) ||
+ nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst))
+ goto out_cancel_nest;
+ }
+
+ mutex_unlock(&tz->lock);
+
+ nla_nest_end(msg, start_trip);
+
+ return 0;
+
+out_cancel_nest:
+ mutex_unlock(&tz->lock);
+
+ return -EMSGSIZE;
+}
+
+static int thermal_genl_cmd_tz_get_temp(struct param *p)
+{
+ struct sk_buff *msg = p->msg;
+ struct thermal_zone_device *tz;
+ int temp, ret, id;
+
+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
+ return -EINVAL;
+
+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
+
+ tz = thermal_zone_get_by_id(id);
+ if (!tz)
+ return -EINVAL;
+
+ ret = thermal_zone_get_temp(tz, &temp);
+ if (ret)
+ return ret;
+
+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
+ nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TEMP, temp))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_cmd_tz_get_gov(struct param *p)
+{
+ struct sk_buff *msg = p->msg;
+ struct thermal_zone_device *tz;
+ int id, ret = 0;
+
+ if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID])
+ return -EINVAL;
+
+ id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]);
+
+ tz = thermal_zone_get_by_id(id);
+ if (!tz)
+ return -EINVAL;
+
+ mutex_lock(&tz->lock);
+
+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) ||
+ nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME,
+ tz->governor->name))
+ ret = -EMSGSIZE;
+
+ mutex_unlock(&tz->lock);
+
+ return ret;
+}
+
+static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev,
+ void *data)
+{
+ struct sk_buff *msg = data;
+
+ if (nla_put_u32(msg, THERMAL_GENL_ATTR_CDEV_ID, cdev->id))
+ return -EMSGSIZE;
+
+ if (nla_put_string(msg, THERMAL_GENL_ATTR_CDEV_NAME, cdev->type))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
+static int thermal_genl_cmd_cdev_get(struct param *p)
+{
+ struct sk_buff *msg = p->msg;
+ struct nlattr *start_cdev;
+ int ret;
+
+ start_cdev = nla_nest_start(msg, THERMAL_GENL_ATTR_CDEV);
+ if (!start_cdev)
+ return -EMSGSIZE;
+
+ ret = for_each_thermal_cooling_device(__thermal_genl_cmd_cdev_get, msg);
+ if (ret)
+ goto out_cancel_nest;
+
+ nla_nest_end(msg, start_cdev);
+
+ return 0;
+out_cancel_nest:
+ nla_nest_cancel(msg, start_cdev);
+
+ return ret;
+}
+
+static cb_t cmd_cb[] = {
+ [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id,
+ [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip,
+ [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp,
+ [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov,
+ [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get,
+};
+
+static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct param p = { .msg = skb };
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
+ int cmd = info->ops->cmd;
+ int ret;
+ void *hdr;
+
+ hdr = genlmsg_put(skb, 0, 0, &thermal_gnl_family, 0, cmd);
+ if (!hdr)
+ return -EMSGSIZE;
+
+ ret = cmd_cb[cmd](&p);
+ if (ret)
+ goto out_cancel_msg;
+
+ genlmsg_end(skb, hdr);
+
+ return 0;
+
+out_cancel_msg:
+ genlmsg_cancel(skb, hdr);
+
+ return ret;
+}
+
+static int thermal_genl_cmd_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct param p = { .attrs = info->attrs };
+ struct sk_buff *msg;
+ void *hdr;
+ int cmd = info->genlhdr->cmd;
+ int ret = -EMSGSIZE;
+
+ msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ p.msg = msg;
+
+ hdr = genlmsg_put_reply(msg, info, &thermal_gnl_family, 0, cmd);
+ if (!hdr)
+ goto out_free_msg;
+
+ ret = cmd_cb[cmd](&p);
+ if (ret)
+ goto out_cancel_msg;
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_reply(msg, info);
+
+out_cancel_msg:
+ genlmsg_cancel(msg, hdr);
+out_free_msg:
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+static const struct genl_ops thermal_genl_ops[] = {
+ {
+ .cmd = THERMAL_GENL_CMD_TZ_GET_ID,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .dumpit = thermal_genl_cmd_dumpit,
+ },
+ {
+ .cmd = THERMAL_GENL_CMD_TZ_GET_TRIP,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = thermal_genl_cmd_doit,
+ },
+ {
+ .cmd = THERMAL_GENL_CMD_TZ_GET_TEMP,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = thermal_genl_cmd_doit,
+ },
+ {
+ .cmd = THERMAL_GENL_CMD_TZ_GET_GOV,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = thermal_genl_cmd_doit,
+ },
+ {
+ .cmd = THERMAL_GENL_CMD_CDEV_GET,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .dumpit = thermal_genl_cmd_dumpit,
+ },
+};
+
+static struct genl_family thermal_gnl_family __ro_after_init = {
+ .hdrsize = 0,
+ .name = THERMAL_GENL_FAMILY_NAME,
+ .version = THERMAL_GENL_VERSION,
+ .maxattr = THERMAL_GENL_ATTR_MAX,
+ .policy = thermal_genl_policy,
+ .ops = thermal_genl_ops,
+ .n_ops = ARRAY_SIZE(thermal_genl_ops),
+ .mcgrps = thermal_genl_mcgrps,
+ .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps),
+};
+
+int __init thermal_netlink_init(void)
+{
+ return genl_register_family(&thermal_gnl_family);
+}
diff --git a/drivers/thermal/thermal_netlink.h b/drivers/thermal/thermal_netlink.h
new file mode 100644
index 000000000000..828d1dddfa98
--- /dev/null
+++ b/drivers/thermal/thermal_netlink.h
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Linaro Ltd 2020
+ * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
+ */
+
+/* Netlink notification function */
+#ifdef CONFIG_THERMAL_NETLINK
+int __init thermal_netlink_init(void);
+int thermal_notify_tz_create(int tz_id, const char *name);
+int thermal_notify_tz_delete(int tz_id);
+int thermal_notify_tz_enable(int tz_id);
+int thermal_notify_tz_disable(int tz_id);
+int thermal_notify_tz_trip_down(int tz_id, int id);
+int thermal_notify_tz_trip_up(int tz_id, int id);
+int thermal_notify_tz_trip_delete(int tz_id, int id);
+int thermal_notify_tz_trip_add(int tz_id, int id, int type,
+ int temp, int hyst);
+int thermal_notify_tz_trip_change(int tz_id, int id, int type,
+ int temp, int hyst);
+int thermal_notify_cdev_state_update(int cdev_id, int state);
+int thermal_notify_cdev_add(int cdev_id, const char *name, int max_state);
+int thermal_notify_cdev_delete(int cdev_id);
+int thermal_notify_tz_gov_change(int tz_id, const char *name);
+int thermal_genl_sampling_temp(int id, int temp);
+#else
+static inline int thermal_netlink_init(void)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_create(int tz_id, const char *name)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_delete(int tz_id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_enable(int tz_id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_disable(int tz_id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_trip_down(int tz_id, int id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_trip_up(int tz_id, int id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_trip_delete(int tz_id, int id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_trip_add(int tz_id, int id, int type,
+ int temp, int hyst)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_trip_change(int tz_id, int id, int type,
+ int temp, int hyst)
+{
+ return 0;
+}
+
+static inline int thermal_notify_cdev_state_update(int cdev_id, int state)
+{
+ return 0;
+}
+
+static inline int thermal_notify_cdev_add(int cdev_id, const char *name,
+ int max_state)
+{
+ return 0;
+}
+
+static inline int thermal_notify_cdev_delete(int cdev_id)
+{
+ return 0;
+}
+
+static inline int thermal_notify_tz_gov_change(int tz_id, const char *name)
+{
+ return 0;
+}
+
+static inline int thermal_genl_sampling_temp(int id, int temp)
+{
+ return 0;
+}
+#endif /* CONFIG_THERMAL_NETLINK */
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index ddf88dbe7ba2..69ef12f852b7 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
/**
* struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
* @passive_delay: polling interval while passive cooling is activated
* @polling_delay: zone polling interval
* @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
*/
struct __thermal_zone {
- enum thermal_device_mode mode;
int passive_delay;
int polling_delay;
int slope;
@@ -269,39 +267,6 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
return 0;
}
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
- enum thermal_device_mode *mode)
-{
- struct __thermal_zone *data = tz->devdata;
-
- *mode = data->mode;
-
- return 0;
-}
-
-static int of_thermal_set_mode(struct thermal_zone_device *tz,
- enum thermal_device_mode mode)
-{
- struct __thermal_zone *data = tz->devdata;
-
- mutex_lock(&tz->lock);
-
- if (mode == THERMAL_DEVICE_ENABLED) {
- tz->polling_delay = data->polling_delay;
- tz->passive_delay = data->passive_delay;
- } else {
- tz->polling_delay = 0;
- tz->passive_delay = 0;
- }
-
- mutex_unlock(&tz->lock);
-
- data->mode = mode;
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
- return 0;
-}
-
static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
enum thermal_trip_type *type)
{
@@ -393,9 +358,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
}
static struct thermal_zone_device_ops of_thermal_ops = {
- .get_mode = of_thermal_get_mode,
- .set_mode = of_thermal_set_mode,
-
.get_trip_type = of_thermal_get_trip_type,
.get_trip_temp = of_thermal_get_trip_temp,
.set_trip_temp = of_thermal_set_trip_temp,
@@ -554,7 +516,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
tzd = thermal_zone_of_add_sensor(child, sensor_np,
data, ops);
if (!IS_ERR(tzd))
- tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+ thermal_zone_device_enable(tzd);
of_node_put(child);
goto exit;
@@ -979,7 +941,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
finish:
of_node_put(child);
- tz->mode = THERMAL_DEVICE_DISABLED;
return tz;
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..8c231219e15d 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -49,18 +49,9 @@ static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- enum thermal_device_mode mode;
- int result;
-
- if (!tz->ops->get_mode)
- return -EPERM;
+ int enabled = thermal_zone_device_is_enabled(tz);
- result = tz->ops->get_mode(tz, &mode);
- if (result)
- return result;
-
- return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
- : "disabled");
+ return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
}
static ssize_t
@@ -70,13 +61,10 @@ mode_store(struct device *dev, struct device_attribute *attr,
struct thermal_zone_device *tz = to_thermal_zone(dev);
int result;
- if (!tz->ops->set_mode)
- return -EPERM;
-
if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+ result = thermal_zone_device_enable(tz);
else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+ result = thermal_zone_device_disable(tz);
else
result = -EINVAL;
@@ -124,7 +112,8 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip, ret;
- int temperature;
+ int temperature, hyst = 0;
+ enum thermal_trip_type type;
if (!tz->ops->set_trip_temp)
return -EPERM;
@@ -139,6 +128,18 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
if (ret)
return ret;
+ if (tz->ops->get_trip_hyst) {
+ ret = tz->ops->get_trip_hyst(tz, trip, &hyst);
+ if (ret)
+ return ret;
+ }
+
+ ret = tz->ops->get_trip_type(tz, trip, &type);
+ if (ret)
+ return ret;
+
+ thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst);
+
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
return count;
@@ -428,30 +429,13 @@ static struct attribute_group thermal_zone_attribute_group = {
.attrs = thermal_zone_dev_attrs,
};
-/* We expose mode only if .get_mode is present */
static struct attribute *thermal_zone_mode_attrs[] = {
&dev_attr_mode.attr,
NULL,
};
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
- struct attribute *attr,
- int attrno)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct thermal_zone_device *tz;
-
- tz = container_of(dev, struct thermal_zone_device, device);
-
- if (tz->ops->get_mode)
- return attr->mode;
-
- return 0;
-}
-
static struct attribute_group thermal_zone_mode_attribute_group = {
.attrs = thermal_zone_mode_attrs,
- .is_visible = thermal_zone_mode_is_visible,
};
/* We expose passive only if passive trips are present */
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 85776db4bf34..2ce4b19f312a 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -169,7 +169,7 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
data = ti_bandgap_get_sensor_data(bgp, id);
- if (!IS_ERR_OR_NULL(data))
+ if (IS_ERR_OR_NULL(data))
data = ti_thermal_build_data(bgp, id);
if (!data)