^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 (C) 2018 Broadcom
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * In stingray thermal IO memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Total Number of available TMONs MASK is at offset 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * temperature registers BASE is at 4 byte offset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Each TMON temperature register size is 4.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define SR_TMON_TEMP_BASE(id) ((id) * 0x4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define SR_TMON_MAX_LIST 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct sr_tmon {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct thermal_zone_device *tz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int crit_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned int tmon_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct sr_thermal *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct sr_thermal {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int max_crit_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct sr_tmon tmon[SR_TMON_MAX_LIST];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int sr_get_temp(void *data, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct sr_tmon *tmon = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct sr_thermal *sr_thermal = tmon->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *temp = readl(sr_thermal->regs + SR_TMON_TEMP_BASE(tmon->tmon_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static const struct thermal_zone_of_device_ops sr_tz_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .get_temp = sr_get_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int sr_thermal_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct sr_thermal *sr_thermal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct sr_tmon *tmon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u32 sr_tmon_list = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) sr_thermal = devm_kzalloc(dev, sizeof(*sr_thermal), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (!sr_thermal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) sr_thermal->regs = (void __iomem *)devm_memremap(&pdev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) resource_size(res),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) MEMREMAP_WB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (IS_ERR(sr_thermal->regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) dev_err(dev, "failed to get io address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return PTR_ERR(sr_thermal->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ret = device_property_read_u32(dev, "brcm,tmon-mask", &sr_tmon_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) tmon = sr_thermal->tmon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) for (i = 0; i < SR_TMON_MAX_LIST; i++, tmon++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (!(sr_tmon_list & BIT(i)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Flush temperature registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) writel(0, sr_thermal->regs + SR_TMON_TEMP_BASE(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) tmon->tmon_id = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) tmon->priv = sr_thermal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) tmon->tz = devm_thermal_zone_of_sensor_register(dev, i, tmon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) &sr_tz_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (IS_ERR(tmon->tz))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return PTR_ERR(tmon->tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev_dbg(dev, "thermal sensor %d registered\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) platform_set_drvdata(pdev, sr_thermal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static const struct of_device_id sr_thermal_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) { .compatible = "brcm,sr-thermal", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) MODULE_DEVICE_TABLE(of, sr_thermal_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static struct platform_driver sr_thermal_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .probe = sr_thermal_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .name = "sr-thermal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .of_match_table = sr_thermal_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) module_platform_driver(sr_thermal_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) MODULE_DESCRIPTION("Stingray thermal driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) MODULE_LICENSE("GPL v2");