From 9c2e5cb38da2202c6591efec631562116761521f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Aug 2017 08:57:36 +0200 Subject: regmap: constify regmap_bus structures These regmap_bus structures are only passed as the second argument to __devm_regmap_init or __regmap_init, both of which are const, so the regmap_bus structures can be const too. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-spi.c | 2 +- drivers/base/regmap/regmap-spmi.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') 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, return spi_write_then_read(spi, reg, reg_size, val, val_size); } -static struct regmap_bus regmap_spi = { +static const struct regmap_bus regmap_spi = { .write = regmap_spi_write, .gather_write = regmap_spi_gather_write, .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, count - 1); } -static struct regmap_bus regmap_spmi_base = { +static const struct regmap_bus regmap_spmi_base = { .read = regmap_spmi_base_read, .write = regmap_spmi_base_write, .gather_write = regmap_spmi_base_gather_write, @@ -203,7 +203,7 @@ static int regmap_spmi_ext_write(void *context, const void *data, count - 2); } -static struct regmap_bus regmap_spmi_ext = { +static const struct regmap_bus regmap_spmi_ext = { .read = regmap_spmi_ext_read, .write = regmap_spmi_ext_write, .gather_write = regmap_spmi_ext_gather_write, -- cgit From 8698b9364710e7bac84b3af07dd410e39c8c2e08 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Wed, 1 Nov 2017 10:11:55 +0800 Subject: 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 Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 2 + drivers/base/regmap/regmap.c | 101 ++++++++++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 16 deletions(-) (limited to 'drivers') 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 { struct rb_root range_tree; void *selector_work_buf; /* Scratch buffer used for selector */ + + struct hwspinlock *hwlock; }; struct 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 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -413,6 +414,49 @@ static unsigned int regmap_parse_64_native(const void *buf) } #endif +static void regmap_lock_hwlock(void *__map) +{ + struct regmap *map = __map; + + hwspin_lock_timeout(map->hwlock, UINT_MAX); +} + +static void regmap_lock_hwlock_irq(void *__map) +{ + struct regmap *map = __map; + + hwspin_lock_timeout_irq(map->hwlock, UINT_MAX); +} + +static void regmap_lock_hwlock_irqsave(void *__map) +{ + struct regmap *map = __map; + + hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX, + &map->spinlock_flags); +} + +static void regmap_unlock_hwlock(void *__map) +{ + struct regmap *map = __map; + + hwspin_unlock(map->hwlock); +} + +static void regmap_unlock_hwlock_irq(void *__map) +{ + struct regmap *map = __map; + + hwspin_unlock_irq(map->hwlock); +} + +static void regmap_unlock_hwlock_irqrestore(void *__map) +{ + struct regmap *map = __map; + + hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags); +} + static void regmap_lock_mutex(void *__map) { struct regmap *map = __map; @@ -627,6 +671,29 @@ struct regmap *__regmap_init(struct device *dev, map->lock = config->lock; map->unlock = config->unlock; map->lock_arg = config->lock_arg; + } else if (config->hwlock_id) { + map->hwlock = hwspin_lock_request_specific(config->hwlock_id); + if (!map->hwlock) { + ret = -ENXIO; + goto err_map; + } + + switch (config->hwlock_mode) { + case HWLOCK_IRQSTATE: + map->lock = regmap_lock_hwlock_irqsave; + map->unlock = regmap_unlock_hwlock_irqrestore; + break; + case HWLOCK_IRQ: + map->lock = regmap_lock_hwlock_irq; + map->unlock = regmap_unlock_hwlock_irq; + break; + default: + map->lock = regmap_lock_hwlock; + map->unlock = regmap_unlock_hwlock; + break; + } + + map->lock_arg = map; } else { if ((bus && bus->fast_io) || config->fast_io) { @@ -729,7 +796,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_write = regmap_format_2_6_write; break; default: - goto err_map; + goto err_hwlock; } break; @@ -739,7 +806,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_write = regmap_format_4_12_write; break; default: - goto err_map; + goto err_hwlock; } break; @@ -749,7 +816,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_write = regmap_format_7_9_write; break; default: - goto err_map; + goto err_hwlock; } break; @@ -759,7 +826,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_write = regmap_format_10_14_write; break; default: - goto err_map; + goto err_hwlock; } break; @@ -779,13 +846,13 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_reg = regmap_format_16_native; break; default: - goto err_map; + goto err_hwlock; } break; case 24: if (reg_endian != REGMAP_ENDIAN_BIG) - goto err_map; + goto err_hwlock; map->format.format_reg = regmap_format_24; break; @@ -801,7 +868,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_reg = regmap_format_32_native; break; default: - goto err_map; + goto err_hwlock; } break; @@ -818,13 +885,13 @@ struct regmap *__regmap_init(struct device *dev, map->format.format_reg = regmap_format_64_native; break; default: - goto err_map; + goto err_hwlock; } break; #endif default: - goto err_map; + goto err_hwlock; } if (val_endian == REGMAP_ENDIAN_NATIVE) @@ -853,12 +920,12 @@ struct regmap *__regmap_init(struct device *dev, map->format.parse_val = regmap_parse_16_native; break; default: - goto err_map; + goto err_hwlock; } break; case 24: if (val_endian != REGMAP_ENDIAN_BIG) - goto err_map; + goto err_hwlock; map->format.format_val = regmap_format_24; map->format.parse_val = regmap_parse_24; break; @@ -879,7 +946,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.parse_val = regmap_parse_32_native; break; default: - goto err_map; + goto err_hwlock; } break; #ifdef CONFIG_64BIT @@ -900,7 +967,7 @@ struct regmap *__regmap_init(struct device *dev, map->format.parse_val = regmap_parse_64_native; break; default: - goto err_map; + goto err_hwlock; } break; #endif @@ -909,18 +976,18 @@ struct regmap *__regmap_init(struct device *dev, if (map->format.format_write) { if ((reg_endian != REGMAP_ENDIAN_BIG) || (val_endian != REGMAP_ENDIAN_BIG)) - goto err_map; + goto err_hwlock; map->use_single_write = true; } if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) - goto err_map; + goto err_hwlock; map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; - goto err_map; + goto err_hwlock; } if (map->format.format_write) { @@ -1041,6 +1108,8 @@ err_regcache: err_range: regmap_range_exit(map); kfree(map->work_buf); +err_hwlock: + hwspin_lock_free(map->hwlock); err_map: kfree(map); err: -- cgit From f25637a6b89e59eddf79f6df39b23e202753f555 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 3 Nov 2017 12:38:04 +0100 Subject: regmap: Add a config option for hwspinlock Unlike other lock types hwspinlocks are optional and can be built modular so we can't use them unconditionally in regmap so add a config option that drivers that want to use hwspinlocks with regmap can select which will ensure that hwspinlock is built in. Signed-off-by: Mark Brown --- drivers/base/regmap/Kconfig | 4 ++++ drivers/base/regmap/regmap.c | 7 +++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 073c0b77e5b3..2d5e849f79c9 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -5,6 +5,7 @@ config REGMAP default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) select IRQ_DOMAIN if REGMAP_IRQ + select HWSPINLOCK if REGMAP_HWSPINLOCK bool config REGCACHE_COMPRESSED @@ -36,3 +37,6 @@ config REGMAP_MMIO config REGMAP_IRQ bool + +config REGMAP_HWSPINLOCK + bool diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 999e981a174a..ff6ef6a579c6 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -414,6 +414,7 @@ static unsigned int regmap_parse_64_native(const void *buf) } #endif +#ifdef REGMAP_HWSPINLOCK static void regmap_lock_hwlock(void *__map) { struct regmap *map = __map; @@ -456,6 +457,7 @@ static void regmap_unlock_hwlock_irqrestore(void *__map) hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags); } +#endif static void regmap_lock_mutex(void *__map) { @@ -672,6 +674,7 @@ struct regmap *__regmap_init(struct device *dev, map->unlock = config->unlock; map->lock_arg = config->lock_arg; } else if (config->hwlock_id) { +#ifdef REGMAP_HWSPINLOCK map->hwlock = hwspin_lock_request_specific(config->hwlock_id); if (!map->hwlock) { ret = -ENXIO; @@ -694,6 +697,10 @@ struct regmap *__regmap_init(struct device *dev, } map->lock_arg = map; +#else + ret = -EINVAL; + goto err; +#endif } else { if ((bus && bus->fast_io) || config->fast_io) { -- cgit From 267f3e4f18f1ccf9e8cf72c3b4689df03025516d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 3 Nov 2017 19:50:20 +0000 Subject: regmap: Also protect hwspinlock in error handling path The previous patch to allow the hwspinlock code to be disabled missed handling the free in the error path, do so using the better IS_ENABLED() pattern as suggested by Baolin. While we're at it also check that we have a hardware spinlock before freeing it - the core code reports an error when freeing an invalid lock. Suggested-by: Baolin Wang Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ff6ef6a579c6..5ff549fa880b 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1116,7 +1116,8 @@ err_range: regmap_range_exit(map); kfree(map->work_buf); err_hwlock: - hwspin_lock_free(map->hwlock); + if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) + hwspin_lock_free(map->hwlock); err_map: kfree(map); err: -- cgit From e8419c40a5ad58eaa112173f554148accc6794f3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 3 Nov 2017 19:53:56 +0000 Subject: regmap: Clean up hwspinlock on regmap exit We should free any hwspinlocks when we destroy the regmap, do so. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 5ff549fa880b..bfe2f250d011 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1305,6 +1305,8 @@ void regmap_exit(struct regmap *map) kfree(async->work_buf); kfree(async); } + if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock) + hwspin_lock_free(map->hwlock); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); -- cgit From ca0db18da26a47f824fe79e6870ad19470a45525 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 6 Nov 2017 11:18:37 +0000 Subject: regmap: Try to work around Kconfig exploding on HWSPINLOCK Trying to work with hwspinlock from built in code is painful as it can be built modular. Invert the test for REGMAP_HWSPINLOCK for now so we end up requiring users to depend on HWSPINLOCK=y in order to turn on the hwspinlock code. Signed-off-by: Mark Brown --- drivers/base/regmap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 2d5e849f79c9..e7fa7b4bf9af 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -5,7 +5,7 @@ config REGMAP default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) select IRQ_DOMAIN if REGMAP_IRQ - select HWSPINLOCK if REGMAP_HWSPINLOCK + select REGMAP_HWSPINLOCK if HWSPINLOCK=y bool config REGCACHE_COMPRESSED -- cgit From c077fadf4d1e05bcdd7ddb07758cbd8acf0033f6 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Sat, 4 Nov 2017 14:08:23 +0800 Subject: regmap: Fix unused warning This patch fixes the warning of label 'err_map' defined but not used. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index bfe2f250d011..8d516a9bfc01 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -699,7 +699,7 @@ struct regmap *__regmap_init(struct device *dev, map->lock_arg = map; #else ret = -EINVAL; - goto err; + goto err_map; #endif } else { if ((bus && bus->fast_io) || -- cgit