aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/qcom
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2018-12-07 03:49:50 -0500
committerZhang Rui <rui.zhang@intel.com>2018-12-07 03:49:50 -0500
commiteaaa598c0a285ef3b0efa54e711a385269fe50ce (patch)
tree6e33bb0f35d84eae9fc0cc8b88dae1570231eafe /drivers/thermal/qcom
parent68000a0d983f539c95ebe5dccd4f29535c7ac0af (diff)
parent72e9baf997286610a2a3109e79fdb528590c5523 (diff)
Merge branches 'for-rc' and 'thermal-core' into next
Diffstat (limited to 'drivers/thermal/qcom')
-rw-r--r--drivers/thermal/qcom/Kconfig11
-rw-r--r--drivers/thermal/qcom/Makefile1
-rw-r--r--drivers/thermal/qcom/qcom-spmi-temp-alarm.c465
3 files changed, 477 insertions, 0 deletions
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index be32e5abce3c..cdb455ffd575 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -9,3 +9,14 @@ config QCOM_TSENS
9 thermal zone device via the mode file results in disabling the sensor. 9 thermal zone device via the mode file results in disabling the sensor.
10 Also able to set threshold temperature for both hot and cold and update 10 Also able to set threshold temperature for both hot and cold and update
11 when a threshold is reached. 11 when a threshold is reached.
12
13config QCOM_SPMI_TEMP_ALARM
14 tristate "Qualcomm SPMI PMIC Temperature Alarm"
15 depends on OF && SPMI && IIO
16 select REGMAP_SPMI
17 help
18 This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP)
19 PMIC devices. It shows up in sysfs as a thermal sensor with multiple
20 trip points. The temperature reported by the thermal sensor reflects the
21 real time die temperature if an ADC is present or an estimate of the
22 temperature based upon the over temperature stage value.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index a821929ede0b..717a08600bb5 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -1,2 +1,3 @@
1obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o 1obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o
2qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-v2.o 2qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-v2.o
3obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
new file mode 100644
index 000000000000..c1fd71dbab3e
--- /dev/null
+++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c
@@ -0,0 +1,465 @@
1/*
2 * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/bitops.h>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <linux/iio/consumer.h>
18#include <linux/interrupt.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_device.h>
22#include <linux/platform_device.h>
23#include <linux/regmap.h>
24#include <linux/thermal.h>
25
26#include "../thermal_core.h"
27
28#define QPNP_TM_REG_TYPE 0x04
29#define QPNP_TM_REG_SUBTYPE 0x05
30#define QPNP_TM_REG_STATUS 0x08
31#define QPNP_TM_REG_SHUTDOWN_CTRL1 0x40
32#define QPNP_TM_REG_ALARM_CTRL 0x46
33
34#define QPNP_TM_TYPE 0x09
35#define QPNP_TM_SUBTYPE_GEN1 0x08
36#define QPNP_TM_SUBTYPE_GEN2 0x09
37
38#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0)
39#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)
40#define STATUS_GEN2_STATE_SHIFT 4
41
42#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6)
43#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
44
45#define SHUTDOWN_CTRL1_RATE_25HZ BIT(3)
46
47#define ALARM_CTRL_FORCE_ENABLE BIT(7)
48
49/*
50 * Trip point values based on threshold control
51 * 0 = {105 C, 125 C, 145 C}
52 * 1 = {110 C, 130 C, 150 C}
53 * 2 = {115 C, 135 C, 155 C}
54 * 3 = {120 C, 140 C, 160 C}
55*/
56#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */
57#define TEMP_STAGE_HYSTERESIS 2000
58
59#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
60#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
61
62#define THRESH_MIN 0
63#define THRESH_MAX 3
64
65/* Stage 2 Threshold Min: 125 C */
66#define STAGE2_THRESHOLD_MIN 125000
67/* Stage 2 Threshold Max: 140 C */
68#define STAGE2_THRESHOLD_MAX 140000
69
70/* Temperature in Milli Celsius reported during stage 0 if no ADC is present */
71#define DEFAULT_TEMP 37000
72
73struct qpnp_tm_chip {
74 struct regmap *map;
75 struct device *dev;
76 struct thermal_zone_device *tz_dev;
77 unsigned int subtype;
78 long temp;
79 unsigned int thresh;
80 unsigned int stage;
81 unsigned int prev_stage;
82 unsigned int base;
83 /* protects .thresh, .stage and chip registers */
84 struct mutex lock;
85 bool initialized;
86
87 struct iio_channel *adc;
88};
89
90/* This array maps from GEN2 alarm state to GEN1 alarm stage */
91static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};
92
93static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data)
94{
95 unsigned int val;
96 int ret;
97
98 ret = regmap_read(chip->map, chip->base + addr, &val);
99 if (ret < 0)
100 return ret;
101
102 *data = val;
103 return 0;
104}
105
106static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
107{
108 return regmap_write(chip->map, chip->base + addr, data);
109}
110
111/**
112 * qpnp_tm_get_temp_stage() - return over-temperature stage
113 * @chip: Pointer to the qpnp_tm chip
114 *
115 * Return: stage (GEN1) or state (GEN2) on success, or errno on failure.
116 */
117static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
118{
119 int ret;
120 u8 reg = 0;
121
122 ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
123 if (ret < 0)
124 return ret;
125
126 if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
127 ret = reg & STATUS_GEN1_STAGE_MASK;
128 else
129 ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT;
130
131 return ret;
132}
133
134/*
135 * This function updates the internal temp value based on the
136 * current thermal stage and threshold as well as the previous stage
137 */
138static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
139{
140 unsigned int stage, stage_new, stage_old;
141 int ret;
142
143 WARN_ON(!mutex_is_locked(&chip->lock));
144
145 ret = qpnp_tm_get_temp_stage(chip);
146 if (ret < 0)
147 return ret;
148 stage = ret;
149
150 if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
151 stage_new = stage;
152 stage_old = chip->stage;
153 } else {
154 stage_new = alarm_state_map[stage];
155 stage_old = alarm_state_map[chip->stage];
156 }
157
158 if (stage_new > stage_old) {
159 /* increasing stage, use lower bound */
160 chip->temp = (stage_new - 1) * TEMP_STAGE_STEP +
161 chip->thresh * TEMP_THRESH_STEP +
162 TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
163 } else if (stage_new < stage_old) {
164 /* decreasing stage, use upper bound */
165 chip->temp = stage_new * TEMP_STAGE_STEP +
166 chip->thresh * TEMP_THRESH_STEP -
167 TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
168 }
169
170 chip->stage = stage;
171
172 return 0;
173}
174
175static int qpnp_tm_get_temp(void *data, int *temp)
176{
177 struct qpnp_tm_chip *chip = data;
178 int ret, mili_celsius;
179
180 if (!temp)
181 return -EINVAL;
182
183 if (!chip->initialized) {
184 *temp = DEFAULT_TEMP;
185 return 0;
186 }
187
188 if (!chip->adc) {
189 mutex_lock(&chip->lock);
190 ret = qpnp_tm_update_temp_no_adc(chip);
191 mutex_unlock(&chip->lock);
192 if (ret < 0)
193 return ret;
194 } else {
195 ret = iio_read_channel_processed(chip->adc, &mili_celsius);
196 if (ret < 0)
197 return ret;
198
199 chip->temp = mili_celsius;
200 }
201
202 *temp = chip->temp < 0 ? 0 : chip->temp;
203
204 return 0;
205}
206
207static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip,
208 int temp)
209{
210 u8 reg;
211 bool disable_s2_shutdown = false;
212
213 WARN_ON(!mutex_is_locked(&chip->lock));
214
215 /*
216 * Default: S2 and S3 shutdown enabled, thresholds at
217 * 105C/125C/145C, monitoring at 25Hz
218 */
219 reg = SHUTDOWN_CTRL1_RATE_25HZ;
220
221 if (temp == THERMAL_TEMP_INVALID ||
222 temp < STAGE2_THRESHOLD_MIN) {
223 chip->thresh = THRESH_MIN;
224 goto skip;
225 }
226
227 if (temp <= STAGE2_THRESHOLD_MAX) {
228 chip->thresh = THRESH_MAX -
229 ((STAGE2_THRESHOLD_MAX - temp) /
230 TEMP_THRESH_STEP);
231 disable_s2_shutdown = true;
232 } else {
233 chip->thresh = THRESH_MAX;
234
235 if (chip->adc)
236 disable_s2_shutdown = true;
237 else
238 dev_warn(chip->dev,
239 "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n");
240 }
241
242skip:
243 reg |= chip->thresh;
244 if (disable_s2_shutdown)
245 reg |= SHUTDOWN_CTRL1_OVERRIDE_S2;
246
247 return qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
248}
249
250static int qpnp_tm_set_trip_temp(void *data, int trip, int temp)
251{
252 struct qpnp_tm_chip *chip = data;
253 const struct thermal_trip *trip_points;
254 int ret;
255
256 trip_points = of_thermal_get_trip_points(chip->tz_dev);
257 if (!trip_points)
258 return -EINVAL;
259
260 if (trip_points[trip].type != THERMAL_TRIP_CRITICAL)
261 return 0;
262
263 mutex_lock(&chip->lock);
264 ret = qpnp_tm_update_critical_trip_temp(chip, temp);
265 mutex_unlock(&chip->lock);
266
267 return ret;
268}
269
270static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = {
271 .get_temp = qpnp_tm_get_temp,
272 .set_trip_temp = qpnp_tm_set_trip_temp,
273};
274
275static irqreturn_t qpnp_tm_isr(int irq, void *data)
276{
277 struct qpnp_tm_chip *chip = data;
278
279 thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED);
280
281 return IRQ_HANDLED;
282}
283
284static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip)
285{
286 int ntrips;
287 const struct thermal_trip *trips;
288 int i;
289
290 ntrips = of_thermal_get_ntrips(chip->tz_dev);
291 if (ntrips <= 0)
292 return THERMAL_TEMP_INVALID;
293
294 trips = of_thermal_get_trip_points(chip->tz_dev);
295 if (!trips)
296 return THERMAL_TEMP_INVALID;
297
298 for (i = 0; i < ntrips; i++) {
299 if (of_thermal_is_trip_valid(chip->tz_dev, i) &&
300 trips[i].type == THERMAL_TRIP_CRITICAL)
301 return trips[i].temperature;
302 }
303
304 return THERMAL_TEMP_INVALID;
305}
306
307/*
308 * This function initializes the internal temp value based on only the
309 * current thermal stage and threshold. Setup threshold control and
310 * disable shutdown override.
311 */
312static int qpnp_tm_init(struct qpnp_tm_chip *chip)
313{
314 unsigned int stage;
315 int ret;
316 u8 reg = 0;
317 int crit_temp;
318
319 mutex_lock(&chip->lock);
320
321 ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg);
322 if (ret < 0)
323 goto out;
324
325 chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
326 chip->temp = DEFAULT_TEMP;
327
328 ret = qpnp_tm_get_temp_stage(chip);
329 if (ret < 0)
330 goto out;
331 chip->stage = ret;
332
333 stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
334 ? chip->stage : alarm_state_map[chip->stage];
335
336 if (stage)
337 chip->temp = chip->thresh * TEMP_THRESH_STEP +
338 (stage - 1) * TEMP_STAGE_STEP +
339 TEMP_THRESH_MIN;
340
341 crit_temp = qpnp_tm_get_critical_trip_temp(chip);
342 ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp);
343 if (ret < 0)
344 goto out;
345
346 /* Enable the thermal alarm PMIC module in always-on mode. */
347 reg = ALARM_CTRL_FORCE_ENABLE;
348 ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg);
349
350 chip->initialized = true;
351
352out:
353 mutex_unlock(&chip->lock);
354 return ret;
355}
356
357static int qpnp_tm_probe(struct platform_device *pdev)
358{
359 struct qpnp_tm_chip *chip;
360 struct device_node *node;
361 u8 type, subtype;
362 u32 res;
363 int ret, irq;
364
365 node = pdev->dev.of_node;
366
367 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
368 if (!chip)
369 return -ENOMEM;
370
371 dev_set_drvdata(&pdev->dev, chip);
372 chip->dev = &pdev->dev;
373
374 mutex_init(&chip->lock);
375
376 chip->map = dev_get_regmap(pdev->dev.parent, NULL);
377 if (!chip->map)
378 return -ENXIO;
379
380 ret = of_property_read_u32(node, "reg", &res);
381 if (ret < 0)
382 return ret;
383
384 irq = platform_get_irq(pdev, 0);
385 if (irq < 0)
386 return irq;
387
388 /* ADC based measurements are optional */
389 chip->adc = devm_iio_channel_get(&pdev->dev, "thermal");
390 if (IS_ERR(chip->adc)) {
391 ret = PTR_ERR(chip->adc);
392 chip->adc = NULL;
393 if (ret == -EPROBE_DEFER)
394 return ret;
395 }
396
397 chip->base = res;
398
399 ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type);
400 if (ret < 0) {
401 dev_err(&pdev->dev, "could not read type\n");
402 return ret;
403 }
404
405 ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype);
406 if (ret < 0) {
407 dev_err(&pdev->dev, "could not read subtype\n");
408 return ret;
409 }
410
411 if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
412 && subtype != QPNP_TM_SUBTYPE_GEN2)) {
413 dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
414 type, subtype);
415 return -ENODEV;
416 }
417
418 chip->subtype = subtype;
419
420 /*
421 * Register the sensor before initializing the hardware to be able to
422 * read the trip points. get_temp() returns the default temperature
423 * before the hardware initialization is completed.
424 */
425 chip->tz_dev = devm_thermal_zone_of_sensor_register(
426 &pdev->dev, 0, chip, &qpnp_tm_sensor_ops);
427 if (IS_ERR(chip->tz_dev)) {
428 dev_err(&pdev->dev, "failed to register sensor\n");
429 return PTR_ERR(chip->tz_dev);
430 }
431
432 ret = qpnp_tm_init(chip);
433 if (ret < 0) {
434 dev_err(&pdev->dev, "init failed\n");
435 return ret;
436 }
437
438 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr,
439 IRQF_ONESHOT, node->name, chip);
440 if (ret < 0)
441 return ret;
442
443 thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED);
444
445 return 0;
446}
447
448static const struct of_device_id qpnp_tm_match_table[] = {
449 { .compatible = "qcom,spmi-temp-alarm" },
450 { }
451};
452MODULE_DEVICE_TABLE(of, qpnp_tm_match_table);
453
454static struct platform_driver qpnp_tm_driver = {
455 .driver = {
456 .name = "spmi-temp-alarm",
457 .of_match_table = qpnp_tm_match_table,
458 },
459 .probe = qpnp_tm_probe,
460};
461module_platform_driver(qpnp_tm_driver);
462
463MODULE_ALIAS("platform:spmi-temp-alarm");
464MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver");
465MODULE_LICENSE("GPL v2");