diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/base/regmap/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/base/regmap/internal.h | 2 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-spi.c | 2 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-spmi.c | 4 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 111 |
5 files changed, 104 insertions, 19 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 073c0b77e5b3..e7fa7b4bf9af 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | config REGMAP | 5 | config REGMAP |
| 6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) | 6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) |
| 7 | select IRQ_DOMAIN if REGMAP_IRQ | 7 | select IRQ_DOMAIN if REGMAP_IRQ |
| 8 | select REGMAP_HWSPINLOCK if HWSPINLOCK=y | ||
| 8 | bool | 9 | bool |
| 9 | 10 | ||
| 10 | config REGCACHE_COMPRESSED | 11 | config REGCACHE_COMPRESSED |
| @@ -36,3 +37,6 @@ config REGMAP_MMIO | |||
| 36 | 37 | ||
| 37 | config REGMAP_IRQ | 38 | config REGMAP_IRQ |
| 38 | bool | 39 | bool |
| 40 | |||
| 41 | config REGMAP_HWSPINLOCK | ||
| 42 | bool | ||
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 | ||
| 162 | struct regcache_ops { | 164 | struct regcache_ops { |
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index edd9a839d004..c7150dd264d5 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c | |||
| @@ -102,7 +102,7 @@ static int regmap_spi_read(void *context, | |||
| 102 | return spi_write_then_read(spi, reg, reg_size, val, val_size); | 102 | return spi_write_then_read(spi, reg, reg_size, val, val_size); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static struct regmap_bus regmap_spi = { | 105 | static const struct regmap_bus regmap_spi = { |
| 106 | .write = regmap_spi_write, | 106 | .write = regmap_spi_write, |
| 107 | .gather_write = regmap_spi_gather_write, | 107 | .gather_write = regmap_spi_gather_write, |
| 108 | .async_write = regmap_spi_async_write, | 108 | .async_write = regmap_spi_async_write, |
diff --git a/drivers/base/regmap/regmap-spmi.c b/drivers/base/regmap/regmap-spmi.c index 4a36e415e938..0bfb8ed244d5 100644 --- a/drivers/base/regmap/regmap-spmi.c +++ b/drivers/base/regmap/regmap-spmi.c | |||
| @@ -83,7 +83,7 @@ static int regmap_spmi_base_write(void *context, const void *data, | |||
| 83 | count - 1); | 83 | count - 1); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | static struct regmap_bus regmap_spmi_base = { | 86 | static const struct regmap_bus regmap_spmi_base = { |
| 87 | .read = regmap_spmi_base_read, | 87 | .read = regmap_spmi_base_read, |
| 88 | .write = regmap_spmi_base_write, | 88 | .write = regmap_spmi_base_write, |
| 89 | .gather_write = regmap_spmi_base_gather_write, | 89 | .gather_write = regmap_spmi_base_gather_write, |
| @@ -203,7 +203,7 @@ static int regmap_spmi_ext_write(void *context, const void *data, | |||
| 203 | count - 2); | 203 | count - 2); |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | static struct regmap_bus regmap_spmi_ext = { | 206 | static const struct regmap_bus regmap_spmi_ext = { |
| 207 | .read = regmap_spmi_ext_read, | 207 | .read = regmap_spmi_ext_read, |
| 208 | .write = regmap_spmi_ext_write, | 208 | .write = regmap_spmi_ext_write, |
| 209 | .gather_write = regmap_spmi_ext_gather_write, | 209 | .gather_write = regmap_spmi_ext_gather_write, |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index b9a779a4a739..8d516a9bfc01 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,51 @@ static unsigned int regmap_parse_64_native(const void *buf) | |||
| 413 | } | 414 | } |
| 414 | #endif | 415 | #endif |
| 415 | 416 | ||
| 417 | #ifdef REGMAP_HWSPINLOCK | ||
| 418 | static void regmap_lock_hwlock(void *__map) | ||
| 419 | { | ||
| 420 | struct regmap *map = __map; | ||
| 421 | |||
| 422 | hwspin_lock_timeout(map->hwlock, UINT_MAX); | ||
| 423 | } | ||
| 424 | |||
| 425 | static void regmap_lock_hwlock_irq(void *__map) | ||
| 426 | { | ||
| 427 | struct regmap *map = __map; | ||
| 428 | |||
| 429 | hwspin_lock_timeout_irq(map->hwlock, UINT_MAX); | ||
| 430 | } | ||
| 431 | |||
| 432 | static void regmap_lock_hwlock_irqsave(void *__map) | ||
| 433 | { | ||
| 434 | struct regmap *map = __map; | ||
| 435 | |||
| 436 | hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX, | ||
| 437 | &map->spinlock_flags); | ||
| 438 | } | ||
| 439 | |||
| 440 | static void regmap_unlock_hwlock(void *__map) | ||
| 441 | { | ||
| 442 | struct regmap *map = __map; | ||
| 443 | |||
| 444 | hwspin_unlock(map->hwlock); | ||
| 445 | } | ||
| 446 | |||
| 447 | static void regmap_unlock_hwlock_irq(void *__map) | ||
| 448 | { | ||
| 449 | struct regmap *map = __map; | ||
| 450 | |||
| 451 | hwspin_unlock_irq(map->hwlock); | ||
| 452 | } | ||
| 453 | |||
| 454 | static void regmap_unlock_hwlock_irqrestore(void *__map) | ||
| 455 | { | ||
| 456 | struct regmap *map = __map; | ||
| 457 | |||
| 458 | hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags); | ||
| 459 | } | ||
| 460 | #endif | ||
| 461 | |||
| 416 | static void regmap_lock_mutex(void *__map) | 462 | static void regmap_lock_mutex(void *__map) |
| 417 | { | 463 | { |
| 418 | struct regmap *map = __map; | 464 | struct regmap *map = __map; |
| @@ -627,6 +673,34 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 627 | map->lock = config->lock; | 673 | map->lock = config->lock; |
| 628 | map->unlock = config->unlock; | 674 | map->unlock = config->unlock; |
| 629 | map->lock_arg = config->lock_arg; | 675 | map->lock_arg = config->lock_arg; |
| 676 | } else if (config->hwlock_id) { | ||
| 677 | #ifdef REGMAP_HWSPINLOCK | ||
| 678 | map->hwlock = hwspin_lock_request_specific(config->hwlock_id); | ||
| 679 | if (!map->hwlock) { | ||
| 680 | ret = -ENXIO; | ||
| 681 | goto err_map; | ||
| 682 | } | ||
| 683 | |||
| 684 | switch (config->hwlock_mode) { | ||
| 685 | case HWLOCK_IRQSTATE: | ||
| 686 | map->lock = regmap_lock_hwlock_irqsave; | ||
| 687 | map->unlock = regmap_unlock_hwlock_irqrestore; | ||
| 688 | break; | ||
| 689 | case HWLOCK_IRQ: | ||
| 690 | map->lock = regmap_lock_hwlock_irq; | ||
| 691 | map->unlock = regmap_unlock_hwlock_irq; | ||
| 692 | break; | ||
| 693 | default: | ||
| 694 | map->lock = regmap_lock_hwlock; | ||
| 695 | map->unlock = regmap_unlock_hwlock; | ||
| 696 | break; | ||
| 697 | } | ||
| 698 | |||
| 699 | map->lock_arg = map; | ||
| 700 | #else | ||
| 701 | ret = -EINVAL; | ||
| 702 | goto err_map; | ||
| 703 | #endif | ||
| 630 | } else { | 704 | } else { |
| 631 | if ((bus && bus->fast_io) || | 705 | if ((bus && bus->fast_io) || |
| 632 | config->fast_io) { | 706 | config->fast_io) { |
| @@ -729,7 +803,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 729 | map->format.format_write = regmap_format_2_6_write; | 803 | map->format.format_write = regmap_format_2_6_write; |
| 730 | break; | 804 | break; |
| 731 | default: | 805 | default: |
| 732 | goto err_map; | 806 | goto err_hwlock; |
| 733 | } | 807 | } |
| 734 | break; | 808 | break; |
| 735 | 809 | ||
| @@ -739,7 +813,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 739 | map->format.format_write = regmap_format_4_12_write; | 813 | map->format.format_write = regmap_format_4_12_write; |
| 740 | break; | 814 | break; |
| 741 | default: | 815 | default: |
| 742 | goto err_map; | 816 | goto err_hwlock; |
| 743 | } | 817 | } |
| 744 | break; | 818 | break; |
| 745 | 819 | ||
| @@ -749,7 +823,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 749 | map->format.format_write = regmap_format_7_9_write; | 823 | map->format.format_write = regmap_format_7_9_write; |
| 750 | break; | 824 | break; |
| 751 | default: | 825 | default: |
| 752 | goto err_map; | 826 | goto err_hwlock; |
| 753 | } | 827 | } |
| 754 | break; | 828 | break; |
| 755 | 829 | ||
| @@ -759,7 +833,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 759 | map->format.format_write = regmap_format_10_14_write; | 833 | map->format.format_write = regmap_format_10_14_write; |
| 760 | break; | 834 | break; |
| 761 | default: | 835 | default: |
| 762 | goto err_map; | 836 | goto err_hwlock; |
| 763 | } | 837 | } |
| 764 | break; | 838 | break; |
| 765 | 839 | ||
| @@ -779,13 +853,13 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 779 | map->format.format_reg = regmap_format_16_native; | 853 | map->format.format_reg = regmap_format_16_native; |
| 780 | break; | 854 | break; |
| 781 | default: | 855 | default: |
| 782 | goto err_map; | 856 | goto err_hwlock; |
| 783 | } | 857 | } |
| 784 | break; | 858 | break; |
| 785 | 859 | ||
| 786 | case 24: | 860 | case 24: |
| 787 | if (reg_endian != REGMAP_ENDIAN_BIG) | 861 | if (reg_endian != REGMAP_ENDIAN_BIG) |
| 788 | goto err_map; | 862 | goto err_hwlock; |
| 789 | map->format.format_reg = regmap_format_24; | 863 | map->format.format_reg = regmap_format_24; |
| 790 | break; | 864 | break; |
| 791 | 865 | ||
| @@ -801,7 +875,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 801 | map->format.format_reg = regmap_format_32_native; | 875 | map->format.format_reg = regmap_format_32_native; |
| 802 | break; | 876 | break; |
| 803 | default: | 877 | default: |
| 804 | goto err_map; | 878 | goto err_hwlock; |
| 805 | } | 879 | } |
| 806 | break; | 880 | break; |
| 807 | 881 | ||
| @@ -818,13 +892,13 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 818 | map->format.format_reg = regmap_format_64_native; | 892 | map->format.format_reg = regmap_format_64_native; |
| 819 | break; | 893 | break; |
| 820 | default: | 894 | default: |
| 821 | goto err_map; | 895 | goto err_hwlock; |
| 822 | } | 896 | } |
| 823 | break; | 897 | break; |
| 824 | #endif | 898 | #endif |
| 825 | 899 | ||
| 826 | default: | 900 | default: |
| 827 | goto err_map; | 901 | goto err_hwlock; |
| 828 | } | 902 | } |
| 829 | 903 | ||
| 830 | if (val_endian == REGMAP_ENDIAN_NATIVE) | 904 | if (val_endian == REGMAP_ENDIAN_NATIVE) |
| @@ -853,12 +927,12 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 853 | map->format.parse_val = regmap_parse_16_native; | 927 | map->format.parse_val = regmap_parse_16_native; |
| 854 | break; | 928 | break; |
| 855 | default: | 929 | default: |
| 856 | goto err_map; | 930 | goto err_hwlock; |
| 857 | } | 931 | } |
| 858 | break; | 932 | break; |
| 859 | case 24: | 933 | case 24: |
| 860 | if (val_endian != REGMAP_ENDIAN_BIG) | 934 | if (val_endian != REGMAP_ENDIAN_BIG) |
| 861 | goto err_map; | 935 | goto err_hwlock; |
| 862 | map->format.format_val = regmap_format_24; | 936 | map->format.format_val = regmap_format_24; |
| 863 | map->format.parse_val = regmap_parse_24; | 937 | map->format.parse_val = regmap_parse_24; |
| 864 | break; | 938 | break; |
| @@ -879,7 +953,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 879 | map->format.parse_val = regmap_parse_32_native; | 953 | map->format.parse_val = regmap_parse_32_native; |
| 880 | break; | 954 | break; |
| 881 | default: | 955 | default: |
| 882 | goto err_map; | 956 | goto err_hwlock; |
| 883 | } | 957 | } |
| 884 | break; | 958 | break; |
| 885 | #ifdef CONFIG_64BIT | 959 | #ifdef CONFIG_64BIT |
| @@ -900,7 +974,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 900 | map->format.parse_val = regmap_parse_64_native; | 974 | map->format.parse_val = regmap_parse_64_native; |
| 901 | break; | 975 | break; |
| 902 | default: | 976 | default: |
| 903 | goto err_map; | 977 | goto err_hwlock; |
| 904 | } | 978 | } |
| 905 | break; | 979 | break; |
| 906 | #endif | 980 | #endif |
| @@ -909,18 +983,18 @@ struct regmap *__regmap_init(struct device *dev, | |||
| 909 | if (map->format.format_write) { | 983 | if (map->format.format_write) { |
| 910 | if ((reg_endian != REGMAP_ENDIAN_BIG) || | 984 | if ((reg_endian != REGMAP_ENDIAN_BIG) || |
| 911 | (val_endian != REGMAP_ENDIAN_BIG)) | 985 | (val_endian != REGMAP_ENDIAN_BIG)) |
| 912 | goto err_map; | 986 | goto err_hwlock; |
| 913 | map->use_single_write = true; | 987 | map->use_single_write = true; |
| 914 | } | 988 | } |
| 915 | 989 | ||
| 916 | if (!map->format.format_write && | 990 | if (!map->format.format_write && |
| 917 | !(map->format.format_reg && map->format.format_val)) | 991 | !(map->format.format_reg && map->format.format_val)) |
| 918 | goto err_map; | 992 | goto err_hwlock; |
| 919 | 993 | ||
| 920 | map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); | 994 | map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); |
| 921 | if (map->work_buf == NULL) { | 995 | if (map->work_buf == NULL) { |
| 922 | ret = -ENOMEM; | 996 | ret = -ENOMEM; |
| 923 | goto err_map; | 997 | goto err_hwlock; |
| 924 | } | 998 | } |
| 925 | 999 | ||
| 926 | if (map->format.format_write) { | 1000 | if (map->format.format_write) { |
| @@ -1041,6 +1115,9 @@ err_regcache: | |||
| 1041 | err_range: | 1115 | err_range: |
| 1042 | regmap_range_exit(map); | 1116 | regmap_range_exit(map); |
| 1043 | kfree(map->work_buf); | 1117 | kfree(map->work_buf); |
| 1118 | err_hwlock: | ||
| 1119 | if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) | ||
| 1120 | hwspin_lock_free(map->hwlock); | ||
| 1044 | err_map: | 1121 | err_map: |
| 1045 | kfree(map); | 1122 | kfree(map); |
| 1046 | err: | 1123 | err: |
| @@ -1228,6 +1305,8 @@ void regmap_exit(struct regmap *map) | |||
| 1228 | kfree(async->work_buf); | 1305 | kfree(async->work_buf); |
| 1229 | kfree(async); | 1306 | kfree(async); |
| 1230 | } | 1307 | } |
| 1308 | if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) | ||
| 1309 | hwspin_lock_free(map->hwlock); | ||
| 1231 | kfree(map); | 1310 | kfree(map); |
| 1232 | } | 1311 | } |
| 1233 | EXPORT_SYMBOL_GPL(regmap_exit); | 1312 | EXPORT_SYMBOL_GPL(regmap_exit); |
