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

Commit 38ee3747 authored by Anirudh Ghayal's avatar Anirudh Ghayal
Browse files

power: vm-bms: Process BMS data during suspend



There could be valid BMS data while going to suspend.
Store this data while entering suspend and process it
in resume. The data is rejected if a new OCV is generated
while suspended.

This fixes the scenarios where the device enters/exists
suspend/resume within the FIFO done IRQ timeline.

CRs-Fixed: 644991
Change-Id: I07b783782d78b61c522492d0d05b67d963411b4d
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent ee3babed
Loading
Loading
Loading
Loading
+107 −48
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ struct qpnp_bms_chip {
	u8				shutdown_soc;
	u16				last_ocv_raw;
	u32				shutdown_ocv;
	bool				suspend_data_valid;

	struct bms_battery_data		*batt_data;
	struct bms_dt_cfg		dt;
@@ -212,6 +213,7 @@ struct qpnp_bms_chip {
	struct mutex			bms_data_mutex;
	struct mutex			bms_device_mutex;
	struct mutex			last_soc_mutex;
	struct mutex			state_change_mutex;
	struct class			*bms_class;
	struct device			*bms_device;
	struct cdev			bms_cdev;
@@ -619,16 +621,16 @@ static int get_fifo_length(struct qpnp_bms_chip *chip,
	return 0;
}

static int update_fsm_state(struct qpnp_bms_chip *chip)
static int get_fsm_state(struct qpnp_bms_chip *chip, u8 *state)
{
	u8 val = 0;
	int rc;

	/*
	 * To read the STATUS1 register, write a value(any) to this register,
	 * wait for 10ms and then read the register.
	 */
	rc = qpnp_write_wrapper(chip, &val, chip->base + STATUS1_REG, 1);
	*state = 0;
	rc = qpnp_write_wrapper(chip, state, chip->base + STATUS1_REG, 1);
	if (rc) {
		pr_err("Unable to write STATUS1_REG rc=%d\n", rc);
		return rc;
@@ -636,16 +638,33 @@ static int update_fsm_state(struct qpnp_bms_chip *chip)
	usleep_range(10000, 11000);

	/* read the current FSM state */
	rc = qpnp_read_wrapper(chip, &val, chip->base + STATUS1_REG, 1);
	rc = qpnp_read_wrapper(chip, state, chip->base + STATUS1_REG, 1);
	if (rc) {
		pr_err("Unable to read STATUS1_REG rc=%d\n", rc);
		return rc;
	}
	val = (val & FSM_STATE_MASK) >> FSM_STATE_SHIFT;
	*state = (*state & FSM_STATE_MASK) >> FSM_STATE_SHIFT;

	chip->current_fsm_state = val;
	return rc;
}

	return 0;
static int update_fsm_state(struct qpnp_bms_chip *chip)
{
	u8 state = 0;
	int rc;

	mutex_lock(&chip->state_change_mutex);
	rc = get_fsm_state(chip, &state);
	if (rc) {
		pr_err("Unable to get fsm_state rc=%d\n", rc);
		goto fail_fsm;
	}

	chip->current_fsm_state = state;

fail_fsm:
	mutex_unlock(&chip->state_change_mutex);
	return rc;
}

static int lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp)
@@ -897,7 +916,9 @@ static void charging_began(struct qpnp_bms_chip *chip)

	if (chip->dt.cfg_force_s2_in_charging) {
		pr_debug("Forcing S2 state\n");
		mutex_lock(&chip->state_change_mutex);
		force_fsm_state(chip, S2_STATE);
		mutex_unlock(&chip->state_change_mutex);
	}
}

@@ -917,7 +938,9 @@ static void charging_ended(struct qpnp_bms_chip *chip)

	if (chip->dt.cfg_force_s2_in_charging) {
		pr_debug("Unforcing S2 state, setting AUTO\n");
		mutex_lock(&chip->state_change_mutex);
		set_auto_fsm_state(chip);
		mutex_unlock(&chip->state_change_mutex);
	}

	/*
@@ -1692,6 +1715,11 @@ static irqreturn_t bms_fifo_update_done_irq_handler(int irq, void *_chip)

	mutex_lock(&chip->bms_data_mutex);

	if (chip->suspend_data_valid) {
		pr_debug("Suspend data not processed yet\n");
		goto fail_fifo;
	}

	rc = calib_vadc(chip);
	if (rc)
		pr_err("Unable to calibrate vadc rc=%d\n", rc);
@@ -1746,6 +1774,11 @@ static irqreturn_t bms_fsm_state_change_irq_handler(int irq, void *_chip)

	mutex_lock(&chip->bms_data_mutex);

	if (chip->suspend_data_valid) {
		pr_debug("Suspend data not processed yet\n");
		goto fail_state;
	}

	rc = calib_vadc(chip);
	if (rc)
		pr_err("Unable to calibrate vadc rc=%d\n", rc);
@@ -2718,6 +2751,7 @@ static int qpnp_vm_bms_probe(struct spmi_device *spmi)
	mutex_init(&chip->bms_data_mutex);
	mutex_init(&chip->bms_device_mutex);
	mutex_init(&chip->last_soc_mutex);
	mutex_init(&chip->state_change_mutex);
	init_waitqueue_head(&chip->bms_wait_q);

	/* read battery-id and select the battery profile */
@@ -2863,11 +2897,41 @@ static int qpnp_vm_bms_remove(struct spmi_device *spmi)
	return 0;
}

static void process_suspended_data(struct qpnp_bms_chip *chip)
static void process_suspend_data(struct qpnp_bms_chip *chip)
{
	int rc;

	mutex_lock(&chip->bms_data_mutex);

	chip->suspend_data_valid = false;

	memset(&chip->bms_data, 0, sizeof(chip->bms_data));

	rc = read_and_populate_fifo_data(chip);
	if (rc)
		pr_err("Unable to read FIFO data rc=%d\n", rc);

	rc = read_and_populate_acc_data(chip);
	if (rc)
		pr_err("Unable to read ACC_SD data rc=%d\n", rc);

	rc = clear_fifo_acc_data(chip);
	if (rc)
		pr_err("Unable to clear FIFO/ACC data rc=%d\n", rc);

	if (chip->bms_data.num_fifo || chip->bms_data.acc_count) {
		pr_debug("suspend data valid\n");
		chip->suspend_data_valid = true;
	}

	mutex_unlock(&chip->bms_data_mutex);
}

static void process_resume_data(struct qpnp_bms_chip *chip)
{
	int rc, batt_temp = 0;
	int old_ocv = 0;
	bool update_data = false;
	bool ocv_updated = false;

	rc = get_batt_therm(chip, &batt_temp);
	if (rc < 0) {
@@ -2878,8 +2942,8 @@ static void process_suspended_data(struct qpnp_bms_chip *chip)

	mutex_lock(&chip->bms_data_mutex);
	/*
	 * We can only get a h/w OCV update when the sleep_b
	 * is low, which is possible only when APPS is suspended.
	 * We can get a h/w OCV update when the sleep_b
	 * is low, which is possible when APPS is suspended.
	 * So check for an OCV update only in bms_resume
	 */
	old_ocv = chip->last_ocv_uv;
@@ -2888,41 +2952,23 @@ static void process_suspended_data(struct qpnp_bms_chip *chip)
		pr_err("Unable to read/upadate OCV rc=%d\n", rc);

	if (old_ocv != chip->last_ocv_uv) {
		update_data = true;
		ocv_updated = true;
		/* new OCV, clear suspended data */
		chip->suspend_data_valid = false;
		memset(&chip->bms_data, 0, sizeof(chip->bms_data));
		chip->calculated_soc = lookup_soc_ocv(chip,
				chip->last_ocv_uv, batt_temp);
		pr_debug("New OCV in sleep - sleep_new_soc=%d\n",
					chip->calculated_soc);
		pr_debug("OCV in sleep SOC=%d\n", chip->calculated_soc);
		chip->last_soc_unbound = true;
		chip->voltage_soc_uv = chip->last_ocv_uv;
		pr_debug("update bms_psy\n");
		power_supply_changed(&chip->bms_psy);
	}

	memset(&chip->bms_data, 0, sizeof(chip->bms_data));

	/* Check if there is data to be sent */
	rc = read_and_populate_fifo_data(chip);
	if (rc)
		pr_err("Unable to read FIFO data rc=%d\n", rc);

	rc = read_and_populate_acc_data(chip);
	if (rc)
		pr_err("Unable to read ACC_SD data rc=%d\n", rc);

	rc = clear_fifo_acc_data(chip);
	if (rc)
		pr_err("Unable to clear FIFO/ACC data rc=%d\n", rc);

	rc = update_fsm_state(chip);
	if (rc)
		pr_err("Unable to read FSM state rc=%d\n", rc);

	if (chip->bms_data.num_fifo || chip->bms_data.acc_count)
		update_data = true;

	if (update_data) {
	if (ocv_updated || chip->suspend_data_valid) {
		/* there is data to be sent */
		pr_debug("ocv_updated=%d suspend_data_valid=%d\n",
				ocv_updated, chip->suspend_data_valid);
		chip->bms_data.seq_num = chip->seq_num++;
		dump_bms_data(__func__, chip);

@@ -2932,6 +2978,7 @@ static void process_suspended_data(struct qpnp_bms_chip *chip)
			pm_stay_awake(chip->dev);

	}
	chip->suspend_data_valid = false;
	mutex_unlock(&chip->bms_data_mutex);
}

@@ -2944,7 +2991,11 @@ static int bms_suspend(struct device *dev)
	if (!chip->charging_while_suspended) {
		if (chip->dt.cfg_force_s3_on_suspend) {
			pr_debug("Forcing S3 state\n");
			mutex_lock(&chip->state_change_mutex);
			force_fsm_state(chip, S3_STATE);
			mutex_unlock(&chip->state_change_mutex);
			/* Store accumulated data if any */
			process_suspend_data(chip);
		}
	}

@@ -2955,24 +3006,32 @@ static int bms_suspend(struct device *dev)

static int bms_resume(struct device *dev)
{
	u8 state = 0;
	int rc, monitor_soc_delay = 0;
	unsigned long tm_now_sec;
	struct qpnp_bms_chip *chip = dev_get_drvdata(dev);

	if (!chip->charging_while_suspended) {
		if (chip->dt.cfg_force_s3_on_suspend) {
			/*
			 * Update the state only if it is in S3. There is
			 * a possibility of being in S2 if we resumed on
			 * a charger insertion
			 */
			mutex_lock(&chip->state_change_mutex);
			get_fsm_state(chip, &state);
			if (state == S3_STATE) {
				pr_debug("Unforcing S3 state, setting AUTO state\n");
				set_auto_fsm_state(chip);
			}
			mutex_unlock(&chip->state_change_mutex);
			/*
			 * if we were charging while suspended, we will
			 * be woken up by the fifo done interrupt and no
		 * additional processing is needed
			 * additional processing is needed.
			 */
		process_suspended_data(chip);

		enable_bms_irq(&chip->fsm_state_change_irq);
		enable_irq_wake(chip->fsm_state_change_irq.irq);
			process_resume_data(chip);
		}
	}

	/* Start monitor_soc_work based on when it last executed */