mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
thermal: int340x: processor_thermal: support acpi notification
BIOS/EC can change PPCC element dynamically and inform OS about the change. When this driver receives notification, it will read PPCC element again. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
This commit is contained in:
parent
b721ca0d19
commit
f1ba9eb85b
@ -198,49 +198,33 @@ 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)
|
||||
static int proc_thermal_read_ppcc(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct acpi_device *adev;
|
||||
int i;
|
||||
acpi_status status;
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (!adev)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf);
|
||||
status = acpi_evaluate_object(proc_priv->adev->handle, "PPCC",
|
||||
NULL, &buf);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
p = buf.pointer;
|
||||
if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
|
||||
dev_err(dev, "Invalid PPCC data\n");
|
||||
dev_err(proc_priv->dev, "Invalid PPCC data\n");
|
||||
ret = -EFAULT;
|
||||
goto free_buffer;
|
||||
}
|
||||
|
||||
if (!p->package.count) {
|
||||
dev_err(dev, "Invalid PPCC package size\n");
|
||||
dev_err(proc_priv->dev, "Invalid PPCC package size\n");
|
||||
ret = -EFAULT;
|
||||
goto free_buffer;
|
||||
}
|
||||
|
||||
proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv) {
|
||||
ret = -ENOMEM;
|
||||
goto free_buffer;
|
||||
}
|
||||
|
||||
proc_priv->dev = dev;
|
||||
proc_priv->adev = adev;
|
||||
|
||||
for (i = 0; i < min((int)p->package.count - 1, 2); ++i) {
|
||||
elements = &(p->package.elements[i+1]);
|
||||
if (elements->type != ACPI_TYPE_PACKAGE ||
|
||||
@ -257,12 +241,62 @@ static int proc_thermal_add(struct device *dev,
|
||||
proc_priv->power_limits[i].step_uw = ppcc[5].integer.value;
|
||||
}
|
||||
|
||||
free_buffer:
|
||||
kfree(buf.pointer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PROC_POWER_CAPABILITY_CHANGED 0x83
|
||||
static void proc_thermal_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv = data;
|
||||
|
||||
if (!proc_priv)
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case PROC_POWER_CAPABILITY_CHANGED:
|
||||
proc_thermal_read_ppcc(proc_priv);
|
||||
int340x_thermal_zone_device_update(proc_priv->int340x_zone);
|
||||
break;
|
||||
default:
|
||||
dev_err(proc_priv->dev, "Unsupported event [0x%x]\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int proc_thermal_add(struct device *dev,
|
||||
struct proc_thermal_device **priv)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
unsigned long long tmp;
|
||||
struct thermal_zone_device_ops *ops = NULL;
|
||||
int ret;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (!adev)
|
||||
return -ENODEV;
|
||||
|
||||
proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
proc_priv->dev = dev;
|
||||
proc_priv->adev = adev;
|
||||
*priv = proc_priv;
|
||||
|
||||
ret = sysfs_create_group(&dev->kobj,
|
||||
&power_limit_attribute_group);
|
||||
ret = proc_thermal_read_ppcc(proc_priv);
|
||||
if (!ret) {
|
||||
ret = sysfs_create_group(&dev->kobj,
|
||||
&power_limit_attribute_group);
|
||||
|
||||
}
|
||||
if (ret)
|
||||
goto free_buffer;
|
||||
return ret;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
@ -274,20 +308,32 @@ static int proc_thermal_add(struct device *dev,
|
||||
|
||||
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);
|
||||
goto remove_group;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
free_buffer:
|
||||
kfree(buf.pointer);
|
||||
ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
|
||||
proc_thermal_notify,
|
||||
(void *)proc_priv);
|
||||
if (ret)
|
||||
goto remove_zone;
|
||||
|
||||
return 0;
|
||||
|
||||
remove_zone:
|
||||
int340x_thermal_zone_remove(proc_priv->int340x_zone);
|
||||
remove_group:
|
||||
sysfs_remove_group(&proc_priv->dev->kobj,
|
||||
&power_limit_attribute_group);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
acpi_remove_notify_handler(proc_priv->adev->handle,
|
||||
ACPI_DEVICE_NOTIFY, proc_thermal_notify);
|
||||
int340x_thermal_zone_remove(proc_priv->int340x_zone);
|
||||
sysfs_remove_group(&proc_priv->dev->kobj,
|
||||
&power_limit_attribute_group);
|
||||
|
Loading…
Reference in New Issue
Block a user