regmap: Add can_sleep configuration option
authorDmitry Osipenko <digetx@gmail.com>
Wed, 2 Sep 2020 14:18:43 +0000 (17:18 +0300)
committerMark Brown <broonie@kernel.org>
Wed, 2 Sep 2020 18:53:27 +0000 (19:53 +0100)
Regmap can't sleep if spinlock is used for the locking protection.
This patch fixes regression caused by a previous commit that switched
regmap to use fsleep() and this broke Amlogic S922X platform.

This patch adds new configuration option for regmap users, allowing to
specify whether regmap operations can sleep and assuming that sleep is
allowed if mutex is used for the regmap locking protection.

Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Fixes: 2b32d2f7ce0a ("regmap: Use flexible sleep")
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20200902141843.6591-1-digetx@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/internal.h
drivers/base/regmap/regmap.c
include/linux/regmap.h

index 3d80c4b43f72017c670329cb744230fee176933c..8a59359e145f694949f3844c293b8f2788857fa0 100644 (file)
@@ -161,6 +161,9 @@ struct regmap {
        void *selector_work_buf;        /* Scratch buffer used for selector */
 
        struct hwspinlock *hwlock;
+
+       /* if set, the regmap core can sleep */
+       bool can_sleep;
 };
 
 struct regcache_ops {
index a417cb1a11dc31cf80eb35dbd481fdc4ecc13784..2807e544658e0f4e4981d672f804e62fbbb1ec7c 100644 (file)
@@ -697,11 +697,13 @@ struct regmap *__regmap_init(struct device *dev,
 
        if (config->disable_locking) {
                map->lock = map->unlock = regmap_lock_unlock_none;
+               map->can_sleep = config->can_sleep;
                regmap_debugfs_disable(map);
        } else if (config->lock && config->unlock) {
                map->lock = config->lock;
                map->unlock = config->unlock;
                map->lock_arg = config->lock_arg;
+               map->can_sleep = config->can_sleep;
        } else if (config->use_hwlock) {
                map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
                if (!map->hwlock) {
@@ -737,6 +739,7 @@ struct regmap *__regmap_init(struct device *dev,
                        mutex_init(&map->mutex);
                        map->lock = regmap_lock_mutex;
                        map->unlock = regmap_unlock_mutex;
+                       map->can_sleep = true;
                        lockdep_set_class_and_name(&map->mutex,
                                                   lock_key, lock_name);
                }
@@ -2230,8 +2233,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
                                if (ret != 0)
                                        return ret;
 
-                               if (regs[i].delay_us)
-                                       fsleep(regs[i].delay_us);
+                               if (regs[i].delay_us) {
+                                       if (map->can_sleep)
+                                               fsleep(regs[i].delay_us);
+                                       else
+                                               udelay(regs[i].delay_us);
+                               }
 
                                base += n;
                                n = 0;
@@ -2267,8 +2274,12 @@ static int _regmap_multi_reg_write(struct regmap *map,
                        if (ret != 0)
                                return ret;
 
-                       if (regs[i].delay_us)
-                               fsleep(regs[i].delay_us);
+                       if (regs[i].delay_us) {
+                               if (map->can_sleep)
+                                       fsleep(regs[i].delay_us);
+                               else
+                                       udelay(regs[i].delay_us);
+                       }
                }
                return 0;
        }
index d865d8fea535e4f25223dab0b96fb88114ddb228..0c49d59168b58edb33f1cd5e426fb4fc6815f2f2 100644 (file)
@@ -342,6 +342,7 @@ typedef void (*regmap_unlock)(void *);
  * @hwlock_id: Specify the hardware spinlock id.
  * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
  *              HWLOCK_IRQ or 0.
+ * @can_sleep: Optional, specifies whether regmap operations can sleep.
  */
 struct regmap_config {
        const char *name;
@@ -398,6 +399,8 @@ struct regmap_config {
        bool use_hwlock;
        unsigned int hwlock_id;
        unsigned int hwlock_mode;
+
+       bool can_sleep;
 };
 
 /**