^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Junction temperature thermal driver for Maxim Max77620.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Laxman Dewangan <ldewangan@nvidia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Mallikarjun Kasoju <mkasoju@nvidia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mfd/max77620.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define MAX77620_NORMAL_OPERATING_TEMP 100000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MAX77620_TJALARM1_TEMP 120000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MAX77620_TJALARM2_TEMP 140000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct max77620_therm_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct regmap *rmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct thermal_zone_device *tz_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int irq_tjalarm1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int irq_tjalarm2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^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) * max77620_thermal_read_temp: Read PMIC die temperatue.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * @data: Device specific data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * @temp: Temperature in millidegrees Celsius
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * The actual temperature of PMIC die is not available from PMIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * PMIC only tells the status if it has crossed or not the threshold level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * of 120degC or 140degC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * If threshold has not been crossed then assume die temperature as 100degC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * else 120degC or 140deG based on the PMIC die temp threshold status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Return 0 on success otherwise error number to show reason of failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int max77620_thermal_read_temp(void *data, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct max77620_therm_info *mtherm = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ret = regmap_read(mtherm->rmap, MAX77620_REG_STATLBT, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) dev_err(mtherm->dev, "Failed to read STATLBT: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (val & MAX77620_IRQ_TJALRM2_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *temp = MAX77620_TJALARM2_TEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) else if (val & MAX77620_IRQ_TJALRM1_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *temp = MAX77620_TJALARM1_TEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *temp = MAX77620_NORMAL_OPERATING_TEMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static const struct thermal_zone_of_device_ops max77620_thermal_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .get_temp = max77620_thermal_read_temp,
^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) static irqreturn_t max77620_thermal_irq(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct max77620_therm_info *mtherm = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (irq == mtherm->irq_tjalarm1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) dev_warn(mtherm->dev, "Junction Temp Alarm1(120C) occurred\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) else if (irq == mtherm->irq_tjalarm2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) dev_crit(mtherm->dev, "Junction Temp Alarm2(140C) occurred\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) thermal_zone_device_update(mtherm->tz_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) THERMAL_EVENT_UNSPECIFIED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int max77620_thermal_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct max77620_therm_info *mtherm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) mtherm = devm_kzalloc(&pdev->dev, sizeof(*mtherm), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!mtherm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) mtherm->irq_tjalarm1 = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) mtherm->irq_tjalarm2 = platform_get_irq(pdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if ((mtherm->irq_tjalarm1 < 0) || (mtherm->irq_tjalarm2 < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) dev_err(&pdev->dev, "Alarm irq number not available\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) mtherm->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!mtherm->rmap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) dev_err(&pdev->dev, "Failed to get parent regmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * The reference taken to the parent's node which will be balanced on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * reprobe or on platform-device release.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) mtherm, &max77620_thermal_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (IS_ERR(mtherm->tz_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) ret = PTR_ERR(mtherm->tz_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_err(&pdev->dev, "Failed to register thermal zone: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) max77620_thermal_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) IRQF_ONESHOT | IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) dev_name(&pdev->dev), mtherm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dev_err(&pdev->dev, "Failed to request irq1: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm2, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) max77620_thermal_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) IRQF_ONESHOT | IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) dev_name(&pdev->dev), mtherm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) dev_err(&pdev->dev, "Failed to request irq2: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) platform_set_drvdata(pdev, mtherm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static struct platform_device_id max77620_thermal_devtype[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { .name = "max77620-thermal", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) MODULE_DEVICE_TABLE(platform, max77620_thermal_devtype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static struct platform_driver max77620_thermal_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .name = "max77620-thermal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .probe = max77620_thermal_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .id_table = max77620_thermal_devtype,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) module_platform_driver(max77620_thermal_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) MODULE_DESCRIPTION("Max77620 Junction temperature Thermal driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) MODULE_LICENSE("GPL v2");