qcom-charger: smb-lib: support input limited state property

Add support to indicate if the switcher is acting in input limited state.
Switcher running in high duty cycle (HDC) mode should also be indicated as
input limited condition.
HDC is a 5uS pulse and sw reading the real time status register may not
indicate that it is active. Basically the presence of the pulses and the
interrupts indicate HDC and conversely their absence indicates no
HDC. Set a flag in the interrupt and clear it in a delayed work queue in
20mS. As long as the interrupts happen this flag will remain set,
indicating HDC.

Change-Id: Ia2e2d02240c36ba982f9e190b88b822b5f1b90f1
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 9f36cc2..3c9e35c 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -588,6 +588,7 @@
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
 	POWER_SUPPLY_PROP_CHARGER_TEMP,
 	POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
 };
 
 static int smb2_batt_get_prop(struct power_supply *psy,
@@ -625,6 +626,9 @@
 	case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
 		rc = smblib_get_prop_charger_temp_max(chg, val);
 		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+		rc = smblib_get_prop_input_current_limited(chg, val);
+		break;
 	default:
 		pr_err("batt power supply prop %d not supported\n", psp);
 		return -EINVAL;
@@ -1124,7 +1128,7 @@
 	{ "wdog-bark",			NULL },
 	{ "aicl-fail",			smblib_handle_debug },
 	{ "aicl-done",			smblib_handle_debug },
-	{ "high-duty-cycle",		smblib_handle_debug },
+	{ "high-duty-cycle",		smblib_handle_high_duty_cycle, true },
 	{ "input-current-limiting",	smblib_handle_debug },
 	{ "temperature-change",		smblib_handle_debug },
 	{ "switcher-power-ok",		smblib_handle_debug },
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index ee4f654..21b3301 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -988,6 +988,21 @@
 	return 0;
 }
 
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	u8 stat;
+	int rc;
+
+	rc = smblib_read(chg, AICL_STATUS_REG, &stat);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't read AICL_STATUS rc=%d\n", rc);
+		return rc;
+	}
+	val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
+	return 0;
+}
+
 /***********************
  * BATTERY PSY SETTERS *
  ***********************/
@@ -1965,6 +1980,17 @@
 	return IRQ_HANDLED;
 }
 
+irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	chg->is_hdc = true;
+	schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
+
+	return IRQ_HANDLED;
+}
+
 /***************
  * Work Queues *
  ***************/
@@ -2054,6 +2080,14 @@
 	vote(chg->awake_votable, PL_VOTER, false, 0);
 }
 
+static void clear_hdc_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						clear_hdc_work.work);
+
+	chg->is_hdc = 0;
+}
+
 static int smblib_create_votables(struct smb_charger *chg)
 {
 	int rc = 0;
@@ -2194,6 +2228,7 @@
 	INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
 	INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
 	INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
+	INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
 	chg->fake_capacity = -EINVAL;
 
 	switch (chg->mode) {
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 1b0c221..aeb1eb2 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -145,6 +145,7 @@
 	struct delayed_work	ps_change_timeout_work;
 	struct delayed_work	pl_taper_work;
 	struct delayed_work	step_soc_req_work;
+	struct delayed_work	clear_hdc_work;
 
 	/* cached status */
 	int			voltage_min_uv;
@@ -159,6 +160,7 @@
 	int			fake_capacity;
 
 	bool			step_chg_enabled;
+	bool			is_hdc;
 };
 
 int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -202,6 +204,7 @@
 irqreturn_t smblib_handle_usb_source_change(int irq, void *data);
 irqreturn_t smblib_handle_icl_change(int irq, void *data);
 irqreturn_t smblib_handle_usb_typec_change(int irq, void *data);
+irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data);
 
 int smblib_get_prop_input_suspend(struct smb_charger *chg,
 				union power_supply_propval *val);
@@ -217,6 +220,8 @@
 				union power_supply_propval *val);
 int smblib_get_prop_system_temp_level(struct smb_charger *chg,
 				union power_supply_propval *val);
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val);
 
 int smblib_set_prop_input_suspend(struct smb_charger *chg,
 				const union power_supply_propval *val);