linux-stable/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c

269 lines
6.7 KiB
C
Raw Normal View History

// 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>
thermal: int340x: switch to use <linux/units.h> helpers This switches the int340x thermal zone driver to use deci_kelvin_to_millicelsius() and millicelsius_to_deci_kelvin() in <linux/units.h> instead of helpers in <linux/thermal.h>. This is preparation for centralizing the kelvin to/from Celsius conversion helpers in <linux/units.h>. Link: http://lkml.kernel.org/r/1576386975-7941-6-git-send-email-akinobu.mita@gmail.com Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: Sujith Thomas <sujith.thomas@intel.com> Cc: Darren Hart <dvhart@infradead.org> Cc: Andy Shevchenko <andy@infradead.org> Cc: Zhang Rui <rui.zhang@intel.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Amit Kucheria <amit.kucheria@verdurent.com> Cc: Jean Delvare <jdelvare@suse.com> Cc: Guenter Roeck <linux@roeck-us.net> Cc: Keith Busch <kbusch@kernel.org> Cc: Jens Axboe <axboe@fb.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Sagi Grimberg <sagi@grimberg.me> Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Cc: Hartmut Knaack <knaack.h@gmx.de> Cc: Johannes Berg <johannes.berg@intel.com> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com> Cc: Kalle Valo <kvalo@codeaurora.org> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Luca Coelho <luciano.coelho@intel.com> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-31 06:15:44 +00:00
#include <linux/units.h>
#include "int340x_thermal_zone.h"
static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
thermal: consistently use int for temperatures The thermal code uses int, long and unsigned long for temperatures in different places. Using an unsigned type limits the thermal framework to positive temperatures without need. Also several drivers currently will report temperatures near UINT_MAX for temperatures below 0°C. This will probably immediately shut the machine down due to overtemperature if started below 0°C. 'long' is 64bit on several architectures. This is not needed since INT_MAX °mC is above the melting point of all known materials. Consistently use a plain 'int' for temperatures throughout the thermal code and the drivers. This only changes the places in the drivers where the temperature is passed around as pointer, when drivers internally use another type this is not changed. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Jean Delvare <jdelvare@suse.de> Reviewed-by: Lukasz Majewski <l.majewski@samsung.com> Reviewed-by: Darren Hart <dvhart@linux.intel.com> Reviewed-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Peter Feuerer <peter@piie.net> Cc: Punit Agrawal <punit.agrawal@arm.com> Cc: Zhang Rui <rui.zhang@intel.com> Cc: Eduardo Valentin <edubezval@gmail.com> Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Jean Delvare <jdelvare@suse.de> Cc: Peter Feuerer <peter@piie.net> Cc: Heiko Stuebner <heiko@sntech.de> Cc: Lukasz Majewski <l.majewski@samsung.com> Cc: Stephen Warren <swarren@wwwdotorg.org> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: linux-acpi@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: Guenter Roeck <linux@roeck-us.net> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Maxime Ripard <maxime.ripard@free-electrons.com> Cc: Darren Hart <dvhart@infradead.org> Cc: lm-sensors@lm-sensors.org Signed-off-by: Zhang Rui <rui.zhang@intel.com>
2015-07-24 06:12:54 +00:00
int *temp)
{
2023-03-01 20:14:30 +00:00
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 */
thermal: int340x: switch to use <linux/units.h> helpers This switches the int340x thermal zone driver to use deci_kelvin_to_millicelsius() and millicelsius_to_deci_kelvin() in <linux/units.h> instead of helpers in <linux/thermal.h>. This is preparation for centralizing the kelvin to/from Celsius conversion helpers in <linux/units.h>. Link: http://lkml.kernel.org/r/1576386975-7941-6-git-send-email-akinobu.mita@gmail.com Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: Sujith Thomas <sujith.thomas@intel.com> Cc: Darren Hart <dvhart@infradead.org> Cc: Andy Shevchenko <andy@infradead.org> Cc: Zhang Rui <rui.zhang@intel.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Amit Kucheria <amit.kucheria@verdurent.com> Cc: Jean Delvare <jdelvare@suse.com> Cc: Guenter Roeck <linux@roeck-us.net> Cc: Keith Busch <kbusch@kernel.org> Cc: Jens Axboe <axboe@fb.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Sagi Grimberg <sagi@grimberg.me> Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Cc: Hartmut Knaack <knaack.h@gmx.de> Cc: Johannes Berg <johannes.berg@intel.com> Cc: Jonathan Cameron <jic23@kernel.org> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com> Cc: Kalle Valo <kvalo@codeaurora.org> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Luca Coelho <luciano.coelho@intel.com> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-31 06:15:44 +00:00
*temp = deci_kelvin_to_millicelsius(tmp);
}
return 0;
}
static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
int trip, int temp)
{
2023-03-01 20:14:30 +00:00
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 inline void *int_to_trip_priv(int i)
{
return (void *)(long)i;
}
static inline int trip_priv_to_int(const struct thermal_trip *trip)
{
return (long)trip->priv;
}
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;
zone_trips[trip_cnt].priv = int_to_trip_priv(i);
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);
static int int340x_update_one_trip(struct thermal_trip *trip, void *arg)
{
struct int34x_thermal_zone *int34x_zone = arg;
struct acpi_device *zone_adev = int34x_zone->adev;
int temp, err;
switch (trip->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,
trip_priv_to_int(trip),
&temp);
break;
default:
err = -ENODEV;
}
if (err)
temp = THERMAL_TEMP_INVALID;
thermal_zone_set_trip_temp(int34x_zone->zone, trip, temp);
return 0;
}
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
{
thermal_zone_for_each_trip(int34x_zone->zone, int340x_update_one_trip,
int34x_zone);
}
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");