Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec717f7d authored by David Collins's avatar David Collins Committed by ansharma
Browse files

thermal: qpnp-temp-alarm: add support for GEN2 PMIC peripherals



Add support for the TEMP_ALARM GEN2 PMIC peripheral subtype.  The
GEN2 subtype adds clock rate control and defines an over
temperature state with hysteresis instead of stage in the status
register.  There are two GEN2 states corresponding to stages 1
and 2.

CRs-Fixed: 1019272
Change-Id: Ic4ad048259eb3a356333e0529d52f39c39fc915f
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
[ansharma@codeaurora.org: Fix minor merge conflicts]
Signed-off-by: default avataransharma <ansharma@codeaurora.org>
parent ee20f199
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -29,6 +29,14 @@ Optional properties:
			 1 = {110 C, 130 C, 150 C}
			 2 = {115 C, 135 C, 155 C}
			 3 = {120 C, 140 C, 160 C}
- qcom,clock-rate:     Integer value which specifies the temperature monitoring
			clock rate.  This property is only supported on GEN2
			temperature alarm peripherals.
			Supported values:
			 0 = 100 Hz
			 1 = 50 Hz
			 2 = 25 Hz
			 3 = 12.5 Hz
- qcom,allow-override: Boolean which controls the ability of software to
			override shutdowns.  If present, then software is
			allowed to override automatic PMIC hardware stage 2 and
+102 −31
Original line number Diff line number Diff line
/*
 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
 * Copyright (c) 2011-2013, 2016, 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
@@ -38,12 +38,17 @@ enum qpnp_tm_registers {
};

#define QPNP_TM_TYPE			0x09
#define QPNP_TM_SUBTYPE			0x08
#define QPNP_TM_SUBTYPE_GEN1		0x08
#define QPNP_TM_SUBTYPE_GEN2		0x09

#define STATUS_STATE_MASK		0x70
#define STATUS_STATE_SHIFT		4
#define STATUS_STAGE_MASK		0x03

#define SHUTDOWN_CTRL1_OVERRIDE_STAGE3	0x80
#define SHUTDOWN_CTRL1_OVERRIDE_STAGE2	0x40
#define SHUTDOWN_CTRL1_CLK_RATE_MASK	0x0C
#define SHUTDOWN_CTRL1_CLK_RATE_SHIFT	2
#define SHUTDOWN_CTRL1_THRESHOLD_MASK	0x03

#define SHUTDOWN_CTRL2_CLEAR_STAGE3	0x80
@@ -61,6 +66,9 @@ enum qpnp_tm_registers {
#define THRESH_MIN			0
#define THRESH_MAX			3

#define CLOCK_RATE_MIN			0
#define CLOCK_RATE_MAX			3

/* Trip points from most critical to least critical */
#define TRIP_STAGE3			0
#define TRIP_STAGE2			1
@@ -83,10 +91,12 @@ struct qpnp_tm_chip {
	struct spmi_device		*spmi_dev;
	struct thermal_zone_device	*tz_dev;
	const char			*tm_name;
	unsigned int			subtype;
	enum qpnp_tm_adc_type		adc_type;
	unsigned long			temperature;
	enum thermal_device_mode	mode;
	unsigned int			thresh;
	unsigned int			clock_rate;
	unsigned int			stage;
	unsigned int			prev_stage;
	int				irq;
@@ -104,6 +114,9 @@ enum pmic_thermal_override_mode {
	SOFTWARE_OVERRIDE_ENABLED,
};

/* This array maps from GEN2 alarm state to GEN1 alarm stage */
const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};

static inline int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *buf,
				int len)
{
@@ -145,6 +158,8 @@ static inline int qpnp_tm_shutdown_override(struct qpnp_tm_chip *chip,

	if (chip->allow_software_override) {
		reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
		reg |= (chip->clock_rate << SHUTDOWN_CTRL1_CLK_RATE_SHIFT)
			& SHUTDOWN_CTRL1_CLK_RATE_MASK;

		if (mode == SOFTWARE_OVERRIDE_ENABLED)
			reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2
@@ -171,24 +186,43 @@ static int qpnp_tm_update_temp(struct qpnp_tm_chip *chip)
	return rc;
}

static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip,
			unsigned int *stage)
{
	int rc;
	u8 reg;

	rc = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg, 1);
	if (rc < 0)
		return rc;

	if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
		*stage = reg & STATUS_STAGE_MASK;
	else
		*stage = (reg & STATUS_STATE_MASK) >> STATUS_STATE_SHIFT;

	return 0;
}

/*
 * This function initializes the internal temperature value based on only the
 * current thermal stage and threshold.
 */
static int qpnp_tm_init_temp_no_adc(struct qpnp_tm_chip *chip)
{
	unsigned int stage;
	int rc;
	u8 reg;

	rc = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg, 1);
	rc = qpnp_tm_get_temp_stage(chip, &chip->stage);
	if (rc < 0)
		return rc;

	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->temperature = chip->thresh * TEMP_THRESH_STEP +
			   (chip->stage - 1) * TEMP_STAGE_STEP +
			   (stage - 1) * TEMP_STAGE_STEP +
			   TEMP_THRESH_MIN;

	return 0;
@@ -200,24 +234,29 @@ static int qpnp_tm_init_temp_no_adc(struct qpnp_tm_chip *chip)
 */
static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
{
	unsigned int stage;
	unsigned int stage, stage_new, stage_old;
	int rc;
	u8 reg;

	rc = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg, 1);
	rc = qpnp_tm_get_temp_stage(chip, &stage);
	if (rc < 0)
		return rc;

	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->temperature = (stage - 1) * TEMP_STAGE_STEP
		chip->temperature = (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->temperature = stage * TEMP_STAGE_STEP
		chip->temperature = stage_new * TEMP_STAGE_STEP
				+ chip->thresh * TEMP_THRESH_STEP
				- TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
	}
@@ -389,31 +428,42 @@ static void qpnp_tm_work(struct work_struct *work)
		= container_of(work, struct delayed_work, work);
	struct qpnp_tm_chip *chip
		= container_of(dwork, struct qpnp_tm_chip, irq_work);
	unsigned int stage_new, stage_old;
	int rc;
	u8 reg;

	if (chip->adc_type == QPNP_TM_ADC_NONE) {
		rc = qpnp_tm_update_temp_no_adc(chip);
		if (rc < 0)
			goto bail;
	} else {
		rc = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, &reg, 1);
		rc = qpnp_tm_get_temp_stage(chip, &chip->stage);
		if (rc < 0)
			goto bail;

		chip->stage = reg & STATUS_STAGE_MASK;

		rc = qpnp_tm_update_temp(chip);
		if (rc < 0)
			goto bail;
	}

	if (chip->stage != chip->prev_stage) {
	if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) {
		stage_new = chip->stage;
		stage_old = chip->prev_stage;
	} else {
		stage_new = alarm_state_map[chip->stage];
		stage_old = alarm_state_map[chip->prev_stage];
	}

	chip->prev_stage = chip->stage;

	if (stage_new != stage_old) {
		if (chip->subtype == QPNP_TM_SUBTYPE_GEN1)
			pr_crit("%s: PMIC Temp Alarm - stage=%u, threshold=%u, temperature=%lu mC\n",
				chip->tm_name, chip->stage, chip->thresh,
				chip->temperature);
		else
			pr_crit("%s: PMIC Temp Alarm - stage=%u, state=%u, threshold=%u, temperature=%lu mC\n",
				chip->tm_name, stage_new, chip->stage,
				chip->thresh, chip->temperature);

		thermal_zone_device_update(chip->tz_dev);

@@ -440,19 +490,29 @@ static int qpnp_tm_init_reg(struct qpnp_tm_chip *chip)
	int rc = 0;
	u8 reg;

	if (chip->thresh < THRESH_MIN || chip->thresh > THRESH_MAX) {
		/* Read hardware threshold value if configuration is invalid. */
	rc = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg, 1);
	if (rc < 0)
		return rc;

	if (chip->thresh < THRESH_MIN || chip->thresh > THRESH_MAX) {
		/* Use hardware threshold value if configuration is invalid. */
		chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK;
	}

	if (chip->clock_rate < CLOCK_RATE_MIN
	    || chip->clock_rate > CLOCK_RATE_MAX) {
		/* Use hardware clock rate value if configuration is invalid. */
		chip->clock_rate = (reg & SHUTDOWN_CTRL1_CLK_RATE_MASK)
					>> SHUTDOWN_CTRL1_CLK_RATE_SHIFT;
	}

	/*
	 * Set threshold and disable software override of stage 2 and 3
	 * shutdowns.
	 * Set threshold and clock rate and also disable software override of
	 * stage 2 and 3 shutdowns.
	 */
	reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
	reg |= (chip->clock_rate << SHUTDOWN_CTRL1_CLK_RATE_SHIFT)
		& SHUTDOWN_CTRL1_CLK_RATE_MASK;
	rc = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg, 1);
	if (rc < 0)
		return rc;
@@ -536,6 +596,14 @@ static int qpnp_tm_probe(struct spmi_device *spmi)
		dev_err(&spmi->dev, "%s: invalid qcom,threshold-set=%u specified\n",
			__func__, chip->thresh);

	chip->clock_rate = CLOCK_RATE_MAX + 1;
	rc = of_property_read_u32(node, "qcom,clock-rate", &chip->clock_rate);
	if (!rc && (chip->clock_rate < CLOCK_RATE_MIN
		    || chip->clock_rate > CLOCK_RATE_MAX))
		dev_err(&spmi->dev,
			"%s: invalid qcom,clock-rate=%u specified\n", __func__,
			chip->clock_rate);

	chip->adc_type = QPNP_TM_ADC_NONE;
	rc = of_property_read_u32(node, "qcom,channel-num", &chip->adc_channel);
	if (!rc) {
@@ -577,13 +645,16 @@ static int qpnp_tm_probe(struct spmi_device *spmi)
	type = raw_type[0];
	subtype = raw_type[1];

	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(&spmi->dev, "%s: invalid type=%02X or subtype=%02X register value\n",
			__func__, type, subtype);
		rc = -ENODEV;
		goto err_cancel_work;
	}

	chip->subtype = subtype;

	rc = qpnp_tm_init_reg(chip);
	if (rc) {
		dev_err(&spmi->dev, "%s: qpnp_tm_init_reg() failed, rc=%d\n",