brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 31ed338 Raw
244 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * int340x_thermal_zone.c4 * Copyright (c) 2015, Intel Corporation.5 */6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/init.h>9#include <linux/acpi.h>10#include <linux/thermal.h>11#include <linux/units.h>12#include "int340x_thermal_zone.h"13 14static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,15					 int *temp)16{17	struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);18	unsigned long long tmp;19	acpi_status status;20 21	status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);22	if (ACPI_FAILURE(status))23		return -EIO;24 25	if (d->lpat_table) {26		int conv_temp;27 28		conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);29		if (conv_temp < 0)30			return conv_temp;31 32		*temp = conv_temp * 10;33	} else {34		/* _TMP returns the temperature in tenths of degrees Kelvin */35		*temp = deci_kelvin_to_millicelsius(tmp);36	}37 38	return 0;39}40 41static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,42					 const struct thermal_trip *trip, int temp)43{44	struct int34x_thermal_zone *d = thermal_zone_device_priv(zone);45	unsigned int trip_index = THERMAL_TRIP_PRIV_TO_INT(trip->priv);46	char name[] = {'P', 'A', 'T', '0' + trip_index, '\0'};47	acpi_status status;48 49	if (trip_index > 9)50		return -EINVAL;51 52	status = acpi_execute_simple_method(d->adev->handle, name,53					    millicelsius_to_deci_kelvin(temp));54	if (ACPI_FAILURE(status))55		return -EIO;56 57	return 0;58}59 60static void int340x_thermal_critical(struct thermal_zone_device *zone)61{62	dev_dbg(thermal_zone_device(zone), "%s: critical temperature reached\n",63		thermal_zone_device_type(zone));64}65 66static int int340x_thermal_read_trips(struct acpi_device *zone_adev,67				      struct thermal_trip *zone_trips,68				      int trip_cnt)69{70	int i, ret;71 72	ret = thermal_acpi_critical_trip_temp(zone_adev,73					      &zone_trips[trip_cnt].temperature);74	if (!ret) {75		zone_trips[trip_cnt].type = THERMAL_TRIP_CRITICAL;76		trip_cnt++;77	}78 79	ret = thermal_acpi_hot_trip_temp(zone_adev,80					 &zone_trips[trip_cnt].temperature);81	if (!ret) {82		zone_trips[trip_cnt].type = THERMAL_TRIP_HOT;83		trip_cnt++;84	}85 86	ret = thermal_acpi_passive_trip_temp(zone_adev,87					     &zone_trips[trip_cnt].temperature);88	if (!ret) {89		zone_trips[trip_cnt].type = THERMAL_TRIP_PASSIVE;90		trip_cnt++;91	}92 93	for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {94		ret = thermal_acpi_active_trip_temp(zone_adev, i,95						    &zone_trips[trip_cnt].temperature);96		if (ret)97			break;98 99		zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;100		zone_trips[trip_cnt].priv = THERMAL_INT_TO_TRIP_PRIV(i);101		trip_cnt++;102	}103 104	return trip_cnt;105}106 107static struct thermal_zone_params int340x_thermal_params = {108	.governor_name = "user_space",109	.no_hwmon = true,110};111 112struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,113						     int (*get_temp) (struct thermal_zone_device *, int *))114{115	const struct thermal_zone_device_ops zone_ops = {116		.set_trip_temp = int340x_thermal_set_trip_temp,117		.critical = int340x_thermal_critical,118		.get_temp = get_temp ? get_temp : int340x_thermal_get_zone_temp,119	};120	struct int34x_thermal_zone *int34x_zone;121	struct thermal_trip *zone_trips;122	unsigned long long trip_cnt = 0;123	unsigned long long hyst;124	acpi_status status;125	int i, ret;126 127	int34x_zone = kzalloc(sizeof(*int34x_zone), GFP_KERNEL);128	if (!int34x_zone)129		return ERR_PTR(-ENOMEM);130 131	int34x_zone->adev = adev;132 133	status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);134	if (ACPI_SUCCESS(status))135		int34x_zone->aux_trip_nr = trip_cnt;136 137	zone_trips = kzalloc(sizeof(*zone_trips) * (trip_cnt + INT340X_THERMAL_MAX_TRIP_COUNT),138			     GFP_KERNEL);139	if (!zone_trips) {140		ret = -ENOMEM;141		goto err_trips_alloc;142	}143 144	for (i = 0; i < trip_cnt; i++) {145		zone_trips[i].type = THERMAL_TRIP_PASSIVE;146		zone_trips[i].temperature = THERMAL_TEMP_INVALID;147		zone_trips[i].flags |= THERMAL_TRIP_FLAG_RW_TEMP;148		zone_trips[i].priv = THERMAL_INT_TO_TRIP_PRIV(i);149	}150 151	trip_cnt = int340x_thermal_read_trips(adev, zone_trips, trip_cnt);152 153	status = acpi_evaluate_integer(adev->handle, "GTSH", NULL, &hyst);154	if (ACPI_SUCCESS(status))155		hyst *= 100;156	else157		hyst = 0;158 159	for (i = 0; i < trip_cnt; ++i)160		zone_trips[i].hysteresis = hyst;161 162	int34x_zone->lpat_table = acpi_lpat_get_conversion_table(adev->handle);163 164	int34x_zone->zone = thermal_zone_device_register_with_trips(165							acpi_device_bid(adev),166							zone_trips, trip_cnt,167							int34x_zone,168							&zone_ops,169							&int340x_thermal_params,170							0, 0);171	kfree(zone_trips);172 173	if (IS_ERR(int34x_zone->zone)) {174		ret = PTR_ERR(int34x_zone->zone);175		goto err_thermal_zone;176	}177	ret = thermal_zone_device_enable(int34x_zone->zone);178	if (ret)179		goto err_enable;180 181	return int34x_zone;182 183err_enable:184	thermal_zone_device_unregister(int34x_zone->zone);185err_thermal_zone:186	acpi_lpat_free_conversion_table(int34x_zone->lpat_table);187err_trips_alloc:188	kfree(int34x_zone);189	return ERR_PTR(ret);190}191EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);192 193void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)194{195	thermal_zone_device_unregister(int34x_zone->zone);196	acpi_lpat_free_conversion_table(int34x_zone->lpat_table);197	kfree(int34x_zone);198}199EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);200 201static int int340x_update_one_trip(struct thermal_trip *trip, void *arg)202{203	struct int34x_thermal_zone *int34x_zone = arg;204	struct acpi_device *zone_adev = int34x_zone->adev;205	int temp, err;206 207	switch (trip->type) {208	case THERMAL_TRIP_CRITICAL:209		err = thermal_acpi_critical_trip_temp(zone_adev, &temp);210		break;211	case THERMAL_TRIP_HOT:212		err = thermal_acpi_hot_trip_temp(zone_adev, &temp);213		break;214	case THERMAL_TRIP_PASSIVE:215		err = thermal_acpi_passive_trip_temp(zone_adev, &temp);216		break;217	case THERMAL_TRIP_ACTIVE:218		err = thermal_acpi_active_trip_temp(zone_adev,219						    THERMAL_TRIP_PRIV_TO_INT(trip->priv),220						    &temp);221		break;222	default:223		err = -ENODEV;224	}225	if (err)226		temp = THERMAL_TEMP_INVALID;227 228	thermal_zone_set_trip_temp(int34x_zone->zone, trip, temp);229 230	return 0;231}232 233void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)234{235	thermal_zone_for_each_trip(int34x_zone->zone, int340x_update_one_trip,236				   int34x_zone);237}238EXPORT_SYMBOL_GPL(int340x_thermal_update_trips);239 240MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");241MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");242MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");243MODULE_LICENSE("GPL v2");244