root/drivers/thermal/thermal_mmio.c
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 */

#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>

struct thermal_mmio {
        void __iomem *mmio_base;
        u32 (*read_mmio)(void __iomem *mmio_base);
        u32 mask;
        int factor;
};

static u32 thermal_mmio_readb(void __iomem *mmio_base)
{
        return readb(mmio_base);
}

static int thermal_mmio_get_temperature(struct thermal_zone_device *tz, int *temp)
{
        int t;
        struct thermal_mmio *sensor = thermal_zone_device_priv(tz);

        t = sensor->read_mmio(sensor->mmio_base) & sensor->mask;
        t *= sensor->factor;

        *temp = t;

        return 0;
}

static const struct thermal_zone_device_ops thermal_mmio_ops = {
        .get_temp = thermal_mmio_get_temperature,
};

static int thermal_mmio_probe(struct platform_device *pdev)
{
        struct thermal_mmio *sensor;
        int (*sensor_init_func)(struct platform_device *pdev,
                                struct thermal_mmio *sensor);
        struct thermal_zone_device *thermal_zone;
        int ret;
        int temperature;

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

        sensor->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
        if (IS_ERR(sensor->mmio_base))
                return PTR_ERR(sensor->mmio_base);

        sensor_init_func = device_get_match_data(&pdev->dev);
        if (sensor_init_func) {
                ret = sensor_init_func(pdev, sensor);
                if (ret) {
                        dev_err(&pdev->dev,
                                "failed to initialize sensor (%d)\n",
                                ret);
                        return ret;
                }
        }

        thermal_zone = devm_thermal_of_zone_register(&pdev->dev,
                                                     0,
                                                     sensor,
                                                     &thermal_mmio_ops);
        if (IS_ERR(thermal_zone)) {
                dev_err(&pdev->dev,
                        "failed to register sensor (%ld)\n",
                        PTR_ERR(thermal_zone));
                return PTR_ERR(thermal_zone);
        }

        thermal_mmio_get_temperature(thermal_zone, &temperature);
        dev_info(&pdev->dev,
                 "thermal mmio sensor %s registered, current temperature: %d\n",
                 pdev->name, temperature);

        return 0;
}

static int al_thermal_init(struct platform_device *pdev,
                           struct thermal_mmio *sensor)
{
        sensor->read_mmio = thermal_mmio_readb;
        sensor->mask = 0xff;
        sensor->factor = 1000;

        return 0;
}

static const struct of_device_id thermal_mmio_id_table[] = {
        { .compatible = "amazon,al-thermal", .data = al_thermal_init},
        {}
};
MODULE_DEVICE_TABLE(of, thermal_mmio_id_table);

static struct platform_driver thermal_mmio_driver = {
        .probe = thermal_mmio_probe,
        .driver = {
                .name = "thermal-mmio",
                .of_match_table = thermal_mmio_id_table,
        },
};

module_platform_driver(thermal_mmio_driver);

MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>");
MODULE_DESCRIPTION("Thermal MMIO Driver");
MODULE_LICENSE("GPL v2");