1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23e8c4d31SAmit Kucheria /* 33e8c4d31SAmit Kucheria * INT3400 thermal driver 43e8c4d31SAmit Kucheria * 53e8c4d31SAmit Kucheria * Copyright (C) 2014, Intel Corporation 63e8c4d31SAmit Kucheria * Authors: Zhang Rui <rui.zhang@intel.com> 73e8c4d31SAmit Kucheria */ 83e8c4d31SAmit Kucheria 93e8c4d31SAmit Kucheria #include <linux/module.h> 103e8c4d31SAmit Kucheria #include <linux/platform_device.h> 113e8c4d31SAmit Kucheria #include <linux/acpi.h> 123e8c4d31SAmit Kucheria #include <linux/thermal.h> 133e8c4d31SAmit Kucheria #include "acpi_thermal_rel.h" 143e8c4d31SAmit Kucheria 153e8c4d31SAmit Kucheria #define INT3400_THERMAL_TABLE_CHANGED 0x83 163e8c4d31SAmit Kucheria 173e8c4d31SAmit Kucheria enum int3400_thermal_uuid { 183e8c4d31SAmit Kucheria INT3400_THERMAL_PASSIVE_1, 193e8c4d31SAmit Kucheria INT3400_THERMAL_ACTIVE, 203e8c4d31SAmit Kucheria INT3400_THERMAL_CRITICAL, 2116fc8ecaSMatthew Garrett INT3400_THERMAL_ADAPTIVE_PERFORMANCE, 2216fc8ecaSMatthew Garrett INT3400_THERMAL_EMERGENCY_CALL_MODE, 2316fc8ecaSMatthew Garrett INT3400_THERMAL_PASSIVE_2, 2416fc8ecaSMatthew Garrett INT3400_THERMAL_POWER_BOSS, 2516fc8ecaSMatthew Garrett INT3400_THERMAL_VIRTUAL_SENSOR, 2616fc8ecaSMatthew Garrett INT3400_THERMAL_COOLING_MODE, 2716fc8ecaSMatthew Garrett INT3400_THERMAL_HARDWARE_DUTY_CYCLING, 283e8c4d31SAmit Kucheria INT3400_THERMAL_MAXIMUM_UUID, 293e8c4d31SAmit Kucheria }; 303e8c4d31SAmit Kucheria 313e8c4d31SAmit Kucheria static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { 323e8c4d31SAmit Kucheria "42A441D6-AE6A-462b-A84B-4A8CE79027D3", 333e8c4d31SAmit Kucheria "3A95C389-E4B8-4629-A526-C52C88626BAE", 343e8c4d31SAmit Kucheria "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", 3516fc8ecaSMatthew Garrett "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D", 3616fc8ecaSMatthew Garrett "5349962F-71E6-431D-9AE8-0A635B710AEE", 3716fc8ecaSMatthew Garrett "9E04115A-AE87-4D1C-9500-0F3E340BFE75", 3816fc8ecaSMatthew Garrett "F5A35014-C209-46A4-993A-EB56DE7530A1", 3916fc8ecaSMatthew Garrett "6ED722A7-9240-48A5-B479-31EEF723D7CF", 4016fc8ecaSMatthew Garrett "16CAF1B7-DD38-40ED-B1C1-1B8A1913D531", 4116fc8ecaSMatthew Garrett "BE84BABF-C4D4-403D-B495-3128FD44dAC1", 423e8c4d31SAmit Kucheria }; 433e8c4d31SAmit Kucheria 443e8c4d31SAmit Kucheria struct int3400_thermal_priv { 453e8c4d31SAmit Kucheria struct acpi_device *adev; 463e8c4d31SAmit Kucheria struct thermal_zone_device *thermal; 473e8c4d31SAmit Kucheria int mode; 483e8c4d31SAmit Kucheria int art_count; 493e8c4d31SAmit Kucheria struct art *arts; 503e8c4d31SAmit Kucheria int trt_count; 513e8c4d31SAmit Kucheria struct trt *trts; 523e8c4d31SAmit Kucheria u8 uuid_bitmap; 533e8c4d31SAmit Kucheria int rel_misc_dev_res; 543e8c4d31SAmit Kucheria int current_uuid_index; 553e8c4d31SAmit Kucheria }; 563e8c4d31SAmit Kucheria 573e8c4d31SAmit Kucheria static ssize_t available_uuids_show(struct device *dev, 583e8c4d31SAmit Kucheria struct device_attribute *attr, 593e8c4d31SAmit Kucheria char *buf) 603e8c4d31SAmit Kucheria { 613e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 623e8c4d31SAmit Kucheria int i; 633e8c4d31SAmit Kucheria int length = 0; 643e8c4d31SAmit Kucheria 653e8c4d31SAmit Kucheria for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { 663e8c4d31SAmit Kucheria if (priv->uuid_bitmap & (1 << i)) 673e8c4d31SAmit Kucheria if (PAGE_SIZE - length > 0) 68f21431f2STakashi Iwai length += scnprintf(&buf[length], 693e8c4d31SAmit Kucheria PAGE_SIZE - length, 703e8c4d31SAmit Kucheria "%s\n", 713e8c4d31SAmit Kucheria int3400_thermal_uuids[i]); 723e8c4d31SAmit Kucheria } 733e8c4d31SAmit Kucheria 743e8c4d31SAmit Kucheria return length; 753e8c4d31SAmit Kucheria } 763e8c4d31SAmit Kucheria 773e8c4d31SAmit Kucheria static ssize_t current_uuid_show(struct device *dev, 783e8c4d31SAmit Kucheria struct device_attribute *devattr, char *buf) 793e8c4d31SAmit Kucheria { 803e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 813e8c4d31SAmit Kucheria 823e8c4d31SAmit Kucheria if (priv->uuid_bitmap & (1 << priv->current_uuid_index)) 833e8c4d31SAmit Kucheria return sprintf(buf, "%s\n", 843e8c4d31SAmit Kucheria int3400_thermal_uuids[priv->current_uuid_index]); 853e8c4d31SAmit Kucheria else 863e8c4d31SAmit Kucheria return sprintf(buf, "INVALID\n"); 873e8c4d31SAmit Kucheria } 883e8c4d31SAmit Kucheria 893e8c4d31SAmit Kucheria static ssize_t current_uuid_store(struct device *dev, 903e8c4d31SAmit Kucheria struct device_attribute *attr, 913e8c4d31SAmit Kucheria const char *buf, size_t count) 923e8c4d31SAmit Kucheria { 933e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 943e8c4d31SAmit Kucheria int i; 953e8c4d31SAmit Kucheria 963e8c4d31SAmit Kucheria for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) { 973e8c4d31SAmit Kucheria if ((priv->uuid_bitmap & (1 << i)) && 983e8c4d31SAmit Kucheria !(strncmp(buf, int3400_thermal_uuids[i], 993e8c4d31SAmit Kucheria sizeof(int3400_thermal_uuids[i]) - 1))) { 1003e8c4d31SAmit Kucheria priv->current_uuid_index = i; 1013e8c4d31SAmit Kucheria return count; 1023e8c4d31SAmit Kucheria } 1033e8c4d31SAmit Kucheria } 1043e8c4d31SAmit Kucheria 1053e8c4d31SAmit Kucheria return -EINVAL; 1063e8c4d31SAmit Kucheria } 1073e8c4d31SAmit Kucheria 1083e8c4d31SAmit Kucheria static DEVICE_ATTR_RW(current_uuid); 1093e8c4d31SAmit Kucheria static DEVICE_ATTR_RO(available_uuids); 1103e8c4d31SAmit Kucheria static struct attribute *uuid_attrs[] = { 1113e8c4d31SAmit Kucheria &dev_attr_available_uuids.attr, 1123e8c4d31SAmit Kucheria &dev_attr_current_uuid.attr, 1133e8c4d31SAmit Kucheria NULL 1143e8c4d31SAmit Kucheria }; 1153e8c4d31SAmit Kucheria 1163e8c4d31SAmit Kucheria static const struct attribute_group uuid_attribute_group = { 1173e8c4d31SAmit Kucheria .attrs = uuid_attrs, 1183e8c4d31SAmit Kucheria .name = "uuids" 1193e8c4d31SAmit Kucheria }; 1203e8c4d31SAmit Kucheria 1213e8c4d31SAmit Kucheria static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) 1223e8c4d31SAmit Kucheria { 1233e8c4d31SAmit Kucheria struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL}; 1243e8c4d31SAmit Kucheria union acpi_object *obja, *objb; 1253e8c4d31SAmit Kucheria int i, j; 1263e8c4d31SAmit Kucheria int result = 0; 1273e8c4d31SAmit Kucheria acpi_status status; 1283e8c4d31SAmit Kucheria 1293e8c4d31SAmit Kucheria status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf); 1303e8c4d31SAmit Kucheria if (ACPI_FAILURE(status)) 1313e8c4d31SAmit Kucheria return -ENODEV; 1323e8c4d31SAmit Kucheria 1333e8c4d31SAmit Kucheria obja = (union acpi_object *)buf.pointer; 1343e8c4d31SAmit Kucheria if (obja->type != ACPI_TYPE_PACKAGE) { 1353e8c4d31SAmit Kucheria result = -EINVAL; 1363e8c4d31SAmit Kucheria goto end; 1373e8c4d31SAmit Kucheria } 1383e8c4d31SAmit Kucheria 1393e8c4d31SAmit Kucheria for (i = 0; i < obja->package.count; i++) { 1403e8c4d31SAmit Kucheria objb = &obja->package.elements[i]; 1413e8c4d31SAmit Kucheria if (objb->type != ACPI_TYPE_BUFFER) { 1423e8c4d31SAmit Kucheria result = -EINVAL; 1433e8c4d31SAmit Kucheria goto end; 1443e8c4d31SAmit Kucheria } 1453e8c4d31SAmit Kucheria 1463e8c4d31SAmit Kucheria /* UUID must be 16 bytes */ 1473e8c4d31SAmit Kucheria if (objb->buffer.length != 16) { 1483e8c4d31SAmit Kucheria result = -EINVAL; 1493e8c4d31SAmit Kucheria goto end; 1503e8c4d31SAmit Kucheria } 1513e8c4d31SAmit Kucheria 1523e8c4d31SAmit Kucheria for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) { 1533e8c4d31SAmit Kucheria guid_t guid; 1543e8c4d31SAmit Kucheria 1553e8c4d31SAmit Kucheria guid_parse(int3400_thermal_uuids[j], &guid); 1563e8c4d31SAmit Kucheria if (guid_equal((guid_t *)objb->buffer.pointer, &guid)) { 1573e8c4d31SAmit Kucheria priv->uuid_bitmap |= (1 << j); 1583e8c4d31SAmit Kucheria break; 1593e8c4d31SAmit Kucheria } 1603e8c4d31SAmit Kucheria } 1613e8c4d31SAmit Kucheria } 1623e8c4d31SAmit Kucheria 1633e8c4d31SAmit Kucheria end: 1643e8c4d31SAmit Kucheria kfree(buf.pointer); 1653e8c4d31SAmit Kucheria return result; 1663e8c4d31SAmit Kucheria } 1673e8c4d31SAmit Kucheria 1683e8c4d31SAmit Kucheria static int int3400_thermal_run_osc(acpi_handle handle, 1693e8c4d31SAmit Kucheria enum int3400_thermal_uuid uuid, bool enable) 1703e8c4d31SAmit Kucheria { 1713e8c4d31SAmit Kucheria u32 ret, buf[2]; 1723e8c4d31SAmit Kucheria acpi_status status; 1733e8c4d31SAmit Kucheria int result = 0; 1743e8c4d31SAmit Kucheria struct acpi_osc_context context = { 1753e8c4d31SAmit Kucheria .uuid_str = int3400_thermal_uuids[uuid], 1763e8c4d31SAmit Kucheria .rev = 1, 1773e8c4d31SAmit Kucheria .cap.length = 8, 1783e8c4d31SAmit Kucheria }; 1793e8c4d31SAmit Kucheria 1803e8c4d31SAmit Kucheria buf[OSC_QUERY_DWORD] = 0; 1813e8c4d31SAmit Kucheria buf[OSC_SUPPORT_DWORD] = enable; 1823e8c4d31SAmit Kucheria 1833e8c4d31SAmit Kucheria context.cap.pointer = buf; 1843e8c4d31SAmit Kucheria 1853e8c4d31SAmit Kucheria status = acpi_run_osc(handle, &context); 1863e8c4d31SAmit Kucheria if (ACPI_SUCCESS(status)) { 1873e8c4d31SAmit Kucheria ret = *((u32 *)(context.ret.pointer + 4)); 1883e8c4d31SAmit Kucheria if (ret != enable) 1893e8c4d31SAmit Kucheria result = -EPERM; 1903e8c4d31SAmit Kucheria } else 1913e8c4d31SAmit Kucheria result = -EPERM; 1923e8c4d31SAmit Kucheria 1933e8c4d31SAmit Kucheria kfree(context.ret.pointer); 1943e8c4d31SAmit Kucheria return result; 1953e8c4d31SAmit Kucheria } 1963e8c4d31SAmit Kucheria 1973e8c4d31SAmit Kucheria static void int3400_notify(acpi_handle handle, 1983e8c4d31SAmit Kucheria u32 event, 1993e8c4d31SAmit Kucheria void *data) 2003e8c4d31SAmit Kucheria { 2013e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = data; 2023e8c4d31SAmit Kucheria char *thermal_prop[5]; 2033e8c4d31SAmit Kucheria 2043e8c4d31SAmit Kucheria if (!priv) 2053e8c4d31SAmit Kucheria return; 2063e8c4d31SAmit Kucheria 2073e8c4d31SAmit Kucheria switch (event) { 2083e8c4d31SAmit Kucheria case INT3400_THERMAL_TABLE_CHANGED: 2093e8c4d31SAmit Kucheria thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", 2103e8c4d31SAmit Kucheria priv->thermal->type); 2113e8c4d31SAmit Kucheria thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", 2123e8c4d31SAmit Kucheria priv->thermal->temperature); 2133e8c4d31SAmit Kucheria thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP="); 2143e8c4d31SAmit Kucheria thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", 2153e8c4d31SAmit Kucheria THERMAL_TABLE_CHANGED); 2163e8c4d31SAmit Kucheria thermal_prop[4] = NULL; 2173e8c4d31SAmit Kucheria kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, 2183e8c4d31SAmit Kucheria thermal_prop); 2193e8c4d31SAmit Kucheria break; 2203e8c4d31SAmit Kucheria default: 2213e8c4d31SAmit Kucheria /* Ignore unknown notification codes sent to INT3400 device */ 2223e8c4d31SAmit Kucheria break; 2233e8c4d31SAmit Kucheria } 2243e8c4d31SAmit Kucheria } 2253e8c4d31SAmit Kucheria 2263e8c4d31SAmit Kucheria static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, 2273e8c4d31SAmit Kucheria int *temp) 2283e8c4d31SAmit Kucheria { 2293e8c4d31SAmit Kucheria *temp = 20 * 1000; /* faked temp sensor with 20C */ 2303e8c4d31SAmit Kucheria return 0; 2313e8c4d31SAmit Kucheria } 2323e8c4d31SAmit Kucheria 2333e8c4d31SAmit Kucheria static int int3400_thermal_get_mode(struct thermal_zone_device *thermal, 2343e8c4d31SAmit Kucheria enum thermal_device_mode *mode) 2353e8c4d31SAmit Kucheria { 2363e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = thermal->devdata; 2373e8c4d31SAmit Kucheria 2383e8c4d31SAmit Kucheria if (!priv) 2393e8c4d31SAmit Kucheria return -EINVAL; 2403e8c4d31SAmit Kucheria 2413e8c4d31SAmit Kucheria *mode = priv->mode; 2423e8c4d31SAmit Kucheria 2433e8c4d31SAmit Kucheria return 0; 2443e8c4d31SAmit Kucheria } 2453e8c4d31SAmit Kucheria 2463e8c4d31SAmit Kucheria static int int3400_thermal_set_mode(struct thermal_zone_device *thermal, 2473e8c4d31SAmit Kucheria enum thermal_device_mode mode) 2483e8c4d31SAmit Kucheria { 2493e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = thermal->devdata; 2503e8c4d31SAmit Kucheria bool enable; 2513e8c4d31SAmit Kucheria int result = 0; 2523e8c4d31SAmit Kucheria 2533e8c4d31SAmit Kucheria if (!priv) 2543e8c4d31SAmit Kucheria return -EINVAL; 2553e8c4d31SAmit Kucheria 2563e8c4d31SAmit Kucheria if (mode == THERMAL_DEVICE_ENABLED) 2573e8c4d31SAmit Kucheria enable = true; 2583e8c4d31SAmit Kucheria else if (mode == THERMAL_DEVICE_DISABLED) 2593e8c4d31SAmit Kucheria enable = false; 2603e8c4d31SAmit Kucheria else 2613e8c4d31SAmit Kucheria return -EINVAL; 2623e8c4d31SAmit Kucheria 2633e8c4d31SAmit Kucheria if (enable != priv->mode) { 2643e8c4d31SAmit Kucheria priv->mode = enable; 2653e8c4d31SAmit Kucheria result = int3400_thermal_run_osc(priv->adev->handle, 2663e8c4d31SAmit Kucheria priv->current_uuid_index, 2673e8c4d31SAmit Kucheria enable); 2683e8c4d31SAmit Kucheria } 2693e8c4d31SAmit Kucheria return result; 2703e8c4d31SAmit Kucheria } 2713e8c4d31SAmit Kucheria 2723e8c4d31SAmit Kucheria static struct thermal_zone_device_ops int3400_thermal_ops = { 2733e8c4d31SAmit Kucheria .get_temp = int3400_thermal_get_temp, 27479799562SAndrzej Pietrasiewicz .get_mode = int3400_thermal_get_mode, 27579799562SAndrzej Pietrasiewicz .set_mode = int3400_thermal_set_mode, 2763e8c4d31SAmit Kucheria }; 2773e8c4d31SAmit Kucheria 2783e8c4d31SAmit Kucheria static struct thermal_zone_params int3400_thermal_params = { 2793e8c4d31SAmit Kucheria .governor_name = "user_space", 2803e8c4d31SAmit Kucheria .no_hwmon = true, 2813e8c4d31SAmit Kucheria }; 2823e8c4d31SAmit Kucheria 2833e8c4d31SAmit Kucheria static int int3400_thermal_probe(struct platform_device *pdev) 2843e8c4d31SAmit Kucheria { 2853e8c4d31SAmit Kucheria struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 2863e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv; 2873e8c4d31SAmit Kucheria int result; 2883e8c4d31SAmit Kucheria 2893e8c4d31SAmit Kucheria if (!adev) 2903e8c4d31SAmit Kucheria return -ENODEV; 2913e8c4d31SAmit Kucheria 2923e8c4d31SAmit Kucheria priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL); 2933e8c4d31SAmit Kucheria if (!priv) 2943e8c4d31SAmit Kucheria return -ENOMEM; 2953e8c4d31SAmit Kucheria 2963e8c4d31SAmit Kucheria priv->adev = adev; 2973e8c4d31SAmit Kucheria 2983e8c4d31SAmit Kucheria result = int3400_thermal_get_uuids(priv); 2993e8c4d31SAmit Kucheria if (result) 3003e8c4d31SAmit Kucheria goto free_priv; 3013e8c4d31SAmit Kucheria 3023e8c4d31SAmit Kucheria result = acpi_parse_art(priv->adev->handle, &priv->art_count, 3033e8c4d31SAmit Kucheria &priv->arts, true); 3043e8c4d31SAmit Kucheria if (result) 3053e8c4d31SAmit Kucheria dev_dbg(&pdev->dev, "_ART table parsing error\n"); 3063e8c4d31SAmit Kucheria 3073e8c4d31SAmit Kucheria result = acpi_parse_trt(priv->adev->handle, &priv->trt_count, 3083e8c4d31SAmit Kucheria &priv->trts, true); 3093e8c4d31SAmit Kucheria if (result) 3103e8c4d31SAmit Kucheria dev_dbg(&pdev->dev, "_TRT table parsing error\n"); 3113e8c4d31SAmit Kucheria 3123e8c4d31SAmit Kucheria platform_set_drvdata(pdev, priv); 3133e8c4d31SAmit Kucheria 3143e8c4d31SAmit Kucheria priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, 3153e8c4d31SAmit Kucheria priv, &int3400_thermal_ops, 3163e8c4d31SAmit Kucheria &int3400_thermal_params, 0, 0); 3173e8c4d31SAmit Kucheria if (IS_ERR(priv->thermal)) { 3183e8c4d31SAmit Kucheria result = PTR_ERR(priv->thermal); 3193e8c4d31SAmit Kucheria goto free_art_trt; 3203e8c4d31SAmit Kucheria } 3213e8c4d31SAmit Kucheria 3223e8c4d31SAmit Kucheria priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add( 3233e8c4d31SAmit Kucheria priv->adev->handle); 3243e8c4d31SAmit Kucheria 3253e8c4d31SAmit Kucheria result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group); 3263e8c4d31SAmit Kucheria if (result) 3273e8c4d31SAmit Kucheria goto free_rel_misc; 3283e8c4d31SAmit Kucheria 3293e8c4d31SAmit Kucheria result = acpi_install_notify_handler( 3303e8c4d31SAmit Kucheria priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify, 3313e8c4d31SAmit Kucheria (void *)priv); 3323e8c4d31SAmit Kucheria if (result) 3333e8c4d31SAmit Kucheria goto free_sysfs; 3343e8c4d31SAmit Kucheria 3353e8c4d31SAmit Kucheria return 0; 3363e8c4d31SAmit Kucheria 3373e8c4d31SAmit Kucheria free_sysfs: 3383e8c4d31SAmit Kucheria sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 3393e8c4d31SAmit Kucheria free_rel_misc: 3403e8c4d31SAmit Kucheria if (!priv->rel_misc_dev_res) 3413e8c4d31SAmit Kucheria acpi_thermal_rel_misc_device_remove(priv->adev->handle); 3423e8c4d31SAmit Kucheria thermal_zone_device_unregister(priv->thermal); 3433e8c4d31SAmit Kucheria free_art_trt: 3443e8c4d31SAmit Kucheria kfree(priv->trts); 3453e8c4d31SAmit Kucheria kfree(priv->arts); 3463e8c4d31SAmit Kucheria free_priv: 3473e8c4d31SAmit Kucheria kfree(priv); 3483e8c4d31SAmit Kucheria return result; 3493e8c4d31SAmit Kucheria } 3503e8c4d31SAmit Kucheria 3513e8c4d31SAmit Kucheria static int int3400_thermal_remove(struct platform_device *pdev) 3523e8c4d31SAmit Kucheria { 3533e8c4d31SAmit Kucheria struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 3543e8c4d31SAmit Kucheria 3553e8c4d31SAmit Kucheria acpi_remove_notify_handler( 3563e8c4d31SAmit Kucheria priv->adev->handle, ACPI_DEVICE_NOTIFY, 3573e8c4d31SAmit Kucheria int3400_notify); 3583e8c4d31SAmit Kucheria 3593e8c4d31SAmit Kucheria if (!priv->rel_misc_dev_res) 3603e8c4d31SAmit Kucheria acpi_thermal_rel_misc_device_remove(priv->adev->handle); 3613e8c4d31SAmit Kucheria 3623e8c4d31SAmit Kucheria sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 3633e8c4d31SAmit Kucheria thermal_zone_device_unregister(priv->thermal); 3643e8c4d31SAmit Kucheria kfree(priv->trts); 3653e8c4d31SAmit Kucheria kfree(priv->arts); 3663e8c4d31SAmit Kucheria kfree(priv); 3673e8c4d31SAmit Kucheria return 0; 3683e8c4d31SAmit Kucheria } 3693e8c4d31SAmit Kucheria 3703e8c4d31SAmit Kucheria static const struct acpi_device_id int3400_thermal_match[] = { 3713e8c4d31SAmit Kucheria {"INT3400", 0}, 37226d8bec1SGayatri Kammela {"INTC1040", 0}, 3733e8c4d31SAmit Kucheria {} 3743e8c4d31SAmit Kucheria }; 3753e8c4d31SAmit Kucheria 3763e8c4d31SAmit Kucheria MODULE_DEVICE_TABLE(acpi, int3400_thermal_match); 3773e8c4d31SAmit Kucheria 3783e8c4d31SAmit Kucheria static struct platform_driver int3400_thermal_driver = { 3793e8c4d31SAmit Kucheria .probe = int3400_thermal_probe, 3803e8c4d31SAmit Kucheria .remove = int3400_thermal_remove, 3813e8c4d31SAmit Kucheria .driver = { 3823e8c4d31SAmit Kucheria .name = "int3400 thermal", 3833e8c4d31SAmit Kucheria .acpi_match_table = ACPI_PTR(int3400_thermal_match), 3843e8c4d31SAmit Kucheria }, 3853e8c4d31SAmit Kucheria }; 3863e8c4d31SAmit Kucheria 3873e8c4d31SAmit Kucheria module_platform_driver(int3400_thermal_driver); 3883e8c4d31SAmit Kucheria 3893e8c4d31SAmit Kucheria MODULE_DESCRIPTION("INT3400 Thermal driver"); 3903e8c4d31SAmit Kucheria MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); 3913e8c4d31SAmit Kucheria MODULE_LICENSE("GPL"); 392