aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2016-08-23 04:20:27 -0400
committerZhang Rui <rui.zhang@intel.com>2016-09-27 02:02:16 -0400
commitec4664b3fd6d565a79eb562e4339528f74eb1cca (patch)
tree0828814b91d910325d5caf25259012a167002c2d /drivers/thermal
parent94c2004ef530a9692ae9f417241eb44a51723c51 (diff)
thermal: max77620: Add thermal driver for reporting junction temp
Maxim Semiconductor Max77620 supports alarm interrupts when its die temperature crosses 120C and 140C. These threshold temperatures are not configurable. Add thermal driver to register PMIC die temperature as thermal zone sensor and capture the die temperature warning interrupts to notifying the client. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig10
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/max77620_thermal.c165
3 files changed, 176 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 900d505ee5d5..38a304e922c4 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -195,6 +195,16 @@ config IMX_THERMAL
195 cpufreq is used as the cooling device to throttle CPUs when the 195 cpufreq is used as the cooling device to throttle CPUs when the
196 passive trip is crossed. 196 passive trip is crossed.
197 197
198config MAX77620_THERMAL
199 tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
200 depends on MFD_MAX77620
201 depends on OF
202 help
203 Support for die junction temperature warning alarm for Maxim
204 Semiconductor PMIC MAX77620 device. Device generates two alarm
205 interrupts when PMIC die temperature cross the threshold of
206 120 degC and 140 degC.
207
198config QORIQ_THERMAL 208config QORIQ_THERMAL
199 tristate "QorIQ Thermal Monitoring Unit" 209 tristate "QorIQ Thermal Monitoring Unit"
200 depends on THERMAL_OF 210 depends on THERMAL_OF
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index fdb4b3871254..7c1aca6d8b14 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
37obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o 37obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
38obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o 38obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
39obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o 39obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
40obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
40obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o 41obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
41obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o 42obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
42obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 43obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
diff --git a/drivers/thermal/max77620_thermal.c b/drivers/thermal/max77620_thermal.c
new file mode 100644
index 000000000000..8d6162676f68
--- /dev/null
+++ b/drivers/thermal/max77620_thermal.c
@@ -0,0 +1,165 @@
1/*
2 * Junction temperature thermal driver for Maxim Max77620.
3 *
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
7 * Mallikarjun Kasoju <mkasoju@nvidia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 */
13
14#include <linux/irq.h>
15#include <linux/interrupt.h>
16#include <linux/mfd/max77620.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20#include <linux/regmap.h>
21#include <linux/slab.h>
22#include <linux/thermal.h>
23
24#define MAX77620_NORMAL_OPERATING_TEMP 100000
25#define MAX77620_TJALARM1_TEMP 120000
26#define MAX77620_TJALARM2_TEMP 140000
27
28struct max77620_therm_info {
29 struct device *dev;
30 struct regmap *rmap;
31 struct thermal_zone_device *tz_device;
32 int irq_tjalarm1;
33 int irq_tjalarm2;
34};
35
36/**
37 * max77620_thermal_read_temp: Read PMIC die temperatue.
38 * @data: Device specific data.
39 * temp: Temperature in millidegrees Celsius
40 *
41 * The actual temperature of PMIC die is not available from PMIC.
42 * PMIC only tells the status if it has crossed or not the threshold level
43 * of 120degC or 140degC.
44 * If threshold has not been crossed then assume die temperature as 100degC
45 * else 120degC or 140deG based on the PMIC die temp threshold status.
46 *
47 * Return 0 on success otherwise error number to show reason of failure.
48 */
49
50static int max77620_thermal_read_temp(void *data, int *temp)
51{
52 struct max77620_therm_info *mtherm = data;
53 unsigned int val;
54 int ret;
55
56 ret = regmap_read(mtherm->rmap, MAX77620_REG_STATLBT, &val);
57 if (ret < 0) {
58 dev_err(mtherm->dev, "Failed to read STATLBT: %d\n", ret);
59 return ret;
60 }
61
62 if (val & MAX77620_IRQ_TJALRM2_MASK)
63 *temp = MAX77620_TJALARM2_TEMP;
64 else if (val & MAX77620_IRQ_TJALRM1_MASK)
65 *temp = MAX77620_TJALARM1_TEMP;
66 else
67 *temp = MAX77620_NORMAL_OPERATING_TEMP;
68
69 return 0;
70}
71
72static const struct thermal_zone_of_device_ops max77620_thermal_ops = {
73 .get_temp = max77620_thermal_read_temp,
74};
75
76static irqreturn_t max77620_thermal_irq(int irq, void *data)
77{
78 struct max77620_therm_info *mtherm = data;
79
80 if (irq == mtherm->irq_tjalarm1)
81 dev_warn(mtherm->dev, "Junction Temp Alarm1(120C) occurred\n");
82 else if (irq == mtherm->irq_tjalarm2)
83 dev_crit(mtherm->dev, "Junction Temp Alarm2(140C) occurred\n");
84
85 thermal_zone_device_update(mtherm->tz_device);
86
87 return IRQ_HANDLED;
88}
89
90static int max77620_thermal_probe(struct platform_device *pdev)
91{
92 struct max77620_therm_info *mtherm;
93 int ret;
94
95 mtherm = devm_kzalloc(&pdev->dev, sizeof(*mtherm), GFP_KERNEL);
96 if (!mtherm)
97 return -ENOMEM;
98
99 mtherm->irq_tjalarm1 = platform_get_irq(pdev, 0);
100 mtherm->irq_tjalarm2 = platform_get_irq(pdev, 1);
101 if ((mtherm->irq_tjalarm1 < 0) || (mtherm->irq_tjalarm2 < 0)) {
102 dev_err(&pdev->dev, "Alarm irq number not available\n");
103 return -EINVAL;
104 }
105
106 pdev->dev.of_node = pdev->dev.parent->of_node;
107
108 mtherm->dev = &pdev->dev;
109 mtherm->rmap = dev_get_regmap(pdev->dev.parent, NULL);
110 if (!mtherm->rmap) {
111 dev_err(&pdev->dev, "Failed to get parent regmap\n");
112 return -ENODEV;
113 }
114
115 mtherm->tz_device = devm_thermal_zone_of_sensor_register(&pdev->dev, 0,
116 mtherm, &max77620_thermal_ops);
117 if (IS_ERR(mtherm->tz_device)) {
118 ret = PTR_ERR(mtherm->tz_device);
119 dev_err(&pdev->dev, "Failed to register thermal zone: %d\n",
120 ret);
121 return ret;
122 }
123
124 ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL,
125 max77620_thermal_irq,
126 IRQF_ONESHOT | IRQF_SHARED,
127 dev_name(&pdev->dev), mtherm);
128 if (ret < 0) {
129 dev_err(&pdev->dev, "Failed to request irq1: %d\n", ret);
130 return ret;
131 }
132
133 ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm2, NULL,
134 max77620_thermal_irq,
135 IRQF_ONESHOT | IRQF_SHARED,
136 dev_name(&pdev->dev), mtherm);
137 if (ret < 0) {
138 dev_err(&pdev->dev, "Failed to request irq2: %d\n", ret);
139 return ret;
140 }
141
142 platform_set_drvdata(pdev, mtherm);
143
144 return 0;
145}
146
147static struct platform_device_id max77620_thermal_devtype[] = {
148 { .name = "max77620-thermal", },
149 {},
150};
151
152static struct platform_driver max77620_thermal_driver = {
153 .driver = {
154 .name = "max77620-thermal",
155 },
156 .probe = max77620_thermal_probe,
157 .id_table = max77620_thermal_devtype,
158};
159
160module_platform_driver(max77620_thermal_driver);
161
162MODULE_DESCRIPTION("Max77620 Junction temperature Thermal driver");
163MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
164MODULE_AUTHOR("Mallikarjun Kasoju <mkasoju@nvidia.com>");
165MODULE_LICENSE("GPL v2");