From patchwork Tue Nov 13 13:22:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?=C5=81ukasz_Majewski?= X-Patchwork-Id: 198657 X-Patchwork-Delegate: agust@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 8E54B2C00D2 for ; Wed, 14 Nov 2012 00:25:13 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BA2304A14F; Tue, 13 Nov 2012 14:24:56 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id COhnOXzHUVG0; Tue, 13 Nov 2012 14:24:56 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C76554A1BE; Tue, 13 Nov 2012 14:23:43 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B7B794A15C for ; Tue, 13 Nov 2012 14:23:36 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2JUK6Md-0cOw for ; Tue, 13 Nov 2012 14:23:32 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mailout2.samsung.com (mailout2.samsung.com [203.254.224.25]) by theia.denx.de (Postfix) with ESMTP id 230D94A026 for ; Tue, 13 Nov 2012 14:23:12 +0100 (CET) Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MDF005X7H5HJYA0@mailout2.samsung.com> for u-boot@lists.denx.de; Tue, 13 Nov 2012 22:23:11 +0900 (KST) X-AuditID: cbfee61a-b7fa66d0000004cf-37-50a249bf2f80 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 25.B3.01231.FB942A05; Tue, 13 Nov 2012 22:23:11 +0900 (KST) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MDF00AK5H593U10@mmp1.samsung.com> for u-boot@lists.denx.de; Tue, 13 Nov 2012 22:23:11 +0900 (KST) From: Lukasz Majewski To: u-boot@lists.denx.de Date: Tue, 13 Nov 2012 14:22:03 +0100 Message-id: <1352812937-15998-13-git-send-email-l.majewski@samsung.com> X-Mailer: git-send-email 1.7.10 In-reply-to: <1352812937-15998-1-git-send-email-l.majewski@samsung.com> References: <1352812937-15998-1-git-send-email-l.majewski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrEJMWRmVeSWpSXmKPExsVy+t9jAd39nosCDDbdNbF4u7eT3YHR4+yd HYwBjFFcNimpOZllqUX6dglcGese/2EpOFVecfXsQ8YGxpkJXYycHBICJhKf7x5hhrDFJC7c W88GYgsJLGKU2LuzuIuRC8hezCRxom8bC0iCTUAPqOEpE4gtIiAh8av/KiNIEbPAHUaJ/9de gCWEBbwk7rT/YQSxWQRUJb6v+QI2lVfAXWLBvR8sENvkJZ7e7wOKc3BwAsX/nGeCWOwmsXnn UeYJjLwLGBlWMYqmFiQXFCel5xrqFSfmFpfmpesl5+duYgT7/JnUDsaVDRaHGAU4GJV4eG+4 LAwQYk0sK67MPcQowcGsJMJ73m1RgBBvSmJlVWpRfnxRaU5q8SFGaQ4WJXHeZo+UACGB9MSS 1OzU1ILUIpgsEwenVAPjhdqvS5KmV5scLdsjvIxL20bK91J+Y2hp6NVisQN/Vygv/b2EaQsb 4wL+L7neuyV4b21unb/Ks1It4un5i/O7DnKyOWv9qq3czHdsR2nXOsbNbkKMVz+rqoud4+r/ IWm0Y9OmG+o92mFLbzVc2ORl3fV36hmbWd+erhdaqpZuOP8dY2sus72cEktxRqKhFnNRcSIA gk2L2fUBAAA= Cc: Kyungmin Park , Tom Rini Subject: [U-Boot] [PATCH v7 12/26] pmic:fuel-gauge: Support for MAX17042 fuel-gauge X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- Changes for v2: - File moved to separate directory at ./drivers/power - {check|update}_battery available as callbacks from struct power_battery Changes for v3: - change code according to struct pmic redesign Changes for v4: - Introduce libfuel_gauge.o at ./Makefile - Move fg_max17042.c file to ./drivers/power/fuel_gauge directory Changes for v5: - None Changes for v6: - None Changes for v7: - Check pmic_alloc() return value (to prevent NULL pointer dereference) --- 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(+), 0 deletions(-) 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 2a8a098..5336531 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 0000000..da15414 --- /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 0000000..9b7c184 --- /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 0000000..7ddf6f2 --- /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 0000000..1103a48 --- /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_ */