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

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

Merge "power: smb1360: Implement Software JEITA"

parents 06cc4351 f59059c0
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -106,6 +106,27 @@ Optional Properties:
- qcom,min-icl-100ma		A bool property to set the minimum ICL current
				to 100mA. If this property is not set the minimum
				ICL is set to 500mA in all the scenarios.
- qcom,config-hard-thresholds	This property indicates if cold and hot thresholds need be modified.
				If it's not defined, default temp thresholds will be used. If this
				defined, it's required to specify the "qcom,hot-bat-decidegc" and
				"qcom,cold-bat-decidegc" values.
- qcom,hot-bat-decidegc		Hot battery temperature in decidegC. This property must be
				out of range [0, 55].
- qcom,cold-bat-decidegc	Cold battery temperature in decidegC. This property must be
				out of range [0, 55].
- qcom,soft-jeita-supported	This property indicates whether soft jeita supported.
- qcom,warm-bat-decidegc	Warm battery temperature in decidegC. After hitting this threshold,
				"qcom,warm-bat-ma" defines maximum charging current and
				"qcom,warm-bat-mv" defines maximum target voltage.
				This property must be in range [0, 55] if needed.
- qcom,cool-bat-decidegc	Cool battery temperature in decidegC. After hitting this threshold,
				"qcom,cool-bat-ma" defines maximum charging current and
				"qcom,cool-bat-mv" defines maximum target voltage.
				This property must be in range [0, 55] if needed.
- qcom,warm-bat-mv		Maximum warm battery target voltage in milli-volts.
- qcom,cool-bat-mv		Maximum cool battery target voltage in milli-volts.
- qcom,warm-bat-ma		Maximum warm battery charge current in milli-amps.
- qcom,cool-bat-ma		Maximum cool battery charge current in milli-amps.

Example:
	i2c@f9967000 {
@@ -143,6 +164,16 @@ Example:
			qcom,fg-soc-min = <15>;
			qcom,fg-auto-recharge-soc = <99>;
			qcom,thermal-mitigation = <1500 700 300 0>;
			qcom,config-hard-thresholds;
			qcom,hot-bat-decidegc = <650>;
			qcom,cold-bat-decidegc = <(-100)>;
			qcom,soft-jeita-supported;
			qcom,warm-bat-decidegc = <450>;
			qcom,cool-bat-decidegc = <100>;
			qcom,warm-bat-mv = <4100>;
			qcom,cool-bat-mv = <4100>;
			qcom,warm-bat-ma = <750>;
			qcom,cool-bat-ma = <750>;

			qcom,otg-batt-curr-limit = <950>;
		};
+396 −11
Original line number Diff line number Diff line
@@ -114,8 +114,15 @@
#define FASTCHG_CURR_MASK		SMB1360_MASK(4, 2)
#define FASTCHG_CURR_SHIFT		2

#define CHG_CMP_CFG			0x14
#define JEITA_COMP_CURR_MASK		SMB1360_MASK(3, 0)
#define JEITA_COMP_EN_MASK		SMB1360_MASK(7, 4)
#define JEITA_COMP_EN_SHIFT		4
#define JEITA_COMP_EN_BIT		SMB1360_MASK(7, 4)
#define BATT_CHG_FLT_VTG_REG		0x15
#define VFLOAT_MASK			SMB1360_MASK(6, 0)
#define CFG_FVC_REG			0x16
#define FLT_VTG_COMP_MASK		SMB1360_MASK(6, 0)

#define SHDN_CTRL_REG			0x1A
#define SHDN_CMD_USE_BIT		BIT(1)
@@ -189,6 +196,8 @@
#define SOC_MIN_REG			0x25
#define VTG_EMPTY_REG			0x26
#define SOC_DELTA_REG			0x28
#define JEITA_SOFT_COLD_REG		0x29
#define JEITA_SOFT_HOT_REG		0x2A
#define VTG_MIN_REG			0x2B

/* FG SHADOW registers */
@@ -221,6 +230,7 @@
#define CURRENT_100_MA			100
#define CURRENT_500_MA			500
#define MAX_8_BITS			255
#define JEITA_WORK_MS			3000

#define SMB1360_REV_1			0x01

@@ -228,6 +238,7 @@ enum {
	WRKRND_FG_CONFIG_FAIL = BIT(0),
	WRKRND_BATT_DET_FAIL = BIT(1),
	WRKRND_USB100_FAIL = BIT(2),
	WRKRND_HARD_JEITA = BIT(3),
};

enum {
@@ -257,6 +268,9 @@ struct smb1360_chip {
	struct i2c_client		*client;
	struct device			*dev;
	u8				revision;
	u8				soft_hot_rt_stat;
	u8				soft_cold_rt_stat;
	struct delayed_work		jeita_work;
	unsigned short			default_i2c_addr;
	unsigned short			fg_i2c_addr;
	bool				pulsed_irq;
@@ -269,6 +283,8 @@ struct smb1360_chip {
	bool				chg_inhibit_disabled;
	bool				iterm_disabled;
	bool				shdn_after_pwroff;
	bool				config_hard_thresholds;
	bool				soft_jeita_supported;
	int				iterm_ma;
	int				vfloat_mv;
	int				safety_time;
@@ -279,6 +295,16 @@ struct smb1360_chip {
	unsigned int			*thermal_mitigation;
	int				otg_batt_curr_limit;
	bool				min_icl_usb100;
	int				cold_bat_decidegc;
	int				hot_bat_decidegc;
	int				cool_bat_decidegc;
	int				warm_bat_decidegc;
	int				cool_bat_mv;
	int				warm_bat_mv;
	int				cool_bat_ma;
	int				warm_bat_ma;
	int				soft_cold_thresh;
	int				soft_hot_thresh;

	/* configuration data - fg */
	int				soc_max;
@@ -747,6 +773,20 @@ static int smb1360_charging_disable(struct smb1360_chip *chip, int reason,
	return rc;
}

static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip,
								bool enable)
{
	int rc = 0;

	rc = smb1360_masked_write(chip, CHG_CMP_CFG, JEITA_COMP_EN_MASK,
					enable ? JEITA_COMP_EN_BIT : 0);
	if (rc)
		pr_err("Couldn't %s JEITA compensation\n", enable ?
						"enable" : "disable");

	return rc;
}

static enum power_supply_property smb1360_battery_properties[] = {
	POWER_SUPPLY_PROP_HEALTH,
	POWER_SUPPLY_PROP_STATUS,
@@ -1041,6 +1081,13 @@ static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip)

	current_ma = min(therm_ma, path_current);

	if (chip->workaround_flags & WRKRND_HARD_JEITA) {
		if (chip->batt_warm)
			current_ma = min(current_ma, chip->warm_bat_ma);
		else if (chip->batt_cool)
			current_ma = min(current_ma, chip->cool_bat_ma);
	}

	if (current_ma <= 2) {
		/*
		 * SMB1360 does not support USB suspend -
@@ -1132,6 +1179,56 @@ static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip)
	return rc;
}

static int smb1360_set_jeita_comp_curr(struct smb1360_chip *chip,
							int current_ma)
{
	int i;
	int rc = 0;

	for (i = ARRAY_SIZE(fastchg_current) - 1; i >= 0; i--) {
		if (fastchg_current[i] <= current_ma)
			break;
	}
	if (i < 0) {
		pr_debug("Couldn't find fastchg_current %dmA\n", current_ma);
		i = 0;
	}

	rc = smb1360_masked_write(chip, CHG_CMP_CFG,
			JEITA_COMP_CURR_MASK, i);
	if (rc)
		pr_err("Couldn't configure for Icomp, rc = %d\n", rc);

	return rc;
}

#define TEMP_THRE_SET(x) ((x + 300) / 10)
static int smb1360_set_soft_jeita_threshold(struct smb1360_chip *chip,
					int cold_threshold, int hot_threshold)
{
	int rc = 0;

	rc = smb1360_write(chip, JEITA_SOFT_COLD_REG,
				TEMP_THRE_SET(cold_threshold));
	if (rc) {
		pr_err("Couldn't set cold threshold, rc = %d\n", rc);
		return rc;
	} else {
		chip->soft_cold_thresh = cold_threshold;
	}

	rc = smb1360_write(chip, JEITA_SOFT_HOT_REG,
				TEMP_THRE_SET(hot_threshold));
	if (rc) {
		pr_err("Couldn't set hot threshold, rc = %d\n", rc);
		return rc;
	} else {
		chip->soft_hot_thresh = hot_threshold;
	}

	return rc;
}

static int smb1360_system_temp_level_set(struct smb1360_chip *chip,
							int lvl_sel)
{
@@ -1330,17 +1427,130 @@ static int cold_hard_handler(struct smb1360_chip *chip, u8 rt_stat)
	return 0;
}

/*
 * This worker thread should only be called when WRKRND_HARD_JEITA
 * is set.
 * It is needed to re-program JEITA soft thresholds, compensate
 * target voltage and charging current manually.
 * The function is required as JEITA hard thresholds can't be programmed.
*/
static void smb1360_jeita_work_fn(struct work_struct *work)
{
	int temp;
	int rc = 0;
	struct delayed_work *dwork = to_delayed_work(work);
	struct smb1360_chip *chip = container_of(dwork, struct smb1360_chip,
							jeita_work);
	temp = smb1360_get_prop_batt_temp(chip);

	if (temp > chip->hot_bat_decidegc) {
		/* battery status is hot, only config thresholds */
		rc = smb1360_set_soft_jeita_threshold(chip,
			chip->warm_bat_decidegc, chip->hot_bat_decidegc);
		if (rc) {
			dev_err(chip->dev, "Couldn't set jeita threshold\n");
			goto end;
		}
	} else if (temp > chip->warm_bat_decidegc ||
		(temp == chip->warm_bat_decidegc && !!chip->soft_hot_rt_stat)) {
		/* battery status is warm, do compensation manually */
		chip->batt_warm = true;
		chip->batt_cool = false;
		rc = smb1360_float_voltage_set(chip, chip->warm_bat_mv);
		if (rc) {
			dev_err(chip->dev, "Couldn't set float voltage\n");
			goto end;
		}
		rc = smb1360_set_appropriate_usb_current(chip);
		if (rc)
			pr_err("Couldn't set USB current\n");
		rc = smb1360_set_soft_jeita_threshold(chip,
			chip->warm_bat_decidegc, chip->hot_bat_decidegc);
		if (rc) {
			dev_err(chip->dev, "Couldn't set jeita threshold\n");
			goto end;
		}
	} else if (temp > chip->cool_bat_decidegc ||
		(temp == chip->cool_bat_decidegc && !chip->soft_cold_rt_stat)) {
		/* battery status is good, do the normal charging */
		chip->batt_warm = false;
		chip->batt_cool = false;
		rc = smb1360_float_voltage_set(chip, chip->vfloat_mv);
		if (rc) {
			dev_err(chip->dev, "Couldn't set float voltage\n");
			goto end;
		}
		rc = smb1360_set_appropriate_usb_current(chip);
		if (rc)
			pr_err("Couldn't set USB current\n");
		rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cool_bat_decidegc, chip->warm_bat_decidegc);
		if (rc) {
			dev_err(chip->dev, "Couldn't set jeita threshold\n");
			goto end;
		}
	} else if (temp > chip->cold_bat_decidegc) {
		/* battery status is cool, do compensation manually */
		chip->batt_cool = true;
		chip->batt_warm = false;
		rc = smb1360_float_voltage_set(chip, chip->cool_bat_mv);
		if (rc) {
			dev_err(chip->dev, "Couldn't set float voltage\n");
			goto end;
		}
		rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cold_bat_decidegc, chip->cool_bat_decidegc);
		if (rc) {
			dev_err(chip->dev, "Couldn't set jeita threshold\n");
			goto end;
		}
	} else {
		/* battery status is cold, only config thresholds */
		rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cold_bat_decidegc, chip->cool_bat_decidegc);
		if (rc) {
			dev_err(chip->dev, "Couldn't set jeita threshold\n");
			goto end;
		}
	}

	pr_debug("warm %d, cool %d, soft_cold_rt_sts %d, soft_hot_rt_sts %d, jeita supported %d, threshold_now %d %d\n",
		chip->batt_warm, chip->batt_cool, !!chip->soft_cold_rt_stat,
		!!chip->soft_hot_rt_stat, chip->soft_jeita_supported,
		chip->soft_cold_thresh, chip->soft_hot_thresh);
end:
	pm_relax(chip->dev);
}

static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat)
{
	chip->soft_hot_rt_stat = rt_stat;
	pr_debug("rt_stat = 0x%02x\n", rt_stat);
	if (!chip->config_hard_thresholds)
		chip->batt_warm = !!rt_stat;

	if (chip->workaround_flags & WRKRND_HARD_JEITA) {
		cancel_delayed_work_sync(&chip->jeita_work);
		schedule_delayed_work(&chip->jeita_work,
					msecs_to_jiffies(JEITA_WORK_MS));
		pm_stay_awake(chip->dev);
	}
	return 0;
}

static int cold_soft_handler(struct smb1360_chip *chip, u8 rt_stat)
{
	chip->soft_cold_rt_stat = rt_stat;
	pr_debug("rt_stat = 0x%02x\n", rt_stat);
	if (!chip->config_hard_thresholds)
		chip->batt_cool = !!rt_stat;

	if (chip->workaround_flags & WRKRND_HARD_JEITA) {
		cancel_delayed_work_sync(&chip->jeita_work);
		schedule_delayed_work(&chip->jeita_work,
					msecs_to_jiffies(JEITA_WORK_MS));
		pm_stay_awake(chip->dev);
	}
	return 0;
}

@@ -2470,14 +2680,20 @@ static int determine_initial_status(struct smb1360_chip *chip)
		return rc;
	}

	if (chip->workaround_flags & WRKRND_HARD_JEITA) {
		schedule_delayed_work(&chip->jeita_work, 0);
	} else {
		if (reg & IRQ_A_HOT_HARD_BIT)
			chip->batt_hot = true;
		if (reg & IRQ_A_COLD_HARD_BIT)
			chip->batt_cold = true;
		if (!chip->config_hard_thresholds) {
			if (reg & IRQ_A_HOT_SOFT_BIT)
				chip->batt_warm = true;
			if (reg & IRQ_A_COLD_SOFT_BIT)
				chip->batt_cool = true;
		}
	}

	rc = smb1360_read(chip, IRQ_E_REG, &reg);
	if (rc < 0) {
@@ -2802,6 +3018,67 @@ static inline int smb1360_poweron(struct smb1360_chip *chip)
	return smb1360_enable(chip, true);
}

static int smb1360_jeita_init(struct smb1360_chip *chip)
{
	int rc = 0;
	int temp;

	if (chip->config_hard_thresholds) {
		if (chip->soft_jeita_supported) {
			chip->workaround_flags |= WRKRND_HARD_JEITA;
			rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cool_bat_decidegc, chip->warm_bat_decidegc);
			if (rc) {
				dev_err(chip->dev,
					"Couldn't set jeita threshold\n");
				return rc;
			}
		} else {
			rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cold_bat_decidegc, chip->hot_bat_decidegc);
			if (rc) {
				dev_err(chip->dev,
					"Couldn't set jeita threshold\n");
				return rc;
			}
		}
	} else {
		if (chip->soft_jeita_supported) {
			temp = min(chip->warm_bat_ma, chip->cool_bat_ma);
			rc = smb1360_set_jeita_comp_curr(chip, temp);
			if (rc) {
				dev_err(chip->dev, "Couldn't set comp current\n");
				return rc;
			}

			temp = (chip->vfloat_mv - chip->warm_bat_mv) / 10;
			rc = smb1360_masked_write(chip, CFG_FVC_REG,
					FLT_VTG_COMP_MASK, temp);
			if (rc < 0) {
				dev_err(chip->dev, "Couldn't set VFLT compensation = %d",
									rc);
				return rc;
			}

			rc = smb1360_set_soft_jeita_threshold(chip,
			chip->cool_bat_decidegc, chip->warm_bat_decidegc);
			if (rc) {
				dev_err(chip->dev,
					"Couldn't set jeita threshold\n");
				return rc;
			}

			rc = smb1360_soft_jeita_comp_enable(chip, true);
			if (rc) {
				dev_err(chip->dev, "Couldn't enable jeita\n");
				return rc;
			}
		}
	}

	return rc;
}

static int smb1360_hw_init(struct smb1360_chip *chip)
{
	int rc;
@@ -2989,6 +3266,12 @@ static int smb1360_hw_init(struct smb1360_chip *chip)
		return rc;
	}

	rc = smb1360_jeita_init(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't init jeita, rc = %d\n", rc);
		return rc;
	}

	/* interrupt enabling - active low */
	if (chip->client->irq) {
		mask = CHG_STAT_IRQ_ONLY_BIT
@@ -3162,6 +3445,99 @@ static int smb_parse_batt_id(struct smb1360_chip *chip)
	return 0;
}

/*
 * Note the below:
 * 1. if both qcom,soft-jeita-supported and qcom,config-hard-thresholds
 * are not defined, SMB continues with default OTP configuration.
 * 2. if both are enabled, the hard thresholds are modified.
 * 3. if only qcom,config-hard-thresholds is defined, the soft JEITA is disabled
 * 4. if only qcom,soft-jeita-supported is defined, the soft JEITA thresholds
 * are modified.
 */
static int smb1360_parse_jeita_params(struct smb1360_chip *chip)
{
	int rc = 0;
	struct device_node *node = chip->dev->of_node;

	if (of_property_read_bool(node, "qcom,config-hard-thresholds")) {
		rc = of_property_read_u32(node,
			"qcom,cold-bat-decidegc", &chip->cold_bat_decidegc);
		if (rc) {
			pr_err("cold_bat_decidegc property error, rc = %d\n",
								rc);
			return -EINVAL;
		}

		rc = of_property_read_u32(node,
			"qcom,hot-bat-decidegc", &chip->hot_bat_decidegc);
		if (rc) {
			pr_err("hot_bat_decidegc property error, rc = %d\n",
								rc);
			return -EINVAL;
		}

		chip->config_hard_thresholds = true;
		pr_debug("config_hard_thresholds = %d, cold_bat_decidegc = %d, hot_bat_decidegc = %d\n",
			chip->config_hard_thresholds, chip->cold_bat_decidegc,
			chip->hot_bat_decidegc);
	}

	if (of_property_read_bool(node, "qcom,soft-jeita-supported")) {
		rc = of_property_read_u32(node, "qcom,warm-bat-decidegc",
						&chip->warm_bat_decidegc);
		if (rc) {
			pr_err("warm_bat_decidegc property error, rc = %d\n",
								rc);
			return -EINVAL;
		}

		rc = of_property_read_u32(node, "qcom,cool-bat-decidegc",
						&chip->cool_bat_decidegc);
		if (rc) {
			pr_err("cool_bat_decidegc property error, rc = %d\n",
								rc);
			return -EINVAL;
		}
		rc = of_property_read_u32(node, "qcom,cool-bat-mv",
						&chip->cool_bat_mv);
		if (rc) {
			pr_err("cool_bat_mv property error, rc = %d\n", rc);
			return -EINVAL;
		}

		rc = of_property_read_u32(node, "qcom,warm-bat-mv",
						&chip->warm_bat_mv);
		if (rc) {
			pr_err("warm_bat_mv property error, rc = %d\n", rc);
			return -EINVAL;
		}

		rc = of_property_read_u32(node, "qcom,cool-bat-ma",
						&chip->cool_bat_ma);
		if (rc) {
			pr_err("cool_bat_ma property error, rc = %d\n", rc);
			return -EINVAL;
		}

		rc = of_property_read_u32(node, "qcom,warm-bat-ma",
						&chip->warm_bat_ma);

		if (rc) {
			pr_err("warm_bat_ma property error, rc = %d\n", rc);
			return -EINVAL;
		}

		chip->soft_jeita_supported = true;
	}

	pr_debug("soft-jeita-enabled = %d, warm-bat-decidegc = %d, cool-bat-decidegc = %d, cool-bat-mv = %d, warm-bat-mv = %d, cool-bat-ma = %d, warm-bat-ma = %d\n",
		chip->soft_jeita_supported, chip->warm_bat_decidegc,
		chip->cool_bat_decidegc, chip->cool_bat_mv, chip->warm_bat_mv,
		chip->cool_bat_ma, chip->warm_bat_ma);

	return rc;
}

static int smb_parse_dt(struct smb1360_chip *chip)
{
	int rc;
@@ -3250,6 +3626,12 @@ static int smb_parse_dt(struct smb1360_chip *chip)
		}
	}

	rc = smb1360_parse_jeita_params(chip);
	if (rc < 0) {
		pr_err("Couldn't parse jeita params, rc = %d\n", rc);
		return rc;
	}

	/* fg params */
	chip->empty_soc_disabled = of_property_read_bool(node,
						"qcom,empty-soc-disabled");
@@ -3349,6 +3731,7 @@ static int smb1360_probe(struct i2c_client *client,
	chip->usb_psy = usb_psy;
	chip->fake_battery_soc = -EINVAL;
	mutex_init(&chip->read_write_lock);
	INIT_DELAYED_WORK(&chip->jeita_work, smb1360_jeita_work_fn);

	/* probe the device to check if its actually connected */
	rc = smb1360_read(chip, CFG_BATT_CHG_REG, &reg);
@@ -3590,7 +3973,9 @@ static int smb1360_suspend(struct device *dev)
	}

	/* enable only important IRQs */
	rc = smb1360_write(chip, IRQ_CFG_REG, IRQ_DCIN_UV_BIT);
	rc = smb1360_write(chip, IRQ_CFG_REG, IRQ_DCIN_UV_BIT
						| IRQ_BAT_HOT_COLD_SOFT_BIT
						| IRQ_BAT_HOT_COLD_HARD_BIT);
	if (rc < 0)
		pr_err("Couldn't set irq_cfg rc=%d\n", rc);