mirror of
git://git.openwrt.org/openwrt/openwrt.git
synced 2024-12-14 19:04:39 +00:00
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
@ -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 New Issue
Block a user