From 2cd11e48cd218886f7f7408da4ba3f22aafe31df Mon Sep 17 00:00:00 2001
From: handsomeyingyan <handsomeyingyan@github.com>
Date: Sun, 2 May 2021 10:14:12 +0800
Subject: [PATCH 77/78] ower: supply: smb1360: add option to dump all  smb1360
 registers

---
 drivers/power/supply/Kconfig          |   4 +
 drivers/power/supply/Makefile         |   2 +
 drivers/power/supply/smb1360-driver.c |   1 +
 drivers/power/supply/smb1360-dump.c   | 298 ++++++++++++++++++++++++++
 drivers/power/supply/smb1360.c        |  40 ++++
 5 files changed, 345 insertions(+)
 create mode 120000 drivers/power/supply/smb1360-driver.c
 create mode 100644 drivers/power/supply/smb1360-dump.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 560ddc083..fd8d9879b 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -801,4 +801,8 @@ config RN5T618_POWER
 	  This driver can also be built as a module. If so, the module will be
 	  called rn5t618_power.
 
+config SMB1360_DEBUG
+	bool "Dump SMB1360 registers before/after driver initialization"
+	depends on SMB1360
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index ac920ca91..e58498732 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -78,6 +78,8 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_MP2629)	+= mp2629_charger.o
 obj-$(CONFIG_CHARGER_QCOM_SMBB)	+= qcom_smbb.o
+smb1360-y			:= smb1360-driver.o
+smb1360-$(CONFIG_SMB1360_DEBUG)	+= smb1360-dump.o
 obj-$(CONFIG_SMB1360)		+= smb1360.o
 obj-$(CONFIG_BATTERY_PM8916_BMS_VM)	+= pm8916_bms_vm.o
 obj-$(CONFIG_CHARGER_PM8916_LBC)	+= pm8916_lbc.o
diff --git a/drivers/power/supply/smb1360-driver.c b/drivers/power/supply/smb1360-driver.c
new file mode 120000
index 000000000..577704623
--- /dev/null
+++ b/drivers/power/supply/smb1360-driver.c
@@ -0,0 +1 @@
+smb1360.c
\ No newline at end of file
diff --git a/drivers/power/supply/smb1360-dump.c b/drivers/power/supply/smb1360-dump.c
new file mode 100644
index 000000000..a0b72b7d2
--- /dev/null
+++ b/drivers/power/supply/smb1360-dump.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#define pr_fmt(fmt) "smb1360-dump: " fmt
+
+#include <linux/i2c.h>
+
+enum smb1360_reg_type {
+	LITTLE_ENDIAN,
+	BIG_ENDIAN,
+	RAW
+};
+
+struct smb1360_reg {
+	u8 addr;
+	const char *name;
+	u8 size;
+	enum smb1360_reg_type type;
+};
+
+struct smb1360_regset {
+	const char *name;
+	u8 start, end;
+	struct smb1360_reg regs[];
+};
+
+static const struct smb1360_regset smb1360_cfg = {
+	.name	= "configuration",
+	.start	= 0x00,
+	.end	= 0x1C,
+	.regs	= {
+		{ 0x00, "CFG_BATT_CHG_REG", 1 },
+		{ 0x05, "CFG_BATT_CHG_ICL_REG", 1 },
+		{ 0x06, "CFG_GLITCH_FLT_REG", 1 },
+		{ 0x07, "CFG_CHG_MISC_REG", 1 },
+		{ 0x08, "CFG_CHG_FUNC_CTRL_REG", 1 },
+		{ 0x09, "CFG_STAT_CTRL_REG", 1 },
+		{ 0x0A, "CFG_SFY_TIMER_CTRL_REG", 1 },
+		{ 0x0D, "CFG_BATT_MISSING_REG", 1 },
+		{ 0x0E, "CFG_FG_BATT_CTRL_REG", 1 },
+		{ 0x0F, "IRQ_CFG_REG", 1 },
+		{ 0x10, "IRQ2_CFG_REG", 1 },
+		{ 0x11, "IRQ3_CFG_REG", 1 },
+		{ 0x12, "PRE_TO_FAST_REG", 1 },
+		{ 0x13, "CHG_CURRENT_REG", 1 },
+		{ 0x14, "CHG_CMP_CFG", 1 },
+		{ 0x15, "BATT_CHG_FLT_VTG_REG", 1 },
+		{ 0x16, "CFG_FVC_REG", 1 },
+		{ 0x1A, "SHDN_CTRL_REG", 1 },
+		{ 0x1C, "TRIM_1C_REG", 1 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_fg_cfg = {
+	.name	= "fg configuration",
+	.start	= 0x20,
+	.end	= 0x2F,
+	.regs	= {
+		{ 0x20, "SHDW_FG_ESR_ACTUAL", 2 },
+		{ 0x24, "SOC_MAX_REG", 1 },
+		{ 0x25, "SOC_MIN_REG", 1 },
+		{ 0x26, "VTG_EMPTY_REG", 1 },
+		{ 0x27, "Temp_external", 1 },
+		{ 0x28, "SOC_DELTA_REG", 1 },
+		{ 0x29, "JEITA_SOFT_COLD_REG", 1 },
+		{ 0x2A, "JEITA_SOFT_HOT_REG", 1 },
+		{ 0x2B, "VTG_MIN_REG", 1 },
+		{ 0x2E, "ESR_sys_replace", 2 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_cmd = {
+	.name	= "command",
+	.start	= 0x40,
+	.end	= 0x42,
+	.regs	= {
+		{ 0x40, "CMD_I2C_REG", 1 },
+		{ 0x41, "CMD_IL_REG", 1 },
+		{ 0x42, "CMD_CHG_REG", 1 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_status = {
+	.name	= "status",
+	.start	= 0x48,
+	.end	= 0x4F,
+	.regs	= {
+		{ 0x48, "STATUS_1_REG", 1 },
+		{ 0x4B, "STATUS_3_REG", 1 },
+		{ 0x4C, "STATUS_4_REG", 1 },
+		{ 0x4F, "REVISION_CTRL_REG", 1 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_irq_status = {
+	.name	= "irq status",
+	.start	= 0x50,
+	.end	= 0x58,
+	.regs	= {
+		{ 0x50, "IRQ_A_REG", 1 },
+		{ 0x51, "IRQ_B_REG", 1 },
+		{ 0x52, "IRQ_C_REG", 1 },
+		{ 0x53, "IRQ_D_REG", 1 },
+		{ 0x54, "IRQ_E_REG", 1 },
+		{ 0x55, "IRQ_F_REG", 1 },
+		{ 0x56, "IRQ_G_REG", 1 },
+		{ 0x57, "IRQ_H_REG", 1 },
+		{ 0x58, "IRQ_I_REG", 1 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_fg_shdw = {
+	.name	= "fg shadow",
+	.start	= 0x60,
+	.end	= 0x6F,
+	.regs	= {
+		{ 0x60, "SHDW_FG_BATT_STATUS", 1 },
+		{ 0x61, "SHDW_FG_MSYS_SOC", 1 },
+		{ 0x62, "SHDW_FG_CAPACITY", 2 },
+		{ 0x64, "Rslow_drop", 2 },
+		{ 0x66, "Latest_SOC", 1 },
+		{ 0x67, "Latest_Cutoff_SOC", 1 },
+		{ 0x68, "Latest_full_SOC", 1 },
+		{ 0x69, "SHDW_FG_VTG_NOW", 2 },
+		{ 0x6B, "SHDW_FG_CURR_NOW", 2 },
+		{ 0x6D, "SHDW_FG_BATT_TEMP", 2 },
+		{ 0x6F, "Latest_system_sbits", 1 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_fg_scratch = {
+	.name	= "fg scratch pad",
+	.start	= 0x80,
+	.end	= 0xDC,
+	.regs	= {
+		{ 0x80, "VOLTAGE_PREDICTED_REG", 2 },
+		{ 0x82, "v_cutoff_predicted", 2 },
+		{ 0x84, "v_full_predicted", 2 },
+		{ 0x86, "ocv_estimate", 2 },
+		{ 0x88, "rslow_drop", 2 },
+		{ 0x8A, "voltage_old", 2 },
+		{ 0x8C, "current_old", 2 },
+		{ 0x8E, "current_average_full", 4 },
+		{ 0x92, "temperature", 2 },
+		{ 0x94, "temp_last_track", 2 },
+		{ 0x96, "ESR_nominal", 2 },
+		{ 0x9A, "Rslow", 2 },
+		{ 0x9C, "counter_imptr", 2 },
+		{ 0x9E, "counter_pulse", 2 },
+		{ 0xA0, "IRQ_delta_prev", 1 },
+		{ 0xA1, "cap_learning_counter", 1 },
+		{ 0xA2, "Vact_int_error", 4 },
+		{ 0xA6, "SOC_cutoff", 3 },
+		{ 0xA9, "SOC_full", 3 },
+		{ 0xAC, "SOC_auto_rechrge_temp", 3 },
+		{ 0xAF, "Battery_SOC", 3 },
+		{ 0xB2, "CC_SOC", 4 },
+		{ 0xB6, "SOC_filtered", 2 },
+		{ 0xB8, "SOC_Monotonic", 2 },
+		{ 0xBA, "CC_TO_SOC_COEFF", 2 },
+		{ 0xBC, "NOMINAL_CAPACITY_REG", 2 },
+		{ 0xBE, "ACTUAL_CAPACITY_REG", 2 },
+		{ 0xC4, "temperature_counter", 1 },
+		{ 0xC5, "Vbatt_filtered", 3 },
+		{ 0xC8, "Ibatt_filtered", 3 },
+		{ 0xCB, "Current_CC_shadow", 2 },
+		{ 0xCF, "FG_IBATT_STANDBY_REG", 2 },
+		{ 0xD2, "FG_AUTO_RECHARGE_SOC", 1 },
+		{ 0xD3, "FG_SYS_CUTOFF_V_REG", 2 },
+		{ 0xD5, "FG_CC_TO_CV_V_REG", 2 },
+		{ 0xD7, "System_term_current", 2 },
+		{ 0xD9, "System_fake_term_current", 2 },
+		{ 0xDB, "FG_THERM_C1_COEFF_REG", 2 },
+		{ }
+	}
+};
+
+/* Note: Only very few OTP registers are known, there may be many more! */
+static const struct smb1360_regset smb1360_fg_otp = {
+	.name	= "fg otp",
+	.start	= 0x12,
+	.end	= 0x1E,
+	.regs	= {
+		{ 0x12, "JEITA_HARD_COLD_REG", 1 },
+		{ 0x13, "JEITA_HARD_HOT_REG", 1 },
+		{ 0x1D, "CURRENT_GAIN_REG", 2 },
+		{ }
+	}
+};
+
+static const struct smb1360_regset smb1360_fg_otp_backup = {
+	.name	= "fg otp backup",
+	.start	= 0xE0,
+	.end	= 0xF1,
+	.regs	= {
+		{ 0xE0, "OTP_BACKUP_REG", 16, RAW },
+		{ 0xF0, "OTP_BACKUP_WA_ALG", 2, BIG_ENDIAN },
+		{ }
+	}
+};
+
+static void smb1360_reg_dump(const struct smb1360_reg *reg, const u8 val[])
+{
+	u32 num = 0;
+	int i;
+
+	switch (reg->type) {
+	case RAW:
+		pr_info("\t<%#x> %s %*ph\n", reg->addr, reg->name, reg->size, val);
+		return;
+	case LITTLE_ENDIAN:
+		for (i = 0; i < reg->size; ++i) {
+			num |= val[i] << (8 * i);
+		}
+		break;
+	case BIG_ENDIAN:
+		for (i = 0; i < reg->size; ++i) {
+			num <<= 8;
+			num |= val[i];
+		}
+		break;
+	}
+
+	pr_info("\t<%#x> %s %0*x\n", reg->addr, reg->name, 2 * reg->size, num);
+}
+
+static void smb1360_regset_dump(struct i2c_client *client, const struct smb1360_regset *set)
+{
+	const struct smb1360_reg *reg = set->regs;
+	u8 val[U8_MAX];
+	u8 r, next;
+	int ret;
+
+	pr_info("%s:\n", set->name);
+
+	for (r = set->start; r <= set->end; r += ret) {
+		u8 len = set->end - r + 1;
+		int i = r - set->start;
+
+		ret = i2c_smbus_read_i2c_block_data(client, r, len, &val[i]);
+		pr_info("\tread %s at %#x len %d, ret %d\n", set->name, r, len, ret);
+		if (ret < 0) {
+			pr_err("\tFailed to read %d %s registers at %#x: %d\n",
+			       len, set->name, r, ret);
+			return;
+		}
+	}
+
+	for (r = set->start; r <= set->end;) {
+		int i = r - set->start;
+
+		if (reg->name) {
+			if (r == reg->addr) {
+				smb1360_reg_dump(reg, &val[i]);
+				r += reg->size;
+				++reg;
+				continue;
+			}
+
+			/* Dump until next documented reg */
+			next = reg->addr;
+		} else {
+			/* No more documented regs, dump remaining regs */
+			next = set->end + 1;
+		}
+
+		pr_info("\t<%#x> %*ph\n", r, next - r, &val[i]);
+		r = next;
+	}
+}
+
+void smb1360_dump(struct i2c_client *client)
+{
+	smb1360_regset_dump(client, &smb1360_cfg);
+	smb1360_regset_dump(client, &smb1360_fg_cfg);
+	smb1360_regset_dump(client, &smb1360_cmd);
+	smb1360_regset_dump(client, &smb1360_status);
+	smb1360_regset_dump(client, &smb1360_irq_status);
+	smb1360_regset_dump(client, &smb1360_fg_shdw);
+}
+
+/* Should be called with smb1360_enable_fg_access() */
+void smb1360_dump_fg_scratch(struct i2c_client *client)
+{
+	smb1360_regset_dump(client, &smb1360_fg_scratch);
+}
+
+/* Should be called with smb1360_enable_fg_access() and FG I2C client */
+void smb1360_dump_fg(struct i2c_client *fg_client)
+{
+	smb1360_regset_dump(fg_client, &smb1360_fg_otp);
+	smb1360_regset_dump(fg_client, &smb1360_fg_otp_backup);
+	pr_info("\n");
+}
diff --git a/drivers/power/supply/smb1360.c b/drivers/power/supply/smb1360.c
index ca83f6db6..682f932b1 100644
--- a/drivers/power/supply/smb1360.c
+++ b/drivers/power/supply/smb1360.c
@@ -12,6 +12,10 @@
  *    - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT
  */
 
+#ifdef CONFIG_SMB1360_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/completion.h>
 #include <linux/extcon-provider.h>
 #include <linux/i2c.h>
@@ -1089,10 +1093,39 @@ static int smb1360_check_cycle_stretch(struct smb1360 *smb)
 	return ret;
 }
 
+#ifdef CONFIG_SMB1360_DEBUG
+extern void smb1360_dump(struct i2c_client *client);
+extern void smb1360_dump_fg_scratch(struct i2c_client *fg_client);
+extern void smb1360_dump_fg(struct i2c_client *client);
+
+static void smb1360_dump_fg_access(struct smb1360 *smb)
+{
+	struct i2c_client *client = to_i2c_client(smb->dev);
+	struct i2c_client *fg_client = to_i2c_client(regmap_get_device(smb->fg_regmap));
+	int ret;
+
+	ret = smb1360_enable_fg_access(smb);
+	if (ret)
+		return;
+
+	smb1360_dump_fg_scratch(client);
+	smb1360_dump_fg(fg_client);
+
+	smb1360_disable_fg_access(smb);
+	smb1360_check_cycle_stretch(smb);
+}
+#else
+static inline void smb1360_dump(struct i2c_client *client) {}
+static inline void smb1360_dump_fg_access(struct smb1360 *smb) {}
+#endif
+
 static int smb1360_delayed_hw_init(struct smb1360 *smb)
 {
 	int ret;
 
+	/* Dump initial FG registers */
+	smb1360_dump_fg_access(smb);
+
 	ret = smb1360_check_batt_profile(smb);
 	if (ret) {
 		dev_err(smb->dev, "unable to modify battery profile: %d\n", ret);
@@ -1133,6 +1166,10 @@ static int smb1360_delayed_hw_init(struct smb1360 *smb)
 		return ret;
 	}
 
+	/* Dump final registers */
+	smb1360_dump(to_i2c_client(smb->dev));
+	smb1360_dump_fg_access(smb);
+
 	return 0;
 }
 
@@ -1599,6 +1636,9 @@ static int smb1360_probe(struct i2c_client *client)
 	device_init_wakeup(smb->dev, 1);
 	i2c_set_clientdata(client, smb);
 
+	/* Dump initial registers */
+	smb1360_dump(client);
+
 	ret = smb1360_hw_init(client);
 	if (ret < 0) {
 		dev_err(&client->dev, "unable to initialize hw: %d\n", ret);
-- 
2.31.1

