msm: wcnss: Dump PMIC regulator contol registers

Dump PMIC registers which are related to WCNSS(RIVA)during the
WCNSS SSR or WDI timeout.  This  information helps to check PMIC
status during the SSR. This allows to debug multiple crash issues,
where WCNSS SSR dumps are insufficient to conclude why FIQ is not
reaching the WCNSS from HOST and why SPM is stuck.

Change-Id: Ibcd767c8832e2df268591e03da93ccf1bd819c68
CRs-fixed: 487483
Signed-off-by: Naresh Jayaram <njayar@codeaurora.org>
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index b302866..380d46e 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -50,6 +50,8 @@
 
 	pr_err("%s: smsm state changed\n", MODULE_NAME);
 
+	wcnss_riva_dump_pmic_regs();
+
 	if (!(new_state & SMSM_RESET))
 		return;
 
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 2babf20..dcab01d 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -28,6 +28,7 @@
 #include <mach/peripheral-loader.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
+#include <linux/mfd/pm8xxx/misc.h>
 
 #define DEVICE "wcnss_wlan"
 #define VERSION "1.01"
@@ -83,6 +84,21 @@
 	unsigned char  revision;
 };
 
+struct wcnss_pmic_dump {
+	char reg_name[10];
+	u16 reg_addr;
+};
+
+static struct wcnss_pmic_dump wcnss_pmic_reg_dump[] = {
+	{"S2", 0x1D8}, /* S2 */
+	{"L4", 0xB4},  /* L4 */
+	{"L10", 0xC0},  /* L10 */
+	{"LVS2", 0x62},   /* LVS2 */
+	{"S4", 0x1E8}, /*S4*/
+	{"LVS7", 0x06C}, /*LVS7*/
+	{"LVS1", 0x060}, /*LVS7*/
+};
+
 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
 
 /*
@@ -228,6 +244,7 @@
 static DEVICE_ATTR(wcnss_version, S_IRUSR,
 		wcnss_version_show, NULL);
 
+
 /* wcnss_reset_intr() is invoked when host drivers fails to
  * communicate with WCNSS over SMD; so logging these registers
  * helps to know WCNSS failure reason */
@@ -262,10 +279,29 @@
 	iounmap(ccu_base);
 }
 
+void wcnss_riva_dump_pmic_regs(void)
+{
+	int i, rc;
+	u8  val;
+
+	for (i = 0; i < ARRAY_SIZE(wcnss_pmic_reg_dump); i++) {
+		val = 0;
+		rc = pm8xxx_read_register(wcnss_pmic_reg_dump[i].reg_addr,
+				&val);
+		if (rc)
+			pr_err("PMIC READ: Failed to read addr = %d\n",
+					wcnss_pmic_reg_dump[i].reg_addr);
+		else
+			pr_err("PMIC READ: addr = %x, value = %x\n",
+					wcnss_pmic_reg_dump[i].reg_addr, val);
+	}
+}
+
 /* interface to reset Riva by sending the reset interrupt */
 void wcnss_reset_intr(void)
 {
 	wcnss_log_ccpu_regs();
+	wcnss_riva_dump_pmic_regs();
 	wmb();
 	__raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
 }
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index eaf7ed3..f23eae7 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -54,6 +54,7 @@
 void wcnss_ssr_boot_notify(void);
 void wcnss_reset_intr(void);
 int wcnss_cold_boot_done(void);
+void wcnss_riva_dump_pmic_regs(void);
 
 #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
 #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))