From patchwork Fri Jan 11 13:12:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 13975 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 4BD2C23E27 for ; Fri, 11 Jan 2013 13:13:28 +0000 (UTC) Received: from mail-vb0-f43.google.com (mail-vb0-f43.google.com [209.85.212.43]) by fiordland.canonical.com (Postfix) with ESMTP id E370FA1849E for ; Fri, 11 Jan 2013 13:13:27 +0000 (UTC) Received: by mail-vb0-f43.google.com with SMTP id fs19so1395653vbb.2 for ; Fri, 11 Jan 2013 05:13:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=MUilezBAXOPOl30ZQNKYea5iv1ixQXB2VCk1kOMztsM=; b=YGQwGtvSs2TXuFsZhz0Xj2iVN3BRDabKe+G0legVO5nAP6nflbh6lrGXTYwqDug9RG JMMIzuxcwXkRpZG1ieEa2Xttcff6xiEKA7FNhxwRM5JAJgaY8D566VJt7Cj+2USDrAxK 8vKRIvpikGFUZUgVVGtP1SxJARVmzTKvt7kR3hODoAPp/nhU+WXTfs4V+gEQptYBJM/K Zf+fYmalhynK89p7xs5DMX3kpb/gCVSEkdpX5mYqVmP+1vsO8a/cDWrf8AX11htg13Vq iUeq5I8H/dSCiBnR8SBxumk+5s9x2D3JAdnPMDnflLb6Z+YfmTlxDLypZ6pTA3yHQDwW gZhA== X-Received: by 10.220.238.139 with SMTP id ks11mr92006317vcb.49.1357910007409; Fri, 11 Jan 2013 05:13:27 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.145.101 with SMTP id st5csp111222veb; Fri, 11 Jan 2013 05:13:26 -0800 (PST) X-Received: by 10.180.85.165 with SMTP id i5mr15201188wiz.11.1357910006155; Fri, 11 Jan 2013 05:13:26 -0800 (PST) Received: from mail-we0-f179.google.com (mail-we0-f179.google.com [74.125.82.179]) by mx.google.com with ESMTPS id cp11si8668885wjb.49.2013.01.11.05.13.25 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 11 Jan 2013 05:13:26 -0800 (PST) Received-SPF: neutral (google.com: 74.125.82.179 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) client-ip=74.125.82.179; Authentication-Results: mx.google.com; spf=neutral (google.com: 74.125.82.179 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) smtp.mail=lee.jones@linaro.org Received: by mail-we0-f179.google.com with SMTP id r6so853473wey.10 for ; Fri, 11 Jan 2013 05:13:25 -0800 (PST) X-Received: by 10.194.242.69 with SMTP id wo5mr121032344wjc.10.1357910005715; Fri, 11 Jan 2013 05:13:25 -0800 (PST) Received: from localhost.localdomain (cpc1-aztw13-0-0-cust473.18-1.cable.virginmedia.com. [77.102.241.218]) by mx.google.com with ESMTPS id p2sm7204515wic.7.2013.01.11.05.13.23 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 11 Jan 2013 05:13:24 -0800 (PST) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: arnd@arndb.de, linus.walleij@stericsson.com, cbouatmailru@gmail.com, Johan Bjornstedt , Lee Jones , Henrik Solver Subject: [PATCH 02/18] power: ab8500_bm: Skip first CCEOC irq for instant current Date: Fri, 11 Jan 2013 13:12:50 +0000 Message-Id: <1357909986-9262-3-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1357909986-9262-1-git-send-email-lee.jones@linaro.org> References: <1357909986-9262-1-git-send-email-lee.jones@linaro.org> X-Gm-Message-State: ALoCoQmy42f/i774j2/UQZv8G+O4q8/0qJPcwbHgnlGdtxcvGvJn4bzONfRJsi9j3jH4fgHx+vpL From: Johan Bjornstedt When enabling the CCEOC irq we might get false interrupt from ab8500-driver due to the latched value will be saved and interpreted as an IRQ when enabled Signed-off-by: Lee Jones Signed-off-by: Johan Bjornstedt Signed-off-by: Henrik Solver Reviewed-by: Karl KOMIEROWSKI --- drivers/power/ab8500_btemp.c | 11 +++--- drivers/power/ab8500_fg.c | 63 +++++++++++++++++++++++++++++----- include/linux/mfd/abx500/ab8500-bm.h | 7 ++++ 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index 158cba5..efeb6dd 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -374,13 +374,10 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) return ret; } - /* - * Since there is no interrupt when current measurement is done, - * loop for over 250ms (250ms is one sample conversion time - * with 32.768 Khz RTC clock). Note that a stop time must be set - * since the ab8500_btemp_read_batctrl_voltage call can block and - * take an unknown amount of time to complete. - */ + do { + msleep(20); + } while (!ab8500_fg_inst_curr_started(di->fg)); + i = 0; do { diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index df681a8..828529e 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -160,6 +160,7 @@ struct inst_curr_result_list { * @recovery_cnt: Counter for recovery mode * @high_curr_cnt: Counter for high current mode * @init_cnt: Counter for init mode + * @nbr_cceoc_irq_cnt Counter for number of CCEOC irqs received since enabled * @recovery_needed: Indicate if recovery is needed * @high_curr_mode: Indicate if we're in high current mode * @init_capacity: Indicate if initial capacity measuring should be done @@ -167,6 +168,7 @@ struct inst_curr_result_list { * @calib_state State during offset calibration * @discharge_state: Current discharge state * @charge_state: Current charge state + * @ab8500_fg_started Completion struct used for the instant current start * @ab8500_fg_complete Completion struct used for the instant current reading * @flags: Structure for information about events triggered * @bat_cap: Structure for battery capacity specific parameters @@ -199,6 +201,7 @@ struct ab8500_fg { int recovery_cnt; int high_curr_cnt; int init_cnt; + int nbr_cceoc_irq_cnt; bool recovery_needed; bool high_curr_mode; bool init_capacity; @@ -206,6 +209,7 @@ struct ab8500_fg { enum ab8500_fg_calibration_state calib_state; enum ab8500_fg_discharge_state discharge_state; enum ab8500_fg_charge_state charge_state; + struct completion ab8500_fg_started; struct completion ab8500_fg_complete; struct ab8500_fg_flags flags; struct ab8500_fg_battery_capacity bat_cap; @@ -524,13 +528,14 @@ cc_err: * Note: This is part "one" and has to be called before * ab8500_fg_inst_curr_finalize() */ - int ab8500_fg_inst_curr_start(struct ab8500_fg *di) +int ab8500_fg_inst_curr_start(struct ab8500_fg *di) { u8 reg_val; int ret; mutex_lock(&di->cc_lock); + di->nbr_cceoc_irq_cnt = 0; ret = abx500_get_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_CC_CONF_REG, ®_val); if (ret < 0) @@ -558,6 +563,7 @@ cc_err: } /* Return and WFI */ + INIT_COMPLETION(di->ab8500_fg_started); INIT_COMPLETION(di->ab8500_fg_complete); enable_irq(di->irq); @@ -569,6 +575,17 @@ fail: } /** + * ab8500_fg_inst_curr_started() - check if fg conversion has started + * @di: pointer to the ab8500_fg structure + * + * Returns 1 if conversion started, 0 if still waiting + */ +int ab8500_fg_inst_curr_started(struct ab8500_fg *di) +{ + return completion_done(&di->ab8500_fg_started); +} + +/** * ab8500_fg_inst_curr_done() - check if fg conversion is done * @di: pointer to the ab8500_fg structure * @@ -596,13 +613,15 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) int timeout; if (!completion_done(&di->ab8500_fg_complete)) { - timeout = wait_for_completion_timeout(&di->ab8500_fg_complete, + timeout = wait_for_completion_timeout( + &di->ab8500_fg_complete, INS_CURR_TIMEOUT); dev_dbg(di->dev, "Finalize time: %d ms\n", ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ); if (!timeout) { ret = -ETIME; disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; dev_err(di->dev, "completion timed out [%d]\n", __LINE__); goto fail; @@ -610,6 +629,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res) } disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, @@ -684,6 +704,7 @@ fail: int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) { int ret; + int timeout; int res = 0; ret = ab8500_fg_inst_curr_start(di); @@ -692,13 +713,32 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di) return 0; } + /* Wait for CC to actually start */ + if (!completion_done(&di->ab8500_fg_started)) { + timeout = wait_for_completion_timeout( + &di->ab8500_fg_started, + INS_CURR_TIMEOUT); + dev_dbg(di->dev, "Start time: %d ms\n", + ((INS_CURR_TIMEOUT - timeout) * 1000) / HZ); + if (!timeout) { + ret = -ETIME; + dev_err(di->dev, "completion timed out [%d]\n", + __LINE__); + goto fail; + } + } + ret = ab8500_fg_inst_curr_finalize(di, &res); if (ret) { dev_err(di->dev, "Failed to finalize fg_inst\n"); return 0; } + dev_dbg(di->dev, "%s instant current: %d", __func__, res); return res; +fail: + mutex_unlock(&di->cc_lock); + return ret; } /** @@ -1523,8 +1563,6 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di) case AB8500_FG_DISCHARGE_WAKEUP: ab8500_fg_coulomb_counter(di, true); - di->inst_curr = ab8500_fg_inst_curr_blocking(di); - ab8500_fg_calc_cap_discharge_voltage(di, true); di->fg_samples = SEC_TO_SAMPLE( @@ -1641,8 +1679,6 @@ static void ab8500_fg_periodic_work(struct work_struct *work) fg_periodic_work.work); if (di->init_capacity) { - /* A dummy read that will return 0 */ - di->inst_curr = ab8500_fg_inst_curr_blocking(di); /* Get an initial capacity calculation */ ab8500_fg_calc_cap_discharge_voltage(di, true); ab8500_fg_check_capacity_limits(di, true); @@ -1828,7 +1864,13 @@ static void ab8500_fg_instant_work(struct work_struct *work) static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di) { struct ab8500_fg *di = _di; - complete(&di->ab8500_fg_complete); + if (!di->nbr_cceoc_irq_cnt) { + di->nbr_cceoc_irq_cnt++; + complete(&di->ab8500_fg_started); + } else { + di->nbr_cceoc_irq_cnt = 0; + complete(&di->ab8500_fg_complete); + } return IRQ_HANDLED; } @@ -2551,7 +2593,11 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->fg_samples = SEC_TO_SAMPLE(di->bm->fg_params->init_timer); ab8500_fg_coulomb_counter(di, true); - /* Initialize completion used to notify completion of inst current */ + /* + * Initialize completion used to notify completion and start + * of inst current + */ + init_completion(&di->ab8500_fg_started); init_completion(&di->ab8500_fg_complete); /* Register interrupts */ @@ -2571,6 +2617,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) } di->irq = platform_get_irq_byname(pdev, "CCEOC"); disable_irq(di->irq); + di->nbr_cceoc_irq_cnt = 0; platform_set_drvdata(pdev, di); diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h index 44310c9..6c6a02e 100644 --- a/include/linux/mfd/abx500/ab8500-bm.h +++ b/include/linux/mfd/abx500/ab8500-bm.h @@ -431,11 +431,18 @@ struct ab8500_fg *ab8500_fg_get(void); int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev); int ab8500_fg_inst_curr_start(struct ab8500_fg *di); int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res); +int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); #else +int ab8500_fg_inst_curr_started(struct ab8500_fg *di) +{ + return 0; +} + int ab8500_fg_inst_curr_done(struct ab8500_fg *di) { + return 0; } static void ab8500_fg_reinit(void) {