From b95aacd332cde91299cf05e1a87dc6d7de545adb Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Majewski?= Date: Tue, 13 Nov 2012 03:22:03 +0000 Subject: [PATCH] pmic:fuel-gauge: Support for MAX17042 fuel-gauge 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 Signed-off-by: Kyungmin Park Cc: Stefano Babic --- Makefile | 1 + drivers/power/fuel_gauge/Makefile | 47 +++++ drivers/power/fuel_gauge/fg_max17042.c | 250 +++++++++++++++++++++++++ include/power/fg_battery_cell_params.h | 90 +++++++++ include/power/max17042_fg.h | 74 ++++++++ 5 files changed, 462 insertions(+) create mode 100644 drivers/power/fuel_gauge/Makefile create mode 100644 drivers/power/fuel_gauge/fg_max17042.c create mode 100644 include/power/fg_battery_cell_params.h create mode 100644 include/power/max17042_fg.h diff --git a/Makefile b/Makefile index 0f18e6cf3d..1a17be9dbe 100644 --- a/Makefile +++ b/Makefile @@ -294,6 +294,7 @@ LIBS-y += drivers/net/phy/libphy.o LIBS-y += drivers/pci/libpci.o LIBS-y += drivers/pcmcia/libpcmcia.o LIBS-y += drivers/power/libpower.o \ + drivers/power/fuel_gauge/libfuel_gauge.o \ drivers/power/pmic/libpmic.o \ drivers/power/battery/libbattery.o LIBS-y += drivers/spi/libspi.o diff --git a/drivers/power/fuel_gauge/Makefile b/drivers/power/fuel_gauge/Makefile new file mode 100644 index 0000000000..da1541412b --- /dev/null +++ b/drivers/power/fuel_gauge/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2012 Samsung Electronics +# Lukasz Majewski +# +# 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 $(TOPDIR)/config.mk + +LIB := $(obj)libfuel_gauge.o + +COBJS-$(CONFIG_POWER_FG_MAX17042) += fg_max17042.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################## diff --git a/drivers/power/fuel_gauge/fg_max17042.c b/drivers/power/fuel_gauge/fg_max17042.c new file mode 100644 index 0000000000..9b7c184cb0 --- /dev/null +++ b/drivers/power/fuel_gauge/fg_max17042.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Lukasz Majewski + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} + +static int power_update_battery(struct pmic *p, struct pmic *bat) +{ + struct power_battery *pb = bat->pbat; + 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); + pb->bat->state_of_chrg = (val >> 8); + + pmic_reg_read(p, MAX17042_VCELL, &val); + debug("vfsoc: 0x%x\n", val); + pb->bat->voltage_uV = ((val & 0xFFUL) >> 3) + ((val & 0xFF00) >> 3); + pb->bat->voltage_uV = (pb->bat->voltage_uV * 625); + + pmic_reg_read(p, 0x05, &val); + pb->bat->capacity = val >> 2; + + return ret; +} + +static int power_check_battery(struct pmic *p, struct pmic *bat) +{ + struct power_battery *pb = bat->pbat; + 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); + pb->bat->version = val; + + power_update_battery(p, bat); + debug("fg ver: 0x%x\n", pb->bat->version); + printf("BAT: state_of_charge(SOC):%d%%\n", + pb->bat->state_of_chrg); + + printf(" voltage: %d.%6.6d [V] (expected to be %d [mAh])\n", + pb->bat->voltage_uV / 1000000, + pb->bat->voltage_uV % 1000000, + pb->bat->capacity); + + if (pb->bat->voltage_uV > 3850000) + pb->bat->state = EXT_SOURCE; + else if (pb->bat->voltage_uV < 3600000 || pb->bat->state_of_chrg < 5) + pb->bat->state = CHARGE; + else + pb->bat->state = NORMAL; + + return ret; +} + +static struct power_fg power_fg_ops = { + .fg_battery_check = power_check_battery, + .fg_battery_update = power_update_battery, +}; + +int power_fg_init(unsigned char bus) +{ + static const char name[] = "MAX17042_FG"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + 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->sensor_byte_order = PMIC_SENSOR_BYTE_ORDER_BIG; + p->bus = bus; + + p->fg = &power_fg_ops; + return 0; +} diff --git a/include/power/fg_battery_cell_params.h b/include/power/fg_battery_cell_params.h new file mode 100644 index 0000000000..7ddf6f2ffa --- /dev/null +++ b/include/power/fg_battery_cell_params.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Lukasz Majewski + * + * 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 */ +/* Shall be written to addr 0x80h */ +u16 cell_character0[16] = { + 0xA2A0, + 0xB6E0, + 0xB850, + 0xBAD0, + 0xBB20, + 0xBB70, + 0xBBC0, + 0xBC20, + 0xBC80, + 0xBCE0, + 0xBD80, + 0xBE20, + 0xC090, + 0xC420, + 0xC910, + 0xD070 +}; + +/* Shall be written to addr 0x90h */ +u16 cell_character1[16] = { + 0x0090, + 0x1A50, + 0x02F0, + 0x2060, + 0x2060, + 0x2E60, + 0x26A0, + 0x2DB0, + 0x2DB0, + 0x1870, + 0x2A20, + 0x16F0, + 0x08F0, + 0x0D40, + 0x08C0, + 0x08C0 +}; + +/* Shall be written to addr 0xA0h */ +u16 cell_character2[16] = { + 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 0000000000..1103a483f2 --- /dev/null +++ b/include/power/max17042_fg.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Lukasz Majewski + * + * 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_ */ -- 2.39.5