Merge tag 'regmap-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 3 Nov 2015 00:16:24 +0000 (16:16 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 3 Nov 2015 00:16:24 +0000 (16:16 -0800)
Pull regmap updates from Mark Brown:
 "Quite a few new features for regmap this time, mostly expanding things
  around the edges of the existing functionality to cover more devices
  rather than thinsg with wide applicability:

   - Support for offload of the update_bits() operation to hardware
     where devices implement bit level access.
   - Support for a few extra operations that need scratch buffers on
     fast_io devices where we can't sleep.
   - Expanded the feature set of regmap_irq to cope with some extra
     register layouts.
   - Cleanups to the debugfs code"

* tag 'regmap-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Allow installing custom reg_update_bits function
  regmap: debugfs: simplify regmap_reg_ranges_read_file() slightly
  regmap: debugfs: use memcpy instead of snprintf
  regmap: debugfs: use snprintf return value in regmap_reg_ranges_read_file()
  regmap: Add generic macro to define regmap_irq
  regmap: debugfs: Remove scratch buffer for register length calculation
  regmap: irq: add ack_invert flag for chips using cleared bits as ack
  regmap: irq: add support for chips who have separate unmask registers
  regmap: Allocate buffers with GFP_ATOMIC when fast_io == true

drivers/base/regmap/internal.h
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index cc557886ab2377a550c1ae529b6ecee23380161f..3250e53473a38957ecd12899612b6acaa5590283 100644 (file)
@@ -59,6 +59,7 @@ struct regmap {
        regmap_lock lock;
        regmap_unlock unlock;
        void *lock_arg; /* This is passed to lock/unlock functions */
+       gfp_t alloc_flags;
 
        struct device *dev; /* Device we do I/O on */
        void *work_buf;     /* Scratch buffer used to format I/O */
@@ -98,6 +99,8 @@ struct regmap {
 
        int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
        int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+       int (*reg_update_bits)(void *context, unsigned int reg,
+                              unsigned int mask, unsigned int val);
 
        bool defer_caching;
 
index 4c55cfbad19e95df8cb67864d78af960c073b4df..3f0a7e262d6982c63dcaf3e81f058b0c471d2880 100644 (file)
@@ -30,7 +30,7 @@ static LIST_HEAD(regmap_debugfs_early_list);
 static DEFINE_MUTEX(regmap_debugfs_early_lock);
 
 /* Calculate the length of a fixed format  */
-static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
+static size_t regmap_calc_reg_len(int max_val)
 {
        return snprintf(NULL, 0, "%x", max_val);
 }
@@ -173,8 +173,7 @@ static inline void regmap_calc_tot_len(struct regmap *map,
 {
        /* Calculate the length of a fixed format  */
        if (!map->debugfs_tot_len) {
-               map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
-                                                          buf, count);
+               map->debugfs_reg_len = regmap_calc_reg_len(map->max_register),
                map->debugfs_val_len = 2 * map->format.val_bytes;
                map->debugfs_tot_len = map->debugfs_reg_len +
                        map->debugfs_val_len + 3;      /* : \n */
@@ -338,6 +337,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
        char *buf;
        char *entry;
        int ret;
+       unsigned entry_len;
 
        if (*ppos < 0 || !count)
                return -EINVAL;
@@ -365,18 +365,15 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
        p = 0;
        mutex_lock(&map->cache_lock);
        list_for_each_entry(c, &map->debugfs_off_cache, list) {
-               snprintf(entry, PAGE_SIZE, "%x-%x",
-                        c->base_reg, c->max_reg);
+               entry_len = snprintf(entry, PAGE_SIZE, "%x-%x\n",
+                                    c->base_reg, c->max_reg);
                if (p >= *ppos) {
-                       if (buf_pos + 1 + strlen(entry) > count)
+                       if (buf_pos + entry_len > count)
                                break;
-                       snprintf(buf + buf_pos, count - buf_pos,
-                                "%s", entry);
-                       buf_pos += strlen(entry);
-                       buf[buf_pos] = '\n';
-                       buf_pos++;
+                       memcpy(buf + buf_pos, entry, entry_len);
+                       buf_pos += entry_len;
                }
-               p += strlen(entry) + 1;
+               p += entry_len;
        }
        mutex_unlock(&map->cache_lock);
 
@@ -420,7 +417,7 @@ static ssize_t regmap_access_read_file(struct file *file,
                return -ENOMEM;
 
        /* Calculate the length of a fixed format  */
-       reg_len = regmap_calc_reg_len(map->max_register, buf, count);
+       reg_len = regmap_calc_reg_len(map->max_register);
        tot_len = reg_len + 10; /* ': R W V P\n' */
 
        for (i = 0; i <= map->max_register; i += map->reg_stride) {
index 38d1f72d869cf4ceb698067f588f81b96e0102df..8d16db533527362efa638f67b69673607d069327 100644 (file)
@@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        struct regmap *map = d->map;
        int i, ret;
        u32 reg;
+       u32 unmask_offset;
 
        if (d->chip->runtime_pm) {
                ret = pm_runtime_get_sync(map->dev);
@@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        for (i = 0; i < d->chip->num_regs; i++) {
                reg = d->chip->mask_base +
                        (i * map->reg_stride * d->irq_reg_stride);
-               if (d->chip->mask_invert)
+               if (d->chip->mask_invert) {
                        ret = regmap_update_bits(d->map, reg,
                                         d->mask_buf_def[i], ~d->mask_buf[i]);
-               else
+               } else if (d->chip->unmask_base) {
+                       /* set mask with mask_base register */
+                       ret = regmap_update_bits(d->map, reg,
+                                       d->mask_buf_def[i], ~d->mask_buf[i]);
+                       if (ret < 0)
+                               dev_err(d->map->dev,
+                                       "Failed to sync unmasks in %x\n",
+                                       reg);
+                       unmask_offset = d->chip->unmask_base -
+                                                       d->chip->mask_base;
+                       /* clear mask with unmask_base register */
+                       ret = regmap_update_bits(d->map,
+                                       reg + unmask_offset,
+                                       d->mask_buf_def[i],
+                                       d->mask_buf[i]);
+               } else {
                        ret = regmap_update_bits(d->map, reg,
                                         d->mask_buf_def[i], d->mask_buf[i]);
+               }
                if (ret != 0)
                        dev_err(d->map->dev, "Failed to sync masks in %x\n",
                                reg);
@@ -116,7 +133,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
                        reg = d->chip->ack_base +
                                (i * map->reg_stride * d->irq_reg_stride);
-                       ret = regmap_write(map, reg, d->mask_buf[i]);
+                       /* some chips ack by write 0 */
+                       if (d->chip->ack_invert)
+                               ret = regmap_write(map, reg, ~d->mask_buf[i]);
+                       else
+                               ret = regmap_write(map, reg, d->mask_buf[i]);
                        if (ret != 0)
                                dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
                                        reg, ret);
@@ -339,6 +360,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        int i;
        int ret = -ENOMEM;
        u32 reg;
+       u32 unmask_offset;
 
        if (chip->num_regs <= 0)
                return -EINVAL;
@@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                if (chip->mask_invert)
                        ret = regmap_update_bits(map, reg,
                                         d->mask_buf[i], ~d->mask_buf[i]);
-               else
+               else if (d->chip->unmask_base) {
+                       unmask_offset = d->chip->unmask_base -
+                                       d->chip->mask_base;
+                       ret = regmap_update_bits(d->map,
+                                       reg + unmask_offset,
+                                       d->mask_buf[i],
+                                       d->mask_buf[i]);
+               } else
                        ret = regmap_update_bits(map, reg,
                                         d->mask_buf[i], d->mask_buf[i]);
                if (ret != 0) {
@@ -445,7 +474,11 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
                        reg = chip->ack_base +
                                (i * map->reg_stride * d->irq_reg_stride);
-                       ret = regmap_write(map, reg,
+                       if (chip->ack_invert)
+                               ret = regmap_write(map, reg,
+                                       ~(d->status_buf[i] & d->mask_buf[i]));
+                       else
+                               ret = regmap_write(map, reg,
                                        d->status_buf[i] & d->mask_buf[i]);
                        if (ret != 0) {
                                dev_err(map->dev, "Failed to ack 0x%x: %d\n",
index afaf56200674a29517678af763bc9a084659224b..4ac63c0e50c7e6a446847b7a29567834d4a5b073 100644 (file)
@@ -561,6 +561,16 @@ struct regmap *__regmap_init(struct device *dev,
                }
                map->lock_arg = map;
        }
+
+       /*
+        * When we write in fast-paths with regmap_bulk_write() don't allocate
+        * scratch buffers with sleeping allocations.
+        */
+       if ((bus && bus->fast_io) || config->fast_io)
+               map->alloc_flags = GFP_ATOMIC;
+       else
+               map->alloc_flags = GFP_KERNEL;
+
        map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
        map->format.pad_bytes = config->pad_bits / 8;
        map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
@@ -619,6 +629,7 @@ struct regmap *__regmap_init(struct device *dev,
                goto skip_format_initialization;
        } else {
                map->reg_read  = _regmap_bus_read;
+               map->reg_update_bits = bus->reg_update_bits;
        }
 
        reg_endian = regmap_get_reg_endian(bus, config);
@@ -1786,7 +1797,7 @@ out:
                if (!val_count)
                        return -EINVAL;
 
-               wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
+               wval = kmemdup(val, val_count * val_bytes, map->alloc_flags);
                if (!wval) {
                        dev_err(map->dev, "Error in memory allocation\n");
                        return -ENOMEM;
@@ -2509,20 +2520,26 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
        int ret;
        unsigned int tmp, orig;
 
-       ret = _regmap_read(map, reg, &orig);
-       if (ret != 0)
-               return ret;
+       if (change)
+               *change = false;
 
-       tmp = orig & ~mask;
-       tmp |= val & mask;
-
-       if (force_write || (tmp != orig)) {
-               ret = _regmap_write(map, reg, tmp);
-               if (change)
+       if (regmap_volatile(map, reg) && map->reg_update_bits) {
+               ret = map->reg_update_bits(map->bus_context, reg, mask, val);
+               if (ret == 0 && change)
                        *change = true;
        } else {
-               if (change)
-                       *change = false;
+               ret = _regmap_read(map, reg, &orig);
+               if (ret != 0)
+                       return ret;
+
+               tmp = orig & ~mask;
+               tmp |= val & mask;
+
+               if (force_write || (tmp != orig)) {
+                       ret = _regmap_write(map, reg, tmp);
+                       if (ret == 0 && change)
+                               *change = true;
+               }
        }
 
        return ret;
index 8fc0bfd8edc4434fc79fda8591323d6be41f0645..d68bb402120e2c1a6d640720ef384663ceaefebe 100644 (file)
@@ -296,6 +296,8 @@ typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
                                  unsigned int *val);
 typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
                                   unsigned int val);
+typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
+                                        unsigned int mask, unsigned int val);
 typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
 typedef void (*regmap_hw_free_context)(void *context);
 
@@ -335,6 +337,7 @@ struct regmap_bus {
        regmap_hw_gather_write gather_write;
        regmap_hw_async_write async_write;
        regmap_hw_reg_write reg_write;
+       regmap_hw_reg_update_bits reg_update_bits;
        regmap_hw_read read;
        regmap_hw_reg_read reg_read;
        regmap_hw_free_context free_context;
@@ -791,6 +794,9 @@ struct regmap_irq {
        unsigned int mask;
 };
 
+#define REGMAP_IRQ_REG(_irq, _off, _mask)              \
+       [_irq] = { .reg_offset = (_off), .mask = (_mask) }
+
 /**
  * Description of a generic regmap irq_chip.  This is not intended to
  * handle every possible interrupt controller, but it should handle a
@@ -800,6 +806,8 @@ struct regmap_irq {
  *
  * @status_base: Base status register address.
  * @mask_base:   Base mask register address.
+ * @unmask_base:  Base unmask register address. for chips who have
+ *                separate mask and unmask registers
  * @ack_base:    Base ack address. If zero then the chip is clear on read.
  *               Using zero value is possible with @use_ack bit.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
@@ -807,6 +815,7 @@ struct regmap_irq {
  * @init_ack_masked: Ack all masked interrupts once during initalization.
  * @mask_invert: Inverted mask register: cleared bits are masked out.
  * @use_ack:     Use @ack register even if it is zero.
+ * @ack_invert:  Inverted ack register: cleared bits for ack.
  * @wake_invert: Inverted wake register: cleared bits are wake enabled.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
@@ -820,12 +829,14 @@ struct regmap_irq_chip {
 
        unsigned int status_base;
        unsigned int mask_base;
+       unsigned int unmask_base;
        unsigned int ack_base;
        unsigned int wake_base;
        unsigned int irq_reg_stride;
        bool init_ack_masked:1;
        bool mask_invert:1;
        bool use_ack:1;
+       bool ack_invert:1;
        bool wake_invert:1;
        bool runtime_pm:1;