aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regmap.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-10-04 12:31:11 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-10-14 21:00:00 -0400
commit98bc7dfd76407eaa0964ecb4d5319c957a3b9df9 (patch)
treeb7c6a097d0b799e5a07971c6764512e9145a53d0 /drivers/base/regmap/regmap.c
parent4b020b3f9ba2af8031c5c7d759fbafd234d1c390 (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.c91
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)
765EXPORT_SYMBOL_GPL(dev_get_regmap); 765EXPORT_SYMBOL_GPL(dev_get_regmap);
766 766
767static int _regmap_select_page(struct regmap *map, unsigned int *reg, 767static 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
818static int _regmap_raw_write(struct regmap *map, unsigned int reg, 815static 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, &reg, 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, &reg, 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,
903int _regmap_write(struct regmap *map, unsigned int reg, 905int _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, &reg, 1); 930 range = _regmap_range_lookup(map, reg);
928 if (ret < 0) 931 if (range) {
929 return ret; 932 ret = _regmap_select_page(map, &reg, 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);
1082static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, 1088static 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, &reg, 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, &reg, 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