From patchwork Mon May 4 00:00:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Cernekee X-Patchwork-Id: 6322461 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 3102ABEEE1 for ; Mon, 4 May 2015 00:01:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 163572026F for ; Mon, 4 May 2015 00:01:20 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id C14F720380 for ; Mon, 4 May 2015 00:01:18 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id CD6F42607C8; Mon, 4 May 2015 02:01:17 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id E4A4C260590; Mon, 4 May 2015 02:00:50 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 7091A2605EC; Mon, 4 May 2015 02:00:49 +0200 (CEST) Received: from mail-ig0-f180.google.com (mail-ig0-f180.google.com [209.85.213.180]) by alsa0.perex.cz (Postfix) with ESMTP id 533D1260590 for ; Mon, 4 May 2015 02:00:42 +0200 (CEST) Received: by igblo3 with SMTP id lo3so72343700igb.1 for ; Sun, 03 May 2015 17:00:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tbpFSpoI7rDJj1cH61+oMvyOHidodHp+VhufYSYTN6g=; b=CHlI1qwZoqdfocLiMjbmB5QHEv0y4KTDw+u32KIq1HksjaxGURr+NJBKwo+fX43z7f Deemp7tkorHO5r94YUp2JmjdCqL9y1uEy9lHtBHr87d/ubQvMWzYjp1bOHqbjWAA6jjC SIGqkookQdv2m9DpjareSVsfJo6KSg0fIdGNl/sHHg5osbStDztYWF2VB5eVPczVmvLK BiqhNbOPKT+k3wMj0wscbiFfhZMUoQcjyqwzF7XOzN5jabngyj5bo6LwnZ+VXxkWS4dv IisikbsxfZVu62P5ndUa6BpHFFnnQGeECglurmDAAYt9NS2e0/ZtLAqp55EbeHR4NwLj vmPA== X-Gm-Message-State: ALoCoQmvwE9zvEpo/m8zkEXZaB7xo7jIIQPo17zsYQTUYLMMsIdwjfg5hD2P+tcFWAN0te76H8j9 X-Received: by 10.43.89.133 with SMTP id be5mr25373985icc.2.1430697639292; Sun, 03 May 2015 17:00:39 -0700 (PDT) Received: from kcl.mtv.corp.google.com ([172.22.66.15]) by mx.google.com with ESMTPSA id 37sm8580423ioj.0.2015.05.03.17.00.37 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 03 May 2015 17:00:38 -0700 (PDT) From: Kevin Cernekee To: lgirdwood@gmail.com, broonie@kernel.org Date: Sun, 3 May 2015 17:00:16 -0700 Message-Id: <1430697619-22773-2-git-send-email-cernekee@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c In-Reply-To: <1430697619-22773-1-git-send-email-cernekee@chromium.org> References: <1430697619-22773-1-git-send-email-cernekee@chromium.org> Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, lars@metafoo.de, abrestic@chromium.org, linux-kernel@vger.kernel.org, dgreid@chromium.org, olofj@chromium.org Subject: [alsa-devel] [PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal "no_sync_defaults" regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map->reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown Signed-off-by: Kevin Cernekee --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 61 ++++++++++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..b2b2849fc6d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -131,7 +131,10 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; + /* if set, the cache contains newer data than the HW */ u32 cache_dirty; + /* if set, the HW registers are known to match map->reg_defaults */ + bool no_sync_defaults; struct reg_default *patch; int patch_regs; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..63af3103d0c6 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { unsigned int reg; + bool no_sync_defaults = map->no_sync_defaults; + + map->no_sync_defaults = false; for (reg = min; reg <= max; reg += map->reg_stride) { unsigned int val; @@ -266,10 +269,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret >= 0 && val == map->reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret >= 0 && val == map->reg_defaults[ret].def) + continue; + } map->cache_bypass = 1; ret = _regmap_write(map, reg, val); @@ -461,18 +466,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map->lock(map->lock_arg); map->cache_dirty = true; + map->no_sync_defaults = true; map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); @@ -604,6 +614,9 @@ static int regcache_sync_block_single(struct regmap *map, void *block, { unsigned int i, regtmp, val; int ret; + bool no_sync_defaults = map->no_sync_defaults; + + map->no_sync_defaults = false; for (i = start; i < end; i++) { regtmp = block_base + (i * map->reg_stride); @@ -614,10 +627,12 @@ static int regcache_sync_block_single(struct regmap *map, void *block, val = regcache_get_val(map, block, i); - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, regtmp); + if (ret >= 0 && val == map->reg_defaults[ret].def) + continue; + } map->cache_bypass = 1; @@ -674,6 +689,9 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, unsigned int base = 0; const void *data = NULL; int ret; + bool no_sync_defaults = map->no_sync_defaults; + + map->no_sync_defaults = false; for (i = start; i < end; i++) { regtmp = block_base + (i * map->reg_stride); @@ -689,14 +707,17 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, val = regcache_get_val(map, block, i); - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) { - ret = regcache_sync_block_raw_flush(map, &data, - base, regtmp); - if (ret != 0) - return ret; - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, regtmp); + if (ret >= 0 && val == map->reg_defaults[ret].def) { + ret = regcache_sync_block_raw_flush(map, &data, + base, + regtmp); + if (ret != 0) + return ret; + continue; + } } if (!data) {