// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
 * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
 */

#define pr_fmt(fmt)	"QG-K: %s: " fmt, __func__

#include <linux/debugfs.h>
#include <linux/alarmtimer.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
#include <linux/pmic-voter.h>
#include <linux/poll.h>
#include <linux/iio/consumer.h>
#include <dt-bindings/iio/qti_power_supply_iio.h>
#include <uapi/linux/qg.h>
#include <uapi/linux/qg-profile.h>
#include "fg-alg.h"
#include "qg-sdam.h"
#include "qg-core.h"
#include "qg-iio.h"
#include "qg-reg.h"
#include "qg-util.h"
#include "qg-soc.h"
#include "qg-battery-profile.h"
#include "qg-defs.h"
#include "battery-profile-loader.h"

static const struct qg_config config[] = {
	[PM2250]	= {QG_LITE, PM2250},
	[PM6150]	= {QG_PMIC5, PM6150},
	[PMI632]	= {QG_PMIC5, PMI632},
	[PM7250B]	= {QG_PMIC5, PM7250B},
};

static const char *qg_get_battery_type(struct qpnp_qg *chip);
static int qg_process_rt_fifo(struct qpnp_qg *chip);
static int qg_load_battery_profile(struct qpnp_qg *chip);

static int qg_debug_mask;

static int qg_esr_mod_count = 30;
static ssize_t esr_mod_count_show(struct device *dev, struct device_attribute
				     *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%d\n", qg_esr_mod_count);
}

static ssize_t esr_mod_count_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	int val;

	if (kstrtos32(buf, 0, &val))
		return -EINVAL;

	qg_esr_mod_count = val;

	return count;
}
static DEVICE_ATTR_RW(esr_mod_count);

static int qg_esr_count = 3;
static ssize_t esr_count_show(struct device *dev, struct device_attribute
				 *attr, char *buf)
{
	return scnprintf(buf, PAGE_SIZE, "%d\n", qg_esr_count);
}

static ssize_t esr_count_store(struct device *dev, struct device_attribute
				  *attr, const char *buf, size_t count)
{
	int val;

	if (kstrtos32(buf, 0, &val))
		return -EINVAL;

	qg_esr_count = val;

	return count;
}
static DEVICE_ATTR_RW(esr_count);

static ssize_t battery_type_show(struct device *dev,
				struct device_attribute
				*attr, char *buf)
{
	struct qpnp_qg *chip = dev_get_drvdata(dev);

	return scnprintf(buf, PAGE_SIZE, "%s\n",
			qg_get_battery_type(chip));
}
static DEVICE_ATTR_RO(battery_type);

static struct attribute *qg_attrs[] = {
	&dev_attr_esr_mod_count.attr,
	&dev_attr_esr_count.attr,
	&dev_attr_soc_interval_ms.attr,
	&dev_attr_soc_cold_interval_ms.attr,
	&dev_attr_maint_soc_update_ms.attr,
	&dev_attr_fvss_delta_soc_interval_ms.attr,
	&dev_attr_fvss_vbat_scaling.attr,
	&dev_attr_qg_ss_feature.attr,
	&dev_attr_battery_type.attr,
	NULL,
};
ATTRIBUTE_GROUPS(qg);

static bool is_battery_present(struct qpnp_qg *chip)
{
	bool present = true;
	u8 reg = 0;
	int rc;

	if (chip->qg_version == QG_LITE) {
		rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &reg, 1);
		if (rc < 0)
			pr_err("Failed to read battery presence, rc=%d\n", rc);
		else
			present = !(reg & BATTERY_MISSING_BIT);
	} else {
		rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, &reg, 1);
		if (rc < 0)
			pr_err("Failed to read battery presence, rc=%d\n", rc);
		else
			present = !!(reg & BATTERY_PRESENT_BIT);
	}

	return present;
}

#define DEBUG_BATT_ID_LOW	6000
#define DEBUG_BATT_ID_HIGH	8500
static bool is_debug_batt_id(struct qpnp_qg *chip)
{
	if (is_between(DEBUG_BATT_ID_LOW, DEBUG_BATT_ID_HIGH,
					chip->batt_id_ohm))
		return true;

	return false;
}

static int qg_read_ocv(struct qpnp_qg *chip, u32 *ocv_uv, u32 *ocv_raw, u8 type)
{
	int rc, addr;
	u64 temp = 0;
	char ocv_name[20];

	switch (type) {
	case S3_GOOD_OCV:
		addr = QG_S3_GOOD_OCV_V_DATA0_REG;
		strscpy(ocv_name, "S3_GOOD_OCV", 20);
		break;
	case S7_PON_OCV:
		addr = QG_S7_PON_OCV_V_DATA0_REG;
		strscpy(ocv_name, "S7_PON_OCV", 20);
		break;
	case S3_LAST_OCV:
		addr = QG_LAST_S3_SLEEP_V_DATA0_REG;
		strscpy(ocv_name, "S3_LAST_OCV", 20);
		break;
	case SDAM_PON_OCV:
		addr = QG_SDAM_PON_OCV_OFFSET;
		strscpy(ocv_name, "SDAM_PON_OCV", 20);
		break;
	default:
		pr_err("Invalid OCV type %d\n", type);
		return -EINVAL;
	}

	if (type == SDAM_PON_OCV) {
		rc = qg_sdam_read(SDAM_PON_OCV_UV, ocv_raw);
		if (rc < 0) {
			pr_err("Failed to read SDAM PON OCV rc=%d\n", rc);
			return rc;
		}
	} else {
		rc = qg_read(chip, chip->qg_base + addr, (u8 *)ocv_raw, 2);
		if (rc < 0) {
			pr_err("Failed to read ocv, rc=%d\n", rc);
			return rc;
		}
	}

	temp = *ocv_raw;
	*ocv_uv = V_RAW_TO_UV(temp);

	pr_debug("%s: OCV_RAW=%x OCV=%duV\n", ocv_name, *ocv_raw, *ocv_uv);

	return rc;
}

#define DEFAULT_S3_FIFO_LENGTH		3
static int qg_update_fifo_length(struct qpnp_qg *chip, u8 length)
{
	int rc;
	u8 s3_entry_fifo_length = 0;

	if (!length || length > chip->max_fifo_length) {
		pr_err("Invalid FIFO length %d\n", length);
		return -EINVAL;
	}

	rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
			FIFO_LENGTH_MASK, (length - 1) << FIFO_LENGTH_SHIFT);
	if (rc < 0)
		pr_err("Failed to write S2 FIFO length, rc=%d\n", rc);

	/* update the S3 FIFO length, when S2 length is updated */
	if (length > 3 && !chip->dt.qg_sleep_config)
		s3_entry_fifo_length = (chip->dt.s3_entry_fifo_length > 0) ?
			chip->dt.s3_entry_fifo_length : DEFAULT_S3_FIFO_LENGTH;
	else	/* Use S3 length as 1 for any S2 length <= 3 */
		s3_entry_fifo_length = 1;

	rc = qg_masked_write(chip,
			chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
			SLEEP_IBAT_QUALIFIED_LENGTH_MASK,
			s3_entry_fifo_length - 1);
	if (rc < 0)
		pr_err("Failed to write S3-entry fifo-length, rc=%d\n",
						rc);

	return rc;
}

static int qg_master_hold(struct qpnp_qg *chip, bool hold)
{
	int rc;

	/* clear the master */
	rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
					MASTER_HOLD_OR_CLR_BIT, 0);
	if (rc < 0)
		return rc;

	if (hold) {
		/* 0 -> 1, hold the master */
		rc = qg_masked_write(chip, chip->qg_base + QG_DATA_CTL1_REG,
					MASTER_HOLD_OR_CLR_BIT,
					MASTER_HOLD_OR_CLR_BIT);
		if (rc < 0)
			return rc;
	}

	qg_dbg(chip, QG_DEBUG_STATUS, "Master hold = %d\n", hold);

	return rc;
}

static void qg_notify_charger(struct qpnp_qg *chip)
{
	union power_supply_propval prop = {0, };
	int rc;

	if (!chip->batt_psy)
		return;

	if (!chip->profile_loaded)
		return;

	prop.intval = chip->bp.float_volt_uv;
	rc = power_supply_set_property(chip->batt_psy,
			POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
	if (rc < 0) {
		pr_err("Failed to set voltage_max property on batt_psy, rc=%d\n",
			rc);
		return;
	}

	prop.intval = chip->bp.fastchg_curr_ma * 1000;
	rc = power_supply_set_property(chip->batt_psy,
			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
	if (rc < 0) {
		pr_err("Failed to set constant_charge_current_max property on batt_psy, rc=%d\n",
			rc);
		return;
	}

	pr_debug("Notified charger on float voltage and FCC\n");

	rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, &prop);
	if (rc < 0) {
		pr_err("Failed to get charge term current, rc=%d\n", rc);
		return;
	}
	chip->chg_iterm_ma = prop.intval;
}

static bool is_batt_available(struct qpnp_qg *chip)
{
	if (chip->batt_psy)
		return true;

	chip->batt_psy = power_supply_get_by_name("battery");
	if (!chip->batt_psy)
		return false;

	/* batt_psy is initialized, set the fcc and fv */
	qg_notify_charger(chip);

	return true;
}

static int qg_store_soc_params(struct qpnp_qg *chip)
{
	int rc, batt_temp = 0, i;
	unsigned long rtc_sec = 0;
	u32 flash_ocv = 0;

	rc = get_rtc_time(&rtc_sec);
	if (rc < 0)
		pr_err("Failed to get RTC time, rc=%d\n", rc);
	else
		chip->sdam_data[SDAM_TIME_SEC] = rtc_sec;

	rc = qg_get_battery_temp(chip, &batt_temp);
	if (rc < 0)
		pr_err("Failed to get battery-temp, rc = %d\n", rc);
	else
		chip->sdam_data[SDAM_TEMP] = (u32)batt_temp;

	for (i = 0; i <= SDAM_TIME_SEC; i++) {
		rc |= qg_sdam_write(i, chip->sdam_data[i]);
		qg_dbg(chip, QG_DEBUG_STATUS, "SDAM write param %d value=%d\n",
					i, chip->sdam_data[i]);
	}

	/* store the SDAM OCV */
	flash_ocv = chip->sdam_data[SDAM_OCV_UV] / 20000;
	rc = qg_sdam_write(SDAM_FLASH_OCV, flash_ocv);
	if (rc < 0)
		pr_err("Failed to update flash-ocv rc=%d\n", rc);

	return rc;
}

#define MAX_FIFO_CNT_FOR_ESR			50
static int qg_config_s2_state(struct qpnp_qg *chip,
		enum s2_state requested_state, bool state_enable,
		bool process_fifo)
{
	int rc, acc_interval, acc_length;
	u8 fifo_length, reg = 0, state = S2_DEFAULT;

	if ((chip->s2_state_mask & requested_state) && state_enable)
		return 0; /* No change in state */

	if (!(chip->s2_state_mask & requested_state) && !state_enable)
		return 0; /* No change in state */

	if (state_enable)
		chip->s2_state_mask |= requested_state;
	else
		chip->s2_state_mask &= ~requested_state;

	/* define the priority of the states */
	if (chip->s2_state_mask & S2_FAST_CHARGING)
		state = S2_FAST_CHARGING;
	else if (chip->s2_state_mask & S2_LOW_VBAT)
		state = S2_LOW_VBAT;
	else if (chip->s2_state_mask & S2_SLEEP)
		state = S2_SLEEP;
	else
		state = S2_DEFAULT;

	if (state == chip->s2_state)
		return 0;

	switch (state) {
	case S2_FAST_CHARGING:
		fifo_length = chip->dt.fast_chg_s2_fifo_length;
		acc_interval = chip->dt.s2_acc_intvl_ms;
		acc_length = chip->dt.s2_acc_length;
		break;
	case S2_LOW_VBAT:
		fifo_length = chip->dt.s2_vbat_low_fifo_length;
		acc_interval = chip->dt.s2_acc_intvl_ms;
		acc_length = chip->dt.s2_acc_length;
		break;
	case S2_SLEEP:
		fifo_length = chip->dt.sleep_s2_fifo_length;
		acc_interval = chip->dt.sleep_s2_acc_intvl_ms;
		acc_length = chip->dt.sleep_s2_acc_length;
		break;
	case S2_DEFAULT:
		fifo_length = chip->dt.s2_fifo_length;
		acc_interval = chip->dt.s2_acc_intvl_ms;
		acc_length = chip->dt.s2_acc_length;
		break;
	default:
		pr_err("Invalid S2 state %d\n", state);
		return -EINVAL;
	}

	if (fifo_length)
		qg_esr_mod_count = MAX_FIFO_CNT_FOR_ESR / fifo_length;

	rc = qg_master_hold(chip, true);
	if (rc < 0) {
		pr_err("Failed to hold master, rc=%d\n", rc);
		return rc;
	}

	if (process_fifo) {
		rc = qg_process_rt_fifo(chip);
		if (rc < 0) {
			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
			goto done;
		}
	}

	rc = qg_update_fifo_length(chip, fifo_length);
	if (rc < 0) {
		pr_err("Failed to update S2 fifo-length, rc=%d\n", rc);
		goto done;
	}

	reg = acc_interval / 10;
	rc = qg_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL3_REG,
					&reg, 1);
	if (rc < 0) {
		pr_err("Failed to update S2 acc intrvl, rc=%d\n", rc);
		goto done;
	}

	reg = ilog2(acc_length) - 1;
	rc = qg_masked_write(chip, chip->qg_base + QG_S2_NORMAL_MEAS_CTL2_REG,
					NUM_OF_ACCUM_MASK, reg);
	if (rc < 0) {
		pr_err("Failed to update S2 ACC length, rc=%d\n", rc);
		goto done;
	}

	chip->s2_state = state;

	qg_dbg(chip, QG_DEBUG_STATUS, "S2 New state=%x  fifo_length=%d interval=%d acc_length=%d\n",
				state, fifo_length, acc_interval, acc_length);

done:
	qg_master_hold(chip, false);
	/* FIFO restarted */
	chip->last_fifo_update_time = ktime_get_boottime();
	return rc;
}

static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
{
	int rc = 0, i, j = 0, temp;
	u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
	u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
	unsigned long rtc_sec = 0;
	bool qg_v_mode = (chip->qg_mode == QG_V_MODE);

	rc = get_rtc_time(&rtc_sec);
	if (rc < 0)
		pr_err("Failed to get RTC time, rc=%d\n", rc);

	chip->kdata.fifo_time = (u32)rtc_sec;

	if (!fifo_length) {
		pr_debug("No FIFO data\n");
		return 0;
	}

	qg_dbg(chip, QG_DEBUG_FIFO, "FIFO length=%d\n", fifo_length);

	rc = get_sample_interval(chip, &sample_interval);
	if (rc < 0) {
		pr_err("Failed to get FIFO sample interval, rc=%d\n", rc);
		return rc;
	}

	rc = get_sample_count(chip, &sample_count);
	if (rc < 0) {
		pr_err("Failed to get FIFO sample count, rc=%d\n", rc);
		return rc;
	}

	/*
	 * If there is pending data from suspend, append the new FIFO
	 * data to it. Only do this if we can accomadate 8 FIFOs
	 */
	if (chip->suspend_data &&
		(chip->kdata.fifo_length < (MAX_FIFO_LENGTH / 2))) {
		j = chip->kdata.fifo_length; /* append the data */
		chip->suspend_data = false;
		qg_dbg(chip, QG_DEBUG_FIFO,
			"Pending suspend-data FIFO length=%d\n", j);
	} else {
		/* clear any old pending data */
		chip->kdata.fifo_length = 0;
	}

	for (i = 0; i < fifo_length * 2; i = i + 2, j++) {
		rc = qg_read(chip, chip->qg_base + QG_V_FIFO0_DATA0_REG + i,
					&v_fifo[i], 2);
		if (rc < 0) {
			pr_err("Failed to read QG_V_FIFO, rc=%d\n", rc);
			return rc;
		}
		rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG + i,
					&i_fifo[i], 2);
		if (rc < 0) {
			pr_err("Failed to read QG_I_FIFO, rc=%d\n", rc);
			return rc;
		}

		fifo_v = v_fifo[i] | (v_fifo[i + 1] << 8);
		fifo_i = i_fifo[i] | (i_fifo[i + 1] << 8);

		if (fifo_v == FIFO_V_RESET_VAL ||
			(fifo_i == FIFO_I_RESET_VAL && !qg_v_mode)) {
			pr_err("Invalid FIFO data V_RAW=%x I_RAW=%x - FIFO rejected\n",
						fifo_v, fifo_i);
			return -EINVAL;
		}

		temp = sign_extend32(fifo_i, 15);

		chip->kdata.fifo[j].v = V_RAW_TO_UV(fifo_v);
		chip->kdata.fifo[j].i =
				qg_v_mode ? 0 : qg_iraw_to_ua(chip, temp);
		chip->kdata.fifo[j].interval = sample_interval;
		chip->kdata.fifo[j].count = sample_count;

		chip->last_fifo_v_uv = chip->kdata.fifo[j].v;
		chip->last_fifo_i_ua = chip->kdata.fifo[j].i;

		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
					j, fifo_v,
					chip->kdata.fifo[j].v,
					qg_v_mode ? 0 : fifo_i,
					(int)chip->kdata.fifo[j].i,
					chip->kdata.fifo[j].interval,
					chip->kdata.fifo[j].count);
	}

	chip->kdata.fifo_length += fifo_length;
	chip->kdata.seq_no = chip->seq_no++ % U32_MAX;

	return rc;
}

static int qg_process_accumulator(struct qpnp_qg *chip)
{
	int rc, sample_interval = 0;
	u8 count, index = chip->kdata.fifo_length;
	u64 acc_v = 0, acc_i = 0;
	s64 temp = 0;
	bool qg_v_mode = (chip->qg_mode == QG_V_MODE);

	rc = qg_read(chip, chip->qg_base + QG_ACCUM_CNT_RT_REG,
			&count, 1);
	if (rc < 0) {
		pr_err("Failed to read ACC count, rc=%d\n", rc);
		return rc;
	}

	if (!count || count < 10) { /* Ignore small accumulator data */
		pr_debug("No ACCUMULATOR data!\n");
		return 0;
	}

	rc = get_sample_interval(chip, &sample_interval);
	if (rc < 0) {
		pr_err("Failed to get ACC sample interval, rc=%d\n", rc);
		return 0;
	}

	rc = qg_read(chip, chip->qg_base + QG_V_ACCUM_DATA0_RT_REG,
			(u8 *)&acc_v, 3);
	if (rc < 0) {
		pr_err("Failed to read ACC RT V data, rc=%d\n", rc);
		return rc;
	}

	rc = qg_read(chip, chip->qg_base + QG_I_ACCUM_DATA0_RT_REG,
			(u8 *)&acc_i, 3);
	if (rc < 0) {
		pr_err("Failed to read ACC RT I data, rc=%d\n", rc);
		return rc;
	}

	temp = sign_extend64(acc_i, 23);

	chip->kdata.fifo[index].v = V_RAW_TO_UV(div_u64(acc_v, count));
	chip->kdata.fifo[index].i = qg_v_mode ?
				0 : qg_iraw_to_ua(chip, div_s64(temp, count));
	chip->kdata.fifo[index].interval = sample_interval;
	chip->kdata.fifo[index].count = count;
	chip->kdata.fifo_length++;
	if (chip->kdata.fifo_length == MAX_FIFO_LENGTH)
		chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1;

	chip->last_fifo_v_uv = chip->kdata.fifo[index].v;
	chip->last_fifo_i_ua = chip->kdata.fifo[index].i;

	if (chip->kdata.fifo_length == 1)	/* Only accumulator data */
		chip->kdata.seq_no = chip->seq_no++ % U32_MAX;

	qg_dbg(chip, QG_DEBUG_FIFO, "ACC v_avg=%duV i_avg=%duA interval=%d count=%d\n",
			chip->kdata.fifo[index].v,
			(int)chip->kdata.fifo[index].i,
			chip->kdata.fifo[index].interval,
			chip->kdata.fifo[index].count);

	return rc;
}

static int qg_process_rt_fifo(struct qpnp_qg *chip)
{
	int rc;
	u32 fifo_length = 0;

	/* Get the real-time FIFO length */
	rc = get_fifo_length(chip, &fifo_length, true);
	if (rc < 0) {
		pr_err("Failed to read RT FIFO length, rc=%d\n", rc);
		return rc;
	}

	rc = qg_process_fifo(chip, fifo_length);
	if (rc < 0) {
		pr_err("Failed to process FIFO data, rc=%d\n", rc);
		return rc;
	}

	rc = qg_process_accumulator(chip);
	if (rc < 0) {
		pr_err("Failed to process ACC data, rc=%d\n", rc);
		return rc;
	}

	return rc;
}

#define MIN_FIFO_FULL_TIME_MS			12000
static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb)
{
	int rc = 0;
	ktime_t now = ktime_get_boottime();
	s64 time_delta;

	/*
	 * Reject the FIFO read event if there are back-to-back requests
	 * This is done to gaurantee that there is always a minimum FIFO
	 * data to be processed, ignore this if vbat_low is set.
	 */
	time_delta = ktime_ms_delta(now, chip->last_user_update_time);

	qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n",
				time_delta, update_smb);

	if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) {
		rc = qg_master_hold(chip, true);
		if (rc < 0) {
			pr_err("Failed to hold master, rc=%d\n", rc);
			goto done;
		}

		rc = qg_process_rt_fifo(chip);
		if (rc < 0) {
			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
			goto done;
		}

		if (update_smb) {
			rc = qg_masked_write(chip, chip->qg_base +
				QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
				chip->parallel_enabled ?
					PARALLEL_IBAT_SENSE_EN_BIT : 0);
			if (rc < 0) {
				pr_err("Failed to update SMB_EN, rc=%d\n", rc);
				goto done;
			}
			qg_dbg(chip, QG_DEBUG_STATUS, "Parallel SENSE %d\n",
						chip->parallel_enabled);
		}

		rc = qg_master_hold(chip, false);
		if (rc < 0) {
			pr_err("Failed to release master, rc=%d\n", rc);
			goto done;
		}
		/* FIFOs restarted */
		chip->last_fifo_update_time = ktime_get_boottime();

		/* signal the read thread */
		chip->data_ready = true;
		wake_up_interruptible(&chip->qg_wait_q);
		chip->last_user_update_time = now;

		/* vote to stay awake until userspace reads data */
		vote(chip->awake_votable, FIFO_RT_DONE_VOTER, true, 0);
	} else {
		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO processing too early time_delta=%lld\n",
							time_delta);
	}
done:
	qg_master_hold(chip, false);
	return rc;
}

#define VBAT_LOW_HYST_UV		50000 /* 50mV */
static int qg_vbat_low_wa(struct qpnp_qg *chip)
{
	int rc, i, temp = 0;
	u32 vbat_low_uv = 0;

	if (chip->wa_flags & QG_VBAT_LOW_WA) {
		rc = qg_get_battery_temp(chip, &temp);
		if (rc < 0) {
			pr_err("Failed to read batt_temp rc=%d\n", rc);
			temp = 250;
		}

		vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ?
					chip->dt.vbatt_low_cold_mv :
					chip->dt.vbatt_low_mv);

		for (i = 0; i < chip->kdata.fifo_length; i++) {
			if ((chip->kdata.fifo[i].v > (vbat_low_uv +
					VBAT_LOW_HYST_UV)) && chip->vbat_low) {
				chip->vbat_low = false;
				pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV\n",
					chip->kdata.fifo[i].v, vbat_low_uv);
				break;
			} else if ((chip->kdata.fifo[i].v < vbat_low_uv) &&
							!chip->vbat_low) {
				chip->vbat_low = true;
				pr_info("Enter VBAT_LOW vbat_avg=%duV vbat_low=%duV\n",
					chip->kdata.fifo[i].v, vbat_low_uv);
				break;
			}
		}
	}

	rc = qg_config_s2_state(chip, S2_LOW_VBAT,
			chip->vbat_low ? true : false, false);
	if (rc < 0)
		pr_err("Failed to configure for VBAT_LOW rc=%d\n", rc);

	return rc;
}

static int qg_vbat_thresholds_config(struct qpnp_qg *chip)
{
	int rc, temp = 0, vbat_mv;
	u8 reg;

	rc = qg_get_battery_temp(chip, &temp);
	if (rc < 0) {
		pr_err("Failed to read batt_temp rc=%d\n", rc);
		return rc;
	}

	vbat_mv = (temp < chip->dt.cold_temp_threshold) ?
			chip->dt.vbatt_empty_cold_mv :
			chip->dt.vbatt_empty_mv;

	rc = qg_read(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG,
					&reg, 1);
	if (rc < 0) {
		pr_err("Failed to read vbat-empty, rc=%d\n", rc);
		return rc;
	}

	if (vbat_mv == (reg * 50))	/* No change */
		goto config_vbat_low;

	reg = vbat_mv / 50;
	rc = qg_write(chip, chip->qg_base + QG_VBAT_EMPTY_THRESHOLD_REG,
					&reg, 1);
	if (rc < 0) {
		pr_err("Failed to write vbat-empty, rc=%d\n", rc);
		return rc;
	}

	qg_dbg(chip, QG_DEBUG_STATUS,
		"VBAT EMPTY threshold updated to %dmV temp=%d\n",
						vbat_mv, temp);

config_vbat_low:
	if (chip->qg_version == QG_LITE)
		return 0;

	vbat_mv = (temp < chip->dt.cold_temp_threshold) ?
			chip->dt.vbatt_low_cold_mv :
			chip->dt.vbatt_low_mv;

	rc = qg_read(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG,
					&reg, 1);
	if (rc < 0) {
		pr_err("Failed to read vbat-low, rc=%d\n", rc);
		return rc;
	}

	if (vbat_mv == (reg * 50))	/* No change */
		return 0;

	reg = vbat_mv / 50;
	rc = qg_write(chip, chip->qg_base + QG_VBAT_LOW_THRESHOLD_REG,
					&reg, 1);
	if (rc < 0) {
		pr_err("Failed to write vbat-low, rc=%d\n", rc);
		return rc;
	}

	qg_dbg(chip, QG_DEBUG_STATUS,
		"VBAT LOW threshold updated to %dmV temp=%d\n",
						vbat_mv, temp);

	return rc;
}

static int qg_fast_charge_config(struct qpnp_qg *chip)
{
	int rc = 0;

	if (!chip->dt.qg_fast_chg_cfg)
		return 0;

	rc = qg_config_s2_state(chip, S2_FAST_CHARGING,
			(chip->charge_status == POWER_SUPPLY_STATUS_CHARGING)
			? true : false, false);
	if (rc < 0)
		pr_err("Failed to exit S2_SLEEP rc=%d\n", rc);

	return rc;
}

static void qg_retrieve_esr_params(struct qpnp_qg *chip)
{
	u32 data = 0;
	int rc;

	rc = qg_sdam_read(SDAM_ESR_CHARGE_DELTA, &data);
	if (!rc && data) {
		chip->kdata.param[QG_ESR_CHARGE_DELTA].data = data;
		chip->kdata.param[QG_ESR_CHARGE_DELTA].valid = true;
		qg_dbg(chip, QG_DEBUG_ESR,
				"ESR_CHARGE_DELTA SDAM=%d\n", data);
	} else if (rc < 0) {
		pr_err("Failed to read ESR_CHARGE_DELTA rc=%d\n", rc);
	}

	rc = qg_sdam_read(SDAM_ESR_DISCHARGE_DELTA, &data);
	if (!rc && data) {
		chip->kdata.param[QG_ESR_DISCHARGE_DELTA].data = data;
		chip->kdata.param[QG_ESR_DISCHARGE_DELTA].valid = true;
		qg_dbg(chip, QG_DEBUG_ESR,
				"ESR_DISCHARGE_DELTA SDAM=%d\n", data);
	} else if (rc < 0) {
		pr_err("Failed to read ESR_DISCHARGE_DELTA rc=%d\n", rc);
	}

	rc = qg_sdam_read(SDAM_ESR_CHARGE_SF, &data);
	if (!rc && data) {
		data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data);
		chip->kdata.param[QG_ESR_CHARGE_SF].data = data;
		chip->kdata.param[QG_ESR_CHARGE_SF].valid = true;
		qg_dbg(chip, QG_DEBUG_ESR,
				"ESR_CHARGE_SF SDAM=%d\n", data);
	} else if (rc < 0) {
		pr_err("Failed to read ESR_CHARGE_SF rc=%d\n", rc);
	}

	rc = qg_sdam_read(SDAM_ESR_DISCHARGE_SF, &data);
	if (!rc && data) {
		data = CAP(QG_ESR_SF_MIN, QG_ESR_SF_MAX, data);
		chip->kdata.param[QG_ESR_DISCHARGE_SF].data = data;
		chip->kdata.param[QG_ESR_DISCHARGE_SF].valid = true;
		qg_dbg(chip, QG_DEBUG_ESR,
				"ESR_DISCHARGE_SF SDAM=%d\n", data);
	} else if (rc < 0) {
		pr_err("Failed to read ESR_DISCHARGE_SF rc=%d\n", rc);
	}
}

static void qg_store_esr_params(struct qpnp_qg *chip)
{
	unsigned int esr;

	if (chip->udata.param[QG_ESR_CHARGE_DELTA].valid) {
		esr = chip->udata.param[QG_ESR_CHARGE_DELTA].data;
		qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr);
		qg_dbg(chip, QG_DEBUG_ESR,
			"SDAM store ESR_CHARGE_DELTA=%d\n", esr);
	}

	if (chip->udata.param[QG_ESR_DISCHARGE_DELTA].valid) {
		esr = chip->udata.param[QG_ESR_DISCHARGE_DELTA].data;
		qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr);
		qg_dbg(chip, QG_DEBUG_ESR,
			"SDAM store ESR_DISCHARGE_DELTA=%d\n", esr);
	}

	if (chip->udata.param[QG_ESR_CHARGE_SF].valid) {
		esr = chip->udata.param[QG_ESR_CHARGE_SF].data;
		qg_sdam_write(SDAM_ESR_CHARGE_SF, esr);
		qg_dbg(chip, QG_DEBUG_ESR,
			"SDAM store ESR_CHARGE_SF=%d\n", esr);
	}

	if (chip->udata.param[QG_ESR_DISCHARGE_SF].valid) {
		esr = chip->udata.param[QG_ESR_DISCHARGE_SF].data;
		qg_sdam_write(SDAM_ESR_DISCHARGE_SF, esr);
		qg_dbg(chip, QG_DEBUG_ESR,
			"SDAM store ESR_DISCHARGE_SF=%d\n", esr);
	}
}

#define MAX_ESR_RETRY_COUNT		10
#define ESR_SD_PERCENT			10
static int qg_process_esr_data(struct qpnp_qg *chip)
{
	int i;
	int pre_i, post_i, pre_v, post_v, first_pre_i = 0;
	int diff_v, diff_i, esr_avg = 0, count = 0;

	for (i = 0; i < qg_esr_count; i++) {
		if (!chip->esr_data[i].valid)
			continue;

		pre_i = chip->esr_data[i].pre_esr_i;
		pre_v = chip->esr_data[i].pre_esr_v;
		post_i = chip->esr_data[i].post_esr_i;
		post_v = chip->esr_data[i].post_esr_v;

		/*
		 * Check if any of the pre/post readings have changed
		 * signs by comparing it with the first valid
		 * pre_i value.
		 */
		if (!first_pre_i)
			first_pre_i = pre_i;

		if ((first_pre_i < 0 && pre_i > 0) ||
			(first_pre_i > 0 && post_i < 0) ||
			(first_pre_i < 0 && post_i > 0)) {
			qg_dbg(chip, QG_DEBUG_ESR,
				"ESR-sign mismatch %d reject all data\n", i);
			esr_avg = count = 0;
			break;
		}

		/* calculate ESR */
		diff_v = abs(post_v - pre_v);
		diff_i = abs(post_i - pre_i);

		if (!diff_v || !diff_i ||
			(diff_i < chip->dt.esr_qual_i_ua) ||
			(diff_v < chip->dt.esr_qual_v_uv)) {
			qg_dbg(chip, QG_DEBUG_ESR,
				"ESR (%d) V/I %duA %duV fails qualification\n",
				i, diff_i, diff_v);
			chip->esr_data[i].valid = false;
			continue;
		}

		chip->esr_data[i].esr =
			DIV_ROUND_CLOSEST(diff_v * 1000, diff_i);
		qg_dbg(chip, QG_DEBUG_ESR,
			"ESR qualified: i=%d pre_i=%d pre_v=%d post_i=%d post_v=%d esr_diff_v=%d esr_diff_i=%d esr=%d\n",
			i, pre_i, pre_v, post_i, post_v,
			diff_v, diff_i, chip->esr_data[i].esr);

		esr_avg += chip->esr_data[i].esr;
		count++;
	}

	if (!count) {
		qg_dbg(chip, QG_DEBUG_ESR,
			"No ESR samples qualified, ESR not found\n");
		chip->esr_avg = 0;
		return 0;
	}

	esr_avg /= count;
	qg_dbg(chip, QG_DEBUG_ESR,
		"ESR all sample average=%d count=%d apply_SD=%d\n",
		esr_avg, count, (esr_avg * ESR_SD_PERCENT) / 100);

	/*
	 * Reject ESR samples which do not fall in
	 * 10% the standard-deviation
	 */
	count = 0;
	for (i = 0; i < qg_esr_count; i++) {
		if (!chip->esr_data[i].valid)
			continue;

		if ((abs(chip->esr_data[i].esr - esr_avg) <=
			(esr_avg * ESR_SD_PERCENT) / 100)) {
			/* valid ESR */
			chip->esr_avg += chip->esr_data[i].esr;
			count++;
			qg_dbg(chip, QG_DEBUG_ESR,
				"Valid ESR after SD (%d) %d mOhm\n",
				i, chip->esr_data[i].esr);
		} else {
			qg_dbg(chip, QG_DEBUG_ESR,
				"ESR (%d) %d falls-out of SD(%d)\n",
				i, chip->esr_data[i].esr, ESR_SD_PERCENT);
		}
	}

	if (count >= QG_MIN_ESR_COUNT) {
		chip->esr_avg /= count;
		qg_dbg(chip, QG_DEBUG_ESR, "Average estimated ESR %d mOhm\n",
					chip->esr_avg);
	} else {
		qg_dbg(chip, QG_DEBUG_ESR,
			"Not enough ESR samples, ESR not found\n");
		chip->esr_avg = 0;
	}

	return 0;
}

static int qg_esr_estimate(struct qpnp_qg *chip)
{
	int rc, i, ibat = 0, temp = 0;
	u8 esr_done_count, reg0 = 0, reg1 = 0;
	bool is_charging = false;

	if (chip->dt.esr_disable)
		return 0;

	/*
	 * Charge - enable ESR estimation if IBAT > MIN_IBAT.
	 * Discharge - enable ESR estimation only if enabled via DT.
	 */
	rc = qg_get_battery_current(chip, &ibat);
	if (rc < 0)
		return rc;
	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
				ibat > chip->dt.esr_min_ibat_ua) {
		qg_dbg(chip, QG_DEBUG_ESR,
			"Skip CHG ESR, Fails IBAT ibat(%d) min_ibat(%d)\n",
				ibat, chip->dt.esr_min_ibat_ua);
		return 0;
	}

	if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
			!chip->dt.esr_discharge_enable)
		return 0;

	/* Ignore ESR if battery-temp is below a threshold */
	rc = qg_get_battery_temp(chip, &temp);
	if (rc < 0)
		return rc;
	if (temp < chip->dt.esr_low_temp_threshold) {
		qg_dbg(chip, QG_DEBUG_ESR,
			"Battery temperature(%d) below threshold(%d) for ESR\n",
				temp, chip->dt.esr_low_temp_threshold);
		return 0;
	}

	if (chip->batt_soc != INT_MIN && (chip->batt_soc <
					chip->dt.esr_disable_soc)) {
		qg_dbg(chip, QG_DEBUG_ESR,
			"Skip ESR, batt-soc below %d\n",
				chip->dt.esr_disable_soc);
		return 0;
	}

	qg_dbg(chip, QG_DEBUG_ESR, "FIFO done count=%d ESR mod count=%d\n",
			chip->fifo_done_count, qg_esr_mod_count);

	if ((chip->fifo_done_count % qg_esr_mod_count) != 0)
		return 0;

	if (qg_esr_count > QG_MAX_ESR_COUNT)
		qg_esr_count = QG_MAX_ESR_COUNT;

	if (qg_esr_count < QG_MIN_ESR_COUNT)
		qg_esr_count = QG_MIN_ESR_COUNT;

	/* clear all data */
	chip->esr_avg = 0;
	memset(&chip->esr_data, 0, sizeof(chip->esr_data));

	rc = qg_master_hold(chip, true);
	if (rc < 0) {
		pr_err("Failed to hold master, rc=%d\n", rc);
		goto done;
	}

	for (i = 0; i < qg_esr_count; i++) {
		/* Fire ESR measurement */
		rc = qg_masked_write(chip,
			chip->qg_base + QG_ESR_MEAS_TRIG_REG,
			HW_ESR_MEAS_START_BIT, HW_ESR_MEAS_START_BIT);
		if (rc < 0) {
			pr_err("Failed to start ESR rc=%d\n", rc);
			continue;
		}

		esr_done_count = reg0 = reg1 = 0;
		do {
			/* delay for ESR processing to complete */
			msleep(50);

			esr_done_count++;

			rc = qg_read(chip,
				chip->qg_base + QG_STATUS1_REG, &reg0, 1);
			if (rc < 0)
				continue;

			rc = qg_read(chip,
				chip->qg_base + QG_STATUS4_REG, &reg1, 1);
			if (rc < 0)
				continue;

			/* check ESR-done status */
			if (!(reg1 & ESR_MEAS_IN_PROGRESS_BIT) &&
					(reg0 & ESR_MEAS_DONE_BIT)) {
				qg_dbg(chip, QG_DEBUG_ESR,
					"ESR measurement done %d count %d\n",
						i, esr_done_count);
				break;
			}
		} while (esr_done_count < MAX_ESR_RETRY_COUNT);

		if (esr_done_count == MAX_ESR_RETRY_COUNT) {
			pr_err("Failed to get ESR done for %d iteration\n", i);
			continue;
		} else {
			/* found a valid ESR, read pre-post data */
			rc = qg_read_raw_data(chip, QG_PRE_ESR_V_DATA0_REG,
					&chip->esr_data[i].pre_esr_v);
			if (rc < 0)
				goto done;

			rc = qg_read_raw_data(chip, QG_PRE_ESR_I_DATA0_REG,
					&chip->esr_data[i].pre_esr_i);
			if (rc < 0)
				goto done;

			rc = qg_read_raw_data(chip, QG_POST_ESR_V_DATA0_REG,
					&chip->esr_data[i].post_esr_v);
			if (rc < 0)
				goto done;

			rc = qg_read_raw_data(chip, QG_POST_ESR_I_DATA0_REG,
					&chip->esr_data[i].post_esr_i);
			if (rc < 0)
				goto done;

			chip->esr_data[i].pre_esr_v =
				V_RAW_TO_UV(chip->esr_data[i].pre_esr_v);
			ibat = sign_extend32(chip->esr_data[i].pre_esr_i, 15);
			chip->esr_data[i].pre_esr_i = qg_iraw_to_ua(chip, ibat);
			chip->esr_data[i].post_esr_v =
				V_RAW_TO_UV(chip->esr_data[i].post_esr_v);
			ibat = sign_extend32(chip->esr_data[i].post_esr_i, 15);
			chip->esr_data[i].post_esr_i =
						qg_iraw_to_ua(chip, ibat);

			chip->esr_data[i].valid = true;

			if ((int)chip->esr_data[i].pre_esr_i < 0)
				is_charging = true;

			qg_dbg(chip, QG_DEBUG_ESR,
				"ESR values for %d iteration pre_v=%d pre_i=%d post_v=%d post_i=%d\n",
				i, chip->esr_data[i].pre_esr_v,
				(int)chip->esr_data[i].pre_esr_i,
				chip->esr_data[i].post_esr_v,
				(int)chip->esr_data[i].post_esr_i);
		}
		/* delay before the next ESR measurement */
		msleep(200);
	}

	rc = qg_process_esr_data(chip);
	if (rc < 0)
		pr_err("Failed to process ESR data rc=%d\n", rc);

	rc = qg_master_hold(chip, false);
	if (rc < 0) {
		pr_err("Failed to release master, rc=%d\n", rc);
		goto done;
	}
	/* FIFOs restarted */
	chip->last_fifo_update_time = ktime_get_boottime();

	if (chip->esr_avg) {
		chip->kdata.param[QG_ESR].data = chip->esr_avg;
		chip->kdata.param[QG_ESR].valid = true;
		qg_dbg(chip, QG_DEBUG_ESR, "ESR_SW=%d during %s\n",
			chip->esr_avg, is_charging ? "CHARGE" : "DISCHARGE");
		qg_retrieve_esr_params(chip);
		chip->esr_actual = chip->esr_avg;
	}

	return 0;
done:
	qg_master_hold(chip, false);
	return rc;
}

static void process_udata_work(struct work_struct *work)
{
	struct qpnp_qg *chip = container_of(work,
			struct qpnp_qg, udata_work);
	int rc;

	if (chip->udata.param[QG_CC_SOC].valid)
		chip->cc_soc = chip->udata.param[QG_CC_SOC].data;

	if (chip->udata.param[QG_BATT_SOC].valid)
		chip->batt_soc = chip->udata.param[QG_BATT_SOC].data;

	if (chip->udata.param[QG_FULL_SOC].valid)
		chip->full_soc = chip->udata.param[QG_FULL_SOC].data;

	if (chip->udata.param[QG_V_IBAT].valid)
		chip->qg_v_ibat = chip->udata.param[QG_V_IBAT].data;

	if (chip->udata.param[QG_SOC].valid ||
			chip->udata.param[QG_SYS_SOC].valid) {

		qg_dbg(chip, QG_DEBUG_SOC, "udata update: QG_SOC=%d QG_SYS_SOC=%d last_catchup_soc=%d\n",
				chip->udata.param[QG_SOC].valid ?
				chip->udata.param[QG_SOC].data : -EINVAL,
				chip->udata.param[QG_SYS_SOC].valid ?
				chip->udata.param[QG_SYS_SOC].data : -EINVAL,
				chip->catch_up_soc);

		if (chip->udata.param[QG_SYS_SOC].valid) {
			chip->sys_soc = chip->udata.param[QG_SYS_SOC].data;
			chip->catch_up_soc = qg_adjust_sys_soc(chip);
		} else {
			chip->catch_up_soc = chip->udata.param[QG_SOC].data;
		}

		qg_scale_soc(chip, chip->force_soc);
		chip->force_soc = false;

		/* update parameters to SDAM */
		chip->sdam_data[SDAM_SOC] = chip->msoc;
		chip->sdam_data[SDAM_OCV_UV] =
				chip->udata.param[QG_OCV_UV].data;
		chip->sdam_data[SDAM_RBAT_MOHM] =
				chip->udata.param[QG_RBAT_MOHM].data;
		chip->sdam_data[SDAM_VALID] = 1;

		rc = qg_store_soc_params(chip);
		if (rc < 0)
			pr_err("Failed to update SDAM params, rc=%d\n", rc);
	}

	if (chip->udata.param[QG_ESR].valid)
		chip->esr_last = chip->udata.param[QG_ESR].data;

	if (chip->esr_actual != -EINVAL && chip->udata.param[QG_ESR].valid) {
		chip->esr_nominal = chip->udata.param[QG_ESR].data;
		if (chip->qg_psy)
			power_supply_changed(chip->qg_psy);
	}

	if (!chip->dt.esr_disable)
		qg_store_esr_params(chip);

	qg_dbg(chip, QG_DEBUG_STATUS, "udata update: batt_soc=%d cc_soc=%d full_soc=%d qg_esr=%d\n",
		(chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL,
		(chip->cc_soc != INT_MIN) ? chip->cc_soc : -EINVAL,
		chip->full_soc, chip->esr_last);
	vote(chip->awake_votable, UDATA_READY_VOTER, false, 0);
}

#define MAX_FIFO_DELTA_PERCENT		10
static irqreturn_t qg_fifo_update_done_handler(int irq, void *data)
{
	ktime_t now = ktime_get_boottime();
	int rc, hw_delta_ms = 0, margin_ms = 0;
	u32 fifo_length = 0;
	s64 time_delta_ms = 0;
	struct qpnp_qg *chip = data;

	time_delta_ms = ktime_ms_delta(now, chip->last_fifo_update_time);
	chip->last_fifo_update_time = now;

	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
	mutex_lock(&chip->data_lock);

	rc = get_fifo_length(chip, &fifo_length, false);
	if (rc < 0) {
		pr_err("Failed to get FIFO length, rc=%d\n", rc);
		goto done;
	}

	rc = qg_process_fifo(chip, fifo_length);
	if (rc < 0) {
		pr_err("Failed to process QG FIFO, rc=%d\n", rc);
		goto done;
	}

	if (++chip->fifo_done_count == U32_MAX)
		chip->fifo_done_count = 0;

	rc = qg_vbat_thresholds_config(chip);
	if (rc < 0)
		pr_err("Failed to apply VBAT EMPTY config rc=%d\n", rc);

	rc = qg_fast_charge_config(chip);
	if (rc < 0)
		pr_err("Failed to apply fast-charge config rc=%d\n", rc);

	rc = qg_vbat_low_wa(chip);
	if (rc < 0) {
		pr_err("Failed to apply VBAT LOW WA, rc=%d\n", rc);
		goto done;
	}

	rc = qg_esr_estimate(chip);
	if (rc < 0) {
		pr_err("Failed to estimate ESR, rc=%d\n", rc);
		goto done;
	}

	rc = get_fifo_done_time(chip, false, &hw_delta_ms);
	if (rc < 0)
		hw_delta_ms = 0;
	else
		margin_ms = (hw_delta_ms * MAX_FIFO_DELTA_PERCENT) / 100;

	if (abs(hw_delta_ms - time_delta_ms) < margin_ms) {
		chip->kdata.param[QG_FIFO_TIME_DELTA].data = time_delta_ms;
		chip->kdata.param[QG_FIFO_TIME_DELTA].valid = true;
		qg_dbg(chip, QG_DEBUG_FIFO, "FIFO_done time_delta_ms=%lld\n",
							time_delta_ms);
	}

	/* signal the read thread */
	chip->data_ready = true;
	wake_up_interruptible(&chip->qg_wait_q);

	/* vote to stay awake until userspace reads data */
	vote(chip->awake_votable, FIFO_DONE_VOTER, true, 0);

done:
	mutex_unlock(&chip->data_lock);
	return IRQ_HANDLED;
}

static irqreturn_t qg_vbat_low_handler(int irq, void *data)
{
	int rc;
	struct qpnp_qg *chip = data;
	u8 status = 0;

	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");
	mutex_lock(&chip->data_lock);

	rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1);
	if (rc < 0) {
		pr_err("Failed to read RT status, rc=%d\n", rc);
		goto done;
	}
	/* ignore VBAT low if battery is missing */
	if ((status & BATTERY_MISSING_INT_RT_STS_BIT) ||
			chip->battery_missing)
		goto done;

	chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT);

	qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low);
done:
	mutex_unlock(&chip->data_lock);
	return IRQ_HANDLED;
}

static irqreturn_t qg_vbat_empty_handler(int irq, void *data)
{
	struct qpnp_qg *chip = data;
	u32 ocv_uv = 0;
	int rc;
	u8 status = 0;

	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");

	rc = qg_read(chip, chip->qg_base + QG_INT_RT_STS_REG, &status, 1);
	if (rc < 0)
		pr_err("Failed to read RT status rc=%d\n", rc);

	/* ignore VBAT empty if battery is missing */
	if ((status & BATTERY_MISSING_INT_RT_STS_BIT) ||
			chip->battery_missing)
		return IRQ_HANDLED;

	pr_warn("VBATT EMPTY SOC = 0\n");

	chip->catch_up_soc = 0;
	qg_scale_soc(chip, true);

	qg_sdam_read(SDAM_OCV_UV, &ocv_uv);
	chip->sdam_data[SDAM_SOC] = 0;
	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
	chip->sdam_data[SDAM_VALID] = 1;

	qg_store_soc_params(chip);

	if (chip->qg_psy)
		power_supply_changed(chip->qg_psy);

	return IRQ_HANDLED;
}

static irqreturn_t qg_good_ocv_handler(int irq, void *data)
{
	int rc;
	u8 status = 0;
	u32 ocv_uv = 0, ocv_raw = 0;
	struct qpnp_qg *chip = data;
	unsigned long rtc_sec = 0;

	qg_dbg(chip, QG_DEBUG_IRQ, "IRQ triggered\n");

	mutex_lock(&chip->data_lock);

	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
	if (rc < 0) {
		pr_err("Failed to read status2 register rc=%d\n", rc);
		goto done;
	}

	if (!(status & GOOD_OCV_BIT))
		goto done;

	rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S3_GOOD_OCV);
	if (rc < 0) {
		pr_err("Failed to read good_ocv, rc=%d\n", rc);
		goto done;
	}

	get_rtc_time(&rtc_sec);
	chip->kdata.fifo_time = (u32)rtc_sec;
	chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
	chip->kdata.param[QG_GOOD_OCV_UV].valid = true;

	vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0);

	/* signal the readd thread */
	chip->data_ready = true;
	wake_up_interruptible(&chip->qg_wait_q);
done:
	mutex_unlock(&chip->data_lock);
	return IRQ_HANDLED;
}

static struct qg_irq_info qg_irqs[] = {
	[QG_BATT_MISSING_IRQ] = {
		.name		= "qg-batt-missing",
	},
	[QG_VBATT_LOW_IRQ] = {
		.name		= "qg-vbat-low",
		.handler	= qg_vbat_low_handler,
		.wake		= true,
	},
	[QG_VBATT_EMPTY_IRQ] = {
		.name		= "qg-vbat-empty",
		.handler	= qg_vbat_empty_handler,
		.wake		= true,
	},
	[QG_FIFO_UPDATE_DONE_IRQ] = {
		.name		= "qg-fifo-done",
		.handler	= qg_fifo_update_done_handler,
		.wake		= true,
	},
	[QG_GOOD_OCV_IRQ] = {
		.name		= "qg-good-ocv",
		.handler	= qg_good_ocv_handler,
		.wake		= true,
	},
	[QG_FSM_STAT_CHG_IRQ] = {
		.name		= "qg-fsm-state-chg",
	},
	[QG_EVENT_IRQ] = {
		.name		= "qg-event",
	},
};

static int qg_awake_cb(struct votable *votable, void *data, int awake,
			const char *client)
{
	struct qpnp_qg *chip = data;

	/* ignore if the QG device is not open */
	if (!chip->qg_device_open)
		return 0;

	if (awake)
		pm_stay_awake(chip->dev);
	else
		pm_relax(chip->dev);

	pr_debug("client: %s awake: %d\n", client, awake);
	return 0;
}

static int qg_fifo_irq_disable_cb(struct votable *votable, void *data,
				int disable, const char *client)
{
	if (disable) {
		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
			disable_irq_wake(
				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
			disable_irq_nosync(
				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
	} else {
		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq)
			enable_irq(qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
		if (qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].wake)
			enable_irq_wake(
				qg_irqs[QG_FIFO_UPDATE_DONE_IRQ].irq);
	}

	return 0;
}

static int qg_vbatt_irq_disable_cb(struct votable *votable, void *data,
				int disable, const char *client)
{
	if (disable) {
		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
			disable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
			disable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
			disable_irq_nosync(qg_irqs[QG_VBATT_LOW_IRQ].irq);
		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
			disable_irq_nosync(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
	} else {
		if (qg_irqs[QG_VBATT_LOW_IRQ].irq)
			enable_irq(qg_irqs[QG_VBATT_LOW_IRQ].irq);
		if (qg_irqs[QG_VBATT_EMPTY_IRQ].irq)
			enable_irq(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
		if (qg_irqs[QG_VBATT_LOW_IRQ].wake)
			enable_irq_wake(qg_irqs[QG_VBATT_LOW_IRQ].irq);
		if (qg_irqs[QG_VBATT_EMPTY_IRQ].wake)
			enable_irq_wake(qg_irqs[QG_VBATT_EMPTY_IRQ].irq);
	}

	return 0;
}

static int qg_good_ocv_irq_disable_cb(struct votable *votable, void *data,
				int disable, const char *client)
{
	if (disable) {
		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
			disable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
			disable_irq_nosync(qg_irqs[QG_GOOD_OCV_IRQ].irq);
	} else {
		if (qg_irqs[QG_GOOD_OCV_IRQ].irq)
			enable_irq(qg_irqs[QG_GOOD_OCV_IRQ].irq);
		if (qg_irqs[QG_GOOD_OCV_IRQ].wake)
			enable_irq_wake(qg_irqs[QG_GOOD_OCV_IRQ].irq);
	}

	return 0;
}

/* ALG callback functions below */

static int qg_get_learned_capacity(void *data, int64_t *learned_cap_uah)
{
	struct qpnp_qg *chip = data;
	int16_t cc_mah;
	int rc;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || !chip->profile_loaded)
		return -ENODEV;

	rc = qg_sdam_multibyte_read(QG_SDAM_LEARNED_CAPACITY_OFFSET,
					(u8 *)&cc_mah, 2);
	if (rc < 0) {
		pr_err("Error in reading learned_capacity, rc=%d\n", rc);
		return rc;
	}
	*learned_cap_uah = cc_mah * 1000;

	return 0;
}

static int qg_store_learned_capacity(void *data, int64_t learned_cap_uah)
{
	struct qpnp_qg *chip = data;
	int16_t cc_mah;
	int rc;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || !learned_cap_uah)
		return -ENODEV;

	cc_mah = div64_s64(learned_cap_uah, 1000);
	rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET,
					 (u8 *)&cc_mah, 2);
	if (rc < 0) {
		pr_err("Error in writing learned_capacity, rc=%d\n", rc);
		return rc;
	}

	qg_dbg(chip, QG_DEBUG_ALG_CL, "Stored learned capacity %llduah\n",
					learned_cap_uah);
	return 0;
}

static int qg_get_batt_age_level(void *data, u32 *batt_age_level)
{
	struct qpnp_qg *chip = data;
	int rc;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || is_debug_batt_id(chip))
		return -ENODEV;

	*batt_age_level = 0;
	rc = qg_sdam_read(SDAM_BATT_AGE_LEVEL, batt_age_level);
	if (rc < 0) {
		pr_err("Error in reading batt_age_level, rc=%d\n", rc);
		return rc;
	}

	return 0;
}

static int qg_store_batt_age_level(void *data, u32 batt_age_level)
{
	struct qpnp_qg *chip = data;
	int rc;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing)
		return -ENODEV;

	rc = qg_sdam_write(SDAM_BATT_AGE_LEVEL, batt_age_level);
	if (rc < 0) {
		pr_err("Error in writing batt_age_level, rc=%d\n", rc);
		return rc;
	}

	return 0;
}

static int qg_get_cc_soc(void *data, int *cc_soc)
{
	struct qpnp_qg *chip = data;

	if (!chip)
		return -ENODEV;

	if (is_debug_batt_id(chip) || chip->battery_missing) {
		*cc_soc = -EINVAL;
		return 0;
	}

	if (chip->cc_soc == INT_MIN)
		*cc_soc = -EINVAL;
	else
		*cc_soc = chip->cc_soc;

	return 0;
}

static int qg_restore_cycle_count(void *data, u16 *buf, int length)
{
	struct qpnp_qg *chip = data;
	int id, rc = 0;
	u8 tmp[2];

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || !chip->profile_loaded)
		return -ENODEV;

	if (!buf || length > BUCKET_COUNT)
		return -EINVAL;

	for (id = 0; id < length; id++) {
		rc = qg_sdam_multibyte_read(
				QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
				(u8 *)tmp, 2);
		if (rc < 0) {
			pr_err("failed to read bucket %d rc=%d\n", id, rc);
			return rc;
		}
		*buf++ = tmp[0] | tmp[1] << 8;
	}

	return rc;
}

static int qg_store_cycle_count(void *data, u16 *buf, int id, int length)
{
	struct qpnp_qg *chip = data;
	int rc = 0;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || !chip->profile_loaded)
		return -ENODEV;

	if (!buf || length > BUCKET_COUNT * 2 || id < 0 ||
		id > BUCKET_COUNT - 1 ||
		(((id * 2) + length) > BUCKET_COUNT * 2))
		return -EINVAL;

	rc = qg_sdam_multibyte_write(
			QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
			(u8 *)buf, length);
	if (rc < 0)
		pr_err("failed to write bucket %d rc=%d\n", id, rc);

	return rc;
}

#define DEFAULT_BATT_TYPE	"Unknown Battery"
#define MISSING_BATT_TYPE	"Missing Battery"
#define DEBUG_BATT_TYPE		"Debug Board"
static const char *qg_get_battery_type(struct qpnp_qg *chip)
{
	if (chip->battery_missing)
		return MISSING_BATT_TYPE;

	if (is_debug_batt_id(chip))
		return DEBUG_BATT_TYPE;

	if (chip->bp.batt_type_str) {
		if (chip->profile_loaded)
			return chip->bp.batt_type_str;
	}

	return DEFAULT_BATT_TYPE;
}

#define DEBUG_BATT_SOC		67
#define BATT_MISSING_SOC	50
#define EMPTY_SOC		0
#define FULL_SOC		100
static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc)
{
	if (is_debug_batt_id(chip)) {
		*soc = DEBUG_BATT_SOC;
		return 0;
	}

	if (chip->battery_missing || !chip->profile_loaded) {
		*soc = BATT_MISSING_SOC;
		return 0;
	}

	if (chip->charge_full) {
		*soc = FULL_SOC;
		return 0;
	}

	mutex_lock(&chip->soc_lock);

	if (chip->dt.linearize_soc && chip->maint_soc > 0)
		*soc = chip->maint_soc;
	else
		*soc = chip->msoc;

	mutex_unlock(&chip->soc_lock);

	return 0;
}

static int qg_get_battery_capacity_real(struct qpnp_qg *chip, int *soc)
{
	mutex_lock(&chip->soc_lock);
	*soc = chip->msoc;
	mutex_unlock(&chip->soc_lock);

	return 0;
}

static int qg_get_charge_counter(struct qpnp_qg *chip, int *charge_counter)
{
	int rc, cc_soc = 0;
	int64_t temp = 0;

	if (is_debug_batt_id(chip) || chip->battery_missing) {
		*charge_counter = -EINVAL;
		return 0;
	}

	rc = qg_get_learned_capacity(chip, &temp);
	if (rc < 0 || !temp)
		rc = qg_get_nominal_capacity((int *)&temp, 250, true);

	if (rc < 0) {
		pr_err("Failed to get FCC for charge-counter rc=%d\n", rc);
		return rc;
	}

	cc_soc = CAP(0, 100, DIV_ROUND_CLOSEST(chip->cc_soc, 100));
	*charge_counter = div_s64(temp * cc_soc, 100);

	return 0;
}

static int qg_get_power(struct qpnp_qg *chip, int *val, bool average)
{
	int rc, v_min, v_ocv, rbatt = 0, esr = 0;
	s64 power;

	if (is_debug_batt_id(chip)) {
		*val = -EINVAL;
		return 0;
	}

	v_min = chip->dt.sys_min_volt_mv * 1000;

	rc = qg_sdam_read(SDAM_OCV_UV, &v_ocv);
	if (rc < 0) {
		pr_err("Failed to read OCV rc=%d\n", rc);
		return rc;
	}

	rc = qg_sdam_read(SDAM_RBAT_MOHM, &rbatt);
	if (rc < 0) {
		pr_err("Failed to read T_RBAT rc=%d\n", rc);
		return rc;
	}

	rbatt *= 1000;	/* uohms */
	esr = chip->esr_last * 1000;

	if (rbatt <= 0 || esr <= 0) {
		pr_debug("Invalid rbatt/esr rbatt=%d esr=%d\n", rbatt, esr);
		*val = -EINVAL;
		return 0;
	}

	power = (s64)v_min * (v_ocv - v_min);

	if (average)
		power = div_s64(power, rbatt);
	else
		power = div_s64(power, esr);

	*val = power;

	qg_dbg(chip, QG_DEBUG_STATUS, "v_min=%d v_ocv=%d rbatt=%d esr=%d power=%lld\n",
			v_min, v_ocv, rbatt, esr, power);

	return 0;
}

static int qg_get_ttf_param(void *data, enum ttf_param param, int *val)
{
	struct qpnp_qg *chip = data;
	int rc = 0;
	int64_t temp = 0;

	if (!chip)
		return -ENODEV;

	switch (param) {
	case TTF_TTE_VALID:
		*val = 1;
		if (chip->battery_missing || is_debug_batt_id(chip))
			*val = 0;
		break;
	case TTF_MSOC:
		rc = qg_get_battery_capacity(chip, val);
		break;
	case TTF_VBAT:
		rc = qg_get_battery_voltage(chip, val);
		break;
	case TTF_IBAT:
		rc = qg_get_battery_current(chip, val);
		break;
	case TTF_FCC:
		if (!chip->dt.cl_disable && chip->dt.cl_feedback_on)
			rc = qg_get_learned_capacity(chip, &temp);
		else
			rc = qg_get_nominal_capacity((int *)&temp, 250,
							true);
		if (!rc) {
			temp = div64_u64(temp, 1000);
			*val  = div64_u64(chip->full_soc * temp,
					QG_SOC_FULL);
		}
		break;
	case TTF_MODE:
		if (chip->ttf->step_chg_cfg_valid)
			*val = TTF_MODE_VBAT_STEP_CHG;
		else
			*val = TTF_MODE_NORMAL;
		break;
	case TTF_ITERM:
		if (chip->chg_iterm_ma == INT_MIN)
			*val = 0;
		else
			*val = chip->chg_iterm_ma;
		break;
	case TTF_RBATT:
		rc = qg_sdam_read(SDAM_RBAT_MOHM, val);
		if (!rc)
			*val *= 1000;
		break;
	case TTF_VFLOAT:
		*val = chip->bp.float_volt_uv;
		break;
	case TTF_CHG_TYPE:
		*val = chip->charge_type;
		break;
	case TTF_CHG_STATUS:
		*val = chip->charge_status;
		break;
	case TTF_CHG_DONE:
		*val = chip->charge_done;
		break;
	default:
		pr_err("Unsupported property %d\n", param);
		rc = -EINVAL;
		break;
	}

	return rc;
}

static int qg_ttf_awake_voter(void *data, bool val)
{
	struct qpnp_qg *chip = data;

	if (!chip)
		return -ENODEV;

	if (chip->battery_missing || !chip->profile_loaded)
		return -ENODEV;

	vote(chip->awake_votable, TTF_AWAKE_VOTER, val, 0);

	return 0;
}

#define MAX_QG_OK_RETRIES	20
static int qg_reset(struct qpnp_qg *chip)
{
	int rc = 0, count = 0, soc = 0;
	u32 ocv_uv = 0, ocv_raw = 0;
	u8 reg = 0;

	qg_dbg(chip, QG_DEBUG_STATUS, "QG RESET triggered\n");

	mutex_lock(&chip->data_lock);

	/* hold and release master to clear FIFO's */
	rc = qg_master_hold(chip, true);
	if (rc < 0) {
		pr_err("Failed to hold master, rc=%d\n", rc);
		goto done;
	}

	/* delay for the master-hold */
	msleep(20);

	rc = qg_master_hold(chip, false);
	if (rc < 0) {
		pr_err("Failed to release master, rc=%d\n", rc);
		goto done;
	}

	/* delay for master to settle */
	msleep(20);

	qg_get_battery_voltage(chip, &rc);
	qg_get_battery_capacity(chip, &soc);
	qg_dbg(chip, QG_DEBUG_STATUS, "VBAT=%duV SOC=%d\n", rc, soc);

	/* Trigger S7 */
	rc = qg_masked_write(chip, chip->qg_base + QG_STATE_TRIG_CMD_REG,
				S7_PON_OCV_START, S7_PON_OCV_START);
	if (rc < 0) {
		pr_err("Failed to trigger S7, rc=%d\n", rc);
		goto done;
	}

	/* poll for QG OK */
	do {
		rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, &reg, 1);
		if (rc < 0) {
			pr_err("Failed to read STATUS1_REG rc=%d\n", rc);
			goto done;
		}

		if (reg & QG_OK_BIT)
			break;

		msleep(200);
		count++;
	} while (count < MAX_QG_OK_RETRIES);

	if (count == MAX_QG_OK_RETRIES) {
		qg_dbg(chip, QG_DEBUG_STATUS, "QG_OK not set\n");
		goto done;
	}

	/* read S7 PON OCV */
	rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S7_PON_OCV);
	if (rc < 0) {
		pr_err("Failed to read PON OCV rc=%d\n", rc);
		goto done;
	}

	qg_dbg(chip, QG_DEBUG_STATUS, "S7_OCV = %duV\n", ocv_uv);

	chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
	chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
	/* clear all the userspace data */
	chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1;
	chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true;

	vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0);
	/* signal the read thread */
	chip->data_ready = true;
	chip->force_soc = true;
	wake_up_interruptible(&chip->qg_wait_q);

done:
	mutex_unlock(&chip->data_lock);
	return rc;
}

static int qg_setprop_batt_age_level(struct qpnp_qg *chip, int batt_age_level)
{
	int rc = 0;
	u16 data = 0;

	if (!chip->dt.multi_profile_load)
		return 0;

	if (batt_age_level < 0) {
		pr_err("Invalid age-level %d\n", batt_age_level);
		return -EINVAL;
	}

	if (chip->batt_age_level == batt_age_level) {
		qg_dbg(chip, QG_DEBUG_PROFILE, "Same age-level %d\n",
						chip->batt_age_level);
		return 0;
	}

	chip->batt_age_level = batt_age_level;
	rc = qg_load_battery_profile(chip);
	if (rc < 0) {
		pr_err("failed to load profile\n");
	} else {
		rc = qg_store_batt_age_level(chip, batt_age_level);
		if (rc < 0)
			pr_err("error in storing batt_age_level rc =%d\n", rc);
	}

	/* Clear the learned capacity on loading a new profile */
	rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET,
						(u8 *)&data, 2);

	if (rc < 0)
		pr_err("Failed to clear SDAM learnt capacity rc=%d\n", rc);

	qg_dbg(chip, QG_DEBUG_PROFILE, "Profile with batt_age_level = %d loaded\n",
						chip->batt_age_level);

	return rc;
}

static int qg_iio_write_raw(struct iio_dev *indio_dev,
		struct iio_chan_spec const *chan, int val1,
		int val2, long mask)
{
	struct qpnp_qg *chip = iio_priv(indio_dev);
	int rc = 0;

	switch (chan->channel) {
	case PSY_IIO_CHARGE_FULL:
		if (chip->dt.cl_disable) {
			pr_warn("Capacity learning disabled!\n");
			return 0;
		}
		if (chip->cl->active) {
			pr_warn("Capacity learning active!\n");
			return 0;
		}
		if (val1 <= 0 || val1 > chip->cl->nom_cap_uah) {
			pr_err("charge_full is out of bounds\n");
			return -EINVAL;
		}
		mutex_lock(&chip->cl->lock);
		rc = qg_store_learned_capacity(chip, val1);
		if (!rc)
			chip->cl->learned_cap_uah = val1;
		mutex_unlock(&chip->cl->lock);
		break;
	case PSY_IIO_SOH:
		chip->soh = val1;
		qg_dbg(chip, QG_DEBUG_STATUS, "SOH update: SOH=%d esr_actual=%d esr_nominal=%d\n",
				chip->soh, chip->esr_actual, chip->esr_nominal);
		if (chip->sp)
			soh_profile_update(chip->sp, chip->soh);
		break;
	case PSY_IIO_CLEAR_SOH:
		chip->first_profile_load = val1;
		break;
	case PSY_IIO_ESR_ACTUAL:
		chip->esr_actual = val1;
		break;
	case PSY_IIO_ESR_NOMINAL:
		chip->esr_nominal = val1;
		break;
	case PSY_IIO_FG_RESET:
		qg_reset(chip);
		break;
	case PSY_IIO_BATT_AGE_LEVEL:
		rc = qg_setprop_batt_age_level(chip, val1);
		break;
	default:
		pr_debug("Unsupported QG IIO chan %d\n", chan->channel);
		rc = -EINVAL;
		break;
	}

	if (rc < 0)
		pr_err_ratelimited("Couldn't write IIO channel %d, rc = %d\n",
			chan->channel, rc);

	return rc;
}

static int qg_iio_read_raw(struct iio_dev *indio_dev,
		struct iio_chan_spec const *chan, int *val1,
		int *val2, long mask)
{
	struct qpnp_qg *chip = iio_priv(indio_dev);
	int64_t temp = 0;
	int rc = 0;

	*val1 = 0;

	switch (chan->channel) {
	case PSY_IIO_CAPACITY:
		rc = qg_get_battery_capacity(chip, val1);
		break;
	case PSY_IIO_CAPACITY_RAW:
		*val1 = chip->sys_soc;
		break;
	case PSY_IIO_REAL_CAPACITY:
		rc = qg_get_battery_capacity_real(chip, val1);
		break;
	case PSY_IIO_VOLTAGE_NOW:
		rc = qg_get_battery_voltage(chip, val1);
		break;
	case PSY_IIO_CURRENT_NOW:
		rc = qg_get_battery_current(chip, val1);
		break;
	case PSY_IIO_VOLTAGE_OCV:
		rc = qg_sdam_read(SDAM_OCV_UV, val1);
		break;
	case PSY_IIO_TEMP:
		rc = qg_get_battery_temp(chip, val1);
		break;
	case PSY_IIO_RESISTANCE_ID:
		*val1 = chip->batt_id_ohm;
		break;
	case PSY_IIO_DEBUG_BATTERY:
		*val1 = is_debug_batt_id(chip);
		break;
	case PSY_IIO_RESISTANCE:
		rc = qg_sdam_read(SDAM_RBAT_MOHM, val1);
		if (!rc)
			*val1 *= 1000;
		break;
	case PSY_IIO_SOC_REPORTING_READY:
		*val1 = chip->soc_reporting_ready;
		break;
	case PSY_IIO_RESISTANCE_CAPACITIVE:
		*val1 = chip->dt.rbat_conn_mohm;
		break;
	case PSY_IIO_VOLTAGE_MIN:
		*val1 = chip->dt.vbatt_cutoff_mv * 1000;
		break;
	case PSY_IIO_VOLTAGE_MAX:
		*val1 = chip->bp.float_volt_uv;
		break;
	case PSY_IIO_BATT_FULL_CURRENT:
		*val1 = chip->dt.iterm_ma * 1000;
		break;
	case PSY_IIO_BATT_PROFILE_VERSION:
		*val1 = chip->bp.qg_profile_version;
		break;
	case PSY_IIO_CHARGE_COUNTER:
		rc = qg_get_charge_counter(chip, val1);
		break;
	case PSY_IIO_CHARGE_FULL:
		if (!chip->dt.cl_disable && chip->dt.cl_feedback_on)
			rc = qg_get_learned_capacity(chip, &temp);
		else
			rc = qg_get_nominal_capacity((int *)&temp, 250, true);
		if (!rc)
			*val1 = (int)temp;
		break;
	case PSY_IIO_CHARGE_FULL_DESIGN:
		rc = qg_get_nominal_capacity((int *)&temp, 250, true);
		if (!rc)
			*val1 = (int)temp;
		break;
	case PSY_IIO_CYCLE_COUNT:
		rc = get_cycle_count(chip->counter, val1);
		break;
	case PSY_IIO_TIME_TO_FULL_AVG:
		rc = ttf_get_time_to_full(chip->ttf, val1);
		break;
	case PSY_IIO_TIME_TO_FULL_NOW:
		rc = ttf_get_time_to_full(chip->ttf, val1);
		break;
	case PSY_IIO_TIME_TO_EMPTY_AVG:
		rc = ttf_get_time_to_empty(chip->ttf, val1);
		break;
	case PSY_IIO_ESR_ACTUAL:
		*val1 = (chip->esr_actual == -EINVAL) ?  -EINVAL :
					(chip->esr_actual * 1000);
		break;
	case PSY_IIO_ESR_NOMINAL:
		*val1 = (chip->esr_nominal == -EINVAL) ?  -EINVAL :
					(chip->esr_nominal * 1000);
		break;
	case PSY_IIO_SOH:
		*val1 = chip->soh;
		break;
	case PSY_IIO_CLEAR_SOH:
		*val1 = chip->first_profile_load;
		break;
	case PSY_IIO_CC_SOC:
		rc = qg_get_cc_soc(chip, val1);
		break;
	case PSY_IIO_FG_RESET:
		*val1 = 0;
		break;
	case PSY_IIO_VOLTAGE_AVG:
		rc = qg_get_vbat_avg(chip, val1);
		break;
	case PSY_IIO_CURRENT_AVG:
		rc = qg_get_ibat_avg(chip, val1);
		break;
	case PSY_IIO_POWER_NOW:
		rc = qg_get_power(chip, val1, false);
		break;
	case PSY_IIO_POWER_AVG:
		rc = qg_get_power(chip, val1, true);
		break;
	case PSY_IIO_SCALE_MODE_EN:
		*val1 = chip->fvss_active;
		break;
	case PSY_IIO_BATT_AGE_LEVEL:
		*val1 = chip->batt_age_level;
		break;
	case PSY_IIO_FG_TYPE:
		*val1 = chip->qg_mode;
		break;
	default:
		pr_debug("Unsupported QG IIO chan %d\n", chan->channel);
		rc = -EINVAL;
		break;
	}

	if (rc < 0) {
		pr_err_ratelimited("Couldn't read IIO channel %d, rc = %d\n",
			chan->channel, rc);
		return rc;
	}

	return IIO_VAL_INT;
}

static int qg_iio_of_xlate(struct iio_dev *indio_dev,
				const struct of_phandle_args *iiospec)
{
	struct qpnp_qg *chip = iio_priv(indio_dev);
	struct iio_chan_spec *iio_chan = chip->iio_chan;
	int i;

	for (i = 0; i < ARRAY_SIZE(qg_iio_psy_channels);
					i++, iio_chan++)
		if (iio_chan->channel == iiospec->args[0])
			return i;

	return -EINVAL;
}

static const struct iio_info qg_iio_info = {
	.read_raw	= qg_iio_read_raw,
	.write_raw	= qg_iio_write_raw,
	.of_xlate	= qg_iio_of_xlate,
};

#define DEFAULT_CL_BEGIN_IBAT_UA	(-100000)
static bool qg_cl_ok_to_begin(void *data)
{
	struct qpnp_qg *chip = data;

	if (chip->last_fifo_i_ua < DEFAULT_CL_BEGIN_IBAT_UA)
		return true;

	return false;
}

#define DEFAULT_RECHARGE_SOC 95
static int qg_charge_full_update(struct qpnp_qg *chip)
{
	union power_supply_propval prop = {0, };
	int rc, recharge_soc, health, val;

	if (!chip->dt.hold_soc_while_full)
		goto out;

	rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_HEALTH, &prop);
	if (rc < 0) {
		pr_err("Failed to get battery health, rc=%d\n", rc);
		goto out;
	}
	health = prop.intval;

	rc = qg_read_iio_chan(chip, RECHARGE_SOC, &val);
	if (rc < 0 || val < 0) {
		pr_debug("Failed to get recharge-soc\n");
		recharge_soc = DEFAULT_RECHARGE_SOC;
	} else {
		recharge_soc = val;
	}
	chip->recharge_soc = recharge_soc;

	qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d charge_done=%d\n",
				chip->msoc, health, chip->charge_full,
				chip->charge_done);
	if (chip->charge_done && !chip->charge_full) {
		if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) {
			chip->charge_full = true;
			qg_dbg(chip, QG_DEBUG_STATUS, "Setting charge_full (0->1) @ msoc=%d\n",
					chip->msoc);
		} else if (health != POWER_SUPPLY_HEALTH_GOOD) {
			/* terminated in JEITA */
			qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n",
					chip->msoc);
		}
	} else if ((!chip->charge_done || chip->msoc <= recharge_soc)
				&& chip->charge_full) {

		bool input_present = is_input_present(chip);

		/*
		 * force a recharge only if SOC <= recharge SOC and
		 * we have not started charging.
		 */
		if ((chip->wa_flags & QG_RECHARGE_SOC_WA) &&
			input_present && chip->msoc <= recharge_soc &&
			chip->charge_status != POWER_SUPPLY_STATUS_CHARGING) {
			/* Force recharge */
			rc = qg_write_iio_chan(chip, FORCE_RECHARGE, 0);
			if (rc < 0)
				pr_err("Failed to force recharge rc=%d\n", rc);
			else
				qg_dbg(chip, QG_DEBUG_STATUS, "Forced recharge\n");
		}


		if (chip->charge_done)
			return 0;	/* wait for recharge */

		/*
		 * If SOC has indeed dropped below recharge-SOC or
		 * the input is removed, if linearize-soc is set scale
		 * msoc from 100% for better UX.
		 */
		if (chip->msoc < recharge_soc || !input_present) {
			if (chip->dt.linearize_soc) {
				get_rtc_time(&chip->last_maint_soc_update_time);
				chip->maint_soc = FULL_SOC;
				qg_scale_soc(chip, false);
			}
			chip->charge_full = false;
			qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n",
					chip->msoc, recharge_soc);
		} else {
			/* continue with charge_full state */
			qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full=%d input_present=%d\n",
					chip->msoc, recharge_soc,
					chip->charge_full, input_present);
		}
	}
out:
	return 0;
}

static int qg_parallel_status_update(struct qpnp_qg *chip)
{
	int rc;
	bool parallel_enabled = is_parallel_enabled(chip);
	bool update_smb = false;

	if (parallel_enabled == chip->parallel_enabled)
		return 0;

	chip->parallel_enabled = parallel_enabled;
	qg_dbg(chip, QG_DEBUG_STATUS,
		"Parallel status changed Enabled=%d\n", parallel_enabled);

	mutex_lock(&chip->data_lock);
	/*
	 * dt.qg_ext_sense = Uses external rsense, if defined do not
	 *		     enable SMB sensing (for non-CP parallel charger).
	 * dt.cp_iin_sns = Uses CP IIN_SNS, enable SMB sensing (for CP charger).
	 */
	if (is_cp_available(chip))
		update_smb = chip->dt.use_cp_iin_sns ? true : false;
	else if (is_parallel_available(chip))
		update_smb = chip->dt.qg_ext_sense ? false : true;

	rc = process_rt_fifo_data(chip, update_smb);
	if (rc < 0)
		pr_err("Failed to process RT FIFO data, rc=%d\n", rc);

	mutex_unlock(&chip->data_lock);

	return 0;
}

static int qg_input_status_update(struct qpnp_qg *chip)
{
	bool usb_present = is_usb_present(chip);
	bool dc_present = is_dc_present(chip);

	if ((chip->usb_present != usb_present) ||
		(chip->dc_present != dc_present)) {
		qg_dbg(chip, QG_DEBUG_STATUS,
			"Input status changed usb_present=%d dc_present=%d\n",
						usb_present, dc_present);
		qg_scale_soc(chip, false);
	}

	chip->usb_present = usb_present;
	chip->dc_present = dc_present;

	return 0;
}

static int qg_handle_battery_removal(struct qpnp_qg *chip)
{
	int rc, length = QG_SDAM_MAX_OFFSET - QG_SDAM_VALID_OFFSET;
	u8 *data;

	/* clear SDAM */
	data = kcalloc(length, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	rc = qg_sdam_multibyte_write(QG_SDAM_VALID_OFFSET, data, length);
	if (rc < 0)
		pr_err("Failed to clear SDAM rc=%d\n", rc);

	return rc;
}

static int qg_handle_battery_insertion(struct qpnp_qg *chip)
{
	int rc, count = 0;
	u32 ocv_uv = 0, ocv_raw = 0;
	u8 reg = 0;

	do {
		rc = qg_read(chip, chip->qg_base + QG_STATUS1_REG, &reg, 1);
		if (rc < 0) {
			pr_err("Failed to read STATUS1_REG rc=%d\n", rc);
			return rc;
		}

		if (reg & QG_OK_BIT)
			break;

		msleep(200);
		count++;
	} while (count < MAX_QG_OK_RETRIES);

	if (count == MAX_QG_OK_RETRIES) {
		qg_dbg(chip, QG_DEBUG_STATUS, "QG_OK not set!\n");
		return 0;
	}

	/* read S7 PON OCV */
	rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S7_PON_OCV);
	if (rc < 0) {
		pr_err("Failed to read PON OCV rc=%d\n", rc);
		return rc;
	}

	qg_dbg(chip, QG_DEBUG_STATUS,
		"S7_OCV on battery insertion = %duV\n", ocv_uv);

	chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
	chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
	/* clear all the userspace data */
	chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1;
	chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true;

	vote(chip->awake_votable, GOOD_OCV_VOTER, true, 0);
	/* signal the read thread */
	chip->data_ready = true;
	wake_up_interruptible(&chip->qg_wait_q);

	return 0;
}

static int qg_battery_status_update(struct qpnp_qg *chip)
{
	int rc;
	union power_supply_propval prop = {0, };

	if (!is_batt_available(chip))
		return 0;

	mutex_lock(&chip->data_lock);

	rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_PRESENT, &prop);
	if (rc < 0) {
		pr_err("Failed to get battery-present, rc=%d\n", rc);
		goto done;
	}

	if (chip->battery_missing && prop.intval) {
		pr_warn("Battery inserted!\n");
		rc = qg_handle_battery_insertion(chip);
		if (rc < 0)
			pr_err("Failed in battery-insertion rc=%d\n", rc);
	} else if (!chip->battery_missing && !prop.intval) {
		pr_warn("Battery removed!\n");
		rc = qg_handle_battery_removal(chip);
		if (rc < 0)
			pr_err("Failed in battery-removal rc=%d\n", rc);
	}

	chip->battery_missing = !prop.intval;

done:
	mutex_unlock(&chip->data_lock);
	return rc;
}

static void qg_sleep_exit_work(struct work_struct *work)
{
	int rc;
	struct qpnp_qg *chip = container_of(work,
			struct qpnp_qg, qg_sleep_exit_work.work);

	vote(chip->awake_votable, SLEEP_EXIT_VOTER, true, 0);

	mutex_lock(&chip->data_lock);
	/*
	 * if this work is executing, the system has been active
	 * for a while. So, force back the S2 active configuration
	 */
	qg_dbg(chip, QG_DEBUG_STATUS, "sleep_exit_work: exit S2_SLEEP\n");
	rc = qg_config_s2_state(chip, S2_SLEEP, false, true);
	if (rc < 0)
		pr_err("Failed to exit S2_SLEEP rc=%d\n", rc);

	vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, true, 0);
	/* signal the read thread */
	chip->data_ready = true;
	wake_up_interruptible(&chip->qg_wait_q);

	mutex_unlock(&chip->data_lock);

	vote(chip->awake_votable, SLEEP_EXIT_VOTER, false, 0);
}

static void qg_status_change_work(struct work_struct *work)
{
	struct qpnp_qg *chip = container_of(work,
			struct qpnp_qg, qg_status_change_work);
	union power_supply_propval prop = {0, };
	int rc = 0, batt_temp = 0, val;
	bool input_present = false;

	if (!is_batt_available(chip)) {
		pr_debug("batt-psy not available\n");
		goto out;
	}

	rc = qg_battery_status_update(chip);
	if (rc < 0)
		pr_err("Failed to process battery status update rc=%d\n", rc);

	rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
	if (rc < 0)
		pr_err("Failed to get charge-type, rc=%d\n", rc);
	else
		chip->charge_type = prop.intval;

	rc = power_supply_get_property(chip->batt_psy,
			POWER_SUPPLY_PROP_STATUS, &prop);
	if (rc < 0)
		pr_err("Failed to get charger status, rc=%d\n", rc);
	else
		chip->charge_status = prop.intval;

	rc = qg_read_iio_chan(chip, CHARGE_DONE, &val);
	if (rc < 0)
		pr_err("Failed to get charge done status, rc=%d\n", rc);
	else
		chip->charge_done = val;

	qg_dbg(chip, QG_DEBUG_STATUS, "charge_status=%d charge_done=%d\n",
			chip->charge_status, chip->charge_done);

	rc = qg_parallel_status_update(chip);
	if (rc < 0)
		pr_err("Failed to update parallel-status, rc=%d\n", rc);

	rc = qg_input_status_update(chip);
	if (rc < 0)
		pr_err("Failed to update input status, rc=%d\n", rc);

	/* get input status */
	input_present = is_input_present(chip);

	cycle_count_update(chip->counter,
			DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
			chip->charge_status, chip->charge_done,
			input_present);

	if (!chip->dt.cl_disable) {
		rc = qg_get_battery_temp(chip, &batt_temp);
		if (rc < 0) {
			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
		} else if (chip->batt_soc >= 0) {
			cap_learning_update(chip->cl, batt_temp, chip->batt_soc,
				chip->charge_status, chip->charge_done,
				input_present, false);
		}
	}
	rc = qg_charge_full_update(chip);
	if (rc < 0)
		pr_err("Failed in charge_full_update, rc=%d\n", rc);

	ttf_update(chip->ttf, input_present);
out:
	pm_relax(chip->dev);
}

static int qg_notifier_cb(struct notifier_block *nb,
			unsigned long event, void *data)
{
	struct power_supply *psy = data;
	struct qpnp_qg *chip = container_of(nb, struct qpnp_qg, nb);

	if (event != PSY_EVENT_PROP_CHANGED)
		return NOTIFY_OK;

	if (work_pending(&chip->qg_status_change_work))
		return NOTIFY_OK;

	if ((strcmp(psy->desc->name, "battery") == 0)
		|| (strcmp(psy->desc->name, "parallel") == 0)
		|| (strcmp(psy->desc->name, "usb") == 0)
		|| (strcmp(psy->desc->name, "dc") == 0)
		|| (strcmp(psy->desc->name, "charge_pump_master") == 0)) {
		/*
		 * We cannot vote for awake votable here as that takes
		 * a mutex lock and this is executed in an atomic context.
		 */
		pm_stay_awake(chip->dev);
		schedule_work(&chip->qg_status_change_work);
	}

	return NOTIFY_OK;
}

static int qg_psy_get_property(struct power_supply *psy,
			       enum power_supply_property psp,
			       union power_supply_propval *pval)
{
	if (psp == POWER_SUPPLY_PROP_TYPE)
		pval->intval = POWER_SUPPLY_TYPE_MAINS;

	return 0;
}

static enum power_supply_property qg_psy_props[] = {
	POWER_SUPPLY_PROP_TYPE,
};

static const struct power_supply_desc qg_psy_desc = {
	.name = "bms",
	.type = POWER_SUPPLY_TYPE_MAINS,
	.properties = qg_psy_props,
	.num_properties = ARRAY_SIZE(qg_psy_props),
	.get_property = qg_psy_get_property,
};

static int qg_init_psy(struct qpnp_qg *chip)
{
	struct power_supply_config qg_psy_cfg = {};
	int rc;

	qg_psy_cfg.drv_data = chip;
	chip->qg_psy = devm_power_supply_register(chip->dev,
				&qg_psy_desc, &qg_psy_cfg);
	if (IS_ERR_OR_NULL(chip->qg_psy)) {
		pr_err("Failed to register qg_psy, rc = %d\n",
				PTR_ERR(chip->qg_psy));
		return -ENODEV;
	}

	chip->nb.notifier_call = qg_notifier_cb;
	rc = power_supply_reg_notifier(&chip->nb);
	if (rc < 0)
		pr_err("Failed to register psy notifier rc = %d\n", rc);

	return rc;
}

static int qg_init_iio_psy(struct qpnp_qg *chip,
				struct platform_device *pdev)
{
	struct iio_dev *indio_dev = chip->indio_dev;
	struct iio_chan_spec *chan;
	int qg_num_iio_channels = ARRAY_SIZE(qg_iio_psy_channels);
	int rc, i;

	chip->iio_chan = devm_kcalloc(chip->dev, qg_num_iio_channels,
				sizeof(*chip->iio_chan), GFP_KERNEL);
	if (!chip->iio_chan)
		return -ENOMEM;

	chip->int_iio_chans = devm_kcalloc(chip->dev,
				qg_num_iio_channels,
				sizeof(*chip->int_iio_chans),
				GFP_KERNEL);
	if (!chip->int_iio_chans)
		return -ENOMEM;

	chip->ext_iio_chans = devm_kcalloc(chip->dev,
				ARRAY_SIZE(qg_ext_iio_chan_name),
				sizeof(*chip->ext_iio_chans),
				GFP_KERNEL);
	if (!chip->ext_iio_chans)
		return -ENOMEM;

	indio_dev->info = &qg_iio_info;
	indio_dev->dev.parent = chip->dev;
	indio_dev->dev.of_node = chip->dev->of_node;
	indio_dev->name = "qpnp,qg";
	indio_dev->modes = INDIO_DIRECT_MODE;
	indio_dev->channels = chip->iio_chan;
	indio_dev->num_channels = qg_num_iio_channels;

	for (i = 0; i < qg_num_iio_channels; i++) {
		chip->int_iio_chans[i].indio_dev = indio_dev;
		chan = &chip->iio_chan[i];
		chip->int_iio_chans[i].channel = chan;
		chan->address = i;
		chan->channel = qg_iio_psy_channels[i].channel_num;
		chan->type = qg_iio_psy_channels[i].type;
		chan->datasheet_name =
			qg_iio_psy_channels[i].datasheet_name;
		chan->extend_name =
			qg_iio_psy_channels[i].datasheet_name;
		chan->info_mask_separate =
			qg_iio_psy_channels[i].info_mask;
	}

	rc = devm_iio_device_register(chip->dev, indio_dev);
	if (rc)
		pr_err("Failed to register QG IIO device, rc=%d\n", rc);

	return rc;
}

static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count,
			  loff_t *ppos)
{
	int rc;
	struct qpnp_qg *chip = file->private_data;
	unsigned long data_size = sizeof(chip->kdata);

	if (count < data_size) {
		pr_err("Invalid datasize %lu, expected lesser then %zu\n",
							data_size, count);
		return -EINVAL;
	}

	/* non-blocking access, return */
	if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
		return 0;

	/* blocking access wait on data_ready */
	if (!(file->f_flags & O_NONBLOCK)) {
		rc = wait_event_interruptible(chip->qg_wait_q,
					chip->data_ready);
		if (rc < 0) {
			pr_debug("Failed wait! rc=%d\n", rc);
			return rc;
		}
	}

	mutex_lock(&chip->data_lock);

	if (!chip->data_ready) {
		pr_debug("No Data, false wakeup\n");
		rc = -EFAULT;
		goto fail_read;
	}


	if (copy_to_user(buf, &chip->kdata, data_size)) {
		pr_err("Failed in copy_to_user\n");
		rc = -EFAULT;
		goto fail_read;
	}
	chip->data_ready = false;

	/* release all wake sources */
	vote(chip->awake_votable, GOOD_OCV_VOTER, false, 0);
	vote(chip->awake_votable, FIFO_DONE_VOTER, false, 0);
	vote(chip->awake_votable, FIFO_RT_DONE_VOTER, false, 0);
	vote(chip->awake_votable, SUSPEND_DATA_VOTER, false, 0);
	vote(chip->awake_votable, SLEEP_EXIT_DATA_VOTER, false, 0);

	qg_dbg(chip, QG_DEBUG_DEVICE,
		"QG device read complete Seq_no=%u Size=%ld\n",
				chip->kdata.seq_no, data_size);

	/* clear data */
	memset(&chip->kdata, 0, sizeof(chip->kdata));

	mutex_unlock(&chip->data_lock);

	return data_size;

fail_read:
	mutex_unlock(&chip->data_lock);
	return rc;
}

static ssize_t qg_device_write(struct file *file, const char __user *buf,
			size_t count, loff_t *ppos)
{
	int rc = -EINVAL;
	struct qpnp_qg *chip = file->private_data;
	unsigned long data_size = sizeof(chip->udata);

	mutex_lock(&chip->data_lock);
	if (count == 0) {
		pr_err("No data!\n");
		goto fail;
	}

	if (count != 0 && count < data_size) {
		pr_err("Invalid datasize %zu expected %lu\n", count, data_size);
		goto fail;
	}

	if (copy_from_user(&chip->udata, buf, data_size)) {
		pr_err("Failed in copy_from_user\n");
		rc = -EFAULT;
		goto fail;
	}

	rc = data_size;
	vote(chip->awake_votable, UDATA_READY_VOTER, true, 0);
	schedule_work(&chip->udata_work);
	qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc);
fail:
	mutex_unlock(&chip->data_lock);
	return rc;
}

static unsigned int qg_device_poll(struct file *file, poll_table *wait)
{
	struct qpnp_qg *chip = file->private_data;
	unsigned int mask = 0;

	poll_wait(file, &chip->qg_wait_q, wait);

	if (chip->data_ready)
		mask = POLLIN | POLLRDNORM;

	return mask;
}

static int qg_device_open(struct inode *inode, struct file *file)
{
	struct qpnp_qg *chip = container_of(inode->i_cdev,
				struct qpnp_qg, qg_cdev);

	file->private_data = chip;
	chip->qg_device_open = true;
	qg_dbg(chip, QG_DEBUG_DEVICE, "QG device opened!\n");

	return 0;
}

static int qg_device_release(struct inode *inode, struct file *file)
{
	struct qpnp_qg *chip = container_of(inode->i_cdev,
				struct qpnp_qg, qg_cdev);

	file->private_data = chip;
	chip->qg_device_open = false;
	qg_dbg(chip, QG_DEBUG_DEVICE, "QG device closed!\n");

	return 0;
}

static const struct file_operations qg_fops = {
	.owner		= THIS_MODULE,
	.open		= qg_device_open,
	.release	= qg_device_release,
	.read		= qg_device_read,
	.write		= qg_device_write,
	.poll		= qg_device_poll,
};

static int qg_register_device(struct qpnp_qg *chip)
{
	int rc;

	rc = alloc_chrdev_region(&chip->dev_no, 0, 1, "qg");
	if (rc < 0) {
		pr_err("Failed to allocate chardev rc=%d\n", rc);
		return rc;
	}

	cdev_init(&chip->qg_cdev, &qg_fops);
	rc = cdev_add(&chip->qg_cdev, chip->dev_no, 1);
	if (rc < 0) {
		pr_err("Failed to cdev_add rc=%d\n", rc);
		goto unregister_chrdev;
	}

	chip->qg_class = class_create(THIS_MODULE, "qg");
	if (IS_ERR_OR_NULL(chip->qg_class)) {
		pr_err("Failed to create qg class\n");
		rc = -EINVAL;
		goto delete_cdev;
	}
	chip->qg_device = device_create(chip->qg_class, NULL, chip->dev_no,
					NULL, "qg");
	if (IS_ERR(chip->qg_device)) {
		pr_err("Failed to create qg_device\n");
		rc = -EINVAL;
		goto destroy_class;
	}

	qg_dbg(chip, QG_DEBUG_DEVICE, "'/dev/qg' successfully created\n");

	return 0;

destroy_class:
	class_destroy(chip->qg_class);
delete_cdev:
	cdev_del(&chip->qg_cdev);
unregister_chrdev:
	unregister_chrdev_region(chip->dev_no, 1);
	return rc;
}

#define BID_RPULL_OHM		100000
#define BID_VREF_MV		1875
static int get_batt_id_ohm(struct qpnp_qg *chip, u32 *batt_id_ohm)
{
	int rc, batt_id_mv;
	int64_t denom;

	/* Read battery-id */
	rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv);
	if (rc < 0) {
		pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc);
		return rc;
	}

	batt_id_mv = div_s64(batt_id_mv, 1000);
	if (batt_id_mv == 0) {
		pr_debug("batt_id_mv = 0 from ADC\n");
		return 0;
	}

	denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000;
	if (denom <= 0) {
		/* batt id connector might be open, return 0 kohms */
		return 0;
	}

	*batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom);

	qg_dbg(chip, QG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n",
					batt_id_mv, *batt_id_ohm);

	return 0;
}

static int qg_load_battery_profile(struct qpnp_qg *chip)
{
	struct device_node *node = chip->dev->of_node;
	struct device_node *profile_node;
	int rc, tuple_len, len, i, avail_age_level = 0;

	chip->batt_node = of_find_node_by_name(node, "qcom,battery-data");
	if (!chip->batt_node) {
		pr_err("Batterydata not available\n");
		return -ENXIO;
	}

	if (chip->dt.multi_profile_load) {
		if (chip->batt_age_level == -EINVAL) {
			rc = qg_get_batt_age_level(chip, &chip->batt_age_level);
			if (rc < 0) {
				pr_err("error in retrieving batt age level rc=%d\n",
									rc);
				return rc;
			}
		}
		profile_node = of_batterydata_get_best_aged_profile(
					chip->batt_node,
					chip->batt_id_ohm / 1000,
					chip->batt_age_level,
					&avail_age_level);
		if (chip->batt_age_level != avail_age_level) {
			qg_dbg(chip, QG_DEBUG_PROFILE, "Batt_age_level %d doesn't exist, using %d\n",
					chip->batt_age_level, avail_age_level);
			chip->batt_age_level = avail_age_level;
		}
	} else {
		profile_node = of_batterydata_get_best_profile(chip->batt_node,
				chip->batt_id_ohm / 1000, NULL);
	}

	if (IS_ERR_OR_NULL(profile_node)) {
		rc = profile_node ? PTR_ERR(profile_node) : -EINVAL;
		pr_err("Failed to detect valid QG battery profile %d\n", rc);
		return rc;
	}

	rc = of_property_read_string(profile_node, "qcom,battery-type",
				&chip->bp.batt_type_str);
	if (rc < 0) {
		pr_err("Failed to detect battery type rc:%d\n", rc);
		return rc;
	}

	rc = qg_batterydata_init(profile_node);
	if (rc < 0) {
		pr_err("Failed to initialize battery-profile rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
				&chip->bp.float_volt_uv);
	if (rc < 0) {
		pr_err("Failed to read battery float-voltage rc:%d\n", rc);
		chip->bp.float_volt_uv = -EINVAL;
	}

	rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
				&chip->bp.fastchg_curr_ma);
	if (rc < 0) {
		pr_err("Failed to read battery fastcharge current rc:%d\n", rc);
		chip->bp.fastchg_curr_ma = -EINVAL;
	}

	/*
	 * Update the max fcc values based on QG subtype including
	 * error margins.
	 */
	chip->bp.fastchg_curr_ma = min(chip->max_fcc_limit_ma,
					chip->bp.fastchg_curr_ma);

	rc = of_property_read_u32(profile_node, "qcom,qg-batt-profile-ver",
				&chip->bp.qg_profile_version);
	if (rc < 0) {
		pr_err("Failed to read QG profile version rc:%d\n", rc);
		chip->bp.qg_profile_version = -EINVAL;
	}

	/*
	 * Currently step charging thresholds should be read only for Vbatt
	 * based and not for SOC based.
	 */
	if (!of_property_read_bool(profile_node, "qcom,soc-based-step-chg") &&
		of_find_property(profile_node, "qcom,step-chg-ranges", &len) &&
		chip->bp.float_volt_uv > 0 && chip->bp.fastchg_curr_ma > 0) {
		len /= sizeof(u32);
		tuple_len = len / (sizeof(struct range_data) / sizeof(u32));
		if (tuple_len <= 0 || tuple_len > MAX_STEP_CHG_ENTRIES)
			return -EINVAL;

		mutex_lock(&chip->ttf->lock);
		chip->ttf->step_chg_cfg =
			kcalloc(len, sizeof(*chip->ttf->step_chg_cfg),
				GFP_KERNEL);
		if (!chip->ttf->step_chg_cfg) {
			mutex_unlock(&chip->ttf->lock);
			return -ENOMEM;
		}

		chip->ttf->step_chg_data =
			kcalloc(tuple_len, sizeof(*chip->ttf->step_chg_data),
				GFP_KERNEL);
		if (!chip->ttf->step_chg_data) {
			kfree(chip->ttf->step_chg_cfg);
			mutex_unlock(&chip->ttf->lock);
			return -ENOMEM;
		}

		rc = qg_read_range_data_from_node(profile_node,
				"qcom,step-chg-ranges",
				chip->ttf->step_chg_cfg,
				chip->bp.float_volt_uv,
				chip->bp.fastchg_curr_ma * 1000);
		if (rc < 0) {
			pr_err("Error in reading qcom,step-chg-ranges from battery profile, rc=%d\n",
				rc);
			kfree(chip->ttf->step_chg_data);
			kfree(chip->ttf->step_chg_cfg);
			chip->ttf->step_chg_cfg = NULL;
			mutex_unlock(&chip->ttf->lock);
			return rc;
		}

		chip->ttf->step_chg_num_params = tuple_len;
		chip->ttf->step_chg_cfg_valid = true;
		mutex_unlock(&chip->ttf->lock);

		if (chip->ttf->step_chg_cfg_valid) {
			for (i = 0; i < tuple_len; i++)
				pr_debug("Vbatt_low: %d Vbatt_high: %d FCC: %d\n",
				chip->ttf->step_chg_cfg[i].low_threshold,
				chip->ttf->step_chg_cfg[i].high_threshold,
				chip->ttf->step_chg_cfg[i].value);
		}
	}

	qg_dbg(chip, QG_DEBUG_PROFILE, "profile=%s FV=%duV FCC=%dma\n",
			chip->bp.batt_type_str, chip->bp.float_volt_uv,
			chip->bp.fastchg_curr_ma);

	return 0;
}

static int qg_setup_battery(struct qpnp_qg *chip)
{
	int rc;

	if (!is_battery_present(chip)) {
		qg_dbg(chip, QG_DEBUG_PROFILE, "Battery Missing!\n");
		chip->battery_missing = true;
		chip->profile_loaded = false;
		chip->soc_reporting_ready = true;
	} else {
		/* battery present */
		rc = get_batt_id_ohm(chip, &chip->batt_id_ohm);
		if (rc < 0) {
			pr_err("Failed to detect batt_id rc=%d\n", rc);
			chip->profile_loaded = false;
		} else {
			rc = qg_load_battery_profile(chip);
			if (rc < 0) {
				pr_err("Failed to load battery-profile rc=%d\n",
								rc);
				chip->profile_loaded = false;
				chip->soc_reporting_ready = true;
			} else {
				chip->profile_loaded = true;
			}
		}
	}

	qg_dbg(chip, QG_DEBUG_PROFILE, "battery_missing=%d batt_id_ohm=%d Ohm profile_loaded=%d profile=%s\n",
			chip->battery_missing, chip->batt_id_ohm,
			chip->profile_loaded, chip->bp.batt_type_str);

	return 0;
}

static struct ocv_all ocv[] = {
	[S7_PON_OCV] = { 0, 0, "S7_PON_OCV"},
	[S3_GOOD_OCV] = { 0, 0, "S3_GOOD_OCV"},
	[S3_LAST_OCV] = { 0, 0, "S3_LAST_OCV"},
	[SDAM_PON_OCV] = { 0, 0, "SDAM_PON_OCV"},
};

#define S7_ERROR_MARGIN_UV		20000
static int qg_determine_pon_soc(struct qpnp_qg *chip)
{
	int rc = 0, batt_temp = 0, i, shutdown_temp = 0;
	bool use_pon_ocv = true;
	unsigned long rtc_sec = 0;
	u32 ocv_uv = 0, soc = 0, pon_soc = 0, full_soc = 0, cutoff_soc = 0;
	u32 shutdown[SDAM_MAX] = {0}, soc_raw = 0;
	char ocv_type[20] = "NONE";

	if (!chip->profile_loaded) {
		qg_dbg(chip, QG_DEBUG_PON, "No Profile, skipping PON soc\n");
		return 0;
	}

	/* read all OCVs */
	for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) {
		rc = qg_read_ocv(chip, &ocv[i].ocv_uv,
					&ocv[i].ocv_raw, i);
		if (rc < 0)
			pr_err("Failed to read %s OCV rc=%d\n",
					ocv[i].ocv_type, rc);
		else
			qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n",
					ocv[i].ocv_type, ocv[i].ocv_uv);
	}

	rc = qg_get_battery_temp(chip, &batt_temp);
	if (rc < 0) {
		pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
		goto done;
	}

	rc = get_rtc_time(&rtc_sec);
	if (rc < 0) {
		pr_err("Failed to read RTC time rc=%d\n", rc);
		goto use_pon_ocv;
	}

	rc = qg_sdam_read_all(shutdown);
	if (rc < 0) {
		pr_err("Failed to read shutdown params rc=%d\n", rc);
		goto use_pon_ocv;
	}
	shutdown_temp = sign_extend32(shutdown[SDAM_TEMP], 15);

	rc = lookup_soc_ocv(&pon_soc, ocv[S7_PON_OCV].ocv_uv, batt_temp, false);
	if (rc < 0) {
		pr_err("Failed to lookup S7_PON SOC rc=%d\n", rc);
		goto done;
	}

	qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs temp=%d, time_now=%ldsecs temp_now=%d S7_soc=%d\n",
			shutdown[SDAM_VALID],
			shutdown[SDAM_SOC],
			shutdown[SDAM_OCV_UV],
			shutdown[SDAM_TIME_SEC],
			shutdown_temp,
			rtc_sec, batt_temp,
			pon_soc);
	/*
	 * Use the shutdown SOC if
	 * 1. SDAM read is a success & SDAM data is valid
	 * 2. The device was powered off for < ignore_shutdown_time
	 * 2. Batt temp has not changed more than shutdown_temp_diff
	 */
	if (!shutdown[SDAM_VALID])
		goto use_pon_ocv;

	if (!is_between(0, chip->dt.ignore_shutdown_soc_secs,
			(rtc_sec - shutdown[SDAM_TIME_SEC])))
		goto use_pon_ocv;

	if (!is_between(0, chip->dt.shutdown_temp_diff,
			abs(shutdown_temp -  batt_temp)) &&
			(shutdown_temp < 0 || batt_temp < 0))
		goto use_pon_ocv;

	if ((chip->dt.shutdown_soc_threshold != -EINVAL) &&
			!is_between(0, chip->dt.shutdown_soc_threshold,
			abs(pon_soc - shutdown[SDAM_SOC])))
		goto use_pon_ocv;

	use_pon_ocv = false;
	ocv_uv = shutdown[SDAM_OCV_UV];
	soc = shutdown[SDAM_SOC];
	soc_raw = shutdown[SDAM_SOC] * 100;
	strscpy(ocv_type, "SHUTDOWN_SOC", 20);
	qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");

use_pon_ocv:
	if (use_pon_ocv) {
		if (chip->wa_flags & QG_PON_OCV_WA) {
			if (ocv[S3_LAST_OCV].ocv_raw == FIFO_V_RESET_VAL) {
				if (!ocv[SDAM_PON_OCV].ocv_uv) {
					strscpy(ocv_type, "S7_PON_SOC", 20);
					ocv_uv = ocv[S7_PON_OCV].ocv_uv;
				} else if (ocv[SDAM_PON_OCV].ocv_uv <=
						ocv[S7_PON_OCV].ocv_uv) {
					strscpy(ocv_type, "S7_PON_SOC", 20);
					ocv_uv = ocv[S7_PON_OCV].ocv_uv;
				} else if (!shutdown[SDAM_VALID] &&
					((ocv[SDAM_PON_OCV].ocv_uv -
						ocv[S7_PON_OCV].ocv_uv) >
						S7_ERROR_MARGIN_UV)) {
					strscpy(ocv_type, "S7_PON_SOC", 20);
					ocv_uv = ocv[S7_PON_OCV].ocv_uv;
				} else {
					strscpy(ocv_type, "SDAM_PON_SOC", 20);
					ocv_uv = ocv[SDAM_PON_OCV].ocv_uv;
				}
			} else {
				if (ocv[S3_LAST_OCV].ocv_uv >=
						ocv[S7_PON_OCV].ocv_uv) {
					strscpy(ocv_type, "S3_LAST_SOC", 20);
					ocv_uv = ocv[S3_LAST_OCV].ocv_uv;
				} else {
					strscpy(ocv_type, "S7_PON_SOC", 20);
					ocv_uv = ocv[S7_PON_OCV].ocv_uv;
				}
			}
		} else {
			/* Use S7 PON OCV */
			strscpy(ocv_type, "S7_PON_SOC", 20);
			ocv_uv = ocv[S7_PON_OCV].ocv_uv;
		}

		ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv);
		rc = lookup_soc_ocv(&pon_soc, ocv_uv, batt_temp, false);
		if (rc < 0) {
			pr_err("Failed to lookup SOC@PON rc=%d\n", rc);
			goto done;
		}

		rc = lookup_soc_ocv(&full_soc, chip->bp.float_volt_uv,
							batt_temp, true);
		if (rc < 0) {
			pr_err("Failed to lookup FULL_SOC@PON rc=%d\n", rc);
			goto done;
		}
		full_soc = CAP(0, 99, full_soc);

		rc = lookup_soc_ocv(&cutoff_soc,
				chip->dt.vbatt_cutoff_mv * 1000,
				batt_temp, false);
		if (rc < 0) {
			pr_err("Failed to lookup CUTOFF_SOC@PON rc=%d\n", rc);
			goto done;
		}

		if ((full_soc > cutoff_soc) && (pon_soc > cutoff_soc)) {
			soc = DIV_ROUND_UP(((pon_soc - cutoff_soc) * 100),
						(full_soc - cutoff_soc));
			soc = CAP(0, 100, soc);
			soc_raw = soc * 100;
		} else {
			soc_raw = pon_soc * 100;
			soc = pon_soc;
		}

		qg_dbg(chip, QG_DEBUG_PON, "v_float=%d v_cutoff=%d FULL_SOC=%d CUTOFF_SOC=%d PON_SYS_SOC=%d pon_soc=%d\n",
			chip->bp.float_volt_uv, chip->dt.vbatt_cutoff_mv * 1000,
			full_soc, cutoff_soc, soc, pon_soc);
	}
done:
	if (rc < 0) {
		pr_err("Failed to get %s @ PON, rc=%d\n", ocv_type, rc);
		return rc;
	}

	if (chip->qg_mode == QG_V_I_MODE)
		chip->cc_soc = soc_raw;
	chip->sys_soc = soc_raw;
	chip->last_adj_ssoc = chip->catch_up_soc = chip->msoc = soc;
	chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv;
	chip->kdata.param[QG_PON_OCV_UV].valid = true;

	/* write back to SDAM */
	chip->sdam_data[SDAM_SOC] = soc;
	chip->sdam_data[SDAM_OCV_UV] = ocv_uv;
	chip->sdam_data[SDAM_VALID] = 1;

	rc = qg_write_monotonic_soc(chip, chip->msoc);
	if (rc < 0)
		pr_err("Failed to update MSOC register rc=%d\n", rc);

	rc = qg_store_soc_params(chip);
	if (rc < 0)
		pr_err("Failed to update sdam params rc=%d\n", rc);

	pr_info("using %s @ PON ocv_uv=%duV soc=%d\n",
			ocv_type, ocv_uv, chip->msoc);

	/* SOC reporting is now ready */
	chip->soc_reporting_ready = 1;

	return 0;
}

static int qg_set_wa_flags(struct qpnp_qg *chip)
{
	switch (chip->pmic_version) {
	case PMI632:
		chip->wa_flags |= QG_RECHARGE_SOC_WA;
		if (!chip->dt.use_s7_ocv)
			chip->wa_flags |= QG_PON_OCV_WA;
		break;
	case PM6150:
		chip->wa_flags |= QG_CLK_ADJUST_WA |
				QG_RECHARGE_SOC_WA;
		qg_esr_mod_count = 10;
		break;
	case PM7250B:
		qg_esr_mod_count = 10;
		break;
	case PM2250:
		chip->wa_flags |= QG_CLK_ADJUST_WA |
				QG_RECHARGE_SOC_WA |
				QG_VBAT_LOW_WA;
		break;
	default:
		pr_err("Unsupported PMIC version %d\n",
			chip->pmic_version);
		return -EINVAL;
	}

	qg_dbg(chip, QG_DEBUG_PON, "wa_flags = %x\n", chip->wa_flags);

	return 0;
}

#define SDAM_MAGIC_NUMBER		0x12345678
static int qg_sanitize_sdam(struct qpnp_qg *chip)
{
	int rc = 0;
	u32 data = 0;

	rc = qg_sdam_read(SDAM_MAGIC, &data);
	if (rc < 0) {
		pr_err("Failed to read SDAM rc=%d\n", rc);
		return rc;
	}

	if (data == SDAM_MAGIC_NUMBER) {
		qg_dbg(chip, QG_DEBUG_PON, "SDAM valid\n");
	} else if (data == 0) {
		rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
		if (!rc)
			qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initialized\n");
		chip->first_profile_load = true;
	} else {
		/* SDAM has invalid value */
		rc = qg_sdam_clear();
		if (!rc) {
			pr_err("SDAM uninitialized, SDAM reset\n");
			rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER);
		}
		chip->first_profile_load = true;
	}

	if (rc < 0)
		pr_err("Failed in SDAM operation, rc=%d\n", rc);

	return rc;
}

#define ADC_CONV_DLY_512MS		0xA
#define IBAT_5A_FCC_MA			4800
#define IBAT_10A_FCC_MA			9600
static int qg_hw_init(struct qpnp_qg *chip)
{
	int rc, temp;
	u8 reg;

	/* read STATUS2 register to clear its last state */
	qg_read(chip, chip->qg_base + QG_STATUS2_REG, &reg, 1);

	/* read the QG perph_subtype */
	rc = qg_read(chip, chip->qg_base + PERPH_SUBTYPE_REG,
					&chip->qg_subtype, 1);
	if (rc < 0) {
		pr_err("Failed to read QG subtype rc=%d\n", rc);
		return rc;
	}

	if (chip->qg_subtype == QG_ADC_IBAT_5A)
		chip->max_fcc_limit_ma = IBAT_5A_FCC_MA;
	else
		chip->max_fcc_limit_ma = IBAT_10A_FCC_MA;

	if (chip->qg_version == QG_LITE) {
		rc = qg_read(chip, chip->qg_base + QG_MODE_CTL2_REG, &reg, 1);
		if (rc < 0) {
			pr_err("Failed to read QG mode rc=%d\n", rc);
			return rc;
		}
		chip->qg_mode = (reg & VI_MODE_BIT) ? QG_V_I_MODE : QG_V_MODE;
	} else {
		chip->qg_mode = QG_V_I_MODE;
	}

	if (chip->qg_mode == QG_V_MODE) {
		chip->dt.esr_disable = true;
		chip->dt.cl_disable = true;
		chip->dt.tcss_enable = false;
		chip->dt.bass_enable = false;
	}

	rc = qg_set_wa_flags(chip);
	if (rc < 0) {
		pr_err("Failed to update PMIC type flags, rc=%d\n", rc);
		return rc;
	}

	rc = qg_master_hold(chip, true);
	if (rc < 0) {
		pr_err("Failed to hold master, rc=%d\n", rc);
		goto done_fifo;
	}

	rc = qg_process_rt_fifo(chip);
	if (rc < 0) {
		pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
		goto done_fifo;
	}

	/* update the changed S2 fifo DT parameters */
	if (chip->dt.s2_fifo_length > 0) {
		rc = qg_update_fifo_length(chip, chip->dt.s2_fifo_length);
		if (rc < 0)
			goto done_fifo;
	}

	if (chip->dt.s2_acc_length > 0) {
		reg = ilog2(chip->dt.s2_acc_length) - 1;
		rc = qg_masked_write(chip, chip->qg_base +
				QG_S2_NORMAL_MEAS_CTL2_REG,
				NUM_OF_ACCUM_MASK, reg);
		if (rc < 0) {
			pr_err("Failed to write S2 ACC length, rc=%d\n", rc);
			goto done_fifo;
		}
	}

	if (chip->dt.s2_acc_intvl_ms > 0) {
		reg = chip->dt.s2_acc_intvl_ms / 10;
		rc = qg_write(chip, chip->qg_base +
				QG_S2_NORMAL_MEAS_CTL3_REG,
				&reg, 1);
		if (rc < 0) {
			pr_err("Failed to write S2 ACC intrvl, rc=%d\n", rc);
			goto done_fifo;
		}
	}

	chip->s2_state = S2_DEFAULT;
	chip->s2_state_mask |= S2_DEFAULT;
	/* signal the read thread */
	chip->data_ready = true;
	wake_up_interruptible(&chip->qg_wait_q);

done_fifo:
	rc = qg_master_hold(chip, false);
	if (rc < 0) {
		pr_err("Failed to release master, rc=%d\n", rc);
		return rc;
	}
	chip->last_fifo_update_time = ktime_get_boottime();

	if (chip->dt.ocv_timer_expiry_min != -EINVAL &&
				chip->qg_version != QG_LITE) {
		if (chip->dt.ocv_timer_expiry_min < 2)
			chip->dt.ocv_timer_expiry_min = 2;
		else if (chip->dt.ocv_timer_expiry_min > 30)
			chip->dt.ocv_timer_expiry_min = 30;

		reg = (chip->dt.ocv_timer_expiry_min - 2) / 4;
		rc = qg_masked_write(chip,
			chip->qg_base + QG_S3_SLEEP_OCV_MEAS_CTL4_REG,
			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
		if (rc < 0) {
			pr_err("Failed to write OCV timer, rc=%d\n", rc);
			return rc;
		}
	}

	if (chip->dt.ocv_tol_threshold_uv != -EINVAL) {
		if (chip->dt.ocv_tol_threshold_uv < 0)
			chip->dt.ocv_tol_threshold_uv = 0;
		else if (chip->dt.ocv_tol_threshold_uv > 12262)
			chip->dt.ocv_tol_threshold_uv = 12262;

		reg = chip->dt.ocv_tol_threshold_uv / 195;
		rc = qg_masked_write(chip,
			chip->qg_base + QG_S3_SLEEP_OCV_TREND_CTL2_REG,
			TREND_TOL_MASK, reg);
		if (rc < 0) {
			pr_err("Failed to write OCV tol-thresh, rc=%d\n", rc);
			return rc;
		}
	}

	if (chip->dt.s3_entry_fifo_length != -EINVAL) {
		if (chip->dt.s3_entry_fifo_length < 1)
			chip->dt.s3_entry_fifo_length = 1;
		else if (chip->dt.s3_entry_fifo_length >
					chip->max_fifo_length)
			chip->dt.s3_entry_fifo_length =
					chip->max_fifo_length;

		reg = chip->dt.s3_entry_fifo_length - 1;
		rc = qg_masked_write(chip,
			chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
			SLEEP_IBAT_QUALIFIED_LENGTH_MASK, reg);
		if (rc < 0) {
			pr_err("Failed to write S3-entry fifo-length, rc=%d\n",
							rc);
			return rc;
		}
	}

	if (chip->dt.s3_entry_ibat_ua != -EINVAL) {
		if (chip->dt.s3_entry_ibat_ua < 0)
			chip->dt.s3_entry_ibat_ua = 0;
		else if (chip->dt.s3_entry_ibat_ua > 155550)
			chip->dt.s3_entry_ibat_ua = 155550;

		reg = chip->dt.s3_entry_ibat_ua / 610;
		rc = qg_write(chip, chip->qg_base +
				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
				&reg, 1);
		if (rc < 0) {
			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
			return rc;
		}
	}

	if (chip->dt.s3_exit_ibat_ua != -EINVAL) {
		if (chip->dt.s3_exit_ibat_ua < 0)
			chip->dt.s3_exit_ibat_ua = 0;
		else if (chip->dt.s3_exit_ibat_ua > 155550)
			chip->dt.s3_exit_ibat_ua = 155550;

		rc = qg_read(chip, chip->qg_base +
				QG_S3_ENTRY_IBAT_THRESHOLD_REG,
				&reg, 1);
		if (rc < 0) {
			pr_err("Failed to read S3-entry ibat-uA, rc=%d\n", rc);
			return rc;
		}
		temp = reg * 610;
		if (chip->dt.s3_exit_ibat_ua < temp)
			chip->dt.s3_exit_ibat_ua = temp;
		else
			chip->dt.s3_exit_ibat_ua -= temp;

		reg = chip->dt.s3_exit_ibat_ua / 610;
		rc = qg_write(chip,
			chip->qg_base + QG_S3_EXIT_IBAT_THRESHOLD_REG,
			&reg, 1);
		if (rc < 0) {
			pr_err("Failed to write S3-entry ibat-uA, rc=%d\n", rc);
			return rc;
		}
	}

	/* vbat based configs */
	if (chip->dt.vbatt_low_mv < 0)
		chip->dt.vbatt_low_mv = 0;
	else if (chip->dt.vbatt_low_mv > 12750)
		chip->dt.vbatt_low_mv = 12750;

	if (chip->dt.vbatt_empty_mv < 0)
		chip->dt.vbatt_empty_mv = 0;
	else if (chip->dt.vbatt_empty_mv > 12750)
		chip->dt.vbatt_empty_mv = 12750;

	if (chip->dt.vbatt_empty_cold_mv < 0)
		chip->dt.vbatt_empty_cold_mv = 0;
	else if (chip->dt.vbatt_empty_cold_mv > 12750)
		chip->dt.vbatt_empty_cold_mv = 12750;

	rc = qg_vbat_thresholds_config(chip);
	if (rc < 0) {
		pr_err("Failed to configure VBAT empty/low rc=%d\n", rc);
		return rc;
	}

	if (chip->qg_version != QG_LITE) {
		/* disable S5 */
		rc = qg_masked_write(chip, chip->qg_base +
					QG_S5_OCV_VALIDATE_MEAS_CTL1_REG,
					ALLOW_S5_BIT, 0);
		if (rc < 0)
			pr_err("Failed to disable S5 rc=%d\n", rc);
	}

	/* change PON OCV time to 512ms */
	rc = qg_masked_write(chip, chip->qg_base +
				QG_S7_PON_OCV_MEAS_CTL1_REG,
				ADC_CONV_DLY_MASK,
				ADC_CONV_DLY_512MS);
	if (rc < 0)
		pr_err("Failed to reconfigure S7-delay rc=%d\n", rc);


	return 0;
}

static int qg_soh_batt_profile_init(struct qpnp_qg *chip)
{
	int rc = 0;

	if (!chip->dt.multi_profile_load)
		return 0;

	if (is_debug_batt_id(chip) || chip->battery_missing)
		return 0;

	if (!chip->sp)
		chip->sp = devm_kzalloc(chip->dev, sizeof(*chip->sp),
					GFP_KERNEL);
	if (!chip->sp)
		return -ENOMEM;

	if (!chip->sp->initialized) {
		chip->sp->batt_id_kohms = chip->batt_id_ohm / 1000;
		chip->sp->bp_node = chip->batt_node;
		chip->sp->last_batt_age_level = chip->batt_age_level;
		chip->sp->bms_psy = chip->qg_psy;
		chip->sp->iio_chan_list = chip->int_iio_chans;
		rc = soh_profile_init(chip->dev, chip->sp);
		if (rc < 0)
			chip->sp = NULL;
		else
			qg_dbg(chip, QG_DEBUG_PROFILE, "SOH profile count: %d\n",
				chip->sp->profile_count);
	}

	return rc;
}

static int qg_post_init(struct qpnp_qg *chip)
{
	int rc = 0;

	/* disable all IRQs if profile is not loaded */
	if (!chip->profile_loaded) {
		vote(chip->vbatt_irq_disable_votable,
				PROFILE_IRQ_DISABLE, true, 0);
		vote(chip->fifo_irq_disable_votable,
				PROFILE_IRQ_DISABLE, true, 0);
		vote(chip->good_ocv_irq_disable_votable,
				PROFILE_IRQ_DISABLE, true, 0);
	}

	/* restore ESR data */
	if (!chip->dt.esr_disable)
		qg_retrieve_esr_params(chip);

	/*soh based multi profile init */
	rc = qg_soh_batt_profile_init(chip);
	if (rc < 0) {
		pr_err("Failed to initialize battery based on soh rc=%d\n",
								rc);
		return rc;
	}

	return 0;
}

static int qg_get_irq_index_byname(const char *irq_name)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(qg_irqs); i++) {
		if (strcmp(qg_irqs[i].name, irq_name) == 0)
			return i;
	}

	return -ENOENT;
}

static int qg_request_interrupt(struct qpnp_qg *chip,
		struct device_node *node, const char *irq_name)
{
	int rc, irq, irq_index;

	irq = of_irq_get_byname(node, irq_name);
	if (irq < 0) {
		pr_err("Failed to get irq %s byname\n", irq_name);
		return irq;
	}

	irq_index = qg_get_irq_index_byname(irq_name);
	if (irq_index < 0) {
		pr_err("%s is not a defined irq\n", irq_name);
		return irq_index;
	}

	if (!qg_irqs[irq_index].handler)
		return 0;

	rc = devm_request_threaded_irq(chip->dev, irq, NULL,
				qg_irqs[irq_index].handler,
				IRQF_ONESHOT, irq_name, chip);
	if (rc < 0) {
		pr_err("Failed to request irq %d\n", irq);
		return rc;
	}

	qg_irqs[irq_index].irq = irq;
	if (qg_irqs[irq_index].wake)
		enable_irq_wake(irq);

	qg_dbg(chip, QG_DEBUG_PON, "IRQ %s registered wakeable=%d\n",
			qg_irqs[irq_index].name, qg_irqs[irq_index].wake);

	return 0;
}

static int qg_request_irqs(struct qpnp_qg *chip)
{
	struct device_node *node = chip->dev->of_node;
	struct device_node *child;
	const char *name;
	struct property *prop;
	int rc = 0;

	for_each_available_child_of_node(node, child) {
		of_property_for_each_string(child, "interrupt-names",
					    prop, name) {
			rc = qg_request_interrupt(chip, child, name);
			if (rc < 0)
				return rc;
		}
	}


	return 0;
}

#define QG_TTF_ITERM_DELTA_MA		1
static int qg_alg_init(struct qpnp_qg *chip)
{
	struct cycle_counter *counter;
	struct cap_learning *cl;
	struct ttf *ttf;
	struct device_node *node = chip->dev->of_node;
	int rc;

	counter = devm_kzalloc(chip->dev, sizeof(*counter), GFP_KERNEL);
	if (!counter)
		return -ENOMEM;

	counter->restore_count = qg_restore_cycle_count;
	counter->store_count = qg_store_cycle_count;
	counter->data = chip;

	rc = cycle_count_init(counter);
	if (rc < 0) {
		dev_err(chip->dev, "Error in initializing cycle counter, rc:%d\n",
			rc);
		counter->data = NULL;
		return rc;
	}

	chip->counter = counter;

	ttf = devm_kzalloc(chip->dev, sizeof(*ttf), GFP_KERNEL);
	if (!ttf)
		return -ENOMEM;

	ttf->get_ttf_param = qg_get_ttf_param;
	ttf->awake_voter = qg_ttf_awake_voter;
	ttf->iterm_delta = QG_TTF_ITERM_DELTA_MA;
	ttf->data = chip;

	rc = ttf_tte_init(ttf);
	if (rc < 0) {
		dev_err(chip->dev, "Error in initializing ttf, rc:%d\n",
			rc);
		ttf->data = NULL;
		counter->data = NULL;
		return rc;
	}

	chip->ttf = ttf;

	chip->dt.cl_disable = of_property_read_bool(node,
					"qcom,cl-disable");

	/*Return if capacity learning is disabled*/
	if (chip->dt.cl_disable)
		return 0;

	cl = devm_kzalloc(chip->dev, sizeof(*cl), GFP_KERNEL);
	if (!cl)
		return -ENOMEM;

	cl->cc_soc_max = QG_SOC_FULL;
	cl->get_cc_soc = qg_get_cc_soc;
	cl->get_learned_capacity = qg_get_learned_capacity;
	cl->store_learned_capacity = qg_store_learned_capacity;
	cl->ok_to_begin = qg_cl_ok_to_begin;
	cl->data = chip;

	rc = cap_learning_init(cl);
	if (rc < 0) {
		dev_err(chip->dev, "Error in initializing capacity learning, rc:%d\n",
			rc);
		counter->data = NULL;
		cl->data = NULL;
		return rc;
	}

	chip->cl = cl;
	return 0;
}

#ifdef CONFIG_DEBUG_FS
static void qg_create_debugfs(struct qpnp_qg *chip)
{

	chip->dfs_root = debugfs_create_dir("qgauge", NULL);
	if (IS_ERR_OR_NULL(chip->dfs_root)) {
		pr_err("Failed to create debugfs directory rc=%ld\n",
				(long)chip->dfs_root);
		return;
	}

	debugfs_create_u32("debug_mask", 0600, chip->dfs_root,
			&qg_debug_mask);
}
#else
static void qg_create_debugfs(struct qpnp_qg *chip)
{
}
#endif

#define DEFAULT_S2_FIFO_LENGTH		5
#define DEFAULT_S2_VBAT_LOW_LENGTH	2
#define DEFAULT_S2_ACC_LENGTH		128
#define DEFAULT_S2_ACC_INTVL_MS		100
#define DEFAULT_SLEEP_S2_FIFO_LENGTH	8
#define DEFAULT_SLEEP_S2_ACC_LENGTH	256
#define DEFAULT_SLEEP_S2_ACC_INTVL_MS	200
#define DEFAULT_FAST_CHG_S2_FIFO_LENGTH	1
static int qg_parse_s2_dt(struct qpnp_qg *chip)
{
	int rc;
	struct device_node *node = chip->dev->of_node;
	u32 temp;

	/* S2 state params */
	rc = of_property_read_u32(node, "qcom,s2-fifo-length", &temp);
	if (rc < 0)
		chip->dt.s2_fifo_length = DEFAULT_S2_FIFO_LENGTH;
	else
		chip->dt.s2_fifo_length = temp;

	if (chip->dt.s2_fifo_length > chip->max_fifo_length) {
		pr_err("Invalid S2 fifo-length=%d max_length=%d\n",
					chip->dt.s2_fifo_length,
					chip->max_fifo_length);
		return -EINVAL;
	}

	rc = of_property_read_u32(node, "qcom,s2-vbat-low-fifo-length", &temp);
	if (rc < 0)
		chip->dt.s2_vbat_low_fifo_length = DEFAULT_S2_VBAT_LOW_LENGTH;
	else
		chip->dt.s2_vbat_low_fifo_length = temp;

	rc = of_property_read_u32(node, "qcom,s2-acc-length", &temp);
	if (rc < 0)
		chip->dt.s2_acc_length = DEFAULT_S2_ACC_LENGTH;
	else
		chip->dt.s2_acc_length = temp;

	rc = of_property_read_u32(node, "qcom,s2-acc-interval-ms", &temp);
	if (rc < 0)
		chip->dt.s2_acc_intvl_ms = DEFAULT_S2_ACC_INTVL_MS;
	else
		chip->dt.s2_acc_intvl_ms = temp;

	qg_dbg(chip, QG_DEBUG_PON, "DT: S2 FIFO length=%d low_vbat_length=%d acc_length=%d acc_interval=%d\n",
		chip->dt.s2_fifo_length, chip->dt.s2_vbat_low_fifo_length,
		chip->dt.s2_acc_length, chip->dt.s2_acc_intvl_ms);

	if (of_property_read_bool(node, "qcom,qg-sleep-config")) {

		chip->dt.qg_sleep_config = true;

		rc = of_property_read_u32(node,
				"qcom,sleep-s2-fifo-length", &temp);
		if (rc < 0)
			chip->dt.sleep_s2_fifo_length =
					DEFAULT_SLEEP_S2_FIFO_LENGTH;
		else
			chip->dt.sleep_s2_fifo_length = temp;

		if (chip->dt.s2_fifo_length > chip->max_fifo_length) {
			pr_err("Invalid S2 sleep-fifo-length=%d max_length=%d\n",
					chip->dt.sleep_s2_fifo_length,
					chip->max_fifo_length);
			return -EINVAL;
		}

		rc = of_property_read_u32(node,
				"qcom,sleep-s2-acc-length", &temp);
		if (rc < 0)
			chip->dt.sleep_s2_acc_length =
					DEFAULT_SLEEP_S2_ACC_LENGTH;
		else
			chip->dt.sleep_s2_acc_length = temp;

		rc = of_property_read_u32(node,
				"qcom,sleep-s2-acc-intvl-ms", &temp);
		if (rc < 0)
			chip->dt.sleep_s2_acc_intvl_ms =
					DEFAULT_SLEEP_S2_ACC_INTVL_MS;
		else
			chip->dt.sleep_s2_acc_intvl_ms = temp;
	}

	if (of_property_read_bool(node, "qcom,qg-fast-chg-config")) {

		chip->dt.qg_fast_chg_cfg = true;

		rc = of_property_read_u32(node,
				"qcom,fast-chg-s2-fifo-length", &temp);
		if (rc < 0)
			chip->dt.fast_chg_s2_fifo_length =
					DEFAULT_FAST_CHG_S2_FIFO_LENGTH;
		else
			chip->dt.fast_chg_s2_fifo_length = temp;

		if (chip->dt.fast_chg_s2_fifo_length > chip->max_fifo_length) {
			pr_err("Invalid S2 fast-fifo-length=%d max_length=%d\n",
					chip->dt.fast_chg_s2_fifo_length,
					chip->max_fifo_length);
			return -EINVAL;
		}
	}

	return 0;
}

#define DEFAULT_CL_MIN_START_SOC	10
#define DEFAULT_CL_MAX_START_SOC	15
#define DEFAULT_CL_MIN_TEMP_DECIDEGC	150
#define DEFAULT_CL_MAX_TEMP_DECIDEGC	500
#define DEFAULT_CL_MAX_INC_DECIPERC	10
#define DEFAULT_CL_MAX_DEC_DECIPERC	20
#define DEFAULT_CL_MIN_LIM_DECIPERC	500
#define DEFAULT_CL_MAX_LIM_DECIPERC	100
#define DEFAULT_CL_DELTA_BATT_SOC	10
#define DEFAULT_CL_WT_START_SOC		15
static int qg_parse_cl_dt(struct qpnp_qg *chip)
{
	int rc;
	struct device_node *node = chip->dev->of_node;
	u32 temp;

	if (chip->dt.cl_disable)
		return 0;

	chip->dt.cl_feedback_on = of_property_read_bool(node,
					"qcom,cl-feedback-on");

	rc = of_property_read_u32(node, "qcom,cl-min-start-soc", &temp);
	if (rc < 0)
		chip->cl->dt.min_start_soc = DEFAULT_CL_MIN_START_SOC;
	else
		chip->cl->dt.min_start_soc = temp;

	rc = of_property_read_u32(node, "qcom,cl-max-start-soc", &temp);
	if (rc < 0)
		chip->cl->dt.max_start_soc = DEFAULT_CL_MAX_START_SOC;
	else
		chip->cl->dt.max_start_soc = temp;

	rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
	if (rc < 0)
		chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
	else
		chip->cl->dt.min_temp = temp;

	rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
	if (rc < 0)
		chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
	else
		chip->cl->dt.max_temp = temp;

	rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
	if (rc < 0)
		chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
	else
		chip->cl->dt.max_cap_inc = temp;

	rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
	if (rc < 0)
		chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
	else
		chip->cl->dt.max_cap_dec = temp;

	rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
	if (rc < 0)
		chip->cl->dt.min_cap_limit =
					DEFAULT_CL_MIN_LIM_DECIPERC;
	else
		chip->cl->dt.min_cap_limit = temp;

	rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
	if (rc < 0)
		chip->cl->dt.max_cap_limit =
					DEFAULT_CL_MAX_LIM_DECIPERC;
	else
		chip->cl->dt.max_cap_limit = temp;

	chip->cl->dt.min_delta_batt_soc = DEFAULT_CL_DELTA_BATT_SOC;
	/* read from DT property and update, if value exists */
	of_property_read_u32(node, "qcom,cl-min-delta-batt-soc",
				&chip->cl->dt.min_delta_batt_soc);

	if (of_property_read_bool(node, "qcom,cl-wt-enable")) {
		chip->cl->dt.cl_wt_enable = true;
		chip->cl->dt.min_start_soc = DEFAULT_CL_WT_START_SOC;
		chip->cl->dt.max_start_soc = -EINVAL;
	}

	qg_dbg(chip, QG_DEBUG_PON, "DT: cl_min_start_soc=%d cl_max_start_soc=%d cl_min_temp=%d cl_max_temp=%d chip->cl->dt.cl_wt_enable=%d\n",
		chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc,
		chip->cl->dt.min_temp, chip->cl->dt.max_temp,
		chip->cl->dt.cl_wt_enable);

	return 0;
}

#define DEFAULT_VBATT_EMPTY_MV		3200
#define DEFAULT_VBATT_EMPTY_COLD_MV	3000
#define DEFAULT_VBATT_CUTOFF_MV		3400
#define DEFAULT_VBATT_LOW_MV		3500
#define DEFAULT_VBATT_LOW_COLD_MV	3800
#define DEFAULT_ITERM_MA		100
#define DEFAULT_DELTA_SOC		1
#define DEFAULT_SHUTDOWN_SOC_SECS	360
#define DEFAULT_COLD_TEMP_THRESHOLD	0
#define DEFAULT_SHUTDOWN_TEMP_DIFF	60	/* 6 degC */
#define DEFAULT_ESR_QUAL_CURRENT_UA	130000
#define DEFAULT_ESR_QUAL_VBAT_UV	7000
#define DEFAULT_ESR_DISABLE_SOC		1000
#define ESR_CHG_MIN_IBAT_UA		(-450000)
#define DEFAULT_SLEEP_TIME_SECS		1800 /* 30 mins */
#define DEFAULT_SYS_MIN_VOLT_MV		2800
#define DEFAULT_FVSS_VBAT_MV		3500
#define DEFAULT_TCSS_ENTRY_SOC		90
#define DEFAULT_ESR_LOW_TEMP_THRESHOLD	100 /* 10 deg */
static int qg_parse_dt(struct qpnp_qg *chip)
{
	int rc = 0;
	struct device_node *child, *node = chip->dev->of_node;
	u32 base, temp;
	u8 type;

	if (!node)  {
		pr_err("Failed to find device-tree node\n");
		return -ENXIO;
	}

	for_each_available_child_of_node(node, child) {
		rc = of_property_read_u32(child, "reg", &base);
		if (rc < 0) {
			pr_err("Failed to read base address, rc=%d\n", rc);
			return rc;
		}

		rc = qg_read(chip, base + PERPH_TYPE_REG, &type, 1);
		if (rc < 0) {
			pr_err("Failed to read type, rc=%d\n", rc);
			return rc;
		}

		switch (type) {
		case QG_TYPE:
			chip->qg_base = base;
			break;
		default:
			break;
		}
	}

	if (!chip->qg_base) {
		pr_err("QG device node missing\n");
		return -EINVAL;
	}

	rc = qg_parse_s2_dt(chip);
	if (rc < 0)
		pr_err("Failed to parse S2 DT params rc=%d\n", rc);

	rc = qg_parse_cl_dt(chip);
	if (rc < 0)
		pr_err("Failed to parse CL parameters rc=%d\n", rc);

	/* OCV params */
	rc = of_property_read_u32(node, "qcom,ocv-timer-expiry-min", &temp);
	if (rc < 0)
		chip->dt.ocv_timer_expiry_min = -EINVAL;
	else
		chip->dt.ocv_timer_expiry_min = temp;

	rc = of_property_read_u32(node, "qcom,ocv-tol-threshold-uv", &temp);
	if (rc < 0)
		chip->dt.ocv_tol_threshold_uv = -EINVAL;
	else
		chip->dt.ocv_tol_threshold_uv = temp;

	qg_dbg(chip, QG_DEBUG_PON, "DT: OCV timer_expiry =%dmin ocv_tol_threshold=%duV\n",
		chip->dt.ocv_timer_expiry_min, chip->dt.ocv_tol_threshold_uv);

	/* S3 sleep configuration */
	rc = of_property_read_u32(node, "qcom,s3-entry-fifo-length", &temp);
	if (rc < 0)
		chip->dt.s3_entry_fifo_length = -EINVAL;
	else
		chip->dt.s3_entry_fifo_length = temp;

	rc = of_property_read_u32(node, "qcom,s3-entry-ibat-ua", &temp);
	if (rc < 0)
		chip->dt.s3_entry_ibat_ua = -EINVAL;
	else
		chip->dt.s3_entry_ibat_ua = temp;

	rc = of_property_read_u32(node, "qcom,s3-exit-ibat-ua", &temp);
	if (rc < 0)
		chip->dt.s3_exit_ibat_ua = -EINVAL;
	else
		chip->dt.s3_exit_ibat_ua = temp;

	/* VBAT thresholds */
	rc = of_property_read_u32(node, "qcom,vbatt-empty-mv", &temp);
	if (rc < 0)
		chip->dt.vbatt_empty_mv = DEFAULT_VBATT_EMPTY_MV;
	else
		chip->dt.vbatt_empty_mv = temp;

	rc = of_property_read_u32(node, "qcom,vbatt-empty-cold-mv", &temp);
	if (rc < 0)
		chip->dt.vbatt_empty_cold_mv = DEFAULT_VBATT_EMPTY_COLD_MV;
	else
		chip->dt.vbatt_empty_cold_mv = temp;

	rc = of_property_read_u32(node, "qcom,cold-temp-threshold", &temp);
	if (rc < 0)
		chip->dt.cold_temp_threshold = DEFAULT_COLD_TEMP_THRESHOLD;
	else
		chip->dt.cold_temp_threshold = temp;

	rc = of_property_read_u32(node, "qcom,vbatt-low-mv", &temp);
	if (rc < 0)
		chip->dt.vbatt_low_mv = DEFAULT_VBATT_LOW_MV;
	else
		chip->dt.vbatt_low_mv = temp;

	rc = of_property_read_u32(node, "qcom,vbatt-low-cold-mv", &temp);
	if (rc < 0)
		chip->dt.vbatt_low_cold_mv = DEFAULT_VBATT_LOW_COLD_MV;
	else
		chip->dt.vbatt_low_cold_mv = temp;

	rc = of_property_read_u32(node, "qcom,vbatt-cutoff-mv", &temp);
	if (rc < 0)
		chip->dt.vbatt_cutoff_mv = DEFAULT_VBATT_CUTOFF_MV;
	else
		chip->dt.vbatt_cutoff_mv = temp;

	/* IBAT thresholds */
	rc = of_property_read_u32(node, "qcom,qg-iterm-ma", &temp);
	if (rc < 0)
		chip->dt.iterm_ma = DEFAULT_ITERM_MA;
	else
		chip->dt.iterm_ma = temp;

	rc = of_property_read_u32(node, "qcom,delta-soc", &temp);
	if (rc < 0)
		chip->dt.delta_soc = DEFAULT_DELTA_SOC;
	else
		chip->dt.delta_soc = temp;

	rc = of_property_read_u32(node, "qcom,ignore-shutdown-soc-secs", &temp);
	if (rc < 0)
		chip->dt.ignore_shutdown_soc_secs = DEFAULT_SHUTDOWN_SOC_SECS;
	else
		chip->dt.ignore_shutdown_soc_secs = temp;

	rc = of_property_read_u32(node, "qcom,shutdown-temp-diff", &temp);
	if (rc < 0)
		chip->dt.shutdown_temp_diff = DEFAULT_SHUTDOWN_TEMP_DIFF;
	else
		chip->dt.shutdown_temp_diff = temp;

	chip->dt.hold_soc_while_full = of_property_read_bool(node,
					"qcom,hold-soc-while-full");

	chip->dt.linearize_soc = of_property_read_bool(node,
					"qcom,linearize-soc");

	rc = of_property_read_u32(node, "qcom,rbat-conn-mohm", &temp);
	if (rc < 0)
		chip->dt.rbat_conn_mohm = 0;
	else
		chip->dt.rbat_conn_mohm = (int)temp;

	/* esr */
	chip->dt.esr_disable = of_property_read_bool(node,
					"qcom,esr-disable");

	chip->dt.esr_discharge_enable = of_property_read_bool(node,
					"qcom,esr-discharge-enable");

	rc = of_property_read_u32(node, "qcom,esr-qual-current-ua", &temp);
	if (rc < 0)
		chip->dt.esr_qual_i_ua = DEFAULT_ESR_QUAL_CURRENT_UA;
	else
		chip->dt.esr_qual_i_ua = temp;

	rc = of_property_read_u32(node, "qcom,esr-qual-vbatt-uv", &temp);
	if (rc < 0)
		chip->dt.esr_qual_v_uv = DEFAULT_ESR_QUAL_VBAT_UV;
	else
		chip->dt.esr_qual_v_uv = temp;

	rc = of_property_read_u32(node, "qcom,esr-disable-soc", &temp);
	if (rc < 0)
		chip->dt.esr_disable_soc = DEFAULT_ESR_DISABLE_SOC;
	else
		chip->dt.esr_disable_soc = temp * 100;

	rc = of_property_read_u32(node, "qcom,esr-chg-min-ibat-ua", &temp);
	if (rc < 0)
		chip->dt.esr_min_ibat_ua = ESR_CHG_MIN_IBAT_UA;
	else
		chip->dt.esr_min_ibat_ua = (int)temp;

	rc = of_property_read_u32(node, "qcom,esr-low-temp-threshold", &temp);
	if (rc < 0)
		chip->dt.esr_low_temp_threshold =
					DEFAULT_ESR_LOW_TEMP_THRESHOLD;
	else
		chip->dt.esr_low_temp_threshold = (int)temp;

	rc = of_property_read_u32(node, "qcom,shutdown-soc-threshold", &temp);
	if (rc < 0)
		chip->dt.shutdown_soc_threshold = -EINVAL;
	else
		chip->dt.shutdown_soc_threshold = temp;

	rc = of_property_read_u32(node, "qcom,qg-sys-min-voltage", &temp);
	if (rc < 0)
		chip->dt.sys_min_volt_mv = DEFAULT_SYS_MIN_VOLT_MV;
	else
		chip->dt.sys_min_volt_mv = temp;

	chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns");

	chip->dt.use_cp_iin_sns = of_property_read_bool(node,
							"qcom,use-cp-iin-sns");

	chip->dt.use_s7_ocv = of_property_read_bool(node, "qcom,qg-use-s7-ocv");

	rc = of_property_read_u32(node, "qcom,min-sleep-time-secs", &temp);
	if (rc < 0)
		chip->dt.min_sleep_time_secs = DEFAULT_SLEEP_TIME_SECS;
	else
		chip->dt.min_sleep_time_secs = temp;

	if (of_property_read_bool(node, "qcom,fvss-enable")) {

		chip->dt.fvss_enable = true;

		rc = of_property_read_u32(node,
				"qcom,fvss-vbatt-mv", &temp);
		if (rc < 0)
			chip->dt.fvss_vbat_mv = DEFAULT_FVSS_VBAT_MV;
		else
			chip->dt.fvss_vbat_mv = temp;
	}

	if (of_property_read_bool(node, "qcom,tcss-enable")) {

		chip->dt.tcss_enable = true;

		rc = of_property_read_u32(node,
				"qcom,tcss-entry-soc", &temp);
		if (rc < 0)
			chip->dt.tcss_entry_soc = DEFAULT_TCSS_ENTRY_SOC;
		else
			chip->dt.tcss_entry_soc = temp;
	}

	chip->dt.bass_enable = of_property_read_bool(node, "qcom,bass-enable");

	chip->dt.multi_profile_load = of_property_read_bool(node,
					"qcom,multi-profile-load");

	qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n",
			chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
			chip->dt.delta_soc, chip->dt.qg_ext_sense);

	return 0;
}

static int process_suspend(struct qpnp_qg *chip)
{
	u8 status = 0;
	int rc;
	u32 fifo_rt_length = 0, sleep_fifo_length = 0;

	/* skip if profile is not loaded */
	if (!chip->profile_loaded)
		return 0;

	cancel_delayed_work_sync(&chip->ttf->ttf_work);

	chip->suspend_data = false;

	/* read STATUS2 register to clear its last state */
	qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);

	/* ignore any suspend processing if we are charging */
	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
		/* Reset the sleep config if we are charging */
		if (chip->dt.qg_sleep_config) {
			qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Charging - Exit S2_SLEEP\n");
			rc = qg_config_s2_state(chip, S2_SLEEP, false, true);
			if (rc < 0)
				pr_err("Failed to exit S2-sleep rc=%d\n", rc);
		}
		qg_dbg(chip, QG_DEBUG_PM, "Charging @ suspend - ignore processing\n");
		return 0;
	}

	rc = get_fifo_length(chip, &fifo_rt_length, true);
	if (rc < 0) {
		pr_err("Failed to read FIFO RT count, rc=%d\n", rc);
		return rc;
	}

	rc = qg_read(chip, chip->qg_base + QG_S3_SLEEP_OCV_IBAT_CTL1_REG,
			(u8 *)&sleep_fifo_length, 1);
	if (rc < 0) {
		pr_err("Failed to read sleep FIFO count, rc=%d\n", rc);
		return rc;
	}
	sleep_fifo_length &= SLEEP_IBAT_QUALIFIED_LENGTH_MASK;
	sleep_fifo_length++;

	if (chip->dt.qg_sleep_config) {
		qg_dbg(chip, QG_DEBUG_STATUS, "Suspend: Forcing S2_SLEEP\n");
		rc = qg_config_s2_state(chip, S2_SLEEP, true, true);
		if (rc < 0)
			pr_err("Failed to config S2_SLEEP rc=%d\n", rc);
		if (chip->kdata.fifo_length > 0)
			chip->suspend_data = true;
	} else if (fifo_rt_length >=
			(chip->dt.s2_fifo_length - sleep_fifo_length)) {
		/*
		 * If the real-time FIFO count is greater than
		 * the #fifo to enter sleep, save the FIFO data
		 * and reset the fifo count. This is avoid a gauranteed wakeup
		 * due to fifo_done event as the curent FIFO length is already
		 * beyond the sleep length.
		 */
		rc = qg_master_hold(chip, true);
		if (rc < 0) {
			pr_err("Failed to hold master, rc=%d\n", rc);
			return rc;
		}

		rc = qg_process_rt_fifo(chip);
		if (rc < 0) {
			pr_err("Failed to process FIFO real-time, rc=%d\n", rc);
			qg_master_hold(chip, false);
			return rc;
		}

		rc = qg_master_hold(chip, false);
		if (rc < 0) {
			pr_err("Failed to release master, rc=%d\n", rc);
			return rc;
		}
		/* FIFOs restarted */
		chip->last_fifo_update_time = ktime_get_boottime();

		chip->suspend_data = true;
	}

	get_rtc_time(&chip->suspend_time);

	qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d time=%d\n",
			fifo_rt_length, sleep_fifo_length,
			chip->dt.s2_fifo_length, chip->suspend_data,
			chip->suspend_time);

	return rc;
}

#define QG_SLEEP_EXIT_TIME_MS		15000 /* 15 secs */
static int process_resume(struct qpnp_qg *chip)
{
	u8 status2 = 0, rt_status = 0;
	u32 ocv_uv = 0, ocv_raw = 0;
	int rc;
	unsigned long rtc_sec = 0, sleep_time_secs = 0;

	/* skip if profile is not loaded */
	if (!chip->profile_loaded)
		return 0;

	get_rtc_time(&rtc_sec);
	sleep_time_secs = rtc_sec - chip->suspend_time;

	if (chip->dt.qg_sleep_config)
		schedule_delayed_work(&chip->qg_sleep_exit_work,
				msecs_to_jiffies(QG_SLEEP_EXIT_TIME_MS));

	rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status2, 1);
	if (rc < 0) {
		pr_err("Failed to read status2 register, rc=%d\n", rc);
		return rc;
	}

	if (status2 & GOOD_OCV_BIT) {
		rc = qg_read_ocv(chip, &ocv_uv, &ocv_raw, S3_GOOD_OCV);
		if (rc < 0) {
			pr_err("Failed to read good_ocv, rc=%d\n", rc);
			return rc;
		}

		 /* Clear suspend data as there has been a GOOD OCV */
		memset(&chip->kdata, 0, sizeof(chip->kdata));
		chip->kdata.fifo_time = (u32)rtc_sec;
		chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
		chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
		chip->suspend_data = false;

		/* allow SOC jump if we have slept longer */
		if (sleep_time_secs >= chip->dt.min_sleep_time_secs)
			chip->force_soc = true;

		qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
				ocv_uv);
	}

	rc = qg_read(chip, chip->qg_base + QG_INT_LATCHED_STS_REG,
						&rt_status, 1);
	if (rc < 0) {
		pr_err("Failed to read latched status register, rc=%d\n", rc);
		return rc;
	}
	rt_status &= FIFO_UPDATE_DONE_INT_LAT_STS_BIT;

	qg_dbg(chip, QG_DEBUG_PM, "FIFO_DONE_STS=%d suspend_data=%d good_ocv=%d sleep_time=%d secs\n",
				!!rt_status, chip->suspend_data,
				chip->kdata.param[QG_GOOD_OCV_UV].valid,
				sleep_time_secs);
	/*
	 * If this is not a wakeup from FIFO-done,
	 * process the data immediately if - we have data from
	 * suspend or there is a good OCV.
	 */
	if (!rt_status && (chip->suspend_data ||
			chip->kdata.param[QG_GOOD_OCV_UV].valid)) {
		vote(chip->awake_votable, SUSPEND_DATA_VOTER, true, 0);
		/* signal the read thread */
		chip->data_ready = true;
		wake_up_interruptible(&chip->qg_wait_q);
		chip->suspend_data = false;
	}

	schedule_delayed_work(&chip->ttf->ttf_work, 0);

	return rc;
}

static int qpnp_qg_suspend_noirq(struct device *dev)
{
	int rc;
	struct qpnp_qg *chip = dev_get_drvdata(dev);

	/* cancel any pending sleep_exit work */
	cancel_delayed_work_sync(&chip->qg_sleep_exit_work);

	mutex_lock(&chip->data_lock);

	rc = process_suspend(chip);
	if (rc < 0)
		pr_err("Failed to process QG suspend, rc=%d\n", rc);

	mutex_unlock(&chip->data_lock);

	return 0;
}

static int qpnp_qg_resume_noirq(struct device *dev)
{
	int rc;
	struct qpnp_qg *chip = dev_get_drvdata(dev);

	mutex_lock(&chip->data_lock);

	rc = process_resume(chip);
	if (rc < 0)
		pr_err("Failed to process QG resume, rc=%d\n", rc);

	mutex_unlock(&chip->data_lock);

	return 0;
}

static int qpnp_qg_suspend(struct device *dev)
{
	struct qpnp_qg *chip = dev_get_drvdata(dev);

	/* skip if profile is not loaded */
	if (!chip->profile_loaded)
		return 0;

	/* disable GOOD_OCV IRQ in sleep */
	vote(chip->good_ocv_irq_disable_votable,
			QG_INIT_STATE_IRQ_DISABLE, true, 0);

	return 0;
}

static int qpnp_qg_resume(struct device *dev)
{
	struct qpnp_qg *chip = dev_get_drvdata(dev);

	/* skip if profile is not loaded */
	if (!chip->profile_loaded)
		return 0;

	/* enable GOOD_OCV IRQ when active */
	vote(chip->good_ocv_irq_disable_votable,
			QG_INIT_STATE_IRQ_DISABLE, false, 0);

	return 0;
}

static const struct dev_pm_ops qpnp_qg_pm_ops = {
	.suspend_noirq	= qpnp_qg_suspend_noirq,
	.resume_noirq	= qpnp_qg_resume_noirq,
	.suspend	= qpnp_qg_suspend,
	.resume		= qpnp_qg_resume,
};

static int qpnp_qg_probe(struct platform_device *pdev)
{
	int rc = 0, soc = 0, nom_cap_uah;
	struct qpnp_qg *chip;
	struct iio_dev *indio_dev;
	struct qg_config *config;

	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*chip));
	if (!indio_dev)
		return -ENOMEM;

	chip = iio_priv(indio_dev);
	chip->indio_dev = indio_dev;

	chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
	if (!chip->regmap) {
		pr_err("Parent regmap is unavailable\n");
		return -ENXIO;
	}

	/* ADC for BID & THERM */
	chip->batt_id_chan = iio_channel_get(&pdev->dev, "batt-id");
	if (IS_ERR(chip->batt_id_chan)) {
		rc = PTR_ERR(chip->batt_id_chan);
		if (rc != -EPROBE_DEFER)
			pr_err("batt-id channel unavailable, rc=%d\n", rc);
		chip->batt_id_chan = NULL;
		return rc;
	}

	chip->batt_therm_chan = iio_channel_get(&pdev->dev, "batt-therm");
	if (IS_ERR(chip->batt_therm_chan)) {
		rc = PTR_ERR(chip->batt_therm_chan);
		if (rc != -EPROBE_DEFER)
			pr_err("batt-therm channel unavailable, rc=%d\n", rc);
		chip->batt_therm_chan = NULL;
		return rc;
	}

	chip->dev = &pdev->dev;
	chip->debug_mask = &qg_debug_mask;
	platform_set_drvdata(pdev, chip);
	INIT_WORK(&chip->udata_work, process_udata_work);
	INIT_WORK(&chip->qg_status_change_work, qg_status_change_work);
	INIT_DELAYED_WORK(&chip->qg_sleep_exit_work, qg_sleep_exit_work);
	mutex_init(&chip->bus_lock);
	mutex_init(&chip->soc_lock);
	mutex_init(&chip->data_lock);
	init_waitqueue_head(&chip->qg_wait_q);
	chip->maint_soc = -EINVAL;
	chip->batt_soc = INT_MIN;
	chip->cc_soc = INT_MIN;
	chip->sys_soc = INT_MIN;
	chip->full_soc = QG_SOC_FULL;
	chip->chg_iterm_ma = INT_MIN;
	chip->soh = -EINVAL;
	chip->esr_actual = -EINVAL;
	chip->esr_nominal = -EINVAL;
	chip->batt_age_level = -EINVAL;

	config = (struct qg_config *)of_device_get_match_data(
							&pdev->dev);
	if (!config) {
		pr_err("Failed to get QG config data\n");
		return -EINVAL;
	}

	chip->qg_version = config->qg_version;
	chip->pmic_version = config->pmic_version;

	qg_dbg(chip, QG_DEBUG_PON, "QG version:%d PMIC version:%d",
		chip->qg_version, chip->pmic_version);

	switch (chip->qg_version) {
	case QG_LITE:
		chip->max_fifo_length = 5;
		break;
	default:
		chip->max_fifo_length = 8;
		break;
	}

	qg_create_debugfs(chip);

	rc = qg_alg_init(chip);
	if (rc < 0) {
		pr_err("Error in alg_init, rc:%d\n", rc);
		return rc;
	}

	rc = qg_parse_dt(chip);
	if (rc < 0) {
		pr_err("Failed to parse DT, rc=%d\n", rc);
		return rc;
	}

	rc = qg_hw_init(chip);
	if (rc < 0) {
		pr_err("Failed to hw_init, rc=%d\n", rc);
		return rc;
	}

	rc = qg_sdam_init(chip->dev);
	if (rc < 0) {
		pr_err("Failed to initialize QG SDAM, rc=%d\n", rc);
		return rc;
	}

	rc = qg_setup_battery(chip);
	if (rc < 0) {
		pr_err("Failed to setup battery, rc=%d\n", rc);
		return rc;
	}

	rc = qg_register_device(chip);
	if (rc < 0) {
		pr_err("Failed to register QG char device, rc=%d\n", rc);
		return rc;
	}

	rc = qg_sanitize_sdam(chip);
	if (rc < 0) {
		pr_err("Failed to sanitize SDAM, rc=%d\n", rc);
		return rc;
	}

	rc = qg_soc_init(chip);
	if (rc < 0) {
		pr_err("Failed to initialize SOC scaling init rc=%d\n", rc);
		return rc;
	}

	if (chip->profile_loaded) {
		if (!chip->dt.cl_disable) {
			/*
			 * Use FCC @ 25 C and charge-profile for
			 * Nominal Capacity
			 */
			rc = qg_get_nominal_capacity(&nom_cap_uah, 250, true);
			if (!rc) {
				rc = cap_learning_post_profile_init(chip->cl,
						nom_cap_uah);
				if (rc < 0) {
					pr_err("Error in cap_learning_post_profile_init rc=%d\n",
						rc);
					return rc;
				}
			}
		}
		rc = restore_cycle_count(chip->counter);
		if (rc < 0) {
			pr_err("Error in restoring cycle_count, rc=%d\n", rc);
			return rc;
		}
		schedule_delayed_work(&chip->ttf->ttf_work, 10000);
	}

	rc = qg_determine_pon_soc(chip);
	if (rc < 0) {
		pr_err("Failed to determine initial state, rc=%d\n", rc);
		goto fail_device;
	}

	chip->awake_votable = create_votable("QG_WS", VOTE_SET_ANY,
					 qg_awake_cb, chip);
	if (IS_ERR(chip->awake_votable)) {
		rc = PTR_ERR(chip->awake_votable);
		chip->awake_votable = NULL;
		goto fail_device;
	}

	chip->vbatt_irq_disable_votable = create_votable("QG_VBATT_IRQ_DISABLE",
				VOTE_SET_ANY, qg_vbatt_irq_disable_cb, chip);
	if (IS_ERR(chip->vbatt_irq_disable_votable)) {
		rc = PTR_ERR(chip->vbatt_irq_disable_votable);
		chip->vbatt_irq_disable_votable = NULL;
		goto fail_device;
	}

	chip->fifo_irq_disable_votable = create_votable("QG_FIFO_IRQ_DISABLE",
				VOTE_SET_ANY, qg_fifo_irq_disable_cb, chip);
	if (IS_ERR(chip->fifo_irq_disable_votable)) {
		rc = PTR_ERR(chip->fifo_irq_disable_votable);
		chip->fifo_irq_disable_votable = NULL;
		goto fail_device;
	}

	chip->good_ocv_irq_disable_votable =
			create_votable("QG_GOOD_IRQ_DISABLE",
			VOTE_SET_ANY, qg_good_ocv_irq_disable_cb, chip);
	if (IS_ERR(chip->good_ocv_irq_disable_votable)) {
		rc = PTR_ERR(chip->good_ocv_irq_disable_votable);
		chip->good_ocv_irq_disable_votable = NULL;
		goto fail_device;
	}

	rc = qg_init_iio_psy(chip, pdev);
	if (rc < 0) {
		pr_err("Failed to initialize QG IIO PSY, rc=%d\n", rc);
		goto fail_votable;
	}

	rc = qg_init_psy(chip);
	if (rc < 0) {
		pr_err("Failed to initialize QG PSY, rc=%d\n", rc);
		goto fail_votable;
	}

	rc = qg_request_irqs(chip);
	if (rc < 0) {
		pr_err("Failed to register QG interrupts, rc=%d\n", rc);
		goto fail_votable;
	}

	rc = qg_post_init(chip);
	if (rc < 0) {
		pr_err("Failed in qg_post_init rc=%d\n", rc);
		goto fail_votable;
	}

	rc = sysfs_create_groups(&chip->dev->kobj, qg_groups);
	if (rc < 0) {
		pr_err("Failed to create sysfs files rc=%d\n", rc);
		goto fail_votable;
	}

	qg_get_battery_capacity(chip, &soc);

	pr_info("QG initialized! battery_profile=%s SOC=%d QG_subtype=%d QG_version=%s QG_mode=%s\n",
			qg_get_battery_type(chip), soc, chip->qg_subtype,
			(chip->qg_version == QG_LITE) ? "QG_LITE" : "QG_PMIC5",
			(chip->qg_mode == QG_V_I_MODE) ? "QG_V_I" : "QG_V");

	return rc;

fail_votable:
	destroy_votable(chip->awake_votable);
fail_device:
	device_destroy(chip->qg_class, chip->dev_no);
	cdev_del(&chip->qg_cdev);
	unregister_chrdev_region(chip->dev_no, 1);
	return rc;
}

static int qpnp_qg_remove(struct platform_device *pdev)
{
	struct qpnp_qg *chip = platform_get_drvdata(pdev);

	qg_batterydata_exit();
	qg_soc_exit(chip);

	cancel_delayed_work_sync(&chip->qg_sleep_exit_work);
	cancel_work_sync(&chip->udata_work);
	cancel_work_sync(&chip->qg_status_change_work);
	sysfs_remove_groups(&chip->dev->kobj, qg_groups);
	debugfs_remove_recursive(chip->dfs_root);
	device_destroy(chip->qg_class, chip->dev_no);
	cdev_del(&chip->qg_cdev);
	unregister_chrdev_region(chip->dev_no, 1);
	mutex_destroy(&chip->bus_lock);
	mutex_destroy(&chip->data_lock);
	mutex_destroy(&chip->soc_lock);
	if (chip->awake_votable)
		destroy_votable(chip->awake_votable);

	return 0;
}

static void qpnp_qg_shutdown(struct platform_device *pdev)
{
	struct qpnp_qg *chip = platform_get_drvdata(pdev);
	bool input_present = is_input_present(chip);

	if (!input_present || !chip->profile_loaded)
		return;
	/*
	 * Charging status doesn't matter when the device shuts down and we
	 * have to treat this as charge done. Hence pass charge_done as true.
	 */
	cycle_count_update(chip->counter,
			DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
			POWER_SUPPLY_STATUS_NOT_CHARGING,
			true, input_present);
}

static const struct of_device_id match_table[] = {
	{
		.compatible = "qcom,qpnp-qg-lite",
		.data = (void *)&config[PM2250],
	},
	{
		.compatible = "qcom,pm6150-qg",
		.data = (void *)&config[PM6150],
	},
	{
		.compatible = "qcom,pmi632-qg",
		.data = (void *)&config[PMI632],
	},
	{
		.compatible = "qcom,pm7250b-qg",
		.data = (void *)&config[PM7250B],
	},
	{
	},
};

static struct platform_driver qpnp_qg_driver = {
	.driver		= {
		.name		= "qcom,qpnp-qg",
		.of_match_table	= match_table,
		.pm		= &qpnp_qg_pm_ops,
	},
	.probe		= qpnp_qg_probe,
	.remove		= qpnp_qg_remove,
	.shutdown	= qpnp_qg_shutdown,
};
module_platform_driver(qpnp_qg_driver);

MODULE_DESCRIPTION("QPNP QG Driver");
MODULE_LICENSE("GPL v2");
