root/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci_legacy.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * B0D4 processor thermal device
 * Copyright (c) 2020, Intel Corporation.
 */

#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/thermal.h>

#include "int340x_thermal_zone.h"
#include "processor_thermal_device.h"
#include "../intel_soc_dts_iosf.h"

#define DRV_NAME "proc_thermal"

static irqreturn_t proc_thermal_pci_msi_irq(int irq, void *devid)
{
        struct proc_thermal_device *proc_priv;
        struct pci_dev *pdev = devid;

        proc_priv = pci_get_drvdata(pdev);

        intel_soc_dts_iosf_interrupt_handler(proc_priv->soc_dts);

        return IRQ_HANDLED;
}

static int proc_thermal_pci_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *id)
{
        struct proc_thermal_device *proc_priv;
        int ret;

        ret = pcim_enable_device(pdev);
        if (ret < 0) {
                dev_err(&pdev->dev, "error: could not enable device\n");
                return ret;
        }

        proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
        if (!proc_priv)
                return -ENOMEM;

        ret = proc_thermal_add(&pdev->dev, proc_priv);
        if (ret)
                return ret;

        pci_set_drvdata(pdev, proc_priv);

        if (pdev->device == PCI_DEVICE_ID_INTEL_BSW_THERMAL) {
                /*
                 * Enumerate additional DTS sensors available via IOSF.
                 * But we are not treating as a failure condition, if
                 * there are no aux DTSs enabled or fails. This driver
                 * already exposes sensors, which can be accessed via
                 * ACPI/MSR. So we don't want to fail for auxiliary DTSs.
                 */
                proc_priv->soc_dts = intel_soc_dts_iosf_init(
                                        INTEL_SOC_DTS_INTERRUPT_MSI, false, 0);

                if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
                        ret = pci_enable_msi(pdev);
                        if (!ret) {
                                ret = request_threaded_irq(pdev->irq, NULL,
                                                proc_thermal_pci_msi_irq,
                                                IRQF_ONESHOT, "proc_thermal",
                                                pdev);
                                if (ret) {
                                        intel_soc_dts_iosf_exit(
                                                        proc_priv->soc_dts);
                                        pci_disable_msi(pdev);
                                        proc_priv->soc_dts = NULL;
                                }
                        }
                } else
                        dev_err(&pdev->dev, "No auxiliary DTSs enabled\n");
        } else {

        }

        ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
        if (ret) {
                proc_thermal_remove(proc_priv);
                return ret;
        }

        return 0;
}

static void proc_thermal_pci_remove(struct pci_dev *pdev)
{
        struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);

        if (proc_priv->soc_dts) {
                intel_soc_dts_iosf_exit(proc_priv->soc_dts);
                if (pdev->irq) {
                        free_irq(pdev->irq, pdev);
                        pci_disable_msi(pdev);
                }
        }

        proc_thermal_mmio_remove(pdev, proc_priv);
        proc_thermal_remove(proc_priv);
}

#ifdef CONFIG_PM_SLEEP
static int proc_thermal_pci_suspend(struct device *dev)
{
        return proc_thermal_suspend(dev);
}
static int proc_thermal_pci_resume(struct device *dev)
{
        return proc_thermal_resume(dev);
}
#else
#define proc_thermal_pci_suspend NULL
#define proc_thermal_pci_resume NULL
#endif

static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
                         proc_thermal_pci_resume);

static const struct pci_device_id proc_thermal_pci_ids[] = {
        { PCI_DEVICE_DATA(INTEL, BDW_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, BSW_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, BXT0_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, BXT1_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, BXTX_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, BXTP_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, CNL_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, CFL_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, GLK_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, HSB_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
        { PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
        { PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
        { PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
          PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_WT_REQ) },
        { },
};

MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);

static struct pci_driver proc_thermal_pci_driver = {
        .name           = DRV_NAME,
        .probe          = proc_thermal_pci_probe,
        .remove         = proc_thermal_pci_remove,
        .id_table       = proc_thermal_pci_ids,
        .driver.pm      = &proc_thermal_pci_pm,
};

module_pci_driver(proc_thermal_pci_driver);

MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
MODULE_LICENSE("GPL v2");