summaryrefslogtreecommitdiff
path: root/drivers/thermal/qcom-spmi-temp-alarm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-12 23:23:51 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-12 23:23:51 +0300
commit19785cf93b6c4252981894394f2dbd35c5e5d1ec (patch)
tree837d86ff16a56bd681974f933813937985225277 /drivers/thermal/qcom-spmi-temp-alarm.c
parent98db5e5503c21c27705c49ebda782b4252b5f7a7 (diff)
parent6d7c70d1cd6526dc79e3d3b3faae1c40c1681168 (diff)
downloadlinux-19785cf93b6c4252981894394f2dbd35c5e5d1ec.tar.xz
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal
Pull thermal SoC updates from Zhang Rui: "Thermal SoC management updates: - imx thermal driver now supports i.MX7 thermal sensor (Anson Huang) - exynos thermal driver dropped support for exynos 5440 (Krzysztof Kozlowski) - rcar_thermal now supports r8a77995 (Yoshihiro Kaneko) - rcar_gen3_thermal now supports r8a77965 (Niklas Söderlund) - qcom-spmi-temp-alarm now supports GEN2 PMIC peripherals (David Collins) - uniphier thermal now supports UniPhier PXs3 (Kunihiko Hayashi) - mediatek thermal now supports MT7622 SoC (Sean Wang) - considerable refactoring of exynos driver (Bartlomiej Zolnierkiewicz) - small fixes all over the place on different drivers" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal: (50 commits) thermal: qcom: tsens: Allow number of sensors to come from DT thermal: tegra: soctherm: add const to struct thermal_cooling_device_ops thermal: exynos: Reduce severity of too early temperature read thermal: imx: Switch to SPDX identifier thermal: qcom-spmi-temp-alarm: add support for GEN2 PMIC peripherals thermal: ti-soc-thermal: fix incorrect entry in omap5430_adc_to_temp[] thermal: rcar_thermal: add r8a77995 support dt-bindings: thermal: rcar-thermal: add R8A77995 support thermal: mediatek: use of_device_get_match_data() thermal: exynos: remove trip reporting to user-space thermal: exynos: remove unused defines for Exynos5433 thermal: exynos: cleanup code for enabling threshold interrupts thermal: exynos: check return values of ->get_trip_[temp, hyst] methods thermal: exynos: move trips setting to exynos_tmu_initialize() thermal: exynos: set trips in ascending order in exynos7_tmu_initialize() thermal: exynos: do not use trips structure directly in ->tmu_initialize thermal: exynos: add exynos*_tmu_set_[trip,hyst]() helpers thermal: exynos: move IRQs clearing to exynos_tmu_initialize() thermal: exynos: clear IRQs later in exynos4412_tmu_initialize() thermal: exynos: make ->tmu_initialize method void ...
Diffstat (limited to 'drivers/thermal/qcom-spmi-temp-alarm.c')
-rw-r--r--drivers/thermal/qcom-spmi-temp-alarm.c92
1 files changed, 71 insertions, 21 deletions
diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c
index 95f987d5aa71..ad4f3a8d6560 100644
--- a/drivers/thermal/qcom-spmi-temp-alarm.c
+++ b/drivers/thermal/qcom-spmi-temp-alarm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015, 2017, 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
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/consumer.h>
@@ -29,13 +30,17 @@
#define QPNP_TM_REG_ALARM_CTRL 0x46
#define QPNP_TM_TYPE 0x09
-#define QPNP_TM_SUBTYPE 0x08
+#define QPNP_TM_SUBTYPE_GEN1 0x08
+#define QPNP_TM_SUBTYPE_GEN2 0x09
-#define STATUS_STAGE_MASK 0x03
+#define STATUS_GEN1_STAGE_MASK GENMASK(1, 0)
+#define STATUS_GEN2_STATE_MASK GENMASK(6, 4)
+#define STATUS_GEN2_STATE_SHIFT 4
-#define SHUTDOWN_CTRL1_THRESHOLD_MASK 0x03
+#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6)
+#define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0)
-#define ALARM_CTRL_FORCE_ENABLE 0x80
+#define ALARM_CTRL_FORCE_ENABLE BIT(7)
/*
* Trip point values based on threshold control
@@ -58,6 +63,7 @@
struct qpnp_tm_chip {
struct regmap *map;
struct thermal_zone_device *tz_dev;
+ unsigned int subtype;
long temp;
unsigned int thresh;
unsigned int stage;
@@ -66,6 +72,9 @@ struct qpnp_tm_chip {
struct iio_channel *adc;
};
+/* This array maps from GEN2 alarm state to GEN1 alarm stage */
+static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};
+
static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data)
{
unsigned int val;
@@ -84,30 +93,59 @@ static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data)
return regmap_write(chip->map, chip->base + addr, data);
}
+/**
+ * qpnp_tm_get_temp_stage() - return over-temperature stage
+ * @chip: Pointer to the qpnp_tm chip
+ *
+ * Return: stage (GEN1) or state (GEN2) on success, or errno on failure.
+ */
+static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip)
+{
+ int ret;
+ u8 reg = 0;
+
+ ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
+ ret = reg & STATUS_GEN1_STAGE_MASK;
+ else
+ ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT;
+
+ return ret;
+}
+
/*
* This function updates the internal temp value based on the
* current thermal stage and threshold as well as the previous stage
*/
static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
{
- unsigned int stage;
+ unsigned int stage, stage_new, stage_old;
int ret;
- u8 reg = 0;
- ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
+ ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
return ret;
+ stage = ret;
- stage = reg & STATUS_STAGE_MASK;
+ if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
+ stage_new = stage;
+ stage_old = chip->stage;
+ } else {
+ stage_new = alarm_state_map[stage];
+ stage_old = alarm_state_map[chip->stage];
+ }
- if (stage > chip->stage) {
+ if (stage_new > stage_old) {
/* increasing stage, use lower bound */
- chip->temp = (stage - 1) * TEMP_STAGE_STEP +
+ chip->temp = (stage_new - 1) * TEMP_STAGE_STEP +
chip->thresh * TEMP_THRESH_STEP +
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
- } else if (stage < chip->stage) {
+ } else if (stage_new < stage_old) {
/* decreasing stage, use upper bound */
- chip->temp = stage * TEMP_STAGE_STEP +
+ chip->temp = stage_new * TEMP_STAGE_STEP +
chip->thresh * TEMP_THRESH_STEP -
TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
}
@@ -162,28 +200,37 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data)
*/
static int qpnp_tm_init(struct qpnp_tm_chip *chip)
{
+ unsigned int stage;
int ret;
- u8 reg;
+ u8 reg = 0;
- chip->thresh = THRESH_MIN;
+ ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg);
+ if (ret < 0)
+ return ret;
+
+ chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
chip->temp = DEFAULT_TEMP;
- ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg);
+ ret = qpnp_tm_get_temp_stage(chip);
if (ret < 0)
return ret;
+ chip->stage = ret;
- chip->stage = reg & STATUS_STAGE_MASK;
+ stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1
+ ? chip->stage : alarm_state_map[chip->stage];
- if (chip->stage)
+ if (stage)
chip->temp = chip->thresh * TEMP_THRESH_STEP +
- (chip->stage - 1) * TEMP_STAGE_STEP +
+ (stage - 1) * TEMP_STAGE_STEP +
TEMP_THRESH_MIN;
/*
* Set threshold and disable software override of stage 2 and 3
* shutdowns.
*/
- reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
+ chip->thresh = THRESH_MIN;
+ reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK);
+ reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg);
if (ret < 0)
return ret;
@@ -246,12 +293,15 @@ static int qpnp_tm_probe(struct platform_device *pdev)
return ret;
}
- if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
+ if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1
+ && subtype != QPNP_TM_SUBTYPE_GEN2)) {
dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n",
type, subtype);
return -ENODEV;
}
+ chip->subtype = subtype;
+
ret = qpnp_tm_init(chip);
if (ret < 0) {
dev_err(&pdev->dev, "init failed\n");