kernel: bump 4.9 to 4.9.77
[openwrt/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0063-1-ipq806x-tsens-driver.patch
1 From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001
2 From: Rajith Cherian <rajith@codeaurora.org>
3 Date: Tue, 14 Feb 2017 18:30:43 +0530
4 Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064
5
6 Add TSENS driver template to support IPQ8064.
7 This is a base file copied from tsens-8960.c
8
9 Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7
10 Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
11
12 ipq8064: tsens: TSENS driver support for IPQ8064
13
14 Support for IPQ8064 tsens driver. The driver works
15 with the thermal framework. The driver overrides the
16 following fucntionalities:
17
18 1. Get current temperature.
19 2. Get/Set trip temperatures.
20 3. Enabled/Disable trip points.
21 4. ISR for threshold generated interrupt.
22 5. Notify userspace when trip points are hit.
23
24 Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918
25 Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
26 ---
27 .../devicetree/bindings/thermal/qcom-tsens.txt | 1 +
28 drivers/thermal/qcom/Makefile | 3 +-
29 drivers/thermal/qcom/tsens-ipq8064.c | 551 +++++++++++++++++++++
30 drivers/thermal/qcom/tsens.c | 3 +
31 drivers/thermal/qcom/tsens.h | 2 +-
32 5 files changed, 558 insertions(+), 2 deletions(-)
33 create mode 100644 drivers/thermal/qcom/tsens-ipq8064.c
34
35 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
36 +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
37 @@ -5,6 +5,7 @@ Required properties:
38 - "qcom,msm8916-tsens" : For 8916 Family of SoCs
39 - "qcom,msm8974-tsens" : For 8974 Family of SoCs
40 - "qcom,msm8996-tsens" : For 8996 Family of SoCs
41 + - "qcom,ipq8064-tsens" : For IPQ8064
42
43 - reg: Address range of the thermal registers
44 - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
45 --- a/drivers/thermal/qcom/Makefile
46 +++ b/drivers/thermal/qcom/Makefile
47 @@ -1,2 +1,3 @@
48 obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o
49 -qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o
50 +qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o \
51 + tsens-ipq8064.o
52 --- /dev/null
53 +++ b/drivers/thermal/qcom/tsens-ipq8064.c
54 @@ -0,0 +1,551 @@
55 +/*
56 + * Copyright (c) 2015, The Linux Foundation. All rights reserved.
57 + *
58 + * This program is free software; you can redistribute it and/or modify
59 + * it under the terms of the GNU General Public License version 2 and
60 + * only version 2 as published by the Free Software Foundation.
61 + *
62 + * This program is distributed in the hope that it will be useful,
63 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
64 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
65 + * GNU General Public License for more details.
66 + *
67 + */
68 +
69 +#include <linux/platform_device.h>
70 +#include <linux/delay.h>
71 +#include <linux/bitops.h>
72 +#include <linux/regmap.h>
73 +#include <linux/thermal.h>
74 +#include <linux/nvmem-consumer.h>
75 +#include <linux/io.h>
76 +#include <linux/interrupt.h>
77 +#include "tsens.h"
78 +
79 +#define CAL_MDEGC 30000
80 +
81 +#define CONFIG_ADDR 0x3640
82 +/* CONFIG_ADDR bitmasks */
83 +#define CONFIG 0x9b
84 +#define CONFIG_MASK 0xf
85 +#define CONFIG_SHIFT 0
86 +
87 +#define STATUS_CNTL_8064 0x3660
88 +#define CNTL_ADDR 0x3620
89 +/* CNTL_ADDR bitmasks */
90 +#define EN BIT(0)
91 +#define SW_RST BIT(1)
92 +#define SENSOR0_EN BIT(3)
93 +#define SLP_CLK_ENA BIT(26)
94 +#define MEASURE_PERIOD 1
95 +#define SENSOR0_SHIFT 3
96 +
97 +/* INT_STATUS_ADDR bitmasks */
98 +#define MIN_STATUS_MASK BIT(0)
99 +#define LOWER_STATUS_CLR BIT(1)
100 +#define UPPER_STATUS_CLR BIT(2)
101 +#define MAX_STATUS_MASK BIT(3)
102 +
103 +#define THRESHOLD_ADDR 0x3624
104 +/* THRESHOLD_ADDR bitmasks */
105 +#define THRESHOLD_MAX_CODE 0x20000
106 +#define THRESHOLD_MIN_CODE 0
107 +#define THRESHOLD_MAX_LIMIT_SHIFT 24
108 +#define THRESHOLD_MIN_LIMIT_SHIFT 16
109 +#define THRESHOLD_UPPER_LIMIT_SHIFT 8
110 +#define THRESHOLD_LOWER_LIMIT_SHIFT 0
111 +#define THRESHOLD_MAX_LIMIT_MASK (THRESHOLD_MAX_CODE << \
112 + THRESHOLD_MAX_LIMIT_SHIFT)
113 +#define THRESHOLD_MIN_LIMIT_MASK (THRESHOLD_MAX_CODE << \
114 + THRESHOLD_MIN_LIMIT_SHIFT)
115 +#define THRESHOLD_UPPER_LIMIT_MASK (THRESHOLD_MAX_CODE << \
116 + THRESHOLD_UPPER_LIMIT_SHIFT)
117 +#define THRESHOLD_LOWER_LIMIT_MASK (THRESHOLD_MAX_CODE << \
118 + THRESHOLD_LOWER_LIMIT_SHIFT)
119 +
120 +/* Initial temperature threshold values */
121 +#define LOWER_LIMIT_TH 0x9d /* 95C */
122 +#define UPPER_LIMIT_TH 0xa6 /* 105C */
123 +#define MIN_LIMIT_TH 0x0
124 +#define MAX_LIMIT_TH 0xff
125 +
126 +#define S0_STATUS_ADDR 0x3628
127 +#define STATUS_ADDR_OFFSET 2
128 +#define SENSOR_STATUS_SIZE 4
129 +#define INT_STATUS_ADDR 0x363c
130 +#define TRDY_MASK BIT(7)
131 +#define TIMEOUT_US 100
132 +
133 +#define TSENS_EN BIT(0)
134 +#define TSENS_SW_RST BIT(1)
135 +#define TSENS_ADC_CLK_SEL BIT(2)
136 +#define SENSOR0_EN BIT(3)
137 +#define SENSOR1_EN BIT(4)
138 +#define SENSOR2_EN BIT(5)
139 +#define SENSOR3_EN BIT(6)
140 +#define SENSOR4_EN BIT(7)
141 +#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \
142 + SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
143 +#define TSENS_8064_SENSOR5_EN BIT(8)
144 +#define TSENS_8064_SENSOR6_EN BIT(9)
145 +#define TSENS_8064_SENSOR7_EN BIT(10)
146 +#define TSENS_8064_SENSOR8_EN BIT(11)
147 +#define TSENS_8064_SENSOR9_EN BIT(12)
148 +#define TSENS_8064_SENSOR10_EN BIT(13)
149 +#define TSENS_8064_SENSORS_EN (SENSORS_EN | \
150 + TSENS_8064_SENSOR5_EN | \
151 + TSENS_8064_SENSOR6_EN | \
152 + TSENS_8064_SENSOR7_EN | \
153 + TSENS_8064_SENSOR8_EN | \
154 + TSENS_8064_SENSOR9_EN | \
155 + TSENS_8064_SENSOR10_EN)
156 +
157 +#define TSENS_8064_SEQ_SENSORS 5
158 +#define TSENS_8064_S4_S5_OFFSET 40
159 +#define TSENS_FACTOR 1
160 +
161 +/* Trips: from very hot to very cold */
162 +enum tsens_trip_type {
163 + TSENS_TRIP_STAGE3 = 0,
164 + TSENS_TRIP_STAGE2,
165 + TSENS_TRIP_STAGE1,
166 + TSENS_TRIP_STAGE0,
167 + TSENS_TRIP_NUM,
168 +};
169 +
170 +u32 tsens_8064_slope[] = {
171 + 1176, 1176, 1154, 1176,
172 + 1111, 1132, 1132, 1199,
173 + 1132, 1199, 1132
174 + };
175 +
176 +/* Temperature on y axis and ADC-code on x-axis */
177 +static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s)
178 +{
179 + int degcbeforefactor, degc;
180 +
181 + degcbeforefactor = (adc_code * s->slope) + s->offset;
182 +
183 + if (degcbeforefactor == 0)
184 + degc = degcbeforefactor;
185 + else if (degcbeforefactor > 0)
186 + degc = (degcbeforefactor + TSENS_FACTOR/2)
187 + / TSENS_FACTOR;
188 + else
189 + degc = (degcbeforefactor - TSENS_FACTOR/2)
190 + / TSENS_FACTOR;
191 +
192 + return degc;
193 +}
194 +
195 +static int degC_to_code(int degC, const struct tsens_sensor *s)
196 +{
197 + int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2))
198 + / s->slope;
199 +
200 + if (code > THRESHOLD_MAX_CODE)
201 + code = THRESHOLD_MAX_CODE;
202 + else if (code < THRESHOLD_MIN_CODE)
203 + code = THRESHOLD_MIN_CODE;
204 + return code;
205 +}
206 +
207 +static int suspend_ipq8064(struct tsens_device *tmdev)
208 +{
209 + int ret;
210 + unsigned int mask;
211 + struct regmap *map = tmdev->map;
212 +
213 + ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
214 + if (ret)
215 + return ret;
216 +
217 + ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
218 + if (ret)
219 + return ret;
220 +
221 + mask = SLP_CLK_ENA | EN;
222 +
223 + ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
224 + if (ret)
225 + return ret;
226 +
227 + return 0;
228 +}
229 +
230 +static int resume_ipq8064(struct tsens_device *tmdev)
231 +{
232 + int ret;
233 + struct regmap *map = tmdev->map;
234 +
235 + ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
236 + if (ret)
237 + return ret;
238 +
239 + ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
240 + if (ret)
241 + return ret;
242 +
243 + ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
244 + if (ret)
245 + return ret;
246 +
247 + ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
248 + if (ret)
249 + return ret;
250 +
251 + return 0;
252 +}
253 +
254 +static void notify_uspace_tsens_fn(struct work_struct *work)
255 +{
256 + struct tsens_sensor *s = container_of(work, struct tsens_sensor,
257 + notify_work);
258 +
259 + sysfs_notify(&s->tzd->device.kobj, NULL, "type");
260 +}
261 +
262 +static void tsens_scheduler_fn(struct work_struct *work)
263 +{
264 + struct tsens_device *tmdev = container_of(work, struct tsens_device,
265 + tsens_work);
266 + unsigned int threshold, threshold_low, code, reg, sensor, mask;
267 + unsigned int sensor_addr;
268 + bool upper_th_x, lower_th_x;
269 + int adc_code, ret;
270 +
271 + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
272 + if (ret)
273 + return;
274 + reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
275 + ret = regmap_write(tmdev->map, STATUS_CNTL_8064, reg);
276 + if (ret)
277 + return;
278 +
279 + mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
280 + ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &threshold);
281 + if (ret)
282 + return;
283 + threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK)
284 + >> THRESHOLD_LOWER_LIMIT_SHIFT;
285 + threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK)
286 + >> THRESHOLD_UPPER_LIMIT_SHIFT;
287 +
288 + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
289 + if (ret)
290 + return;
291 +
292 + ret = regmap_read(tmdev->map, CNTL_ADDR, &sensor);
293 + if (ret)
294 + return;
295 + sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
296 + sensor >>= SENSOR0_SHIFT;
297 +
298 + /* Constraint: There is only 1 interrupt control register for all
299 + * 11 temperature sensor. So monitoring more than 1 sensor based
300 + * on interrupts will yield inconsistent result. To overcome this
301 + * issue we will monitor only sensor 0 which is the master sensor.
302 + */
303 +
304 + /* Skip if the sensor is disabled */
305 + if (sensor & 1) {
306 + ret = regmap_read(tmdev->map, tmdev->sensor[0].status, &code);
307 + if (ret)
308 + return;
309 + upper_th_x = code >= threshold;
310 + lower_th_x = code <= threshold_low;
311 + if (upper_th_x)
312 + mask |= UPPER_STATUS_CLR;
313 + if (lower_th_x)
314 + mask |= LOWER_STATUS_CLR;
315 + if (upper_th_x || lower_th_x) {
316 + /* Notify user space */
317 + schedule_work(&tmdev->sensor[0].notify_work);
318 + regmap_read(tmdev->map, sensor_addr, &adc_code);
319 + pr_debug("Trigger (%d degrees) for sensor %d\n",
320 + code_to_degC(adc_code, &tmdev->sensor[0]), 0);
321 + }
322 + }
323 + regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask);
324 +
325 + /* force memory to sync */
326 + mb();
327 +}
328 +
329 +static irqreturn_t tsens_isr(int irq, void *data)
330 +{
331 + struct tsens_device *tmdev = data;
332 +
333 + schedule_work(&tmdev->tsens_work);
334 + return IRQ_HANDLED;
335 +}
336 +
337 +static void hw_init(struct tsens_device *tmdev)
338 +{
339 + int ret;
340 + unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
341 + unsigned int reg_status_cntl = 0;
342 +
343 + regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
344 + regmap_write(tmdev->map, CNTL_ADDR, reg_cntl | TSENS_SW_RST);
345 +
346 + reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18)
347 + | (((1 << tmdev->num_sensors) - 1) << SENSOR0_SHIFT);
348 + regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
349 + regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_status_cntl);
350 + reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR
351 + | MIN_STATUS_MASK | MAX_STATUS_MASK;
352 + regmap_write(tmdev->map, STATUS_CNTL_8064, reg_status_cntl);
353 + reg_cntl |= TSENS_EN;
354 + regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
355 +
356 + regmap_read(tmdev->map, CONFIG_ADDR, &reg_cfg);
357 + reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT);
358 + regmap_write(tmdev->map, CONFIG_ADDR, reg_cfg);
359 +
360 + reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT)
361 + | (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT)
362 + | (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT)
363 + | (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT);
364 +
365 + regmap_write(tmdev->map, THRESHOLD_ADDR, reg_thr);
366 +
367 + ret = devm_request_irq(tmdev->dev, tmdev->tsens_irq, tsens_isr,
368 + IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
369 + if (ret < 0) {
370 + pr_err("%s: request_irq FAIL: %d\n", __func__, ret);
371 + return;
372 + }
373 +
374 + INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
375 +}
376 +
377 +static int init_ipq8064(struct tsens_device *tmdev)
378 +{
379 + int ret, i;
380 + u32 reg_cntl, offset = 0;
381 +
382 + init_common(tmdev);
383 + if (!tmdev->map)
384 + return -ENODEV;
385 +
386 + /*
387 + * The status registers for each sensor are discontiguous
388 + * because some SoCs have 5 sensors while others have more
389 + * but the control registers stay in the same place, i.e
390 + * directly after the first 5 status registers.
391 + */
392 + for (i = 0; i < tmdev->num_sensors; i++) {
393 + if (i >= TSENS_8064_SEQ_SENSORS)
394 + offset = TSENS_8064_S4_S5_OFFSET;
395 +
396 + tmdev->sensor[i].status = S0_STATUS_ADDR + offset
397 + + (i << STATUS_ADDR_OFFSET);
398 + tmdev->sensor[i].slope = tsens_8064_slope[i];
399 + INIT_WORK(&tmdev->sensor[i].notify_work,
400 + notify_uspace_tsens_fn);
401 + }
402 +
403 + reg_cntl = SW_RST;
404 + ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
405 + if (ret)
406 + return ret;
407 +
408 + reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
409 + reg_cntl &= ~SW_RST;
410 + ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
411 + CONFIG_MASK, CONFIG);
412 +
413 + reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
414 + ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
415 + if (ret)
416 + return ret;
417 +
418 + reg_cntl |= EN;
419 + ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
420 + if (ret)
421 + return ret;
422 +
423 + return 0;
424 +}
425 +
426 +static int calibrate_ipq8064(struct tsens_device *tmdev)
427 +{
428 + int i;
429 + char *data, *data_backup;
430 +
431 + ssize_t num_read = tmdev->num_sensors;
432 + struct tsens_sensor *s = tmdev->sensor;
433 +
434 + data = qfprom_read(tmdev->dev, "calib");
435 + if (IS_ERR(data)) {
436 + pr_err("Calibration not found.\n");
437 + return PTR_ERR(data);
438 + }
439 +
440 + data_backup = qfprom_read(tmdev->dev, "calib_backup");
441 + if (IS_ERR(data_backup)) {
442 + pr_err("Backup calibration not found.\n");
443 + return PTR_ERR(data_backup);
444 + }
445 +
446 + for (i = 0; i < num_read; i++) {
447 + s[i].calib_data = readb_relaxed(data + i);
448 + s[i].calib_data_backup = readb_relaxed(data_backup + i);
449 +
450 + if (s[i].calib_data_backup)
451 + s[i].calib_data = s[i].calib_data_backup;
452 + if (!s[i].calib_data) {
453 + pr_err("QFPROM TSENS calibration data not present\n");
454 + return -ENODEV;
455 + }
456 + s[i].slope = tsens_8064_slope[i];
457 + s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope);
458 + }
459 +
460 + hw_init(tmdev);
461 +
462 + return 0;
463 +}
464 +
465 +static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp)
466 +{
467 + int ret;
468 + u32 code, trdy;
469 + const struct tsens_sensor *s = &tmdev->sensor[id];
470 + unsigned long timeout;
471 +
472 + timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
473 + do {
474 + ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
475 + if (ret)
476 + return ret;
477 + if (!(trdy & TRDY_MASK))
478 + continue;
479 + ret = regmap_read(tmdev->map, s->status, &code);
480 + if (ret)
481 + return ret;
482 + *temp = code_to_degC(code, s);
483 + return 0;
484 + } while (time_before(jiffies, timeout));
485 +
486 + return -ETIMEDOUT;
487 +}
488 +
489 +static int set_trip_temp_ipq8064(void *data, int trip, int temp)
490 +{
491 + unsigned int reg_th, reg_cntl;
492 + int ret, code, code_chk, hi_code, lo_code;
493 + const struct tsens_sensor *s = data;
494 + struct tsens_device *tmdev = s->tmdev;
495 +
496 + code_chk = code = degC_to_code(temp, s);
497 +
498 + if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE)
499 + return -EINVAL;
500 +
501 + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
502 + if (ret)
503 + return ret;
504 +
505 + ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &reg_th);
506 + if (ret)
507 + return ret;
508 +
509 + hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK)
510 + >> THRESHOLD_UPPER_LIMIT_SHIFT;
511 + lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK)
512 + >> THRESHOLD_LOWER_LIMIT_SHIFT;
513 +
514 + switch (trip) {
515 + case TSENS_TRIP_STAGE3:
516 + code <<= THRESHOLD_MAX_LIMIT_SHIFT;
517 + reg_th &= ~THRESHOLD_MAX_LIMIT_MASK;
518 + break;
519 + case TSENS_TRIP_STAGE2:
520 + if (code_chk <= lo_code)
521 + return -EINVAL;
522 + code <<= THRESHOLD_UPPER_LIMIT_SHIFT;
523 + reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK;
524 + break;
525 + case TSENS_TRIP_STAGE1:
526 + if (code_chk >= hi_code)
527 + return -EINVAL;
528 + code <<= THRESHOLD_LOWER_LIMIT_SHIFT;
529 + reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK;
530 + break;
531 + case TSENS_TRIP_STAGE0:
532 + code <<= THRESHOLD_MIN_LIMIT_SHIFT;
533 + reg_th &= ~THRESHOLD_MIN_LIMIT_MASK;
534 + break;
535 + default:
536 + return -EINVAL;
537 + }
538 +
539 + ret = regmap_write(tmdev->map, THRESHOLD_ADDR, reg_th | code);
540 + if (ret)
541 + return ret;
542 +
543 + return 0;
544 +}
545 +
546 +static int set_trip_activate_ipq8064(void *data, int trip,
547 + enum thermal_trip_activation_mode mode)
548 +{
549 + unsigned int reg_cntl, mask, val;
550 + const struct tsens_sensor *s = data;
551 + struct tsens_device *tmdev = s->tmdev;
552 + int ret;
553 +
554 + if (!tmdev || trip < 0)
555 + return -EINVAL;
556 +
557 + ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
558 + if (ret)
559 + return ret;
560 +
561 + switch (trip) {
562 + case TSENS_TRIP_STAGE3:
563 + mask = MAX_STATUS_MASK;
564 + break;
565 + case TSENS_TRIP_STAGE2:
566 + mask = UPPER_STATUS_CLR;
567 + break;
568 + case TSENS_TRIP_STAGE1:
569 + mask = LOWER_STATUS_CLR;
570 + break;
571 + case TSENS_TRIP_STAGE0:
572 + mask = MIN_STATUS_MASK;
573 + break;
574 + default:
575 + return -EINVAL;
576 + }
577 +
578 + if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
579 + val = reg_cntl | mask;
580 + else
581 + val = reg_cntl & ~mask;
582 +
583 + ret = regmap_write(tmdev->map, STATUS_CNTL_8064, val);
584 + if (ret)
585 + return ret;
586 +
587 + /* force memory to sync */
588 + mb();
589 + return 0;
590 +}
591 +
592 +const struct tsens_ops ops_ipq8064 = {
593 + .init = init_ipq8064,
594 + .calibrate = calibrate_ipq8064,
595 + .get_temp = get_temp_ipq8064,
596 + .suspend = suspend_ipq8064,
597 + .resume = resume_ipq8064,
598 + .set_trip_temp = set_trip_temp_ipq8064,
599 + .set_trip_activate = set_trip_activate_ipq8064,
600 +};
601 +
602 +const struct tsens_data data_ipq8064 = {
603 + .num_sensors = 11,
604 + .ops = &ops_ipq8064,
605 +};
606 --- a/drivers/thermal/qcom/tsens.c
607 +++ b/drivers/thermal/qcom/tsens.c
608 @@ -72,6 +72,9 @@ static const struct of_device_id tsens_t
609 }, {
610 .compatible = "qcom,msm8996-tsens",
611 .data = &data_8996,
612 + }, {
613 + .compatible = "qcom,ipq8064-tsens",
614 + .data = &data_ipq8064,
615 },
616 {}
617 };
618 --- a/drivers/thermal/qcom/tsens.h
619 +++ b/drivers/thermal/qcom/tsens.h
620 @@ -89,6 +89,6 @@ void compute_intercept_slope(struct tsen
621 int init_common(struct tsens_device *);
622 int get_temp_common(struct tsens_device *, int, int *);
623
624 -extern const struct tsens_data data_8916, data_8974, data_8960, data_8996;
625 +extern const struct tsens_data data_8916, data_8974, data_8960, data_8996, data_ipq8064;
626
627 #endif /* __QCOM_TSENS_H__ */