From 77f5f3e9c86dc4604366a567819cc3ec4bdb4400 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Apr 2015 21:52:10 +0900 Subject: [PATCH 1/7] regmap: Constify irq_domain_ops The irq_domain_ops are not modified by the driver and the irqdomain core code accepts pointer to a const data. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index a6c3f75b4b01..e7273bb890be 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -318,7 +318,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops regmap_domain_ops = { +static const struct irq_domain_ops regmap_domain_ops = { .map = regmap_irq_map, .xlate = irq_domain_xlate_twocell, }; From 3969fa080661dcdf20d04392b900189086e04c2c Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 5 May 2015 15:14:13 -0700 Subject: [PATCH 2/7] regmap: Add a helper function for regcache sync test We're going to add another "does this register need syncing?" check, so rather than repeating it in three places, we'll separate all of the relevant logic into a helper function. Signed-off-by: Kevin Cernekee Signed-off-by: Mark Brown --- drivers/base/regmap/regcache.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..c58493eaf050 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -249,6 +249,18 @@ int regcache_write(struct regmap *map, return 0; } +static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, + unsigned int val) +{ + int ret; + + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret >= 0 && val == map->reg_defaults[ret].def) + return false; + return true; +} + static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { @@ -266,9 +278,7 @@ 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) + if (!regcache_reg_needs_sync(map, reg, val)) continue; map->cache_bypass = 1; @@ -613,10 +623,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block, continue; 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) + if (!regcache_reg_needs_sync(map, regtmp, val)) continue; map->cache_bypass = 1; @@ -688,10 +695,7 @@ 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) { + if (!regcache_reg_needs_sync(map, regtmp, val)) { ret = regcache_sync_block_raw_flush(map, &data, base, regtmp); if (ret != 0) From 1c79771a7270278e6ff486edf4dfeb8c4fc01ee0 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Tue, 5 May 2015 15:14:14 -0700 Subject: [PATCH 3/7] regmap: Use regcache_mark_dirty() to indicate power loss or reset 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 Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 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 c58493eaf050..b9862d741a56 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -254,6 +254,10 @@ static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, { int ret; + /* If we don't know the chip just got reset, then sync everything. */ + if (!map->no_sync_defaults) + return true; + /* Is this the hardware default? If so skip. */ ret = regcache_lookup_reg(map, reg); if (ret >= 0 && val == map->reg_defaults[ret].def) @@ -352,6 +356,7 @@ out: /* Restore the bypass state */ map->async = false; map->cache_bypass = bypass; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -407,6 +412,7 @@ out: /* Restore the bypass state */ map->cache_bypass = bypass; map->async = false; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -471,18 +477,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); From 668abc729fcb9d034eccadf63166d2c76cd645d1 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 21 May 2015 17:42:43 +0100 Subject: [PATCH 4/7] regmap: Introduce regmap_get_max_register This patch introduces regmap_get_max_register() function which would be used by the infrastructures like nvmem framework built on top of regmap. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 12 ++++++++++++ include/linux/regmap.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6273ff072f3e..d6c84047b957 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2613,6 +2613,18 @@ int regmap_get_val_bytes(struct regmap *map) } EXPORT_SYMBOL_GPL(regmap_get_val_bytes); +/** + * regmap_get_max_register(): Report the max register value + * + * Report the max register value, mainly intended to for use by + * generic infrastructure built on top of regmap. + */ +int regmap_get_max_register(struct regmap *map) +{ + return map->max_register ? map->max_register : -EINVAL; +} +EXPORT_SYMBOL_GPL(regmap_get_max_register); + int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val) { diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 116655d92269..2d87deda79cd 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); int regmap_get_val_bytes(struct regmap *map); +int regmap_get_max_register(struct regmap *map); int regmap_async_complete(struct regmap *map); bool regmap_can_raw_write(struct regmap *map); @@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map) return -EINVAL; } +static inline int regmap_get_max_register(struct regmap *map) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regcache_sync(struct regmap *map) { WARN_ONCE(1, "regmap API is disabled"); From a2f776cbb8271d7149784207da0b0c51e8b1847c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 21 May 2015 17:42:54 +0100 Subject: [PATCH 5/7] regmap: Introduce regmap_get_reg_stride This patch introduces regmap_get_reg_stride() function which would be used by the infrastructures like nvmem framework built on top of regmap. Mostly this function would be used for sanity checks on inputs within such infrastructure. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 12 ++++++++++++ include/linux/regmap.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d6c84047b957..e5eef6f1408a 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2625,6 +2625,18 @@ int regmap_get_max_register(struct regmap *map) } EXPORT_SYMBOL_GPL(regmap_get_max_register); +/** + * regmap_get_reg_stride(): Report the register address stride + * + * Report the register address stride, mainly intended to for use by + * generic infrastructure built on top of regmap. + */ +int regmap_get_reg_stride(struct regmap *map) +{ + return map->reg_stride; +} +EXPORT_SYMBOL_GPL(regmap_get_reg_stride); + int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val) { diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 2d87deda79cd..59c55ea0f0b5 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, bool *change); int regmap_get_val_bytes(struct regmap *map); int regmap_get_max_register(struct regmap *map); +int regmap_get_reg_stride(struct regmap *map); int regmap_async_complete(struct regmap *map); bool regmap_can_raw_write(struct regmap *map); @@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map) return -EINVAL; } +static inline int regmap_get_reg_stride(struct regmap *map) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regcache_sync(struct regmap *map) { WARN_ONCE(1, "regmap API is disabled"); From 7043f5fb20b564f547d187f58725dbe75b942535 Mon Sep 17 00:00:00 2001 From: dashsriram Date: Wed, 27 May 2015 00:55:13 +0530 Subject: [PATCH 6/7] regmap: irq: Fixed a typo error Fixed a typo error in the file Signed-off-by: Sriram Dash Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index e7273bb890be..956e125c4680 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -109,7 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) if (!d->chip->init_ack_masked) continue; /* - * Ack all the masked interrupts uncondictionly, + * Ack all the masked interrupts unconditionally, * OR if there is masked interrupt which hasn't been Acked, * it'll be ignored in irq handler, then may introduce irq storm */ From e723f2ceb1ab571c660b1a1db31cb71aa2c0b29d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Jun 2015 13:26:28 -0500 Subject: [PATCH 7/7] regmap: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also set IRQ_NOPROBE and this has been maintained although it is not clear that is really needed. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 956e125c4680..2597600a5d26 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -306,14 +306,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, data); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); - - /* ARM needs us to explicitly flag the IRQ as valid - * and will set them noprobe when we do so. */ -#ifdef CONFIG_ARM - set_irq_flags(virq, IRQF_VALID); -#else irq_set_noprobe(virq); -#endif return 0; }