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