Loading Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt +8 −0 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/thermal/qpnp-temp-alarm.c +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 Loading Loading @@ -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 Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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, ®, 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, ®, 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; Loading @@ -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, ®, 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; } Loading Loading @@ -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, ®, 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); Loading @@ -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, ®, 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, ®, 1); if (rc < 0) return rc; Loading Loading @@ -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) { Loading Loading @@ -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", Loading Loading
Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt +8 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/thermal/qpnp-temp-alarm.c +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 Loading Loading @@ -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 Loading @@ -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 Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 Loading @@ -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, ®, 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, ®, 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; Loading @@ -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, ®, 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; } Loading Loading @@ -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, ®, 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); Loading @@ -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, ®, 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, ®, 1); if (rc < 0) return rc; Loading Loading @@ -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) { Loading Loading @@ -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", Loading