1 /* 2 * INT3402 thermal driver for memory temperature reporting 3 * 4 * Copyright (C) 2014, Intel Corporation 5 * Authors: Aaron Lu <aaron.lu@intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 */ 12 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/acpi.h> 16 #include <linux/thermal.h> 17 #include "int340x_thermal_zone.h" 18 19 #define INT3402_PERF_CHANGED_EVENT 0x80 20 #define INT3402_THERMAL_EVENT 0x90 21 22 struct int3402_thermal_data { 23 acpi_handle *handle; 24 struct int34x_thermal_zone *int340x_zone; 25 }; 26 27 static void int3402_notify(acpi_handle handle, u32 event, void *data) 28 { 29 struct int3402_thermal_data *priv = data; 30 31 if (!priv) 32 return; 33 34 switch (event) { 35 case INT3402_PERF_CHANGED_EVENT: 36 break; 37 case INT3402_THERMAL_EVENT: 38 int340x_thermal_zone_device_update(priv->int340x_zone, 39 THERMAL_TRIP_VIOLATED); 40 break; 41 default: 42 break; 43 } 44 } 45 46 static int int3402_thermal_probe(struct platform_device *pdev) 47 { 48 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 49 struct int3402_thermal_data *d; 50 int ret; 51 52 if (!acpi_has_method(adev->handle, "_TMP")) 53 return -ENODEV; 54 55 d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL); 56 if (!d) 57 return -ENOMEM; 58 59 d->int340x_zone = int340x_thermal_zone_add(adev, NULL); 60 if (IS_ERR(d->int340x_zone)) 61 return PTR_ERR(d->int340x_zone); 62 63 ret = acpi_install_notify_handler(adev->handle, 64 ACPI_DEVICE_NOTIFY, 65 int3402_notify, 66 d); 67 if (ret) { 68 int340x_thermal_zone_remove(d->int340x_zone); 69 return ret; 70 } 71 72 d->handle = adev->handle; 73 platform_set_drvdata(pdev, d); 74 75 return 0; 76 } 77 78 static int int3402_thermal_remove(struct platform_device *pdev) 79 { 80 struct int3402_thermal_data *d = platform_get_drvdata(pdev); 81 82 acpi_remove_notify_handler(d->handle, 83 ACPI_DEVICE_NOTIFY, int3402_notify); 84 int340x_thermal_zone_remove(d->int340x_zone); 85 86 return 0; 87 } 88 89 static const struct acpi_device_id int3402_thermal_match[] = { 90 {"INT3402", 0}, 91 {} 92 }; 93 94 MODULE_DEVICE_TABLE(acpi, int3402_thermal_match); 95 96 static struct platform_driver int3402_thermal_driver = { 97 .probe = int3402_thermal_probe, 98 .remove = int3402_thermal_remove, 99 .driver = { 100 .name = "int3402 thermal", 101 .acpi_match_table = int3402_thermal_match, 102 }, 103 }; 104 105 module_platform_driver(int3402_thermal_driver); 106 107 MODULE_DESCRIPTION("INT3402 Thermal driver"); 108 MODULE_LICENSE("GPL"); 109