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

Commit e4923386 authored by Anirudh Ghayal's avatar Anirudh Ghayal
Browse files

power: qpnp-qg: Minor modifications in QG



 - Reading of sticky register and its usage
   for GOOD_OCV check.
 - SOC scaling and suspend/resume handing only
   if the profile is loaded.
 - Update the PON SOC handling logic.

Change-Id: I4e08aa33a168adf7aa23f273ff3f3676091237e3
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent 70cf9e96
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -144,6 +144,12 @@ First Level Node - QGAUGE device
	Value type: <u32>
	Definition: Resistance of the battery connectors in mOhms.

- qcom,ignore-shutdown-soc-secs
	Usage:      optional
	Value type: <u32>
	Definition: Time in seconds beyond which shutdown SOC is ignored.
		    If not specified the default value is 360 secs.

==========================================================
Second Level Nodes - Peripherals managed by QGAUGE driver
==========================================================
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ struct qg_dt {
	int			s3_exit_ibat_ua;
	int			delta_soc;
	int			rbat_conn_mohm;
	int			ignore_shutdown_soc_secs;
};

struct qpnp_qg {
@@ -79,6 +80,7 @@ struct qpnp_qg {

	/* status variable */
	u32			*debug_mask;
	bool			qg_device_open;
	bool			profile_loaded;
	bool			battery_missing;
	bool			data_ready;
+3 −0
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ static void get_next_update_time(struct qpnp_qg *chip, int *time_ms)

static bool is_scaling_required(struct qpnp_qg *chip)
{
	if (!chip->profile_loaded)
		return false;

	if ((abs(chip->catch_up_soc - chip->msoc) < chip->dt.delta_soc) &&
		chip->catch_up_soc != 0 && chip->catch_up_soc != 100)
		return false;
+7 −6
Original line number Diff line number Diff line
@@ -36,7 +36,14 @@ int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
	int rc, i;
	u32 dummy = 0;

	rc = regmap_bulk_read(chip->regmap, addr, val, len);
	if (rc < 0) {
		pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
		return rc;
	}

	if (is_sticky_register(addr)) {
		/* write to the sticky register to clear it */
		rc = regmap_write(chip->regmap, addr, dummy);
		if (rc < 0) {
			pr_err("Failed regmap_write for %04x rc=%d\n",
@@ -45,12 +52,6 @@ int qg_read(struct qpnp_qg *chip, u32 addr, u8 *val, int len)
		}
	}

	rc = regmap_bulk_read(chip->regmap, addr, val, len);
	if (rc < 0) {
		pr_err("Failed regmap_read for address %04x rc=%d\n", addr, rc);
		return rc;
	}

	if (*chip->debug_mask & QG_DEBUG_BUS_READ) {
		pr_info("length %d addr=%04x\n", len, addr);
		for (i = 0; i < len; i++)
+107 −68
Original line number Diff line number Diff line
@@ -671,6 +671,7 @@ static irqreturn_t qg_vbat_empty_handler(int irq, void *data)
static irqreturn_t qg_good_ocv_handler(int irq, void *data)
{
	int rc;
	u8 status = 0;
	u32 ocv_uv;
	struct qpnp_qg *chip = data;

@@ -678,6 +679,15 @@ static irqreturn_t qg_good_ocv_handler(int irq, void *data)

	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, GOOD_OCV);
	if (rc < 0) {
		pr_err("Failed to read good_ocv, rc=%d\n", rc);
@@ -737,6 +747,10 @@ static int qg_awake_cb(struct votable *votable, void *data, int awake,
{
	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
@@ -1278,14 +1292,28 @@ static int qg_device_open(struct inode *inode, struct file *file)
				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,
@@ -1464,9 +1492,9 @@ static int qg_setup_battery(struct qpnp_qg *chip)

static int qg_determine_pon_soc(struct qpnp_qg *chip)
{
	u8 status;
	int rc, batt_temp = 0;
	bool use_pon_ocv = false;
	u8 status = 0, ocv_type = 0;
	int rc = 0, batt_temp = 0;
	bool use_pon_ocv = true, use_shutdown_ocv = false;
	unsigned long rtc_sec = 0;
	u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0};

@@ -1475,47 +1503,18 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip)
		return 0;
	}

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

	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);
		return rc;
	}

	if (status & GOOD_OCV_BIT) {
		qg_dbg(chip, QG_DEBUG_PON, "Using GOOD_OCV @ PON\n");
		rc = qg_read_ocv(chip, &ocv_uv, GOOD_OCV);
		if (rc < 0) {
			pr_err("Failed to read good_ocv rc=%d\n", rc);
			use_pon_ocv = true;
		} else {
			rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
			if (rc < 0) {
				pr_err("Failed to lookup SOC (GOOD_OCV) @ PON rc=%d\n",
					rc);
				use_pon_ocv = true;
			}
		}
	} else {
	rc = get_rtc_time(&rtc_sec);
	if (rc < 0) {
		pr_err("Failed to read RTC time rc=%d\n", rc);
			use_pon_ocv = true;
			goto done;
		goto use_pon_ocv;
	}

	rc = qg_sdam_read_all(shutdown);
	if (rc < 0) {
		pr_err("Failed to read shutdown params rc=%d\n", rc);
			use_pon_ocv = true;
			goto done;
		goto use_pon_ocv;
	}

	qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
			shutdown[SDAM_VALID],
			shutdown[SDAM_SOC],
@@ -1524,35 +1523,57 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip)
			rtc_sec);
	/*
	 * Use the shutdown SOC if
		 * 1. The device was powered off for < 180 seconds
	 * 1. The device was powered off for < ignore_shutdown_time
	 * 2. SDAM read is a success & SDAM data is valid
	 */
		use_pon_ocv = true;
		if (!rc && shutdown[SDAM_VALID] &&
			((rtc_sec - shutdown[SDAM_TIME_SEC]) < 180)) {
	if (shutdown[SDAM_VALID] && is_between(0,
			chip->dt.ignore_shutdown_soc_secs,
			(rtc_sec - shutdown[SDAM_TIME_SEC]))) {
		use_pon_ocv = false;
		use_shutdown_ocv = true;
		ocv_uv = shutdown[SDAM_OCV_UV];
		soc = shutdown[SDAM_SOC];
		qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
	}

use_pon_ocv:
	if (use_pon_ocv == true) {
		rc = qg_get_battery_temp(chip, &batt_temp);
		if (rc) {
			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
			goto done;
		}
done:
	/*
	 * Use PON OCV if
	 * OCV_UV is not set or shutdown SOC is invalid.
	 */
	if (use_pon_ocv || !ocv_uv || !rtc_sec) {
		qg_dbg(chip, QG_DEBUG_PON, "Using PON_OCV @ PON\n");
		rc = qg_read_ocv(chip, &ocv_uv, PON_OCV);

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

		if (status & GOOD_OCV_BIT)
			ocv_type = GOOD_OCV;
		else
			ocv_type = PON_OCV;

		qg_dbg(chip, QG_DEBUG_PON, "Using %s @ PON\n",
				ocv_type == GOOD_OCV ? "GOOD_OCV" : "PON_OCV");

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

		rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false);
		if (rc < 0) {
			pr_err("Failed to lookup SOC@PON rc=%d\n", rc);
			soc = 50;
			goto done;
		}
	}
done:
	if (rc < 0) {
		pr_err("Failed to get SOC @ PON, rc=%d\n", rc);
		return rc;
	}

	chip->pon_soc = chip->catch_up_soc = chip->msoc = soc;
@@ -1572,10 +1593,9 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip)
	if (rc < 0)
		pr_err("Failed to update sdam params rc=%d\n", rc);

	pr_info("use_pon_ocv=%d good_ocv=%d ocv_uv=%duV temp=%d soc=%d\n",
	pr_info("use_pon_ocv=%d use_good_ocv=%d use_shutdown_ocv=%d ocv_uv=%duV soc=%d\n",
			use_pon_ocv, !!(status & GOOD_OCV_BIT),
			ocv_uv, batt_temp, chip->msoc);

			use_shutdown_ocv, ocv_uv, chip->msoc);
	return 0;
}

@@ -1885,6 +1905,7 @@ static int qg_request_irqs(struct qpnp_qg *chip)
#define DEFAULT_S2_ACC_LENGTH		128
#define DEFAULT_S2_ACC_INTVL_MS		100
#define DEFAULT_DELTA_SOC		1
#define DEFAULT_SHUTDOWN_SOC_SECS	360
static int qg_parse_dt(struct qpnp_qg *chip)
{
	int rc = 0;
@@ -2042,6 +2063,12 @@ static int qg_parse_dt(struct qpnp_qg *chip)
	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,rbat-conn-mohm", &temp);
	if (rc < 0)
		chip->dt.rbat_conn_mohm = 0;
@@ -2057,9 +2084,14 @@ static int qg_parse_dt(struct qpnp_qg *chip)

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;

	chip->suspend_data = false;

	/* ignore any suspend processing if we are charging */
@@ -2111,6 +2143,9 @@ static int process_suspend(struct qpnp_qg *chip)
		chip->suspend_data = true;
	}

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

	qg_dbg(chip, QG_DEBUG_PM, "FIFO rt_length=%d sleep_fifo_length=%d default_s2_count=%d suspend_data=%d\n",
			fifo_rt_length, sleep_fifo_length,
			chip->dt.s2_fifo_length, chip->suspend_data);
@@ -2124,6 +2159,10 @@ static int process_resume(struct qpnp_qg *chip)
	u32 ocv_uv = 0;
	int rc, batt_temp = 0;

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

	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);