From patchwork Fri Apr 24 22:36:45 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Cernekee X-Patchwork-Id: 6273781 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 0BF479F389 for ; Fri, 24 Apr 2015 22:37:53 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A276D20274 for ; Fri, 24 Apr 2015 22:37:51 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id D9E842026F for ; Fri, 24 Apr 2015 22:37:49 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 0B2A0261555; Sat, 25 Apr 2015 00:37:49 +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,NO_DNS_FOR_FROM, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 818FF2606CA; Sat, 25 Apr 2015 00:37:16 +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 D4DC2261293; Sat, 25 Apr 2015 00:37:14 +0200 (CEST) Received: from mail-ig0-f178.google.com (mail-ig0-f178.google.com [209.85.213.178]) by alsa0.perex.cz (Postfix) with ESMTP id B50B22606CA for ; Sat, 25 Apr 2015 00:37:07 +0200 (CEST) Received: by igbyr2 with SMTP id yr2so26605246igb.0 for ; Fri, 24 Apr 2015 15:37:06 -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=v/bJIs7ifQOLnhG5jAwkkOv0h5AOzLBZisvG2oMBegw=; b=O9+ke57lhHXw+ZOy3su2noyfoxc83b7+bvBRi6gcZ0JlJ8NiREOzAf0dBr1Kk3dmOQ TgKBjNgMmlhr+rgRiRyBBLP3kKOkndKhmzIIDcDHzm5D8zXjW/KVJ3dKxSW9CJnB//kG /xXg7D29bSBubTQPheeKi+h65PCwFaVFIHeTHIforpaQQI6vhobLQ7K2gf9DOWD3O//C 0/yrhCwm92qqwhmjz/gsAVIm9qGvEuah6q9Zc2xs2s05LhmcmKEFKr4E5vEmGHfeCXjH 11Pkx0scZPfApRvoUgUFBSHEY7AKdg4NVNjBaA4FuHa/yikXw5pWyH/Dw94tdNub/OtK a+Rw== X-Gm-Message-State: ALoCoQkPKqHpVsxrhDNELqXegO4yMT6lPo0IOVZ+SnQ0Ofa6JKraKL0mPDH6MET4RLchC1VHSjeD X-Received: by 10.50.77.13 with SMTP id o13mr227537igw.39.1429915026807; Fri, 24 Apr 2015 15:37:06 -0700 (PDT) Received: from kcl.mtv.corp.google.com ([172.22.66.15]) by mx.google.com with ESMTPSA id r4sm482854igw.12.2015.04.24.15.37.04 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 24 Apr 2015 15:37:05 -0700 (PDT) From: Kevin Cernekee To: lgirdwood@gmail.com, broonie@kernel.org Date: Fri, 24 Apr 2015 15:36:45 -0700 Message-Id: <1429915008-22015-2-git-send-email-cernekee@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c In-Reply-To: <1429915008-22015-1-git-send-email-cernekee@chromium.org> References: <1429915008-22015-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 V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region() 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 regcache_sync() and regcache_sync_region() currently assume that the hardware has just emerged from a clean reset, and that all registers are in their default states. But that isn't the only possibility; the device may have been in a different state in which the registers were inaccessible but have retained their contents, e.g. clock gating. So we will extend the more versatile of the two functions, regcache_sync_region(), to let the caller decide what assumptions should be made. One driver that can benefit from this is adau1977, which has hacks to overwrite the registers that regcache_sync() might have missed. Also, the powerdown pin on tas571x does not reset the register contents either, so a similar feature will be required by that driver. This commit just adds the new argument by changing the function declarations and call sites, but doesn't wire it up yet. Signed-off-by: Kevin Cernekee --- drivers/base/regmap/internal.h | 5 ++- drivers/base/regmap/regcache-lzo.c | 2 +- drivers/base/regmap/regcache-rbtree.c | 5 ++- drivers/base/regmap/regcache.c | 75 ++++++++++++++++++++--------------- drivers/media/radio/radio-si476x.c | 18 ++++++--- drivers/mfd/wm8994-core.c | 5 ++- include/linux/regmap.h | 4 +- include/sound/hda_regmap.h | 3 +- sound/soc/codecs/wm8962.c | 3 +- 9 files changed, 72 insertions(+), 48 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..89dfefeb168e 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -155,7 +155,8 @@ struct regcache_ops { #endif int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); int (*write)(struct regmap *map, unsigned int reg, unsigned int value); - int (*sync)(struct regmap *map, unsigned int min, unsigned int max); + int (*sync)(struct regmap *map, unsigned int min, unsigned int max, + bool was_reset); int (*drop)(struct regmap *map, unsigned int min, unsigned int max); }; @@ -215,7 +216,7 @@ int regcache_sync(struct regmap *map); int regcache_sync_block(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, unsigned int start, - unsigned int end); + unsigned int end, bool was_reset); static inline const void *regcache_get_val_addr(struct regmap *map, const void *base, diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index 2d53f6f138e1..52ed0d03ce69 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c @@ -332,7 +332,7 @@ out: } static int regcache_lzo_sync(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { struct regcache_lzo_ctx **lzo_blocks; unsigned int val; diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 81751a49d8bf..8fc1727e635c 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -445,7 +445,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, } static int regcache_rbtree_sync(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { struct regcache_rbtree_ctx *rbtree_ctx; struct rb_node *node; @@ -477,7 +477,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, ret = regcache_sync_block(map, rbnode->block, rbnode->cache_present, - rbnode->base_reg, start, end); + rbnode->base_reg, start, end, + was_reset); if (ret != 0) return ret; } diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..d27b45f50497 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -250,7 +250,7 @@ int regcache_write(struct regmap *map, } static int regcache_default_sync(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { unsigned int reg; @@ -266,10 +266,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 (was_reset) { + /* 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); @@ -294,6 +296,10 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, * volatile. In general drivers can choose not to use the provided * syncing functionality if they so require. * + * This assumes that the hardware registers contain their default values. + * If the cached value matches the default value for a register, the write + * operation will be skipped. + * * Return a negative value on failure, 0 on success. */ int regcache_sync(struct regmap *map) @@ -331,9 +337,9 @@ int regcache_sync(struct regmap *map) map->cache_bypass = 0; if (map->cache_ops->sync) - ret = map->cache_ops->sync(map, 0, map->max_register); + ret = map->cache_ops->sync(map, 0, map->max_register, true); else - ret = regcache_default_sync(map, 0, map->max_register); + ret = regcache_default_sync(map, 0, map->max_register, true); if (ret == 0) map->cache_dirty = false; @@ -353,19 +359,18 @@ out: EXPORT_SYMBOL_GPL(regcache_sync); /** - * regcache_sync_region: Sync part of the register cache with the hardware. + * regcache_sync_region: Sync part of the register cache with the hardware. * * @map: map to sync. * @min: first register to sync * @max: last register to sync - * - * Write all non-default register values in the specified region to - * the hardware. + * @was_reset: true if the hardware is known to contain default register values + * in the given range; false otherwise * * Return a negative value on failure, 0 on success. */ int regcache_sync_region(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { int ret = 0; const char *name; @@ -389,9 +394,9 @@ int regcache_sync_region(struct regmap *map, unsigned int min, map->async = true; if (map->cache_ops->sync) - ret = map->cache_ops->sync(map, min, max); + ret = map->cache_ops->sync(map, min, max, was_reset); else - ret = regcache_default_sync(map, min, max); + ret = regcache_default_sync(map, min, max, was_reset); out: /* Restore the bypass state */ @@ -600,7 +605,8 @@ static bool regcache_reg_present(unsigned long *cache_present, unsigned int idx) static int regcache_sync_block_single(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, - unsigned int start, unsigned int end) + unsigned int start, unsigned int end, + bool was_reset) { unsigned int i, regtmp, val; int ret; @@ -614,10 +620,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 (was_reset) { + /* 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; @@ -667,7 +675,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, static int regcache_sync_block_raw(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, unsigned int start, - unsigned int end) + unsigned int end, bool was_reset) { unsigned int i, val; unsigned int regtmp = 0; @@ -689,14 +697,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 (was_reset) { + /* 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) { @@ -712,12 +723,14 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, int regcache_sync_block(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, unsigned int start, - unsigned int end) + unsigned int end, bool was_reset) { if (regmap_can_raw_write(map) && !map->use_single_rw) return regcache_sync_block_raw(map, block, cache_present, - block_base, start, end); + block_base, start, end, + was_reset); else return regcache_sync_block_single(map, block, cache_present, - block_base, start, end); + block_base, start, end, + was_reset); } diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index dccf58691650..ff4785f0416d 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -567,19 +567,22 @@ static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, /* regcache_mark_dirty(radio->core->regmap); */ err = regcache_sync_region(radio->core->regmap, SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); + SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT, + true); if (err < 0) return err; err = regcache_sync_region(radio->core->regmap, SI476X_PROP_AUDIO_DEEMPHASIS, - SI476X_PROP_AUDIO_PWR_LINE_FILTER); + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + true); if (err < 0) return err; err = regcache_sync_region(radio->core->regmap, SI476X_PROP_INT_CTL_ENABLE, - SI476X_PROP_INT_CTL_ENABLE); + SI476X_PROP_INT_CTL_ENABLE, + true); if (err < 0) return err; @@ -589,13 +592,15 @@ static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, */ err = regcache_sync_region(radio->core->regmap, SI476X_PROP_VALID_MAX_TUNE_ERROR, - SI476X_PROP_VALID_MAX_TUNE_ERROR); + SI476X_PROP_VALID_MAX_TUNE_ERROR, + true); if (err < 0) return err; err = regcache_sync_region(radio->core->regmap, SI476X_PROP_VALID_SNR_THRESHOLD, - SI476X_PROP_VALID_RSSI_THRESHOLD); + SI476X_PROP_VALID_RSSI_THRESHOLD, + true); if (err < 0) return err; @@ -609,7 +614,8 @@ static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, err = regcache_sync_region(radio->core->regmap, SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, - SI476X_PROP_FM_RDS_CONFIG); + SI476X_PROP_FM_RDS_CONFIG, + true); if (err < 0) return err; } diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 53ae5af5d6e4..d5632634a362 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -158,14 +158,15 @@ static int wm8994_suspend(struct device *dev) * pin configurations. */ ret = regcache_sync_region(wm8994->regmap, WM8994_GPIO_1, - WM8994_GPIO_11); + WM8994_GPIO_11, true); if (ret != 0) dev_err(dev, "Failed to restore GPIO registers: %d\n", ret); /* In case one of the GPIOs is used as a wake input. */ ret = regcache_sync_region(wm8994->regmap, WM8994_INTERRUPT_STATUS_1_MASK, - WM8994_INTERRUPT_STATUS_1_MASK); + WM8994_INTERRUPT_STATUS_1_MASK, + true); if (ret != 0) dev_err(dev, "Failed to restore interrupt mask: %d\n", ret); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 116655d92269..ece122a6fdeb 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -438,7 +438,7 @@ bool regmap_can_raw_write(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, - unsigned int max); + unsigned int max, bool was_reset); int regcache_drop_region(struct regmap *map, unsigned int min, unsigned int max); void regcache_cache_only(struct regmap *map, bool enable); @@ -683,7 +683,7 @@ static inline int regcache_sync(struct regmap *map) } static inline int regcache_sync_region(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { WARN_ONCE(1, "regmap API is disabled"); return -EINVAL; diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h index 53a18b3635e2..f6bb68137ca4 100644 --- a/include/sound/hda_regmap.h +++ b/include/sound/hda_regmap.h @@ -211,7 +211,8 @@ static inline void snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid) { regcache_mark_dirty(codec->regmap); - regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1); + regcache_sync_region(codec->regmap, nid << 20, + ((nid + 1) << 20) - 1, true); } #endif /* __SOUND_HDA_REGMAP_H */ diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 118b0034ba23..3a25d2d93705 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1483,7 +1483,8 @@ static int wm8962_dsp2_write_config(struct snd_soc_codec *codec) struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); return regcache_sync_region(wm8962->regmap, - WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER); + WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER, + true); } static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)