^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct thermal_mmio {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) void __iomem *mmio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) u32 (*read_mmio)(void __iomem *mmio_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static u32 thermal_mmio_readb(void __iomem *mmio_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) return readb(mmio_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int thermal_mmio_get_temperature(void *private, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct thermal_mmio *sensor =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) (struct thermal_mmio *)private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) t = sensor->read_mmio(sensor->mmio_base) & sensor->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) t *= sensor->factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *temp = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct thermal_zone_of_device_ops thermal_mmio_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .get_temp = thermal_mmio_get_temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int thermal_mmio_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct thermal_mmio *sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int (*sensor_init_func)(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct thermal_mmio *sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct thermal_zone_device *thermal_zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) int temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!sensor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (IS_ERR(sensor->mmio_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) PTR_ERR(sensor->mmio_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return PTR_ERR(sensor->mmio_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) sensor_init_func = device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (sensor_init_func) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ret = sensor_init_func(pdev, sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "failed to initialize sensor (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) sensor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) &thermal_mmio_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (IS_ERR(thermal_zone)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) "failed to register sensor (%ld)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) PTR_ERR(thermal_zone));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return PTR_ERR(thermal_zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) thermal_mmio_get_temperature(sensor, &temperature);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) dev_info(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "thermal mmio sensor %s registered, current temperature: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) pdev->name, temperature);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int al_thermal_init(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct thermal_mmio *sensor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) sensor->read_mmio = thermal_mmio_readb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) sensor->mask = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) sensor->factor = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static const struct of_device_id thermal_mmio_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) { .compatible = "amazon,al-thermal", .data = al_thermal_init},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MODULE_DEVICE_TABLE(of, thermal_mmio_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static struct platform_driver thermal_mmio_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .probe = thermal_mmio_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .name = "thermal-mmio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .of_match_table = of_match_ptr(thermal_mmio_id_table),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) module_platform_driver(thermal_mmio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) MODULE_DESCRIPTION("Thermal MMIO Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) MODULE_LICENSE("GPL v2");