diff options
-rw-r--r-- | drivers/base/regmap/internal.h | 4 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 85 | ||||
-rw-r--r-- | include/linux/regmap.h | 4 |
3 files changed, 78 insertions, 15 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index d744ae3926dd..fc554e357c5d 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -146,6 +146,10 @@ struct regmap { | |||
146 | /* if set, the device supports multi write mode */ | 146 | /* if set, the device supports multi write mode */ |
147 | bool can_multi_write; | 147 | bool can_multi_write; |
148 | 148 | ||
149 | /* if set, raw reads/writes are limited to this size */ | ||
150 | size_t max_raw_read; | ||
151 | size_t max_raw_write; | ||
152 | |||
149 | struct rb_root range_tree; | 153 | struct rb_root range_tree; |
150 | void *selector_work_buf; /* Scratch buffer used for selector */ | 154 | void *selector_work_buf; /* Scratch buffer used for selector */ |
151 | }; | 155 | }; |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index a6b6f7ee87ee..7cbe42680877 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -579,6 +579,8 @@ struct regmap *regmap_init(struct device *dev, | |||
579 | map->use_single_read = config->use_single_rw || !bus || !bus->read; | 579 | map->use_single_read = config->use_single_rw || !bus || !bus->read; |
580 | map->use_single_write = config->use_single_rw || !bus || !bus->write; | 580 | map->use_single_write = config->use_single_rw || !bus || !bus->write; |
581 | map->can_multi_write = config->can_multi_write && bus && bus->write; | 581 | map->can_multi_write = config->can_multi_write && bus && bus->write; |
582 | map->max_raw_read = bus->max_raw_read; | ||
583 | map->max_raw_write = bus->max_raw_write; | ||
582 | map->dev = dev; | 584 | map->dev = dev; |
583 | map->bus = bus; | 585 | map->bus = bus; |
584 | map->bus_context = bus_context; | 586 | map->bus_context = bus_context; |
@@ -1674,6 +1676,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1674 | { | 1676 | { |
1675 | int ret = 0, i; | 1677 | int ret = 0, i; |
1676 | size_t val_bytes = map->format.val_bytes; | 1678 | size_t val_bytes = map->format.val_bytes; |
1679 | size_t total_size = val_bytes * val_count; | ||
1677 | 1680 | ||
1678 | if (map->bus && !map->format.parse_inplace) | 1681 | if (map->bus && !map->format.parse_inplace) |
1679 | return -EINVAL; | 1682 | return -EINVAL; |
@@ -1722,16 +1725,37 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1722 | } | 1725 | } |
1723 | out: | 1726 | out: |
1724 | map->unlock(map->lock_arg); | 1727 | map->unlock(map->lock_arg); |
1725 | } else if (map->use_single_write) { | 1728 | } else if (map->use_single_write || |
1729 | (map->max_raw_write && map->max_raw_write < total_size)) { | ||
1730 | int chunk_stride = map->reg_stride; | ||
1731 | size_t chunk_size = val_bytes; | ||
1732 | size_t chunk_count = val_count; | ||
1733 | |||
1734 | if (!map->use_single_write) { | ||
1735 | chunk_size = map->max_raw_write; | ||
1736 | if (chunk_size % val_bytes) | ||
1737 | chunk_size -= chunk_size % val_bytes; | ||
1738 | chunk_count = total_size / chunk_size; | ||
1739 | chunk_stride *= chunk_size / val_bytes; | ||
1740 | } | ||
1741 | |||
1726 | map->lock(map->lock_arg); | 1742 | map->lock(map->lock_arg); |
1727 | for (i = 0; i < val_count; i++) { | 1743 | /* Write as many bytes as possible with chunk_size */ |
1744 | for (i = 0; i < chunk_count; i++) { | ||
1728 | ret = _regmap_raw_write(map, | 1745 | ret = _regmap_raw_write(map, |
1729 | reg + (i * map->reg_stride), | 1746 | reg + (i * chunk_stride), |
1730 | val + (i * val_bytes), | 1747 | val + (i * chunk_size), |
1731 | val_bytes); | 1748 | chunk_size); |
1732 | if (ret) | 1749 | if (ret) |
1733 | break; | 1750 | break; |
1734 | } | 1751 | } |
1752 | |||
1753 | /* Write remaining bytes */ | ||
1754 | if (!ret && chunk_size * i < total_size) { | ||
1755 | ret = _regmap_raw_write(map, reg + (i * chunk_stride), | ||
1756 | val + (i * chunk_size), | ||
1757 | total_size - i * chunk_size); | ||
1758 | } | ||
1735 | map->unlock(map->lock_arg); | 1759 | map->unlock(map->lock_arg); |
1736 | } else { | 1760 | } else { |
1737 | void *wval; | 1761 | void *wval; |
@@ -2319,20 +2343,51 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, | |||
2319 | * Some devices does not support bulk read, for | 2343 | * Some devices does not support bulk read, for |
2320 | * them we have a series of single read operations. | 2344 | * them we have a series of single read operations. |
2321 | */ | 2345 | */ |
2322 | if (map->use_single_read) { | 2346 | size_t total_size = val_bytes * val_count; |
2323 | for (i = 0; i < val_count; i++) { | 2347 | |
2324 | ret = regmap_raw_read(map, | 2348 | if (!map->use_single_read && |
2325 | reg + (i * map->reg_stride), | 2349 | (!map->max_raw_read || map->max_raw_read > total_size)) { |
2326 | val + (i * val_bytes), | ||
2327 | val_bytes); | ||
2328 | if (ret != 0) | ||
2329 | return ret; | ||
2330 | } | ||
2331 | } else { | ||
2332 | ret = regmap_raw_read(map, reg, val, | 2350 | ret = regmap_raw_read(map, reg, val, |
2333 | val_bytes * val_count); | 2351 | val_bytes * val_count); |
2334 | if (ret != 0) | 2352 | if (ret != 0) |
2335 | return ret; | 2353 | return ret; |
2354 | } else { | ||
2355 | /* | ||
2356 | * Some devices do not support bulk read or do not | ||
2357 | * support large bulk reads, for them we have a series | ||
2358 | * of read operations. | ||
2359 | */ | ||
2360 | int chunk_stride = map->reg_stride; | ||
2361 | size_t chunk_size = val_bytes; | ||
2362 | size_t chunk_count = val_count; | ||
2363 | |||
2364 | if (!map->use_single_read) { | ||
2365 | chunk_size = map->max_raw_read; | ||
2366 | if (chunk_size % val_bytes) | ||
2367 | chunk_size -= chunk_size % val_bytes; | ||
2368 | chunk_count = total_size / chunk_size; | ||
2369 | chunk_stride *= chunk_size / val_bytes; | ||
2370 | } | ||
2371 | |||
2372 | /* Read bytes that fit into a multiple of chunk_size */ | ||
2373 | for (i = 0; i < chunk_count; i++) { | ||
2374 | ret = regmap_raw_read(map, | ||
2375 | reg + (i * chunk_stride), | ||
2376 | val + (i * chunk_size), | ||
2377 | chunk_size); | ||
2378 | if (ret != 0) | ||
2379 | return ret; | ||
2380 | } | ||
2381 | |||
2382 | /* Read remaining bytes */ | ||
2383 | if (chunk_size * i < total_size) { | ||
2384 | ret = regmap_raw_read(map, | ||
2385 | reg + (i * chunk_stride), | ||
2386 | val + (i * chunk_size), | ||
2387 | total_size - i * chunk_size); | ||
2388 | if (ret != 0) | ||
2389 | return ret; | ||
2390 | } | ||
2336 | } | 2391 | } |
2337 | 2392 | ||
2338 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | 2393 | for (i = 0; i < val_count * val_bytes; i += val_bytes) |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 73fc34d0c4c2..327b8f291d3f 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -311,6 +311,8 @@ typedef void (*regmap_hw_free_context)(void *context); | |||
311 | * @val_format_endian_default: Default endianness for formatted register | 311 | * @val_format_endian_default: Default endianness for formatted register |
312 | * values. Used when the regmap_config specifies DEFAULT. If this is | 312 | * values. Used when the regmap_config specifies DEFAULT. If this is |
313 | * DEFAULT, BIG is assumed. | 313 | * DEFAULT, BIG is assumed. |
314 | * @max_raw_read: Max raw read size that can be used on the bus. | ||
315 | * @max_raw_write: Max raw write size that can be used on the bus. | ||
314 | */ | 316 | */ |
315 | struct regmap_bus { | 317 | struct regmap_bus { |
316 | bool fast_io; | 318 | bool fast_io; |
@@ -325,6 +327,8 @@ struct regmap_bus { | |||
325 | u8 read_flag_mask; | 327 | u8 read_flag_mask; |
326 | enum regmap_endian reg_format_endian_default; | 328 | enum regmap_endian reg_format_endian_default; |
327 | enum regmap_endian val_format_endian_default; | 329 | enum regmap_endian val_format_endian_default; |
330 | size_t max_raw_read; | ||
331 | size_t max_raw_write; | ||
328 | }; | 332 | }; |
329 | 333 | ||
330 | struct regmap *regmap_init(struct device *dev, | 334 | struct regmap *regmap_init(struct device *dev, |