From 5fbf7f27fa3da2c7b538772cfe3340391ef8b3b9 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 16 Jan 2015 15:59:03 -0800 Subject: Thermal/int340x: Add common thermal zone handler Most of the processing for each int340x driver to add a thermal zone is very similar and every driver has to duplicate code. Created a common module, which exports API to add and remove zones. In this way, we not only avoid duplicate code but also helps in bug fixes and enhancements. If for some driver default processing for thermal zone callback is not enough they can overide individual callback. The code for this driver is primarily copied from int3402_thermal.c. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/int340x_thermal/Makefile | 1 + .../thermal/int340x_thermal/int340x_thermal_zone.c | 262 +++++++++++++++++++++ .../thermal/int340x_thermal/int340x_thermal_zone.h | 65 +++++ 3 files changed, 328 insertions(+) create mode 100644 drivers/thermal/int340x_thermal/int340x_thermal_zone.c create mode 100644 drivers/thermal/int340x_thermal/int340x_thermal_zone.h (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile index d4413698a85f..ba77a34f659f 100644 --- a/drivers/thermal/int340x_thermal/Makefile +++ b/drivers/thermal/int340x_thermal/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o +obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c new file mode 100644 index 000000000000..162e545cc93a --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c @@ -0,0 +1,262 @@ +/* + * int340x_thermal_zone.c + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include +#include +#include +#include +#include +#include "int340x_thermal_zone.h" + +static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, + unsigned long *temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + unsigned long long tmp; + acpi_status status; + + if (d->override_ops && d->override_ops->get_temp) + return d->override_ops->get_temp(zone, temp); + + status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp); + if (ACPI_FAILURE(status)) + return -EIO; + + /* _TMP returns the temperature in tenths of degrees Kelvin */ + *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); + + return 0; +} + +static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, + int trip, unsigned long *temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + int i; + + if (d->override_ops && d->override_ops->get_trip_temp) + return d->override_ops->get_trip_temp(zone, trip, temp); + + if (trip < d->aux_trip_nr) + *temp = d->aux_trips[trip]; + else if (trip == d->crt_trip_id) + *temp = d->crt_temp; + else if (trip == d->psv_trip_id) + *temp = d->psv_temp; + else if (trip == d->hot_trip_id) + *temp = d->hot_temp; + else { + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { + if (d->act_trips[i].valid && + d->act_trips[i].id == trip) { + *temp = d->act_trips[i].temp; + break; + } + } + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) + return -EINVAL; + } + + return 0; +} + +static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, + int trip, + enum thermal_trip_type *type) +{ + struct int34x_thermal_zone *d = zone->devdata; + int i; + + if (d->override_ops && d->override_ops->get_trip_type) + return d->override_ops->get_trip_type(zone, trip, type); + + if (trip < d->aux_trip_nr) + *type = THERMAL_TRIP_PASSIVE; + else if (trip == d->crt_trip_id) + *type = THERMAL_TRIP_CRITICAL; + else if (trip == d->hot_trip_id) + *type = THERMAL_TRIP_HOT; + else if (trip == d->psv_trip_id) + *type = THERMAL_TRIP_PASSIVE; + else { + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { + if (d->act_trips[i].valid && + d->act_trips[i].id == trip) { + *type = THERMAL_TRIP_ACTIVE; + break; + } + } + if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT) + return -EINVAL; + } + + return 0; +} + +static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, + int trip, unsigned long temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + acpi_status status; + char name[10]; + + if (d->override_ops && d->override_ops->set_trip_temp) + return d->override_ops->set_trip_temp(zone, trip, temp); + + snprintf(name, sizeof(name), "PAT%d", trip); + status = acpi_execute_simple_method(d->adev->handle, name, + MILLICELSIUS_TO_DECI_KELVIN(temp)); + if (ACPI_FAILURE(status)) + return -EIO; + + d->aux_trips[trip] = temp; + + return 0; +} + + +static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, + int trip, unsigned long *temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + acpi_status status; + unsigned long long hyst; + + if (d->override_ops && d->override_ops->get_trip_hyst) + return d->override_ops->get_trip_hyst(zone, trip, temp); + + status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst); + if (ACPI_FAILURE(status)) + return -EIO; + + *temp = hyst * 100; + + return 0; +} + +static struct thermal_zone_device_ops int340x_thermal_zone_ops = { + .get_temp = int340x_thermal_get_zone_temp, + .get_trip_temp = int340x_thermal_get_trip_temp, + .get_trip_type = int340x_thermal_get_trip_type, + .set_trip_temp = int340x_thermal_set_trip_temp, + .get_trip_hyst = int340x_thermal_get_trip_hyst, +}; + +static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, + unsigned long *temp) +{ + unsigned long long r; + acpi_status status; + + status = acpi_evaluate_integer(handle, name, NULL, &r); + if (ACPI_FAILURE(status)) + return -EIO; + + *temp = DECI_KELVIN_TO_MILLICELSIUS(r); + + return 0; +} + +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, + struct thermal_zone_device_ops *override_ops) +{ + struct int34x_thermal_zone *int34x_thermal_zone; + acpi_status status; + unsigned long long trip_cnt; + int trip_mask = 0, i; + int ret; + + int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone), + GFP_KERNEL); + if (!int34x_thermal_zone) + return ERR_PTR(-ENOMEM); + + int34x_thermal_zone->adev = adev; + int34x_thermal_zone->override_ops = override_ops; + + status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); + if (ACPI_FAILURE(status)) + trip_cnt = 0; + else { + int34x_thermal_zone->aux_trips = kzalloc( + sizeof(*int34x_thermal_zone->aux_trips) * + trip_cnt, GFP_KERNEL); + if (!int34x_thermal_zone->aux_trips) { + ret = -ENOMEM; + goto free_mem; + } + trip_mask = BIT(trip_cnt) - 1; + int34x_thermal_zone->aux_trip_nr = trip_cnt; + } + + int34x_thermal_zone->crt_trip_id = -1; + if (!int340x_thermal_get_trip_config(adev->handle, "_CRT", + &int34x_thermal_zone->crt_temp)) + int34x_thermal_zone->crt_trip_id = trip_cnt++; + int34x_thermal_zone->hot_trip_id = -1; + if (!int340x_thermal_get_trip_config(adev->handle, "_HOT", + &int34x_thermal_zone->hot_temp)) + int34x_thermal_zone->hot_trip_id = trip_cnt++; + int34x_thermal_zone->psv_trip_id = -1; + if (!int340x_thermal_get_trip_config(adev->handle, "_PSV", + &int34x_thermal_zone->psv_temp)) + int34x_thermal_zone->psv_trip_id = trip_cnt++; + for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) { + char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; + + if (int340x_thermal_get_trip_config(adev->handle, name, + &int34x_thermal_zone->act_trips[i].temp)) + break; + + int34x_thermal_zone->act_trips[i].id = trip_cnt++; + int34x_thermal_zone->act_trips[i].valid = true; + } + + int34x_thermal_zone->zone = thermal_zone_device_register( + acpi_device_bid(adev), + trip_cnt, + trip_mask, int34x_thermal_zone, + &int340x_thermal_zone_ops, + &int340x_thermal_params, + 0, 0); + if (IS_ERR(int34x_thermal_zone->zone)) { + ret = PTR_ERR(int34x_thermal_zone->zone); + goto free_mem; + } + + return int34x_thermal_zone; + +free_mem: + kfree(int34x_thermal_zone); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(int340x_thermal_zone_add); + +void int340x_thermal_zone_remove(struct int34x_thermal_zone + *int34x_thermal_zone) +{ + thermal_zone_device_unregister(int34x_thermal_zone->zone); + kfree(int34x_thermal_zone); +} +EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); + +MODULE_AUTHOR("Aaron Lu "); +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h new file mode 100644 index 000000000000..11f2f5260c3a --- /dev/null +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h @@ -0,0 +1,65 @@ +/* + * int340x_thermal_zone.h + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __INT340X_THERMAL_ZONE_H__ +#define __INT340X_THERMAL_ZONE_H__ + +#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 + +struct active_trip { + unsigned long temp; + int id; + bool valid; +}; + +struct int34x_thermal_zone { + struct acpi_device *adev; + struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; + unsigned long *aux_trips; + int aux_trip_nr; + unsigned long psv_temp; + int psv_trip_id; + unsigned long crt_temp; + int crt_trip_id; + unsigned long hot_temp; + int hot_trip_id; + struct thermal_zone_device *zone; + struct thermal_zone_device_ops *override_ops; + void *priv_data; +}; + +struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, + struct thermal_zone_device_ops *override_ops); +void int340x_thermal_zone_remove(struct int34x_thermal_zone *); + +static inline void int340x_thermal_zone_set_priv_data( + struct int34x_thermal_zone *tzone, void *priv_data) +{ + tzone->priv_data = priv_data; +} + +static inline void *int340x_thermal_zone_get_priv_data( + struct int34x_thermal_zone *tzone) +{ + return tzone->priv_data; +} + +static inline void int340x_thermal_zone_device_update( + struct int34x_thermal_zone *tzone) +{ + thermal_zone_device_update(tzone->zone); +} + +#endif -- cgit v1.2.3 From 820cdeba4086c74eb977088f1f9d31fd4c0aba9a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 16 Jan 2015 15:59:04 -0800 Subject: Thermal/int340x/int3402: Use int340x thermal API Using APIs from int340x thermal zone module to add and remove thermal zones. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/int340x_thermal/int3402_thermal.c | 189 ++-------------------- 1 file changed, 11 insertions(+), 178 deletions(-) (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index c5cbc3af3a05..7ffc749ce0f2 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c @@ -14,152 +14,17 @@ #include #include #include - -#define ACPI_ACTIVE_COOLING_MAX_NR 10 - -struct active_trip { - unsigned long temp; - int id; - bool valid; -}; +#include "int340x_thermal_zone.h" struct int3402_thermal_data { - unsigned long *aux_trips; - int aux_trip_nr; - unsigned long psv_temp; - int psv_trip_id; - unsigned long crt_temp; - int crt_trip_id; - unsigned long hot_temp; - int hot_trip_id; - struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR]; acpi_handle *handle; + struct int34x_thermal_zone *int340x_zone; }; -static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, - unsigned long *temp) -{ - struct int3402_thermal_data *d = zone->devdata; - unsigned long long tmp; - acpi_status status; - - status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp); - if (ACPI_FAILURE(status)) - return -ENODEV; - - /* _TMP returns the temperature in tenths of degrees Kelvin */ - *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); - - return 0; -} - -static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone, - int trip, unsigned long *temp) -{ - struct int3402_thermal_data *d = zone->devdata; - int i; - - if (trip < d->aux_trip_nr) - *temp = d->aux_trips[trip]; - else if (trip == d->crt_trip_id) - *temp = d->crt_temp; - else if (trip == d->psv_trip_id) - *temp = d->psv_temp; - else if (trip == d->hot_trip_id) - *temp = d->hot_temp; - else { - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { - if (d->act_trips[i].valid && - d->act_trips[i].id == trip) { - *temp = d->act_trips[i].temp; - break; - } - } - if (i == ACPI_ACTIVE_COOLING_MAX_NR) - return -EINVAL; - } - return 0; -} - -static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone, - int trip, enum thermal_trip_type *type) -{ - struct int3402_thermal_data *d = zone->devdata; - int i; - - if (trip < d->aux_trip_nr) - *type = THERMAL_TRIP_PASSIVE; - else if (trip == d->crt_trip_id) - *type = THERMAL_TRIP_CRITICAL; - else if (trip == d->hot_trip_id) - *type = THERMAL_TRIP_HOT; - else if (trip == d->psv_trip_id) - *type = THERMAL_TRIP_PASSIVE; - else { - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { - if (d->act_trips[i].valid && - d->act_trips[i].id == trip) { - *type = THERMAL_TRIP_ACTIVE; - break; - } - } - if (i == ACPI_ACTIVE_COOLING_MAX_NR) - return -EINVAL; - } - return 0; -} - -static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip, - unsigned long temp) -{ - struct int3402_thermal_data *d = zone->devdata; - acpi_status status; - char name[10]; - - snprintf(name, sizeof(name), "PAT%d", trip); - status = acpi_execute_simple_method(d->handle, name, - MILLICELSIUS_TO_DECI_KELVIN(temp)); - if (ACPI_FAILURE(status)) - return -EIO; - - d->aux_trips[trip] = temp; - return 0; -} - -static struct thermal_zone_device_ops int3402_thermal_zone_ops = { - .get_temp = int3402_thermal_get_zone_temp, - .get_trip_temp = int3402_thermal_get_trip_temp, - .get_trip_type = int3402_thermal_get_trip_type, - .set_trip_temp = int3402_thermal_set_trip_temp, -}; - -static struct thermal_zone_params int3402_thermal_params = { - .governor_name = "user_space", - .no_hwmon = true, -}; - -static int int3402_thermal_get_temp(acpi_handle handle, char *name, - unsigned long *temp) -{ - unsigned long long r; - acpi_status status; - - status = acpi_evaluate_integer(handle, name, NULL, &r); - if (ACPI_FAILURE(status)) - return -EIO; - - *temp = DECI_KELVIN_TO_MILLICELSIUS(r); - return 0; -} - static int int3402_thermal_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct int3402_thermal_data *d; - struct thermal_zone_device *zone; - acpi_status status; - unsigned long long trip_cnt; - int trip_mask = 0, i; if (!acpi_has_method(adev->handle, "_TMP")) return -ENODEV; @@ -168,54 +33,22 @@ static int int3402_thermal_probe(struct platform_device *pdev) if (!d) return -ENOMEM; - status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); - if (ACPI_FAILURE(status)) - trip_cnt = 0; - else { - d->aux_trips = devm_kzalloc(&pdev->dev, - sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); - if (!d->aux_trips) - return -ENOMEM; - trip_mask = trip_cnt - 1; - d->handle = adev->handle; - d->aux_trip_nr = trip_cnt; - } - - d->crt_trip_id = -1; - if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp)) - d->crt_trip_id = trip_cnt++; - d->hot_trip_id = -1; - if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp)) - d->hot_trip_id = trip_cnt++; - d->psv_trip_id = -1; - if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp)) - d->psv_trip_id = trip_cnt++; - for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { - char name[5] = { '_', 'A', 'C', '0' + i, '\0' }; - if (int3402_thermal_get_temp(adev->handle, name, - &d->act_trips[i].temp)) - break; - d->act_trips[i].id = trip_cnt++; - d->act_trips[i].valid = true; - } - - zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, - trip_mask, d, - &int3402_thermal_zone_ops, - &int3402_thermal_params, - 0, 0); - if (IS_ERR(zone)) - return PTR_ERR(zone); - platform_set_drvdata(pdev, zone); + d->int340x_zone = int340x_thermal_zone_add(adev, NULL); + if (IS_ERR(d->int340x_zone)) + return PTR_ERR(d->int340x_zone); + + d->handle = adev->handle; + platform_set_drvdata(pdev, d); return 0; } static int int3402_thermal_remove(struct platform_device *pdev) { - struct thermal_zone_device *zone = platform_get_drvdata(pdev); + struct int3402_thermal_data *d = platform_get_drvdata(pdev); + + int340x_thermal_zone_remove(d->int340x_zone); - thermal_zone_device_unregister(zone); return 0; } -- cgit v1.2.3 From 593df40475b719103e095aa1116653636662077e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 16 Jan 2015 15:59:05 -0800 Subject: Thermal/int340x/int3403: Use int340x thermal API Using APIs from int340x thermal zone module to add and remove thermal zones. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/int340x_thermal/int3403_thermal.c | 208 ++-------------------- 1 file changed, 10 insertions(+), 198 deletions(-) (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 0faf500d8a77..50a7a08e3a15 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c @@ -19,6 +19,7 @@ #include #include #include +#include "int340x_thermal_zone.h" #define INT3403_TYPE_SENSOR 0x03 #define INT3403_TYPE_CHARGER 0x0B @@ -26,18 +27,9 @@ #define INT3403_PERF_CHANGED_EVENT 0x80 #define INT3403_THERMAL_EVENT 0x90 -#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) -#define KELVIN_OFFSET 2732 -#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off)) - +/* Preserved structure for future expandbility */ struct int3403_sensor { - struct thermal_zone_device *tzone; - unsigned long *thresholds; - unsigned long crit_temp; - int crit_trip_id; - unsigned long psv_temp; - int psv_trip_id; - + struct int34x_thermal_zone *int340x_zone; }; struct int3403_performance_state { @@ -63,126 +55,6 @@ struct int3403_priv { void *priv; }; -static int sys_get_curr_temp(struct thermal_zone_device *tzone, - unsigned long *temp) -{ - struct int3403_priv *priv = tzone->devdata; - struct acpi_device *device = priv->adev; - unsigned long long tmp; - acpi_status status; - - status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp); - if (ACPI_FAILURE(status)) - return -EIO; - - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET); - - return 0; -} - -static int sys_get_trip_hyst(struct thermal_zone_device *tzone, - int trip, unsigned long *temp) -{ - struct int3403_priv *priv = tzone->devdata; - struct acpi_device *device = priv->adev; - unsigned long long hyst; - acpi_status status; - - status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst); - if (ACPI_FAILURE(status)) - return -EIO; - - /* - * Thermal hysteresis represents a temperature difference. - * Kelvin and Celsius have same degree size. So the - * conversion here between tenths of degree Kelvin unit - * and Milli-Celsius unit is just to multiply 100. - */ - *temp = hyst * 100; - - return 0; -} - -static int sys_get_trip_temp(struct thermal_zone_device *tzone, - int trip, unsigned long *temp) -{ - struct int3403_priv *priv = tzone->devdata; - struct int3403_sensor *obj = priv->priv; - - if (priv->type != INT3403_TYPE_SENSOR || !obj) - return -EINVAL; - - if (trip == obj->crit_trip_id) - *temp = obj->crit_temp; - else if (trip == obj->psv_trip_id) - *temp = obj->psv_temp; - else { - /* - * get_trip_temp is a mandatory callback but - * PATx method doesn't return any value, so return - * cached value, which was last set from user space - */ - *temp = obj->thresholds[trip]; - } - - return 0; -} - -static int sys_get_trip_type(struct thermal_zone_device *thermal, - int trip, enum thermal_trip_type *type) -{ - struct int3403_priv *priv = thermal->devdata; - struct int3403_sensor *obj = priv->priv; - - /* Mandatory callback, may not mean much here */ - if (trip == obj->crit_trip_id) - *type = THERMAL_TRIP_CRITICAL; - else - *type = THERMAL_TRIP_PASSIVE; - - return 0; -} - -int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip, - unsigned long temp) -{ - struct int3403_priv *priv = tzone->devdata; - struct acpi_device *device = priv->adev; - struct int3403_sensor *obj = priv->priv; - acpi_status status; - char name[10]; - int ret = 0; - - snprintf(name, sizeof(name), "PAT%d", trip); - if (acpi_has_method(device->handle, name)) { - status = acpi_execute_simple_method(device->handle, name, - MILLI_CELSIUS_TO_DECI_KELVIN(temp, - KELVIN_OFFSET)); - if (ACPI_FAILURE(status)) - ret = -EIO; - else - obj->thresholds[trip] = temp; - } else { - ret = -EIO; - dev_err(&device->dev, "sys_set_trip_temp: method not found\n"); - } - - return ret; -} - -static struct thermal_zone_device_ops tzone_ops = { - .get_temp = sys_get_curr_temp, - .get_trip_temp = sys_get_trip_temp, - .get_trip_type = sys_get_trip_type, - .set_trip_temp = sys_set_trip_temp, - .get_trip_hyst = sys_get_trip_hyst, -}; - -static struct thermal_zone_params int3403_thermal_params = { - .governor_name = "user_space", - .no_hwmon = true, -}; - static void int3403_notify(acpi_handle handle, u32 event, void *data) { @@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle, case INT3403_PERF_CHANGED_EVENT: break; case INT3403_THERMAL_EVENT: - thermal_zone_device_update(obj->tzone); + int340x_thermal_zone_device_update(obj->int340x_zone); break; default: dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); @@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle, } } -static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp) -{ - unsigned long long crt; - acpi_status status; - - status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt); - if (ACPI_FAILURE(status)) - return -EIO; - - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET); - - return 0; -} - -static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp) -{ - unsigned long long psv; - acpi_status status; - - status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv); - if (ACPI_FAILURE(status)) - return -EIO; - - *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET); - - return 0; -} - static int int3403_sensor_add(struct int3403_priv *priv) { int result = 0; - acpi_status status; struct int3403_sensor *obj; - unsigned long long trip_cnt; - int trip_mask = 0; obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); if (!obj) @@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv) priv->priv = obj; - status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, - &trip_cnt); - if (ACPI_FAILURE(status)) - trip_cnt = 0; - - if (trip_cnt) { - /* We have to cache, thresholds can't be readback */ - obj->thresholds = devm_kzalloc(&priv->pdev->dev, - sizeof(*obj->thresholds) * trip_cnt, - GFP_KERNEL); - if (!obj->thresholds) { - result = -ENOMEM; - goto err_free_obj; - } - trip_mask = BIT(trip_cnt) - 1; - } - - obj->psv_trip_id = -1; - if (!sys_get_trip_psv(priv->adev, &obj->psv_temp)) - obj->psv_trip_id = trip_cnt++; - - obj->crit_trip_id = -1; - if (!sys_get_trip_crt(priv->adev, &obj->crit_temp)) - obj->crit_trip_id = trip_cnt++; - - obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev), - trip_cnt, trip_mask, priv, &tzone_ops, - &int3403_thermal_params, 0, 0); - if (IS_ERR(obj->tzone)) { - result = PTR_ERR(obj->tzone); - obj->tzone = NULL; - goto err_free_obj; - } + obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL); + if (IS_ERR(obj->int340x_zone)) + return PTR_ERR(obj->int340x_zone); result = acpi_install_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY, int3403_notify, @@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv) return 0; err_free_obj: - thermal_zone_device_unregister(obj->tzone); + int340x_thermal_zone_remove(obj->int340x_zone); return result; } @@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) acpi_remove_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY, int3403_notify); - thermal_zone_device_unregister(obj->tzone); + int340x_thermal_zone_remove(obj->int340x_zone); + return 0; } -- cgit v1.2.3 From 1c55be020806eeffbda6f1a981511e46427eb4ec Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 16 Jan 2015 15:59:06 -0800 Subject: Thermal/int340x/processor_thermal: Add thermal zone support Added thermal zones for processor thermal using APIs provided by int340x thermal zone module. Like other INT340x devices, processor thermal device can also contain trip points and way to get temperature. On some platform there is no ACPI _TMP method, in those platform using IA64 architecture MSRs to get temperature. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- .../int340x_thermal/processor_thermal_device.c | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 0fe5dbbea968..7c3848da2df0 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include "int340x_thermal_zone.h" /* Broadwell-U/HSB thermal reporting device */ #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 @@ -39,6 +41,7 @@ struct proc_thermal_device { struct device *dev; struct acpi_device *adev; struct power_config power_limits[2]; + struct int34x_thermal_zone *int340x_zone; }; enum proc_thermal_emum_mode_type { @@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = { .name = "power_limits" }; +static int stored_tjmax; /* since it is fixed, we can have local storage */ + +static int get_tjmax(void) +{ + u32 eax, edx; + u32 val; + int err; + + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (err) + return err; + + val = (eax >> 16) & 0xff; + if (val) + return val; + + return -EINVAL; +} + +static int read_temp_msr(unsigned long *temp) +{ + int cpu; + u32 eax, edx; + int err; + unsigned long curr_temp_off = 0; + + *temp = 0; + + for_each_online_cpu(cpu) { + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, + &edx); + if (err) + goto err_ret; + else { + if (eax & 0x80000000) { + curr_temp_off = (eax >> 16) & 0x7f; + if (!*temp || curr_temp_off < *temp) + *temp = curr_temp_off; + } else { + err = -EINVAL; + goto err_ret; + } + } + } + + return 0; +err_ret: + return err; +} + +static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, + unsigned long *temp) +{ + int ret; + + ret = read_temp_msr(temp); + if (!ret) + *temp = (stored_tjmax - *temp) * 1000; + + return ret; +} + +static struct thermal_zone_device_ops proc_thermal_local_ops = { + .get_temp = proc_thermal_get_zone_temp, +}; + static int proc_thermal_add(struct device *dev, struct proc_thermal_device **priv) { @@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev, struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *elements, *ppcc; union acpi_object *p; + unsigned long long tmp; + struct thermal_zone_device_ops *ops = NULL; int i; int ret; @@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev, ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group); + if (ret) + goto free_buffer; + + status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); + if (ACPI_FAILURE(status)) { + /* there is no _TMP method, add local method */ + stored_tjmax = get_tjmax(); + if (stored_tjmax > 0) + ops = &proc_thermal_local_ops; + } + + proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); + if (IS_ERR(proc_priv->int340x_zone)) { + sysfs_remove_group(&proc_priv->dev->kobj, + &power_limit_attribute_group); + ret = PTR_ERR(proc_priv->int340x_zone); + } else + ret = 0; free_buffer: kfree(buf.pointer); @@ -187,6 +276,7 @@ free_buffer: void proc_thermal_remove(struct proc_thermal_device *proc_priv) { + int340x_thermal_zone_remove(proc_priv->int340x_zone); sysfs_remove_group(&proc_priv->dev->kobj, &power_limit_attribute_group); } -- cgit v1.2.3 From acebf7eea449f8e18f443804f1f20bc090f22d0a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 23 Dec 2014 15:29:57 -0800 Subject: Thermal/int340x/int3402: Provide notification support This driver supports programmable trips, but didn't register notification handler to receive threshold violation notification. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/int340x_thermal/int3402_thermal.c | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index 7ffc749ce0f2..69df3d960303 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c @@ -16,15 +16,37 @@ #include #include "int340x_thermal_zone.h" +#define INT3402_PERF_CHANGED_EVENT 0x80 +#define INT3402_THERMAL_EVENT 0x90 + struct int3402_thermal_data { acpi_handle *handle; struct int34x_thermal_zone *int340x_zone; }; +static void int3402_notify(acpi_handle handle, u32 event, void *data) +{ + struct int3402_thermal_data *priv = data; + + if (!priv) + return; + + switch (event) { + case INT3402_PERF_CHANGED_EVENT: + break; + case INT3402_THERMAL_EVENT: + int340x_thermal_zone_device_update(priv->int340x_zone); + break; + default: + break; + } +} + static int int3402_thermal_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct int3402_thermal_data *d; + int ret; if (!acpi_has_method(adev->handle, "_TMP")) return -ENODEV; @@ -37,6 +59,15 @@ static int int3402_thermal_probe(struct platform_device *pdev) if (IS_ERR(d->int340x_zone)) return PTR_ERR(d->int340x_zone); + ret = acpi_install_notify_handler(adev->handle, + ACPI_DEVICE_NOTIFY, + int3402_notify, + d); + if (ret) { + int340x_thermal_zone_remove(d->int340x_zone); + return ret; + } + d->handle = adev->handle; platform_set_drvdata(pdev, d); @@ -47,6 +78,8 @@ static int int3402_thermal_remove(struct platform_device *pdev) { struct int3402_thermal_data *d = platform_get_drvdata(pdev); + acpi_remove_notify_handler(d->handle, + ACPI_DEVICE_NOTIFY, int3402_notify); int340x_thermal_zone_remove(d->int340x_zone); return 0; -- cgit v1.2.3 From 317d9dda0522c18eb230367c88601c2e46cda4f8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 28 Jan 2015 11:56:48 -0800 Subject: Thermal/int340x: LPAT conversion for temperature When LPAT table is present, we need to convert raw temperature to real temp using LPAT. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- .../thermal/int340x_thermal/int340x_thermal_zone.c | 20 +++++++++++++++++--- .../thermal/int340x_thermal/int340x_thermal_zone.h | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/thermal/int340x_thermal') diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c index 162e545cc93a..f88b08877025 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c @@ -33,8 +33,17 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, if (ACPI_FAILURE(status)) return -EIO; - /* _TMP returns the temperature in tenths of degrees Kelvin */ - *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); + 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 = (unsigned long)conv_temp * 10; + } else + /* _TMP returns the temperature in tenths of degrees Kelvin */ + *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); return 0; } @@ -227,6 +236,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, int34x_thermal_zone->act_trips[i].id = trip_cnt++; int34x_thermal_zone->act_trips[i].valid = true; } + int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table( + adev->handle); int34x_thermal_zone->zone = thermal_zone_device_register( acpi_device_bid(adev), @@ -237,11 +248,13 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev, 0, 0); if (IS_ERR(int34x_thermal_zone->zone)) { ret = PTR_ERR(int34x_thermal_zone->zone); - goto free_mem; + goto free_lpat; } return int34x_thermal_zone; +free_lpat: + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); free_mem: kfree(int34x_thermal_zone); return ERR_PTR(ret); @@ -252,6 +265,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_thermal_zone) { thermal_zone_device_unregister(int34x_thermal_zone->zone); + acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); kfree(int34x_thermal_zone); } EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h index 11f2f5260c3a..9f38ab72c4bf 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h @@ -16,6 +16,8 @@ #ifndef __INT340X_THERMAL_ZONE_H__ #define __INT340X_THERMAL_ZONE_H__ +#include + #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 struct active_trip { @@ -38,6 +40,7 @@ struct int34x_thermal_zone { struct thermal_zone_device *zone; struct thermal_zone_device_ops *override_ops; void *priv_data; + struct acpi_lpat_conversion_table *lpat_table; }; struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, -- cgit v1.2.3