diff options
| author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-10-04 12:31:11 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-10-14 21:00:00 -0400 |
| commit | 98bc7dfd76407eaa0964ecb4d5319c957a3b9df9 (patch) | |
| tree | b7c6a097d0b799e5a07971c6764512e9145a53d0 /drivers/base/regmap | |
| parent | 4b020b3f9ba2af8031c5c7d759fbafd234d1c390 (diff) | |
regmap: Factor range lookup out of page selection
This will support a subsequent update to allow bulk writes to cross window
boundaries.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap')
| -rw-r--r-- | drivers/base/regmap/regmap.c | 91 |
1 files changed, 51 insertions, 40 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 366b629f4b1..4bb926cd7bf 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) | |||
| 765 | EXPORT_SYMBOL_GPL(dev_get_regmap); | 765 | EXPORT_SYMBOL_GPL(dev_get_regmap); |
| 766 | 766 | ||
| 767 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, | 767 | static int _regmap_select_page(struct regmap *map, unsigned int *reg, |
| 768 | struct regmap_range_node *range, | ||
| 768 | unsigned int val_num) | 769 | unsigned int val_num) |
| 769 | { | 770 | { |
| 770 | struct regmap_range_node *range; | ||
| 771 | void *orig_work_buf; | 771 | void *orig_work_buf; |
| 772 | unsigned int win_offset; | 772 | unsigned int win_offset; |
| 773 | unsigned int win_page; | 773 | unsigned int win_page; |
| 774 | bool page_chg; | 774 | bool page_chg; |
| 775 | int ret; | 775 | int ret; |
| 776 | 776 | ||
| 777 | range = _regmap_range_lookup(map, *reg); | 777 | win_offset = (*reg - range->range_min) % range->window_len; |
| 778 | if (range) { | 778 | win_page = (*reg - range->range_min) / range->window_len; |
| 779 | win_offset = (*reg - range->range_min) % range->window_len; | ||
| 780 | win_page = (*reg - range->range_min) / range->window_len; | ||
| 781 | 779 | ||
| 782 | if (val_num > 1) { | 780 | if (val_num > 1) { |
| 783 | /* Bulk write shouldn't cross range boundary */ | 781 | /* Bulk write shouldn't cross range boundary */ |
| 784 | if (*reg + val_num - 1 > range->range_max) | 782 | if (*reg + val_num - 1 > range->range_max) |
| 785 | return -EINVAL; | 783 | return -EINVAL; |
| 786 | 784 | ||
| 787 | /* ... or single page boundary */ | 785 | /* ... or single page boundary */ |
| 788 | if (val_num > range->window_len - win_offset) | 786 | if (val_num > range->window_len - win_offset) |
| 789 | return -EINVAL; | 787 | return -EINVAL; |
| 790 | } | 788 | } |
| 791 | 789 | ||
| 792 | /* It is possible to have selector register inside data window. | 790 | /* It is possible to have selector register inside data window. |
| 793 | In that case, selector register is located on every page and | 791 | In that case, selector register is located on every page and |
| 794 | it needs no page switching, when accessed alone. */ | 792 | it needs no page switching, when accessed alone. */ |
| 795 | if (val_num > 1 || | 793 | if (val_num > 1 || |
| 796 | range->window_start + win_offset != range->selector_reg) { | 794 | range->window_start + win_offset != range->selector_reg) { |
| 797 | /* Use separate work_buf during page switching */ | 795 | /* Use separate work_buf during page switching */ |
| 798 | orig_work_buf = map->work_buf; | 796 | orig_work_buf = map->work_buf; |
| 799 | map->work_buf = map->selector_work_buf; | 797 | map->work_buf = map->selector_work_buf; |
| 800 | 798 | ||
| 801 | ret = _regmap_update_bits(map, range->selector_reg, | 799 | ret = _regmap_update_bits(map, range->selector_reg, |
| 802 | range->selector_mask, | 800 | range->selector_mask, |
| 803 | win_page << range->selector_shift, | 801 | win_page << range->selector_shift, |
| 804 | &page_chg); | 802 | &page_chg); |
| 805 | 803 | ||
| 806 | map->work_buf = orig_work_buf; | 804 | map->work_buf = orig_work_buf; |
| 807 | 805 | ||
| 808 | if (ret < 0) | 806 | if (ret < 0) |
| 809 | return ret; | 807 | return ret; |
| 810 | } | ||
| 811 | |||
| 812 | *reg = range->window_start + win_offset; | ||
| 813 | } | 808 | } |
| 814 | 809 | ||
| 810 | *reg = range->window_start + win_offset; | ||
| 811 | |||
| 815 | return 0; | 812 | return 0; |
| 816 | } | 813 | } |
| 817 | 814 | ||
| 818 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 815 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, |
| 819 | const void *val, size_t val_len) | 816 | const void *val, size_t val_len) |
| 820 | { | 817 | { |
| 818 | struct regmap_range_node *range; | ||
| 821 | u8 *u8 = map->work_buf; | 819 | u8 *u8 = map->work_buf; |
| 822 | void *buf; | 820 | void *buf; |
| 823 | int ret = -ENOTSUPP; | 821 | int ret = -ENOTSUPP; |
| @@ -852,9 +850,13 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
| 852 | } | 850 | } |
| 853 | } | 851 | } |
| 854 | 852 | ||
| 855 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 853 | range = _regmap_range_lookup(map, reg); |
| 856 | if (ret < 0) | 854 | if (range) { |
| 857 | return ret; | 855 | ret = _regmap_select_page(map, ®, range, |
| 856 | val_len / map->format.val_bytes); | ||
| 857 | if (ret < 0) | ||
| 858 | return ret; | ||
| 859 | } | ||
| 858 | 860 | ||
| 859 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 861 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
| 860 | 862 | ||
| @@ -903,6 +905,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
| 903 | int _regmap_write(struct regmap *map, unsigned int reg, | 905 | int _regmap_write(struct regmap *map, unsigned int reg, |
| 904 | unsigned int val) | 906 | unsigned int val) |
| 905 | { | 907 | { |
| 908 | struct regmap_range_node *range; | ||
| 906 | int ret; | 909 | int ret; |
| 907 | BUG_ON(!map->format.format_write && !map->format.format_val); | 910 | BUG_ON(!map->format.format_write && !map->format.format_val); |
| 908 | 911 | ||
| @@ -924,9 +927,12 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
| 924 | trace_regmap_reg_write(map->dev, reg, val); | 927 | trace_regmap_reg_write(map->dev, reg, val); |
| 925 | 928 | ||
| 926 | if (map->format.format_write) { | 929 | if (map->format.format_write) { |
| 927 | ret = _regmap_select_page(map, ®, 1); | 930 | range = _regmap_range_lookup(map, reg); |
| 928 | if (ret < 0) | 931 | if (range) { |
| 929 | return ret; | 932 | ret = _regmap_select_page(map, ®, range, 1); |
| 933 | if (ret < 0) | ||
| 934 | return ret; | ||
| 935 | } | ||
| 930 | 936 | ||
| 931 | map->format.format_write(map, reg, val); | 937 | map->format.format_write(map, reg, val); |
| 932 | 938 | ||
| @@ -1082,12 +1088,17 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); | |||
| 1082 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 1088 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
| 1083 | unsigned int val_len) | 1089 | unsigned int val_len) |
| 1084 | { | 1090 | { |
| 1091 | struct regmap_range_node *range; | ||
| 1085 | u8 *u8 = map->work_buf; | 1092 | u8 *u8 = map->work_buf; |
| 1086 | int ret; | 1093 | int ret; |
| 1087 | 1094 | ||
| 1088 | ret = _regmap_select_page(map, ®, val_len / map->format.val_bytes); | 1095 | range = _regmap_range_lookup(map, reg); |
| 1089 | if (ret < 0) | 1096 | if (range) { |
| 1090 | return ret; | 1097 | ret = _regmap_select_page(map, ®, range, |
| 1098 | val_len / map->format.val_bytes); | ||
| 1099 | if (ret < 0) | ||
| 1100 | return ret; | ||
| 1101 | } | ||
| 1091 | 1102 | ||
| 1092 | map->format.format_reg(map->work_buf, reg, map->reg_shift); | 1103 | map->format.format_reg(map->work_buf, reg, map->reg_shift); |
| 1093 | 1104 | ||
