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/regmap.c | |
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/regmap.c')
-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 366b629f4b10..4bb926cd7bf2 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 | ||