1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23e8c4d31SAmit Kucheria /*
33e8c4d31SAmit Kucheria * INT3402 thermal driver for memory temperature reporting
43e8c4d31SAmit Kucheria *
53e8c4d31SAmit Kucheria * Copyright (C) 2014, Intel Corporation
63e8c4d31SAmit Kucheria * Authors: Aaron Lu <aaron.lu@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 "int340x_thermal_zone.h"
143e8c4d31SAmit Kucheria
153e8c4d31SAmit Kucheria #define INT3402_PERF_CHANGED_EVENT 0x80
163e8c4d31SAmit Kucheria #define INT3402_THERMAL_EVENT 0x90
173e8c4d31SAmit Kucheria
183e8c4d31SAmit Kucheria struct int3402_thermal_data {
193e8c4d31SAmit Kucheria acpi_handle *handle;
203e8c4d31SAmit Kucheria struct int34x_thermal_zone *int340x_zone;
213e8c4d31SAmit Kucheria };
223e8c4d31SAmit Kucheria
int3402_notify(acpi_handle handle,u32 event,void * data)233e8c4d31SAmit Kucheria static void int3402_notify(acpi_handle handle, u32 event, void *data)
243e8c4d31SAmit Kucheria {
253e8c4d31SAmit Kucheria struct int3402_thermal_data *priv = data;
263e8c4d31SAmit Kucheria
273e8c4d31SAmit Kucheria if (!priv)
283e8c4d31SAmit Kucheria return;
293e8c4d31SAmit Kucheria
303e8c4d31SAmit Kucheria switch (event) {
313e8c4d31SAmit Kucheria case INT3402_PERF_CHANGED_EVENT:
323e8c4d31SAmit Kucheria break;
333e8c4d31SAmit Kucheria case INT3402_THERMAL_EVENT:
343e8c4d31SAmit Kucheria int340x_thermal_zone_device_update(priv->int340x_zone,
353e8c4d31SAmit Kucheria THERMAL_TRIP_VIOLATED);
363e8c4d31SAmit Kucheria break;
373e8c4d31SAmit Kucheria default:
383e8c4d31SAmit Kucheria break;
393e8c4d31SAmit Kucheria }
403e8c4d31SAmit Kucheria }
413e8c4d31SAmit Kucheria
int3402_thermal_probe(struct platform_device * pdev)423e8c4d31SAmit Kucheria static int int3402_thermal_probe(struct platform_device *pdev)
433e8c4d31SAmit Kucheria {
443e8c4d31SAmit Kucheria struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
453e8c4d31SAmit Kucheria struct int3402_thermal_data *d;
463e8c4d31SAmit Kucheria int ret;
473e8c4d31SAmit Kucheria
48*ac2eb737SChenyuan Yang if (!adev)
49*ac2eb737SChenyuan Yang return -ENODEV;
50*ac2eb737SChenyuan Yang
513e8c4d31SAmit Kucheria if (!acpi_has_method(adev->handle, "_TMP"))
523e8c4d31SAmit Kucheria return -ENODEV;
533e8c4d31SAmit Kucheria
543e8c4d31SAmit Kucheria d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
553e8c4d31SAmit Kucheria if (!d)
563e8c4d31SAmit Kucheria return -ENOMEM;
573e8c4d31SAmit Kucheria
583e8c4d31SAmit Kucheria d->int340x_zone = int340x_thermal_zone_add(adev, NULL);
593e8c4d31SAmit Kucheria if (IS_ERR(d->int340x_zone))
603e8c4d31SAmit Kucheria return PTR_ERR(d->int340x_zone);
613e8c4d31SAmit Kucheria
623e8c4d31SAmit Kucheria ret = acpi_install_notify_handler(adev->handle,
633e8c4d31SAmit Kucheria ACPI_DEVICE_NOTIFY,
643e8c4d31SAmit Kucheria int3402_notify,
653e8c4d31SAmit Kucheria d);
663e8c4d31SAmit Kucheria if (ret) {
673e8c4d31SAmit Kucheria int340x_thermal_zone_remove(d->int340x_zone);
683e8c4d31SAmit Kucheria return ret;
693e8c4d31SAmit Kucheria }
703e8c4d31SAmit Kucheria
713e8c4d31SAmit Kucheria d->handle = adev->handle;
723e8c4d31SAmit Kucheria platform_set_drvdata(pdev, d);
733e8c4d31SAmit Kucheria
743e8c4d31SAmit Kucheria return 0;
753e8c4d31SAmit Kucheria }
763e8c4d31SAmit Kucheria
773e8c4d31SAmit Kucheria static int int3402_thermal_remove(struct platform_device *pdev)
783e8c4d31SAmit Kucheria {
793e8c4d31SAmit Kucheria struct int3402_thermal_data *d = platform_get_drvdata(pdev);
803e8c4d31SAmit Kucheria
813e8c4d31SAmit Kucheria acpi_remove_notify_handler(d->handle,
823e8c4d31SAmit Kucheria ACPI_DEVICE_NOTIFY, int3402_notify);
833e8c4d31SAmit Kucheria int340x_thermal_zone_remove(d->int340x_zone);
843e8c4d31SAmit Kucheria
853e8c4d31SAmit Kucheria return 0;
863e8c4d31SAmit Kucheria }
873e8c4d31SAmit Kucheria
883e8c4d31SAmit Kucheria static const struct acpi_device_id int3402_thermal_match[] = {
893e8c4d31SAmit Kucheria {"INT3402", 0},
903e8c4d31SAmit Kucheria {}
913e8c4d31SAmit Kucheria };
923e8c4d31SAmit Kucheria
933e8c4d31SAmit Kucheria MODULE_DEVICE_TABLE(acpi, int3402_thermal_match);
943e8c4d31SAmit Kucheria
953e8c4d31SAmit Kucheria static struct platform_driver int3402_thermal_driver = {
963e8c4d31SAmit Kucheria .probe = int3402_thermal_probe,
973e8c4d31SAmit Kucheria .remove = int3402_thermal_remove,
983e8c4d31SAmit Kucheria .driver = {
993e8c4d31SAmit Kucheria .name = "int3402 thermal",
1003e8c4d31SAmit Kucheria .acpi_match_table = int3402_thermal_match,
1013e8c4d31SAmit Kucheria },
1023e8c4d31SAmit Kucheria };
1033e8c4d31SAmit Kucheria
1043e8c4d31SAmit Kucheria module_platform_driver(int3402_thermal_driver);
1053e8c4d31SAmit Kucheria
1063e8c4d31SAmit Kucheria MODULE_DESCRIPTION("INT3402 Thermal driver");
1073e8c4d31SAmit Kucheria MODULE_LICENSE("GPL");
108