public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] MAX17042 add support for maxim POR procedure
@ 2011-11-28 19:49 dirk.brandewie
  2011-11-28 19:49 ` [PATCH 1/4] max17042: Move power suppply registration to a worker thread dirk.brandewie
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: dirk.brandewie @ 2011-11-28 19:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham, alan, Dirk Brandewie

From: Dirk Brandewie <dirk.brandewie@gmail.com>

This patch set adds support for the power on reset procedure for the
max17042 battery fuel gauge.  The accuracy of the fuel gauge is
improved by configuring the fuel gauge with the characterization data
for the battery present in the platform.



Dirk Brandewie (4):
  max17042: Move power suppply registration to a worker thread
  max17042: Align register definitions with data sheet and init appnote
  max17042: Add POR init procedure from Maxim appnote
  x86-mrst: Add battery fuel guage platform data

 arch/x86/platform/mrst/mrst.c          |   46 ++++
 drivers/power/max17042_battery.c       |  401 ++++++++++++++++++++++++++++++--
 include/linux/power/max17042_battery.h |   93 +++++++-
 3 files changed, 510 insertions(+), 30 deletions(-)

-- 
1.7.7.3


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] max17042: Move power suppply registration to a worker thread
  2011-11-28 19:49 [PATCH 0/4] MAX17042 add support for maxim POR procedure dirk.brandewie
@ 2011-11-28 19:49 ` dirk.brandewie
  2011-11-28 19:49 ` [PATCH 2/4] max17042: Align register definitions with data sheet and init appnote dirk.brandewie
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: dirk.brandewie @ 2011-11-28 19:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham, alan, Dirk Brandewie

From: Dirk Brandewie <dirk.brandewie@gmail.com>

This patch move the final registration of the battery to a worker
thread in preperation for adding the POR proceedure recommended by
maxim. This is needed since the Maxim init proceedure requires two
long delays totaling 850ms. This patch will reduce the impact on
system boot time.  The battery will not be available to the power
supply subsystem until the init proceedure is complete

Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
---
 drivers/power/max17042_battery.c |   53 +++++++++++++++++++++++---------------
 1 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 9f0183c..33fdce0 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -34,6 +34,7 @@ struct max17042_chip {
 	struct i2c_client *client;
 	struct power_supply battery;
 	struct max17042_platform_data *pdata;
+	struct work_struct work;
 };
 
 static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
@@ -180,12 +181,40 @@ static int max17042_get_property(struct power_supply *psy,
 	return 0;
 }
 
+static void max17042_init_worker(struct work_struct *work)
+{
+	struct max17042_chip *chip = container_of(work,
+				struct max17042_chip, work);
+	struct i2c_client *client = chip->client;
+	int ret;
+
+
+	/* Initialize registers according to values from the platform data */
+	if (chip->pdata->init_data)
+		max17042_set_reg(client, chip->pdata->init_data,
+				 chip->pdata->num_init_data);
+
+	if (!chip->pdata->enable_current_sense) {
+		max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
+		max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
+		max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+	} else {
+		if (chip->pdata->r_sns == 0)
+			chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
+	}
+
+	ret = power_supply_register(&client->dev, &chip->battery);
+	if (ret) {
+		dev_err(&client->dev, "failed: power supply register\n");
+		kfree(chip);
+	}
+}
+
 static int __devinit max17042_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct max17042_chip *chip;
-	int ret;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
 		return -EIO;
@@ -210,26 +239,8 @@ static int __devinit max17042_probe(struct i2c_client *client,
 	if (!chip->pdata->enable_current_sense)
 		chip->battery.num_properties -= 2;
 
-	ret = power_supply_register(&client->dev, &chip->battery);
-	if (ret) {
-		dev_err(&client->dev, "failed: power supply register\n");
-		kfree(chip);
-		return ret;
-	}
-
-	/* Initialize registers according to values from the platform data */
-	if (chip->pdata->init_data)
-		max17042_set_reg(client, chip->pdata->init_data,
-				 chip->pdata->num_init_data);
-
-	if (!chip->pdata->enable_current_sense) {
-		max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
-		max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
-		max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
-	} else {
-		if (chip->pdata->r_sns == 0)
-			chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
-	}
+	INIT_WORK(&chip->work, max17042_init_worker);
+	schedule_work(&chip->work);
 
 	return 0;
 }
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] max17042: Align register definitions with data sheet and init appnote
  2011-11-28 19:49 [PATCH 0/4] MAX17042 add support for maxim POR procedure dirk.brandewie
  2011-11-28 19:49 ` [PATCH 1/4] max17042: Move power suppply registration to a worker thread dirk.brandewie
@ 2011-11-28 19:49 ` dirk.brandewie
  2011-11-28 19:49 ` [PATCH 3/4] max17042: Add POR init procedure from Maxim appnote dirk.brandewie
  2011-11-28 19:49 ` [PATCH 4/4] x86-mrst: Add battery fuel guage platform data dirk.brandewie
  3 siblings, 0 replies; 6+ messages in thread
From: dirk.brandewie @ 2011-11-28 19:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham, alan, Dirk Brandewie

From: Dirk Brandewie <dirk.brandewie@gmail.com>

align the register names with max17042 data sheet removing
registers that are marked reserved that are not used.

Add register definitions defined in the maxim initialization appnote

Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
---
 include/linux/power/max17042_battery.h |   37 ++++++++++++++++++++++++-------
 1 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index fe99211..67eeada 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -40,11 +40,11 @@ enum max17042_register {
 	MAX17042_VCELL		= 0x09,
 	MAX17042_Current	= 0x0A,
 	MAX17042_AvgCurrent	= 0x0B,
-	MAX17042_Qresidual	= 0x0C,
+
 	MAX17042_SOC		= 0x0D,
 	MAX17042_AvSOC		= 0x0E,
 	MAX17042_RemCap		= 0x0F,
-	MAX17402_FullCAP	= 0x10,
+	MAX17042_FullCAP	= 0x10,
 	MAX17042_TTE		= 0x11,
 	MAX17042_V_empty	= 0x12,
 
@@ -62,14 +62,14 @@ enum max17042_register {
 	MAX17042_AvCap		= 0x1F,
 	MAX17042_ManName	= 0x20,
 	MAX17042_DevName	= 0x21,
-	MAX17042_DevChem	= 0x22,
 
+	MAX17042_FullCAPNom	= 0x23,
 	MAX17042_TempNom	= 0x24,
-	MAX17042_TempCold	= 0x25,
+	MAX17042_TempLim	= 0x25,
 	MAX17042_TempHot	= 0x26,
 	MAX17042_AIN		= 0x27,
 	MAX17042_LearnCFG	= 0x28,
-	MAX17042_SHFTCFG	= 0x29,
+	MAX17042_FilterCFG	= 0x29,
 	MAX17042_RelaxCFG	= 0x2A,
 	MAX17042_MiscCFG	= 0x2B,
 	MAX17042_TGAIN		= 0x2C,
@@ -77,22 +77,41 @@ enum max17042_register {
 	MAX17042_CGAIN		= 0x2E,
 	MAX17042_COFF		= 0x2F,
 
-	MAX17042_Q_empty	= 0x33,
+	MAX17042_MaskSOC	= 0x32,
+	MAX17042_SOC_empty	= 0x33,
 	MAX17042_T_empty	= 0x34,
 
+	MAX17042_FullCAP0       = 0x35,
+	MAX17042_LAvg_empty	= 0x36,
+	MAX17042_FCTC		= 0x37,
 	MAX17042_RCOMP0		= 0x38,
 	MAX17042_TempCo		= 0x39,
-	MAX17042_Rx		= 0x3A,
-	MAX17042_T_empty0	= 0x3B,
+	MAX17042_EmptyTempCo	= 0x3A,
+	MAX17042_K_empty0	= 0x3B,
 	MAX17042_TaskPeriod	= 0x3C,
 	MAX17042_FSTAT		= 0x3D,
 
 	MAX17042_SHDNTIMER	= 0x3F,
 
-	MAX17042_VFRemCap	= 0x4A,
+	MAX17042_dQacc		= 0x45,
+	MAX17042_dPacc		= 0x46,
+
+	MAX17042_VFSOC0		= 0x48,
 
 	MAX17042_QH		= 0x4D,
 	MAX17042_QL		= 0x4E,
+
+	MAX17042_VFSOC0Enable	= 0x60,
+	MAX17042_MLOCKReg1	= 0x62,
+	MAX17042_MLOCKReg2	= 0x63,
+
+	MAX17042_MODELChrTbl	= 0x80,
+
+	MAX17042_OCV		= 0xEE,
+
+	MAX17042_OCVInternal	= 0xFB,
+
+	MAX17042_VFSOC		= 0xFF,
 };
 
 /*
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] max17042: Add POR init procedure from Maxim appnote
  2011-11-28 19:49 [PATCH 0/4] MAX17042 add support for maxim POR procedure dirk.brandewie
  2011-11-28 19:49 ` [PATCH 1/4] max17042: Move power suppply registration to a worker thread dirk.brandewie
  2011-11-28 19:49 ` [PATCH 2/4] max17042: Align register definitions with data sheet and init appnote dirk.brandewie
@ 2011-11-28 19:49 ` dirk.brandewie
  2011-11-28 19:49 ` [PATCH 4/4] x86-mrst: Add battery fuel guage platform data dirk.brandewie
  3 siblings, 0 replies; 6+ messages in thread
From: dirk.brandewie @ 2011-11-28 19:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham, alan, Dirk Brandewie

From: Dirk Brandewie <dirk.brandewie@gmail.com>

Add power on reset (POR) init procedure defined by the maxim
appnote. Using this procedure ensures that the part is
configured/initialized correctly at POR and improves early accuracy of
the fuel gauge and informs the fuel gauge with the battery
characterization parameters.  The battery characterization parameters
come from the maxim characterization procedure.
Summary:
---
 drivers/power/max17042_battery.c       |  348 ++++++++++++++++++++++++++++++++
 include/linux/power/max17042_battery.h |   56 +++++
 2 files changed, 404 insertions(+), 0 deletions(-)

diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 33fdce0..1eef5f9 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -26,10 +26,34 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
 #include <linux/mod_devicetable.h>
 #include <linux/power_supply.h>
 #include <linux/power/max17042_battery.h>
 
+/* Status register bits */
+#define STATUS_POR_BIT         (1 << 1)
+#define STATUS_BST_BIT         (1 << 3)
+#define STATUS_VMN_BIT         (1 << 8)
+#define STATUS_TMN_BIT         (1 << 9)
+#define STATUS_SMN_BIT         (1 << 10)
+#define STATUS_BI_BIT          (1 << 11)
+#define STATUS_VMX_BIT         (1 << 12)
+#define STATUS_TMX_BIT         (1 << 13)
+#define STATUS_SMX_BIT         (1 << 14)
+#define STATUS_BR_BIT          (1 << 15)
+
+#define VFSOC0_LOCK		0x0000
+#define VFSOC0_UNLOCK		0x0080
+#define MODEL_UNLOCK1	0X0059
+#define MODEL_UNLOCK2	0X00C4
+#define MODEL_LOCK1		0X0000
+#define MODEL_LOCK2		0X0000
+
+#define dQ_ACC_DIV	0x4
+#define dP_ACC_100	0x1900
+#define dP_ACC_200	0x3200
+
 struct max17042_chip {
 	struct i2c_client *client;
 	struct power_supply battery;
@@ -181,6 +205,324 @@ static int max17042_get_property(struct power_supply *psy,
 	return 0;
 }
 
+static int max17042_write_verify_reg(struct i2c_client *client,
+				u8 reg, u16 value)
+{
+	int retries = 8;
+	int ret;
+	u16 read_value;
+
+	do {
+		ret = i2c_smbus_write_word_data(client, reg, value);
+		read_value =  max17042_read_reg(client, reg);
+		if (read_value != value) {
+			ret = -EIO;
+			retries--;
+		}
+	} while (retries && read_value != value);
+
+	if (ret < 0)
+		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+	return ret;
+}
+
+static inline void max17042_override_por(
+	struct i2c_client *client, u8 reg, u16 value)
+{
+	if (value)
+		max17042_write_reg(client, reg, value);
+}
+
+static inline void max10742_unlock_model(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
+	max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
+}
+
+static inline void max10742_lock_model(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	max17042_write_reg(client, MAX17042_MLOCKReg1, MODEL_LOCK1);
+	max17042_write_reg(client, MAX17042_MLOCKReg2, MODEL_LOCK2);
+}
+
+static inline void max17042_write_model_data(struct max17042_chip *chip,
+					u8 addr, int size)
+{
+	struct i2c_client *client = chip->client;
+	int i;
+	for (i = 0; i < size; i++)
+		max17042_write_reg(client, addr + i,
+				chip->pdata->config_data->cell_char_tbl[i]);
+}
+
+static inline void max17042_read_model_data(struct max17042_chip *chip,
+					u8 addr, u16 *data, int size)
+{
+	struct i2c_client *client = chip->client;
+	int i;
+
+	for (i = 0; i < size; i++)
+		data[i] = max17042_read_reg(client, addr + i);
+}
+
+static inline int max17042_model_data_compare(struct max17042_chip *chip,
+					u16 *data1, u16 *data2, int size)
+{
+	int i;
+
+	if (memcmp(data1, data2, size)) {
+		dev_err(&chip->client->dev, "%s compare failed\n", __func__);
+		for (i = 0; i < size; i++)
+			dev_info(&chip->client->dev, "0x%x, 0x%x",
+				data1[i], data2[i]);
+		dev_info(&chip->client->dev, "\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int max17042_init_model(struct max17042_chip *chip)
+{
+	int ret;
+	int table_size =
+		sizeof(chip->pdata->config_data->cell_char_tbl)/sizeof(u16);
+	u16 *temp_data;
+
+	temp_data = kzalloc(table_size, GFP_KERNEL);
+	if (!temp_data)
+		return -ENOMEM;
+
+	max10742_unlock_model(chip);
+	max17042_write_model_data(chip, MAX17042_MODELChrTbl,
+				table_size);
+	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
+				table_size);
+
+	ret = max17042_model_data_compare(
+		chip,
+		chip->pdata->config_data->cell_char_tbl,
+		temp_data,
+		table_size);
+
+	max10742_lock_model(chip);
+	kfree(temp_data);
+
+	return ret;
+}
+
+static int max17042_verify_model_lock(struct max17042_chip *chip)
+{
+	int i;
+	int table_size =
+		sizeof(chip->pdata->config_data->cell_char_tbl)/sizeof(u16);
+	u16 *temp_data;
+
+	temp_data = kzalloc(table_size, GFP_KERNEL);
+	if (!temp_data)
+		return -ENOMEM;
+
+	max17042_read_model_data(chip, MAX17042_MODELChrTbl, temp_data,
+				table_size);
+	for (i = 0; i < table_size; i++)
+		if (temp_data[i])
+			return -EINVAL;
+	kfree(temp_data);
+	return 0;
+}
+
+static void max17042_write_config_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_reg(chip->client, MAX17042_CONFIG, config->config);
+	max17042_write_reg(chip->client, MAX17042_LearnCFG, config->learn_cfg);
+	max17042_write_reg(chip->client, MAX17042_FilterCFG,
+			config->filter_cfg);
+	max17042_write_reg(chip->client, MAX17042_RelaxCFG, config->relax_cfg);
+}
+
+static void  max17042_write_custom_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_verify_reg(chip->client, MAX17042_RCOMP0,
+				config->rcomp0);
+	max17042_write_verify_reg(chip->client, MAX17042_TempCo,
+				config->tcompc0);
+	max17042_write_reg(chip->client, MAX17042_EmptyTempCo,
+			config->empty_tempco);
+	max17042_write_verify_reg(chip->client, MAX17042_K_empty0,
+				config->kempty0);
+	max17042_write_verify_reg(chip->client, MAX17042_ICHGTerm,
+				config->ichgt_term);
+}
+
+static void max17042_update_capacity_regs(struct max17042_chip *chip)
+{
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAP,
+				config->fullcap);
+	max17042_write_reg(chip->client, MAX17042_DesignCap,
+			config->design_cap);
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
+				config->fullcapnom);
+}
+
+static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
+{
+	u16 vfSoc;
+
+	vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC);
+	max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_UNLOCK);
+	max17042_write_verify_reg(chip->client, MAX17042_VFSOC0, vfSoc);
+	max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
+}
+
+static void max17042_load_new_capacity_params(struct max17042_chip *chip)
+{
+	u16 full_cap0, rep_cap, dq_acc, vfSoc;
+	u32 rem_cap;
+
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	full_cap0 = max17042_read_reg(chip->client, MAX17042_FullCAP0);
+	vfSoc = max17042_read_reg(chip->client, MAX17042_VFSOC);
+
+	/* fg_vfSoc needs to shifted by 8 bits to get the
+	 * perc in 1% accuracy, to get the right rem_cap multiply
+	 * full_cap0, fg_vfSoc and devide by 100
+	 */
+	rem_cap = ((vfSoc >> 8) * full_cap0) / 100;
+	max17042_write_verify_reg(chip->client, MAX17042_RemCap, (u16)rem_cap);
+
+	rep_cap = (u16)rem_cap;
+	max17042_write_verify_reg(chip->client, MAX17042_RepCap, rep_cap);
+
+	/* Write dQ_acc to 200% of Capacity and dP_acc to 200% */
+	dq_acc = config->fullcap / dQ_ACC_DIV;
+	max17042_write_verify_reg(chip->client, MAX17042_dQacc, dq_acc);
+	max17042_write_verify_reg(chip->client, MAX17042_dPacc, dP_ACC_200);
+
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAP,
+			config->fullcap);
+	max17042_write_reg(chip->client, MAX17042_DesignCap,
+			config->design_cap);
+	max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
+			config->fullcapnom);
+}
+
+/*
+ * Block write all the override values coming from platform data.
+ * This function MUST be called before the POR initialization proceedure
+ * specified by maxim.
+ */
+static inline void max17042_override_por_values(struct max17042_chip *chip)
+{
+	struct i2c_client *client = chip->client;
+	struct max17042_config_data *config = chip->pdata->config_data;
+
+	max17042_override_por(client, MAX17042_TGAIN, config->tgain);
+	max17042_override_por(client, MAx17042_TOFF, config->toff);
+	max17042_override_por(client, MAX17042_CGAIN, config->cgain);
+	max17042_override_por(client, MAX17042_COFF, config->coff);
+
+	max17042_override_por(client, MAX17042_VALRT_Th, config->valrt_thresh);
+	max17042_override_por(client, MAX17042_TALRT_Th, config->talrt_thresh);
+	max17042_override_por(client, MAX17042_SALRT_Th,
+			config->soc_alrt_thresh);
+	max17042_override_por(client, MAX17042_CONFIG, config->config);
+	max17042_override_por(client, MAX17042_SHDNTIMER, config->shdntimer);
+
+	max17042_override_por(client, MAX17042_DesignCap, config->design_cap);
+	max17042_override_por(client, MAX17042_ICHGTerm, config->ichgt_term);
+
+	max17042_override_por(client, MAX17042_AtRate, config->at_rate);
+	max17042_override_por(client, MAX17042_LearnCFG, config->learn_cfg);
+	max17042_override_por(client, MAX17042_FilterCFG, config->filter_cfg);
+	max17042_override_por(client, MAX17042_RelaxCFG, config->relax_cfg);
+	max17042_override_por(client, MAX17042_MiscCFG, config->misc_cfg);
+	max17042_override_por(client, MAX17042_MaskSOC, config->masksoc);
+
+	max17042_override_por(client, MAX17042_FullCAP, config->fullcap);
+	max17042_override_por(client, MAX17042_FullCAPNom, config->fullcapnom);
+	max17042_override_por(client, MAX17042_SOC_empty, config->socempty);
+	max17042_override_por(client, MAX17042_LAvg_empty, config->lavg_empty);
+	max17042_override_por(client, MAX17042_dQacc, config->dqacc);
+	max17042_override_por(client, MAX17042_dPacc, config->dpacc);
+
+	max17042_override_por(client, MAX17042_V_empty, config->vempty);
+	max17042_override_por(client, MAX17042_TempNom, config->temp_nom);
+	max17042_override_por(client, MAX17042_TempLim, config->temp_lim);
+	max17042_override_por(client, MAX17042_FCTC, config->fctc);
+	max17042_override_por(client, MAX17042_RCOMP0, config->rcomp0);
+	max17042_override_por(client, MAX17042_TempCo, config->tcompc0);
+	max17042_override_por(client, MAX17042_EmptyTempCo,
+			config->empty_tempco);
+	max17042_override_por(client, MAX17042_K_empty0, config->kempty0);
+}
+
+static int max17042_init_chip(struct max17042_chip *chip)
+{
+	int val;
+	int ret;
+
+	val = max17042_read_reg(chip->client, MAX17042_STATUS);
+
+	if (val & STATUS_POR_BIT) {
+
+		max17042_override_por_values(chip);
+		/* After Power up, the MAX17042 requires 500mS in order
+		 * to perform signal debouncing and initial SOC reporting
+		 */
+		msleep(500);
+
+		/* Initialize configaration */
+		max17042_write_config_regs(chip);
+
+		/* write cell characterization data */
+		ret = max17042_init_model(chip);
+		if (ret) {
+			dev_err(&chip->client->dev, "%s init failed\n",
+				__func__);
+			return -EIO;
+		}
+		max17042_verify_model_lock(chip);
+		if (ret) {
+			dev_err(&chip->client->dev, "%s lock verify failed\n",
+				__func__);
+			return -EIO;
+		}
+		/* write custom parameters */
+		max17042_write_custom_regs(chip);
+
+		/* update capacity params */
+		max17042_update_capacity_regs(chip);
+
+		/* delay must be atleast 350mS to allow VFSOC
+		 * to be calculated from the new configuration
+		 */
+		msleep(350);
+
+		/* reset vfsoc0 reg */
+		max17042_reset_vfsoc0_reg(chip);
+
+
+		/* load new capacity params */
+		max17042_load_new_capacity_params(chip);
+
+		/* Init complete, Clear the POR bit */
+		val = max17042_read_reg(chip->client, MAX17042_STATUS);
+		max17042_write_reg(chip->client, MAX17042_STATUS,
+						val & (~STATUS_POR_BIT));
+	}
+	return 0;
+}
+
+
 static void max17042_init_worker(struct work_struct *work)
 {
 	struct max17042_chip *chip = container_of(work,
@@ -194,6 +536,12 @@ static void max17042_init_worker(struct work_struct *work)
 		max17042_set_reg(client, chip->pdata->init_data,
 				 chip->pdata->num_init_data);
 
+	if (chip->pdata->enable_por_init && chip->pdata->config_data) {
+		ret = max17042_init_chip(chip);
+		if (ret)
+			return;
+	}
+
 	if (!chip->pdata->enable_current_sense) {
 		max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
 		max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index 67eeada..e01b167 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -27,6 +27,8 @@
 #define MAX17042_BATTERY_FULL	(100)
 #define MAX17042_DEFAULT_SNS_RESISTOR	(10000)
 
+#define MAX17042_CHARACTERIZATION_DATA_SIZE 48
+
 enum max17042_register {
 	MAX17042_STATUS		= 0x00,
 	MAX17042_VALRT_Th	= 0x01,
@@ -124,10 +126,64 @@ struct max17042_reg_data {
 	u16 data;
 };
 
+struct max17042_config_data {
+	/* External current sense resistor value in milli-ohms */
+	u32	cur_sense_val;
+
+	/* A/D measurement */
+	u16	tgain;		/* 0x2C */
+	u16	toff;		/* 0x2D */
+	u16	cgain;		/* 0x2E */
+	u16	coff;		/* 0x2F */
+
+	/* Alert / Status */
+	u16	valrt_thresh;	/* 0x01 */
+	u16	talrt_thresh;	/* 0x02 */
+	u16	soc_alrt_thresh;	/* 0x03 */
+	u16	config;		/* 0x01D */
+	u16	shdntimer;	/* 0x03F */
+
+	/* App data */
+	u16	design_cap;	/* 0x18 */
+	u16	ichgt_term;	/* 0x1E */
+
+	/* MG3 config */
+	u16	at_rate;	/* 0x04 */
+	u16	learn_cfg;	/* 0x28 */
+	u16	filter_cfg;	/* 0x29 */
+	u16	relax_cfg;	/* 0x2A */
+	u16	misc_cfg;	/* 0x2B */
+	u16	masksoc;	/* 0x32 */
+
+	/* MG3 save and restore */
+	u16	fullcap;	/* 0x10 */
+	u16	fullcapnom;	/* 0x23 */
+	u16	socempty;	/* 0x33 */
+	u16	lavg_empty;	/* 0x36 */
+	u16	dqacc;		/* 0x45 */
+	u16	dpacc;		/* 0x46 */
+
+	/* Cell technology from power_supply.h */
+	u16	cell_technology;
+
+	/* Cell Data */
+	u16	vempty;		/* 0x12 */
+	u16	temp_nom;	/* 0x24 */
+	u16	temp_lim;	/* 0x25 */
+	u16	fctc;		/* 0x37 */
+	u16	rcomp0;		/* 0x38 */
+	u16	tcompc0;	/* 0x39 */
+	u16	empty_tempco;	/* 0x3A */
+	u16	kempty0;	/* 0x3B */
+	u16	cell_char_tbl[MAX17042_CHARACTERIZATION_DATA_SIZE];
+} __packed;
+
 struct max17042_platform_data {
 	struct max17042_reg_data *init_data;
+	struct max17042_config_data *config_data;
 	int num_init_data; /* Number of enties in init_data array */
 	bool enable_current_sense;
+	bool enable_por_init; /* Use POR init from Maxim appnote */
 
 	/*
 	 * R_sns in micro-ohms.
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] x86-mrst: Add battery fuel guage platform data
  2011-11-28 19:49 [PATCH 0/4] MAX17042 add support for maxim POR procedure dirk.brandewie
                   ` (2 preceding siblings ...)
  2011-11-28 19:49 ` [PATCH 3/4] max17042: Add POR init procedure from Maxim appnote dirk.brandewie
@ 2011-11-28 19:49 ` dirk.brandewie
  2011-11-29 17:29   ` Alan Cox
  3 siblings, 1 reply; 6+ messages in thread
From: dirk.brandewie @ 2011-11-28 19:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham, alan, Dirk Brandewie

From: Dirk Brandewie <dirk.brandewie@gmail.com>

Add platform data to configure the MAX17042 at POR.  The accuracy of
the MAX17042 is improved by initializing the fuel gauge with the
battery characterization data.Summary:
---
 arch/x86/platform/mrst/mrst.c |   46 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index b1489a0..b4032a9 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -22,6 +22,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c/pca953x.h>
 #include <linux/gpio_keys.h>
+#include <linux/power_supply.h>
+#include <linux/power/max17042_battery.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
@@ -484,6 +486,49 @@ static void __init *max7315_platform_data(void *info)
 	return max7315;
 }
 
+#define	NTC_47K_TGAIN	0xE4E4
+#define	NTC_47K_TOFF	0x2F1D
+
+static void *max17042_platform_data(void *info)
+{
+	struct i2c_board_info *i2c_info = (struct i2c_board_info *)info;
+	static struct max17042_platform_data platform_data;
+	static struct max17042_config_data config_data = {
+		.tgain = NTC_47K_TGAIN,
+		.toff = NTC_47K_TOFF,
+		.config = 0x2210,
+		.learn_cfg = 0x0076,
+		.filter_cfg = 0x87A4,
+		.relax_cfg = 0x506B,
+		.rcomp0 = 0x0092,
+		.tcompc0 = 0x0B19,
+		.empty_tempco = 0x2D51,
+		.kempty0 = 0x0D83,
+		.fullcap = 14727,
+		.design_cap = 14727,
+		.fullcapnom = 14727,
+		.cell_technology = POWER_SUPPLY_TECHNOLOGY_LION,
+		.cell_char_tbl = {
+	/* Data to be written from 0x80h */
+	0xABB0, 0xB2B0, 0xBB10, 0xBBB0, 0xBC10, 0xBC70, 0xBD00, 0xBD70,
+	0xBDC0, 0xBE10, 0xC010, 0xC130, 0xC4A0, 0xC9C0, 0xCD10, 0xD090,
+ 	/* Data to be written from 0x90h */
+	0x0620, 0x0420, 0x1900, 0x3600, 0x3DA0, 0x2CA0, 0x3C20, 0x3500,
+	0x3500, 0x0440, 0x1240, 0x0DF0, 0x08F0, 0x0870, 0x07F0, 0x07F0,
+	/* Data to be written from 0xA0h */
+	0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
+	0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
+		},
+	};
+
+	strcpy(i2c_info->type, "max17042");
+	platform_data.enable_por_init = 1;
+	platform_data.config_data = &config_data;
+	platform_data.enable_current_sense = 1;
+
+	return &platform_data;
+}
+
 static void __init *emc1403_platform_data(void *info)
 {
 	static short intr2nd_pdata;
@@ -649,6 +694,7 @@ static const struct devs_id __initconst device_ids[] = {
 	{"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data},
 	{"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
 	{"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
+	{"max17042", SFI_DEV_TYPE_I2C, 0, &max17042_platform_data},
 	{"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data},
 	{"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
 	{"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/4] x86-mrst: Add battery fuel guage platform data
  2011-11-28 19:49 ` [PATCH 4/4] x86-mrst: Add battery fuel guage platform data dirk.brandewie
@ 2011-11-29 17:29   ` Alan Cox
  0 siblings, 0 replies; 6+ messages in thread
From: Alan Cox @ 2011-11-29 17:29 UTC (permalink / raw)
  To: dirk.brandewie
  Cc: linux-kernel, cbouatmailru, dg77.kim, kyungmin.park, myungjoo.ham,
	Jason.Wortham

On Mon, 28 Nov 2011 11:49:53 -0800
dirk.brandewie@gmail.com wrote:

> From: Dirk Brandewie <dirk.brandewie@gmail.com>
> 
> Add platform data to configure the MAX17042 at POR.  The accuracy of
> the MAX17042 is improved by initializing the fuel gauge with the
> battery characterization data.Summary:


Please cc the x86 maintainers on the final version of this as there is
stuff queued there from me for updating bits of mrst.c as well.

Alan

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-11-29 17:17 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-28 19:49 [PATCH 0/4] MAX17042 add support for maxim POR procedure dirk.brandewie
2011-11-28 19:49 ` [PATCH 1/4] max17042: Move power suppply registration to a worker thread dirk.brandewie
2011-11-28 19:49 ` [PATCH 2/4] max17042: Align register definitions with data sheet and init appnote dirk.brandewie
2011-11-28 19:49 ` [PATCH 3/4] max17042: Add POR init procedure from Maxim appnote dirk.brandewie
2011-11-28 19:49 ` [PATCH 4/4] x86-mrst: Add battery fuel guage platform data dirk.brandewie
2011-11-29 17:29   ` Alan Cox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox