Merge remote-tracking branches 'regmap/topic/const' and 'regmap/topic/hwspinlock...
authorMark Brown <broonie@kernel.org>
Mon, 6 Nov 2017 11:39:41 +0000 (11:39 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 6 Nov 2017 11:39:41 +0000 (11:39 +0000)
drivers/base/regmap/Kconfig
drivers/base/regmap/internal.h
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap-spmi.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index 073c0b77e5b301f263fca13cd869cc20aef74d77..e7fa7b4bf9af3045c2c17cf0effe58c98aead5a7 100644 (file)
@@ -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 REGMAP_HWSPINLOCK if HWSPINLOCK=y
        bool
 
 config REGCACHE_COMPRESSED
@@ -36,3 +37,6 @@ config REGMAP_MMIO
 
 config REGMAP_IRQ
        bool
+
+config REGMAP_HWSPINLOCK
+       bool
index 2a4435d760289118f00882fb89693346972ae996..8641183cac2ff35ae883b8913b00831fa3a5af8a 100644 (file)
@@ -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 {
index edd9a839d004dcf98ab46b15c9002c958ad6fe56..c7150dd264d5806ca2fd0581b7c972c79949920e 100644 (file)
@@ -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,
index 4a36e415e938560ce2e3ba927b81888444767a7d..0bfb8ed244d50c054f3a1d88d78a32ea942930eb 100644 (file)
@@ -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,
index b9a779a4a739cda497351be2b2dc51d69f35c022..8d516a9bfc01722567588523b92e7fdcc2b75339 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/log2.h>
+#include <linux/hwspinlock.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -413,6 +414,51 @@ 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;
+
+       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);
+}
+#endif
+
 static void regmap_lock_mutex(void *__map)
 {
        struct regmap *map = __map;
@@ -627,6 +673,34 @@ 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) {
+#ifdef REGMAP_HWSPINLOCK
+               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
+               ret = -EINVAL;
+               goto err_map;
+#endif
        } else {
                if ((bus && bus->fast_io) ||
                    config->fast_io) {
@@ -729,7 +803,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 +813,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 +823,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 +833,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 +853,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 +875,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 +892,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 +927,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 +953,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 +974,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 +983,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 +1115,9 @@ err_regcache:
 err_range:
        regmap_range_exit(map);
        kfree(map->work_buf);
+err_hwlock:
+       if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock)
+               hwspin_lock_free(map->hwlock);
 err_map:
        kfree(map);
 err:
@@ -1228,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);
index edad98890b9b69833bd331bf983171675da1d6be..15eddc1353bae3a272f6bbae881abe97981c0a6b 100644 (file)
@@ -317,6 +317,9 @@ typedef void (*regmap_unlock)(void *);
  *
  * @ranges: Array of configuration entries for virtual address ranges.
  * @num_ranges: Number of range configuration entries.
+ * @hwlock_id: Specify the hardware spinlock id.
+ * @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
+ *              HWLOCK_IRQ or 0.
  */
 struct regmap_config {
        const char *name;
@@ -361,6 +364,9 @@ struct regmap_config {
 
        const struct regmap_range_cfg *ranges;
        unsigned int num_ranges;
+
+       unsigned int hwlock_id;
+       unsigned int hwlock_mode;
 };
 
 /**