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

Commit bbf356f8 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 95944f26 ec717f7d
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",