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

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

Merge "drivers: thermal: qpnp-temp-alarm: Use of-thermal interface" into msm-4.9

parents a461cc69 5bca648d
Loading
Loading
Loading
Loading
+38 −6
Original line number Diff line number Diff line
@@ -12,10 +12,17 @@ Required properties:
- interrupts:      PMIC temperature alarm interrupt
- label:           A string used as a descriptive name for this thermal device.
		    This name should be 19 characters or less.
- #thermal-sensor-cells: Must be 0. Please refer to
			 <devicetree/bindings/thermal/thermal.txt> for more
			 details.

Required structure:
- A qcom,qpnp-temp-alarm node must be a child of an SPMI node that has specified
   the spmi-slave-container property
- A top level device tree node named "thermal-zones" must exist. It must
   contain a subnode with a property named "thermal-sensors" which is assigned
   a phandle to the qpnp-temp-alarm device node. See
   <devicetree/bindings/thermal/thermal.txt> for more details.

Optional properties:
- qcom,channel-num:    VADC channel number associated PMIC DIE_TEMP thermistor.
@@ -38,11 +45,6 @@ Optional properties:
			 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
			stage 3 over temperature shutdowns.  Otherwise, software
			is not allowed to override automatic shutdown.
- qcom,default-temp:   Specifies the default temperature in millicelcius to use
			if no ADC channel is present to read the real time
			temperature.
@@ -64,7 +66,7 @@ Example:
		#address-cells = <1>;
		#size-cells = <1>;

		qcom,temp-alarm@2400 {
		pm8941_tz: qcom,temp-alarm@2400 {
			compatible = "qcom,qpnp-temp-alarm";
			reg = <0x2400 0x100>;
			interrupts = <0x0 0x24 0x0>;
@@ -72,6 +74,36 @@ Example:
			qcom,channel-num = <8>;
			qcom,threshold-set = <0>;
			qcom,temp_alarm-vadc = <&pm8941_vadc>;
			#thermal-sensor-cells = <0>;
		};
	};
};

Below is an example thermal zone definition for the temperature alarm
peripheral.
thermal-zones {
	pm8941_tz {
		polling-delay-passive = <0>;
		polling-delay = <0>;
		thermal-governor = "step_wise";
		thermal-sensors = <&pm8941_tz>;

		trips {
			pm8941-trip0 {
				temperature = <105000>;
				hysteresis = <0>;
				type = "passive";
			};
			pm8941-trip1 {
				temperature = <125000>;
				hysteresis = <0>;
				type = "passive";
			};
			pm8941-trip2 {
				temperature = <145000>;
				hysteresis = <0>;
				type = "critical";
			};
		};
	};
};
+14 −203
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
#include <linux/thermal.h>
#include <linux/qpnp/qpnp-adc.h>

#include "thermal_core.h"

#define QPNP_TM_DRIVER_NAME "qcom,qpnp-temp-alarm"

enum qpnp_tm_registers {
@@ -97,7 +99,6 @@ struct qpnp_tm_chip {
	unsigned int			subtype;
	enum qpnp_tm_adc_type		adc_type;
	int				temperature;
	enum thermal_device_mode	mode;
	unsigned int			thresh;
	unsigned int			clock_rate;
	unsigned int			stage;
@@ -105,18 +106,12 @@ struct qpnp_tm_chip {
	int				irq;
	enum qpnp_vadc_channels		adc_channel;
	u16				base_addr;
	bool				allow_software_override;
	struct qpnp_vadc_chip		*vadc_dev;
};

/* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
#define STATUS_REGISTER_DELAY_MS       40

enum pmic_thermal_override_mode {
	SOFTWARE_OVERRIDE_DISABLED = 0,
	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};

@@ -156,28 +151,6 @@ static inline int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 *buf,
	return rc;
}


static inline int qpnp_tm_shutdown_override(struct qpnp_tm_chip *chip,
			    enum pmic_thermal_override_mode mode)
{
	int rc = 0;
	u8 reg;

	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
				| SHUTDOWN_CTRL1_OVERRIDE_STAGE3;

		rc = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg, 1);
	}

	return rc;
}

static int qpnp_tm_update_temp(struct qpnp_tm_chip *chip)
{
	struct qpnp_vadc_result adc_result;
@@ -274,10 +247,9 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip)
	return 0;
}

static int qpnp_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
				     int *temperature)
static int qpnp_tz_get_temp_no_adc(void *data, int *temperature)
{
	struct qpnp_tm_chip *chip = thermal->devdata;
	struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
	int rc;

	if (!temperature)
@@ -292,10 +264,9 @@ static int qpnp_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
	return 0;
}

static int qpnp_tz_get_temp_qpnp_adc(struct thermal_zone_device *thermal,
				      int *temperature)
static int qpnp_tz_get_temp_qpnp_adc(void *data, int *temperature)
{
	struct qpnp_tm_chip *chip = thermal->devdata;
	struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
	int rc;

	if (!temperature)
@@ -314,121 +285,12 @@ static int qpnp_tz_get_temp_qpnp_adc(struct thermal_zone_device *thermal,
	return 0;
}

static int qpnp_tz_get_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode *mode)
{
	struct qpnp_tm_chip *chip = thermal->devdata;

	if (!mode)
		return -EINVAL;

	*mode = chip->mode;

	return 0;
}

static int qpnp_tz_set_mode(struct thermal_zone_device *thermal,
			      enum thermal_device_mode mode)
{
	struct qpnp_tm_chip *chip = thermal->devdata;
	int rc = 0;

	if (mode != chip->mode) {
		if (mode == THERMAL_DEVICE_ENABLED)
			rc = qpnp_tm_shutdown_override(chip,
				SOFTWARE_OVERRIDE_ENABLED);
		else
			rc = qpnp_tm_shutdown_override(chip,
				SOFTWARE_OVERRIDE_DISABLED);

		chip->mode = mode;
	}

	return rc;
}

static int qpnp_tz_get_trip_type(struct thermal_zone_device *thermal,
				   int trip, enum thermal_trip_type *type)
{
	if (trip < 0 || !type)
		return -EINVAL;

	switch (trip) {
	case TRIP_STAGE3:
		*type = THERMAL_TRIP_CRITICAL;
		break;
	case TRIP_STAGE2:
		*type = THERMAL_TRIP_HOT;
		break;
	case TRIP_STAGE1:
		*type = THERMAL_TRIP_HOT;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int qpnp_tz_get_trip_temp(struct thermal_zone_device *thermal,
				   int trip, int *temperature)
{
	struct qpnp_tm_chip *chip = thermal->devdata;
	int thresh_temperature;

	if (trip < 0 || !temperature)
		return -EINVAL;

	thresh_temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN;

	switch (trip) {
	case TRIP_STAGE3:
		thresh_temperature += 2 * TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE2:
		thresh_temperature += TEMP_STAGE_STEP;
		break;
	case TRIP_STAGE1:
		break;
	default:
		return -EINVAL;
	}

	*temperature = thresh_temperature;

	return 0;
}

static int qpnp_tz_get_crit_temp(struct thermal_zone_device *thermal,
				   int *temperature)
{
	struct qpnp_tm_chip *chip = thermal->devdata;

	if (!temperature)
		return -EINVAL;

	*temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
		2 * TEMP_STAGE_STEP;

	return 0;
}

static struct thermal_zone_device_ops qpnp_thermal_zone_ops_no_adc = {
static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_no_adc = {
	.get_temp = qpnp_tz_get_temp_no_adc,
	.get_mode = qpnp_tz_get_mode,
	.set_mode = qpnp_tz_set_mode,
	.get_trip_type = qpnp_tz_get_trip_type,
	.get_trip_temp = qpnp_tz_get_trip_temp,
	.get_crit_temp = qpnp_tz_get_crit_temp,
};

static struct thermal_zone_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
	.get_temp = qpnp_tz_get_temp_qpnp_adc,
	.get_mode = qpnp_tz_get_mode,
	.set_mode = qpnp_tz_set_mode,
	.get_trip_type = qpnp_tz_get_trip_type,
	.get_trip_temp = qpnp_tz_get_trip_temp,
	.get_crit_temp = qpnp_tz_get_crit_temp,
};

static void qpnp_tm_work(struct work_struct *work)
@@ -474,11 +336,7 @@ static void qpnp_tm_work(struct work_struct *work)
				chip->tm_name, stage_new, chip->stage,
				chip->thresh, chip->temperature);

		thermal_zone_device_update(chip->tz_dev,
						THERMAL_EVENT_UNSPECIFIED);

		/* Notify user space */
		sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
		of_thermal_handle_trip(chip->tz_dev);
	}

bail:
@@ -539,7 +397,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
	struct device_node *node;
	unsigned int base;
	struct qpnp_tm_chip *chip;
	struct thermal_zone_device_ops *tz_ops;
	struct thermal_zone_of_device_ops *tz_ops;
	char *tm_name;
	u32 default_temperature;
	int rc = 0;
@@ -640,9 +498,6 @@ static int qpnp_tm_probe(struct platform_device *pdev)
	else
		tz_ops = &qpnp_thermal_zone_ops_no_adc;

	chip->allow_software_override
		= of_property_read_bool(node, "qcom,allow-override");

	default_temperature = DEFAULT_NO_ADC_TEMP;
	rc = of_property_read_u32(node, "qcom,default-temp",
					&default_temperature);
@@ -686,18 +541,8 @@ static int qpnp_tm_probe(struct platform_device *pdev)
		}
	}

	/* Start in HW control; switch to SW control when user changes mode. */
	chip->mode = THERMAL_DEVICE_DISABLED;
	rc = qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
	if (rc) {
		dev_err(&pdev->dev,
			"%s: qpnp_tm_shutdown_override() failed, rc=%d\n",
			__func__, rc);
		goto err_cancel_work;
	}

	chip->tz_dev = thermal_zone_device_register(tm_name, TRIP_NUM, 0, chip,
			tz_ops, NULL, 0, 0);
	chip->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
							tz_ops);
	if (chip->tz_dev == NULL) {
		dev_err(&pdev->dev,
			"%s: thermal_zone_device_register() failed.\n",
@@ -717,7 +562,7 @@ static int qpnp_tm_probe(struct platform_device *pdev)
	return 0;

err_free_tz:
	thermal_zone_device_unregister(chip->tz_dev);
	thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
err_cancel_work:
	cancel_delayed_work_sync(&chip->irq_work);
	kfree(chip->tm_name);
@@ -731,10 +576,9 @@ static int qpnp_tm_remove(struct platform_device *pdev)
{
	struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev);

	thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
	dev_set_drvdata(&pdev->dev, NULL);
	thermal_zone_device_unregister(chip->tz_dev);
	kfree(chip->tm_name);
	qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
	free_irq(chip->irq, chip);
	cancel_delayed_work_sync(&chip->irq_work);
	kfree(chip);
@@ -742,38 +586,6 @@ static int qpnp_tm_remove(struct platform_device *pdev)
	return 0;
}

#ifdef CONFIG_PM
static int qpnp_tm_suspend(struct device *dev)
{
	struct qpnp_tm_chip *chip = dev_get_drvdata(dev);

	/* Clear override bits in suspend to allow hardware control */
	qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);

	return 0;
}

static int qpnp_tm_resume(struct device *dev)
{
	struct qpnp_tm_chip *chip = dev_get_drvdata(dev);

	/* Override hardware actions so software can control */
	if (chip->mode == THERMAL_DEVICE_ENABLED)
		qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);

	return 0;
}

static const struct dev_pm_ops qpnp_tm_pm_ops = {
	.suspend = qpnp_tm_suspend,
	.resume = qpnp_tm_resume,
};

#define QPNP_TM_PM_OPS	(&qpnp_tm_pm_ops)
#else
#define QPNP_TM_PM_OPS	NULL
#endif

static const struct of_device_id qpnp_tm_match_table[] = {
	{ .compatible = QPNP_TM_DRIVER_NAME, },
	{}
@@ -789,7 +601,6 @@ static struct platform_driver qpnp_tm_driver = {
		.name		= QPNP_TM_DRIVER_NAME,
		.of_match_table	= qpnp_tm_match_table,
		.owner		= THIS_MODULE,
		.pm		= QPNP_TM_PM_OPS,
	},
	.probe	  = qpnp_tm_probe,
	.remove	  = qpnp_tm_remove,