aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaolin Wang <baolin.wang@linaro.org>2017-10-31 22:11:55 -0400
committerMark Brown <broonie@kernel.org>2017-11-01 06:06:29 -0400
commit8698b9364710e7bac84b3af07dd410e39c8c2e08 (patch)
tree78f4e1c6341aa609c76583fd9030241c72b2e3cd
parent2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e (diff)
regmap: Add hardware spinlock support
On some platforms, when reading or writing some special registers through regmap, we should acquire one hardware spinlock to synchronize between the multiple subsystems. Thus this patch adds the hardware spinlock support for regmap. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/base/regmap/internal.h2
-rw-r--r--drivers/base/regmap/regmap.c101
-rw-r--r--include/linux/regmap.h6
3 files changed, 93 insertions, 16 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 2a4435d76028..8641183cac2f 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -157,6 +157,8 @@ struct regmap {
157 157
158 struct rb_root range_tree; 158 struct rb_root range_tree;
159 void *selector_work_buf; /* Scratch buffer used for selector */ 159 void *selector_work_buf; /* Scratch buffer used for selector */
160
161 struct hwspinlock *hwlock;
160}; 162};
161 163
162struct regcache_ops { 164struct regcache_ops {
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index b9a779a4a739..999e981a174a 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -20,6 +20,7 @@
20#include <linux/sched.h> 20#include <linux/sched.h>
21#include <linux/delay.h> 21#include <linux/delay.h>
22#include <linux/log2.h> 22#include <linux/log2.h>
23#include <linux/hwspinlock.h>
23 24
24#define CREATE_TRACE_POINTS 25#define CREATE_TRACE_POINTS
25#include "trace.h" 26#include "trace.h"
@@ -413,6 +414,49 @@ static unsigned int regmap_parse_64_native(const void *buf)
413} 414}
414#endif 415#endif
415 416
417static void regmap_lock_hwlock(void *__map)
418{
419 struct regmap *map = __map;
420
421 hwspin_lock_timeout(map->hwlock, UINT_MAX);
422}
423
424static void regmap_lock_hwlock_irq(void *__map)
425{
426 struct regmap *map = __map;
427
428 hwspin_lock_timeout_irq(map->hwlock, UINT_MAX);
429}
430
431static void regmap_lock_hwlock_irqsave(void *__map)
432{
433 struct regmap *map = __map;
434
435 hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX,
436 &map->spinlock_flags);
437}
438
439static void regmap_unlock_hwlock(void *__map)
440{
441 struct regmap *map = __map;
442
443 hwspin_unlock(map->hwlock);
444}
445
446static void regmap_unlock_hwlock_irq(void *__map)
447{
448 struct regmap *map = __map;
449
450 hwspin_unlock_irq(map->hwlock);
451}
452
453static void regmap_unlock_hwlock_irqrestore(void *__map)
454{
455 struct regmap *map = __map;
456
457 hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);
458}
459
416static void regmap_lock_mutex(void *__map) 460static void regmap_lock_mutex(void *__map)
417{ 461{
418 struct regmap *map = __map; 462 struct regmap *map = __map;
@@ -627,6 +671,29 @@ struct regmap *__regmap_init(struct device *dev,
627 map->lock = config->lock; 671 map->lock = config->lock;
628 map->unlock = config->unlock; 672 map->unlock = config->unlock;
629 map->lock_arg = config->lock_arg; 673 map->lock_arg = config->lock_arg;
674 } else if (config->hwlock_id) {
675 map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
676 if (!map->hwlock) {
677 ret = -ENXIO;
678 goto err_map;
679 }
680
681 switch (config->hwlock_mode) {
682 case HWLOCK_IRQSTATE:
683 map->lock = regmap_lock_hwlock_irqsave;
684 map->unlock = regmap_unlock_hwlock_irqrestore;
685 break;
686 case HWLOCK_IRQ:
687 map->lock = regmap_lock_hwlock_irq;
688 map->unlock = regmap_unlock_hwlock_irq;
689 break;
690 default:
691 map->lock = regmap_lock_hwlock;
692 map->unlock = regmap_unlock_hwlock;
693 break;
694 }
695
696 map->lock_arg = map;
630 } else { 697 } else {
631 if ((bus && bus->fast_io) || 698 if ((bus && bus->fast_io) ||
632 config->fast_io) { 699 config->fast_io) {
@@ -729,7 +796,7 @@ struct regmap *__regmap_init(struct device *dev,
729 map->format.format_write = regmap_format_2_6_write; 796 map->format.format_write = regmap_format_2_6_write;
730 break; 797 break;
731 default: 798 default:
732 goto err_map; 799 goto err_hwlock;
733 } 800 }
734 break; 801 break;
735 802
@@ -739,7 +806,7 @@ struct regmap *__regmap_init(struct device *dev,
739 map->format.format_write = regmap_format_4_12_write; 806 map->format.format_write = regmap_format_4_12_write;
740 break; 807 break;
741 default: 808 default:
742 goto err_map; 809 goto err_hwlock;
743 } 810 }
744 break; 811 break;
745 812
@@ -749,7 +816,7 @@ struct regmap *__regmap_init(struct device *dev,
749 map->format.format_write = regmap_format_7_9_write; 816 map->format.format_write = regmap_format_7_9_write;
750 break; 817 break;
751 default: 818 default:
752 goto err_map; 819 goto err_hwlock;
753 } 820 }
754 break; 821 break;
755 822
@@ -759,7 +826,7 @@ struct regmap *__regmap_init(struct device *dev,
759 map->format.format_write = regmap_format_10_14_write; 826 map->format.format_write = regmap_format_10_14_write;
760 break; 827 break;
761 default: 828 default:
762 goto err_map; 829 goto err_hwlock;
763 } 830 }
764 break; 831 break;
765 832
@@ -779,13 +846,13 @@ struct regmap *__regmap_init(struct device *dev,
779 map->format.format_reg = regmap_format_16_native; 846 map->format.format_reg = regmap_format_16_native;
780 break; 847 break;
781 default: 848 default:
782 goto err_map; 849 goto err_hwlock;
783 } 850 }
784 break; 851 break;
785 852
786 case 24: 853 case 24:
787 if (reg_endian != REGMAP_ENDIAN_BIG) 854 if (reg_endian != REGMAP_ENDIAN_BIG)
788 goto err_map; 855 goto err_hwlock;
789 map->format.format_reg = regmap_format_24; 856 map->format.format_reg = regmap_format_24;
790 break; 857 break;
791 858
@@ -801,7 +868,7 @@ struct regmap *__regmap_init(struct device *dev,
801 map->format.format_reg = regmap_format_32_native; 868 map->format.format_reg = regmap_format_32_native;
802 break; 869 break;
803 default: 870 default:
804 goto err_map; 871 goto err_hwlock;
805 } 872 }
806 break; 873 break;
807 874
@@ -818,13 +885,13 @@ struct regmap *__regmap_init(struct device *dev,
818 map->format.format_reg = regmap_format_64_native; 885 map->format.format_reg = regmap_format_64_native;
819 break; 886 break;
820 default: 887 default:
821 goto err_map; 888 goto err_hwlock;
822 } 889 }
823 break; 890 break;
824#endif 891#endif
825 892
826 default: 893 default:
827 goto err_map; 894 goto err_hwlock;
828 } 895 }
829 896
830 if (val_endian == REGMAP_ENDIAN_NATIVE) 897 if (val_endian == REGMAP_ENDIAN_NATIVE)
@@ -853,12 +920,12 @@ struct regmap *__regmap_init(struct device *dev,
853 map->format.parse_val = regmap_parse_16_native; 920 map->format.parse_val = regmap_parse_16_native;
854 break; 921 break;
855 default: 922 default:
856 goto err_map; 923 goto err_hwlock;
857 } 924 }
858 break; 925 break;
859 case 24: 926 case 24:
860 if (val_endian != REGMAP_ENDIAN_BIG) 927 if (val_endian != REGMAP_ENDIAN_BIG)
861 goto err_map; 928 goto err_hwlock;
862 map->format.format_val = regmap_format_24; 929 map->format.format_val = regmap_format_24;
863 map->format.parse_val = regmap_parse_24; 930 map->format.parse_val = regmap_parse_24;
864 break; 931 break;
@@ -879,7 +946,7 @@ struct regmap *__regmap_init(struct device *dev,
879 map->format.parse_val = regmap_parse_32_native; 946 map->format.parse_val = regmap_parse_32_native;
880 break; 947 break;
881 default: 948 default:
882 goto err_map; 949 goto err_hwlock;
883 } 950 }
884 break; 951 break;
885#ifdef CONFIG_64BIT 952#ifdef CONFIG_64BIT
@@ -900,7 +967,7 @@ struct regmap *__regmap_init(struct device *dev,
900 map->format.parse_val = regmap_parse_64_native; 967 map->format.parse_val = regmap_parse_64_native;
901 break; 968 break;
902 default: 969 default:
903 goto err_map; 970 goto err_hwlock;
904 } 971 }
905 break; 972 break;
906#endif 973#endif
@@ -909,18 +976,18 @@ struct regmap *__regmap_init(struct device *dev,
909 if (map->format.format_write) { 976 if (map->format.format_write) {
910 if ((reg_endian != REGMAP_ENDIAN_BIG) || 977 if ((reg_endian != REGMAP_ENDIAN_BIG) ||
911 (val_endian != REGMAP_ENDIAN_BIG)) 978 (val_endian != REGMAP_ENDIAN_BIG))
912 goto err_map; 979 goto err_hwlock;
913 map->use_single_write = true; 980 map->use_single_write = true;
914 } 981 }
915 982
916 if (!map->format.format_write && 983 if (!map->format.format_write &&
917 !(map->format.format_reg && map->format.format_val)) 984 !(map->format.format_reg && map->format.format_val))
918 goto err_map; 985 goto err_hwlock;
919 986
920 map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); 987 map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
921 if (map->work_buf == NULL) { 988 if (map->work_buf == NULL) {
922 ret = -ENOMEM; 989 ret = -ENOMEM;
923 goto err_map; 990 goto err_hwlock;
924 } 991 }
925 992
926 if (map->format.format_write) { 993 if (map->format.format_write) {
@@ -1041,6 +1108,8 @@ err_regcache:
1041err_range: 1108err_range:
1042 regmap_range_exit(map); 1109 regmap_range_exit(map);
1043 kfree(map->work_buf); 1110 kfree(map->work_buf);
1111err_hwlock:
1112 hwspin_lock_free(map->hwlock);
1044err_map: 1113err_map:
1045 kfree(map); 1114 kfree(map);
1046err: 1115err:
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 978abfbac617..edc32aac84d7 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -273,6 +273,9 @@ typedef void (*regmap_unlock)(void *);
273 * 273 *
274 * @ranges: Array of configuration entries for virtual address ranges. 274 * @ranges: Array of configuration entries for virtual address ranges.
275 * @num_ranges: Number of range configuration entries. 275 * @num_ranges: Number of range configuration entries.
276 * @hwlock_id: Specify the hardware spinlock id.
277 * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
278 * HWLOCK_IRQ or 0.
276 */ 279 */
277struct regmap_config { 280struct regmap_config {
278 const char *name; 281 const char *name;
@@ -317,6 +320,9 @@ struct regmap_config {
317 320
318 const struct regmap_range_cfg *ranges; 321 const struct regmap_range_cfg *ranges;
319 unsigned int num_ranges; 322 unsigned int num_ranges;
323
324 unsigned int hwlock_id;
325 unsigned int hwlock_mode;
320}; 326};
321 327
322/** 328/**