Merge "power: qpnp-charger: avoid unbalanced irq enable"
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 10a9fcc..624a42f 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -184,6 +184,11 @@
 /* Workaround flags */
 #define CHG_FLAGS_VCP_WA		BIT(0)
 
+struct qpnp_chg_irq {
+	unsigned int		irq;
+	unsigned long		disabled;
+};
+
 /**
  * struct qpnp_chg_chip - device information
  * @dev:			device pointer to access the parent
@@ -242,14 +247,14 @@
 	u16				boost_base;
 	u16				misc_base;
 	u16				freq_base;
-	unsigned int			usbin_valid_irq;
-	unsigned int			dcin_valid_irq;
-	unsigned int			chg_gone_irq;
-	unsigned int			chg_fastchg_irq;
-	unsigned int			chg_trklchg_irq;
-	unsigned int			chg_failed_irq;
-	unsigned int			chg_vbatdet_lo_irq;
-	unsigned int			batt_pres_irq;
+	struct qpnp_chg_irq		usbin_valid;
+	struct qpnp_chg_irq		dcin_valid;
+	struct qpnp_chg_irq		chg_gone;
+	struct qpnp_chg_irq		chg_fastchg;
+	struct qpnp_chg_irq		chg_trklchg;
+	struct qpnp_chg_irq		chg_failed;
+	struct qpnp_chg_irq		chg_vbatdet_lo;
+	struct qpnp_chg_irq		batt_pres;
 	bool				bat_is_cool;
 	bool				bat_is_warm;
 	bool				chg_done;
@@ -292,6 +297,7 @@
 	struct wake_lock		eoc_wake_lock;
 };
 
+
 static struct of_device_id qpnp_charger_match_table[] = {
 	{ .compatible = QPNP_CHARGER_DEV_NAME, },
 	{}
@@ -379,6 +385,24 @@
 	return 0;
 }
 
+static void
+qpnp_chg_enable_irq(struct qpnp_chg_irq *irq)
+{
+	if (__test_and_clear_bit(0, &irq->disabled)) {
+		pr_debug("number = %d\n", irq->irq);
+		enable_irq(irq->irq);
+	}
+}
+
+static void
+qpnp_chg_disable_irq(struct qpnp_chg_irq *irq)
+{
+	if (!__test_and_set_bit(0, &irq->disabled)) {
+		pr_debug("number = %d\n", irq->irq);
+		disable_irq_nosync(irq->irq);
+	}
+}
+
 #define USB_OTG_EN_BIT	BIT(0)
 static int
 qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip)
@@ -674,7 +698,7 @@
 		schedule_delayed_work(&chip->eoc_work,
 			msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 		wake_lock(&chip->eoc_wake_lock);
-		disable_irq_nosync(chip->chg_vbatdet_lo_irq);
+		qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
 	} else {
 		qpnp_chg_charge_en(chip, !chip->charging_disabled);
 	}
@@ -832,7 +856,7 @@
 	power_supply_changed(chip->usb_psy);
 	if (chip->dc_chgpth_base)
 		power_supply_changed(&chip->dc_psy);
-	enable_irq(chip->chg_vbatdet_lo_irq);
+	qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
 
 	return IRQ_HANDLED;
 }
@@ -1555,7 +1579,7 @@
 				qpnp_chg_charge_en(chip, 0);
 				chip->chg_done = true;
 				power_supply_changed(&chip->batt_psy);
-				enable_irq(chip->chg_vbatdet_lo_irq);
+				qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
 				goto stop_eoc;
 			} else {
 				count += 1;
@@ -1564,7 +1588,7 @@
 		} else if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
 			(chip->max_voltage_mv - chip->resume_delta_mv))) {
 			pr_debug("woke up too early\n");
-			enable_irq(chip->chg_vbatdet_lo_irq);
+			qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
 			goto stop_eoc;
 		}
 	} else {
@@ -1721,157 +1745,157 @@
 		case SMBB_CHGR_SUBTYPE:
 		case SMBBP_CHGR_SUBTYPE:
 		case SMBCL_CHGR_SUBTYPE:
-			chip->chg_fastchg_irq = spmi_get_irq_byname(spmi,
+			chip->chg_fastchg.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "fast-chg-on");
-			if (chip->chg_fastchg_irq < 0) {
+			if (chip->chg_fastchg.irq < 0) {
 				pr_err("Unable to get fast-chg-on irq\n");
 				return rc;
 			}
 
-			chip->chg_trklchg_irq = spmi_get_irq_byname(spmi,
+			chip->chg_trklchg.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "trkl-chg-on");
-			if (chip->chg_trklchg_irq < 0) {
+			if (chip->chg_trklchg.irq < 0) {
 				pr_err("Unable to get trkl-chg-on irq\n");
 				return rc;
 			}
 
-			chip->chg_failed_irq = spmi_get_irq_byname(spmi,
+			chip->chg_failed.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "chg-failed");
-			if (chip->chg_failed_irq < 0) {
+			if (chip->chg_failed.irq < 0) {
 				pr_err("Unable to get chg_failed irq\n");
 				return rc;
 			}
 
-			chip->chg_vbatdet_lo_irq = spmi_get_irq_byname(spmi,
+			chip->chg_vbatdet_lo.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "vbat-det-lo");
-			if (chip->chg_vbatdet_lo_irq < 0) {
+			if (chip->chg_vbatdet_lo.irq < 0) {
 				pr_err("Unable to get fast-chg-on irq\n");
 				return rc;
 			}
 
-			rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
+			rc |= devm_request_irq(chip->dev, chip->chg_failed.irq,
 				qpnp_chg_chgr_chg_failed_irq_handler,
 				IRQF_TRIGGER_RISING, "chg-failed", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d chg-failed: %d\n",
-						chip->chg_failed_irq, rc);
+						chip->chg_failed.irq, rc);
 				return rc;
 			}
 
-			rc |= devm_request_irq(chip->dev, chip->chg_fastchg_irq,
+			rc |= devm_request_irq(chip->dev, chip->chg_fastchg.irq,
 					qpnp_chg_chgr_chg_fastchg_irq_handler,
 					IRQF_TRIGGER_RISING,
 					"fast-chg-on", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d fast-chg-on: %d\n",
-						chip->chg_fastchg_irq, rc);
+						chip->chg_fastchg.irq, rc);
 				return rc;
 			}
 
-			rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
+			rc |= devm_request_irq(chip->dev, chip->chg_trklchg.irq,
 				qpnp_chg_chgr_chg_trklchg_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 				"trkl-chg-on", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d trkl-chg-on: %d\n",
-						chip->chg_trklchg_irq, rc);
+						chip->chg_trklchg.irq, rc);
 				return rc;
 			}
 
 			rc |= devm_request_irq(chip->dev,
-				chip->chg_vbatdet_lo_irq,
+				chip->chg_vbatdet_lo.irq,
 				qpnp_chg_vbatdet_lo_irq_handler,
 				IRQF_TRIGGER_RISING,
 				"vbat-det-lo", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d vbat-det-lo: %d\n",
-						chip->chg_vbatdet_lo_irq, rc);
+						chip->chg_vbatdet_lo.irq, rc);
 				return rc;
 			}
 
-			enable_irq_wake(chip->chg_fastchg_irq);
-			enable_irq_wake(chip->chg_trklchg_irq);
-			enable_irq_wake(chip->chg_failed_irq);
-			disable_irq_nosync(chip->chg_vbatdet_lo_irq);
-			enable_irq_wake(chip->chg_vbatdet_lo_irq);
+			enable_irq_wake(chip->chg_trklchg.irq);
+			enable_irq_wake(chip->chg_failed.irq);
+			qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
+			enable_irq_wake(chip->chg_vbatdet_lo.irq);
 
 			break;
 		case SMBB_BAT_IF_SUBTYPE:
 		case SMBBP_BAT_IF_SUBTYPE:
 		case SMBCL_BAT_IF_SUBTYPE:
-			chip->batt_pres_irq = spmi_get_irq_byname(spmi,
+			chip->batt_pres.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "batt-pres");
-			if (chip->batt_pres_irq < 0) {
+			if (chip->batt_pres.irq < 0) {
 				pr_err("Unable to get batt-pres irq\n");
 				return rc;
 			}
-			rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
+			rc = devm_request_irq(chip->dev, chip->batt_pres.irq,
 				qpnp_chg_bat_if_batt_pres_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 				"batt-pres", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d batt-pres irq: %d\n",
-						chip->batt_pres_irq, rc);
+						chip->batt_pres.irq, rc);
 				return rc;
 			}
 
-			enable_irq_wake(chip->batt_pres_irq);
+			enable_irq_wake(chip->batt_pres.irq);
 			break;
 		case SMBB_USB_CHGPTH_SUBTYPE:
 		case SMBBP_USB_CHGPTH_SUBTYPE:
 		case SMBCL_USB_CHGPTH_SUBTYPE:
-			chip->usbin_valid_irq = spmi_get_irq_byname(spmi,
+			chip->usbin_valid.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "usbin-valid");
-			if (chip->usbin_valid_irq < 0) {
+			if (chip->usbin_valid.irq < 0) {
 				pr_err("Unable to get usbin irq\n");
 				return rc;
 			}
-			rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
+			rc = devm_request_irq(chip->dev, chip->usbin_valid.irq,
 				qpnp_chg_usb_usbin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 					"usbin-valid", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d usbin-valid: %d\n",
-						chip->usbin_valid_irq, rc);
+						chip->usbin_valid.irq, rc);
 				return rc;
 			}
 
-			chip->chg_gone_irq = spmi_get_irq_byname(spmi,
+			chip->chg_gone.irq = spmi_get_irq_byname(spmi,
 						spmi_resource, "chg-gone");
-			if (chip->chg_gone_irq < 0) {
+			if (chip->chg_gone.irq < 0) {
 				pr_err("Unable to get chg-gone irq\n");
 				return rc;
 			}
-			rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
+			rc = devm_request_irq(chip->dev, chip->chg_gone.irq,
 				qpnp_chg_usb_chg_gone_irq_handler,
 				IRQF_TRIGGER_RISING,
 					"chg-gone", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d chg-gone: %d\n",
-						chip->chg_gone_irq, rc);
+						chip->chg_gone.irq, rc);
 				return rc;
 			}
-			enable_irq_wake(chip->usbin_valid_irq);
-			enable_irq_wake(chip->chg_gone_irq);
+
+			enable_irq_wake(chip->usbin_valid.irq);
+			enable_irq_wake(chip->chg_gone.irq);
 			break;
 		case SMBB_DC_CHGPTH_SUBTYPE:
-			chip->dcin_valid_irq = spmi_get_irq_byname(spmi,
+			chip->dcin_valid.irq = spmi_get_irq_byname(spmi,
 					spmi_resource, "dcin-valid");
-			if (chip->dcin_valid_irq < 0) {
+			if (chip->dcin_valid.irq < 0) {
 				pr_err("Unable to get dcin irq\n");
 				return -rc;
 			}
-			rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
+			rc = devm_request_irq(chip->dev, chip->dcin_valid.irq,
 				qpnp_chg_dc_dcin_valid_irq_handler,
 				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 				"dcin-valid", chip);
 			if (rc < 0) {
 				pr_err("Can't request %d dcin-valid: %d\n",
-						chip->dcin_valid_irq, rc);
+						chip->dcin_valid.irq, rc);
 				return rc;
 			}
 
-			enable_irq_wake(chip->dcin_valid_irq);
+			enable_irq_wake(chip->dcin_valid.irq);
 			break;
 		}
 	}