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

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

Merge "power: qpnp-smbcharger: parallel: step reduce ICL by 100mA and rerun AICL"

parents b61b6622 e623120d
Loading
Loading
Loading
Loading
+245 −235
Original line number Diff line number Diff line
@@ -1719,96 +1719,6 @@ static int smbchg_get_min_parallel_current_ma(struct smbchg_chip *chip)
	return chip->parallel.min_current_thr_ma;
}

#define ICL_STS_1_REG			0x7
#define ICL_STS_2_REG			0x9
#define ICL_STS_MASK			0x1F
#define AICL_SUSP_BIT			BIT(6)
#define AICL_STS_BIT			BIT(5)
#define USBIN_SUSPEND_STS_BIT		BIT(3)
#define USBIN_ACTIVE_PWR_SRC_BIT	BIT(1)
#define DCIN_ACTIVE_PWR_SRC_BIT		BIT(0)
#define PARALLEL_REENABLE_TIMER_MS	30000
static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip)
{
	int min_current_thr_ma, rc, type;
	ktime_t kt_since_last_disable;
	u8 reg;

	if (!smbchg_parallel_en || !chip->parallel_charger_detected) {
		pr_smb(PR_STATUS, "Parallel charging not enabled\n");
		return false;
	}

	kt_since_last_disable = ktime_sub(ktime_get_boottime(),
					chip->parallel.last_disabled);
	if (chip->parallel.current_max_ma == 0
		&& chip->parallel.enabled_once
		&& ktime_to_ms(kt_since_last_disable)
			< PARALLEL_REENABLE_TIMER_MS) {
		pr_smb(PR_STATUS, "Only been %lld since disable, skipping\n",
				ktime_to_ms(kt_since_last_disable));
		return false;
	}

	if (get_prop_charge_type(chip) != POWER_SUPPLY_CHARGE_TYPE_FAST) {
		pr_smb(PR_STATUS, "Not in fast charge, skipping\n");
		return false;
	}

	if (get_prop_batt_health(chip) != POWER_SUPPLY_HEALTH_GOOD) {
		pr_smb(PR_STATUS, "JEITA active, skipping\n");
		return false;
	}

	rc = smbchg_read(chip, &reg, chip->misc_base + IDEV_STS, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't read status 5 rc = %d\n", rc);
		return false;
	}

	type = get_type(reg);
	if (get_usb_supply_type(type) == POWER_SUPPLY_TYPE_USB_CDP) {
		pr_smb(PR_STATUS, "CDP adapter, skipping\n");
		return false;
	}

	if (get_usb_supply_type(type) == POWER_SUPPLY_TYPE_USB) {
		pr_smb(PR_STATUS, "SDP adapter, skipping\n");
		return false;
	}

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_2_REG, 1);
	if (rc) {
		dev_err(chip->dev, "Could not read usb icl sts 2: %d\n", rc);
		return false;
	}

	/*
	 * If USBIN is suspended or not the active power source, do not enable
	 * parallel charging. The device may be charging off of DCIN.
	 */
	if (!!(reg & USBIN_SUSPEND_STS_BIT) ||
				!(reg & USBIN_ACTIVE_PWR_SRC_BIT)) {
		pr_smb(PR_STATUS, "USB not active power source: %02x\n", reg);
		return false;
	}

	min_current_thr_ma = smbchg_get_min_parallel_current_ma(chip);
	if (min_current_thr_ma <= 0) {
		pr_smb(PR_STATUS, "parallel charger unavailable for thr: %d\n",
				min_current_thr_ma);
		return false;
	}
	if (chip->usb_tl_current_ma < min_current_thr_ma) {
		pr_smb(PR_STATUS, "Weak USB chg skip enable: %d < %d\n",
			chip->usb_tl_current_ma, min_current_thr_ma);
		return false;
	}

	return true;
}

#define FCC_CFG			0xF2
#define FCC_500MA_VAL		0x4
#define FCC_MASK		SMB_MASK(4, 0)
@@ -1871,6 +1781,17 @@ static int smbchg_set_fastchg_current(struct smbchg_chip *chip,
	return rc;
}

#define ICL_STS_1_REG			0x7
#define ICL_STS_2_REG			0x9
#define ICL_STS_MASK			0x1F
#define AICL_SUSP_BIT			BIT(6)
#define AICL_STS_BIT			BIT(5)
#define USBIN_SUSPEND_STS_BIT		BIT(3)
#define USBIN_ACTIVE_PWR_SRC_BIT	BIT(1)
#define DCIN_ACTIVE_PWR_SRC_BIT		BIT(0)
#define PARALLEL_REENABLE_TIMER_MS	30000
#define PARALLEL_CHG_THRESHOLD_CURRENT	1800

static int smbchg_parallel_usb_charging_en(struct smbchg_chip *chip, bool en)
{
	struct power_supply *parallel_psy = get_parallel_psy(chip);
@@ -1937,6 +1858,43 @@ static void taper_irq_en(struct smbchg_chip *chip, bool en)
	mutex_unlock(&chip->taper_irq_lock);
}

static bool smbchg_is_aicl_complete(struct smbchg_chip *chip)
{
	int rc;
	u8 reg;

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_1_REG, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Could not read usb icl sts 1: %d\n", rc);
		return true;
	}
	return (reg & AICL_STS_BIT) != 0;
}

static int smbchg_get_aicl_level_ma(struct smbchg_chip *chip)
{
	int rc;
	u8 reg;

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_1_REG, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Could not read usb icl sts 1: %d\n", rc);
		return 0;
	}
	if (reg & AICL_SUSP_BIT) {
		pr_warn("AICL suspended: %02x\n", reg);
		return 0;
	}
	reg &= ICL_STS_MASK;
	if (reg >= chip->tables.usb_ilim_ma_len) {
		pr_warn("invalid AICL value: %02x\n", reg);
		return 0;
	}
	return chip->tables.usb_ilim_ma_table[reg];
}

static void smbchg_parallel_usb_disable(struct smbchg_chip *chip)
{
	struct power_supply *parallel_psy = get_parallel_psy(chip);
@@ -2023,78 +1981,197 @@ done:
	smbchg_relax(chip, PM_PARALLEL_TAPER);
}

static bool smbchg_is_aicl_complete(struct smbchg_chip *chip)
static void smbchg_parallel_usb_enable(struct smbchg_chip *chip,
		int total_current_ma)
{
	int rc;
	u8 reg;
	struct power_supply *parallel_psy = get_parallel_psy(chip);
	union power_supply_propval pval = {0, };
	int new_parallel_cl_ma, rc;
	int current_table_index;

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_1_REG, 1);
	if (rc) {
		dev_err(chip->dev, "Could not read usb icl sts 1: %d\n", rc);
		return true;
	if (!parallel_psy || !chip->parallel_charger_detected)
		return;

	pr_smb(PR_STATUS, "Attempting to enable parallel charger\n");

	rc = power_supply_set_voltage_limit(parallel_psy, chip->vfloat_mv + 50);
	if (rc < 0) {
		dev_err(chip->dev,
			"Couldn't set Vflt on parallel psy rc: %d\n", rc);
		return;
	}
	return (reg & AICL_STS_BIT) != 0;
	/*
	 * set the primary charger to the set point closest to 40% of the fcc
	 * while remaining below it
	 */
	current_table_index = find_smaller_in_array(
			chip->tables.usb_ilim_ma_table,
			chip->cfg_fastchg_current_ma
				* chip->parallel.main_chg_fcc_percent / 100,
			chip->tables.usb_ilim_ma_len);
	chip->target_fastchg_current_ma =
		chip->tables.usb_ilim_ma_table[current_table_index];
	smbchg_set_fastchg_current(chip, chip->target_fastchg_current_ma);
	pr_smb(PR_STATUS, "main chg %%=%d, requested=%d, found=%d\n",
			chip->parallel.main_chg_fcc_percent,
			chip->cfg_fastchg_current_ma
				* chip->parallel.main_chg_fcc_percent / 100,
			chip->target_fastchg_current_ma);

	/* allow the parallel charger to use the remaining available fcc */
	pval.intval = (chip->cfg_fastchg_current_ma
			- chip->target_fastchg_current_ma) * 1000;
	parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);

	pr_smb(PR_STATUS, "FCC = %d[%d, %d]\n",
			chip->cfg_fastchg_current_ma,
			chip->target_fastchg_current_ma,
			chip->cfg_fastchg_current_ma
			- chip->target_fastchg_current_ma);

	chip->parallel.enabled_once = true;

	/* Set USB ICL */
	new_parallel_cl_ma = total_current_ma / 2;

	if (chip->parallel.current_max_ma == new_parallel_cl_ma) {
		pr_smb(PR_STATUS,
			"Skipping since Total USB current %d [%d, %d] didn't change from last time\n",
			total_current_ma, new_parallel_cl_ma,
			new_parallel_cl_ma);
		return;
	}

static int smbchg_get_aicl_level_ma(struct smbchg_chip *chip)
	/*
	 * if the total current is decreasing then reduce it by few mA instead
	 * of directly setting it to the lower current
	 */
	if (new_parallel_cl_ma <= chip->parallel.current_max_ma) {
		total_current_ma = 2 * chip->parallel.current_max_ma;
		total_current_ma -= 100;
		new_parallel_cl_ma = total_current_ma / 2;
	}

	pr_smb(PR_STATUS, "New Total USB current = %d[%d, %d]\n",
		total_current_ma, new_parallel_cl_ma,
		new_parallel_cl_ma);

	taper_irq_en(chip, true);
	chip->parallel.current_max_ma = new_parallel_cl_ma;
	power_supply_set_present(parallel_psy, true);
	smbchg_set_usb_current_max(chip, chip->parallel.current_max_ma);
	power_supply_set_current_limit(parallel_psy,
				chip->parallel.current_max_ma * 1000);

	if (smbchg_get_aicl_level_ma(chip) <  chip->parallel.current_max_ma) {
		/* allow for the current from parallel and main to settle */
		msleep(500);
		smbchg_rerun_aicl(chip);
	}
	return;
}

static bool smbchg_is_parallel_usb_ok(struct smbchg_chip *chip,
		int *ret_total_current_ma)
{
	int rc;
	struct power_supply *parallel_psy = get_parallel_psy(chip);
	int min_current_thr_ma, rc, type;
	int total_current_ma, current_limit_ma, parallel_cl_ma;
	ktime_t kt_since_last_disable;
	u8 reg;

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_1_REG, 1);
	if (rc) {
		dev_err(chip->dev, "Could not read usb icl sts 1: %d\n", rc);
		return 0;
	if (!parallel_psy || !smbchg_parallel_en
			|| !chip->parallel_charger_detected) {
		pr_smb(PR_STATUS, "Parallel charging not enabled\n");
		return false;
	}
	if (reg & AICL_SUSP_BIT) {
		pr_warn("AICL suspended: %02x\n", reg);
		return 0;

	kt_since_last_disable = ktime_sub(ktime_get_boottime(),
					chip->parallel.last_disabled);
	if (chip->parallel.current_max_ma == 0
		&& chip->parallel.enabled_once
		&& ktime_to_ms(kt_since_last_disable)
			< PARALLEL_REENABLE_TIMER_MS) {
		pr_smb(PR_STATUS, "Only been %lld since disable, skipping\n",
				ktime_to_ms(kt_since_last_disable));
		return false;
	}
	reg &= ICL_STS_MASK;
	if (reg >= chip->tables.usb_ilim_ma_len) {
		pr_warn("invalid AICL value: %02x\n", reg);
		return 0;

	if (get_prop_charge_type(chip) != POWER_SUPPLY_CHARGE_TYPE_FAST) {
		pr_smb(PR_STATUS, "Not in fast charge, skipping\n");
		return false;
	}
	return chip->tables.usb_ilim_ma_table[reg];

	if (get_prop_batt_health(chip) != POWER_SUPPLY_HEALTH_GOOD) {
		pr_smb(PR_STATUS, "JEITA active, skipping\n");
		return false;
	}

#define PARALLEL_CHG_THRESHOLD_CURRENT	1800
static void smbchg_parallel_usb_enable(struct smbchg_chip *chip)
{
	struct power_supply *parallel_psy = get_parallel_psy(chip);
	union power_supply_propval pval = {0, };
	int current_limit_ma, parallel_cl_ma, total_current_ma;
	int new_parallel_cl_ma, min_current_thr_ma, rc;
	int current_table_index;
	rc = smbchg_read(chip, &reg, chip->misc_base + IDEV_STS, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Couldn't read status 5 rc = %d\n", rc);
		return false;
	}

	if (!parallel_psy || !chip->parallel_charger_detected)
		return;
	type = get_type(reg);
	if (get_usb_supply_type(type) == POWER_SUPPLY_TYPE_USB_CDP) {
		pr_smb(PR_STATUS, "CDP adapter, skipping\n");
		return false;
	}

	pr_smb(PR_STATUS, "Attempting to enable parallel charger\n");
	/* Suspend the parallel charger if the charging current is < 1800 mA */
	if (chip->cfg_fastchg_current_ma < PARALLEL_CHG_THRESHOLD_CURRENT) {
		pr_smb(PR_STATUS, "suspend parallel charger as FCC is %d\n",
			chip->cfg_fastchg_current_ma);
		goto disable_parallel;
	if (get_usb_supply_type(type) == POWER_SUPPLY_TYPE_USB) {
		pr_smb(PR_STATUS, "SDP adapter, skipping\n");
		return false;
	}

	rc = smbchg_read(chip, &reg,
			chip->usb_chgpth_base + ICL_STS_2_REG, 1);
	if (rc < 0) {
		dev_err(chip->dev, "Could not read usb icl sts 2: %d\n", rc);
		return false;
	}

	/*
	 * If USBIN is suspended or not the active power source, do not enable
	 * parallel charging. The device may be charging off of DCIN.
	 */
	if (!!(reg & USBIN_SUSPEND_STS_BIT) ||
				!(reg & USBIN_ACTIVE_PWR_SRC_BIT)) {
		pr_smb(PR_STATUS, "USB not active power source: %02x\n", reg);
		return false;
	}

	min_current_thr_ma = smbchg_get_min_parallel_current_ma(chip);
	if (min_current_thr_ma <= 0) {
		pr_smb(PR_STATUS, "parallel charger unavailable for thr: %d\n",
				min_current_thr_ma);
		goto disable_parallel;
		return false;
	}

	if (chip->usb_tl_current_ma < min_current_thr_ma) {
		pr_smb(PR_STATUS, "Weak USB chg skip enable: %d < %d\n",
			chip->usb_tl_current_ma, min_current_thr_ma);
		return false;
	}

	/* Suspend the parallel charger if the charging current is < 1800 mA */
	if (chip->cfg_fastchg_current_ma < PARALLEL_CHG_THRESHOLD_CURRENT) {
		pr_smb(PR_STATUS, "FCC %d lower than %d\n",
			chip->cfg_fastchg_current_ma,
			PARALLEL_CHG_THRESHOLD_CURRENT);
		return false;
	}

	current_limit_ma = smbchg_get_aicl_level_ma(chip);
	if (current_limit_ma <= 0)
		goto disable_parallel;
		return false;

	if (chip->parallel.initial_aicl_ma == 0) {
		if (current_limit_ma < min_current_thr_ma) {
			pr_smb(PR_STATUS, "Initial AICL very low: %d < %d\n",
				current_limit_ma, min_current_thr_ma);
			goto disable_parallel;
			return false;
		}
		chip->parallel.initial_aicl_ma = current_limit_ma;
	}
@@ -2116,85 +2193,16 @@ static void smbchg_parallel_usb_enable(struct smbchg_chip *chip)
	if (total_current_ma < chip->parallel.initial_aicl_ma
			- chip->parallel.allowed_lowering_ma) {
		pr_smb(PR_STATUS,
			"Too little total current : %d (%d + %d) < %d - %d\n",
			"Total current reduced a lot: %d (%d + %d) < %d - %d\n",
			total_current_ma,
			current_limit_ma, parallel_cl_ma,
			chip->parallel.initial_aicl_ma,
			chip->parallel.allowed_lowering_ma);
		goto disable_parallel;
	}

	rc = power_supply_set_voltage_limit(parallel_psy, chip->vfloat_mv + 50);
	if (rc) {
		dev_err(chip->dev, "Couldn't set float voltage on parallel psy rc: %d\n",
			rc);
		goto disable_parallel;
	}
	/*
	 * set the primary charger to the set point closest to 40% of the fcc
	 * while remaining below it
	 */
	current_table_index = find_smaller_in_array(
			chip->tables.usb_ilim_ma_table,
			chip->cfg_fastchg_current_ma
				* chip->parallel.main_chg_fcc_percent / 100,
			chip->tables.usb_ilim_ma_len);
	chip->target_fastchg_current_ma =
		chip->tables.usb_ilim_ma_table[current_table_index];
	smbchg_set_fastchg_current(chip, chip->target_fastchg_current_ma);
	pr_smb(PR_STATUS, "main chg %%=%d, requested=%d, found=%d\n",
			chip->parallel.main_chg_fcc_percent,
			chip->cfg_fastchg_current_ma
				* chip->parallel.main_chg_fcc_percent / 100,
			chip->target_fastchg_current_ma);

	/* allow the parallel charger to use the remaining available fcc */
	pval.intval = (chip->cfg_fastchg_current_ma
			- chip->target_fastchg_current_ma) * 1000;
	parallel_psy->set_property(parallel_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);

	chip->parallel.enabled_once = true;
	new_parallel_cl_ma = total_current_ma / 2;

	if (new_parallel_cl_ma == parallel_cl_ma) {
		pr_smb(PR_STATUS,
			"AICL at %d, old ICL: %d new ICL: %d, skipping\n",
			current_limit_ma, parallel_cl_ma, new_parallel_cl_ma);
		return;
	} else {
		pr_smb(PR_STATUS, "AICL at %d, old ICL: %d new ICL: %d\n",
			current_limit_ma, parallel_cl_ma, new_parallel_cl_ma);
		return false;
	}

	taper_irq_en(chip, true);
	chip->parallel.current_max_ma = new_parallel_cl_ma;
	power_supply_set_present(parallel_psy, true);
	smbchg_set_usb_current_max(chip, chip->parallel.current_max_ma);
	power_supply_set_current_limit(parallel_psy,
				chip->parallel.current_max_ma * 1000);
	return;

disable_parallel:
	if (chip->parallel.current_max_ma != 0) {
		pr_smb(PR_STATUS, "disabling parallel charger\n");
		smbchg_parallel_usb_disable(chip);
	} else if (chip->cfg_fastchg_current_ma !=
			chip->target_fastchg_current_ma) {
		/* There is a possibility that parallel charging is enabled
		 * and a weak charger is connected, AICL result will be
		 * lower than the min_current_thr_ma. In those cases, we
		 * should fall back to configure the FCC of main charger.
		 */
		rc = smbchg_set_fastchg_current(chip,
				chip->cfg_fastchg_current_ma);
		if (rc)
			pr_err("Couldn't set fastchg current rc: %d\n",
				rc);
		else
			chip->target_fastchg_current_ma =
				chip->cfg_fastchg_current_ma;
	}
	*ret_total_current_ma = total_current_ma;
	return true;
}

static void smbchg_parallel_usb_en_work(struct work_struct *work)
@@ -2202,11 +2210,12 @@ static void smbchg_parallel_usb_en_work(struct work_struct *work)
	struct smbchg_chip *chip = container_of(work,
				struct smbchg_chip,
				parallel_en_work.work);
	int total_current_ma;

	smbchg_relax(chip, PM_PARALLEL_CHECK);
	mutex_lock(&chip->parallel.lock);
	if (smbchg_is_parallel_usb_ok(chip)) {
		smbchg_parallel_usb_enable(chip);
	if (smbchg_is_parallel_usb_ok(chip, &total_current_ma)) {
		smbchg_parallel_usb_enable(chip, total_current_ma);
	} else if (chip->parallel.current_max_ma != 0) {
		pr_smb(PR_STATUS, "parallel charging unavailable\n");
		smbchg_parallel_usb_disable(chip);
@@ -2218,19 +2227,28 @@ static void smbchg_parallel_usb_en_work(struct work_struct *work)
static void smbchg_parallel_usb_check_ok(struct smbchg_chip *chip)
{
	struct power_supply *parallel_psy = get_parallel_psy(chip);
	bool in_progress;
	int total_current_ma;

	if (!parallel_psy || !chip->parallel_charger_detected)
		return;
	mutex_lock(&chip->parallel.lock);
	if (smbchg_is_parallel_usb_ok(chip)) {
	in_progress = (chip->parallel.current_max_ma != 0);
	if (smbchg_is_parallel_usb_ok(chip, &total_current_ma)) {
		if (!in_progress) {
			smbchg_stay_awake(chip, PM_PARALLEL_CHECK);
			schedule_delayed_work(
				&chip->parallel_en_work,
				msecs_to_jiffies(PARALLEL_CHARGER_EN_DELAY_MS));
	} else if (chip->parallel.current_max_ma != 0) {
		} else {
			smbchg_parallel_usb_enable(chip, total_current_ma);
		}
	} else {
		if (in_progress) {
			pr_smb(PR_STATUS, "parallel charging unavailable\n");
			smbchg_parallel_usb_disable(chip);
		}
	}
	mutex_unlock(&chip->parallel.lock);
}

@@ -2250,29 +2268,21 @@ static int smbchg_set_fastchg_current_user(struct smbchg_chip *chip,
{
	int rc = 0;

	mutex_lock(&chip->parallel.lock);
	pr_smb(PR_STATUS, "User setting FCC to %d\n", current_ma);
	chip->cfg_fastchg_current_ma = current_ma;
	if (smbchg_is_parallel_usb_ok(chip)) {
		smbchg_parallel_usb_enable(chip);
	} else {
		if (chip->parallel.current_max_ma != 0) {
			/*
			 * If parallel charging is not available, disable it.
			 * FCC for main charger will be configured in that.
			 */
			pr_smb(PR_STATUS, "parallel charging unavailable\n");
			smbchg_parallel_usb_disable(chip);
			goto out;
		}

	if (chip->parallel.current_max_ma == 0) {
		rc = smbchg_set_fastchg_current(chip,
				chip->cfg_fastchg_current_ma);
		if (rc)
			pr_err("Couldn't set fastchg current rc: %d\n",
				rc);
		if (rc < 0)
			pr_err("Couldn't set fastchg current rc: %d\n", rc);
	}
out:
	mutex_unlock(&chip->parallel.lock);
	/*
	 * check if parallel charging can be enabled, and if enabled,
	 * distribute the fcc
	 */
	smbchg_parallel_usb_check_ok(chip);

	return rc;
}