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 /drivers/base/regmap | |
| parent | eae4b51b21f7452b0b53a9848f48c02cb0fac336 (diff) | |
| parent | df00c79f78d8b0ad788daf689ea461ace9d0811f (diff) | |
Merge remote-tracking branch 'regmap/topic/bulk' into regmap-next
Diffstat (limited to 'drivers/base/regmap')
| -rw-r--r-- | drivers/base/regmap/regcache.c | 5 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 76 |
2 files changed, 76 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 | { |
