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

Commit 6a781770 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: add api to force charger tlim"

parents bd75e2d4 7fead985
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -306,6 +306,7 @@
			qcom,cycle-counter-high-soc = <85>;
			qcom,capacity-learning-on;
			qcom,fg-cc-cv-threshold-mv = <4340>;
			qcom,pmic-revid = <&pmi8994_revid>;

			qcom,fg-soc@4000 {
				status = "okay";
@@ -455,7 +456,7 @@
				qcom,qpnp-lab-switching-clock-frequency = <1600>;
				qcom,qpnp-lab-limit-maximum-current = <800>;
				qcom,qpnp-lab-limit-max-current-enable;
				qcom,qpnp-lab-ps-threshold = <40>;
				qcom,qpnp-lab-ps-threshold = <20>;
				qcom,qpnp-lab-ps-enable;
				qcom,qpnp-lab-nfet-size = <100>;
				qcom,qpnp-lab-pfet-size = <100>;
+2 −2
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, 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
@@ -208,7 +208,7 @@ static void __exit qpnp_revid_exit(void)
	return spmi_driver_unregister(&qpnp_revid_driver);
}

module_init(qpnp_revid_init);
subsys_initcall(qpnp_revid_init);
module_exit(qpnp_revid_exit);

MODULE_DESCRIPTION("QPNP REVID DRIVER");
+1 −0
Original line number Diff line number Diff line
@@ -234,6 +234,7 @@ static struct device_attribute power_supply_attrs[] = {
	POWER_SUPPLY_ATTR(charge_done),
	POWER_SUPPLY_ATTR(allow_detection),
	POWER_SUPPLY_ATTR(flash_active),
	POWER_SUPPLY_ATTR(force_tlim),
	/* Local extensions of type int64_t */
	POWER_SUPPLY_ATTR(charge_counter_ext),
	/* Properties of type `const char *' */
+376 −160
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/of_batterydata.h>
#include <linux/string_helpers.h>
#include <linux/alarmtimer.h>
#include <linux/qpnp/qpnp-revid.h>

/* Register offsets */

@@ -92,6 +93,11 @@ enum dig_major {
	DIG_REV_8950_3 = 0x3,
};

enum pmic_subtype {
	PMI8994		= 10,
	PMI8950		= 17,
};

struct fg_mem_setting {
	u16	address;
	u8	offset;
@@ -229,6 +235,7 @@ module_param_named(
);

static int fg_sense_type = -EINVAL;
static int fg_restart;

static int fg_est_dump;
module_param_named(
@@ -240,6 +247,11 @@ module_param_named(
	battery_type, fg_batt_type, charp, S_IRUSR | S_IWUSR
);

static int fg_sram_update_period_ms = 30000;
module_param_named(
	sram_update_period_ms, fg_sram_update_period_ms, int, S_IRUSR | S_IWUSR
);

struct fg_irq {
	int			irq;
	unsigned long		disabled;
@@ -341,6 +353,7 @@ static void fg_relax(struct fg_wakeup_source *source)
struct fg_chip {
	struct device		*dev;
	struct spmi_device	*spmi;
	u8			pmic_subtype;
	u8			revision[4];
	u16			soc_base;
	u16			batt_base;
@@ -358,6 +371,7 @@ struct fg_chip {
	struct power_supply	bms_psy;
	struct mutex		rw_lock;
	struct mutex		cyc_ctr_lock;
	struct mutex		sysfs_restart_lock;
	struct work_struct	batt_profile_init;
	struct work_struct	dump_sram;
	struct work_struct	status_change_work;
@@ -366,6 +380,7 @@ struct fg_chip {
	struct work_struct	update_esr_work;
	struct work_struct	set_resume_soc_work;
	struct work_struct	rslow_comp_work;
	struct work_struct	sysfs_restart_work;
	struct power_supply	*batt_psy;
	struct power_supply	*usb_psy;
	struct power_supply	*dc_psy;
@@ -1835,7 +1850,6 @@ static int64_t twos_compliment_extend(int64_t val, int nbytes)
#define LSB_8B		9800
#define TEMP_LSB_16B	625
#define DECIKELVIN	2730
#define SRAM_PERIOD_UPDATE_MS		30000
#define SRAM_PERIOD_NO_ID_UPDATE_MS	100
#define FULL_PERCENT_28BIT		0xFFFFFFF
static void update_sram_data(struct fg_chip *chip, int *resched_ms)
@@ -1916,22 +1930,39 @@ static void update_sram_data(struct fg_chip *chip, int *resched_ms)

	if (battid_valid) {
		complete_all(&chip->batt_id_avail);
		*resched_ms = SRAM_PERIOD_UPDATE_MS;
		*resched_ms = fg_sram_update_period_ms;
	} else {
		*resched_ms = SRAM_PERIOD_NO_ID_UPDATE_MS;
	}
	fg_relax(&chip->update_sram_wakeup_source);
}

#define SRAM_TIMEOUT_MS			3000
static void update_sram_data_work(struct work_struct *work)
{
	struct fg_chip *chip = container_of(work,
				struct fg_chip,
				update_sram_data.work);
	int resched_ms;
	int resched_ms, ret;
	bool tried_again = false;

wait:
	/* Wait for MEMIF access revoked */
	ret = wait_for_completion_interruptible_timeout(
			&chip->sram_access_revoked,
			msecs_to_jiffies(SRAM_TIMEOUT_MS));

	/* If we were interrupted wait again one more time. */
	if (ret == -ERESTARTSYS && !tried_again) {
		tried_again = true;
		goto wait;
	} else if (ret <= 0) {
		pr_err("transaction timed out ret=%d\n", ret);
		goto out;
	}
	update_sram_data(chip, &resched_ms);

out:
	schedule_delayed_work(
		&chip->update_sram_data,
		msecs_to_jiffies(resched_ms));
@@ -1955,7 +1986,6 @@ static void update_temp_data(struct work_struct *work)

	fg_stay_awake(&chip->update_temp_wakeup_source);
	if (chip->sw_rbias_ctrl) {
		reinit_completion(&chip->sram_access_revoked);
		rc = fg_mem_masked_write(chip, EXTERNAL_SENSE_SELECT,
				BATT_TEMP_CNTRL_MASK,
				BATT_TEMP_ON,
@@ -3145,6 +3175,7 @@ static irqreturn_t fg_mem_avail_irq_handler(int irq, void *_chip)
		if ((fg_debug_mask & FG_IRQS)
				& (FG_MEM_DEBUG_READS | FG_MEM_DEBUG_WRITES))
			pr_info("sram access granted\n");
		reinit_completion(&chip->sram_access_revoked);
		complete_all(&chip->sram_access_granted);
	} else {
		if ((fg_debug_mask & FG_IRQS)
@@ -3560,24 +3591,175 @@ static void update_cc_cv_setpoint(struct fg_chip *chip)
			tmp[0], tmp[1], CC_CV_SETPOINT_REG);
}

#define V_PREDICTED_ADDR		0x540
#define V_CURRENT_PREDICTED_OFFSET	0
#define LOW_LATENCY			BIT(6)
#define PROFILE_LOAD_TIMEOUT_MS		5000
#define BATT_PROFILE_OFFSET		0x4C0
#define PROFILE_INTEGRITY_REG		0x53C
#define PROFILE_INTEGRITY_BIT		BIT(0)
#define FIRST_EST_DONE_BIT		BIT(5)
#define MAX_TRIES_FIRST_EST		3
#define FIRST_EST_WAIT_MS		2000
static int fg_do_restart(struct fg_chip *chip, bool write_profile)
{
	int rc;
	int tries = 0;
	u8 reg = 0;

	if (fg_debug_mask & FG_STATUS)
		pr_info("restarting fuel gauge...\n");
	/*
	 * release the sram access and configure the correct settings
	 * before re-requesting access.
	 */
	mutex_lock(&chip->rw_lock);
	fg_release_access(chip);

	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, 0, 1);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto unlock_and_fail;
	}

	/* unset the restart bits so the fg doesn't continuously restart */
	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, 0, 1);
	if (rc) {
		pr_err("failed to unset fg restart: %d\n", rc);
		goto unlock_and_fail;
	}

	rc = fg_masked_write(chip, MEM_INTF_CFG(chip),
			LOW_LATENCY, LOW_LATENCY, 1);
	if (rc) {
		pr_err("failed to set low latency access bit\n");
		goto unlock_and_fail;
	}
	mutex_unlock(&chip->rw_lock);

	/* read once to get a fg cycle in */
	rc = fg_mem_read(chip, &reg, PROFILE_INTEGRITY_REG, 1, 0, 0);
	if (rc) {
		pr_err("failed to read profile integrity rc=%d\n", rc);
		goto fail;
	}

	/*
	 * If this is not the first time a profile has been loaded, sleep for
	 * 3 seconds to make sure the NO_OTP_RELOAD is cleared in memory
	 */
	if (chip->first_profile_loaded)
		msleep(3000);

	mutex_lock(&chip->rw_lock);
	fg_release_access(chip);
	rc = fg_masked_write(chip, MEM_INTF_CFG(chip), LOW_LATENCY, 0, 1);
	if (rc) {
		pr_err("failed to set low latency access bit\n");
		goto unlock_and_fail;
	}

	atomic_add_return(1, &chip->memif_user_cnt);
	mutex_unlock(&chip->rw_lock);

	if (write_profile) {
		/* write the battery profile */
		rc = fg_mem_write(chip, chip->batt_profile, BATT_PROFILE_OFFSET,
				chip->batt_profile_len, 0, 1);
		if (rc) {
			pr_err("failed to write profile rc=%d\n", rc);
			goto sub_and_fail;
		}
		/* write the integrity bits and release access */
		rc = fg_mem_masked_write(chip, PROFILE_INTEGRITY_REG,
				PROFILE_INTEGRITY_BIT,
				PROFILE_INTEGRITY_BIT, 0);
		if (rc) {
			pr_err("failed to write profile rc=%d\n", rc);
			goto sub_and_fail;
		}
	}

	/* decrement the user count so that memory access can be released */
	fg_release_access_if_necessary(chip);
	/*
	 * set the restart bits so that the next fg cycle will not reload
	 * the profile
	 */
	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, NO_OTP_PROF_RELOAD, 1);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto fail;
	}

	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, reg, 1);
	if (rc) {
		pr_err("failed to set fg restart: %d\n", rc);
		goto fail;
	}

	/* wait for the first estimate to complete */
	for (tries = 0; tries < MAX_TRIES_FIRST_EST; tries++) {
		msleep(FIRST_EST_WAIT_MS);

		rc = fg_read(chip, &reg, INT_RT_STS(chip->soc_base), 1);
		if (rc) {
			pr_err("spmi read failed: addr=%03X, rc=%d\n",
					INT_RT_STS(chip->soc_base), rc);
		}
		if (reg & FIRST_EST_DONE_BIT)
			break;
		if (fg_debug_mask & FG_STATUS)
			pr_info("waiting for est, tries = %d\n", tries);
	}
	if ((reg & FIRST_EST_DONE_BIT) == 0)
		pr_err("Battery profile reloading failed, no first estimate\n");

	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, 0, 1);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto fail;
	}
	/* unset the restart bits so the fg doesn't continuously restart */
	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, 0, 1);
	if (rc) {
		pr_err("failed to unset fg restart: %d\n", rc);
		goto fail;
	}

	if (fg_debug_mask & FG_STATUS)
		pr_info("done!\n");
	return 0;

unlock_and_fail:
	mutex_unlock(&chip->rw_lock);
	goto fail;
sub_and_fail:
	fg_release_access_if_necessary(chip);
	goto fail;
fail:
	return -EINVAL;
}

#define V_PREDICTED_ADDR		0x540
#define V_CURRENT_PREDICTED_OFFSET	0
#define PROFILE_LOAD_TIMEOUT_MS		5000
#define FG_PROFILE_LEN			128
#define PROFILE_COMPARE_LEN		32
static int fg_batt_profile_init(struct fg_chip *chip)
{
	int rc = 0, ret;
	int len, tries;
	int len;
	struct device_node *node = chip->spmi->dev.of_node;
	struct device_node *batt_node, *profile_node;
	const char *data, *batt_type_str, *old_batt_type;
	bool tried_again = false, vbat_in_range;
	bool tried_again = false, vbat_in_range, profiles_same;
	u8 reg = 0;

wait:
@@ -3654,6 +3836,12 @@ wait:
		goto no_profile;
	}

	if (len != FG_PROFILE_LEN) {
		pr_err("battery profile incorrect size: %d\n", len);
		rc = -EINVAL;
		goto fail;
	}

	rc = of_property_read_string(profile_node, "qcom,battery-type",
					&batt_type_str);
	if (rc) {
@@ -3688,11 +3876,13 @@ wait:
	vbat_in_range = abs(fg_data[FG_DATA_VOLTAGE].value
				- fg_data[FG_DATA_CPRED_VOLTAGE].value)
				< settings[FG_MEM_VBAT_EST_DIFF].value * 1000;
	profiles_same = memcmp(chip->batt_profile, data,
					PROFILE_COMPARE_LEN) == 0;
	if (reg & PROFILE_INTEGRITY_BIT)
		fg_cap_learning_load_data(chip);
	if ((reg & PROFILE_INTEGRITY_BIT) && vbat_in_range
			&& !fg_is_batt_empty(chip)
			&& memcmp(chip->batt_profile, data, len - 4) == 0) {
			&& profiles_same) {
		if (fg_debug_mask & FG_STATUS)
			pr_info("Battery profiles same, using default\n");
		if (fg_est_dump)
@@ -3707,6 +3897,8 @@ wait:
				fg_data[FG_DATA_VOLTAGE].value);
	if ((fg_debug_mask & FG_STATUS) && fg_is_batt_empty(chip))
		pr_info("battery empty\n");
	if ((fg_debug_mask & FG_STATUS) && !profiles_same)
		pr_info("profiles differ\n");
	if (fg_debug_mask & FG_STATUS) {
		pr_info("Using new profile\n");
		print_hex_dump(KERN_INFO, "FG: loaded profile: ",
@@ -3727,131 +3919,12 @@ wait:
				DUMP_PREFIX_NONE, 16, 1, chip->batt_profile,
				chip->batt_profile_len, false);

	/*
	 * release the sram access and configure the correct settings
	 * before re-requesting access.
	 */
	mutex_lock(&chip->rw_lock);
	fg_release_access(chip);

	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, 0, 1);
	rc = fg_do_restart(chip, true);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto unlock_and_fail;
	}

	/* unset the restart bits so the fg doesn't continuously restart */
	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, 0, 1);
	if (rc) {
		pr_err("failed to unset fg restart: %d\n", rc);
		goto unlock_and_fail;
	}

	rc = fg_masked_write(chip, MEM_INTF_CFG(chip),
			LOW_LATENCY, LOW_LATENCY, 1);
	if (rc) {
		pr_err("failed to set low latency access bit\n");
		goto unlock_and_fail;
	}
	mutex_unlock(&chip->rw_lock);

	/* read once to get a fg cycle in */
	rc = fg_mem_read(chip, &reg, PROFILE_INTEGRITY_REG, 1, 0, 0);
	if (rc) {
		pr_err("failed to read profile integrity rc=%d\n", rc);
		pr_err("restart failed: %d\n", rc);
		goto fail;
	}

	/*
	 * If this is not the first time a profile has been loaded, sleep for
	 * 3 seconds to make sure the NO_OTP_RELOAD is cleared in memory
	 */
	if (chip->first_profile_loaded)
		msleep(3000);

	mutex_lock(&chip->rw_lock);
	fg_release_access(chip);
	rc = fg_masked_write(chip, MEM_INTF_CFG(chip), LOW_LATENCY, 0, 1);
	if (rc) {
		pr_err("failed to set low latency access bit\n");
		goto unlock_and_fail;
	}

	atomic_add_return(1, &chip->memif_user_cnt);
	mutex_unlock(&chip->rw_lock);

	/* write the battery profile */
	rc = fg_mem_write(chip, chip->batt_profile, BATT_PROFILE_OFFSET,
			chip->batt_profile_len, 0, 1);
	if (rc) {
		pr_err("failed to write profile rc=%d\n", rc);
		goto sub_and_fail;
	}

	/* write the integrity bits and release access */
	rc = fg_mem_masked_write(chip, PROFILE_INTEGRITY_REG,
			PROFILE_INTEGRITY_BIT, PROFILE_INTEGRITY_BIT, 0);
	if (rc) {
		pr_err("failed to write profile rc=%d\n", rc);
		goto sub_and_fail;
	}

	/* decrement the user count so that memory access can be released */
	fg_release_access_if_necessary(chip);
	/*
	 * set the restart bits so that the next fg cycle will reload
	 * the profile
	 */
	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, NO_OTP_PROF_RELOAD, 1);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto fail;
	}

	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, reg, 1);
	if (rc) {
		pr_err("failed to set fg restart: %d\n", rc);
		goto fail;
	}

	/* wait for the first estimate to complete */
	for (tries = 0; tries < MAX_TRIES_FIRST_EST; tries++) {
		msleep(FIRST_EST_WAIT_MS);

		rc = fg_read(chip, &reg, INT_RT_STS(chip->soc_base), 1);
		if (rc) {
			pr_err("spmi read failed: addr=%03X, rc=%d\n",
					INT_RT_STS(chip->soc_base), rc);
		}
		if (reg & FIRST_EST_DONE_BIT)
			break;
		else
			if (fg_debug_mask & FG_STATUS)
				pr_info("waiting for est, tries = %d\n", tries);
	}
	if ((reg & FIRST_EST_DONE_BIT) == 0)
		pr_err("Battery profile reloading failed, no first estimate\n");

	rc = fg_masked_write(chip, chip->soc_base + SOC_BOOT_MOD,
			NO_OTP_PROF_RELOAD, 0, 1);
	if (rc) {
		pr_err("failed to set no otp reload bit\n");
		goto fail;
	}
	/* unset the restart bits so the fg doesn't continuously restart */
	reg = REDO_FIRST_ESTIMATE | RESTART_GO;
	rc = fg_masked_write(chip, chip->soc_base + SOC_RESTART,
			reg, 0, 1);
	if (rc) {
		pr_err("failed to unset fg restart: %d\n", rc);
		goto fail;
	}
done:
	if (fg_batt_type)
		chip->batt_type = fg_batt_type;
@@ -3873,12 +3946,6 @@ done:
		power_supply_changed(&chip->bms_psy);
	fg_relax(&chip->profile_wakeup_source);
	return rc;
unlock_and_fail:
	mutex_unlock(&chip->rw_lock);
	goto fail;
sub_and_fail:
	fg_release_access_if_necessary(chip);
	goto fail;
fail:
	chip->batt_type = old_batt_type;
	if (chip->power_supply_registered)
@@ -3914,6 +3981,21 @@ static void batt_profile_init(struct work_struct *work)
		pr_err("failed to initialize profile\n");
}

static void sysfs_restart_work(struct work_struct *work)
{
	struct fg_chip *chip = container_of(work,
				struct fg_chip,
				sysfs_restart_work);
	int rc;

	rc = fg_do_restart(chip, false);
	if (rc)
		pr_err("fg restart failed: %d\n", rc);
	mutex_lock(&chip->sysfs_restart_lock);
	fg_restart = 0;
	mutex_unlock(&chip->sysfs_restart_lock);
}

static void update_bcl_thresholds(struct fg_chip *chip)
{
	u8 data[4];
@@ -4327,9 +4409,13 @@ static int fg_remove(struct spmi_device *spmi)
	cancel_work_sync(&chip->status_change_work);
	cancel_work_sync(&chip->cycle_count_work);
	cancel_work_sync(&chip->update_esr_work);
	cancel_work_sync(&chip->sysfs_restart_work);
	power_supply_unregister(&chip->bms_psy);
	mutex_destroy(&chip->rslow_comp.lock);
	mutex_destroy(&chip->rw_lock);
	mutex_destroy(&chip->cyc_ctr_lock);
	mutex_destroy(&chip->learning_data.learning_lock);
	mutex_destroy(&chip->sysfs_restart_lock);
	wakeup_source_trash(&chip->resume_soc_wakeup_source.source);
	wakeup_source_trash(&chip->empty_check_wakeup_source.source);
	wakeup_source_trash(&chip->memif_wakeup_source.source);
@@ -4805,27 +4891,16 @@ static int bcl_trim_workaround(struct fg_chip *chip)
#define FG_ADC_CONFIG_REG		0x4B8
#define FG_BCL_CONFIG_OFFSET		0x3
#define BCL_FORCED_HPM_IN_CHARGE	BIT(2)
static int fg_hw_init(struct fg_chip *chip)
static int fg_common_hw_init(struct fg_chip *chip)
{
	int rc;
	u8 resume_soc;
	u8 data[4];
	u64 esr_value;
	int rc = 0;

	update_iterm(chip);
	update_cutoff_voltage(chip);
	update_irq_volt_empty(chip);
	update_bcl_thresholds(chip);

	rc = fg_mem_masked_write(chip, EXTERNAL_SENSE_SELECT,
			PATCH_NEG_CURRENT_BIT,
			PATCH_NEG_CURRENT_BIT,
			EXTERNAL_SENSE_OFFSET);
	if (rc) {
		pr_err("failed to write patch current bit rc=%d\n", rc);
		return rc;
	}

	resume_soc = settings[FG_MEM_RESUME_SOC].value;
	if (resume_soc > 0) {
		resume_soc = resume_soc * 255 / 100;
@@ -4879,6 +4954,30 @@ static int fg_hw_init(struct fg_chip *chip)
		return rc;
	}

	if (chip->use_thermal_coefficients) {
		fg_mem_write(chip, chip->thermal_coefficients,
			THERMAL_COEFF_ADDR, THERMAL_COEFF_N_BYTES,
			THERMAL_COEFF_OFFSET, 0);
	}

	return 0;
}

static int fg_8994_hw_init(struct fg_chip *chip)
{
	int rc = 0;
	u8 data[4];
	u64 esr_value;

	rc = fg_mem_masked_write(chip, EXTERNAL_SENSE_SELECT,
			PATCH_NEG_CURRENT_BIT,
			PATCH_NEG_CURRENT_BIT,
			EXTERNAL_SENSE_OFFSET);
	if (rc) {
		pr_err("failed to write patch current bit rc=%d\n", rc);
		return rc;
	}

	rc = bcl_trim_workaround(chip);
	if (rc) {
		pr_err("failed to redo bcl trim rc=%d\n", rc);
@@ -4894,12 +4993,6 @@ static int fg_hw_init(struct fg_chip *chip)
		return rc;
	}

	if (chip->use_thermal_coefficients) {
		fg_mem_write(chip, chip->thermal_coefficients,
			THERMAL_COEFF_ADDR, THERMAL_COEFF_N_BYTES,
			THERMAL_COEFF_OFFSET, 0);
	}

	fg_mem_masked_write(chip, FG_ALG_SYSCTL_1, I_TERM_QUAL_BIT, 0, 0);

	data[0] = 0xA2;
@@ -4935,6 +5028,45 @@ static int fg_hw_init(struct fg_chip *chip)
	return 0;
}

static int fg_8950_hw_init(struct fg_chip *chip)
{
	int rc;

	rc = fg_mem_masked_write(chip, FG_ADC_CONFIG_REG,
			BCL_FORCED_HPM_IN_CHARGE,
			BCL_FORCED_HPM_IN_CHARGE,
			FG_BCL_CONFIG_OFFSET);
	if (rc)
		pr_err("failed to force hpm in charge rc=%d\n", rc);

	return rc;
}

static int fg_hw_init(struct fg_chip *chip)
{
	int rc = 0;

	rc = fg_common_hw_init(chip);
	if (rc) {
		pr_err("Unable to initialize FG HW rc=%d\n", rc);
		return rc;
	}

	/* add PMIC specific hw init */
	switch (chip->pmic_subtype) {
	case PMI8994:
		rc = fg_8994_hw_init(chip);
		break;
	case PMI8950:
		rc = fg_8950_hw_init(chip);
		break;
	}
	if (rc)
		pr_err("Unable to initialize PMIC specific FG HW rc=%d\n", rc);

	return rc;
}

#define DIG_MINOR		0x0
#define DIG_MAJOR		0x1
#define ANA_MINOR		0x2
@@ -4983,6 +5115,44 @@ static int fg_setup_memif_offset(struct fg_chip *chip)
	return 0;
}

static int fg_detect_pmic_type(struct fg_chip *chip)
{
	struct pmic_revid_data *pmic_rev_id;
	struct device_node *revid_dev_node;

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

	pmic_rev_id = get_revid_data(revid_dev_node);
	if (IS_ERR(pmic_rev_id)) {
		pr_err("Unable to get pmic_revid rc=%ld\n",
				PTR_ERR(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;
	}

	switch (pmic_rev_id->pmic_subtype) {
	case PMI8994:
	case PMI8950:
		chip->pmic_subtype = pmic_rev_id->pmic_subtype;
		break;
	default:
		pr_err("PMIC subtype %d not supported\n",
				pmic_rev_id->pmic_subtype);
		return -EINVAL;
	}

	return 0;
}

#define INIT_JEITA_DELAY_MS 1000
static int fg_probe(struct spmi_device *spmi)
{
@@ -5028,6 +5198,7 @@ static int fg_probe(struct spmi_device *spmi)
	mutex_init(&chip->cyc_ctr_lock);
	mutex_init(&chip->learning_data.learning_lock);
	mutex_init(&chip->rslow_comp.lock);
	mutex_init(&chip->sysfs_restart_lock);
	INIT_DELAYED_WORK(&chip->update_jeita_setting, update_jeita_setting);
	INIT_DELAYED_WORK(&chip->update_sram_data, update_sram_data_work);
	INIT_DELAYED_WORK(&chip->update_temp_work, update_temp_data);
@@ -5041,10 +5212,12 @@ static int fg_probe(struct spmi_device *spmi)
	INIT_WORK(&chip->battery_age_work, battery_age_work);
	INIT_WORK(&chip->update_esr_work, update_esr_value);
	INIT_WORK(&chip->set_resume_soc_work, set_resume_soc_work);
	INIT_WORK(&chip->sysfs_restart_work, sysfs_restart_work);
	alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME,
			fg_cap_learning_alarm_cb);
	init_completion(&chip->sram_access_granted);
	init_completion(&chip->sram_access_revoked);
	complete_all(&chip->sram_access_revoked);
	init_completion(&chip->batt_id_avail);
	dev_set_drvdata(&spmi->dev, chip);

@@ -5101,6 +5274,12 @@ static int fg_probe(struct spmi_device *spmi)
		}
	}

	rc = fg_detect_pmic_type(chip);
	if (rc) {
		pr_err("Unable to detect PMIC type rc=%d\n", rc);
		return rc;
	}

	rc = fg_setup_memif_offset(chip);
	if (rc) {
		pr_err("Unable to setup mem_if offsets rc=%d\n", rc);
@@ -5184,9 +5363,10 @@ static int fg_probe(struct spmi_device *spmi)
	if (!chip->use_otp_profile)
		schedule_work(&chip->batt_profile_init);

	pr_info("FG Probe success - FG Revision DIG:%d.%d ANA:%d.%d\n",
	pr_info("FG Probe success - FG Revision DIG:%d.%d ANA:%d.%d PMIC subtype=%d\n",
		chip->revision[DIG_MAJOR], chip->revision[DIG_MINOR],
		chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR]);
		chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR],
		chip->pmic_subtype);

	return rc;

@@ -5206,11 +5386,13 @@ cancel_work:
	cancel_work_sync(&chip->cycle_count_work);
	cancel_work_sync(&chip->update_esr_work);
	cancel_work_sync(&chip->rslow_comp_work);
	cancel_work_sync(&chip->sysfs_restart_work);
of_init_fail:
	mutex_destroy(&chip->rslow_comp.lock);
	mutex_destroy(&chip->rw_lock);
	mutex_destroy(&chip->cyc_ctr_lock);
	mutex_destroy(&chip->learning_data.learning_lock);
	mutex_destroy(&chip->sysfs_restart_lock);
	wakeup_source_trash(&chip->resume_soc_wakeup_source.source);
	wakeup_source_trash(&chip->empty_check_wakeup_source.source);
	wakeup_source_trash(&chip->memif_wakeup_source.source);
@@ -5238,7 +5420,7 @@ static void check_and_update_sram_data(struct fg_chip *chip)
		&chip->update_temp_work, msecs_to_jiffies(time_left * 1000));

	next_update_time = chip->last_sram_update_time
		+ (SRAM_PERIOD_UPDATE_MS / 1000);
		+ (fg_sram_update_period_ms / 1000);

	if (next_update_time > current_time)
		time_left = next_update_time - current_time;
@@ -5318,6 +5500,40 @@ static struct kernel_param_ops fg_sense_type_ops = {

module_param_cb(sense_type, &fg_sense_type_ops, &fg_sense_type, 0644);

static int fg_restart_set(const char *val, const struct kernel_param *kp)
{
	struct power_supply *bms_psy;
	struct fg_chip *chip;

	bms_psy = power_supply_get_by_name("bms");
	if (!bms_psy) {
		pr_err("bms psy not found\n");
		return 0;
	}
	chip = container_of(bms_psy, struct fg_chip, bms_psy);

	mutex_lock(&chip->sysfs_restart_lock);
	if (fg_restart != 0) {
		mutex_unlock(&chip->sysfs_restart_lock);
		return 0;
	}
	fg_restart = 1;
	mutex_unlock(&chip->sysfs_restart_lock);

	if (fg_debug_mask & FG_STATUS)
		pr_info("fuel gauge restart initiated from sysfs...\n");

	schedule_work(&chip->sysfs_restart_work);
	return 0;
}

static struct kernel_param_ops fg_restart_ops = {
	.set = fg_restart_set,
	.get = param_get_int,
};

module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);

static struct spmi_driver fg_driver = {
	.driver		= {
		.name	= QPNP_FG_DEV_NAME,
Loading