提交 9346116d 编写于 作者: L Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux

Pull thermal management updates from Zhang Rui:

 - Thermal core code reorganization and cleanup. Two new files are
   created for thermal sysfs I/F code and thermal helper functions
   (Eduardo Valentin).

 - Sanitize hotplug and locking for x86_pkg_temp driver (Thomas
   Gleixner)

 - Update MAINTAINER file for pwm-fan driver and Samsung thermal driver
   (Lukasz Majewski)

 - Fix module auto-load for max77620, tango and db8500 thermal driver
   (Javier Martinez Canillas)

 - Fix a bug that thermal hwmon sysfs I/F returns wrong critical trip
   point temperature value (Krzysztof Kozlowski)

 - Add Skylake PCH 100 series support for intel_pch_thermal driver
   (OGAWA Hirofumi)

 - Small fixes and cleanups for platform thermal drivers (Julia Lawall,
   Luis Henriques, Leo Yan, Stephen Boyd, Shawn Lin, Javi Merino and
   Lukasz Luba)

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: (76 commits)
  MAINTAINERS: Samsung: Update maintainer for PWM FAN and SAMSUNG THERMAL
  thermal/x86 pkg temp: Convert to hotplug state machine
  thermal/x86_pkg_temp: Sanitize package management
  thermal/x86_pkg_temp: Move work into package struct
  thermal/x86_pkg_temp: Move work scheduled flag into package struct
  thermal/x86_pkg_temp: Sanitize locking
  thermal/x86_pkg_temp: Cleanup code some more
  thermal/x86_pkg_temp: Cleanup namespace
  thermal/x86_pkg_temp: Get rid of ref counting
  thermal/x86_pkg_temp: Sanitize callback (de)initialization
  thermal/x86_pkg_temp: Replace open coded cpu search
  thermal/x86_pkg_temp: Remove redundant package search
  thermal/x86_pkg_temp: Cleanup thermal interrupt handling
  thermal: hwmon: Properly report critical temperature in sysfs
  devfreq_cooling: pass a pointer to devfreq in the power model callbacks
  devfreq_cooling: make the structs devfreq_cooling_xxx visible for all
  dt-bindings: rockchip-thermal: fix the misleading description
  thermal: rockchip: improve the warning log
  thermal: db8500: Fix module autoload
  thermal: tango: Fix module autoload
  ...
......@@ -22,10 +22,13 @@ Required properties:
TSADC controller.
- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend.
- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
Optional properties:
- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value.
- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO.
- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW
1:HIGH.
- rockchip,grf : The phandle of the syscon node for the general register file.
Exiample:
tsadc: tsadc@ff280000 {
......
......@@ -9838,7 +9838,7 @@ F: drivers/media/usb/pwc/*
PWM FAN DRIVER
M: Kamil Debski <kamil@wypas.org>
M: Lukasz Majewski <l.majewski@samsung.com>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-hwmon@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/hwmon/pwm-fan.txt
......@@ -10609,7 +10609,7 @@ L: netdev@vger.kernel.org
F: drivers/net/ethernet/samsung/sxgbe/
SAMSUNG THERMAL DRIVER
M: Lukasz Majewski <l.majewski@samsung.com>
M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-pm@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org
S: Supported
......
......@@ -177,8 +177,10 @@ config THERMAL_EMULATION
config HISI_THERMAL
tristate "Hisilicon thermal driver"
depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST
depends on ARCH_HISI || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
default y
help
Enable this to plug hisilicon's thermal sensor driver into the Linux
thermal framework. cpufreq is used as the cooling device to throttle
......
......@@ -3,7 +3,8 @@
#
obj-$(CONFIG_THERMAL) += thermal_sys.o
thermal_sys-y += thermal_core.o
thermal_sys-y += thermal_core.o thermal_sysfs.o \
thermal_helpers.o
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
......
......@@ -512,6 +512,7 @@ static const struct of_device_id db8500_thermal_match[] = {
{ .compatible = "stericsson,db8500-thermal" },
{},
};
MODULE_DEVICE_TABLE(of, db8500_thermal_match);
#endif
static struct platform_driver db8500_thermal_driver = {
......
......@@ -238,7 +238,7 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
return 0;
}
return dfc->power_ops->get_static_power(voltage);
return dfc->power_ops->get_static_power(df, voltage);
}
/**
......@@ -262,7 +262,8 @@ get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq,
struct devfreq_cooling_power *dfc_power = dfc->power_ops;
if (dfc_power->get_dynamic_power)
return dfc_power->get_dynamic_power(freq, voltage);
return dfc_power->get_dynamic_power(dfc->devfreq, freq,
voltage);
freq_mhz = freq / 1000000;
power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage;
......
......@@ -96,7 +96,7 @@ static ssize_t current_uuid_store(struct device *dev,
return -EINVAL;
}
static DEVICE_ATTR(current_uuid, 0644, current_uuid_show, current_uuid_store);
static DEVICE_ATTR_RW(current_uuid);
static DEVICE_ATTR_RO(available_uuids);
static struct attribute *uuid_attrs[] = {
&dev_attr_available_uuids.attr,
......
......@@ -29,6 +29,7 @@
#define PCH_THERMAL_DID_HSW_2 0x8C24 /* Haswell PCH */
#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */
#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */
#define PCH_THERMAL_DID_SKL_H 0xA131 /* Skylake PCH 100 series */
/* Wildcat Point-LP PCH Thermal registers */
#define WPT_TEMP 0x0000 /* Temperature */
......@@ -273,37 +274,44 @@ static struct thermal_zone_device_ops tzd_ops = {
.get_trip_temp = pch_get_trip_temp,
};
enum board_ids {
board_hsw,
board_wpt,
board_skl,
};
static const struct board_info {
const char *name;
const struct pch_dev_ops *ops;
} board_info[] = {
[board_hsw] = {
.name = "pch_haswell",
.ops = &pch_dev_ops_wpt,
},
[board_wpt] = {
.name = "pch_wildcat_point",
.ops = &pch_dev_ops_wpt,
},
[board_skl] = {
.name = "pch_skylake",
.ops = &pch_dev_ops_wpt,
},
};
static int intel_pch_thermal_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
enum board_ids board_id = id->driver_data;
const struct board_info *bi = &board_info[board_id];
struct pch_thermal_device *ptd;
int err;
int nr_trips;
char *dev_name;
ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL);
if (!ptd)
return -ENOMEM;
switch (pdev->device) {
case PCH_THERMAL_DID_WPT:
ptd->ops = &pch_dev_ops_wpt;
dev_name = "pch_wildcat_point";
break;
case PCH_THERMAL_DID_SKL:
ptd->ops = &pch_dev_ops_wpt;
dev_name = "pch_skylake";
break;
case PCH_THERMAL_DID_HSW_1:
case PCH_THERMAL_DID_HSW_2:
ptd->ops = &pch_dev_ops_wpt;
dev_name = "pch_haswell";
break;
default:
dev_err(&pdev->dev, "unknown pch thermal device\n");
return -ENODEV;
}
ptd->ops = bi->ops;
pci_set_drvdata(pdev, ptd);
ptd->pdev = pdev;
......@@ -331,11 +339,11 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev,
if (err)
goto error_cleanup;
ptd->tzd = thermal_zone_device_register(dev_name, nr_trips, 0, ptd,
ptd->tzd = thermal_zone_device_register(bi->name, nr_trips, 0, ptd,
&tzd_ops, NULL, 0, 0);
if (IS_ERR(ptd->tzd)) {
dev_err(&pdev->dev, "Failed to register thermal zone %s\n",
dev_name);
bi->name);
err = PTR_ERR(ptd->tzd);
goto error_cleanup;
}
......@@ -380,10 +388,16 @@ static int intel_pch_thermal_resume(struct device *device)
}
static struct pci_device_id intel_pch_thermal_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_1),
.driver_data = board_hsw, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_HSW_2),
.driver_data = board_hsw, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT),
.driver_data = board_wpt, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL),
.driver_data = board_skl, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL_H),
.driver_data = board_skl, },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
......
......@@ -149,6 +149,7 @@ static struct platform_device_id max77620_thermal_devtype[] = {
{ .name = "max77620-thermal", },
{},
};
MODULE_DEVICE_TABLE(platform, max77620_thermal_devtype);
static struct platform_driver max77620_thermal_driver = {
.driver = {
......
......@@ -200,7 +200,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
struct qpnp_tm_chip *chip;
struct device_node *node;
u8 type, subtype;
u32 res[2];
u32 res;
int ret, irq;
node = pdev->dev.of_node;
......@@ -215,7 +215,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
if (!chip->map)
return -ENXIO;
ret = of_property_read_u32_array(node, "reg", res, 2);
ret = of_property_read_u32(node, "reg", &res);
if (ret < 0)
return ret;
......@@ -228,7 +228,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
if (PTR_ERR(chip->adc) == -EPROBE_DEFER)
return PTR_ERR(chip->adc);
chip->base = res[0];
chip->base = res;
ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
if (ret < 0) {
......
......@@ -524,11 +524,6 @@ static void rk_tsadcv2_initialize(struct regmap *grf, void __iomem *regs,
regs + TSADCV2_AUTO_PERIOD_HT);
writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT,
regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE);
if (IS_ERR(grf)) {
pr_warn("%s: Missing rockchip,grf property\n", __func__);
return;
}
}
/**
......@@ -971,6 +966,8 @@ static int rockchip_configure_from_dt(struct device *dev,
* need this property.
*/
thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(thermal->grf))
dev_warn(dev, "Missing rockchip,grf property\n");
return 0;
}
......
......@@ -107,6 +107,7 @@ static const struct of_device_id tango_sensor_ids[] = {
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tango_sensor_ids);
static struct platform_driver tango_thermal_driver = {
.probe = tango_thermal_probe,
......
此差异已折叠。
......@@ -54,8 +54,34 @@ struct thermal_instance {
unsigned int weight; /* The weight of the cooling device */
};
#define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device)
#define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device)
int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);
void thermal_zone_device_rebind_exception(struct thermal_zone_device *,
const char *, size_t);
void thermal_zone_device_unbind_exception(struct thermal_zone_device *,
const char *, size_t);
int thermal_zone_device_set_policy(struct thermal_zone_device *, char *);
int thermal_build_list_of_policies(char *buf);
/* sysfs I/F */
int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *);
/* used only at binding time */
ssize_t
thermal_cooling_device_trip_point_show(struct device *,
struct device_attribute *, char *);
ssize_t thermal_cooling_device_weight_show(struct device *,
struct device_attribute *, char *);
ssize_t thermal_cooling_device_weight_store(struct device *,
struct device_attribute *,
const char *, size_t);
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
int thermal_gov_step_wise_register(void);
......
/*
* thermal_helpers.c - helper functions to handle thermal devices
*
* Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com>
*
* Highly based on original thermal_core.c
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <trace/events/thermal.h>
#include "thermal_core.h"
int get_tz_trend(struct thermal_zone_device *tz, int trip)
{
enum thermal_trend trend;
if (tz->emul_temperature || !tz->ops->get_trend ||
tz->ops->get_trend(tz, trip, &trend)) {
if (tz->temperature > tz->last_temperature)
trend = THERMAL_TREND_RAISING;
else if (tz->temperature < tz->last_temperature)
trend = THERMAL_TREND_DROPPING;
else
trend = THERMAL_TREND_STABLE;
}
return trend;
}
EXPORT_SYMBOL(get_tz_trend);
struct thermal_instance *
get_thermal_instance(struct thermal_zone_device *tz,
struct thermal_cooling_device *cdev, int trip)
{
struct thermal_instance *pos = NULL;
struct thermal_instance *target_instance = NULL;
mutex_lock(&tz->lock);
mutex_lock(&cdev->lock);
list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
target_instance = pos;
break;
}
}
mutex_unlock(&cdev->lock);
mutex_unlock(&tz->lock);
return target_instance;
}
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
* @temp: a valid pointer to where to store the resulting temperature.
*
* When a valid thermal zone reference is passed, it will fetch its
* temperature and fill @temp.
*
* Return: On success returns 0, an error code otherwise
*/
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
{
int ret = -EINVAL;
int count;
int crit_temp = INT_MAX;
enum thermal_trip_type type;
if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
goto exit;
mutex_lock(&tz->lock);
ret = tz->ops->get_temp(tz, temp);
if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
for (count = 0; count < tz->trips; count++) {
ret = tz->ops->get_trip_type(tz, count, &type);
if (!ret && type == THERMAL_TRIP_CRITICAL) {
ret = tz->ops->get_trip_temp(tz, count,
&crit_temp);
break;
}
}
/*
* Only allow emulating a temperature when the real temperature
* is below the critical temperature so that the emulation code
* cannot hide critical conditions.
*/
if (!ret && *temp < crit_temp)
*temp = tz->emul_temperature;
}
mutex_unlock(&tz->lock);
exit:
return ret;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
void thermal_zone_set_trips(struct thermal_zone_device *tz)
{
int low = -INT_MAX;
int high = INT_MAX;
int trip_temp, hysteresis;
int i, ret;
mutex_lock(&tz->lock);
if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
goto exit;
for (i = 0; i < tz->trips; i++) {
int trip_low;
tz->ops->get_trip_temp(tz, i, &trip_temp);
tz->ops->get_trip_hyst(tz, i, &hysteresis);
trip_low = trip_temp - hysteresis;
if (trip_low < tz->temperature && trip_low > low)
low = trip_low;
if (trip_temp > tz->temperature && trip_temp < high)
high = trip_temp;
}
/* No need to change trip points */
if (tz->prev_low_trip == low && tz->prev_high_trip == high)
goto exit;
tz->prev_low_trip = low;
tz->prev_high_trip = high;
dev_dbg(&tz->device,
"new temperature boundaries: %d < x < %d\n", low, high);
/*
* Set a temperature window. When this window is left the driver
* must inform the thermal core via thermal_zone_device_update.
*/
ret = tz->ops->set_trips(tz, low, high);
if (ret)
dev_err(&tz->device, "Failed to set trips: %d\n", ret);
exit:
mutex_unlock(&tz->lock);
}
EXPORT_SYMBOL_GPL(thermal_zone_set_trips);
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
struct thermal_instance *instance;
unsigned long target = 0;
mutex_lock(&cdev->lock);
/* cooling device is updated*/
if (cdev->updated) {
mutex_unlock(&cdev->lock);
return;
}
/* 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)
target = instance->target;
}
cdev->ops->set_cur_state(cdev, target);
cdev->updated = true;
mutex_unlock(&cdev->lock);
trace_cdev_update(cdev, target);
dev_dbg(&cdev->device, "set to state %lu\n", target);
}
EXPORT_SYMBOL(thermal_cdev_update);
/**
* thermal_zone_get_slope - return the slope attribute of the thermal zone
* @tz: thermal zone device with the slope attribute
*
* Return: If the thermal zone device has a slope attribute, return it, else
* return 1.
*/
int thermal_zone_get_slope(struct thermal_zone_device *tz)
{
if (tz && tz->tzp)
return tz->tzp->slope;
return 1;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_slope);
/**
* thermal_zone_get_offset - return the offset attribute of the thermal zone
* @tz: thermal zone device with the offset attribute
*
* Return: If the thermal zone device has a offset attribute, return it, else
* return 0.
*/
int thermal_zone_get_offset(struct thermal_zone_device *tz)
{
if (tz && tz->tzp)
return tz->tzp->offset;
return 0;
}
EXPORT_SYMBOL_GPL(thermal_zone_get_offset);
......@@ -64,7 +64,7 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf)
struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", hwmon->type);
}
static DEVICE_ATTR(name, 0444, name_show, NULL);
static DEVICE_ATTR_RO(name);
static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
......@@ -98,7 +98,7 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
int temperature;
int ret;
ret = tz->ops->get_trip_temp(tz, 0, &temperature);
ret = tz->ops->get_crit_temp(tz, &temperature);
if (ret)
return ret;
......
此差异已折叠。
......@@ -1298,7 +1298,7 @@ int ti_bandgap_probe(struct platform_device *pdev)
if (IS_ERR(bgp->div_clk)) {
dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n");
ret = PTR_ERR(bgp->div_clk);
goto free_irqs;
goto put_fclock;
}
for (i = 0; i < bgp->conf->sensor_count; i++) {
......@@ -1430,8 +1430,9 @@ int ti_bandgap_probe(struct platform_device *pdev)
if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
clk_disable_unprepare(bgp->fclock);
put_clks:
clk_put(bgp->fclock);
clk_put(bgp->div_clk);
put_fclock:
clk_put(bgp->fclock);
free_irqs:
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
......
......@@ -20,7 +20,6 @@
#include <linux/devfreq.h>
#include <linux/thermal.h>
#ifdef CONFIG_DEVFREQ_THERMAL
/**
* struct devfreq_cooling_power - Devfreq cooling power ops
......@@ -37,12 +36,16 @@
* @dyn_power_coeff * frequency * voltage^2
*/
struct devfreq_cooling_power {
unsigned long (*get_static_power)(unsigned long voltage);
unsigned long (*get_dynamic_power)(unsigned long freq,
unsigned long (*get_static_power)(struct devfreq *devfreq,
unsigned long voltage);
unsigned long (*get_dynamic_power)(struct devfreq *devfreq,
unsigned long freq,
unsigned long voltage);
unsigned long dyn_power_coeff;
};
#ifdef CONFIG_DEVFREQ_THERMAL
struct thermal_cooling_device *
of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
struct devfreq_cooling_power *dfc_power);
......
......@@ -28,6 +28,7 @@
#include <linux/of.h>
#include <linux/idr.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/workqueue.h>
#include <uapi/linux/thermal.h>
......@@ -204,6 +205,7 @@ struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
struct device device;
struct attribute_group trips_attribute_group;
struct thermal_attr *trip_temp_attrs;
struct thermal_attr *trip_type_attrs;
struct thermal_attr *trip_hyst_attrs;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册