From 180829aed8ae8d903baf5314687ec74a635f020a Mon Sep 17 00:00:00 2001
From: "choongryeol.lee" <choongryeol.lee@lge.com>
Date: Thu, 27 Feb 2014 10:10:43 -0800
Subject: [PATCH] power: max17050: check version of custom parameters

To update custom parameters without fuel gauge's
POR(Power on reset), define and store the version
of custom parameters to the unused register, 0x20
register. MAXIM confirmed the 0x20 register can be
used for this purpose. By checking this version,
driver can detect the change of the parameters and
update them without POR.

For use of userspace, add sysfs entries which pass the
status of init done and power on reset.

Change-Id: I0ee008d75f722d44449c85fe1a18b550ceed7126
Signed-off-by: choongryeol.lee <choongryeol.lee@lge.com>
---
 drivers/power/max17050_battery.c       | 70 +++++++++++++++++++++++++-
 include/linux/power/max17050_battery.h |  3 +-
 2 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/drivers/power/max17050_battery.c b/drivers/power/max17050_battery.c
index f965aaa10918..f79bdb55ae0c 100644
--- a/drivers/power/max17050_battery.c
+++ b/drivers/power/max17050_battery.c
@@ -59,6 +59,7 @@ struct max17050_learned_params {
 	u16 qrtable20;
 	u16 qrtable30;
 	u16 cycles;
+	u16 param_version;
 };
 
 struct max17050_chip {
@@ -74,6 +75,8 @@ struct max17050_chip {
 	bool suspended;
 	bool use_ext_temp;
 	int ext_temp;
+	bool init_done;
+	bool power_on_reset;
 
 	/* values read from chip */
 	u16 status;
@@ -279,9 +282,18 @@ static void max17050_init_chip(struct max17050_chip *chip)
 
 	/* Complete initialisation */
 	chip->status = max17050_read_reg(client, MAX17050_STATUS);
+
 	max17050_write_verify_reg(client, MAX17050_STATUS,
 		chip->status & ~(STATUS_POR_BIT | STATUS_BR_BIT |
 							STATUS_BI_BIT));
+
+	/* Write custom parameter version */
+	max17050_write_verify_reg(client, MAX17050_CUSTOMVER,
+					chip->pdata->param_version);
+
+	/* Set the parameter init status */
+	if (chip->status & (STATUS_POR_BIT | STATUS_BI_BIT))
+		chip->power_on_reset = true;
 }
 
 /* Must call with mutex locked */
@@ -309,6 +321,8 @@ static void max17050_save_learned_params(struct max17050_chip *chip)
 							MAX17050_QRTABLE20);
 	chip->learned.qrtable30 = max17050_read_reg(client,
 							MAX17050_QRTABLE30);
+	chip->learned.param_version = max17050_read_reg(client,
+							MAX17050_CUSTOMVER);
 }
 
 /* Must call with mutex locked */
@@ -317,6 +331,11 @@ static void max17050_restore_learned_params(struct max17050_chip *chip)
 	struct i2c_client *client = chip->client;
 	u16 remcap;
 
+	/* Skip restore when custom param version has changed */
+	if (chip->learned.param_version !=
+			max17050_read_reg(client, MAX17050_CUSTOMVER))
+		return;
+
 	max17050_write_verify_reg(client, MAX17050_RCOMP0,
 						chip->learned.rcomp0);
 	max17050_write_verify_reg(client, MAX17050_TEMPCO,
@@ -409,6 +428,28 @@ static struct bin_attribute max17050_learned_attr = {
 	.write = max17050_learned_write,
 };
 
+static ssize_t max17050_show_init_done(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct max17050_chip *chip = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->init_done);
+}
+static DEVICE_ATTR(init_done, S_IRUGO,
+			max17050_show_init_done, NULL);
+
+static ssize_t max17050_show_power_on_reset(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct max17050_chip *chip = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", chip->power_on_reset);
+}
+static DEVICE_ATTR(power_on_reset, S_IRUGO,
+			max17050_show_power_on_reset, NULL);
+
 static void max17050_update_ext_temp(struct work_struct *work)
 {
 	struct max17050_chip *chip =
@@ -603,6 +644,12 @@ static void max17050_complete_init(struct max17050_chip *chip)
 	if (sysfs_create_bin_file(&client->dev.kobj, &max17050_learned_attr))
 		dev_err(&client->dev, "sysfs_create_bin_file failed");
 
+	if (device_create_file(&client->dev, &dev_attr_init_done))
+		dev_err(&client->dev, "device_create_file failed");
+
+	if (device_create_file(&client->dev, &dev_attr_power_on_reset))
+		dev_err(&client->dev, "device_create_file failed");
+
 	if (power_supply_register(&client->dev, &chip->battery))
 		dev_err(&client->dev, "failed: power supply register");
 	else
@@ -623,6 +670,8 @@ static void max17050_complete_init(struct max17050_chip *chip)
 
 	if (chip->use_ext_temp && chip->pdata->ext_batt_psy)
 		schedule_delayed_work(&chip->ext_batt_work, 0);
+
+	chip->init_done = true;
 }
 
 static void max17050_init_worker(struct work_struct *work)
@@ -714,6 +763,9 @@ max17050_get_pdata(struct device *dev)
 	else
 		pdata->full_soc = 100;
 
+	if (of_property_read_u32(np, "maxim,param-version", &prop) == 0)
+		pdata->param_version = prop;
+
 	model = of_get_property(np, "maxim,model", &len);
 	if (model && ((len / 2) == MODEL_SIZE)) {
 		int i;
@@ -733,6 +785,7 @@ static int max17050_probe(struct i2c_client *client,
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct max17050_chip *chip;
 	int ret = 0;
+	bool new_custom_param = false;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
@@ -796,8 +849,19 @@ static int max17050_probe(struct i2c_client *client,
 	INIT_WORK(&chip->work, max17050_init_worker);
 	mutex_init(&chip->mutex);
 
-	if (max17050_read_reg(client, MAX17050_STATUS) &
-					(STATUS_POR_BIT | STATUS_BI_BIT))
+	/*
+	 * If the version of custom parameters is changed, the init chip
+	 * should be called even if POR doesn't happen.
+	 * For checking parameter change, the reserved register, 0x20,
+	 * is defined as custom version register.
+	 */
+	if (max17050_read_reg(client, MAX17050_CUSTOMVER) !=
+					chip->pdata->param_version)
+		new_custom_param = true;
+
+	if ((max17050_read_reg(client, MAX17050_STATUS) &
+				(STATUS_POR_BIT | STATUS_BI_BIT)) ||
+							new_custom_param)
 		schedule_work(&chip->work);
 	else
 		max17050_complete_init(chip);
@@ -809,6 +873,8 @@ static int max17050_remove(struct i2c_client *client)
 {
 	struct max17050_chip *chip = i2c_get_clientdata(client);
 
+	device_remove_file(&client->dev, &dev_attr_power_on_reset);
+	device_remove_file(&client->dev, &dev_attr_init_done);
 	sysfs_remove_bin_file(&client->dev.kobj, &max17050_learned_attr);
 
 	if (client->irq)
diff --git a/include/linux/power/max17050_battery.h b/include/linux/power/max17050_battery.h
index 3f2ea7854e57..698d869c1160 100644
--- a/include/linux/power/max17050_battery.h
+++ b/include/linux/power/max17050_battery.h
@@ -63,7 +63,7 @@ enum max17050_register {
 	MAX17050_CONFIG		= 0X1D,
 	MAX17050_ICHGTERM	= 0X1E,
 	MAX17050_AVCAP		= 0X1F,
-
+	MAX17050_CUSTOMVER	= 0X20,
 	MAX17050_VERSION	= 0X21,
 	MAX17050_QRTABLE10	= 0X22,
 	MAX17050_FULLCAPNOM	= 0X23,
@@ -152,6 +152,7 @@ struct max17050_platform_data {
 
 	u16 temperature;
 	u16 dpacc;
+	u16 param_version;
 
 	/* model characterisation data */
 	u16 model[MODEL_SIZE];
-- 
GitLab