All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const
@ 2014-02-25 13:45 Charles Keepax
  2014-02-25 13:45 ` [PATCH 2/4] regmap: Add bypassed version of regmap_multi_reg_write Charles Keepax
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Charles Keepax @ 2014-02-25 13:45 UTC (permalink / raw)
  To: broonie; +Cc: gregkh, sameo, lee.jones, linux-kernel, patches

There should be no need for the writes supplied to this function to be
edited by it so mark them as const.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |    4 ++--
 include/linux/regmap.h       |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 2b4e72f..1ebc6df 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1607,8 +1607,8 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
  */
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
-				int num_regs)
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+			   int num_regs)
 {
 	int ret = 0, i;
 
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index fa4d079..ccb2ed0 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -388,7 +388,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 		     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 			size_t val_count);
-int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
 			int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 			   const void *val, size_t val_len);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] regmap: Add bypassed version of regmap_multi_reg_write
  2014-02-25 13:45 [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Charles Keepax
@ 2014-02-25 13:45 ` Charles Keepax
  2014-02-25 13:45 ` [PATCH 3/4] regmap: Base regmap_register_patch on _regmap_multi_reg_write Charles Keepax
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Charles Keepax @ 2014-02-25 13:45 UTC (permalink / raw)
  To: broonie; +Cc: gregkh, sameo, lee.jones, linux-kernel, patches

Devices with more complex boot proceedures may occasionally apply the
register patch manual. regmap_multi_reg_write is a logical way to do so,
however the patch must be applied with cache bypass on, such that it
doesn't override any user settings. This patch adds a
regmap_multi_reg_write_bypassed function that applies a set of writes
with the bypass enabled.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |   75 ++++++++++++++++++++++++++++++++++-------
 include/linux/regmap.h       |    3 ++
 2 files changed, 65 insertions(+), 13 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 1ebc6df..6b07a97 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1591,6 +1591,26 @@ out:
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_write);
 
+static int _regmap_multi_reg_write(struct regmap *map,
+				   const struct reg_default *regs,
+				   int num_regs)
+{
+	int i, ret;
+
+	for (i = 0; i < num_regs; i++) {
+		if (regs[i].reg % map->reg_stride)
+			return -EINVAL;
+		ret = _regmap_write(map, regs[i].reg, regs[i].def);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to write %x = %x: %d\n",
+				regs[i].reg, regs[i].def, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * regmap_multi_reg_write(): Write multiple registers to the device
  *
@@ -1610,28 +1630,57 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
 int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
 			   int num_regs)
 {
-	int ret = 0, i;
-
-	for (i = 0; i < num_regs; i++) {
-		int reg = regs[i].reg;
-		if (reg % map->reg_stride)
-			return -EINVAL;
-	}
+	int ret;
 
 	map->lock(map->lock_arg);
 
-	for (i = 0; i < num_regs; i++) {
-		ret = _regmap_write(map, regs[i].reg, regs[i].def);
-		if (ret != 0)
-			goto out;
-	}
-out:
+	ret = _regmap_multi_reg_write(map, regs, num_regs);
+
 	map->unlock(map->lock_arg);
 
 	return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
 
+/*
+ * regmap_multi_reg_write_bypassed(): Write multiple registers to the
+ *                                    device but not the cache
+ *
+ * where the set of register are supplied in any order
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * This function is intended to be used for writing a large block of data
+ * atomically to the device in single transfer for those I2C client devices
+ * that implement this alternative block write mode.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+				    const struct reg_default *regs,
+				    int num_regs)
+{
+	int ret;
+	bool bypass;
+
+	map->lock(map->lock_arg);
+
+	bypass = map->cache_bypass;
+	map->cache_bypass = true;
+
+	ret = _regmap_multi_reg_write(map, regs, num_regs);
+
+	map->cache_bypass = bypass;
+
+	map->unlock(map->lock_arg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
+
 /**
  * regmap_raw_write_async(): Write raw values to one or more registers
  *                           asynchronously
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index ccb2ed0..15a6c2c 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -390,6 +390,9 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 			size_t val_count);
 int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
 			int num_regs);
+int regmap_multi_reg_write_bypassed(struct regmap *map,
+				    const struct reg_default *regs,
+				    int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
 			   const void *val, size_t val_len);
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] regmap: Base regmap_register_patch on _regmap_multi_reg_write
  2014-02-25 13:45 [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Charles Keepax
  2014-02-25 13:45 ` [PATCH 2/4] regmap: Add bypassed version of regmap_multi_reg_write Charles Keepax
@ 2014-02-25 13:45 ` Charles Keepax
  2014-02-25 13:45 ` [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch Charles Keepax
  2014-02-25 23:58 ` [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Mark Brown
  3 siblings, 0 replies; 6+ messages in thread
From: Charles Keepax @ 2014-02-25 13:45 UTC (permalink / raw)
  To: broonie; +Cc: gregkh, sameo, lee.jones, linux-kernel, patches

Since we now have an internal version of regmap_multi_reg_write use this
to apply the register patch.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |   18 ++++--------------
 1 files changed, 4 insertions(+), 14 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6b07a97..0e5c833 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2245,7 +2245,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 			  int num_regs)
 {
 	struct reg_default *p;
-	int i, ret;
+	int ret;
 	bool bypass;
 
 	if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n",
@@ -2259,19 +2259,9 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 	map->cache_bypass = true;
 	map->async = true;
 
-	/* Write out first; it's useful to apply even if we fail later. */
-	for (i = 0; i < num_regs; i++) {
-		if (regs[i].reg % map->reg_stride) {
-			ret = -EINVAL;
-			goto out;
-		}
-		ret = _regmap_write(map, regs[i].reg, regs[i].def);
-		if (ret != 0) {
-			dev_err(map->dev, "Failed to write %x = %x: %d\n",
-				regs[i].reg, regs[i].def, ret);
-			goto out;
-		}
-	}
+	ret = _regmap_multi_reg_write(map, regs, num_regs);
+	if (ret != 0)
+		goto out;
 
 	p = krealloc(map->patch,
 		     sizeof(struct reg_default) * (map->patch_regs + num_regs),
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch
  2014-02-25 13:45 [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Charles Keepax
  2014-02-25 13:45 ` [PATCH 2/4] regmap: Add bypassed version of regmap_multi_reg_write Charles Keepax
  2014-02-25 13:45 ` [PATCH 3/4] regmap: Base regmap_register_patch on _regmap_multi_reg_write Charles Keepax
@ 2014-02-25 13:45 ` Charles Keepax
  2014-02-25 14:27   ` Lee Jones
  2014-02-25 23:58 ` [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Mark Brown
  3 siblings, 1 reply; 6+ messages in thread
From: Charles Keepax @ 2014-02-25 13:45 UTC (permalink / raw)
  To: broonie; +Cc: gregkh, sameo, lee.jones, linux-kernel, patches

On the wm5102 the register patches are applied manually, rather than by
the regmap core. This application is wrapped in calls to
regcache_cache_bypass. However, this is dangerous as other threads may
be accessing the hardware at the same time as the pm_runtime operations
and if they do so during the period whilst cache_bypass is enabled those
writes will miss the cache when they shouldn't.

Apply the register patch using the new regmap_multi_reg_write_bypassed
function to avoid this problem. Also remove the call to
regcache_cache_bypass from the hardware patch application as it is
unneeded there and creates a similar window for writes to miss the
cache.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/mfd/arizona-core.c  |    4 ----
 drivers/mfd/wm5102-tables.c |   21 ++++-----------------
 2 files changed, 4 insertions(+), 21 deletions(-)

diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index a45aab9..1c3ae57 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -251,8 +251,6 @@ static int arizona_apply_hardware_patch(struct arizona* arizona)
 	unsigned int fll, sysclk;
 	int ret, err;
 
-	regcache_cache_bypass(arizona->regmap, true);
-
 	/* Cache existing FLL and SYSCLK settings */
 	ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll);
 	if (ret != 0) {
@@ -322,8 +320,6 @@ err_fll:
 			err);
 	}
 
-	regcache_cache_bypass(arizona->regmap, false);
-
 	if (ret != 0)
 		return ret;
 	else
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 1e9a4b2..bffc584 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -80,8 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
 int wm5102_patch(struct arizona *arizona)
 {
 	const struct reg_default *wm5102_patch;
-	int ret = 0;
-	int i, patch_size;
+	int patch_size;
 
 	switch (arizona->rev) {
 	case 0:
@@ -92,21 +91,9 @@ int wm5102_patch(struct arizona *arizona)
 		patch_size = ARRAY_SIZE(wm5102_revb_patch);
 	}
 
-	regcache_cache_bypass(arizona->regmap, true);
-
-	for (i = 0; i < patch_size; i++) {
-		ret = regmap_write(arizona->regmap, wm5102_patch[i].reg,
-				   wm5102_patch[i].def);
-		if (ret != 0) {
-			dev_err(arizona->dev, "Failed to write %x = %x: %d\n",
-				wm5102_patch[i].reg, wm5102_patch[i].def, ret);
-			goto out;
-		}
-	}
-
-out:
-	regcache_cache_bypass(arizona->regmap, false);
-	return ret;
+	return regmap_multi_reg_write_bypassed(arizona->regmap,
+					       wm5102_patch,
+					       patch_size);
 }
 
 static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = {
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch
  2014-02-25 13:45 ` [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch Charles Keepax
@ 2014-02-25 14:27   ` Lee Jones
  0 siblings, 0 replies; 6+ messages in thread
From: Lee Jones @ 2014-02-25 14:27 UTC (permalink / raw)
  To: Charles Keepax; +Cc: broonie, gregkh, sameo, linux-kernel, patches

On Tue, 25 Feb 2014, Charles Keepax wrote:

> On the wm5102 the register patches are applied manually, rather than by
> the regmap core. This application is wrapped in calls to
> regcache_cache_bypass. However, this is dangerous as other threads may
> be accessing the hardware at the same time as the pm_runtime operations
> and if they do so during the period whilst cache_bypass is enabled those
> writes will miss the cache when they shouldn't.
> 
> Apply the register patch using the new regmap_multi_reg_write_bypassed
> function to avoid this problem. Also remove the call to
> regcache_cache_bypass from the hardware patch application as it is
> unneeded there and creates a similar window for writes to miss the
> cache.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  drivers/mfd/arizona-core.c  |    4 ----
>  drivers/mfd/wm5102-tables.c |   21 ++++-----------------
>  2 files changed, 4 insertions(+), 21 deletions(-)

Acked-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const
  2014-02-25 13:45 [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Charles Keepax
                   ` (2 preceding siblings ...)
  2014-02-25 13:45 ` [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch Charles Keepax
@ 2014-02-25 23:58 ` Mark Brown
  3 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2014-02-25 23:58 UTC (permalink / raw)
  To: Charles Keepax; +Cc: gregkh, sameo, lee.jones, linux-kernel, patches

[-- Attachment #1: Type: text/plain, Size: 197 bytes --]

On Tue, Feb 25, 2014 at 01:45:49PM +0000, Charles Keepax wrote:
> There should be no need for the writes supplied to this function to be
> edited by it so mark them as const.

Applied all, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-02-25 23:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-25 13:45 [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Charles Keepax
2014-02-25 13:45 ` [PATCH 2/4] regmap: Add bypassed version of regmap_multi_reg_write Charles Keepax
2014-02-25 13:45 ` [PATCH 3/4] regmap: Base regmap_register_patch on _regmap_multi_reg_write Charles Keepax
2014-02-25 13:45 ` [PATCH 4/4] mfd: arizona: Use new regmap features for manual register patch Charles Keepax
2014-02-25 14:27   ` Lee Jones
2014-02-25 23:58 ` [PATCH 1/4] regmap: Mark reg_defaults in regmap_multi_reg_write as const Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.