diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-14 09:15:48 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-14 09:15:48 -0400 |
commit | addfd8a09e1f434a73b3d87d36ef050c73511d2b (patch) | |
tree | 22dd5a1f108dcd123797dbe9f5aa45e8d3faa492 | |
parent | eae4b51b21f7452b0b53a9848f48c02cb0fac336 (diff) | |
parent | df00c79f78d8b0ad788daf689ea461ace9d0811f (diff) |
Merge remote-tracking branch 'regmap/topic/bulk' into regmap-next
-rw-r--r-- | drivers/base/regmap/regcache.c | 5 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 76 | ||||
-rw-r--r-- | include/linux/regmap.h | 2 |
3 files changed, 78 insertions, 5 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index fb84d711fbb4..938cb1d2ea26 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -35,12 +35,17 @@ static int regcache_hw_init(struct regmap *map) | |||
35 | return -EINVAL; | 35 | return -EINVAL; |
36 | 36 | ||
37 | if (!map->reg_defaults_raw) { | 37 | if (!map->reg_defaults_raw) { |
38 | u32 cache_bypass = map->cache_bypass; | ||
38 | dev_warn(map->dev, "No cache defaults, reading back from HW\n"); | 39 | dev_warn(map->dev, "No cache defaults, reading back from HW\n"); |
40 | |||
41 | /* Bypass the cache access till data read from HW*/ | ||
42 | map->cache_bypass = 1; | ||
39 | tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); | 43 | tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); |
40 | if (!tmp_buf) | 44 | if (!tmp_buf) |
41 | return -EINVAL; | 45 | return -EINVAL; |
42 | ret = regmap_bulk_read(map, 0, tmp_buf, | 46 | ret = regmap_bulk_read(map, 0, tmp_buf, |
43 | map->num_reg_defaults_raw); | 47 | map->num_reg_defaults_raw); |
48 | map->cache_bypass = cache_bypass; | ||
44 | if (ret < 0) { | 49 | if (ret < 0) { |
45 | kfree(tmp_buf); | 50 | kfree(tmp_buf); |
46 | return ret; | 51 | return ret; |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2f7c25c68c9e..7a3f535e481c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -411,6 +411,26 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
411 | if (!map->writeable_reg(map->dev, reg + i)) | 411 | if (!map->writeable_reg(map->dev, reg + i)) |
412 | return -EINVAL; | 412 | return -EINVAL; |
413 | 413 | ||
414 | if (!map->cache_bypass && map->format.parse_val) { | ||
415 | unsigned int ival; | ||
416 | int val_bytes = map->format.val_bytes; | ||
417 | for (i = 0; i < val_len / val_bytes; i++) { | ||
418 | memcpy(map->work_buf, val + (i * val_bytes), val_bytes); | ||
419 | ival = map->format.parse_val(map->work_buf); | ||
420 | ret = regcache_write(map, reg + i, ival); | ||
421 | if (ret) { | ||
422 | dev_err(map->dev, | ||
423 | "Error in caching of register: %u ret: %d\n", | ||
424 | reg + i, ret); | ||
425 | return ret; | ||
426 | } | ||
427 | } | ||
428 | if (map->cache_only) { | ||
429 | map->cache_dirty = true; | ||
430 | return 0; | ||
431 | } | ||
432 | } | ||
433 | |||
414 | map->format.format_reg(map->work_buf, reg); | 434 | map->format.format_reg(map->work_buf, reg); |
415 | 435 | ||
416 | u8[0] |= map->write_flag_mask; | 436 | u8[0] |= map->write_flag_mask; |
@@ -461,7 +481,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
461 | int ret; | 481 | int ret; |
462 | BUG_ON(!map->format.format_write && !map->format.format_val); | 482 | BUG_ON(!map->format.format_write && !map->format.format_val); |
463 | 483 | ||
464 | if (!map->cache_bypass) { | 484 | if (!map->cache_bypass && map->format.format_write) { |
465 | ret = regcache_write(map, reg, val); | 485 | ret = regcache_write(map, reg, val); |
466 | if (ret != 0) | 486 | if (ret != 0) |
467 | return ret; | 487 | return ret; |
@@ -538,12 +558,8 @@ EXPORT_SYMBOL_GPL(regmap_write); | |||
538 | int regmap_raw_write(struct regmap *map, unsigned int reg, | 558 | int regmap_raw_write(struct regmap *map, unsigned int reg, |
539 | const void *val, size_t val_len) | 559 | const void *val, size_t val_len) |
540 | { | 560 | { |
541 | size_t val_count = val_len / map->format.val_bytes; | ||
542 | int ret; | 561 | int ret; |
543 | 562 | ||
544 | WARN_ON(!regmap_volatile_range(map, reg, val_count) && | ||
545 | map->cache_type != REGCACHE_NONE); | ||
546 | |||
547 | mutex_lock(&map->lock); | 563 | mutex_lock(&map->lock); |
548 | 564 | ||
549 | ret = _regmap_raw_write(map, reg, val, val_len); | 565 | ret = _regmap_raw_write(map, reg, val, val_len); |
@@ -554,6 +570,56 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
554 | } | 570 | } |
555 | EXPORT_SYMBOL_GPL(regmap_raw_write); | 571 | EXPORT_SYMBOL_GPL(regmap_raw_write); |
556 | 572 | ||
573 | /* | ||
574 | * regmap_bulk_write(): Write multiple registers to the device | ||
575 | * | ||
576 | * @map: Register map to write to | ||
577 | * @reg: First register to be write from | ||
578 | * @val: Block of data to be written, in native register size for device | ||
579 | * @val_count: Number of registers to write | ||
580 | * | ||
581 | * This function is intended to be used for writing a large block of | ||
582 | * data to be device either in single transfer or multiple transfer. | ||
583 | * | ||
584 | * A value of zero will be returned on success, a negative errno will | ||
585 | * be returned in error cases. | ||
586 | */ | ||
587 | int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | ||
588 | size_t val_count) | ||
589 | { | ||
590 | int ret = 0, i; | ||
591 | size_t val_bytes = map->format.val_bytes; | ||
592 | void *wval; | ||
593 | |||
594 | if (!map->format.parse_val) | ||
595 | return -EINVAL; | ||
596 | |||
597 | mutex_lock(&map->lock); | ||
598 | |||
599 | /* No formatting is require if val_byte is 1 */ | ||
600 | if (val_bytes == 1) { | ||
601 | wval = (void *)val; | ||
602 | } else { | ||
603 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); | ||
604 | if (!wval) { | ||
605 | ret = -ENOMEM; | ||
606 | dev_err(map->dev, "Error in memory allocation\n"); | ||
607 | goto out; | ||
608 | } | ||
609 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | ||
610 | map->format.parse_val(wval + i); | ||
611 | } | ||
612 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); | ||
613 | |||
614 | if (val_bytes != 1) | ||
615 | kfree(wval); | ||
616 | |||
617 | out: | ||
618 | mutex_unlock(&map->lock); | ||
619 | return ret; | ||
620 | } | ||
621 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | ||
622 | |||
557 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 623 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
558 | unsigned int val_len) | 624 | unsigned int val_len) |
559 | { | 625 | { |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 398377d89332..5d7e6add0084 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -146,6 +146,8 @@ int regmap_reinit_cache(struct regmap *map, | |||
146 | int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); | 146 | int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); |
147 | int regmap_raw_write(struct regmap *map, unsigned int reg, | 147 | int regmap_raw_write(struct regmap *map, unsigned int reg, |
148 | const void *val, size_t val_len); | 148 | const void *val, size_t val_len); |
149 | int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | ||
150 | size_t val_count); | ||
149 | int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); | 151 | int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); |
150 | int regmap_raw_read(struct regmap *map, unsigned int reg, | 152 | int regmap_raw_read(struct regmap *map, unsigned int reg, |
151 | void *val, size_t val_len); | 153 | void *val, size_t val_len); |