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: Anirudh Ghayal <aghayal@codeaurora.org>
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 4e4a298..56233f5 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -671,6 +671,7 @@
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 @@
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 @@
{
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 @@
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_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,84 +1503,77 @@
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);
+ rc = get_rtc_time(&rtc_sec);
if (rc < 0) {
- pr_err("Failed to read status2 register rc=%d\n", rc);
- return rc;
+ pr_err("Failed to read RTC time rc=%d\n", rc);
+ goto use_pon_ocv;
}
- 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;
+ rc = qg_sdam_read_all(shutdown);
+ if (rc < 0) {
+ pr_err("Failed to read shutdown params rc=%d\n", rc);
+ 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],
+ shutdown[SDAM_OCV_UV],
+ shutdown[SDAM_TIME_SEC],
+ rtc_sec);
+ /*
+ * Use the shutdown SOC if
+ * 1. The device was powered off for < ignore_shutdown_time
+ * 2. SDAM read is a success & SDAM data is valid
+ */
+ 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;
}
- rc = qg_sdam_read_all(shutdown);
+ rc = qg_read(chip, chip->qg_base + QG_STATUS2_REG, &status, 1);
if (rc < 0) {
- pr_err("Failed to read shutdown params rc=%d\n", rc);
- use_pon_ocv = true;
+ pr_err("Failed to read status2 register rc=%d\n", rc);
goto done;
}
- 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],
- shutdown[SDAM_OCV_UV],
- shutdown[SDAM_TIME_SEC],
- rtc_sec);
- /*
- * Use the shutdown SOC if
- * 1. The device was powered off for < 180 seconds
- * 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)) {
- use_pon_ocv = false;
- ocv_uv = shutdown[SDAM_OCV_UV];
- soc = shutdown[SDAM_SOC];
- qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
+
+ 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);
+ 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);
- if (rc < 0) {
- pr_err("Failed to read HW PON ocv rc=%d\n", rc);
- return rc;
- }
- 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;
- }
+ 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 @@
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 @@
#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 @@
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 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 @@
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 @@
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);