linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] regmap: Factor range lookup out of page selection
@ 2012-10-04 17:36 Mark Brown
  2012-10-04 17:36 ` [PATCH 2/3] regmap: Make return code checks consistent Mark Brown
  2012-10-04 17:36 ` [PATCH 3/3] regmap: Split raw writes that cross window boundaries Mark Brown
  0 siblings, 2 replies; 3+ messages in thread
From: Mark Brown @ 2012-10-04 17:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Brown

This will support a subsequent update to allow bulk writes to cross window
boundaries.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |   91 +++++++++++++++++++++++-------------------
 1 file changed, 51 insertions(+), 40 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 366b629..4bb926c 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -765,59 +765,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
 EXPORT_SYMBOL_GPL(dev_get_regmap);
 
 static int _regmap_select_page(struct regmap *map, unsigned int *reg,
+			       struct regmap_range_node *range,
 			       unsigned int val_num)
 {
-	struct regmap_range_node *range;
 	void *orig_work_buf;
 	unsigned int win_offset;
 	unsigned int win_page;
 	bool page_chg;
 	int ret;
 
-	range = _regmap_range_lookup(map, *reg);
-	if (range) {
-		win_offset = (*reg - range->range_min) % range->window_len;
-		win_page = (*reg - range->range_min) / range->window_len;
+	win_offset = (*reg - range->range_min) % range->window_len;
+	win_page = (*reg - range->range_min) / range->window_len;
 
-		if (val_num > 1) {
-			/* Bulk write shouldn't cross range boundary */
-			if (*reg + val_num - 1 > range->range_max)
-				return -EINVAL;
+	if (val_num > 1) {
+		/* Bulk write shouldn't cross range boundary */
+		if (*reg + val_num - 1 > range->range_max)
+			return -EINVAL;
 
-			/* ... or single page boundary */
-			if (val_num > range->window_len - win_offset)
-				return -EINVAL;
-		}
+		/* ... or single page boundary */
+		if (val_num > range->window_len - win_offset)
+			return -EINVAL;
+	}
 
-		/* It is possible to have selector register inside data window.
-		   In that case, selector register is located on every page and
-		   it needs no page switching, when accessed alone. */
-		if (val_num > 1 ||
-		    range->window_start + win_offset != range->selector_reg) {
-			/* Use separate work_buf during page switching */
-			orig_work_buf = map->work_buf;
-			map->work_buf = map->selector_work_buf;
+	/* It is possible to have selector register inside data window.
+	   In that case, selector register is located on every page and
+	   it needs no page switching, when accessed alone. */
+	if (val_num > 1 ||
+	    range->window_start + win_offset != range->selector_reg) {
+		/* Use separate work_buf during page switching */
+		orig_work_buf = map->work_buf;
+		map->work_buf = map->selector_work_buf;
 
-			ret = _regmap_update_bits(map, range->selector_reg,
-					range->selector_mask,
-					win_page << range->selector_shift,
-					&page_chg);
+		ret = _regmap_update_bits(map, range->selector_reg,
+					  range->selector_mask,
+					  win_page << range->selector_shift,
+					  &page_chg);
 
-			map->work_buf = orig_work_buf;
+		map->work_buf = orig_work_buf;
 
-			if (ret < 0)
-				return ret;
-		}
-
-		*reg = range->window_start + win_offset;
+		if (ret < 0)
+			return ret;
 	}
 
+	*reg = range->window_start + win_offset;
+
 	return 0;
 }
 
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 			     const void *val, size_t val_len)
 {
+	struct regmap_range_node *range;
 	u8 *u8 = map->work_buf;
 	void *buf;
 	int ret = -ENOTSUPP;
@@ -852,9 +850,13 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 		}
 	}
 
-	ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
-	if (ret < 0)
-		return ret;
+	range = _regmap_range_lookup(map, reg);
+	if (range) {
+		ret = _regmap_select_page(map, &reg, range,
+					  val_len / map->format.val_bytes);
+		if (ret < 0)
+			return ret;
+	}
 
 	map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
@@ -903,6 +905,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 int _regmap_write(struct regmap *map, unsigned int reg,
 		  unsigned int val)
 {
+	struct regmap_range_node *range;
 	int ret;
 	BUG_ON(!map->format.format_write && !map->format.format_val);
 
@@ -924,9 +927,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 	trace_regmap_reg_write(map->dev, reg, val);
 
 	if (map->format.format_write) {
-		ret = _regmap_select_page(map, &reg, 1);
-		if (ret < 0)
-			return ret;
+		range = _regmap_range_lookup(map, reg);
+		if (range) {
+			ret = _regmap_select_page(map, &reg, range, 1);
+			if (ret < 0)
+				return ret;
+		}
 
 		map->format.format_write(map, reg, val);
 
@@ -1082,12 +1088,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
 static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 			    unsigned int val_len)
 {
+	struct regmap_range_node *range;
 	u8 *u8 = map->work_buf;
 	int ret;
 
-	ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
-	if (ret < 0)
-		return ret;
+	range = _regmap_range_lookup(map, reg);
+	if (range) {
+		ret = _regmap_select_page(map, &reg, range,
+					  val_len / map->format.val_bytes);
+		if (ret < 0)
+			return ret;
+	}
 
 	map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
-- 
1.7.10.4


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

* [PATCH 2/3] regmap: Make return code checks consistent
  2012-10-04 17:36 [PATCH 1/3] regmap: Factor range lookup out of page selection Mark Brown
@ 2012-10-04 17:36 ` Mark Brown
  2012-10-04 17:36 ` [PATCH 3/3] regmap: Split raw writes that cross window boundaries Mark Brown
  1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-10-04 17:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Brown

The range code was written to check for return codes less than zero as
errors but throughout the rest of the API return codes not equal to zero
are errors. Change all these checks to match the house style.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 4bb926c..baf9586 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -606,7 +606,7 @@ struct regmap *regmap_init(struct device *dev,
 	}
 
 	ret = regcache_init(map, config);
-	if (ret < 0)
+	if (ret != 0)
 		goto err_range;
 
 	regmap_debugfs_init(map, config->name);
@@ -803,7 +803,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
 
 		map->work_buf = orig_work_buf;
 
-		if (ret < 0)
+		if (ret != 0)
 			return ret;
 	}
 
@@ -854,7 +854,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 	if (range) {
 		ret = _regmap_select_page(map, &reg, range,
 					  val_len / map->format.val_bytes);
-		if (ret < 0)
+		if (ret != 0)
 			return ret;
 	}
 
@@ -930,7 +930,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 		range = _regmap_range_lookup(map, reg);
 		if (range) {
 			ret = _regmap_select_page(map, &reg, range, 1);
-			if (ret < 0)
+			if (ret != 0)
 				return ret;
 		}
 
@@ -1096,7 +1096,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 	if (range) {
 		ret = _regmap_select_page(map, &reg, range,
 					  val_len / map->format.val_bytes);
-		if (ret < 0)
+		if (ret != 0)
 			return ret;
 	}
 
-- 
1.7.10.4


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

* [PATCH 3/3] regmap: Split raw writes that cross window boundaries
  2012-10-04 17:36 [PATCH 1/3] regmap: Factor range lookup out of page selection Mark Brown
  2012-10-04 17:36 ` [PATCH 2/3] regmap: Make return code checks consistent Mark Brown
@ 2012-10-04 17:36 ` Mark Brown
  1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-10-04 17:36 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Brown

If a block write covers a paged memory region and crosses a window
boundary then rather than failing the write split the transfer up
into multiple writes, making the whole process more transparent for
drivers.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/regmap.c |   21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index baf9586..07ea564 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -852,8 +852,25 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
 	range = _regmap_range_lookup(map, reg);
 	if (range) {
-		ret = _regmap_select_page(map, &reg, range,
-					  val_len / map->format.val_bytes);
+		int val_num = val_len / map->format.val_bytes;
+		int win_offset = (reg - range->range_min) % range->window_len;
+		int win_residue = range->window_len - win_offset;
+
+		/* If the write goes beyond the end of the window split it */
+		while (val_num > win_residue) {
+			dev_dbg(map->dev, "Writing window %d/%d\n",
+				win_residue, val_len);
+			ret = _regmap_raw_write(map, reg, val, win_residue);
+			if (ret != 0)
+				return ret;
+
+			val += win_residue;
+			val_len -= win_residue;
+			val_num = val_len / map->format.val_bytes;
+			win_residue = range->window_len - win_offset;
+		}
+
+		ret = _regmap_select_page(map, &reg, range, val_num);
 		if (ret != 0)
 			return ret;
 	}
-- 
1.7.10.4


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

end of thread, other threads:[~2012-10-04 17:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-04 17:36 [PATCH 1/3] regmap: Factor range lookup out of page selection Mark Brown
2012-10-04 17:36 ` [PATCH 2/3] regmap: Make return code checks consistent Mark Brown
2012-10-04 17:36 ` [PATCH 3/3] regmap: Split raw writes that cross window boundaries Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).