OpenWrt – Rev 4

Subversion Repositories:
Rev:
From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001
From: Rajith Cherian <rajith@codeaurora.org>
Date: Tue, 14 Feb 2017 18:30:43 +0530
Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064

Add TSENS driver template to support IPQ8064.
This is a base file copied from tsens-8960.c

Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7
Signed-off-by: Rajith Cherian <rajith@codeaurora.org>

ipq8064: tsens: TSENS driver support for IPQ8064

Support for IPQ8064 tsens driver. The driver works
with the thermal framework. The driver overrides the
following fucntionalities:

1. Get current temperature.
2. Get/Set trip temperatures.
3. Enabled/Disable trip points.
4. ISR for threshold generated interrupt.
5. Notify userspace when trip points are hit.

Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918
Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
---
 .../devicetree/bindings/thermal/qcom-tsens.txt     |   1 +
 drivers/thermal/qcom/Makefile                      |   3 +-
 drivers/thermal/qcom/tsens-ipq8064.c               | 551 +++++++++++++++++++++
 drivers/thermal/qcom/tsens.c                       |   3 +
 drivers/thermal/qcom/tsens.h                       |   2 +-
 5 files changed, 558 insertions(+), 2 deletions(-)
 create mode 100644 drivers/thermal/qcom/tsens-ipq8064.c

--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
@@ -5,6 +5,7 @@ Required properties:
  - "qcom,msm8916-tsens" : For 8916 Family of SoCs
  - "qcom,msm8974-tsens" : For 8974 Family of SoCs
  - "qcom,msm8996-tsens" : For 8996 Family of SoCs
+ - "qcom,ipq8064-tsens" : For IPQ8064
 
 - reg: Address range of the thermal registers
 - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_QCOM_TSENS)       += qcom_tsens.o
-qcom_tsens-y                   += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o
+qcom_tsens-y                   += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o \
+                               tsens-ipq8064.o
--- /dev/null
+++ b/drivers/thermal/qcom/tsens-ipq8064.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include "tsens.h"
+
+#define CAL_MDEGC              30000
+
+#define CONFIG_ADDR            0x3640
+/* CONFIG_ADDR bitmasks */
+#define CONFIG                 0x9b
+#define CONFIG_MASK            0xf
+#define CONFIG_SHIFT           0
+
+#define STATUS_CNTL_8064       0x3660
+#define CNTL_ADDR              0x3620
+/* CNTL_ADDR bitmasks */
+#define EN                     BIT(0)
+#define SW_RST                 BIT(1)
+#define SENSOR0_EN             BIT(3)
+#define SLP_CLK_ENA            BIT(26)
+#define MEASURE_PERIOD         1
+#define SENSOR0_SHIFT          3
+
+/* INT_STATUS_ADDR bitmasks */
+#define MIN_STATUS_MASK                BIT(0)
+#define LOWER_STATUS_CLR       BIT(1)
+#define UPPER_STATUS_CLR       BIT(2)
+#define MAX_STATUS_MASK                BIT(3)
+
+#define THRESHOLD_ADDR         0x3624
+/* THRESHOLD_ADDR bitmasks */
+#define THRESHOLD_MAX_CODE             0x20000
+#define THRESHOLD_MIN_CODE             0
+#define THRESHOLD_MAX_LIMIT_SHIFT      24
+#define THRESHOLD_MIN_LIMIT_SHIFT      16
+#define THRESHOLD_UPPER_LIMIT_SHIFT    8
+#define THRESHOLD_LOWER_LIMIT_SHIFT    0
+#define THRESHOLD_MAX_LIMIT_MASK       (THRESHOLD_MAX_CODE << \
+                                               THRESHOLD_MAX_LIMIT_SHIFT)
+#define THRESHOLD_MIN_LIMIT_MASK       (THRESHOLD_MAX_CODE << \
+                                               THRESHOLD_MIN_LIMIT_SHIFT)
+#define THRESHOLD_UPPER_LIMIT_MASK     (THRESHOLD_MAX_CODE << \
+                                               THRESHOLD_UPPER_LIMIT_SHIFT)
+#define THRESHOLD_LOWER_LIMIT_MASK     (THRESHOLD_MAX_CODE << \
+                                               THRESHOLD_LOWER_LIMIT_SHIFT)
+
+/* Initial temperature threshold values */
+#define LOWER_LIMIT_TH         0x9d /* 95C */
+#define UPPER_LIMIT_TH         0xa6 /* 105C */
+#define MIN_LIMIT_TH           0x0
+#define MAX_LIMIT_TH           0xff
+
+#define S0_STATUS_ADDR         0x3628
+#define STATUS_ADDR_OFFSET     2
+#define SENSOR_STATUS_SIZE     4
+#define INT_STATUS_ADDR                0x363c
+#define TRDY_MASK              BIT(7)
+#define TIMEOUT_US             100
+
+#define TSENS_EN               BIT(0)
+#define TSENS_SW_RST           BIT(1)
+#define TSENS_ADC_CLK_SEL      BIT(2)
+#define SENSOR0_EN             BIT(3)
+#define SENSOR1_EN             BIT(4)
+#define SENSOR2_EN             BIT(5)
+#define SENSOR3_EN             BIT(6)
+#define SENSOR4_EN             BIT(7)
+#define SENSORS_EN             (SENSOR0_EN | SENSOR1_EN | \
+                               SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
+#define TSENS_8064_SENSOR5_EN                          BIT(8)
+#define TSENS_8064_SENSOR6_EN                          BIT(9)
+#define TSENS_8064_SENSOR7_EN                          BIT(10)
+#define TSENS_8064_SENSOR8_EN                          BIT(11)
+#define TSENS_8064_SENSOR9_EN                          BIT(12)
+#define TSENS_8064_SENSOR10_EN                         BIT(13)
+#define TSENS_8064_SENSORS_EN                          (SENSORS_EN | \
+                                               TSENS_8064_SENSOR5_EN | \
+                                               TSENS_8064_SENSOR6_EN | \
+                                               TSENS_8064_SENSOR7_EN | \
+                                               TSENS_8064_SENSOR8_EN | \
+                                               TSENS_8064_SENSOR9_EN | \
+                                               TSENS_8064_SENSOR10_EN)
+
+#define TSENS_8064_SEQ_SENSORS 5
+#define TSENS_8064_S4_S5_OFFSET        40
+#define TSENS_FACTOR           1
+
+/* Trips: from very hot to very cold */
+enum tsens_trip_type {
+       TSENS_TRIP_STAGE3 = 0,
+       TSENS_TRIP_STAGE2,
+       TSENS_TRIP_STAGE1,
+       TSENS_TRIP_STAGE0,
+       TSENS_TRIP_NUM,
+};
+
+u32 tsens_8064_slope[] = {
+                       1176, 1176, 1154, 1176,
+                       1111, 1132, 1132, 1199,
+                       1132, 1199, 1132
+                       };
+
+/* Temperature on y axis and ADC-code on x-axis */
+static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s)
+{
+       int degcbeforefactor, degc;
+
+       degcbeforefactor = (adc_code * s->slope) + s->offset;
+
+       if (degcbeforefactor == 0)
+               degc = degcbeforefactor;
+       else if (degcbeforefactor > 0)
+               degc = (degcbeforefactor + TSENS_FACTOR/2)
+                       / TSENS_FACTOR;
+       else
+               degc = (degcbeforefactor - TSENS_FACTOR/2)
+                       / TSENS_FACTOR;
+
+       return degc;
+}
+
+static int degC_to_code(int degC, const struct tsens_sensor *s)
+{
+       int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2))
+                       / s->slope;
+
+       if (code > THRESHOLD_MAX_CODE)
+               code = THRESHOLD_MAX_CODE;
+       else if (code < THRESHOLD_MIN_CODE)
+               code = THRESHOLD_MIN_CODE;
+       return code;
+}
+
+static int suspend_ipq8064(struct tsens_device *tmdev)
+{
+       int ret;
+       unsigned int mask;
+       struct regmap *map = tmdev->map;
+
+       ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
+       if (ret)
+               return ret;
+
+       mask = SLP_CLK_ENA | EN;
+
+       ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int resume_ipq8064(struct tsens_device *tmdev)
+{
+       int ret;
+       struct regmap *map = tmdev->map;
+
+       ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void notify_uspace_tsens_fn(struct work_struct *work)
+{
+       struct tsens_sensor *s = container_of(work, struct tsens_sensor,
+                                                               notify_work);
+
+       sysfs_notify(&s->tzd->device.kobj, NULL, "type");
+}
+
+static void tsens_scheduler_fn(struct work_struct *work)
+{
+       struct tsens_device *tmdev = container_of(work, struct tsens_device,
+                                       tsens_work);
+       unsigned int threshold, threshold_low, code, reg, sensor, mask;
+       unsigned int sensor_addr;
+       bool upper_th_x, lower_th_x;
+       int adc_code, ret;
+
+       ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
+       if (ret)
+               return;
+       reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
+       ret = regmap_write(tmdev->map, STATUS_CNTL_8064, reg);
+       if (ret)
+               return;
+
+       mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
+       ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &threshold);
+       if (ret)
+               return;
+       threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK)
+                               >> THRESHOLD_LOWER_LIMIT_SHIFT;
+       threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK)
+                               >> THRESHOLD_UPPER_LIMIT_SHIFT;
+
+       ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
+       if (ret)
+               return;
+
+       ret = regmap_read(tmdev->map, CNTL_ADDR, &sensor);
+       if (ret)
+               return;
+       sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
+       sensor >>= SENSOR0_SHIFT;
+
+       /* Constraint: There is only 1 interrupt control register for all
+        * 11 temperature sensor. So monitoring more than 1 sensor based
+        * on interrupts will yield inconsistent result. To overcome this
+        * issue we will monitor only sensor 0 which is the master sensor.
+        */
+
+       /* Skip if the sensor is disabled */
+       if (sensor & 1) {
+               ret = regmap_read(tmdev->map, tmdev->sensor[0].status, &code);
+               if (ret)
+                       return;
+               upper_th_x = code >= threshold;
+               lower_th_x = code <= threshold_low;
+               if (upper_th_x)
+                       mask |= UPPER_STATUS_CLR;
+               if (lower_th_x)
+                       mask |= LOWER_STATUS_CLR;
+               if (upper_th_x || lower_th_x) {
+                       /* Notify user space */
+                       schedule_work(&tmdev->sensor[0].notify_work);
+                       regmap_read(tmdev->map, sensor_addr, &adc_code);
+                       pr_debug("Trigger (%d degrees) for sensor %d\n",
+                               code_to_degC(adc_code, &tmdev->sensor[0]), 0);
+               }
+       }
+       regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask);
+
+       /* force memory to sync */
+       mb();
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+       struct tsens_device *tmdev = data;
+
+       schedule_work(&tmdev->tsens_work);
+       return IRQ_HANDLED;
+}
+
+static void hw_init(struct tsens_device *tmdev)
+{
+       int ret;
+       unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
+       unsigned int reg_status_cntl = 0;
+
+       regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
+       regmap_write(tmdev->map, CNTL_ADDR, reg_cntl | TSENS_SW_RST);
+
+       reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18)
+               | (((1 << tmdev->num_sensors) - 1) << SENSOR0_SHIFT);
+       regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+       regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_status_cntl);
+       reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR
+                       | MIN_STATUS_MASK | MAX_STATUS_MASK;
+       regmap_write(tmdev->map, STATUS_CNTL_8064, reg_status_cntl);
+       reg_cntl |= TSENS_EN;
+       regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+
+       regmap_read(tmdev->map, CONFIG_ADDR, &reg_cfg);
+       reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT);
+       regmap_write(tmdev->map, CONFIG_ADDR, reg_cfg);
+
+       reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT)
+               | (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT)
+               | (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT)
+               | (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT);
+
+       regmap_write(tmdev->map, THRESHOLD_ADDR, reg_thr);
+
+       ret = devm_request_irq(tmdev->dev, tmdev->tsens_irq, tsens_isr,
+                       IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
+       if (ret < 0) {
+               pr_err("%s: request_irq FAIL: %d\n", __func__, ret);
+               return;
+       }
+
+       INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
+}
+
+static int init_ipq8064(struct tsens_device *tmdev)
+{
+       int ret, i;
+       u32 reg_cntl, offset = 0;
+
+       init_common(tmdev);
+       if (!tmdev->map)
+               return -ENODEV;
+
+       /*
+        * The status registers for each sensor are discontiguous
+        * because some SoCs have 5 sensors while others have more
+        * but the control registers stay in the same place, i.e
+        * directly after the first 5 status registers.
+        */
+       for (i = 0; i < tmdev->num_sensors; i++) {
+               if (i >= TSENS_8064_SEQ_SENSORS)
+                       offset = TSENS_8064_S4_S5_OFFSET;
+
+               tmdev->sensor[i].status = S0_STATUS_ADDR + offset
+                                       + (i << STATUS_ADDR_OFFSET);
+               tmdev->sensor[i].slope = tsens_8064_slope[i];
+               INIT_WORK(&tmdev->sensor[i].notify_work,
+                                               notify_uspace_tsens_fn);
+       }
+
+       reg_cntl = SW_RST;
+       ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
+       if (ret)
+               return ret;
+
+       reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
+       reg_cntl &= ~SW_RST;
+       ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
+                                        CONFIG_MASK, CONFIG);
+
+       reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
+       ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+       if (ret)
+               return ret;
+
+       reg_cntl |= EN;
+       ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int calibrate_ipq8064(struct tsens_device *tmdev)
+{
+       int i;
+       char *data, *data_backup;
+
+       ssize_t num_read = tmdev->num_sensors;
+       struct tsens_sensor *s = tmdev->sensor;
+
+       data = qfprom_read(tmdev->dev, "calib");
+       if (IS_ERR(data)) {
+               pr_err("Calibration not found.\n");
+               return PTR_ERR(data);
+       }
+
+       data_backup = qfprom_read(tmdev->dev, "calib_backup");
+       if (IS_ERR(data_backup)) {
+               pr_err("Backup calibration not found.\n");
+               return PTR_ERR(data_backup);
+       }
+
+       for (i = 0; i < num_read; i++) {
+               s[i].calib_data = readb_relaxed(data + i);
+               s[i].calib_data_backup = readb_relaxed(data_backup + i);
+
+               if (s[i].calib_data_backup)
+                       s[i].calib_data = s[i].calib_data_backup;
+               if (!s[i].calib_data) {
+                       pr_err("QFPROM TSENS calibration data not present\n");
+                       return -ENODEV;
+               }
+               s[i].slope = tsens_8064_slope[i];
+               s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope);
+       }
+
+       hw_init(tmdev);
+
+       return 0;
+}
+
+static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp)
+{
+       int ret;
+       u32 code, trdy;
+       const struct tsens_sensor *s = &tmdev->sensor[id];
+       unsigned long timeout;
+
+       timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+       do {
+               ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
+               if (ret)
+                       return ret;
+               if (!(trdy & TRDY_MASK))
+                       continue;
+               ret = regmap_read(tmdev->map, s->status, &code);
+               if (ret)
+                       return ret;
+               *temp = code_to_degC(code, s);
+               return 0;
+       } while (time_before(jiffies, timeout));
+
+       return -ETIMEDOUT;
+}
+
+static int set_trip_temp_ipq8064(void *data, int trip, int temp)
+{
+       unsigned int reg_th, reg_cntl;
+       int ret, code, code_chk, hi_code, lo_code;
+       const struct tsens_sensor *s = data;
+       struct tsens_device *tmdev = s->tmdev;
+
+       code_chk = code = degC_to_code(temp, s);
+
+       if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE)
+               return -EINVAL;
+
+       ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &reg_th);
+       if (ret)
+               return ret;
+
+       hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK)
+                       >> THRESHOLD_UPPER_LIMIT_SHIFT;
+       lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK)
+                       >> THRESHOLD_LOWER_LIMIT_SHIFT;
+
+       switch (trip) {
+       case TSENS_TRIP_STAGE3:
+               code <<= THRESHOLD_MAX_LIMIT_SHIFT;
+               reg_th &= ~THRESHOLD_MAX_LIMIT_MASK;
+               break;
+       case TSENS_TRIP_STAGE2:
+               if (code_chk <= lo_code)
+                       return -EINVAL;
+               code <<= THRESHOLD_UPPER_LIMIT_SHIFT;
+               reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK;
+               break;
+       case TSENS_TRIP_STAGE1:
+               if (code_chk >= hi_code)
+                       return -EINVAL;
+               code <<= THRESHOLD_LOWER_LIMIT_SHIFT;
+               reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK;
+               break;
+       case TSENS_TRIP_STAGE0:
+               code <<= THRESHOLD_MIN_LIMIT_SHIFT;
+               reg_th &= ~THRESHOLD_MIN_LIMIT_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_write(tmdev->map, THRESHOLD_ADDR, reg_th | code);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int set_trip_activate_ipq8064(void *data, int trip,
+                                       enum thermal_trip_activation_mode mode)
+{
+       unsigned int reg_cntl, mask, val;
+       const struct tsens_sensor *s = data;
+       struct tsens_device *tmdev = s->tmdev;
+       int ret;
+
+       if (!tmdev || trip < 0)
+               return -EINVAL;
+
+       ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
+       if (ret)
+               return ret;
+
+       switch (trip) {
+       case TSENS_TRIP_STAGE3:
+               mask = MAX_STATUS_MASK;
+               break;
+       case TSENS_TRIP_STAGE2:
+               mask = UPPER_STATUS_CLR;
+               break;
+       case TSENS_TRIP_STAGE1:
+               mask = LOWER_STATUS_CLR;
+               break;
+       case TSENS_TRIP_STAGE0:
+               mask = MIN_STATUS_MASK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
+               val = reg_cntl | mask;
+       else
+               val = reg_cntl & ~mask;
+
+       ret = regmap_write(tmdev->map, STATUS_CNTL_8064, val);
+       if (ret)
+               return ret;
+
+       /* force memory to sync */
+       mb();
+       return 0;
+}
+
+const struct tsens_ops ops_ipq8064 = {
+       .init           = init_ipq8064,
+       .calibrate      = calibrate_ipq8064,
+       .get_temp       = get_temp_ipq8064,
+       .suspend        = suspend_ipq8064,
+       .resume         = resume_ipq8064,
+       .set_trip_temp  = set_trip_temp_ipq8064,
+       .set_trip_activate = set_trip_activate_ipq8064,
+};
+
+const struct tsens_data data_ipq8064 = {
+       .num_sensors    = 11,
+       .ops            = &ops_ipq8064,
+};
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -72,6 +72,9 @@ static const struct of_device_id tsens_t
        }, {
                .compatible = "qcom,msm8996-tsens",
                .data = &data_8996,
+       }, {
+               .compatible = "qcom,ipq8064-tsens",
+               .data = &data_ipq8064,
        },
        {}
 };
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -89,6 +89,6 @@ void compute_intercept_slope(struct tsen
 int init_common(struct tsens_device *);
 int get_temp_common(struct tsens_device *, int, int *);
 
-extern const struct tsens_data data_8916, data_8974, data_8960, data_8996;
+extern const struct tsens_data data_8916, data_8974, data_8960, data_8996, data_ipq8064;
 
 #endif /* __QCOM_TSENS_H__ */