[PATCH] power: reset: qcom-pon: Add power on/off reason info

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add power on/off reason message for debug.

Signed-off-by: Jun Nie <jun.nie@xxxxxxxxxx>
---
 drivers/power/reset/qcom-pon.c | 124 ++++++++++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 1 deletion(-)

diff --git a/drivers/power/reset/qcom-pon.c b/drivers/power/reset/qcom-pon.c
index 4a688741a88a..012b87f5ab1d 100644
--- a/drivers/power/reset/qcom-pon.c
+++ b/drivers/power/reset/qcom-pon.c
@@ -12,6 +12,11 @@
 #include <linux/reboot-mode.h>
 #include <linux/regmap.h>
 
+#define PON_REASON1			0x08
+#define PON_WARM_RESET_REASON1		0x0a
+#define PON_WARM_RESET_REASON2		0x0b
+#define PON_WARM_RESET_TFT		BIT(4)
+#define POFF_REASON1			0x0c
 #define PON_SOFT_RB_SPARE		0x8f
 
 #define GEN1_REASON_SHIFT		2
@@ -23,6 +28,41 @@ struct pm8916_pon {
 	u32 baseaddr;
 	struct reboot_mode_driver reboot_mode;
 	long reason_shift;
+	int pon_trigger_reason;
+	int pon_power_off_reason;
+	unsigned int warm_reset_reason1;
+	unsigned int warm_reset_reason2;
+};
+
+static const char * const pm8916_pon_reason[] = {
+	[0] = "Triggered from Hard Reset",
+	[1] = "Triggered from SMPL (sudden momentary power loss)",
+	[2] = "Triggered from RTC (RTC alarm expiry)",
+	[3] = "Triggered from DC (DC charger insertion)",
+	[4] = "Triggered from USB (USB charger insertion)",
+	[5] = "Triggered from PON1 (secondary PMIC)",
+	[6] = "Triggered from CBL (external power supply)",
+	[7] = "Triggered from KPD (power key press)",
+};
+
+static const char * const pm8916_poff_reason[] = {
+	[0] = "Triggered from SOFT (Software)",
+	[1] = "Triggered from PS_HOLD (PS_HOLD/MSM controlled shutdown)",
+	[2] = "Triggered from PMIC_WD (PMIC watchdog)",
+	[3] = "Triggered from GP1 (Keypad_Reset1)",
+	[4] = "Triggered from GP2 (Keypad_Reset2)",
+	[5] = "Triggered from KPDPWR_AND_RESIN"
+		"(Simultaneous power key and reset line)",
+	[6] = "Triggered from RESIN_N (Reset line/Volume Down Key)",
+	[7] = "Triggered from KPDPWR_N (Long Power Key hold)",
+	[8] = "N/A",
+	[9] = "N/A",
+	[10] = "N/A",
+	[11] = "Triggered from CHARGER (Charger ENUM_TIMER, BOOT_DONE)",
+	[12] = "Triggered from TFT (Thermal Fault Tolerance)",
+	[13] = "Triggered from UVLO (Under Voltage Lock Out)",
+	[14] = "Triggered from OTST3 (Overtemp)",
+	[15] = "Triggered from STAGE3 (Stage 3 reset)",
 };
 
 static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
@@ -42,10 +82,49 @@ static int pm8916_reboot_mode_write(struct reboot_mode_driver *reboot,
 	return ret;
 }
 
+/*
+ * This function stores the PMIC warm reset reason register values. It also
+ * clears these registers if the qcom,clear-warm-reset device tree property
+ * is specified.
+ */
+static int pm8916_pon_store_and_clear_warm_reset(struct pm8916_pon *pon)
+{
+	int rc;
+
+	rc = regmap_read(pon->regmap,
+			 pon->baseaddr + PON_WARM_RESET_REASON1,
+			 &pon->warm_reset_reason1);
+	if (rc) {
+		dev_err(pon->dev,
+			"Unable to read addr=%x, rc(%d)\n",
+			PON_WARM_RESET_REASON1, rc);
+		return rc;
+	}
+
+	rc = regmap_read(pon->regmap,
+			 pon->baseaddr + PON_WARM_RESET_REASON2,
+			 &pon->warm_reset_reason2);
+	if (rc) {
+		dev_err(pon->dev,
+			"Unable to read addr=%x, rc(%d)\n",
+			PON_WARM_RESET_REASON2, rc);
+		return rc;
+	}
+
+	/* keeps the register in good state */
+	regmap_update_bits(pon->regmap,
+			   pon->baseaddr + PON_WARM_RESET_REASON1,
+			   ~0, 0);
+	return 0;
+}
+
 static int pm8916_pon_probe(struct platform_device *pdev)
 {
 	struct pm8916_pon *pon;
-	int error;
+	int error, index;
+	unsigned int val, cold_boot;
+	u16 poff_sts = 0;
+	u8 buf[2];
 
 	pon = devm_kzalloc(&pdev->dev, sizeof(*pon), GFP_KERNEL);
 	if (!pon)
@@ -75,6 +154,49 @@ static int pm8916_pon_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pon);
 
+	error = pm8916_pon_store_and_clear_warm_reset(pon);
+	if (error)
+		dev_err(pon->dev,
+			"Unable to store/clear WARM_RESET_REASONx registers\n");
+
+	/* PON reason */
+	error = regmap_read(pon->regmap, pon->baseaddr + PON_REASON1, &val);
+	if (error < 0)
+		dev_err(pon->dev, "read power on reason register failed\n");
+
+	index = ffs(val) - 1;
+	cold_boot = !(pon->warm_reset_reason1
+		      || (pon->warm_reset_reason2 & PON_WARM_RESET_TFT));
+	if (index >= ARRAY_SIZE(pm8916_pon_reason) || index < 0) {
+		dev_info(pon->dev,
+			 "PMIC Power-on reason: Unknown and '%s' boot\n",
+			 cold_boot ? "cold" : "warm");
+	} else {
+		pon->pon_trigger_reason = index;
+		dev_info(pon->dev,
+			 "PMIC Power-on reason: %s and '%s' boot\n",
+			 pm8916_pon_reason[index],
+			 cold_boot ? "cold" : "warm");
+	}
+
+	/* POFF reason */
+	error = regmap_bulk_read(pon->regmap,
+				 pon->baseaddr + POFF_REASON1,
+				 &buf[0], 2);
+	if (error) {
+		dev_err(pon->dev, "Unable to read POFF_RESASON regs\n");
+		return error;
+	}
+	poff_sts = buf[0] | (buf[1] << 8);
+	index = ffs(poff_sts) - 1;
+	if (index >= ARRAY_SIZE(pm8916_poff_reason) || index < 0) {
+		dev_info(pon->dev, "PMIC: Unknown power-off reason\n");
+	} else {
+		pon->pon_power_off_reason = index;
+		dev_info(pon->dev, "PMIC: Power-off reason: %s\n",
+			 pm8916_poff_reason[index]);
+	}
+
 	return devm_of_platform_populate(&pdev->dev);
 }
 
-- 
2.25.1




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux