ipq806x: use newer tsens patch
Use improved tsens patch proposed upstream. Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
This commit is contained in:
parent
d53be2a2e9
commit
96f10c9d7a
14 changed files with 973 additions and 1228 deletions
|
@ -1,616 +0,0 @@
|
||||||
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>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/thermal/qcom/Makefile
|
|
||||||
+++ b/drivers/thermal/qcom/Makefile
|
|
||||||
@@ -2,5 +2,5 @@
|
|
||||||
obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o
|
|
||||||
|
|
||||||
qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \
|
|
||||||
- tsens-8960.o tsens-v2.o tsens-v1.o
|
|
||||||
+ tsens-8960.o tsens-v2.o tsens-v1.o tsens-ipq8064.o
|
|
||||||
obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.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_priv *priv)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+ unsigned int mask;
|
|
||||||
+ struct regmap *map = priv->tm_map;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(map, CNTL_ADDR, &priv->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_priv *priv)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+ struct regmap *map = priv->tm_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, priv->ctx.threshold);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_write(map, CNTL_ADDR, priv->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_priv *priv = container_of(work, struct tsens_priv,
|
|
||||||
+ 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(priv->tm_map, STATUS_CNTL_8064, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return;
|
|
||||||
+ reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
|
|
||||||
+ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, reg);
|
|
||||||
+ if (ret)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
|
|
||||||
+ ret = regmap_read(priv->tm_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(priv->tm_map, STATUS_CNTL_8064, ®);
|
|
||||||
+ if (ret)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(priv->tm_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(priv->tm_map, priv->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(&priv->sensor[0].notify_work);
|
|
||||||
+ regmap_read(priv->tm_map, sensor_addr, &adc_code);
|
|
||||||
+ pr_debug("Trigger (%d degrees) for sensor %d\n",
|
|
||||||
+ code_to_degC(adc_code, &priv->sensor[0]), 0);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask);
|
|
||||||
+
|
|
||||||
+ /* force memory to sync */
|
|
||||||
+ mb();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static irqreturn_t tsens_isr(int irq, void *data)
|
|
||||||
+{
|
|
||||||
+ struct tsens_priv *priv = data;
|
|
||||||
+
|
|
||||||
+ schedule_work(&priv->tsens_work);
|
|
||||||
+ return IRQ_HANDLED;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void hw_init(struct tsens_priv *priv)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+ unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
|
|
||||||
+ unsigned int reg_status_cntl = 0;
|
|
||||||
+
|
|
||||||
+ regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl);
|
|
||||||
+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl | TSENS_SW_RST);
|
|
||||||
+
|
|
||||||
+ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18)
|
|
||||||
+ | (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT);
|
|
||||||
+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
|
||||||
+ regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_status_cntl);
|
|
||||||
+ reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR
|
|
||||||
+ | MIN_STATUS_MASK | MAX_STATUS_MASK;
|
|
||||||
+ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg_status_cntl);
|
|
||||||
+ reg_cntl |= TSENS_EN;
|
|
||||||
+ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
|
||||||
+
|
|
||||||
+ regmap_read(priv->tm_map, CONFIG_ADDR, ®_cfg);
|
|
||||||
+ reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT);
|
|
||||||
+ regmap_write(priv->tm_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(priv->tm_map, THRESHOLD_ADDR, reg_thr);
|
|
||||||
+
|
|
||||||
+ ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr,
|
|
||||||
+ IRQF_TRIGGER_RISING, "tsens_interrupt", priv);
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ pr_err("%s: request_irq FAIL: %d\n", __func__, ret);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int init_ipq8064(struct tsens_priv *priv)
|
|
||||||
+{
|
|
||||||
+ int ret, i;
|
|
||||||
+ u32 reg_cntl, offset = 0;
|
|
||||||
+
|
|
||||||
+ init_common(priv);
|
|
||||||
+ if (!priv->tm_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 < priv->num_sensors; i++) {
|
|
||||||
+ if (i >= TSENS_8064_SEQ_SENSORS)
|
|
||||||
+ offset = TSENS_8064_S4_S5_OFFSET;
|
|
||||||
+
|
|
||||||
+ priv->sensor[i].status = S0_STATUS_ADDR + offset
|
|
||||||
+ + (i << STATUS_ADDR_OFFSET);
|
|
||||||
+ priv->sensor[i].slope = tsens_8064_slope[i];
|
|
||||||
+ INIT_WORK(&priv->sensor[i].notify_work,
|
|
||||||
+ notify_uspace_tsens_fn);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ reg_cntl = SW_RST;
|
|
||||||
+ ret = regmap_update_bits(priv->tm_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(priv->tm_map, CONFIG_ADDR,
|
|
||||||
+ CONFIG_MASK, CONFIG);
|
|
||||||
+
|
|
||||||
+ reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
|
|
||||||
+ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ reg_cntl |= EN;
|
|
||||||
+ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int calibrate_ipq8064(struct tsens_priv *priv)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+ char *data, *data_backup;
|
|
||||||
+
|
|
||||||
+ ssize_t num_read = priv->num_sensors;
|
|
||||||
+ struct tsens_sensor *s = priv->sensor;
|
|
||||||
+
|
|
||||||
+ data = qfprom_read(priv->dev, "calib");
|
|
||||||
+ if (IS_ERR(data)) {
|
|
||||||
+ pr_err("Calibration not found.\n");
|
|
||||||
+ return PTR_ERR(data);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ data_backup = qfprom_read(priv->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(priv);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+ u32 code, trdy;
|
|
||||||
+ const struct tsens_sensor *s = &priv->sensor[id];
|
|
||||||
+ unsigned long timeout;
|
|
||||||
+
|
|
||||||
+ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
|
||||||
+ do {
|
|
||||||
+ ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+ if (!(trdy & TRDY_MASK))
|
|
||||||
+ continue;
|
|
||||||
+ ret = regmap_read(priv->tm_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_priv *priv = s->priv;
|
|
||||||
+
|
|
||||||
+ code_chk = code = degC_to_code(temp, s);
|
|
||||||
+
|
|
||||||
+ if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl);
|
|
||||||
+ if (ret)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, ®_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(priv->tm_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_priv *priv = s->priv;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (!priv || trip < 0)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_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(priv->tm_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_plat_data data_ipq8064 = {
|
|
||||||
+ .num_sensors = 11,
|
|
||||||
+ .ops = &ops_ipq8064,
|
|
||||||
+};
|
|
||||||
--- a/drivers/thermal/qcom/tsens.c
|
|
||||||
+++ b/drivers/thermal/qcom/tsens.c
|
|
||||||
@@ -69,8 +69,11 @@ static const struct of_device_id tsens_t
|
|
||||||
}, {
|
|
||||||
.compatible = "qcom,tsens-v2",
|
|
||||||
.data = &data_tsens_v2,
|
|
||||||
+ }, {
|
|
||||||
+ .compatible = "qcom,ipq8064-tsens",
|
|
||||||
+ .data = &data_ipq8064,
|
|
||||||
},
|
|
||||||
- {}
|
|
||||||
+ {}
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, tsens_table);
|
|
||||||
|
|
||||||
--- a/drivers/thermal/qcom/tsens.h
|
|
||||||
+++ b/drivers/thermal/qcom/tsens.h
|
|
||||||
@@ -324,7 +324,7 @@ extern const struct tsens_plat_data data
|
|
||||||
extern const struct tsens_plat_data data_8916, data_8974;
|
|
||||||
|
|
||||||
/* TSENS v1 targets */
|
|
||||||
-extern const struct tsens_plat_data data_tsens_v1;
|
|
||||||
+extern const struct tsens_plat_data data_tsens_v1, data_ipq8064;
|
|
||||||
|
|
||||||
/* TSENS v2 targets */
|
|
||||||
extern const struct tsens_plat_data data_8996, data_tsens_v2;
|
|
|
@ -1,437 +0,0 @@
|
||||||
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(-)
|
|
||||||
|
|
||||||
--- a/drivers/thermal/of-thermal.c
|
|
||||||
+++ b/drivers/thermal/of-thermal.c
|
|
||||||
@@ -91,7 +91,7 @@ static int of_thermal_get_temp(struct th
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
@@ -102,7 +102,8 @@ static int of_thermal_set_trips(struct t
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
@@ -188,6 +189,9 @@ static int of_thermal_set_emul_temp(stru
|
|
||||||
{
|
|
||||||
struct __thermal_zone *data = tz->devdata;
|
|
||||||
|
|
||||||
+ if (data->mode == THERMAL_DEVICE_DISABLED)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
return data->ops->set_emul_temp(data->sensor_data, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -196,7 +200,7 @@ static int of_thermal_get_trend(struct t
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
@@ -297,7 +301,9 @@ static int of_thermal_set_mode(struct th
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -307,7 +313,8 @@ static int of_thermal_get_trip_type(stru
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
@@ -315,12 +322,39 @@ static int of_thermal_get_trip_type(stru
|
|
||||||
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;
|
|
||||||
@@ -333,7 +367,8 @@ static int of_thermal_set_trip_temp(stru
|
|
||||||
{
|
|
||||||
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) {
|
|
||||||
@@ -355,7 +390,8 @@ static int of_thermal_get_trip_hyst(stru
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
@@ -368,7 +404,8 @@ static int of_thermal_set_trip_hyst(stru
|
|
||||||
{
|
|
||||||
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) */
|
|
||||||
@@ -443,6 +480,9 @@ thermal_zone_of_add_sensor(struct device
|
|
||||||
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;
|
|
||||||
@@ -762,7 +802,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",
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
--- a/drivers/thermal/qcom/tsens.c
|
|
||||||
+++ b/drivers/thermal/qcom/tsens.c
|
|
||||||
@@ -22,7 +22,7 @@ static int tsens_get_temp(void *data, in
|
|
||||||
|
|
||||||
static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend)
|
|
||||||
{
|
|
||||||
- const struct tsens_sensor *s = data;
|
|
||||||
+ struct tsens_sensor *s = data;
|
|
||||||
struct tsens_priv *priv = s->priv;
|
|
||||||
|
|
||||||
if (priv->ops->get_trend)
|
|
||||||
@@ -31,9 +31,10 @@ static int tsens_get_trend(void *data, i
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int __maybe_unused tsens_suspend(struct device *dev)
|
|
||||||
+static int __maybe_unused tsens_suspend(void *data)
|
|
||||||
{
|
|
||||||
- struct tsens_priv *priv = dev_get_drvdata(dev);
|
|
||||||
+ struct tsens_sensor *s = data;
|
|
||||||
+ struct tsens_priv *priv = s->priv;
|
|
||||||
|
|
||||||
if (priv->ops && priv->ops->suspend)
|
|
||||||
return priv->ops->suspend(priv);
|
|
||||||
@@ -41,9 +42,10 @@ static int __maybe_unused tsens_suspend
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int __maybe_unused tsens_resume(struct device *dev)
|
|
||||||
+static int __maybe_unused tsens_resume(void *data)
|
|
||||||
{
|
|
||||||
- struct tsens_priv *priv = dev_get_drvdata(dev);
|
|
||||||
+ struct tsens_sensor *s = data;
|
|
||||||
+ struct tsens_priv *priv = s->priv;
|
|
||||||
|
|
||||||
if (priv->ops && priv->ops->resume)
|
|
||||||
return priv->ops->resume(priv);
|
|
||||||
@@ -51,6 +53,30 @@ static int __maybe_unused tsens_resume(s
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp)
|
|
||||||
+{
|
|
||||||
+ struct tsens_sensor *s = data;
|
|
||||||
+ struct tsens_priv *priv = s->priv;
|
|
||||||
+
|
|
||||||
+ if (priv->ops && priv->ops->set_trip_temp)
|
|
||||||
+ return priv->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_priv *priv = s->priv;
|
|
||||||
+
|
|
||||||
+ if (priv->ops && priv->ops->set_trip_activate)
|
|
||||||
+ return priv->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[] = {
|
|
||||||
@@ -80,6 +106,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_priv *priv)
|
|
||||||
@@ -123,7 +151,7 @@ static int tsens_probe(struct platform_d
|
|
||||||
if (id)
|
|
||||||
data = id->data;
|
|
||||||
else
|
|
||||||
- data = &data_8960;
|
|
||||||
+ return -EINVAL;
|
|
||||||
|
|
||||||
num_sensors = data->num_sensors;
|
|
||||||
|
|
||||||
@@ -144,6 +172,9 @@ static int tsens_probe(struct platform_d
|
|
||||||
priv->dev = dev;
|
|
||||||
priv->num_sensors = num_sensors;
|
|
||||||
priv->ops = data->ops;
|
|
||||||
+
|
|
||||||
+ priv->tsens_irq = platform_get_irq(pdev, 0);
|
|
||||||
+
|
|
||||||
for (i = 0; i < priv->num_sensors; i++) {
|
|
||||||
if (data->hw_ids)
|
|
||||||
priv->sensor[i].hw_id = data->hw_ids[i];
|
|
||||||
--- a/drivers/thermal/qcom/tsens.h
|
|
||||||
+++ b/drivers/thermal/qcom/tsens.h
|
|
||||||
@@ -40,9 +40,12 @@ enum tsens_ver {
|
|
||||||
struct tsens_sensor {
|
|
||||||
struct tsens_priv *priv;
|
|
||||||
struct thermal_zone_device *tzd;
|
|
||||||
+ struct work_struct notify_work;
|
|
||||||
int offset;
|
|
||||||
unsigned int id;
|
|
||||||
unsigned int hw_id;
|
|
||||||
+ int calib_data;
|
|
||||||
+ int calib_data_backup;
|
|
||||||
int slope;
|
|
||||||
u32 status;
|
|
||||||
};
|
|
||||||
@@ -57,6 +60,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 */
|
|
||||||
@@ -69,6 +75,9 @@ struct tsens_ops {
|
|
||||||
int (*suspend)(struct tsens_priv *priv);
|
|
||||||
int (*resume)(struct tsens_priv *priv);
|
|
||||||
int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend);
|
|
||||||
+ int (*set_trip_temp)(void *data, int trip, int temp);
|
|
||||||
+ int (*set_trip_activate)(void *data, int trip,
|
|
||||||
+ enum thermal_trip_activation_mode mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
|
|
||||||
@@ -300,6 +309,7 @@ struct tsens_context {
|
|
||||||
struct tsens_priv {
|
|
||||||
struct device *dev;
|
|
||||||
u32 num_sensors;
|
|
||||||
+ u32 tsens_irq;
|
|
||||||
struct regmap *tm_map;
|
|
||||||
struct regmap *srot_map;
|
|
||||||
u32 tm_offset;
|
|
||||||
@@ -308,6 +318,7 @@ struct tsens_priv {
|
|
||||||
const struct tsens_features *feat;
|
|
||||||
const struct reg_field *fields;
|
|
||||||
const struct tsens_ops *ops;
|
|
||||||
+ struct work_struct tsens_work;
|
|
||||||
struct tsens_sensor sensor[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
--- a/drivers/thermal/thermal_sysfs.c
|
|
||||||
+++ b/drivers/thermal/thermal_sysfs.c
|
|
||||||
@@ -113,12 +113,48 @@ trip_point_type_show(struct device *dev,
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
@@ -559,6 +595,12 @@ static int create_trip_attrs(struct ther
|
|
||||||
tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
|
|
||||||
attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
|
|
||||||
|
|
||||||
+ 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;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* create trip temp attribute */
|
|
||||||
snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
|
|
||||||
"trip_point_%d_temp", indx);
|
|
||||||
--- a/include/linux/thermal.h
|
|
||||||
+++ b/include/linux/thermal.h
|
|
||||||
@@ -63,11 +63,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 {
|
|
||||||
@@ -105,6 +113,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 *);
|
|
||||||
@@ -349,6 +359,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 *);
|
|
||||||
@@ -356,6 +368,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);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
|
@ -1,68 +0,0 @@
|
||||||
--- a/drivers/thermal/qcom/tsens-ipq8064.c
|
|
||||||
+++ b/drivers/thermal/qcom/tsens-ipq8064.c
|
|
||||||
@@ -18,6 +18,7 @@
|
|
||||||
#include <linux/regmap.h>
|
|
||||||
#include <linux/thermal.h>
|
|
||||||
#include <linux/nvmem-consumer.h>
|
|
||||||
+#include <linux/of_platform.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include "tsens.h"
|
|
||||||
@@ -320,15 +321,42 @@ static void hw_init(struct tsens_priv *p
|
|
||||||
INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static const struct regmap_config tsens_config = {
|
|
||||||
+ .name = "tm",
|
|
||||||
+ .reg_bits = 32,
|
|
||||||
+ .val_bits = 32,
|
|
||||||
+ .reg_stride = 4,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
static int init_ipq8064(struct tsens_priv *priv)
|
|
||||||
{
|
|
||||||
- int ret, i;
|
|
||||||
+ struct device *dev = priv->dev;
|
|
||||||
u32 reg_cntl, offset = 0;
|
|
||||||
+ struct resource *res;
|
|
||||||
+ resource_size_t size;
|
|
||||||
+ void __iomem *base;
|
|
||||||
+ int ret, i;
|
|
||||||
+ struct platform_device *op = of_find_device_by_node(priv->dev->of_node);
|
|
||||||
+
|
|
||||||
+ if (!op)
|
|
||||||
+ return -EINVAL;
|
|
||||||
|
|
||||||
- init_common(priv);
|
|
||||||
- if (!priv->tm_map)
|
|
||||||
- return -ENODEV;
|
|
||||||
+ /* old DTs where SROT and TM were in a contiguous 2K block */
|
|
||||||
+ priv->tm_offset = 0x1000;
|
|
||||||
|
|
||||||
+ res = platform_get_resource(op, IORESOURCE_MEM, 0);
|
|
||||||
+ size = resource_size(res);
|
|
||||||
+ base = devm_ioremap(&op->dev, res->start, size);
|
|
||||||
+ if (IS_ERR(base)) {
|
|
||||||
+ ret = PTR_ERR(base);
|
|
||||||
+ goto err_put_device;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ priv->tm_map = devm_regmap_init_mmio(dev, base, &tsens_config);
|
|
||||||
+ if (IS_ERR(priv->tm_map)) {
|
|
||||||
+ ret = PTR_ERR(priv->tm_map);
|
|
||||||
+ goto err_put_device;
|
|
||||||
+ }
|
|
||||||
/*
|
|
||||||
* The status registers for each sensor are discontiguous
|
|
||||||
* because some SoCs have 5 sensors while others have more
|
|
||||||
@@ -367,6 +395,10 @@ static int init_ipq8064(struct tsens_pri
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
+
|
|
||||||
+err_put_device:
|
|
||||||
+ put_device(&op->dev);
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calibrate_ipq8064(struct tsens_priv *priv)
|
|
|
@ -1,107 +0,0 @@
|
||||||
--- a/drivers/thermal/qcom/tsens-ipq8064.c
|
|
||||||
+++ b/drivers/thermal/qcom/tsens-ipq8064.c
|
|
||||||
@@ -13,10 +13,12 @@
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
+#include <linux/err.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/regmap.h>
|
|
||||||
#include <linux/thermal.h>
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
#include <linux/nvmem-consumer.h>
|
|
||||||
#include <linux/of_platform.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
@@ -211,9 +213,8 @@ static void tsens_scheduler_fn(struct wo
|
|
||||||
struct tsens_priv *priv = container_of(work, struct tsens_priv,
|
|
||||||
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;
|
|
||||||
+ int ret;
|
|
||||||
|
|
||||||
ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®);
|
|
||||||
if (ret)
|
|
||||||
@@ -262,9 +263,8 @@ static void tsens_scheduler_fn(struct wo
|
|
||||||
if (upper_th_x || lower_th_x) {
|
|
||||||
/* Notify user space */
|
|
||||||
schedule_work(&priv->sensor[0].notify_work);
|
|
||||||
- regmap_read(priv->tm_map, sensor_addr, &adc_code);
|
|
||||||
pr_debug("Trigger (%d degrees) for sensor %d\n",
|
|
||||||
- code_to_degC(adc_code, &priv->sensor[0]), 0);
|
|
||||||
+ code_to_degC(code, &priv->sensor[0]), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask);
|
|
||||||
@@ -404,40 +404,55 @@ err_put_device:
|
|
||||||
static int calibrate_ipq8064(struct tsens_priv *priv)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
- char *data, *data_backup;
|
|
||||||
-
|
|
||||||
+ int ret = 0;
|
|
||||||
+ u8 *data, *data_backup;
|
|
||||||
+ struct device *dev = priv->dev;
|
|
||||||
ssize_t num_read = priv->num_sensors;
|
|
||||||
struct tsens_sensor *s = priv->sensor;
|
|
||||||
|
|
||||||
- data = qfprom_read(priv->dev, "calib");
|
|
||||||
+ data = qfprom_read(dev, "calib");
|
|
||||||
if (IS_ERR(data)) {
|
|
||||||
- pr_err("Calibration not found.\n");
|
|
||||||
- return PTR_ERR(data);
|
|
||||||
+ ret = PTR_ERR(data);
|
|
||||||
+ if (ret != -EPROBE_DEFER)
|
|
||||||
+ dev_err(dev, "Calibration not found.");
|
|
||||||
+ goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
- data_backup = qfprom_read(priv->dev, "calib_backup");
|
|
||||||
+ data_backup = qfprom_read(dev, "calib_backup");
|
|
||||||
if (IS_ERR(data_backup)) {
|
|
||||||
- pr_err("Backup calibration not found.\n");
|
|
||||||
- return PTR_ERR(data_backup);
|
|
||||||
+ ret = PTR_ERR(data_backup);
|
|
||||||
+ if (ret != -EPROBE_DEFER)
|
|
||||||
+ dev_err(dev, "Backup Calibration not found.");
|
|
||||||
+ goto free_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
+ s[i].calib_data_backup = readb_relaxed(data_backup + i);
|
|
||||||
+
|
|
||||||
+ if (!s[i].calib_data_backup) {
|
|
||||||
+ dev_err(dev, "QFPROM TSENS calibration data not present");
|
|
||||||
+ ret = -ENODEV;
|
|
||||||
+ goto free_backup;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- 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(priv);
|
|
||||||
|
|
||||||
- return 0;
|
|
||||||
+free_backup:
|
|
||||||
+ kfree(data_backup);
|
|
||||||
+free_data:
|
|
||||||
+ kfree(data);
|
|
||||||
+exit:
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp)
|
|
|
@ -0,0 +1,292 @@
|
||||||
|
From 5c7d1181056feef0b58fb2f556f55e170ba5b479 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Sat, 25 Jul 2020 19:14:59 +0200
|
||||||
|
Subject: [PATCH 01/10] drivers: thermal: tsens: Add VER_0 tsens version
|
||||||
|
|
||||||
|
VER_0 is used to describe device based on tsens version before v0.1.
|
||||||
|
These device are devices based on msm8960 for example apq8064 or
|
||||||
|
ipq806x.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
Reported-by: kernel test robot <lkp@intel.com>
|
||||||
|
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens.c | 150 ++++++++++++++++++++++++++++-------
|
||||||
|
drivers/thermal/qcom/tsens.h | 4 +-
|
||||||
|
2 files changed, 124 insertions(+), 30 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
|
||||||
|
index d8ce3a687b80..9a7e991d4bd2 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens.c
|
||||||
|
@@ -12,6 +12,7 @@
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
+#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
|
||||||
|
dev_dbg(priv->dev, "[%u] %s: no violation: %d\n",
|
||||||
|
hw_id, __func__, temp);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ if (tsens_version(priv) < VER_0_1) {
|
||||||
|
+ /* 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.
|
||||||
|
+ */
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int high)
|
||||||
|
int high_val, low_val, cl_high, cl_low;
|
||||||
|
u32 hw_id = s->hw_id;
|
||||||
|
|
||||||
|
+ if (tsens_version(priv) < VER_0_1) {
|
||||||
|
+ /* Pre v0.1 IP had a single register for each type of interrupt
|
||||||
|
+ * and thresholds
|
||||||
|
+ */
|
||||||
|
+ hw_id = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
|
||||||
|
hw_id, __func__, low, high);
|
||||||
|
|
||||||
|
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, int *temp)
|
||||||
|
u32 valid;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
- while (!valid) {
|
||||||
|
- /* Valid bit is 0 for 6 AHB clock cycles.
|
||||||
|
- * At 19.2MHz, 1 AHB clock is ~60ns.
|
||||||
|
- * We should enter this loop very, very rarely.
|
||||||
|
- */
|
||||||
|
- ndelay(400);
|
||||||
|
+ /* VER_0 doesn't have VALID bit */
|
||||||
|
+ if (tsens_version(priv) >= VER_0_1) {
|
||||||
|
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
+ while (!valid) {
|
||||||
|
+ /* Valid bit is 0 for 6 AHB clock cycles.
|
||||||
|
+ * At 19.2MHz, 1 AHB clock is ~60ns.
|
||||||
|
+ * We should enter this loop very, very rarely.
|
||||||
|
+ */
|
||||||
|
+ ndelay(400);
|
||||||
|
+ ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Valid bit is set, OK to read the temperature */
|
||||||
|
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int *temp)
|
||||||
|
{
|
||||||
|
struct tsens_priv *priv = s->priv;
|
||||||
|
int hw_id = s->hw_id;
|
||||||
|
- int last_temp = 0, ret;
|
||||||
|
+ int last_temp = 0, ret, trdy;
|
||||||
|
+ unsigned long timeout;
|
||||||
|
|
||||||
|
- ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
+ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
||||||
|
+ do {
|
||||||
|
+ if (tsens_version(priv) == VER_0) {
|
||||||
|
+ ret = regmap_field_read(priv->rf[TRDY], &trdy);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ if (!trdy)
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- *temp = code_to_degc(last_temp, s) * 1000;
|
||||||
|
+ ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
|
||||||
|
- return 0;
|
||||||
|
+ *temp = code_to_degc(last_temp, s) * 1000;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+ } while (time_before(jiffies, timeout));
|
||||||
|
+
|
||||||
|
+ return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv *priv)
|
||||||
|
priv->tm_offset = 0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
- res = platform_get_resource(op, IORESOURCE_MEM, 0);
|
||||||
|
- tm_base = devm_ioremap_resource(dev, res);
|
||||||
|
- if (IS_ERR(tm_base)) {
|
||||||
|
- ret = PTR_ERR(tm_base);
|
||||||
|
- goto err_put_device;
|
||||||
|
+ if (tsens_version(priv) >= VER_0_1) {
|
||||||
|
+ res = platform_get_resource(op, IORESOURCE_MEM, 0);
|
||||||
|
+ tm_base = devm_ioremap_resource(dev, res);
|
||||||
|
+ if (IS_ERR(tm_base)) {
|
||||||
|
+ ret = PTR_ERR(tm_base);
|
||||||
|
+ goto err_put_device;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
|
||||||
|
+ } else { /* VER_0 share the same gcc regs using a syscon */
|
||||||
|
+ struct device *parent = priv->dev->parent;
|
||||||
|
+
|
||||||
|
+ if (parent)
|
||||||
|
+ priv->tm_map = syscon_node_to_regmap(parent->of_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
- priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
|
||||||
|
- if (IS_ERR(priv->tm_map)) {
|
||||||
|
- ret = PTR_ERR(priv->tm_map);
|
||||||
|
+ if (IS_ERR_OR_NULL(priv->tm_map)) {
|
||||||
|
+ if (!priv->tm_map)
|
||||||
|
+ ret = -ENODEV;
|
||||||
|
+ else
|
||||||
|
+ ret = PTR_ERR(priv->tm_map);
|
||||||
|
goto err_put_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* VER_0 have only tm_map */
|
||||||
|
+ if (!priv->srot_map)
|
||||||
|
+ priv->srot_map = priv->tm_map;
|
||||||
|
+
|
||||||
|
if (tsens_version(priv) > VER_0_1) {
|
||||||
|
for (i = VER_MAJOR; i <= VER_STEP; i++) {
|
||||||
|
priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
|
||||||
|
@@ -769,6 +818,10 @@ int __init init_common(struct tsens_priv *priv)
|
||||||
|
ret = PTR_ERR(priv->rf[TSENS_EN]);
|
||||||
|
goto err_put_device;
|
||||||
|
}
|
||||||
|
+ /* in VER_0 TSENS need to be explicitly enabled */
|
||||||
|
+ if (tsens_version(priv) == VER_0)
|
||||||
|
+ regmap_field_write(priv->rf[TSENS_EN], 1);
|
||||||
|
+
|
||||||
|
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
|
||||||
|
if (ret)
|
||||||
|
goto err_put_device;
|
||||||
|
@@ -791,6 +844,19 @@ int __init init_common(struct tsens_priv *priv)
|
||||||
|
goto err_put_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ priv->rf[TSENS_SW_RST] =
|
||||||
|
+ devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
|
||||||
|
+ if (IS_ERR(priv->rf[TSENS_SW_RST])) {
|
||||||
|
+ ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
|
||||||
|
+ goto err_put_device;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
|
||||||
|
+ if (IS_ERR(priv->rf[TRDY])) {
|
||||||
|
+ ret = PTR_ERR(priv->rf[TRDY]);
|
||||||
|
+ goto err_put_device;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* This loop might need changes if enum regfield_ids is reordered */
|
||||||
|
for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
|
||||||
|
for (i = 0; i < priv->feat->max_sensors; i++) {
|
||||||
|
@@ -806,7 +872,7 @@ int __init init_common(struct tsens_priv *priv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (priv->feat->crit_int) {
|
||||||
|
+ if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
|
||||||
|
/* Loop might need changes if enum regfield_ids is reordered */
|
||||||
|
for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
|
||||||
|
for (i = 0; i < priv->feat->max_sensors; i++) {
|
||||||
|
@@ -844,7 +910,11 @@ int __init init_common(struct tsens_priv *priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&priv->ul_lock);
|
||||||
|
- tsens_enable_irq(priv);
|
||||||
|
+
|
||||||
|
+ /* VER_0 interrupt doesn't need to be enabled */
|
||||||
|
+ if (tsens_version(priv) >= VER_0_1)
|
||||||
|
+ tsens_enable_irq(priv);
|
||||||
|
+
|
||||||
|
tsens_debug_init(op);
|
||||||
|
|
||||||
|
err_put_device:
|
||||||
|
@@ -943,10 +1013,19 @@ static int tsens_register_irq(struct tsens_priv *priv, char *irqname,
|
||||||
|
if (irq == -ENXIO)
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
- ret = devm_request_threaded_irq(&pdev->dev, irq,
|
||||||
|
- NULL, thread_fn,
|
||||||
|
- IRQF_ONESHOT,
|
||||||
|
- dev_name(&pdev->dev), priv);
|
||||||
|
+ /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */
|
||||||
|
+ if (tsens_version(priv) == VER_0)
|
||||||
|
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
|
||||||
|
+ thread_fn, NULL,
|
||||||
|
+ IRQF_TRIGGER_RISING,
|
||||||
|
+ dev_name(&pdev->dev),
|
||||||
|
+ priv);
|
||||||
|
+ else
|
||||||
|
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
|
+ thread_fn, IRQF_ONESHOT,
|
||||||
|
+ dev_name(&pdev->dev),
|
||||||
|
+ priv);
|
||||||
|
+
|
||||||
|
if (ret)
|
||||||
|
dev_err(&pdev->dev, "%s: failed to get irq\n",
|
||||||
|
__func__);
|
||||||
|
@@ -975,6 +1054,19 @@ static int tsens_register(struct tsens_priv *priv)
|
||||||
|
priv->ops->enable(priv, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* VER_0 require to set MIN and MAX THRESH
|
||||||
|
+ * These 2 regs are set using the:
|
||||||
|
+ * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C
|
||||||
|
+ * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C
|
||||||
|
+ */
|
||||||
|
+ if (tsens_version(priv) < VER_0_1) {
|
||||||
|
+ regmap_field_write(priv->rf[CRIT_THRESH_0],
|
||||||
|
+ tsens_mC_to_hw(priv->sensor, 120000));
|
||||||
|
+
|
||||||
|
+ regmap_field_write(priv->rf[CRIT_THRESH_1],
|
||||||
|
+ tsens_mC_to_hw(priv->sensor, 0));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ret = tsens_register_irq(priv, "uplow", tsens_irq_thread);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h
|
||||||
|
index f40b625f897e..8e6c1fd3ccf5 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens.h
|
||||||
|
+++ b/drivers/thermal/qcom/tsens.h
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
#define CAL_DEGC_PT2 120
|
||||||
|
#define SLOPE_FACTOR 1000
|
||||||
|
#define SLOPE_DEFAULT 3200
|
||||||
|
+#define TIMEOUT_US 100
|
||||||
|
#define THRESHOLD_MAX_ADC_CODE 0x3ff
|
||||||
|
#define THRESHOLD_MIN_ADC_CODE 0x0
|
||||||
|
|
||||||
|
@@ -25,7 +26,8 @@ struct tsens_priv;
|
||||||
|
|
||||||
|
/* IP version numbers in ascending order */
|
||||||
|
enum tsens_ver {
|
||||||
|
- VER_0_1 = 0,
|
||||||
|
+ VER_0 = 0,
|
||||||
|
+ VER_0_1,
|
||||||
|
VER_1_X,
|
||||||
|
VER_2_X,
|
||||||
|
};
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
From efa0d50a6c5ec7619371dfe4d3e6ca54b73787d5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Nov 2020 16:47:21 +0100
|
||||||
|
Subject: [PATCH 02/10] drivers: thermal: tsens: Don't hardcode sensor slope
|
||||||
|
|
||||||
|
Function compute_intercept_slope hardcode the sensor slope to
|
||||||
|
SLOPE_DEFAULT. Change this and use the default value only if a slope is
|
||||||
|
not defined. This is needed for tsens VER_0 that has a hardcoded slope
|
||||||
|
table.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens.c | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
|
||||||
|
index 9a7e991d4bd2..38b9936def1a 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens.c
|
||||||
|
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
|
||||||
|
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
|
||||||
|
__func__, i, p1[i], p2[i]);
|
||||||
|
|
||||||
|
- priv->sensor[i].slope = SLOPE_DEFAULT;
|
||||||
|
+ if (!priv->sensor[i].slope)
|
||||||
|
+ priv->sensor[i].slope = SLOPE_DEFAULT;
|
||||||
|
if (mode == TWO_PT_CALIB) {
|
||||||
|
/*
|
||||||
|
* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
From 6bac2e2fa36c2d7c304768a689d8b73155b90aa2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Nov 2020 17:15:51 +0100
|
||||||
|
Subject: [PATCH 03/10] drivers: thermal: tsens: Convert msm8960 to reg_field
|
||||||
|
|
||||||
|
Convert msm9860 driver to reg_field to use the init_common
|
||||||
|
function.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 79 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 2a28a5af209e..3f4fc1ffe679 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -51,11 +51,22 @@
|
||||||
|
#define MIN_LIMIT_TH 0x0
|
||||||
|
#define MAX_LIMIT_TH 0xff
|
||||||
|
|
||||||
|
-#define S0_STATUS_ADDR 0x3628
|
||||||
|
#define INT_STATUS_ADDR 0x363c
|
||||||
|
#define TRDY_MASK BIT(7)
|
||||||
|
#define TIMEOUT_US 100
|
||||||
|
|
||||||
|
+#define S0_STATUS_OFF 0x3628
|
||||||
|
+#define S1_STATUS_OFF 0x362c
|
||||||
|
+#define S2_STATUS_OFF 0x3630
|
||||||
|
+#define S3_STATUS_OFF 0x3634
|
||||||
|
+#define S4_STATUS_OFF 0x3638
|
||||||
|
+#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */
|
||||||
|
+#define S6_STATUS_OFF 0x3668
|
||||||
|
+#define S7_STATUS_OFF 0x366c
|
||||||
|
+#define S8_STATUS_OFF 0x3670
|
||||||
|
+#define S9_STATUS_OFF 0x3674
|
||||||
|
+#define S10_STATUS_OFF 0x3678
|
||||||
|
+
|
||||||
|
static int suspend_8960(struct tsens_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int *temp)
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static struct tsens_features tsens_8960_feat = {
|
||||||
|
+ .ver_major = VER_0,
|
||||||
|
+ .crit_int = 0,
|
||||||
|
+ .adc = 1,
|
||||||
|
+ .srot_split = 0,
|
||||||
|
+ .max_sensors = 11,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
|
||||||
|
+ /* ----- SROT ------ */
|
||||||
|
+ /* No VERSION information */
|
||||||
|
+
|
||||||
|
+ /* CNTL */
|
||||||
|
+ [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0),
|
||||||
|
+ [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1),
|
||||||
|
+ /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
|
||||||
|
+ [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7),
|
||||||
|
+
|
||||||
|
+ /* ----- TM ------ */
|
||||||
|
+ /* INTERRUPT ENABLE */
|
||||||
|
+ /* NO INTERRUPT ENABLE */
|
||||||
|
+
|
||||||
|
+ /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
|
||||||
|
+ [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7),
|
||||||
|
+ [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15),
|
||||||
|
+ /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
|
||||||
|
+ * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp
|
||||||
|
+ * MIN_THRESH_0 -> CRIT_THRESH_1
|
||||||
|
+ * MAX_THRESH_0 -> CRIT_THRESH_0
|
||||||
|
+ */
|
||||||
|
+ [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23),
|
||||||
|
+ [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31),
|
||||||
|
+
|
||||||
|
+ /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
|
||||||
|
+ /* 1 == clear, 0 == normal operation */
|
||||||
|
+ [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9),
|
||||||
|
+ [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10),
|
||||||
|
+
|
||||||
|
+ /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
|
||||||
|
+
|
||||||
|
+ /* Sn_STATUS */
|
||||||
|
+ [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7),
|
||||||
|
+ [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7),
|
||||||
|
+
|
||||||
|
+ /* No VALID field on 8960 */
|
||||||
|
+ /* TSENS_INT_STATUS bits: 1 == threshold violated */
|
||||||
|
+ [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
|
||||||
|
+ [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
|
||||||
|
+ [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
|
||||||
|
+ /* No CRITICAL field on 8960 */
|
||||||
|
+ [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
|
||||||
|
+
|
||||||
|
+ /* TRDY: 1=ready, 0=in progress */
|
||||||
|
+ [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static const struct tsens_ops ops_8960 = {
|
||||||
|
.init = init_8960,
|
||||||
|
.calibrate = calibrate_8960,
|
||||||
|
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
|
||||||
|
struct tsens_plat_data data_8960 = {
|
||||||
|
.num_sensors = 11,
|
||||||
|
.ops = &ops_8960,
|
||||||
|
+ .feat = &tsens_8960_feat,
|
||||||
|
+ .fields = tsens_8960_regfields,
|
||||||
|
};
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
From c04f98a496929f75d75c65115d5717423c3d0634 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Nov 2020 17:16:36 +0100
|
||||||
|
Subject: [PATCH 04/10] drivers: thermal: tsens: Use init_common for msm8960
|
||||||
|
|
||||||
|
Use init_common and drop custom init for msm8960.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------
|
||||||
|
1 file changed, 1 insertion(+), 51 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 3f4fc1ffe679..86585f439985 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
|
||||||
|
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int init_8960(struct tsens_priv *priv)
|
||||||
|
-{
|
||||||
|
- int ret, i;
|
||||||
|
- u32 reg_cntl;
|
||||||
|
-
|
||||||
|
- priv->tm_map = dev_get_regmap(priv->dev, NULL);
|
||||||
|
- if (!priv->tm_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 < priv->num_sensors; i++) {
|
||||||
|
- if (i >= 5)
|
||||||
|
- priv->sensor[i].status = S0_STATUS_ADDR + 40;
|
||||||
|
- priv->sensor[i].status += i * 4;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- reg_cntl = SW_RST;
|
||||||
|
- ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- if (priv->num_sensors > 1) {
|
||||||
|
- reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
|
||||||
|
- reg_cntl &= ~SW_RST;
|
||||||
|
- ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
|
||||||
|
- CONFIG_MASK, CONFIG);
|
||||||
|
- } else {
|
||||||
|
- reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
|
||||||
|
- reg_cntl &= ~CONFIG_MASK_8660;
|
||||||
|
- reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
|
||||||
|
- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- reg_cntl |= EN;
|
||||||
|
- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int calibrate_8960(struct tsens_priv *priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tsens_ops ops_8960 = {
|
||||||
|
- .init = init_8960,
|
||||||
|
+ .init = init_common,
|
||||||
|
.calibrate = calibrate_8960,
|
||||||
|
.get_temp = get_temp_8960,
|
||||||
|
.enable = enable_8960,
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
From b3e8bd33b84a6b6c863bd1733bd15b5f1483b8ab Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Nov 2020 17:06:55 +0100
|
||||||
|
Subject: [PATCH 05/10] drivers: thermal: tsens: Fix bug in sensor enable for
|
||||||
|
msm8960
|
||||||
|
|
||||||
|
Device based on tsens VER_0 contains a hardware bug that results in some
|
||||||
|
problem with sensor enablement. Sensor id 6-11 can't be enabled
|
||||||
|
selectively and all of them must be enabled in one step.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++---
|
||||||
|
1 file changed, 20 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 86585f439985..95fcccafae14 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -27,9 +27,9 @@
|
||||||
|
#define EN BIT(0)
|
||||||
|
#define SW_RST BIT(1)
|
||||||
|
#define SENSOR0_EN BIT(3)
|
||||||
|
+#define MEASURE_PERIOD BIT(18)
|
||||||
|
#define SLP_CLK_ENA BIT(26)
|
||||||
|
#define SLP_CLK_ENA_8660 BIT(24)
|
||||||
|
-#define MEASURE_PERIOD 1
|
||||||
|
#define SENSOR0_SHIFT 3
|
||||||
|
|
||||||
|
/* INT_STATUS_ADDR bitmasks */
|
||||||
|
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv)
|
||||||
|
static int enable_8960(struct tsens_priv *priv, int id)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
- u32 reg, mask;
|
||||||
|
+ u32 reg, mask = BIT(id);
|
||||||
|
|
||||||
|
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- mask = BIT(id + SENSOR0_SHIFT);
|
||||||
|
+ /* HARDWARE BUG:
|
||||||
|
+ * On platforms with more than 6 sensors, all remaining sensors
|
||||||
|
+ * must be enabled together, otherwise undefined results are expected.
|
||||||
|
+ * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
|
||||||
|
+ * all the sensors are enabled in one step hence this bug is not
|
||||||
|
+ * triggered.
|
||||||
|
+ */
|
||||||
|
+ if (id > 5)
|
||||||
|
+ mask = GENMASK(10, 6);
|
||||||
|
+
|
||||||
|
+ mask <<= SENSOR0_SHIFT;
|
||||||
|
+
|
||||||
|
+ /* Sensors already enabled. Skip. */
|
||||||
|
+ if ((reg & mask) == mask)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
+ reg |= MEASURE_PERIOD;
|
||||||
|
+
|
||||||
|
if (priv->num_sensors > 1)
|
||||||
|
reg |= mask | SLP_CLK_ENA | EN;
|
||||||
|
else
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
From 1ff9f982051759e0387e8c7e793b49c48eae291d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Wed, 25 Nov 2020 17:11:05 +0100
|
||||||
|
Subject: [PATCH 06/10] drivers: thermal: tsens: Replace custom 8960 apis with
|
||||||
|
generic apis
|
||||||
|
|
||||||
|
Rework calibrate function to use common function. Derive the offset from
|
||||||
|
a missing hardcoded slope table and the data from the nvmem calib
|
||||||
|
efuses.
|
||||||
|
Drop custom get_temp function and use generic api.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Acked-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 56 +++++++++----------------------
|
||||||
|
1 file changed, 15 insertions(+), 41 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 95fcccafae14..9cc8a7dd23ae 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -67,6 +67,13 @@
|
||||||
|
#define S9_STATUS_OFF 0x3674
|
||||||
|
#define S10_STATUS_OFF 0x3678
|
||||||
|
|
||||||
|
+/* Original slope - 200 to compensate mC to C inaccuracy */
|
||||||
|
+static u32 tsens_msm8960_slope[] = {
|
||||||
|
+ 976, 976, 954, 976,
|
||||||
|
+ 911, 932, 932, 999,
|
||||||
|
+ 932, 999, 932
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
static int suspend_8960(struct tsens_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *data;
|
||||||
|
-
|
||||||
|
- ssize_t num_read = priv->num_sensors;
|
||||||
|
- struct tsens_sensor *s = priv->sensor;
|
||||||
|
+ u32 p1[11];
|
||||||
|
|
||||||
|
data = qfprom_read(priv->dev, "calib");
|
||||||
|
if (IS_ERR(data))
|
||||||
|
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv)
|
||||||
|
if (IS_ERR(data))
|
||||||
|
return PTR_ERR(data);
|
||||||
|
|
||||||
|
- for (i = 0; i < num_read; i++, s++)
|
||||||
|
- s->offset = data[i];
|
||||||
|
+ for (i = 0; i < priv->num_sensors; i++) {
|
||||||
|
+ p1[i] = data[i];
|
||||||
|
+ priv->sensor[i].slope = tsens_msm8960_slope[i];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Temperature on y axis and ADC-code on x-axis */
|
||||||
|
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
|
||||||
|
-{
|
||||||
|
- int slope, offset;
|
||||||
|
-
|
||||||
|
- slope = thermal_zone_get_slope(s->tzd);
|
||||||
|
- offset = CAL_MDEGC - slope * s->offset;
|
||||||
|
-
|
||||||
|
- return adc_code * slope + offset;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
|
||||||
|
-{
|
||||||
|
- int ret;
|
||||||
|
- u32 code, trdy;
|
||||||
|
- struct tsens_priv *priv = s->priv;
|
||||||
|
- unsigned long timeout;
|
||||||
|
-
|
||||||
|
- timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
||||||
|
- do {
|
||||||
|
- ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
- if (!(trdy & TRDY_MASK))
|
||||||
|
- continue;
|
||||||
|
- ret = regmap_read(priv->tm_map, s->status, &code);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
- *temp = code_to_mdegC(code, s);
|
||||||
|
- return 0;
|
||||||
|
- } while (time_before(jiffies, timeout));
|
||||||
|
-
|
||||||
|
- return -ETIMEDOUT;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static struct tsens_features tsens_8960_feat = {
|
||||||
|
.ver_major = VER_0,
|
||||||
|
.crit_int = 0,
|
||||||
|
@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
|
||||||
|
static const struct tsens_ops ops_8960 = {
|
||||||
|
.init = init_common,
|
||||||
|
.calibrate = calibrate_8960,
|
||||||
|
- .get_temp = get_temp_8960,
|
||||||
|
+ .get_temp = get_temp_common,
|
||||||
|
.enable = enable_8960,
|
||||||
|
.disable = disable_8960,
|
||||||
|
.suspend = suspend_8960,
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
From 5716a61239c6ac9ceb137e825e93c3aea06c4634 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Fri, 19 Mar 2021 00:48:23 +0100
|
||||||
|
Subject: [PATCH 07/10] drivers: thermal: tsens: Drop unused define for msm8960
|
||||||
|
|
||||||
|
Drop unused define for msm8960 replaced by generic api and reg_field.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 24 +-----------------------
|
||||||
|
1 file changed, 1 insertion(+), 23 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 9cc8a7dd23ae..58d09e927383 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -10,8 +10,6 @@
|
||||||
|
#include <linux/thermal.h>
|
||||||
|
#include "tsens.h"
|
||||||
|
|
||||||
|
-#define CAL_MDEGC 30000
|
||||||
|
-
|
||||||
|
#define CONFIG_ADDR 0x3640
|
||||||
|
#define CONFIG_ADDR_8660 0x3620
|
||||||
|
/* CONFIG_ADDR bitmasks */
|
||||||
|
@@ -21,39 +19,19 @@
|
||||||
|
#define CONFIG_SHIFT_8660 28
|
||||||
|
#define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660)
|
||||||
|
|
||||||
|
-#define STATUS_CNTL_ADDR_8064 0x3660
|
||||||
|
#define CNTL_ADDR 0x3620
|
||||||
|
/* CNTL_ADDR bitmasks */
|
||||||
|
#define EN BIT(0)
|
||||||
|
#define SW_RST BIT(1)
|
||||||
|
-#define SENSOR0_EN BIT(3)
|
||||||
|
+
|
||||||
|
#define MEASURE_PERIOD BIT(18)
|
||||||
|
#define SLP_CLK_ENA BIT(26)
|
||||||
|
#define SLP_CLK_ENA_8660 BIT(24)
|
||||||
|
#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_LIMIT_SHIFT 24
|
||||||
|
-#define THRESHOLD_MIN_LIMIT_SHIFT 16
|
||||||
|
-#define THRESHOLD_UPPER_LIMIT_SHIFT 8
|
||||||
|
-#define THRESHOLD_LOWER_LIMIT_SHIFT 0
|
||||||
|
-
|
||||||
|
-/* Initial temperature threshold values */
|
||||||
|
-#define LOWER_LIMIT_TH 0x50
|
||||||
|
-#define UPPER_LIMIT_TH 0xdf
|
||||||
|
-#define MIN_LIMIT_TH 0x0
|
||||||
|
-#define MAX_LIMIT_TH 0xff
|
||||||
|
|
||||||
|
#define INT_STATUS_ADDR 0x363c
|
||||||
|
-#define TRDY_MASK BIT(7)
|
||||||
|
-#define TIMEOUT_US 100
|
||||||
|
|
||||||
|
#define S0_STATUS_OFF 0x3628
|
||||||
|
#define S1_STATUS_OFF 0x362c
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
From 0d0c22a59bf2672b57e23da9a9ea743e91b71f54 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Sat, 25 Jul 2020 19:55:57 +0200
|
||||||
|
Subject: [PATCH 08/10] drivers: thermal: tsens: Add support for ipq8064-tsens
|
||||||
|
|
||||||
|
Add support for tsens present in ipq806x SoCs based on generic msm8960
|
||||||
|
tsens driver.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Thara Gopinath <thara.gopinath@linaro.org>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens.c | 3 +++
|
||||||
|
1 file changed, 3 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
|
||||||
|
index 38b9936def1a..58073dc5d30b 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens.c
|
||||||
|
@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
|
||||||
|
|
||||||
|
static const struct of_device_id tsens_table[] = {
|
||||||
|
{
|
||||||
|
+ .compatible = "qcom,ipq8064-tsens",
|
||||||
|
+ .data = &data_8960,
|
||||||
|
+ }, {
|
||||||
|
.compatible = "qcom,msm8916-tsens",
|
||||||
|
.data = &data_8916,
|
||||||
|
}, {
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
From ac369071920d427dd484cf74cddba2774bba45f5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Thu, 9 Jul 2020 22:35:54 +0200
|
||||||
|
Subject: [PATCH 09/10] dt-bindings: thermal: tsens: Document ipq8064 bindings
|
||||||
|
|
||||||
|
Document the use of bindings used for msm8960 tsens based devices.
|
||||||
|
msm8960 use the same gcc regs and is set as a child of the qcom gcc.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||||
|
---
|
||||||
|
.../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++---
|
||||||
|
1 file changed, 48 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
|
||||||
|
index 95462e071ab4..1785b1c75a3c 100644
|
||||||
|
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
|
||||||
|
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
|
||||||
|
@@ -19,6 +19,11 @@ description: |
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
+ - description: msm9860 TSENS based
|
||||||
|
+ items:
|
||||||
|
+ - enum:
|
||||||
|
+ - qcom,ipq8064-tsens
|
||||||
|
+
|
||||||
|
- description: v0.1 of TSENS
|
||||||
|
items:
|
||||||
|
- enum:
|
||||||
|
@@ -73,7 +78,9 @@ properties:
|
||||||
|
maxItems: 2
|
||||||
|
items:
|
||||||
|
- const: calib
|
||||||
|
- - const: calib_sel
|
||||||
|
+ - enum:
|
||||||
|
+ - calib_backup
|
||||||
|
+ - calib_sel
|
||||||
|
|
||||||
|
"#qcom,sensors":
|
||||||
|
description:
|
||||||
|
@@ -88,12 +95,20 @@ properties:
|
||||||
|
Number of cells required to uniquely identify the thermal sensors. Since
|
||||||
|
we have multiple sensors this is set to 1
|
||||||
|
|
||||||
|
+required:
|
||||||
|
+ - compatible
|
||||||
|
+ - interrupts
|
||||||
|
+ - interrupt-names
|
||||||
|
+ - "#thermal-sensor-cells"
|
||||||
|
+ - "#qcom,sensors"
|
||||||
|
+
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
+ - qcom,ipq8064-tsens
|
||||||
|
- qcom,msm8916-tsens
|
||||||
|
- qcom,msm8974-tsens
|
||||||
|
- qcom,msm8976-tsens
|
||||||
|
@@ -114,17 +129,42 @@ allOf:
|
||||||
|
interrupt-names:
|
||||||
|
minItems: 2
|
||||||
|
|
||||||
|
-required:
|
||||||
|
- - compatible
|
||||||
|
- - reg
|
||||||
|
- - "#qcom,sensors"
|
||||||
|
- - interrupts
|
||||||
|
- - interrupt-names
|
||||||
|
- - "#thermal-sensor-cells"
|
||||||
|
+ - if:
|
||||||
|
+ properties:
|
||||||
|
+ compatible:
|
||||||
|
+ contains:
|
||||||
|
+ enum:
|
||||||
|
+ - qcom,tsens-v0_1
|
||||||
|
+ - qcom,tsens-v1
|
||||||
|
+ - qcom,tsens-v2
|
||||||
|
+
|
||||||
|
+ then:
|
||||||
|
+ required:
|
||||||
|
+ - reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
+ - |
|
||||||
|
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
+ // Example msm9860 based SoC (ipq8064):
|
||||||
|
+ gcc: clock-controller {
|
||||||
|
+
|
||||||
|
+ /* ... */
|
||||||
|
+
|
||||||
|
+ tsens: thermal-sensor {
|
||||||
|
+ compatible = "qcom,ipq8064-tsens";
|
||||||
|
+
|
||||||
|
+ nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>;
|
||||||
|
+ nvmem-cell-names = "calib", "calib_backup";
|
||||||
|
+ interrupts = <GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
+ interrupt-names = "uplow";
|
||||||
|
+
|
||||||
|
+ #qcom,sensors = <11>;
|
||||||
|
+ #thermal-sensor-cells = <1>;
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
// Example 1 (legacy: for pre v1 IP):
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
From 68e720ed73c8f038c8c500e4c49c1e65a993a448 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
Date: Tue, 6 Apr 2021 04:45:31 +0200
|
||||||
|
Subject: [PATCH 10/10] drivers: thermal: tsens: Fix wrong slope on msm-8960
|
||||||
|
|
||||||
|
Some user using some stats with the old legacy implementation and the
|
||||||
|
new implementation using the compute_intercept_slope reported an offset
|
||||||
|
of 3C. Fix the slope table to reflect the original temp.
|
||||||
|
|
||||||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||||
|
---
|
||||||
|
drivers/thermal/qcom/tsens-8960.c | 8 ++++----
|
||||||
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
index 58d09e927383..5cc5b3527f1f 100644
|
||||||
|
--- a/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
+++ b/drivers/thermal/qcom/tsens-8960.c
|
||||||
|
@@ -45,11 +45,11 @@
|
||||||
|
#define S9_STATUS_OFF 0x3674
|
||||||
|
#define S10_STATUS_OFF 0x3678
|
||||||
|
|
||||||
|
-/* Original slope - 200 to compensate mC to C inaccuracy */
|
||||||
|
+/* Original slope - 350 to compensate mC to C inaccuracy */
|
||||||
|
static u32 tsens_msm8960_slope[] = {
|
||||||
|
- 976, 976, 954, 976,
|
||||||
|
- 911, 932, 932, 999,
|
||||||
|
- 932, 999, 932
|
||||||
|
+ 826, 826, 804, 826,
|
||||||
|
+ 761, 782, 782, 849,
|
||||||
|
+ 782, 849, 782
|
||||||
|
};
|
||||||
|
|
||||||
|
static int suspend_8960(struct tsens_priv *priv)
|
||||||
|
--
|
||||||
|
2.30.2
|
||||||
|
|
Loading…
Reference in a new issue