power: qpnp-bms: implement workarounds for coupling issue

On certain PMICs there is a coupling issue which causes bad calibration
values that reports a high current value even when the BATFET is open.
This coupling issue happens regardless of an internal/external rsense
configuration.

The suggested workaround is to repeatedly calibrate until we get values
that result in less than 3mA of current.

Expose the BATFET open/closed as battery's ONLINE property. It is
reasonable use of this property since PRESENT suggests a battery is
actually present in the device and ONLINE suggests if it is connected to
the system via BATFET.

The BATFET can open when a charger is present and
* the battery is fully charged
* the battery is hot/cold
(Note that if charger is disabled the buck will not operate
and we don't have coupling issue)
The fully charged notifications trickle down to BMS driver,
since battery psy supplies to "bms", use it to check if the
BATFET has opened.
The hot/cold interrupt is not yet registered to, add it so we can notify
the BMS driver if the battery goes hot or cold. Since the battery can
go hot or cold while the device is sleeping, we need to wakeup for
calibration workaround.

The BATFET can close when
* the charger is removed
* the battery recovers form hot/cold conditions when charger is present
These notifications too trickle down to the BMS driver and can be used to
check if the BATFET has closed.

Also once good calibration values are detected above use them until BATFET
closes i.e. do NOT calibrate until the BATFET closes. Update the code
that periodically calculates SOC to skip calibrations as long as BATFET
is open. On the same lines ask the iadc driver to skip auto calibrations
until BATFET closes.

CRs-Fixed: 509620
Change-Id: I89b521368304d7171d75e462cf15f2f1daa55cdc
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index f0793b2..a453159 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -146,9 +146,10 @@
 	bool					iadc_mode_sel;
 	struct qpnp_iadc_comp			iadc_comp;
 	struct sensor_device_attribute		sens_attr[0];
+	bool					skip_auto_calibrations;
 };
 
-struct qpnp_iadc_drv	*qpnp_iadc;
+static struct qpnp_iadc_drv	*qpnp_iadc;
 
 static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
 {
@@ -635,13 +636,15 @@
 	struct qpnp_iadc_drv *iadc = qpnp_iadc;
 	int rc = 0;
 
-	rc = qpnp_iadc_calibrate_for_trim(true);
-	if (rc)
-		pr_debug("periodic IADC calibration failed\n");
-	else
-		schedule_delayed_work(&iadc->iadc_work,
-			round_jiffies_relative(msecs_to_jiffies
-					(QPNP_IADC_CALIB_SECONDS)));
+	if (!iadc->skip_auto_calibrations) {
+		rc = qpnp_iadc_calibrate_for_trim(true);
+		if (rc)
+			pr_debug("periodic IADC calibration failed\n");
+	}
+
+	schedule_delayed_work(&iadc->iadc_work,
+		round_jiffies_relative(msecs_to_jiffies
+				(QPNP_IADC_CALIB_SECONDS)));
 	return;
 }
 
@@ -731,9 +734,11 @@
 
 	if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
 		iadc->die_temp = result_pmic_therm.physical;
-		rc = qpnp_iadc_calibrate_for_trim(true);
-		if (rc)
-			pr_err("periodic IADC calibration failed\n");
+		if (!iadc->skip_auto_calibrations) {
+			rc = qpnp_iadc_calibrate_for_trim(true);
+			if (rc)
+				pr_err("IADC calibration failed rc = %d\n", rc);
+		}
 	}
 
 	return rc;
@@ -833,6 +838,30 @@
 }
 EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
 
+int qpnp_iadc_skip_calibration(void)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+
+	iadc->skip_auto_calibrations = true;
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
+
+int qpnp_iadc_resume_calibration(void)
+{
+	struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+	if (!iadc || !iadc->iadc_initialized)
+		return -EPROBE_DEFER;
+
+	iadc->skip_auto_calibrations = false;
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
+
 int32_t qpnp_iadc_vadc_sync_read(
 	enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
 	enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)