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

Commit 44ee2b90 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: smb5: Add support for thermal throttling"

parents aeb3a5c3 7f6791c7
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -451,6 +451,11 @@ static struct device_attribute power_supply_attrs[] = {
	POWER_SUPPLY_ATTR(cc_soc),
	POWER_SUPPLY_ATTR(batt_age_level),
	POWER_SUPPLY_ATTR(scale_mode_en),
	POWER_SUPPLY_ATTR(voltage_vph),
	POWER_SUPPLY_ATTR(chip_version),
	POWER_SUPPLY_ATTR(therm_icl_limit),
	POWER_SUPPLY_ATTR(dc_reset),
	POWER_SUPPLY_ATTR(voltage_max_limit),
	/* Charge pump properties */
	POWER_SUPPLY_ATTR(cp_status1),
	POWER_SUPPLY_ATTR(cp_status2),
+11 −8
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#define DRV_MAJOR_VERSION	1
#define DRV_MINOR_VERSION	0

#define BATT_PROFILE_VOTER		"BATT_PROFILE_VOTER"
#define CHG_STATE_VOTER			"CHG_STATE_VOTER"
#define TAPER_STEPPER_VOTER		"TAPER_STEPPER_VOTER"
#define TAPER_END_VOTER			"TAPER_END_VOTER"
@@ -571,11 +572,12 @@ static void pl_taper_work(struct work_struct *work)
						pl_taper_work);
	union power_supply_propval pval = {0, };
	int rc;
	int eff_fcc_ua;
	int total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0;
	int fcc_ua, total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0;

	chip->taper_entry_fv = get_effective_result(chip->fv_votable);
	chip->taper_work_running = true;
	fcc_ua = get_client_vote(chip->fcc_votable, BATT_PROFILE_VOTER);
	vote(chip->fcc_votable, TAPER_STEPPER_VOTER, true, fcc_ua);
	while (true) {
		if (get_effective_result(chip->pl_disable_votable)) {
			/*
@@ -624,21 +626,22 @@ static void pl_taper_work(struct work_struct *work)

		chip->charge_type = pval.intval;
		if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
			eff_fcc_ua = get_effective_result(chip->fcc_votable);
			if (eff_fcc_ua < 0) {
			fcc_ua = get_client_vote(chip->fcc_votable,
					TAPER_STEPPER_VOTER);
			if (fcc_ua < 0) {
				pr_err("Couldn't get fcc, exiting taper work\n");
				goto done;
			}
			eff_fcc_ua = eff_fcc_ua - TAPER_REDUCTION_UA;
			if (eff_fcc_ua < 0) {
			fcc_ua -= TAPER_REDUCTION_UA;
			if (fcc_ua < 0) {
				pr_err("Can't reduce FCC any more\n");
				goto done;
			}

			pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing FCC to %dua\n",
					eff_fcc_ua);
					fcc_ua);
			vote(chip->fcc_votable, TAPER_STEPPER_VOTER,
					true, eff_fcc_ua);
					true, fcc_ua);
		} else {
			pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
		}
+52 −9
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ struct smb_dt_props {
	int			auto_recharge_soc;
	int			auto_recharge_vbat_mv;
	int			wd_bark_time;
	int			wd_snarl_time_cfg;
	int			batt_profile_fcc_ua;
	int			batt_profile_fv_uv;
	int			term_current_src;
@@ -448,6 +449,11 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node)
	if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
		chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;

	rc = of_property_read_u32(node, "qcom,wd-snarl-time-config",
					&chip->dt.wd_snarl_time_cfg);
	if (rc < 0)
		chip->dt.wd_snarl_time_cfg = -EINVAL;

	chip->dt.no_battery = of_property_read_bool(node,
						"qcom,batteryless-platform");

@@ -724,6 +730,8 @@ static enum power_supply_property smb5_usb_props[] = {
	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
	POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED,
	POWER_SUPPLY_PROP_QC_OPTI_DISABLE,
	POWER_SUPPLY_PROP_VOLTAGE_VPH,
	POWER_SUPPLY_PROP_THERM_ICL_LIMIT,
};

static int smb5_usb_get_prop(struct power_supply *psy,
@@ -845,6 +853,13 @@ static int smb5_usb_get_prop(struct power_supply *psy,
		if (chg->hw_connector_mitigation)
			val->intval |= POWER_SUPPLY_QC_CTM_DISABLE;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_VPH:
		rc = smblib_get_prop_vph_voltage_now(chg, val);
		break;
	case POWER_SUPPLY_PROP_THERM_ICL_LIMIT:
		val->intval = get_client_vote(chg->usb_icl_votable,
					THERMAL_THROTTLE_VOTER);
		break;
	default:
		pr_err("get prop %d is not supported in usb\n", psp);
		rc = -EINVAL;
@@ -865,7 +880,7 @@ static int smb5_usb_set_prop(struct power_supply *psy,
{
	struct smb5 *chip = power_supply_get_drvdata(psy);
	struct smb_charger *chg = &chip->chg;
	int rc = 0;
	int icl, rc = 0;

	switch (psp) {
	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
@@ -909,6 +924,14 @@ static int smb5_usb_set_prop(struct power_supply *psy,
		chg->connector_health = val->intval;
		power_supply_changed(chg->usb_psy);
		break;
	case POWER_SUPPLY_PROP_THERM_ICL_LIMIT:
		icl = get_effective_result(chg->usb_icl_votable);
		if ((icl + val->intval) > 0)
			rc = vote(chg->usb_icl_votable, THERMAL_THROTTLE_VOTER,
					true, icl + val->intval);
		else
			rc = -EINVAL;
		break;
	default:
		pr_err("set prop %d is not supported\n", psp);
		rc = -EINVAL;
@@ -924,6 +947,7 @@ static int smb5_usb_prop_is_writeable(struct power_supply *psy,
	switch (psp) {
	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
	case POWER_SUPPLY_PROP_THERM_ICL_LIMIT:
		return 1;
	default:
		break;
@@ -1890,9 +1914,18 @@ static int smb5_configure_typec(struct smb_charger *chg)
	rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
		USBIN_IN_COLLAPSE_GF_SEL_MASK | USBIN_AICL_STEP_TIMING_SEL_MASK,
		0);
	if (rc < 0)
	if (rc < 0) {
		dev_err(chg->dev,
			"Couldn't set USBIN_LOAD_CFG_REG rc=%d\n", rc);
		return rc;
	}

	/* Set CC threshold to 1.6 V in source mode */
	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
				SEL_SRC_UPPER_REF_BIT, SEL_SRC_UPPER_REF_BIT);
	if (rc < 0)
		dev_err(chg->dev,
			"Couldn't configure CC threshold voltage rc=%d\n", rc);

	return rc;
}
@@ -2324,7 +2357,8 @@ static int smb5_init_hw(struct smb5 *chip)
	 */
	if (chg->wa_flags & SW_THERM_REGULATION_WA) {
		rc = smblib_write(chg, MISC_THERMREG_SRC_CFG_REG,
					THERMREG_DIE_CMP_SRC_EN_BIT);
					THERMREG_SW_ICL_ADJUST_BIT
					| THERMREG_DIE_CMP_SRC_EN_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't disable HW thermal regulation rc=%d\n",
				rc);
@@ -2450,9 +2484,17 @@ static int smb5_init_hw(struct smb5 *chip)
	val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
			& BARK_WDOG_TIMEOUT_MASK;
	val |= (BITE_WDOG_TIMEOUT_8S | BITE_WDOG_DISABLE_CHARGING_CFG_BIT);

	if (chip->dt.wd_snarl_time_cfg == -EINVAL)
		val |= SNARL_WDOG_TMOUT_8S;
	else
		val |= (chip->dt.wd_snarl_time_cfg << SNARL_WDOG_TIMEOUT_SHIFT)
			& SNARL_WDOG_TIMEOUT_MASK;

	rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
			BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
			BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
			SNARL_WDOG_TIMEOUT_MASK | BARK_WDOG_TIMEOUT_MASK |
			BITE_WDOG_TIMEOUT_MASK,
			val);
	if (rc < 0) {
		pr_err("Couldn't configue WD config rc=%d\n", rc);
@@ -2956,13 +2998,14 @@ static int smb5_request_interrupts(struct smb5 *chip)
		chg->usb_icl_change_irq_enabled = true;

	/*
	 * WDOG_SNARL_IRQ is required for SW Thermal Regulation WA only. In
	 * case the WA is not required, disable the WDOG_SNARL_IRQ to prevent
	 * interrupt storm.
	 * WDOG_SNARL_IRQ is required for SW Thermal Regulation WA. In case
	 * the WA is not required and neither is the snarl timer configuration
	 * defined, disable the WDOG_SNARL_IRQ to prevent interrupt storm.
	 */

	if (chg->irq_info[WDOG_SNARL_IRQ].irq && !(chg->wa_flags &
						SW_THERM_REGULATION_WA)) {
	if (chg->irq_info[WDOG_SNARL_IRQ].irq && (!(chg->wa_flags &
				SW_THERM_REGULATION_WA) &&
				chip->dt.wd_snarl_time_cfg == -EINVAL)) {
		disable_irq_wake(chg->irq_info[WDOG_SNARL_IRQ].irq);
		disable_irq_nosync(chg->irq_info[WDOG_SNARL_IRQ].irq);
	}
+23 −3
Original line number Diff line number Diff line
@@ -243,6 +243,7 @@ struct smb1355 {
	int			c_health;
	int			c_charger_temp_max;
	int			die_temp_deciDegC;
	int			suspended_usb_icl;
	bool			exit_die_temp;
	struct delayed_work	die_temp_work;
	bool			disabled;
@@ -589,6 +590,7 @@ static int smb1355_get_prop_health(struct smb1355 *chip, int type)
}

#define MIN_PARALLEL_ICL_UA		250000
#define SUSPEND_CURRENT_UA		2000
static int smb1355_parallel_get_prop(struct power_supply *psy,
				     enum power_supply_property prop,
				     union power_supply_propval *val)
@@ -665,11 +667,16 @@ static int smb1355_parallel_get_prop(struct power_supply *psy,
			val->intval = 0;
		break;
	case POWER_SUPPLY_PROP_CURRENT_MAX:
		if (IS_USBIN(chip->dt.pl_mode))
		if (IS_USBIN(chip->dt.pl_mode)) {
			/* Report cached ICL until its configured correctly */
			if (chip->suspended_usb_icl)
				val->intval = chip->suspended_usb_icl;
			else
				rc = smb1355_get_charge_param(chip,
					&chip->param.usb_icl, &val->intval);
		else
		} else {
			val->intval = 0;
		}
		break;
	case POWER_SUPPLY_PROP_MIN_ICL:
		val->intval = MIN_PARALLEL_ICL_UA;
@@ -702,6 +709,18 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable)
	if (chip->disabled == disable)
		return 0;

	if (IS_USBIN(chip->dt.pl_mode)) {
		/*
		 * Initialize ICL configuration to minimum value while
		 * depending upon the set icl configuration method to properly
		 * configure the ICL value. At the same time, cache the value
		 * of ICL to be reported as 2mA.
		 */
		chip->suspended_usb_icl = SUSPEND_CURRENT_UA;
		smb1355_set_charge_param(chip,
				&chip->param.usb_icl, MIN_PARALLEL_ICL_UA);
	}

	rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT,
				 disable ? 0 : WDOG_TIMER_EN_BIT);
	if (rc < 0) {
@@ -770,6 +789,7 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr)

		rc = smb1355_set_charge_param(chip,
				&chip->param.usb_icl, curr);
		chip->suspended_usb_icl = 0;
	}

	return rc;
+87 −10
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/qpnp/qpnp-revid.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@@ -61,6 +62,10 @@
#define CORE_FTRIM_ILIM_REG		0x1030
#define CFG_ILIM_MASK			GENMASK(4, 0)

#define CORE_FTRIM_CTRL_REG		0x1031
#define TEMP_ALERT_LVL_MASK		GENMASK(6, 5)
#define TEMP_ALERT_LVL_SHIFT		5

#define CORE_FTRIM_LVL_REG		0x1033
#define CFG_WIN_HI_MASK			GENMASK(3, 2)
#define WIN_OV_LVL_1000MV		0x08
@@ -85,6 +90,8 @@
#define SRC_VOTER		"SRC_VOTER"
#define SWITCHER_TOGGLE_VOTER	"SWITCHER_TOGGLE_VOTER"

#define THERMAL_SUSPEND_DECIDEGC	1400

#define smb1390_dbg(chip, reason, fmt, ...)				\
	do {								\
		if (chip->debug_mask & (reason))			\
@@ -130,6 +137,7 @@ struct smb1390 {
	struct notifier_block	nb;
	struct wakeup_source	*cp_ws;
	struct dentry		*dfs_root;
	struct pmic_revid_data	*pmic_rev_id;

	/* work structs */
	struct work_struct	status_change_work;
@@ -161,6 +169,8 @@ struct smb1390 {
	int			die_temp;
	bool			suspended;
	u32			debug_mask;
	u32			min_ilim_ua;
	u32			max_temp_alarm_degc;
};

struct smb_irq {
@@ -493,8 +503,8 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data,
		return rc;
	}

	/* ILIM less than 1A is not accurate; disable charging */
	if (ilim_uA < 1000000) {
	/* ILIM less than min_ilim_ua, disable charging */
	if (ilim_uA < chip->min_ilim_ua) {
		smb1390_dbg(chip, PR_INFO, "ILIM %duA is too low to allow charging\n",
			ilim_uA);
		vote(chip->disable_votable, ILIM_VOTER, true, 0);
@@ -660,7 +670,7 @@ static void smb1390_taper_work(struct work_struct *work)
				fcc_uA);
			vote(chip->fcc_votable, CP_VOTER, true, fcc_uA);

			if (fcc_uA < 2000000) {
			if (fcc_uA < (chip->min_ilim_ua * 2)) {
				vote(chip->disable_votable, TAPER_END_VOTER,
								true, 0);
				goto out;
@@ -687,6 +697,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = {
	POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER,
	POWER_SUPPLY_PROP_CP_IRQ_STATUS,
	POWER_SUPPLY_PROP_CP_ILIM,
	POWER_SUPPLY_PROP_CHIP_VERSION,
};

static int smb1390_get_prop(struct power_supply *psy,
@@ -731,9 +742,24 @@ static int smb1390_get_prop(struct power_supply *psy,
			else
				rc = -ENODATA;
		} else {
			/*
			 * Add a filter to the die temp value read:
			 * If temp > THERMAL_SUSPEND_DECIDEGC then
			 *	- treat it as an error and report last valid
			 *	  cached temperature.
			 *	- return -ENODATA if the cached value is
			 *	  invalid.
			 */

			rc = smb1390_get_die_temp(chip, val);
			if (rc >= 0)
			if (rc >= 0) {
				if (val->intval <= THERMAL_SUSPEND_DECIDEGC)
					chip->die_temp = val->intval;
				else if (chip->die_temp == -ENODATA)
					rc = -ENODATA;
				else
					val->intval = chip->die_temp;
			}
		}
		break;
	case POWER_SUPPLY_PROP_CP_ISNS:
@@ -758,6 +784,9 @@ static int smb1390_get_prop(struct power_supply *psy,
			val->intval = ((status & CFG_ILIM_MASK) * 100000)
					+ 500000;
		break;
	case POWER_SUPPLY_PROP_CHIP_VERSION:
		val->intval = chip->pmic_rev_id->rev4;
		break;
	default:
		smb1390_dbg(chip, PR_MISC, "charge pump power supply get prop %d not supported\n",
			prop);
@@ -855,9 +884,19 @@ static int smb1390_parse_dt(struct smb1390 *chip)
			chip->iio.die_temp_chan = NULL;
			return rc;
		}
	} else {
		return rc;
	}

	return rc;
	chip->min_ilim_ua = 1000000; /* 1A */
	of_property_read_u32(chip->dev->of_node, "qcom,min-ilim-ua",
			&chip->min_ilim_ua);

	chip->max_temp_alarm_degc = 110;
	of_property_read_u32(chip->dev->of_node, "qcom,max-temp-alarm-degc",
			&chip->max_temp_alarm_degc);

	return 0;
}

static void smb1390_release_channels(struct smb1390 *chip)
@@ -903,7 +942,7 @@ static void smb1390_destroy_votables(struct smb1390 *chip)

static int smb1390_init_hw(struct smb1390 *chip)
{
	int rc;
	int rc = 0, val;

	/*
	 * Improve ILIM accuracy:
@@ -920,8 +959,25 @@ static int smb1390_init_hw(struct smb1390 *chip)
	if (rc < 0)
		return rc;

	switch (chip->max_temp_alarm_degc) {
	case 125:
		val = 0x00;
		break;
	case 95:
		val = 0x02;
		break;
	case 85:
		val = 0x03;
		break;
	case 110:
	default:
		val = 0x01;
		break;
	}
	rc = smb1390_masked_write(chip, CORE_FTRIM_CTRL_REG,
			TEMP_ALERT_LVL_MASK, val << TEMP_ALERT_LVL_SHIFT);

	return 0;
	return rc;
}

static int smb1390_get_irq_index_byname(const char *irq_name)
@@ -1023,8 +1079,28 @@ static void smb1390_create_debugfs(struct smb1390 *chip)
static int smb1390_probe(struct platform_device *pdev)
{
	struct smb1390 *chip;
	struct device_node *revid_dev_node;
	struct pmic_revid_data *pmic_rev_id;
	int rc;

	revid_dev_node = of_parse_phandle(pdev->dev.of_node,
					  "qcom,pmic-revid", 0);
	if (!revid_dev_node) {
		pr_err("Missing qcom,pmic-revid property\n");
		return -EINVAL;
	}

	pmic_rev_id = get_revid_data(revid_dev_node);
	of_node_put(revid_dev_node);
	if (IS_ERR_OR_NULL(pmic_rev_id)) {
		/*
		 * the revid peripheral must be registered, any failure
		 * here only indicates that the rev-id module has not
		 * probed yet.
		 */
		return -EPROBE_DEFER;
	}

	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
	if (!chip)
		return -ENOMEM;
@@ -1033,6 +1109,7 @@ static int smb1390_probe(struct platform_device *pdev)
	spin_lock_init(&chip->status_change_lock);
	mutex_init(&chip->die_chan_lock);
	chip->die_temp = -ENODATA;
	chip->pmic_rev_id = pmic_rev_id;
	platform_set_drvdata(pdev, chip);

	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
@@ -1087,8 +1164,8 @@ static int smb1390_probe(struct platform_device *pdev)

	smb1390_create_debugfs(chip);

	pr_debug("smb1390 probed successfully\n");

	pr_debug("smb1390 probed successfully chip_version=%d\n",
			chip->pmic_rev_id->rev4);
	return 0;

out_notifier:
Loading