linux/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
Daniel Lezcano 5f68d0785e thermal/core: Use the thermal zone 'devdata' accessor in thermal located drivers
The thermal zone device structure is exposed to the different drivers
and obviously they access the internals while that should be
restricted to the core thermal code.

In order to self-encapsulate the thermal core code, we need to prevent
the drivers accessing directly the thermal zone structure and provide
accessor functions to deal with.

Use the devdata accessor introduced in the previous patch.

No functional changes intended.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> #R-Car
Acked-by: Mark Brown <broonie@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> #MediaTek auxadc and lvts
Reviewed-by: Balsam CHIHI <bchihi@baylibre.com> #Mediatek lvts
Reviewed-by: Adam Ward <DLG-Adam.Ward.opensource@dm.renesas.com> #da9062
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>  #spread
Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> #sun8i_thermal
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com> #Broadcom
Reviewed-by: Dhruva Gole <d-gole@ti.com> # K3 bandgap
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Heiko Stuebner <heiko@sntech.de> #rockchip
Reviewed-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> #uniphier
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2023-03-03 20:45:02 +01:00

261 lines
6.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* int340x_thermal_zone.c
* Copyright (c) 2015, Intel Corporation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#include <linux/units.h>
#include "int340x_thermal_zone.h"
static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
int *temp)
{
struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);
unsigned long long tmp;
acpi_status status;
status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -EIO;
if (d->lpat_table) {
int conv_temp;
conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
if (conv_temp < 0)
return conv_temp;
*temp = conv_temp * 10;
} else {
/* _TMP returns the temperature in tenths of degrees Kelvin */
*temp = deci_kelvin_to_millicelsius(tmp);
}
return 0;
}
static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
int trip, int temp)
{
struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);
char name[] = {'P', 'A', 'T', '0' + trip, '\0'};
acpi_status status;
if (trip > 9)
return -EINVAL;
status = acpi_execute_simple_method(d->adev->handle, name,
millicelsius_to_deci_kelvin(temp));
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
static void int340x_thermal_critical(struct thermal_zone_device *zone)
{
dev_dbg(&zone->device, "%s: critical temperature reached\n", zone->type);
}
static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
.get_temp = int340x_thermal_get_zone_temp,
.set_trip_temp = int340x_thermal_set_trip_temp,
.critical = int340x_thermal_critical,
};
static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
struct thermal_trip *zone_trips,
int trip_cnt)
{
int i, ret;
ret = thermal_acpi_critical_trip_temp(zone_adev,
&zone_trips[trip_cnt].temperature);
if (!ret) {
zone_trips[trip_cnt].type = THERMAL_TRIP_CRITICAL;
trip_cnt++;
}
ret = thermal_acpi_hot_trip_temp(zone_adev,
&zone_trips[trip_cnt].temperature);
if (!ret) {
zone_trips[trip_cnt].type = THERMAL_TRIP_HOT;
trip_cnt++;
}
ret = thermal_acpi_passive_trip_temp(zone_adev,
&zone_trips[trip_cnt].temperature);
if (!ret) {
zone_trips[trip_cnt].type = THERMAL_TRIP_PASSIVE;
trip_cnt++;
}
for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
ret = thermal_acpi_active_trip_temp(zone_adev, i,
&zone_trips[trip_cnt].temperature);
if (ret)
break;
zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;
trip_cnt++;
}
return trip_cnt;
}
static struct thermal_zone_params int340x_thermal_params = {
.governor_name = "user_space",
.no_hwmon = true,
};
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
int (*get_temp) (struct thermal_zone_device *, int *))
{
struct int34x_thermal_zone *int34x_zone;
struct thermal_trip *zone_trips;
unsigned long long trip_cnt = 0;
unsigned long long hyst;
int trip_mask = 0;
acpi_status status;
int i, ret;
int34x_zone = kzalloc(sizeof(*int34x_zone), GFP_KERNEL);
if (!int34x_zone)
return ERR_PTR(-ENOMEM);
int34x_zone->adev = adev;
int34x_zone->ops = kmemdup(&int340x_thermal_zone_ops,
sizeof(int340x_thermal_zone_ops), GFP_KERNEL);
if (!int34x_zone->ops) {
ret = -ENOMEM;
goto err_ops_alloc;
}
if (get_temp)
int34x_zone->ops->get_temp = get_temp;
status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
if (ACPI_SUCCESS(status)) {
int34x_zone->aux_trip_nr = trip_cnt;
trip_mask = BIT(trip_cnt) - 1;
}
zone_trips = kzalloc(sizeof(*zone_trips) * (trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT),
GFP_KERNEL);
if (!zone_trips) {
ret = -ENOMEM;
goto err_trips_alloc;
}
for (i = 0; i < trip_cnt; i++) {
zone_trips[i].type = THERMAL_TRIP_PASSIVE;
zone_trips[i].temperature = THERMAL_TEMP_INVALID;
}
trip_cnt = int340x_thermal_read_trips(adev, zone_trips, trip_cnt);
status = acpi_evaluate_integer(adev->handle, "GTSH", NULL, &hyst);
if (ACPI_SUCCESS(status))
hyst *= 100;
else
hyst = 0;
for (i = 0; i < trip_cnt; ++i)
zone_trips[i].hysteresis = hyst;
int34x_zone->trips = zone_trips;
int34x_zone->lpat_table = acpi_lpat_get_conversion_table(adev->handle);
int34x_zone->zone = thermal_zone_device_register_with_trips(
acpi_device_bid(adev),
zone_trips, trip_cnt,
trip_mask, int34x_zone,
int34x_zone->ops,
&int340x_thermal_params,
0, 0);
if (IS_ERR(int34x_zone->zone)) {
ret = PTR_ERR(int34x_zone->zone);
goto err_thermal_zone;
}
ret = thermal_zone_device_enable(int34x_zone->zone);
if (ret)
goto err_enable;
return int34x_zone;
err_enable:
thermal_zone_device_unregister(int34x_zone->zone);
err_thermal_zone:
kfree(int34x_zone->trips);
acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
err_trips_alloc:
kfree(int34x_zone->ops);
err_ops_alloc:
kfree(int34x_zone);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)
{
thermal_zone_device_unregister(int34x_zone->zone);
acpi_lpat_free_conversion_table(int34x_zone->lpat_table);
kfree(int34x_zone->trips);
kfree(int34x_zone->ops);
kfree(int34x_zone);
}
EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
{
struct acpi_device *zone_adev = int34x_zone->adev;
struct thermal_trip *zone_trips = int34x_zone->trips;
int trip_cnt = int34x_zone->zone->num_trips;
int act_trip_nr = 0;
int i;
mutex_lock(&int34x_zone->zone->lock);
for (i = int34x_zone->aux_trip_nr; i < trip_cnt; i++) {
int temp, err;
switch (zone_trips[i].type) {
case THERMAL_TRIP_CRITICAL:
err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
break;
case THERMAL_TRIP_HOT:
err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
break;
case THERMAL_TRIP_PASSIVE:
err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
break;
case THERMAL_TRIP_ACTIVE:
err = thermal_acpi_active_trip_temp(zone_adev, act_trip_nr++,
&temp);
break;
default:
err = -ENODEV;
}
if (err) {
zone_trips[i].temperature = THERMAL_TEMP_INVALID;
continue;
}
zone_trips[i].temperature = temp;
}
mutex_unlock(&int34x_zone->zone->lock);
}
EXPORT_SYMBOL_GPL(int340x_thermal_update_trips);
MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
MODULE_LICENSE("GPL v2");