Commit d2230051 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull thermal control updates from Rafael Wysocki:
 "These mostly continue to rework the thermal core and the thermal zone
  driver interface to make the code more straightforward and reduce
  bloat

  The most significant piece of this work is a change of the code
  related to binding cooling devices to thermal zones which, among other
  things, replaces two previously existing thermal zone operations with
  one allowing driver implementations to be much simpler

  There is also a new thermal core testing module allowing mock thermal
  zones to be created and controlled via debugfs in order to exercise
  the thermal core functionality. It is expected to be used for
  implementing thermal core self tests in the future

  Apart from the above, there are assorted thermal driver updates

  Specifics:

   - Update some thermal drivers to eliminate thermal_zone_get_trip()
     calls from them and get rid of that function (Rafael Wysocki)

   - Update the thermal sysfs code to store trip point attributes in
     trip descriptors and get to trip points via attribute pointers
     (Rafael Wysocki)

   - Move the computation of the low and high boundaries for
     thermal_zone_set_trips() to __thermal_zone_device_update() (Daniel
     Lezcano)

   - Introduce a debugfs-based facility for thermal core testing (Rafael
     Wysocki)

   - Replace the thermal zone .bind() and .unbind() callbacks for
     binding cooling devices to thermal zones with one .should_bind()
     callback used for deciding whether or not a given cooling devices
     should be bound to a given trip point in a given thermal zone
     (Rafael Wysocki)

   - Eliminate code that has no more users after the other changes, drop
     some redundant checks from the thermal core and clean it up (Rafael
     Wysocki)

   - Fix rounding of delay jiffies in the thermal core (Rafael Wysocki)

   - Refuse to accept trip point temperature or hysteresis that would
     lead to an invalid threshold value when setting them via sysfs
     (Rafael Wysocki)

   - Adjust states of all uninitialized instances in the .manage()
     callback of the Bang-bang thermal governor (Rafael Wysocki)

   - Drop a couple of redundant checks along with the code depending on
     them from the thermal core (Rafael Wysocki)

   - Rearrange the thermal core to avoid redundant checks and simplify
     control flow in a couple of code paths (Rafael Wysocki)

   - Add power domain DT bindings for new Amlogic SoCs (Georges Stark)

   - Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr() in the ST
     driver and add a Kconfig dependency on THERMAL_OF subsystem for the
     STi driver (Raphael Gallais-Pou)

   - Simplify the error code path in the probe functions in the brcmstb
     driver with the helo of dev_err_probe() (Yan Zhen)

   - Make imx_sc_thermal use dev_err_probe() (Alexander Stein)

   - Remove trailing space after \n newline in the Renesas driver (Colin
     Ian King)

   - Add DT binding compatible string for the SA8255p to the tsens
     thermal driver (Nikunj Kela)

   - Use the devm_clk_get_enabled() helpers to simplify the init routine
     in the sprd thermal driver (Huan Yang)

   - Remove __maybe_unused notations for the functions by using the new
     RUNTIME_PM_OPS() and SYSTEM_SLEEP_PM_OPS() macros on the IMx and
     Qoriq drivers (Fabio Estevam)

   - Remove unused declarations from the ti-soc-thermal driver's header
     file as the functions in question were removed previously (Zhang
     Zekun)"

* tag 'thermal-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (48 commits)
  thermal: core: Drop thermal_zone_device_is_enabled()
  thermal: core: Check passive delay in monitor_thermal_zone()
  thermal: core: Drop dead code from monitor_thermal_zone()
  thermal: core: Drop redundant lockdep_assert_held()
  thermal: gov_bang_bang: Adjust states of all uninitialized instances
  thermal: sysfs: Add sanity checks for trip temperature and hysteresis
  thermal/drivers/imx_sc_thermal: Use dev_err_probe
  thermal/drivers/ti-soc-thermal: Remove unused declarations
  thermal/drivers/imx: Remove __maybe_unused notations
  thermal/drivers/qoriq: Remove __maybe_unused notations
  thermal/drivers/sprd: Use devm_clk_get_enabled() helpers
  dt-bindings: thermal: tsens: document support on SA8255p
  thermal/drivers/renesas: Remove trailing space after \n newline
  thermal/drivers/brcmstb_thermal: Simplify with dev_err_probe()
  thermal/drivers/sti: Depend on THERMAL_OF subsystem
  thermal/drivers/st: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr()
  dt-bindings: thermal: amlogic,thermal: add optional power-domains
  thermal: core: Drop tz field from struct thermal_instance
  thermal: core: Drop redundant checks from thermal_bind_cdev_to_trip()
  thermal: core: Rename cdev-to-thermal-zone bind/unbind functions
  ...
parents 02824a5f 3bc5ed15
......@@ -32,6 +32,9 @@ properties:
clocks:
maxItems: 1
power-domains:
maxItems: 1
amlogic,ao-secure:
description: phandle to the ao-secure syscon
$ref: /schemas/types.yaml#/definitions/phandle
......
......@@ -51,6 +51,7 @@ properties:
- qcom,msm8996-tsens
- qcom,msm8998-tsens
- qcom,qcm2290-tsens
- qcom,sa8255p-tsens
- qcom,sa8775p-tsens
- qcom,sc7180-tsens
- qcom,sc7280-tsens
......
......@@ -58,10 +58,9 @@ temperature) and throttle appropriate devices.
ops:
thermal zone device call-backs.
.bind:
bind the thermal zone device with a thermal cooling device.
.unbind:
unbind the thermal zone device with a thermal cooling device.
.should_bind:
check whether or not a given cooling device should be bound to
a given trip point in this thermal zone.
.get_temp:
get the current temperature of the thermal zone.
.set_trips:
......@@ -246,56 +245,6 @@ temperature) and throttle appropriate devices.
It deletes the corresponding entry from /sys/class/thermal folder and
unbinds itself from all the thermal zone devices using it.
1.3 interface for binding a thermal zone device with a thermal cooling device
-----------------------------------------------------------------------------
::
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev,
unsigned long upper, unsigned long lower, unsigned int weight);
This interface function binds a thermal cooling device to a particular trip
point of a thermal zone device.
This function is usually called in the thermal zone device .bind callback.
tz:
the thermal zone device
cdev:
thermal cooling device
trip:
indicates which trip point in this thermal zone the cooling device
is associated with.
upper:
the Maximum cooling state for this trip point.
THERMAL_NO_LIMIT means no upper limit,
and the cooling device can be in max_state.
lower:
the Minimum cooling state can be used for this trip point.
THERMAL_NO_LIMIT means no lower limit,
and the cooling device can be in cooling state 0.
weight:
the influence of this cooling device in this thermal
zone. See 1.4.1 below for more information.
::
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev);
This interface function unbinds a thermal cooling device from a particular
trip point of a thermal zone device. This function is usually called in
the thermal zone device .unbind callback.
tz:
the thermal zone device
cdev:
thermal cooling device
trip:
indicates which trip point in this thermal zone the cooling device
is associated with.
1.4 Thermal Zone Parameters
---------------------------
......@@ -366,8 +315,6 @@ Thermal cooling device sys I/F, created once it's registered::
Then next two dynamic attributes are created/removed in pairs. They represent
the relationship between a thermal zone and its associated cooling device.
They are created/removed for each successful execution of
thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device.
::
......@@ -459,14 +406,7 @@ are supposed to implement the callback. If they don't, the thermal
framework calculated the trend by comparing the previous and the current
temperature values.
4.2. get_thermal_instance
-------------------------
This function returns the thermal_instance corresponding to a given
{thermal_zone, cooling_device, trip_point} combination. Returns NULL
if such an instance does not exist.
4.3. thermal_cdev_update
4.2. thermal_cdev_update
------------------------
This function serves as an arbitrator to set the state of a cooling
......
......@@ -558,77 +558,31 @@ static void acpi_thermal_zone_device_critical(struct thermal_zone_device *therma
thermal_zone_device_critical(thermal);
}
struct acpi_thermal_bind_data {
struct thermal_zone_device *thermal;
struct thermal_cooling_device *cdev;
bool bind;
};
static int bind_unbind_cdev_cb(struct thermal_trip *trip, void *arg)
static bool acpi_thermal_should_bind_cdev(struct thermal_zone_device *thermal,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
struct acpi_thermal_trip *acpi_trip = trip->priv;
struct acpi_thermal_bind_data *bd = arg;
struct thermal_zone_device *thermal = bd->thermal;
struct thermal_cooling_device *cdev = bd->cdev;
struct acpi_device *cdev_adev = cdev->devdata;
int i;
/* Skip critical and hot trips. */
if (!acpi_trip)
return 0;
return false;
for (i = 0; i < acpi_trip->devices.count; i++) {
acpi_handle handle = acpi_trip->devices.handles[i];
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
if (adev != cdev_adev)
continue;
if (bd->bind) {
int ret;
ret = thermal_bind_cdev_to_trip(thermal, trip, cdev,
THERMAL_NO_LIMIT,
THERMAL_NO_LIMIT,
THERMAL_WEIGHT_DEFAULT);
if (ret)
return ret;
} else {
thermal_unbind_cdev_from_trip(thermal, trip, cdev);
}
}
return 0;
}
static int acpi_thermal_bind_unbind_cdev(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev,
bool bind)
{
struct acpi_thermal_bind_data bd = {
.thermal = thermal, .cdev = cdev, .bind = bind
};
return for_each_thermal_trip(thermal, bind_unbind_cdev_cb, &bd);
}
static int
acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_bind_unbind_cdev(thermal, cdev, true);
}
if (acpi_fetch_acpi_dev(handle) == cdev_adev)
return true;
}
static int
acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_bind_unbind_cdev(thermal, cdev, false);
return false;
}
static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.should_bind = acpi_thermal_should_bind_cdev,
.get_temp = thermal_get_temp,
.get_trend = thermal_get_trend,
.hot = acpi_thermal_zone_device_hot,
......
......@@ -165,52 +165,22 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
return -ENODEV;
}
static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev,
struct thermal_cooling_device *cdev)
static bool mlxsw_thermal_should_bind(struct thermal_zone_device *tzdev,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzdev);
struct device *dev = thermal->bus_info->dev;
int i, err;
const struct mlxsw_cooling_states *state = trip->priv;
/* If the cooling device is one of ours bind it */
if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
return 0;
return false;
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
const struct mlxsw_cooling_states *state = &thermal->cooling_states[i];
c->upper = state->max_state;
c->lower = state->min_state;
err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
state->max_state,
state->min_state,
THERMAL_WEIGHT_DEFAULT);
if (err < 0) {
dev_err(dev, "Failed to bind cooling device to trip %d\n", i);
return err;
}
}
return 0;
}
static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
struct thermal_cooling_device *cdev)
{
struct mlxsw_thermal *thermal = thermal_zone_device_priv(tzdev);
struct device *dev = thermal->bus_info->dev;
int i;
int err;
/* If the cooling device is our one unbind it */
if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
return 0;
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
if (err < 0) {
dev_err(dev, "Failed to unbind cooling device\n");
return err;
}
}
return 0;
return true;
}
static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev,
......@@ -240,57 +210,27 @@ static struct thermal_zone_params mlxsw_thermal_params = {
};
static struct thermal_zone_device_ops mlxsw_thermal_ops = {
.bind = mlxsw_thermal_bind,
.unbind = mlxsw_thermal_unbind,
.should_bind = mlxsw_thermal_should_bind,
.get_temp = mlxsw_thermal_get_temp,
};
static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev,
struct thermal_cooling_device *cdev)
static bool mlxsw_thermal_module_should_bind(struct thermal_zone_device *tzdev,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzdev);
const struct mlxsw_cooling_states *state = trip->priv;
struct mlxsw_thermal *thermal = tz->parent;
int i, j, err;
/* If the cooling device is one of ours bind it */
if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
return 0;
return false;
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
const struct mlxsw_cooling_states *state = &tz->cooling_states[i];
c->upper = state->max_state;
c->lower = state->min_state;
err = thermal_zone_bind_cooling_device(tzdev, i, cdev,
state->max_state,
state->min_state,
THERMAL_WEIGHT_DEFAULT);
if (err < 0)
goto err_thermal_zone_bind_cooling_device;
}
return 0;
err_thermal_zone_bind_cooling_device:
for (j = i - 1; j >= 0; j--)
thermal_zone_unbind_cooling_device(tzdev, j, cdev);
return err;
}
static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
struct thermal_cooling_device *cdev)
{
struct mlxsw_thermal_module *tz = thermal_zone_device_priv(tzdev);
struct mlxsw_thermal *thermal = tz->parent;
int i;
int err;
/* If the cooling device is one of ours unbind it */
if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0)
return 0;
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) {
err = thermal_zone_unbind_cooling_device(tzdev, i, cdev);
WARN_ON(err);
}
return err;
return true;
}
static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
......@@ -313,8 +253,7 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev,
}
static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
.bind = mlxsw_thermal_module_bind,
.unbind = mlxsw_thermal_module_unbind,
.should_bind = mlxsw_thermal_module_should_bind,
.get_temp = mlxsw_thermal_module_temp_get,
};
......@@ -342,8 +281,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
}
static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
.bind = mlxsw_thermal_module_bind,
.unbind = mlxsw_thermal_module_unbind,
.should_bind = mlxsw_thermal_module_should_bind,
.get_temp = mlxsw_thermal_gearbox_temp_get,
};
......@@ -450,6 +388,7 @@ mlxsw_thermal_module_init(struct mlxsw_thermal *thermal,
struct mlxsw_thermal_area *area, u8 module)
{
struct mlxsw_thermal_module *module_tz;
int i;
module_tz = &area->tz_module_arr[module];
module_tz->module = module;
......@@ -461,6 +400,8 @@ mlxsw_thermal_module_init(struct mlxsw_thermal *thermal,
sizeof(thermal->trips));
memcpy(module_tz->cooling_states, default_cooling_states,
sizeof(thermal->cooling_states));
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++)
module_tz->trips[i].priv = &module_tz->cooling_states[i];
return mlxsw_thermal_module_tz_init(module_tz);
}
......@@ -566,7 +507,7 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
struct mlxsw_thermal_module *gearbox_tz;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
u8 gbox_num;
int i;
int i, j;
int err;
mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index);
......@@ -593,6 +534,9 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core,
sizeof(thermal->trips));
memcpy(gearbox_tz->cooling_states, default_cooling_states,
sizeof(thermal->cooling_states));
for (j = 0; j < MLXSW_THERMAL_NUM_TRIPS; j++)
gearbox_tz->trips[j].priv = &gearbox_tz->cooling_states[j];
gearbox_tz->module = i;
gearbox_tz->parent = thermal;
gearbox_tz->slot_index = area->slot_index;
......@@ -709,6 +653,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
thermal->bus_info = bus_info;
memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
memcpy(thermal->cooling_states, default_cooling_states, sizeof(thermal->cooling_states));
for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++)
thermal->trips[i].priv = &thermal->cooling_states[i];
thermal->line_cards[0].slot_index = 0;
err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
......
......@@ -378,33 +378,13 @@ static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t)
return 0;
}
static int acerhdf_bind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
static bool acerhdf_should_bind(struct thermal_zone_device *thermal,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
/* if the cooling device is the one from acerhdf bind it */
if (cdev != cl_dev)
return 0;
if (thermal_zone_bind_cooling_device(thermal, 0, cdev,
THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
THERMAL_WEIGHT_DEFAULT)) {
pr_err("error binding cooling dev\n");
return -EINVAL;
}
return 0;
}
static int acerhdf_unbind(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
if (cdev != cl_dev)
return 0;
if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
pr_err("error unbinding cooling dev\n");
return -EINVAL;
}
return 0;
return cdev == cl_dev && trip->type == THERMAL_TRIP_ACTIVE;
}
static inline void acerhdf_revert_to_bios_mode(void)
......@@ -447,8 +427,7 @@ static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
/* bind callback functions to thermalzone */
static struct thermal_zone_device_ops acerhdf_dev_ops = {
.bind = acerhdf_bind,
.unbind = acerhdf_unbind,
.should_bind = acerhdf_should_bind,
.get_temp = acerhdf_get_ec_temp,
.change_mode = acerhdf_change_mode,
.get_crit_temp = acerhdf_get_crit_temp,
......
......@@ -40,6 +40,15 @@ config THERMAL_DEBUGFS
Say Y to allow the thermal subsystem to collect diagnostic
information that can be accessed via debugfs.
config THERMAL_CORE_TESTING
tristate "Thermal core testing facility"
depends on DEBUG_FS
help
Say Y to add a debugfs-based thermal core testing facility.
It allows test thermal zones to be created and populated
with trip points in order to exercise the thermal core
functionality in a controlled way.
config THERMAL_EMERGENCY_POWEROFF_DELAY_MS
int "Emergency poweroff delay in milli-seconds"
default 0
......@@ -429,7 +438,7 @@ source "drivers/thermal/samsung/Kconfig"
endmenu
menu "STMicroelectronics thermal drivers"
depends on (ARCH_STI || ARCH_STM32) && OF
depends on (ARCH_STI || ARCH_STM32) && THERMAL_OF
source "drivers/thermal/st/Kconfig"
endmenu
......
......@@ -63,3 +63,4 @@ obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o
obj-$(CONFIG_THERMAL_CORE_TESTING) += testing/
......@@ -208,8 +208,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
*/
val = readl(data->regs + BCM2835_TS_TSENSCTL);
if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
struct thermal_trip trip;
int offset, slope;
int offset, slope, crit_temp;
slope = thermal_zone_get_slope(tz);
offset = thermal_zone_get_offset(tz);
......@@ -217,7 +216,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
* For now we deal only with critical, otherwise
* would need to iterate
*/
err = thermal_zone_get_trip(tz, 0, &trip);
err = thermal_zone_get_crit_temp(tz, &crit_temp);
if (err < 0) {
dev_err(dev, "Not able to read trip_temp: %d\n", err);
return err;
......@@ -232,7 +231,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev)
val |= (0xFE << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
/* trip_adc value from info */
val |= bcm2835_thermal_temp2adc(trip.temperature,
val |= bcm2835_thermal_temp2adc(crit_temp,
offset,
slope)
<< BCM2835_TS_TSENSCTL_THOLD_SHIFT;
......
......@@ -338,11 +338,9 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
thermal = devm_thermal_of_zone_register(&pdev->dev, 0, priv,
of_ops);
if (IS_ERR(thermal)) {
ret = PTR_ERR(thermal);
dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
return ret;
}
if (IS_ERR(thermal))
return dev_err_probe(&pdev->dev, PTR_ERR(thermal),
"could not register sensor\n");
priv->thermal = thermal;
......@@ -352,10 +350,9 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
brcmstb_tmon_irq_thread,
IRQF_ONESHOT,
DRV_NAME, priv);
if (ret < 0) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", ret);
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"could not request IRQ\n");
}
dev_info(&pdev->dev, "registered AVS TMON of-sensor driver\n");
......
......@@ -92,23 +92,21 @@ static void bang_bang_manage(struct thermal_zone_device *tz)
for_each_trip_desc(tz, td) {
const struct thermal_trip *trip = &td->trip;
bool turn_on;
if (tz->temperature >= td->threshold ||
trip->temperature == THERMAL_TEMP_INVALID ||
if (trip->temperature == THERMAL_TEMP_INVALID ||
trip->type == THERMAL_TRIP_CRITICAL ||
trip->type == THERMAL_TRIP_HOT)
continue;
/*
* If the initial cooling device state is "on", but the zone
* temperature is not above the trip point, the core will not
* call bang_bang_control() until the zone temperature reaches
* the trip point temperature which may be never. In those
* cases, set the initial state of the cooling device to 0.
* Adjust the target states for uninitialized thermal instances
* to the thermal zone temperature and the trip point threshold.
*/
turn_on = tz->temperature >= td->threshold;
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if (!instance->initialized && instance->trip == trip)
bang_bang_set_instance_target(instance, 0);
bang_bang_set_instance_target(instance, turn_on);
}
}
......
......@@ -465,11 +465,22 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
return IRQ_HANDLED;
}
static int hisi_trip_walk_cb(struct thermal_trip *trip, void *arg)
{
struct hisi_thermal_sensor *sensor = arg;
if (trip->type != THERMAL_TRIP_PASSIVE)
return 0;
sensor->thres_temp = trip->temperature;
/* Return nonzero to terminate the search. */
return 1;
}
static int hisi_thermal_register_sensor(struct platform_device *pdev,
struct hisi_thermal_sensor *sensor)
{
int ret, i;
struct thermal_trip trip;
int ret;
sensor->tzd = devm_thermal_of_zone_register(&pdev->dev,
sensor->id, sensor,
......@@ -482,15 +493,7 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev,
return ret;
}
for (i = 0; i < thermal_zone_get_num_trips(sensor->tzd); i++) {
thermal_zone_get_trip(sensor->tzd, i, &trip);
if (trip.type == THERMAL_TRIP_PASSIVE) {
sensor->thres_temp = trip.temperature;
break;
}
}
thermal_zone_for_each_trip(sensor->tzd, hisi_trip_walk_cb, sensor);
return 0;
}
......
......@@ -111,8 +111,7 @@ static int imx_sc_thermal_probe(struct platform_device *pdev)
if (ret == -ENODEV)
continue;
dev_err(&pdev->dev, "failed to register thermal zone\n");
return ret;
return dev_err_probe(&pdev->dev, ret, "failed to register thermal zone\n");
}
devm_thermal_add_hwmon_sysfs(&pdev->dev, sensor->tzd);
......
......@@ -353,24 +353,16 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz,
return 0;
}
static int imx_bind(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev)
static bool imx_should_bind(struct thermal_zone_device *tz,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
return thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
THERMAL_NO_LIMIT,
THERMAL_NO_LIMIT,
THERMAL_WEIGHT_DEFAULT);
}
static int imx_unbind(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev)
{
return thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
return trip->type == THERMAL_TRIP_PASSIVE;
}
static struct thermal_zone_device_ops imx_tz_ops = {
.bind = imx_bind,
.unbind = imx_unbind,
.should_bind = imx_should_bind,
.get_temp = imx_get_temp,
.change_mode = imx_change_mode,
.set_trip_temp = imx_set_trip_temp,
......@@ -773,7 +765,7 @@ static void imx_thermal_remove(struct platform_device *pdev)
imx_thermal_unregister_legacy_cooling(data);
}
static int __maybe_unused imx_thermal_suspend(struct device *dev)
static int imx_thermal_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
int ret;
......@@ -792,7 +784,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
return pm_runtime_force_suspend(data->dev);
}
static int __maybe_unused imx_thermal_resume(struct device *dev)
static int imx_thermal_resume(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
int ret;
......@@ -804,7 +796,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
return thermal_zone_device_enable(data->tz);
}
static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev)
static int imx_thermal_runtime_suspend(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
const struct thermal_soc_data *socdata = data->socdata;
......@@ -826,7 +818,7 @@ static int __maybe_unused imx_thermal_runtime_suspend(struct device *dev)
return 0;
}
static int __maybe_unused imx_thermal_runtime_resume(struct device *dev)
static int imx_thermal_runtime_resume(struct device *dev)
{
struct imx_thermal_data *data = dev_get_drvdata(dev);
const struct thermal_soc_data *socdata = data->socdata;
......@@ -857,15 +849,15 @@ static int __maybe_unused imx_thermal_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops imx_thermal_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume)
SET_RUNTIME_PM_OPS(imx_thermal_runtime_suspend,
imx_thermal_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(imx_thermal_suspend, imx_thermal_resume)
RUNTIME_PM_OPS(imx_thermal_runtime_suspend,
imx_thermal_runtime_resume, NULL)
};
static struct platform_driver imx_thermal = {
.driver = {
.name = "imx_thermal",
.pm = &imx_thermal_pm_ops,
.pm = pm_ptr(&imx_thermal_pm_ops),
.of_match_table = of_imx_thermal_match,
},
.probe = imx_thermal_probe,
......
......@@ -291,24 +291,6 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
return IRQ_HANDLED;
}
static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip)
{
struct thermal_trip trip;
int i, ret;
for (i = 0; i < thermal_zone_get_num_trips(chip->tz_dev); i++) {
ret = thermal_zone_get_trip(chip->tz_dev, i, &trip);
if (ret)
continue;
if (trip.type == THERMAL_TRIP_CRITICAL)
return trip.temperature;
}
return THERMAL_TEMP_INVALID;
}
/*
* This function initializes the internal temp value based on only the
* current thermal stage and threshold. Setup threshold control and
......@@ -343,7 +325,9 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip)
mutex_unlock(&chip->lock);
crit_temp = qpnp_tm_get_critical_trip_temp(chip);
ret = thermal_zone_get_crit_temp(chip->tz_dev, &crit_temp);
if (ret)
crit_temp = THERMAL_TEMP_INVALID;
mutex_lock(&chip->lock);
......
......@@ -347,7 +347,7 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
return 0;
}
static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
static int qoriq_tmu_suspend(struct device *dev)
{
struct qoriq_tmu_data *data = dev_get_drvdata(dev);
int ret;
......@@ -361,7 +361,7 @@ static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
return 0;
}
static int __maybe_unused qoriq_tmu_resume(struct device *dev)
static int qoriq_tmu_resume(struct device *dev)
{
int ret;
struct qoriq_tmu_data *data = dev_get_drvdata(dev);
......@@ -374,8 +374,8 @@ static int __maybe_unused qoriq_tmu_resume(struct device *dev)
return regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, TMR_ME);
}
static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
qoriq_tmu_suspend, qoriq_tmu_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
qoriq_tmu_suspend, qoriq_tmu_resume);
static const struct of_device_id qoriq_tmu_match[] = {
{ .compatible = "fsl,qoriq-tmu", },
......@@ -387,7 +387,7 @@ MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
static struct platform_driver qoriq_tmu = {
.driver = {
.name = "qoriq_thermal",
.pm = &qoriq_tmu_pm_ops,
.pm = pm_sleep_ptr(&qoriq_tmu_pm_ops),
.of_match_table = qoriq_tmu_match,
},
.probe = qoriq_tmu_probe,
......
......@@ -563,11 +563,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
if (ret)
goto error_unregister;
ret = thermal_zone_get_num_trips(tsc->zone);
if (ret < 0)
goto error_unregister;
dev_info(dev, "Sensor %u: Loaded %d trip points\n", i, ret);
dev_info(dev, "Sensor %u: Loaded\n", i);
}
if (!priv->num_tscs) {
......
......@@ -447,7 +447,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, rcar_thermal_irq,
IRQF_SHARED, dev_name(dev), common);
if (ret) {
dev_err(dev, "irq request failed\n ");
dev_err(dev, "irq request failed\n");
goto error_unregister;
}
......
......@@ -359,21 +359,17 @@ static int sprd_thm_probe(struct platform_device *pdev)
return -EINVAL;
}
thm->clk = devm_clk_get(&pdev->dev, "enable");
thm->clk = devm_clk_get_enabled(&pdev->dev, "enable");
if (IS_ERR(thm->clk)) {
dev_err(&pdev->dev, "failed to get enable clock\n");
return PTR_ERR(thm->clk);
}
ret = clk_prepare_enable(thm->clk);
if (ret)
return ret;
sprd_thm_para_config(thm);
ret = sprd_thm_cal_read(np, "thm_sign_cal", &val);
if (ret)
goto disable_clk;
return ret;
if (val > 0)
thm->ratio_sign = -1;
......@@ -382,7 +378,7 @@ static int sprd_thm_probe(struct platform_device *pdev)
ret = sprd_thm_cal_read(np, "thm_ratio_cal", &thm->ratio_off);
if (ret)
goto disable_clk;
return ret;
for_each_child_of_node(np, sen_child) {
sen = devm_kzalloc(&pdev->dev, sizeof(*sen), GFP_KERNEL);
......@@ -439,8 +435,6 @@ static int sprd_thm_probe(struct platform_device *pdev)
of_put:
of_node_put(sen_child);
disable_clk:
clk_disable_unprepare(thm->clk);
return ret;
}
......@@ -526,8 +520,6 @@ static void sprd_thm_remove(struct platform_device *pdev)
devm_thermal_of_zone_unregister(&pdev->dev,
thm->sensor[i]->tzd);
}
clk_disable_unprepare(thm->clk);
}
static const struct of_device_id sprd_thermal_of_match[] = {
......
......@@ -12,6 +12,7 @@
#include <linux/of_device.h>
#include "st_thermal.h"
#include "../thermal_hwmon.h"
/* The Thermal Framework expects millidegrees */
#define mcelsius(temp) ((temp) * 1000)
......@@ -135,8 +136,6 @@ static struct thermal_zone_device_ops st_tz_ops = {
.get_temp = st_thermal_get_temp,
};
static struct thermal_trip trip;
int st_thermal_register(struct platform_device *pdev,
const struct of_device_id *st_thermal_of_match)
{
......@@ -145,7 +144,6 @@ int st_thermal_register(struct platform_device *pdev,
struct device_node *np = dev->of_node;
const struct of_device_id *match;
int polling_delay;
int ret;
if (!np) {
......@@ -197,29 +195,24 @@ int st_thermal_register(struct platform_device *pdev,
if (ret)
goto sensor_off;
polling_delay = sensor->ops->register_enable_irq ? 0 : 1000;
trip.temperature = sensor->cdata->crit_temp;
trip.type = THERMAL_TRIP_CRITICAL;
sensor->thermal_dev =
thermal_zone_device_register_with_trips(dev_name(dev), &trip, 1, sensor,
&st_tz_ops, NULL, 0, polling_delay);
devm_thermal_of_zone_register(dev, 0, sensor, &st_tz_ops);
if (IS_ERR(sensor->thermal_dev)) {
dev_err(dev, "failed to register thermal zone device\n");
dev_err(dev, "failed to register thermal of zone\n");
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);
/*
* devm_thermal_of_zone_register() doesn't enable hwmon by default
* Enable it here
*/
devm_thermal_add_hwmon_sysfs(dev, sensor->thermal_dev);
return 0;
tzd_unregister:
thermal_zone_device_unregister(sensor->thermal_dev);
sensor_off:
st_thermal_sensor_off(sensor);
......@@ -232,11 +225,11 @@ void st_thermal_unregister(struct platform_device *pdev)
struct st_thermal_sensor *sensor = platform_get_drvdata(pdev);
st_thermal_sensor_off(sensor);
thermal_zone_device_unregister(sensor->thermal_dev);
thermal_remove_hwmon_sysfs(sensor->thermal_dev);
devm_thermal_of_zone_unregister(sensor->dev, sensor->thermal_dev);
}
EXPORT_SYMBOL_GPL(st_thermal_unregister);
#ifdef CONFIG_PM_SLEEP
static int st_thermal_suspend(struct device *dev)
{
struct st_thermal_sensor *sensor = dev_get_drvdata(dev);
......@@ -265,9 +258,8 @@ static int st_thermal_resume(struct device *dev)
return 0;
}
#endif
SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
DEFINE_SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume);
EXPORT_SYMBOL_GPL(st_thermal_pm_ops);
MODULE_AUTHOR("STMicroelectronics (R&D) Limited <ajitpal.singh@st.com>");
......
......@@ -170,7 +170,7 @@ static void st_mmap_remove(struct platform_device *pdev)
static struct platform_driver st_mmap_thermal_driver = {
.driver = {
.name = "st_thermal_mmap",
.pm = &st_thermal_pm_ops,
.pm = pm_sleep_ptr(&st_thermal_pm_ops),
.of_match_table = st_mmap_thermal_of_match,
},
.probe = st_mmap_probe,
......
......@@ -440,7 +440,6 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int stm_thermal_suspend(struct device *dev)
{
struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
......@@ -466,10 +465,9 @@ static int stm_thermal_resume(struct device *dev)
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops,
stm_thermal_suspend, stm_thermal_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops,
stm_thermal_suspend, stm_thermal_resume);
static const struct thermal_zone_device_ops stm_tz_ops = {
.get_temp = stm_thermal_get_temp,
......@@ -580,7 +578,7 @@ static void stm_thermal_remove(struct platform_device *pdev)
static struct platform_driver stm_thermal_driver = {
.driver = {
.name = "stm_thermal",
.pm = &stm_thermal_pm_ops,
.pm = pm_sleep_ptr(&stm_thermal_pm_ops),
.of_match_table = stm_thermal_of_match,
},
.probe = stm_thermal_probe,
......
......@@ -682,24 +682,25 @@ static const struct thermal_zone_device_ops tegra_of_thermal_ops = {
.set_trips = tegra_thermctl_set_trips,
};
static int get_hot_temp(struct thermal_zone_device *tz, int *trip_id, int *temp)
static int get_hot_trip_cb(struct thermal_trip *trip, void *arg)
{
int i, ret;
struct thermal_trip trip;
const struct thermal_trip **trip_ret = arg;
for (i = 0; i < thermal_zone_get_num_trips(tz); i++) {
if (trip->type != THERMAL_TRIP_HOT)
return 0;
ret = thermal_zone_get_trip(tz, i, &trip);
if (ret)
return -EINVAL;
*trip_ret = trip;
/* Return nonzero to terminate the search. */
return 1;
}
if (trip.type == THERMAL_TRIP_HOT) {
*trip_id = i;
return 0;
}
}
static const struct thermal_trip *get_hot_trip(struct thermal_zone_device *tz)
{
const struct thermal_trip *trip = NULL;
return -EINVAL;
thermal_zone_for_each_trip(tz, get_hot_trip_cb, &trip);
return trip;
}
/**
......@@ -731,8 +732,9 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
struct thermal_zone_device *tz)
{
struct tegra_soctherm *ts = dev_get_drvdata(dev);
const struct thermal_trip *hot_trip;
struct soctherm_throt_cfg *stc;
int i, trip, temperature, ret;
int i, temperature, ret;
/* Get thermtrips. If missing, try to get critical trips. */
temperature = tsensor_group_thermtrip_get(ts, sg->id);
......@@ -749,8 +751,8 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
dev_info(dev, "thermtrip: will shut down when %s reaches %d mC\n",
sg->name, temperature);
ret = get_hot_temp(tz, &trip, &temperature);
if (ret) {
hot_trip = get_hot_trip(tz);
if (!hot_trip) {
dev_info(dev, "throttrip: %s: missing hot temperature\n",
sg->name);
return 0;
......@@ -763,7 +765,7 @@ static int tegra_soctherm_set_hwtrips(struct device *dev,
continue;
cdev = ts->throt_cfgs[i].cdev;
if (get_thermal_instance(tz, cdev, trip))
if (thermal_trip_is_bound_to_cdev(tz, hot_trip, cdev))
stc = find_throttle_cfg_by_name(ts, cdev->type);
else
continue;
......
......@@ -303,33 +303,37 @@ static int tegra_tsensor_disable_hw_channel(const struct tegra_tsensor *ts,
return 0;
}
static void tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd,
int *hot_trip, int *crit_trip)
struct trip_temps {
int hot_trip;
int crit_trip;
};
static int tegra_tsensor_get_trips_cb(struct thermal_trip *trip, void *arg)
{
unsigned int i;
struct trip_temps *temps = arg;
if (trip->type == THERMAL_TRIP_HOT)
temps->hot_trip = trip->temperature;
else if (trip->type == THERMAL_TRIP_CRITICAL)
temps->crit_trip = trip->temperature;
return 0;
}
static void tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd,
struct trip_temps *temps)
{
/*
* 90C is the maximal critical temperature of all Tegra30 SoC variants,
* use it for the default trip if unspecified in a device-tree.
*/
*hot_trip = 85000;
*crit_trip = 90000;
for (i = 0; i < thermal_zone_get_num_trips(tzd); i++) {
struct thermal_trip trip;
temps->hot_trip = 85000;
temps->crit_trip = 90000;
thermal_zone_get_trip(tzd, i, &trip);
if (trip.type == THERMAL_TRIP_HOT)
*hot_trip = trip.temperature;
if (trip.type == THERMAL_TRIP_CRITICAL)
*crit_trip = trip.temperature;
}
thermal_zone_for_each_trip(tzd, tegra_tsensor_get_trips_cb, temps);
/* clamp hardware trips to the calibration limits */
*hot_trip = clamp(*hot_trip, 25000, 90000);
temps->hot_trip = clamp(temps->hot_trip, 25000, 90000);
/*
* Kernel will perform a normal system shut down if it will
......@@ -338,7 +342,7 @@ static void tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd,
* shut down gracefully before sending signal to the Power
* Management controller.
*/
*crit_trip = clamp(*crit_trip + 5000, 25000, 90000);
temps->crit_trip = clamp(temps->crit_trip + 5000, 25000, 90000);
}
static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
......@@ -346,7 +350,8 @@ static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
{
const struct tegra_tsensor_channel *tsc = &ts->ch[id];
struct thermal_zone_device *tzd = tsc->tzd;
int err, hot_trip = 0, crit_trip = 0;
struct trip_temps temps = { 0 };
int err;
u32 val;
if (!tzd) {
......@@ -357,24 +362,24 @@ static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts,
return 0;
}
tegra_tsensor_get_hw_channel_trips(tzd, &hot_trip, &crit_trip);
tegra_tsensor_get_hw_channel_trips(tzd, &temps);
dev_info_once(ts->dev, "ch%u: PMC emergency shutdown trip set to %dC\n",
id, DIV_ROUND_CLOSEST(crit_trip, 1000));
id, DIV_ROUND_CLOSEST(temps.crit_trip, 1000));
hot_trip = tegra_tsensor_temp_to_counter(ts, hot_trip);
crit_trip = tegra_tsensor_temp_to_counter(ts, crit_trip);
temps.hot_trip = tegra_tsensor_temp_to_counter(ts, temps.hot_trip);
temps.crit_trip = tegra_tsensor_temp_to_counter(ts, temps.crit_trip);
/* program LEVEL2 counter threshold */
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG1);
val &= ~TSENSOR_SENSOR0_CONFIG1_TH2;
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH2, hot_trip);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH2, temps.hot_trip);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG1);
/* program LEVEL3 counter threshold */
val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG2);
val &= ~TSENSOR_SENSOR0_CONFIG2_TH3;
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG2_TH3, crit_trip);
val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG2_TH3, temps.crit_trip);
writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG2);
/*
......
# SPDX-License-Identifier: GPL-2.0
#
# Thermal core testing facility.
obj-$(CONFIG_THERMAL_CORE_TESTING) += thermal-testing.o
thermal-testing-y := command.o zone.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2024, Intel Corporation
*
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* Thermal subsystem testing facility.
*
* This facility allows the thermal core functionality to be exercised in a
* controlled way in order to verify its behavior.
*
* It resides in the "thermal-testing" directory under the debugfs root and
* starts with a single file called "command" which can be written a string
* representing a thermal testing facility command.
*
* The currently supported commands are listed in the tt_commands enum below.
*
* The "addtz" command causes a new test thermal zone template to be created,
* for example:
*
* # echo addtz > /sys/kernel/debug/thermal-testing/command
*
* That template will be represented as a subdirectory in the "thermal-testing"
* directory, for example
*
* # ls /sys/kernel/debug/thermal-testing/
* command tz0
*
* The thermal zone template can be populated with trip points with the help of
* the "tzaddtrip" command, for example:
*
* # echo tzaddtrip:0 > /sys/kernel/debug/thermal-testing/command
*
* which causes a trip point template to be added to the test thermal zone
* template 0 (represented by the tz0 subdirectory in "thermal-testing").
*
* # ls /sys/kernel/debug/thermal-testing/tz0
* init_temp temp trip_0_temp trip_0_hyst
*
* The temperature of a trip point template is initially THERMAL_TEMP_INVALID
* and its hysteresis is initially 0. They can be adjusted by writing to the
* "trip_x_temp" and "trip_x_hyst" files correspoinding to that trip point
* template, respectively.
*
* The initial temperature of a thermal zone based on a template can be set by
* writing to the "init_temp" file in its directory under "thermal-testing", for
* example:
*
* echo 50000 > /sys/kernel/debug/thermal-testing/tz0/init_temp
*
* When ready, "tzreg" command can be used for registering and enabling a
* thermal zone based on a given template with the thermal core, for example
*
* # echo tzreg:0 > /sys/kernel/debug/thermal-testing/command
*
* In this case, test thermal zone template 0 is used for registering a new
* thermal zone and the set of trip point templates associated with it is used
* for populating the new thermal zone's trip points table. The type of the new
* thermal zone is "test_tz".
*
* The temperature and hysteresis of all of the trip points in that new thermal
* zone are adjustable via sysfs, so they can be updated at any time.
*
* The current temperature of the new thermal zone can be set by writing to the
* "temp" file in the corresponding thermal zone template's directory under
* "thermal-testing", for example
*
* echo 10000 > /sys/kernel/debug/thermal-testing/tz0/temp
*
* which will also trigger a temperature update for this zone in the thermal
* core, including checking its trip points, sending notifications to user space
* if any of them have been crossed and so on.
*
* When it is not needed any more, a test thermal zone template can be deleted
* with the help of the "deltz" command, for example
*
* # echo deltz:0 > /sys/kernel/debug/thermal-testing/command
*
* which will also unregister the thermal zone based on it, if present.
*/
#define pr_fmt(fmt) "thermal-testing: " fmt
#include <linux/debugfs.h>
#include <linux/module.h>
#include "thermal_testing.h"
struct dentry *d_testing;
#define TT_COMMAND_SIZE 16
enum tt_commands {
TT_CMD_ADDTZ,
TT_CMD_DELTZ,
TT_CMD_TZADDTRIP,
TT_CMD_TZREG,
TT_CMD_TZUNREG,
};
static const char *tt_command_strings[] = {
[TT_CMD_ADDTZ] = "addtz",
[TT_CMD_DELTZ] = "deltz",
[TT_CMD_TZADDTRIP] = "tzaddtrip",
[TT_CMD_TZREG] = "tzreg",
[TT_CMD_TZUNREG] = "tzunreg",
};
static int tt_command_exec(int index, const char *arg)
{
int ret;
switch (index) {
case TT_CMD_ADDTZ:
ret = tt_add_tz();
break;
case TT_CMD_DELTZ:
ret = tt_del_tz(arg);
break;
case TT_CMD_TZADDTRIP:
ret = tt_zone_add_trip(arg);
break;
case TT_CMD_TZREG:
ret = tt_zone_reg(arg);
break;
case TT_CMD_TZUNREG:
ret = tt_zone_unreg(arg);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static ssize_t tt_command_process(struct dentry *dentry, const char __user *user_buf,
size_t count)
{
char *buf __free(kfree);
char *arg;
int i;
buf = kmalloc(count + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
buf[count] = '\0';
strim(buf);
arg = strstr(buf, ":");
if (arg) {
*arg = '\0';
arg++;
}
for (i = 0; i < ARRAY_SIZE(tt_command_strings); i++) {
if (!strcmp(buf, tt_command_strings[i]))
return tt_command_exec(i, arg);
}
return -EINVAL;
}
static ssize_t tt_command_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct dentry *dentry = file->f_path.dentry;
ssize_t ret;
if (*ppos)
return -EINVAL;
if (count + 1 > TT_COMMAND_SIZE)
return -E2BIG;
ret = debugfs_file_get(dentry);
if (unlikely(ret))
return ret;
ret = tt_command_process(dentry, user_buf, count);
if (ret)
return ret;
return count;
}
static const struct file_operations tt_command_fops = {
.write = tt_command_write,
.open = simple_open,
.llseek = default_llseek,
};
static int __init thermal_testing_init(void)
{
d_testing = debugfs_create_dir("thermal-testing", NULL);
if (!IS_ERR(d_testing))
debugfs_create_file("command", 0200, d_testing, NULL,
&tt_command_fops);
return 0;
}
module_init(thermal_testing_init);
static void __exit thermal_testing_exit(void)
{
debugfs_remove(d_testing);
tt_zone_cleanup();
}
module_exit(thermal_testing_exit);
MODULE_DESCRIPTION("Thermal core testing facility");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
extern struct dentry *d_testing;
int tt_add_tz(void);
int tt_del_tz(const char *arg);
int tt_zone_add_trip(const char *arg);
int tt_zone_reg(const char *arg);
int tt_zone_unreg(const char *arg);
void tt_zone_cleanup(void);
This diff is collapsed.
This diff is collapsed.
......@@ -15,8 +15,20 @@
#include "thermal_netlink.h"
#include "thermal_debugfs.h"
struct thermal_attr {
struct device_attribute attr;
char name[THERMAL_NAME_LENGTH];
};
struct thermal_trip_attrs {
struct thermal_attr type;
struct thermal_attr temp;
struct thermal_attr hyst;
};
struct thermal_trip_desc {
struct thermal_trip trip;
struct thermal_trip_attrs trip_attrs;
struct list_head notify_list_node;
int notify_temp;
int threshold;
......@@ -56,9 +68,6 @@ struct thermal_governor {
* @device: &struct device for this thermal zone
* @removal: removal completion
* @resume: resume completion
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
* @trip_type_attrs: attributes for trip points for sysfs: trip type
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
* @mode: current mode of this thermal zone
* @devdata: private pointer for device private data
* @num_trips: number of trip points the thermal zone supports
......@@ -102,9 +111,6 @@ struct thermal_zone_device {
struct completion removal;
struct completion resume;
struct attribute_group trips_attribute_group;
struct thermal_attr *trip_temp_attrs;
struct thermal_attr *trip_type_attrs;
struct thermal_attr *trip_hyst_attrs;
enum thermal_device_mode mode;
void *devdata;
int num_trips;
......@@ -188,11 +194,6 @@ int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *),
struct thermal_zone_device *thermal_zone_get_by_id(int id);
struct thermal_attr {
struct device_attribute attr;
char name[THERMAL_NAME_LENGTH];
};
static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
{
return cdev->ops->get_requested_power && cdev->ops->state2power &&
......@@ -204,11 +205,6 @@ void __thermal_cdev_update(struct thermal_cooling_device *cdev);
int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip);
struct thermal_instance *
get_thermal_instance(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev,
int trip);
/*
* This structure is used to describe the behavior of
* a certain cooling device on a certain trip point
......@@ -217,7 +213,6 @@ get_thermal_instance(struct thermal_zone_device *tz,
struct thermal_instance {
int id;
char name[THERMAL_NAME_LENGTH];
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
const struct thermal_trip *trip;
bool initialized;
......@@ -259,14 +254,14 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
const char *thermal_trip_type_name(enum thermal_trip_type trip_type);
void thermal_zone_set_trips(struct thermal_zone_device *tz);
void thermal_zone_set_trips(struct thermal_zone_device *tz, int low, int high);
int thermal_zone_trip_id(const struct thermal_zone_device *tz,
const struct thermal_trip *trip);
void thermal_zone_trip_updated(struct thermal_zone_device *tz,
const struct thermal_trip *trip);
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
void thermal_zone_trip_down(struct thermal_zone_device *tz,
const struct thermal_trip *trip);
void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
struct thermal_trip *trip, int hyst);
/* sysfs I/F */
int thermal_zone_create_device_groups(struct thermal_zone_device *tz);
......@@ -289,7 +284,4 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
unsigned long new_state) {}
#endif /* CONFIG_THERMAL_STATISTICS */
/* device tree support */
int thermal_zone_device_is_enabled(struct thermal_zone_device *tz);
#endif /* __THERMAL_CORE_H__ */
......@@ -39,18 +39,18 @@ int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip
return trend;
}
static struct thermal_instance *get_instance(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev,
const struct thermal_trip *trip)
static bool thermal_instance_present(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev,
const struct thermal_trip *trip)
{
struct thermal_instance *ti;
list_for_each_entry(ti, &tz->thermal_instances, tz_node) {
if (ti->trip == trip && ti->cdev == cdev)
return ti;
return true;
}
return NULL;
return false;
}
bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz,
......@@ -62,7 +62,7 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz,
mutex_lock(&tz->lock);
mutex_lock(&cdev->lock);
ret = !!get_instance(tz, cdev, trip);
ret = thermal_instance_present(tz, cdev, trip);
mutex_unlock(&cdev->lock);
mutex_unlock(&tz->lock);
......@@ -71,24 +71,6 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev);
struct thermal_instance *
get_thermal_instance(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev, int trip_index)
{
struct thermal_instance *ti;
mutex_lock(&tz->lock);
mutex_lock(&cdev->lock);
ti = get_instance(tz, cdev, &tz->trips[trip_index].trip);
mutex_unlock(&cdev->lock);
mutex_unlock(&tz->lock);
return ti;
}
EXPORT_SYMBOL(get_thermal_instance);
/**
* __thermal_zone_get_temp() - returns the temperature of a thermal zone
* @tz: a valid pointer to a struct thermal_zone_device
......@@ -199,8 +181,6 @@ void __thermal_cdev_update(struct thermal_cooling_device *cdev)
/* Make sure cdev enters the deepest cooling state */
list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
dev_dbg(&cdev->device, "zone%d->target=%lu\n",
instance->tz->id, instance->target);
if (instance->target == THERMAL_NO_TARGET)
continue;
if (instance->target > target)
......
......@@ -20,37 +20,6 @@
/*** functions parsing device tree nodes ***/
static int of_find_trip_id(struct device_node *np, struct device_node *trip)
{
struct device_node *trips;
struct device_node *t;
int i = 0;
trips = of_get_child_by_name(np, "trips");
if (!trips) {
pr_err("Failed to find 'trips' node\n");
return -EINVAL;
}
/*
* Find the trip id point associated with the cooling device map
*/
for_each_child_of_node(trips, t) {
if (t == trip) {
of_node_put(t);
goto out;
}
i++;
}
i = -ENXIO;
out:
of_node_put(trips);
return i;
}
/*
* It maps 'enum thermal_trip_type' found in include/linux/thermal.h
* into the device tree binding of 'trip', property type.
......@@ -119,6 +88,8 @@ static int thermal_of_populate_trip(struct device_node *np,
trip->flags = THERMAL_TRIP_FLAG_RW_TEMP;
trip->priv = np;
return 0;
}
......@@ -291,39 +262,9 @@ static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_devic
return tz_np;
}
static int __thermal_of_unbind(struct device_node *map_np, int index, int trip_id,
struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
{
struct of_phandle_args cooling_spec;
int ret;
ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
index, &cooling_spec);
if (ret < 0) {
pr_err("Invalid cooling-device entry\n");
return ret;
}
of_node_put(cooling_spec.np);
if (cooling_spec.args_count < 2) {
pr_err("wrong reference to cooling device, missing limits\n");
return -EINVAL;
}
if (cooling_spec.np != cdev->np)
return 0;
ret = thermal_zone_unbind_cooling_device(tz, trip_id, cdev);
if (ret)
pr_err("Failed to unbind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
return ret;
}
static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id,
struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
struct of_phandle_args cooling_spec;
int ret, weight = THERMAL_WEIGHT_DEFAULT;
......@@ -335,104 +276,73 @@ static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id,
if (ret < 0) {
pr_err("Invalid cooling-device entry\n");
return ret;
return false;
}
of_node_put(cooling_spec.np);
if (cooling_spec.args_count < 2) {
pr_err("wrong reference to cooling device, missing limits\n");
return -EINVAL;
return false;
}
if (cooling_spec.np != cdev->np)
return 0;
return false;
ret = thermal_zone_bind_cooling_device(tz, trip_id, cdev, cooling_spec.args[1],
cooling_spec.args[0],
weight);
if (ret)
pr_err("Failed to bind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
c->lower = cooling_spec.args[0];
c->upper = cooling_spec.args[1];
c->weight = weight;
return ret;
return true;
}
static int thermal_of_for_each_cooling_device(struct device_node *tz_np, struct device_node *map_np,
struct thermal_zone_device *tz, struct thermal_cooling_device *cdev,
int (*action)(struct device_node *, int, int,
struct thermal_zone_device *, struct thermal_cooling_device *))
{
struct device_node *tr_np;
int count, i, trip_id;
tr_np = of_parse_phandle(map_np, "trip", 0);
if (!tr_np)
return -ENODEV;
trip_id = of_find_trip_id(tz_np, tr_np);
if (trip_id < 0)
return trip_id;
count = of_count_phandle_with_args(map_np, "cooling-device", "#cooling-cells");
if (count <= 0) {
pr_err("Add a cooling_device property with at least one device\n");
return -ENOENT;
}
/*
* At this point, we don't want to bail out when there is an
* error, we will try to bind/unbind as many as possible
* cooling devices
*/
for (i = 0; i < count; i++)
action(map_np, i, trip_id, tz, cdev);
return 0;
}
static int thermal_of_for_each_cooling_maps(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev,
int (*action)(struct device_node *, int, int,
struct thermal_zone_device *, struct thermal_cooling_device *))
static bool thermal_of_should_bind(struct thermal_zone_device *tz,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
struct cooling_spec *c)
{
struct device_node *tz_np, *cm_np, *child;
int ret = 0;
bool result = false;
tz_np = thermal_of_zone_get_by_name(tz);
if (IS_ERR(tz_np)) {
pr_err("Failed to get node tz by name\n");
return PTR_ERR(tz_np);
return false;
}
cm_np = of_get_child_by_name(tz_np, "cooling-maps");
if (!cm_np)
goto out;
/* Look up the trip and the cdev in the cooling maps. */
for_each_child_of_node(cm_np, child) {
ret = thermal_of_for_each_cooling_device(tz_np, child, tz, cdev, action);
if (ret) {
of_node_put(child);
break;
struct device_node *tr_np;
int count, i;
tr_np = of_parse_phandle(child, "trip", 0);
if (tr_np != trip->priv)
continue;
/* The trip has been found, look up the cdev. */
count = of_count_phandle_with_args(child, "cooling-device", "#cooling-cells");
if (count <= 0)
pr_err("Add a cooling_device property with at least one device\n");
for (i = 0; i < count; i++) {
result = thermal_of_get_cooling_spec(child, i, cdev, c);
if (result)
break;
}
of_node_put(child);
break;
}
of_node_put(cm_np);
out:
of_node_put(tz_np);
return ret;
}
static int thermal_of_bind(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev)
{
return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_bind);
}
static int thermal_of_unbind(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev)
{
return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_unbind);
return result;
}
/**
......@@ -504,8 +414,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
thermal_of_parameters_init(np, &tzp);
of_ops.bind = thermal_of_bind;
of_ops.unbind = thermal_of_unbind;
of_ops.should_bind = thermal_of_should_bind;
ret = of_property_read_string(np, "critical-action", &action);
if (!ret)
......
This diff is collapsed.
......@@ -55,31 +55,8 @@ int thermal_zone_for_each_trip(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);
int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
void thermal_zone_set_trips(struct thermal_zone_device *tz, int low, int high)
{
return tz->num_trips;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
/**
* thermal_zone_set_trips - Computes the next trip points for the driver
* @tz: a pointer to a thermal zone device structure
*
* The function computes the next temperature boundaries by browsing
* the trip points. The result is the closer low and high trip points
* to the current temperature. These values are passed to the backend
* driver to let it set its own notification mechanism (usually an
* interrupt).
*
* This function must be called with tz->lock held. Both tz and tz->ops
* must be valid pointers.
*
* It does not return a value
*/
void thermal_zone_set_trips(struct thermal_zone_device *tz)
{
const struct thermal_trip_desc *td;
int low = -INT_MAX, high = INT_MAX;
int ret;
lockdep_assert_held(&tz->lock);
......@@ -87,14 +64,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
if (!tz->ops.set_trips)
return;
for_each_trip_desc(tz, td) {
if (td->threshold <= tz->temperature && td->threshold > low)
low = td->threshold;
if (td->threshold >= tz->temperature && td->threshold < high)
high = td->threshold;
}
/* No need to change trip points */
if (tz->prev_low_trip == low && tz->prev_high_trip == high)
return;
......@@ -114,20 +83,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
}
int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
struct thermal_trip *trip)
{
if (!tz || !trip || trip_id < 0 || trip_id >= tz->num_trips)
return -EINVAL;
mutex_lock(&tz->lock);
*trip = tz->trips[trip_id].trip;
mutex_unlock(&tz->lock);
return 0;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_trip);
int thermal_zone_trip_id(const struct thermal_zone_device *tz,
const struct thermal_trip *trip)
{
......@@ -138,11 +93,11 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
return trip_to_trip_desc(trip) - tz->trips;
}
void thermal_zone_trip_updated(struct thermal_zone_device *tz,
const struct thermal_trip *trip)
void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz,
struct thermal_trip *trip, int hyst)
{
WRITE_ONCE(trip->hysteresis, hyst);
thermal_notify_tz_trip_change(tz, trip);
__thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
}
void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
......
......@@ -336,10 +336,6 @@ struct ti_bandgap_data {
struct ti_temp_sensor sensors[];
};
int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot);
int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val);
int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold);
int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val);
int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
int *interval);
int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id,
......
......@@ -85,11 +85,17 @@ struct thermal_trip {
struct thermal_zone_device;
struct cooling_spec {
unsigned long upper; /* Highest cooling state */
unsigned long lower; /* Lowest cooling state */
unsigned int weight; /* Cooling device weight */
};
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
bool (*should_bind) (struct thermal_zone_device *,
const struct thermal_trip *,
struct thermal_cooling_device *,
struct cooling_spec *);
int (*get_temp) (struct thermal_zone_device *, int *);
int (*set_trips) (struct thermal_zone_device *, int, int);
int (*change_mode) (struct thermal_zone_device *,
......@@ -203,15 +209,12 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev,
}
#endif
int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
struct thermal_trip *trip);
int for_each_thermal_trip(struct thermal_zone_device *tz,
int (*cb)(struct thermal_trip *, void *),
void *data);
int thermal_zone_for_each_trip(struct thermal_zone_device *tz,
int (*cb)(struct thermal_trip *, void *),
void *data);
int thermal_zone_get_num_trips(struct thermal_zone_device *tz);
void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
struct thermal_trip *trip, int temp);
......@@ -240,20 +243,6 @@ const char *thermal_zone_device_type(struct thermal_zone_device *tzd);
int thermal_zone_device_id(struct thermal_zone_device *tzd);
struct device *thermal_zone_device(struct thermal_zone_device *tzd);
int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev,
unsigned long upper, unsigned long lower,
unsigned int weight);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *,
unsigned long, unsigned long,
unsigned int);
int thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
const struct thermal_trip *trip,
struct thermal_cooling_device *cdev);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
void thermal_zone_device_update(struct thermal_zone_device *,
enum thermal_notify_event);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment