ipq806x: add ipq806x specific tsens driver

Current upstream driver doesnt fully support ipq806x devices
ipq806x has 11 sensors, the upstream one doesn't allow to check
sensors 0-4, only 5-10.

A specific driver for ipq806x has been found in Qualcomm SDK repo.

https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c089e464cd7ce652419a0dc44d7959ce4d24b8a5
https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c23d94b702c4182862e7f5051a2b7d00bb922a29
https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=742f3684b62a6b9f082cb49404b1a92dc0b16bf5
https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/?h=release/endive_preview_cc&id=c0a9b2e2a382c152fa128f5b864c800dd6dfb311

Merging it into LEDE with this commit.

Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
This commit is contained in:
Pavel Kubelun 2017-03-23 17:59:30 +03:00 committed by John Crispin
parent 02fe942337
commit dc32d0a53c
5 changed files with 1449 additions and 110 deletions

View file

@ -78,86 +78,354 @@
};
thermal-zones {
cpu-thermal0 {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&gcc 5>;
coefficients = <1132 0>;
tsens_tz_sensor0 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 0>;
trips {
cpu_alert0: trip0 {
temperature = <75000>;
hysteresis = <2000>;
type = "passive";
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu_crit0: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
cpu-thermal1 {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&gcc 6>;
coefficients = <1132 0>;
tsens_tz_sensor1 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 1>;
trips {
cpu_alert1: trip0 {
temperature = <75000>;
hysteresis = <2000>;
type = "passive";
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu_crit1: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
cpu-thermal2 {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&gcc 7>;
coefficients = <1199 0>;
tsens_tz_sensor2 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 2>;
trips {
cpu_alert2: trip0 {
temperature = <75000>;
hysteresis = <2000>;
type = "passive";
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu_crit2: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
cpu-thermal3 {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&gcc 8>;
coefficients = <1132 0>;
tsens_tz_sensor3 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 3>;
trips {
cpu_alert3: trip0 {
temperature = <75000>;
hysteresis = <2000>;
type = "passive";
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu_crit3: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor4 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 4>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor5 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 5>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor6 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 6>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor7 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 7>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor8 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 8>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor9 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 9>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
tsens_tz_sensor10 {
polling-delay-passive = <0>;
polling-delay = <0>;
thermal-sensors = <&tsens 10>;
trips {
cpu-critical-hi {
temperature = <125>;
hysteresis = <2>;
type = "critical_high";
};
cpu-config-hi {
temperature = <105>;
hysteresis = <2>;
type = "configurable_hi";
};
cpu-config-lo {
temperature = <95>;
hysteresis = <2>;
type = "configurable_lo";
};
cpu-critical-low {
temperature = <0>;
hysteresis = <2>;
type = "critical_low";
};
};
};
@ -273,15 +541,14 @@
qfprom: qfprom@700000 {
compatible = "qcom,qfprom", "syscon";
reg = <0x00700000 0x1000>;
reg = <0x700000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
tsens_calib: calib {
status = "okay";
tsens_calib: calib@400 {
reg = <0x400 0x10>;
};
tsens_backup: backup_calib {
tsens_backup: backup@410 {
reg = <0x410 0x10>;
};
};
@ -620,11 +887,17 @@
gcc: clock-controller@900000 {
compatible = "qcom,gcc-ipq8064";
reg = <0x00900000 0x4000>;
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
nvmem-cell-names = "calib", "calib_backup";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
tsens: thermal-sensor@900000 {
compatible = "qcom,ipq8064-tsens";
reg = <0x900000 0x3680>;
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
nvmem-cell-names = "calib", "calib_backup";
interrupts = <0 178 0>;
#thermal-sensor-cells = <1>;
};

View file

@ -34,7 +34,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
.hw.init = &(struct clk_init_data){
.name = "gsbi1_h_clk",
.ops = &clk_branch_ops,
++ .flags = CLK_IGNORE_UNUSED,
+ .flags = CLK_IGNORE_UNUSED,
},
},
};

View file

@ -0,0 +1,638 @@
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
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
index 292ed89..f4a76f6 100644
--- 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.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 2cc2193..cc07cf4 100644
--- 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
diff --git a/drivers/thermal/qcom/tsens-ipq8064.c b/drivers/thermal/qcom/tsens-ipq8064.c
new file mode 100644
index 0000000..c52888f
--- /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 0xff
+#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 1000
+
+/* 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,
+};
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 3f9fe6a..2d25593 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -72,6 +72,9 @@ static const struct of_device_id tsens_table[] = {
}, {
.compatible = "qcom,msm8996-tsens",
.data = &data_8996,
+ }, {
+ .compatible = "qcom,ipq8064-tsens",
+ .data = &data_ipq8064,
},
{}
};
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 911c197..31279a2 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -89,6 +89,6 @@ void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
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__ */

View file

@ -0,0 +1,474 @@
From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001
From: Rajith Cherian <rajith@codeaurora.org>
Date: Wed, 1 Feb 2017 19:00:26 +0530
Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts
Provide support for adding configurable high and
configurable low trip temperatures. An interrupts is
also triggerred when these trip points are hit. The
interrupts can be activated or deactivated from sysfs.
This functionality is made available only if
CONFIG_THERMAL_WRITABLE_TRIPS is defined.
Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934
Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
---
.../devicetree/bindings/thermal/qcom-tsens.txt | 4 ++
drivers/thermal/of-thermal.c | 63 ++++++++++++++++++----
drivers/thermal/qcom/tsens.c | 43 ++++++++++++---
drivers/thermal/qcom/tsens.h | 11 ++++
drivers/thermal/thermal_core.c | 44 ++++++++++++++-
include/linux/thermal.h | 14 +++++
6 files changed, 162 insertions(+), 17 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
index f4a76f6..7c0a6a7 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
@@ -12,11 +12,15 @@ Required properties:
- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
nvmem cells
+Optional properties:
+- interrupts: Interrupt which gets triggered when threshold is hit
+
Example:
tsens: thermal-sensor@900000 {
compatible = "qcom,msm8916-tsens";
reg = <0x4a8000 0x2000>;
nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
nvmem-cell-names = "caldata", "calsel";
+ interrupts = <0 178 0>;
#thermal-sensor-cells = <1>;
};
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d04ec3b..d83697e 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_temp)
+ if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->get_temp(data->sensor_data, temp);
@@ -106,7 +106,8 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops || !data->ops->set_trips)
+ if (!data->ops || !data->ops->set_trips
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->set_trips(data->sensor_data, low, high);
@@ -192,6 +193,9 @@ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
{
struct __thermal_zone *data = tz->devdata;
+ if (data->mode == THERMAL_DEVICE_DISABLED)
+ return -EINVAL;
+
return data->ops->set_emul_temp(data->sensor_data, temp);
}
@@ -200,7 +204,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (!data->ops->get_trend)
+ if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED))
return -EINVAL;
return data->ops->get_trend(data->sensor_data, trip, trend);
@@ -286,7 +290,9 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
mutex_unlock(&tz->lock);
data->mode = mode;
- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+ if (mode == THERMAL_DEVICE_ENABLED)
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
return 0;
}
@@ -296,7 +302,8 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*type = data->trips[trip].type;
@@ -304,12 +311,39 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
return 0;
}
+static int of_thermal_activate_trip_type(struct thermal_zone_device *tz,
+ int trip, enum thermal_trip_activation_mode mode)
+{
+ struct __thermal_zone *data = tz->devdata;
+
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
+ return -EDOM;
+
+ /*
+ * The configurable_hi and configurable_lo trip points can be
+ * activated and deactivated.
+ */
+
+ if (data->ops->set_trip_activate) {
+ int ret;
+
+ ret = data->ops->set_trip_activate(data->sensor_data,
+ trip, mode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
int *temp)
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*temp = data->trips[trip].temperature;
@@ -322,7 +356,8 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
if (data->ops->set_trip_temp) {
@@ -344,7 +379,8 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
*hyst = data->trips[trip].hysteresis;
@@ -357,7 +393,8 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
{
struct __thermal_zone *data = tz->devdata;
- if (trip >= data->ntrips || trip < 0)
+ if (trip >= data->ntrips || trip < 0
+ || (data->mode == THERMAL_DEVICE_DISABLED))
return -EDOM;
/* thermal framework should take care of data->mask & (1 << trip) */
@@ -432,6 +469,9 @@ thermal_zone_of_add_sensor(struct device_node *zone,
if (ops->set_emul_temp)
tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+ if (ops->set_trip_activate)
+ tzd->ops->set_trip_activate = of_thermal_activate_trip_type;
+
mutex_unlock(&tzd->lock);
return tzd;
@@ -726,7 +766,10 @@ static const char * const trip_types[] = {
[THERMAL_TRIP_ACTIVE] = "active",
[THERMAL_TRIP_PASSIVE] = "passive",
[THERMAL_TRIP_HOT] = "hot",
- [THERMAL_TRIP_CRITICAL] = "critical",
+ [THERMAL_TRIP_CRITICAL] = "critical_high",
+ [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi",
+ [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo",
+ [THERMAL_TRIP_CRITICAL_LOW] = "critical_low",
};
/**
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 2d25593..ac68af3 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, int *temp)
static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
{
- const struct tsens_sensor *s = p;
+ struct tsens_sensor *s = p;
struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops->get_trend)
@@ -40,9 +40,10 @@ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
return -ENOTSUPP;
}
-static int __maybe_unused tsens_suspend(struct device *dev)
+static int __maybe_unused tsens_suspend(void *data)
{
- struct tsens_device *tmdev = dev_get_drvdata(dev);
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops && tmdev->ops->suspend)
return tmdev->ops->suspend(tmdev);
@@ -50,9 +51,10 @@ static int __maybe_unused tsens_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tsens_resume(struct device *dev)
+static int __maybe_unused tsens_resume(void *data)
{
- struct tsens_device *tmdev = dev_get_drvdata(dev);
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
if (tmdev->ops && tmdev->ops->resume)
return tmdev->ops->resume(tmdev);
@@ -60,6 +62,30 @@ static int __maybe_unused tsens_resume(struct device *dev)
return 0;
}
+static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp)
+{
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
+
+ if (tmdev->ops && tmdev->ops->set_trip_temp)
+ return tmdev->ops->set_trip_temp(s, trip, temp);
+
+ return 0;
+}
+
+static int __maybe_unused tsens_activate_trip_type(void *data, int trip,
+ enum thermal_trip_activation_mode mode)
+{
+ struct tsens_sensor *s = data;
+ struct tsens_device *tmdev = s->tmdev;
+
+ if (tmdev->ops && tmdev->ops->set_trip_activate)
+ return tmdev->ops->set_trip_activate(s, trip, mode);
+
+ return 0;
+}
+
+
static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
static const struct of_device_id tsens_table[] = {
@@ -83,6 +109,8 @@ MODULE_DEVICE_TABLE(of, tsens_table);
static const struct thermal_zone_of_device_ops tsens_of_ops = {
.get_temp = tsens_get_temp,
.get_trend = tsens_get_trend,
+ .set_trip_temp = tsens_set_trip_temp,
+ .set_trip_activate = tsens_activate_trip_type,
};
static int tsens_register(struct tsens_device *tmdev)
@@ -131,7 +159,7 @@ static int tsens_probe(struct platform_device *pdev)
if (id)
data = id->data;
else
- data = &data_8960;
+ return -EINVAL;
if (data->num_sensors <= 0) {
dev_err(dev, "invalid number of sensors\n");
@@ -146,6 +174,9 @@ static int tsens_probe(struct platform_device *pdev)
tmdev->dev = dev;
tmdev->num_sensors = data->num_sensors;
tmdev->ops = data->ops;
+
+ tmdev->tsens_irq = platform_get_irq(pdev, 0);
+
for (i = 0; i < tmdev->num_sensors; i++) {
if (data->hw_ids)
tmdev->sensor[i].hw_id = data->hw_ids[i];
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
index 31279a2..54bbdc0 100644
--- a/drivers/thermal/qcom/tsens.h
+++ b/drivers/thermal/qcom/tsens.h
@@ -24,9 +24,12 @@ struct tsens_device;
struct tsens_sensor {
struct tsens_device *tmdev;
struct thermal_zone_device *tzd;
+ struct work_struct notify_work;
int offset;
int id;
int hw_id;
+ int calib_data;
+ int calib_data_backup;
int slope;
u32 status;
};
@@ -41,6 +44,9 @@ struct tsens_sensor {
* @suspend: Function to suspend the tsens device
* @resume: Function to resume the tsens device
* @get_trend: Function to get the thermal/temp trend
+ * @set_trip_temp: Function to set trip temp
+ * @get_trip_temp: Function to get trip temp
+ * @set_trip_activate: Function to activate trip points
*/
struct tsens_ops {
/* mandatory callbacks */
@@ -53,6 +59,9 @@ struct tsens_ops {
int (*suspend)(struct tsens_device *);
int (*resume)(struct tsens_device *);
int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
+ int (*set_trip_temp)(void *, int, int);
+ int (*set_trip_activate)(void *, int,
+ enum thermal_trip_activation_mode);
};
/**
@@ -76,11 +85,13 @@ struct tsens_context {
struct tsens_device {
struct device *dev;
u32 num_sensors;
+ u32 tsens_irq;
struct regmap *map;
struct regmap_field *status_field;
struct tsens_context ctx;
bool trdy;
const struct tsens_ops *ops;
+ struct work_struct tsens_work;
struct tsens_sensor sensor[0];
};
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 226b0b4..20bd624 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -732,12 +732,48 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "passive\n");
case THERMAL_TRIP_ACTIVE:
return sprintf(buf, "active\n");
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ return sprintf(buf, "configurable_hi\n");
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ return sprintf(buf, "configurable_low\n");
+ case THERMAL_TRIP_CRITICAL_LOW:
+ return sprintf(buf, "critical_low\n");
default:
return sprintf(buf, "unknown\n");
}
}
static ssize_t
+trip_point_type_activate(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+ char *enabled = "enabled";
+ char *disabled = "disabled";
+
+ if (!tz->ops->set_trip_activate)
+ return -EPERM;
+
+ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+ return -EINVAL;
+
+ if (!strncmp(buf, enabled, strlen(enabled)))
+ ret = tz->ops->set_trip_activate(tz, trip,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ else if (!strncmp(buf, disabled, strlen(disabled)))
+ ret = tz->ops->set_trip_activate(tz, trip,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ else
+ ret = -EINVAL;
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t
trip_point_temp_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -1321,7 +1357,7 @@ thermal_cooling_device_weight_store(struct device *dev,
*/
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip,
- struct thermal_cooling_device *cdev,
+ struct thermal_cooling_device *cdev,
unsigned long upper, unsigned long lower,
unsigned int weight)
{
@@ -1772,6 +1808,12 @@ static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
+ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) {
+ tz->trip_type_attrs[indx].attr.store
+ = trip_point_type_activate;
+ tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR;
+ }
+
device_create_file(&tz->device,
&tz->trip_type_attrs[indx].attr);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 511182a..510a087 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -77,11 +77,19 @@ enum thermal_device_mode {
THERMAL_DEVICE_ENABLED,
};
+enum thermal_trip_activation_mode {
+ THERMAL_TRIP_ACTIVATION_DISABLED = 0,
+ THERMAL_TRIP_ACTIVATION_ENABLED,
+};
+
enum thermal_trip_type {
THERMAL_TRIP_ACTIVE = 0,
THERMAL_TRIP_PASSIVE,
THERMAL_TRIP_HOT,
THERMAL_TRIP_CRITICAL,
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_TRIP_CRITICAL_LOW,
};
enum thermal_trend {
@@ -118,6 +126,8 @@ struct thermal_zone_device_ops {
enum thermal_trip_type *);
int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
int (*set_trip_temp) (struct thermal_zone_device *, int, int);
+ int (*set_trip_activate) (struct thermal_zone_device *, int,
+ enum thermal_trip_activation_mode);
int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
int (*get_crit_temp) (struct thermal_zone_device *, int *);
@@ -360,6 +370,8 @@ struct thermal_genl_event {
* temperature.
* @set_trip_temp: a pointer to a function that sets the trip temperature on
* hardware.
+ * @activate_trip_type: a pointer to a function to enable/disable trip
+ * temperature interrupts
*/
struct thermal_zone_of_device_ops {
int (*get_temp)(void *, int *);
@@ -367,6 +379,8 @@ struct thermal_zone_of_device_ops {
int (*set_trips)(void *, int, int);
int (*set_emul_temp)(void *, int);
int (*set_trip_temp)(void *, int, int);
+ int (*set_trip_activate)(void *, int,
+ enum thermal_trip_activation_mode);
};
/**

View file

@ -1,46 +0,0 @@
From 3064376aa3e8dae03dc2c5c3c064e2283c4337d8 Mon Sep 17 00:00:00 2001
From: Pavel Kubelun <be.dissent@gmail.com>
Date: Tue, 22 Nov 2016 17:37:56 +0300
Subject: [PATCH 63/69] ipq806x: clk: gcc: add tsens child node
Thermal sensors in ipq806x are inside a Global clock controller.
Add a child node into it to be used by the TSENS driver.
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
---
drivers/clk/qcom/gcc-ipq806x.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -970,7 +970,7 @@ static struct clk_branch gsbi1_h_clk = {
.hw.init = &(struct clk_init_data){
.name = "gsbi1_h_clk",
.ops = &clk_branch_ops,
-+ .flags = CLK_IGNORE_UNUSED,
+ .flags = CLK_IGNORE_UNUSED,
},
},
};
@@ -3073,6 +3073,7 @@ MODULE_DEVICE_TABLE(of, gcc_ipq806x_matc
static int gcc_ipq806x_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct platform_device *tsens;
struct regmap *regmap;
int ret;
@@ -3102,6 +3103,13 @@ static int gcc_ipq806x_probe(struct plat
regmap_write(regmap, 0x3cf8, 8);
regmap_write(regmap, 0x3d18, 8);
+ tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
+ NULL, 0);
+ if (IS_ERR(tsens))
+ return PTR_ERR(tsens);
+
+ platform_set_drvdata(pdev, tsens);
+
return 0;
}