From patchwork Wed Nov 14 09:07:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "(Exiting) Baolin Wang" X-Patchwork-Id: 10682221 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9718B14E2 for ; Wed, 14 Nov 2018 09:07:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B5732AF3D for ; Wed, 14 Nov 2018 09:07:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7F38E2AF46; Wed, 14 Nov 2018 09:07:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EDC942AF3D for ; Wed, 14 Nov 2018 09:07:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727966AbeKNTKN (ORCPT ); Wed, 14 Nov 2018 14:10:13 -0500 Received: from mail-pg1-f196.google.com ([209.85.215.196]:41611 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732234AbeKNTKM (ORCPT ); Wed, 14 Nov 2018 14:10:12 -0500 Received: by mail-pg1-f196.google.com with SMTP id 70so7073771pgh.8 for ; Wed, 14 Nov 2018 01:07:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=5jCGoWWaBFWMEfVdu5BxQTbZHcNaLmB1PTqRJRj8eG0=; b=BwnucNaAnlGs23qpoK4CECQiv24ZjCFhPKAY33oXhEsXPMffEElmigj4ZKEwQDghNK M0HzRXJuvWUjH/spyWEqUdXhjcox27pGsjpwISK3OI0ageH3R8aTYtTNmFE5g8E5parg RIrkGBfWPZ6Fccbq467RTsp8AGP401aUV0Dkc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=5jCGoWWaBFWMEfVdu5BxQTbZHcNaLmB1PTqRJRj8eG0=; b=Huhf6U3xtBkkSrv2V3bMIjvUzmcCuP5EmfHbLjFdIx9OUrJqTporT+ea9T7b00Zr0r N4reI3SWjbogdKH+Hz5sbpGGQeNDY/gLZIAhyNy356S6dTX8n9Pd6CPsSxm+b+XUTBr+ psehnWQ/jeWIUy97d1pv1QXDFHZYSxzlCthczSMcj7buIFsY8fhUR1Rmfh0LrwUWwcIl LfXvcR4hAiUg5HGGs575+Ij7DBLCQVf0u0F6DMHSKM+w8R1Ig7jNT/l1rSbq/o6zJQQX XbAxbSklI2BYSQBuq9ojxEwU53V7IraQQgocijzh8dFy2ZLkMUmkbZ0aBvO5wsDg6Bhk gS+A== X-Gm-Message-State: AGRZ1gIaCnlM34CtRk+EQY2kohGqKBu5TYckDQN7x1jbx2Ba/sGwXUm8 OcW8EDIYyO+lmXNtIj6Fq2OhXQ== X-Google-Smtp-Source: AJdET5f7Othf28Q7cDWUE07jr22xc/7ggewvMzcoXqYgu0XZGtQYxYMXEu9HlO+t+QgfQKKcDDKTXA== X-Received: by 2002:a63:4d0e:: with SMTP id a14mr999631pgb.408.1542186470198; Wed, 14 Nov 2018 01:07:50 -0800 (PST) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.102]) by smtp.gmail.com with ESMTPSA id 127-v6sm25048814pfx.91.2018.11.14.01.07.47 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 14 Nov 2018 01:07:49 -0800 (PST) From: Baolin Wang To: sre@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com Cc: linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, yuanjiang.yu@unisoc.com, baolin.wang@linaro.org, broonie@kernel.org Subject: [PATCH 2/5] power: supply: sc27xx: Add fuel gauge calibration Date: Wed, 14 Nov 2018 17:07:05 +0800 Message-Id: X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: In-Reply-To: References: Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support to read calibration values from the eFuse controller to calibrate the ADC values corresponding to current and voltage, which can make the current and voltage data more accurate. Signed-off-by: Baolin Wang --- drivers/power/supply/sc27xx_fuel_gauge.c | 62 ++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 8613584..66f4db2 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -6,10 +6,12 @@ #include #include #include +#include #include #include #include #include +#include /* PMIC global control registers definition */ #define SC27XX_MODULE_EN0 0xc08 @@ -39,8 +41,6 @@ #define SC27XX_FGU_CLBCNT_MASK GENMASK(15, 0) #define SC27XX_FGU_CLBCNT_SHIFT 16 -#define SC27XX_FGU_1000MV_ADC 686 -#define SC27XX_FGU_1000MA_ADC 1372 #define SC27XX_FGU_CUR_BASIC_ADC 8192 #define SC27XX_FGU_SAMPLE_HZ 2 @@ -59,6 +59,8 @@ * @init_clbcnt: the initial coulomb counter * @max_volt: the maximum constant input voltage in millivolt * @table_len: the capacity table length + * @cur_1000ma_adc: ADC value corresponding to 1000 mA + * @vol_1000mv_adc: ADC value corresponding to 1000 mV * @cap_table: capacity table with corresponding ocv */ struct sc27xx_fgu_data { @@ -76,6 +78,8 @@ struct sc27xx_fgu_data { int init_clbcnt; int max_volt; int table_len; + int cur_1000ma_adc; + int vol_1000mv_adc; struct power_supply_battery_ocv_table *cap_table; }; @@ -86,14 +90,14 @@ struct sc27xx_fgu_data { "sc2723_charger", }; -static int sc27xx_fgu_adc_to_current(int adc) +static int sc27xx_fgu_adc_to_current(struct sc27xx_fgu_data *data, int adc) { - return DIV_ROUND_CLOSEST(adc * 1000, SC27XX_FGU_1000MA_ADC); + return DIV_ROUND_CLOSEST(adc * 1000, data->cur_1000ma_adc); } -static int sc27xx_fgu_adc_to_voltage(int adc) +static int sc27xx_fgu_adc_to_voltage(struct sc27xx_fgu_data *data, int adc) { - return DIV_ROUND_CLOSEST(adc * 1000, SC27XX_FGU_1000MV_ADC); + return DIV_ROUND_CLOSEST(adc * 1000, data->vol_1000mv_adc); } /* @@ -116,7 +120,7 @@ static int sc27xx_fgu_get_boot_capacity(struct sc27xx_fgu_data *data, int *cap) return ret; cur <<= 1; - oci = sc27xx_fgu_adc_to_current(cur - SC27XX_FGU_CUR_BASIC_ADC); + oci = sc27xx_fgu_adc_to_current(data, cur - SC27XX_FGU_CUR_BASIC_ADC); /* * Should get the OCV from SC27XX_FGU_POCV register at the system @@ -127,7 +131,7 @@ static int sc27xx_fgu_get_boot_capacity(struct sc27xx_fgu_data *data, int *cap) if (ret) return ret; - volt = sc27xx_fgu_adc_to_voltage(volt); + volt = sc27xx_fgu_adc_to_voltage(data, volt); ocv = volt * 1000 - oci * data->internal_resist; /* @@ -201,7 +205,7 @@ static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap) * as 100 to improve the precision. */ temp = DIV_ROUND_CLOSEST(delta_clbcnt, 360); - temp = sc27xx_fgu_adc_to_current(temp); + temp = sc27xx_fgu_adc_to_current(data, temp); /* * Convert to capacity percent of the battery total capacity, @@ -225,7 +229,7 @@ static int sc27xx_fgu_get_vbat_vol(struct sc27xx_fgu_data *data, int *val) * It is ADC values reading from registers which need to convert to * corresponding voltage values. */ - *val = sc27xx_fgu_adc_to_voltage(vol); + *val = sc27xx_fgu_adc_to_voltage(data, vol); return 0; } @@ -242,7 +246,7 @@ static int sc27xx_fgu_get_current(struct sc27xx_fgu_data *data, int *val) * It is ADC values reading from registers which need to convert to * corresponding current values. */ - *val = sc27xx_fgu_adc_to_current(cur - SC27XX_FGU_CUR_BASIC_ADC); + *val = sc27xx_fgu_adc_to_current(data, cur - SC27XX_FGU_CUR_BASIC_ADC); return 0; } @@ -469,6 +473,38 @@ static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity) return DIV_ROUND_CLOSEST(cur_cap * 36, 10); } +static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) +{ + struct nvmem_cell *cell; + int calib_data, cal_4200mv; + void *buf; + size_t len; + + cell = nvmem_cell_get(data->dev, "fgu_calib"); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + + if (IS_ERR(buf)) + return PTR_ERR(buf); + + memcpy(&calib_data, buf, min(len, sizeof(u32))); + + /* + * Get the ADC value corresponding to 4200 mV from eFuse controller + * according to below formula. Then convert to ADC values corresponding + * to 1000 mV and 1000 mA. + */ + cal_4200mv = (calib_data & 0x1ff) + 6963 - 4096 - 256; + data->vol_1000mv_adc = DIV_ROUND_CLOSEST(cal_4200mv * 10, 42); + data->cur_1000ma_adc = data->vol_1000mv_adc * 4; + + kfree(buf); + return 0; +} + static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) { struct power_supply_battery_info info = { }; @@ -503,6 +539,10 @@ static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) power_supply_put_battery_info(data->battery, &info); + ret = sc27xx_fgu_calibration(data); + if (ret) + return ret; + /* Enable the FGU module */ ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, SC27XX_FGU_EN, SC27XX_FGU_EN);