Patchwork [U-Boot,09/16] pmic:fuel-gauge: Support for MAX17042 fuel-gauge

login
register
mail settings
Submitter Łukasz Majewski
Date Sept. 14, 2012, 3:40 p.m.
Message ID <1347637215-4830-10-git-send-email-l.majewski@samsung.com>
Download mbox | patch
Permalink /patch/183954/
State Superseded
Delegated to: Minkyu Kang
Headers show

Comments

Łukasz Majewski - Sept. 14, 2012, 3:40 p.m.
Support for MAX17042 fuel-gauge (FG), which is built into the MAX8997
power management device.
Special file - fg_battery_cell_params.h with cells characteristics
added.

The FG device will work with redesigned PMIC framework.

Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Stefano Babic <sbabic@denx.de>
---
 drivers/misc/Makefile                  |    1 +
 drivers/misc/fg_max17042.c             |  235 ++++++++++++++++++++++++++++++++
 include/power/fg_battery_cell_params.h |   88 ++++++++++++
 include/power/max17042_fg.h            |   74 ++++++++++
 include/power/power_chrg.h             |    2 +
 5 files changed, 400 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/fg_max17042.c
 create mode 100644 include/power/fg_battery_cell_params.h
 create mode 100644 include/power/max17042_fg.h
Tom Rini - Sept. 14, 2012, 5:23 p.m.
On Fri, Sep 14, 2012 at 05:40:08PM +0200, Lukasz Majewski wrote:

> Support for MAX17042 fuel-gauge (FG), which is built into the MAX8997
> power management device.
> Special file - fg_battery_cell_params.h with cells characteristics
> added.
[snip]
> +#ifndef __FG_BATTERY_CELL_PARAMS_H_
> +#define __FG_BATTERY_CELL_PARAMS_H_
> +
> +#if  defined(CONFIG_POWER_FG_MAX17042) && defined(CONFIG_TRATS)
> +
> +/* Cell characteristics - Exynos4 TRATS development board */
> +
> +u16 cell_character0[16]  /* Shall be written to addr 0x80h */
> += { 0xA2A0,

This (and the rest of the file) should be:
/* Shall be written to addr 0x80h */
u16 cell_character0[16] = {
	0xA2A0,
...

Thanks.

Also:
[snip]
> +	MAX17042_AVG_CURRENT	= 0x0B,
> +	MAX17042_SOCMIX	= 0x0D,
> +	MAX17042_SOCAV		= 0x0E,

I assume this is just odd formatting in the mail and once applied it's
aligned.  If not, please fix (and check the rest of the series).
Thanks!
Lukasz Majewski - Sept. 17, 2012, 8:59 p.m.
Hi Tom ,

> On Fri, Sep 14, 2012 at 05:40:08PM +0200, Lukasz Majewski wrote:
> 
> > Support for MAX17042 fuel-gauge (FG), which is built into the
> > MAX8997 power management device.
> > Special file - fg_battery_cell_params.h with cells characteristics
> > added.
> [snip]
> > +#ifndef __FG_BATTERY_CELL_PARAMS_H_
> > +#define __FG_BATTERY_CELL_PARAMS_H_
> > +
> > +#if  defined(CONFIG_POWER_FG_MAX17042) && defined(CONFIG_TRATS)
> > +
> > +/* Cell characteristics - Exynos4 TRATS development board */
> > +
> > +u16 cell_character0[16]  /* Shall be written to addr 0x80h */
> > += { 0xA2A0,
> 
> This (and the rest of the file) should be:
> /* Shall be written to addr 0x80h */
> u16 cell_character0[16] = {
> 	0xA2A0,
> ...
> 


Ok, I will fix this.
> Thanks.
> 
> Also:
> [snip]
> > +	MAX17042_AVG_CURRENT	= 0x0B,
> > +	MAX17042_SOCMIX	= 0x0D,
> > +	MAX17042_SOCAV		= 0x0E,
> 
> I assume this is just odd formatting in the mail and once applied it's
> aligned.  If not, please fix (and check the rest of the series).
> Thanks!
> 

I will double check that. Nether checkpatch nor emac's
whitespace-cleanup weren't complaining.

Regards,
Lukasz

Patch

diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f08a800..f3b302b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -41,6 +41,7 @@  COBJS-$(CONFIG_PMIC_I2C) += pmic_i2c.o
 COBJS-$(CONFIG_PMIC_SPI) += pmic_spi.o
 COBJS-$(CONFIG_PMIC_MAX8998) += pmic_max8998.o
 COBJS-$(CONFIG_PMIC_MAX8997) += pmic_max8997.o
+COBJS-$(CONFIG_POWER_FG_MAX17042) += fg_max17042.o
 COBJS-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
 
 COBJS	:= $(COBJS-y)
diff --git a/drivers/misc/fg_max17042.c b/drivers/misc/fg_max17042.c
new file mode 100644
index 0000000..27285e8
--- /dev/null
+++ b/drivers/misc/fg_max17042.c
@@ -0,0 +1,235 @@ 
+/*
+ *  Copyright (C) 2012 Samsung Electronics
+ *  Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <power/pmic.h>
+#include <power/max17042_fg.h>
+#include <i2c.h>
+#include <power/max8997_pmic.h>
+#include <power/power_chrg.h>
+#include <power/fg_battery_cell_params.h>
+
+int power_fg_init(unsigned char bus)
+{
+	struct pmic *p = pmic_alloc();
+	static const char name[] = "MAX17042_FG";
+
+	debug("Board Fuel Gauge init\n");
+
+	p->name = name;
+	p->interface = PMIC_I2C;
+	p->number_of_regs = FG_NUM_OF_REGS;
+	p->hw.i2c.addr = MAX17042_I2C_ADDR;
+	p->hw.i2c.tx_num = 2;
+	p->hw.i2c.byte_order = PMIC_BYTE_ORDER_NORMAL;
+	p->bus = bus;
+
+	return 0;
+}
+
+static int fg_write_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < num; i++, addr++)
+		ret |= pmic_reg_write(p, addr, *(data + i));
+
+	return ret;
+}
+
+static int fg_read_regs(struct pmic *p, u8 addr, u16 *data, int num)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < num; i++, addr++)
+		ret |= pmic_reg_read(p, addr, (u32 *) (data + i));
+
+	return ret;
+}
+
+static int fg_write_and_verify(struct pmic *p, u8 addr, u16 data)
+{
+	unsigned int val = data;
+	int ret = 0;
+
+	ret |= pmic_reg_write(p, addr, val);
+	ret |= pmic_reg_read(p, addr, &val);
+
+	if (ret)
+		return ret;
+
+	if (((u16) val) == data)
+		return 0;
+
+	return -1;
+}
+
+static void por_fuelgauge_init(struct pmic *p)
+{
+	u16 r_data0[16], r_data1[16], r_data2[16];
+	u32 rewrite_count = 5, i = 0;
+	unsigned int val;
+	int ret = 0;
+
+	/* Delay 500 ms */
+	mdelay(500);
+	/* Initilize Configuration */
+	pmic_reg_write(p, MAX17042_CONFIG, 0x2310);
+
+rewrite_model:
+	/* Unlock Model Access */
+	pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_UNLOCK1);
+	pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_UNLOCK2);
+
+	/* Write/Read/Verify the Custom Model */
+	ret |= fg_write_regs(p, MAX17042_MODEL1, cell_character0,
+			     ARRAY_SIZE(cell_character0));
+	ret |= fg_write_regs(p, MAX17042_MODEL2, cell_character1,
+			     ARRAY_SIZE(cell_character1));
+	ret |= fg_write_regs(p, MAX17042_MODEL3, cell_character2,
+			     ARRAY_SIZE(cell_character2));
+
+	if (ret) {
+		printf("%s: Cell parameters write failed!\n", __func__);
+		return;
+	}
+
+	ret |= fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+	ret |= fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+	ret |= fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+
+	if (ret)
+		printf("%s: Cell parameters read failed!\n", __func__);
+
+	for (i = 0; i < 16; i++) {
+		if ((cell_character0[i] != r_data0[i])
+		    || (cell_character1[i] != r_data1[i])
+		    || (cell_character2[i] != r_data2[i]))
+			goto rewrite_model;
+		}
+
+	/* Lock model access */
+	pmic_reg_write(p, MAX17042_MLOCKReg1, MODEL_LOCK1);
+	pmic_reg_write(p, MAX17042_MLOCKReg2, MODEL_LOCK2);
+
+	/* Verify the model access is locked */
+	ret |= fg_read_regs(p, MAX17042_MODEL1, r_data0, ARRAY_SIZE(r_data0));
+	ret |= fg_read_regs(p, MAX17042_MODEL2, r_data1, ARRAY_SIZE(r_data1));
+	ret |= fg_read_regs(p, MAX17042_MODEL3, r_data2, ARRAY_SIZE(r_data2));
+
+	if (ret) {
+		printf("%s: Cell parameters read failed!\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(r_data0); i++) {
+		/* Check if model locked */
+		if (r_data0[i] || r_data1[i] || r_data2[i]) {
+			/* Rewrite model data - prevent from endless loop */
+			if (rewrite_count--) {
+				puts("FG - Lock model access failed!\n");
+				goto rewrite_model;
+			}
+		}
+	}
+
+	/* Write Custom Parameters */
+	fg_write_and_verify(p, MAX17042_RCOMP0, RCOMP0);
+	fg_write_and_verify(p, MAX17042_TEMPCO, TempCo);
+
+	/* Delay at least 350mS */
+	mdelay(350);
+
+	/* Initialization Complete */
+	pmic_reg_read(p, MAX17042_STATUS, &val);
+	/* Write and Verify Status with POR bit Cleared */
+	fg_write_and_verify(p, MAX17042_STATUS, val & ~MAX17042_POR);
+
+	/* Delay at least 350 ms */
+	mdelay(350);
+}
+
+int power_update_battery(struct battery *bat)
+{
+	struct pmic *p = pmic_get("MAX17042_FG");
+	unsigned int val;
+	int ret = 0;
+
+	if (pmic_probe(p)) {
+		puts("Can't find max17042 fuel gauge\n");
+		return -1;
+	}
+
+	ret |= pmic_reg_read(p, MAX17042_VFSOC, &val);
+	bat->state_of_chrg = (val >> 8);
+
+	pmic_reg_read(p, MAX17042_VCELL, &val);
+	debug("vfsoc: 0x%x\n", val);
+	bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3);
+	bat->voltage_uV = (bat->voltage_uV * 625);
+
+	pmic_reg_read(p, 0x05, &val);
+	bat->capacity = val >> 2;
+
+	return ret;
+}
+
+int power_check_battery(struct battery *bat)
+{
+	struct pmic *p = pmic_get("MAX17042_FG");
+	unsigned int val;
+	int ret = 0;
+
+	if (pmic_probe(p)) {
+		puts("Can't find max17042 fuel gauge\n");
+		return -1;
+	}
+
+	ret |= pmic_reg_read(p, MAX17042_STATUS, &val);
+	debug("fg status: 0x%x\n", val);
+
+	if (val == MAX17042_POR)
+		por_fuelgauge_init(p);
+
+	ret |= pmic_reg_read(p, MAX17042_VERSION, &val);
+	bat->version = val;
+
+	power_update_battery(bat);
+	printf("fg ver: 0x%x state_of_charge(SOC):%d%%\n",
+	       bat->version, bat->state_of_chrg);
+
+	printf("voltage:\t%d.%6.6d [V] (expected to be %d [mAh])\n",
+	       bat->voltage_uV / 1000000, bat->voltage_uV % 1000000,
+	       bat->capacity);
+
+	if (bat->voltage_uV > 3850000)
+		bat->state = EXT_SOURCE;
+	else if (bat->voltage_uV < 3600000 || bat->state_of_chrg < 5)
+		bat->state = CHARGE;
+	else
+		bat->state = NORMAL;
+
+	return ret;
+}
diff --git a/include/power/fg_battery_cell_params.h b/include/power/fg_battery_cell_params.h
new file mode 100644
index 0000000..fd068a9
--- /dev/null
+++ b/include/power/fg_battery_cell_params.h
@@ -0,0 +1,88 @@ 
+/*
+ *  Copyright (C) 2012 Samsung Electronics
+ *  Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __FG_BATTERY_CELL_PARAMS_H_
+#define __FG_BATTERY_CELL_PARAMS_H_
+
+#if  defined(CONFIG_POWER_FG_MAX17042) && defined(CONFIG_TRATS)
+
+/* Cell characteristics - Exynos4 TRATS development board */
+
+u16 cell_character0[16]  /* Shall be written to addr 0x80h */
+= { 0xA2A0,
+	0xB6E0,
+	0xB850,
+	0xBAD0,
+	0xBB20,
+	0xBB70,
+	0xBBC0,
+	0xBC20,
+	0xBC80,
+	0xBCE0,
+	0xBD80,
+	0xBE20,
+	0xC090,
+	0xC420,
+	0xC910,
+	0xD070
+};
+
+u16 cell_character1[16]  /* Shall be written to addr 0x90h */
+= { 0x0090,
+	0x1A50,
+	0x02F0,
+	0x2060,
+	0x2060,
+	0x2E60,
+	0x26A0,
+	0x2DB0,
+	0x2DB0,
+	0x1870,
+	0x2A20,
+	0x16F0,
+	0x08F0,
+	0x0D40,
+	0x08C0,
+	0x08C0
+};
+
+u16 cell_character2[16]  /* Shall be written to addr 0xA0h */
+= { 0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100,
+	0x0100
+};
+#endif
+#endif /* __FG_BATTERY_CELL_PARAMS_H_ */
diff --git a/include/power/max17042_fg.h b/include/power/max17042_fg.h
new file mode 100644
index 0000000..1103a48
--- /dev/null
+++ b/include/power/max17042_fg.h
@@ -0,0 +1,74 @@ 
+/*
+ *  Copyright (C) 2012 Samsung Electronics
+ *  Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __MAX17042_FG_H_
+#define __MAX17042_FG_H_
+
+/* MAX 17042 registers */
+enum {
+	MAX17042_STATUS         = 0x00,
+	MAX17042_SOCREP         = 0x06,
+	MAX17042_VCELL          = 0x09,
+	MAX17042_CURRENT        = 0x0A,
+	MAX17042_AVG_CURRENT	= 0x0B,
+	MAX17042_SOCMIX	= 0x0D,
+	MAX17042_SOCAV		= 0x0E,
+	MAX17042_DESIGN_CAP	= 0x18,
+	MAX17042_AVG_VCELL	= 0x19,
+	MAX17042_CONFIG	= 0x1D,
+	MAX17042_VERSION	= 0x21,
+	MAX17042_LEARNCFG       = 0x28,
+	MAX17042_FILTERCFG	= 0x29,
+	MAX17042_RELAXCFG	= 0x2A,
+	MAX17042_MISCCFG	= 0x2B,
+	MAX17042_CGAIN		= 0x2E,
+	MAX17042_COFF		= 0x2F,
+	MAX17042_RCOMP0	= 0x38,
+	MAX17042_TEMPCO	= 0x39,
+	MAX17042_FSTAT		= 0x3D,
+	MAX17042_MLOCKReg1	= 0x62,
+	MAX17042_MLOCKReg2	= 0x63,
+	MAX17042_MODEL1         = 0x80,
+	MAX17042_MODEL2         = 0x90,
+	MAX17042_MODEL3         = 0xA0,
+	MAX17042_VFOCV		= 0xFB,
+	MAX17042_VFSOC		= 0xFF,
+
+	FG_NUM_OF_REGS = 0x100,
+};
+
+#define RCOMP0			0x0060
+#define TempCo			0x1015
+
+
+#define MAX17042_POR (1 << 1)
+
+#define MODEL_UNLOCK1		0x0059
+#define MODEL_UNLOCK2		0x00c4
+#define MODEL_LOCK1		0x0000
+#define MODEL_LOCK2		0x0000
+
+#define MAX17042_I2C_ADDR	(0x6C >> 1)
+
+int power_fg_init(unsigned char bus);
+#endif /* __MAX17042_FG_H_ */
diff --git a/include/power/power_chrg.h b/include/power/power_chrg.h
index ecbad46..c8ae650 100644
--- a/include/power/power_chrg.h
+++ b/include/power/power_chrg.h
@@ -50,5 +50,7 @@  struct battery {
 	unsigned int state;
 };
 
+int power_update_battery(struct battery *bat);
+int power_check_battery(struct battery *bat);
 int power_chrg_get_type(void);
 #endif /* __POWER_CHARGER_H_ */