]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'regmap/topic/drivers' into regmap-next
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 14 Mar 2012 13:13:25 +0000 (13:13 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 14 Mar 2012 13:13:25 +0000 (13:13 +0000)
Resolved simple add/add conflicts:
drivers/base/regmap/internal.h
drivers/base/regmap/regmap.c

1  2 
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index e93d7b7d1cf90ecdafdf87e4fcb6f6a658c2fed1,d141b80479b5257d9fff00b9be47e47029e0f163..abd76678ed7309036c3b1e6091422bfba2078659
@@@ -22,7 -22,6 +22,7 @@@ struct regcache_ops
  struct regmap_format {
        size_t buf_size;
        size_t reg_bytes;
 +      size_t pad_bytes;
        size_t val_bytes;
        void (*format_write)(struct regmap *map,
                             unsigned int reg, unsigned int val);
@@@ -66,16 -65,19 +66,19 @@@ struct regmap 
        unsigned int num_reg_defaults_raw;
  
        /* if set, only the cache is modified not the HW */
 -      unsigned int cache_only:1;
 +      u32 cache_only;
        /* if set, only the HW is modified not the cache */
 -      unsigned int cache_bypass:1;
 +      u32 cache_bypass;
        /* if set, remember to free reg_defaults_raw */
 -      unsigned int cache_free:1;
 +      bool cache_free;
  
        struct reg_default *reg_defaults;
        const void *reg_defaults_raw;
        void *cache;
 -      bool cache_dirty;
 +      u32 cache_dirty;
+       struct reg_default *patch;
+       int patch_regs;
  };
  
  struct regcache_ops {
index 2d89ce08f1373d3069b4704bb87e383b26e3ae50,e9032c3290675a79571a521aebd06c8cc3500426..8db713ffef66eed4eb4739f90af93eed4b616d7d
@@@ -53,7 -53,7 +53,7 @@@ static int regcache_hw_init(struct regm
        for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
                val = regcache_get_val(map->reg_defaults_raw,
                                       i, map->cache_word_size);
-               if (!val)
+               if (regmap_volatile(map, i))
                        continue;
                count++;
        }
@@@ -70,7 -70,7 +70,7 @@@
        for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
                val = regcache_get_val(map->reg_defaults_raw,
                                       i, map->cache_word_size);
-               if (!val)
+               if (regmap_volatile(map, i))
                        continue;
                map->reg_defaults[j].reg = i;
                map->reg_defaults[j].def = val;
@@@ -211,6 -211,7 +211,6 @@@ int regcache_read(struct regmap *map
  
        return -EINVAL;
  }
 -EXPORT_SYMBOL_GPL(regcache_read);
  
  /**
   * regcache_write: Set the value of a given register in the cache.
@@@ -237,6 -238,7 +237,6 @@@ int regcache_write(struct regmap *map
  
        return 0;
  }
 -EXPORT_SYMBOL_GPL(regcache_write);
  
  /**
   * regcache_sync: Sync the register cache with the hardware.
@@@ -266,8 -268,22 +266,22 @@@ int regcache_sync(struct regmap *map
                map->cache_ops->name);
        name = map->cache_ops->name;
        trace_regcache_sync(map->dev, name, "start");
        if (!map->cache_dirty)
                goto out;
+       /* Apply any patch first */
+       map->cache_bypass = 1;
+       for (i = 0; i < map->patch_regs; i++) {
+               ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def);
+               if (ret != 0) {
+                       dev_err(map->dev, "Failed to write %x = %x: %d\n",
+                               map->patch[i].reg, map->patch[i].def, ret);
+                       goto out;
+               }
+       }
+       map->cache_bypass = 0;
        if (map->cache_ops->sync) {
                ret = map->cache_ops->sync(map);
        } else {
@@@ -313,7 -329,6 +327,7 @@@ void regcache_cache_only(struct regmap 
        mutex_lock(&map->lock);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
 +      trace_regmap_cache_only(map->dev, enable);
        mutex_unlock(&map->lock);
  }
  EXPORT_SYMBOL_GPL(regcache_cache_only);
@@@ -351,7 -366,6 +365,7 @@@ void regcache_cache_bypass(struct regma
        mutex_lock(&map->lock);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
 +      trace_regmap_cache_bypass(map->dev, enable);
        mutex_unlock(&map->lock);
  }
  EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@@ -374,16 -388,10 +388,16 @@@ bool regcache_set_val(void *base, unsig
                cache[idx] = val;
                break;
        }
 +      case 4: {
 +              u32 *cache = base;
 +              if (cache[idx] == val)
 +                      return true;
 +              cache[idx] = val;
 +              break;
 +      }
        default:
                BUG();
        }
 -      /* unreachable */
        return false;
  }
  
@@@ -402,10 -410,6 +416,10 @@@ unsigned int regcache_get_val(const voi
                const u16 *cache = base;
                return cache[idx];
        }
 +      case 4: {
 +              const u32 *cache = base;
 +              return cache[idx];
 +      }
        default:
                BUG();
        }
index 58f84c3a6fc1031261f9d78cbdd9ee5101a096e5,1752f13ddebc391b27dee4b791b9676de69f515d..e3ee9cabccb46d9ff31d2954715308c08007aedd
@@@ -10,9 -10,8 +10,9 @@@
   * published by the Free Software Foundation.
   */
  
 +#include <linux/device.h>
  #include <linux/slab.h>
 -#include <linux/module.h>
 +#include <linux/export.h>
  #include <linux/mutex.h>
  #include <linux/err.h>
  
@@@ -37,9 -36,6 +37,9 @@@ bool regmap_readable(struct regmap *map
        if (map->max_register && reg > map->max_register)
                return false;
  
 +      if (map->format.format_write)
 +              return false;
 +
        if (map->readable_reg)
                return map->readable_reg(map->dev, reg);
  
@@@ -48,7 -44,7 +48,7 @@@
  
  bool regmap_volatile(struct regmap *map, unsigned int reg)
  {
 -      if (map->max_register && reg > map->max_register)
 +      if (!regmap_readable(map, reg))
                return false;
  
        if (map->volatile_reg)
@@@ -59,7 -55,7 +59,7 @@@
  
  bool regmap_precious(struct regmap *map, unsigned int reg)
  {
 -      if (map->max_register && reg > map->max_register)
 +      if (!regmap_readable(map, reg))
                return false;
  
        if (map->precious_reg)
@@@ -80,14 -76,6 +80,14 @@@ static bool regmap_volatile_range(struc
        return true;
  }
  
 +static void regmap_format_2_6_write(struct regmap *map,
 +                                   unsigned int reg, unsigned int val)
 +{
 +      u8 *out = map->work_buf;
 +
 +      *out = (reg << 6) | val;
 +}
 +
  static void regmap_format_4_12_write(struct regmap *map,
                                     unsigned int reg, unsigned int val)
  {
@@@ -126,13 -114,6 +126,13 @@@ static void regmap_format_16(void *buf
        b[0] = cpu_to_be16(val);
  }
  
 +static void regmap_format_32(void *buf, unsigned int val)
 +{
 +      __be32 *b = buf;
 +
 +      b[0] = cpu_to_be32(val);
 +}
 +
  static unsigned int regmap_parse_8(void *buf)
  {
        u8 *b = buf;
@@@ -149,15 -130,6 +149,15 @@@ static unsigned int regmap_parse_16(voi
        return b[0];
  }
  
 +static unsigned int regmap_parse_32(void *buf)
 +{
 +      __be32 *b = buf;
 +
 +      b[0] = be32_to_cpu(b[0]);
 +
 +      return b[0];
 +}
 +
  /**
   * regmap_init(): Initialise register map
   *
@@@ -187,10 -159,8 +187,10 @@@ struct regmap *regmap_init(struct devic
  
        mutex_init(&map->lock);
        map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
 -      map->format.reg_bytes = config->reg_bits / 8;
 -      map->format.val_bytes = config->val_bits / 8;
 +      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);
 +      map->format.buf_size += map->format.pad_bytes;
        map->dev = dev;
        map->bus = bus;
        map->max_register = config->max_register;
        }
  
        switch (config->reg_bits) {
 +      case 2:
 +              switch (config->val_bits) {
 +              case 6:
 +                      map->format.format_write = regmap_format_2_6_write;
 +                      break;
 +              default:
 +                      goto err_map;
 +              }
 +              break;
 +
        case 4:
                switch (config->val_bits) {
                case 12:
                map->format.format_reg = regmap_format_16;
                break;
  
 +      case 32:
 +              map->format.format_reg = regmap_format_32;
 +              break;
 +
        default:
                goto err_map;
        }
                map->format.format_val = regmap_format_16;
                map->format.parse_val = regmap_parse_16;
                break;
 +      case 32:
 +              map->format.format_val = regmap_format_32;
 +              map->format.parse_val = regmap_parse_32;
 +              break;
        }
  
        if (!map->format.format_write &&
            !(map->format.format_reg && map->format.format_val))
                goto err_map;
  
 -      map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
 +      map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
        if (map->work_buf == NULL) {
                ret = -ENOMEM;
                goto err_map;
@@@ -363,7 -315,6 +363,7 @@@ int regmap_reinit_cache(struct regmap *
        mutex_lock(&map->lock);
  
        regcache_exit(map);
 +      regmap_debugfs_exit(map);
  
        map->max_register = config->max_register;
        map->writeable_reg = config->writeable_reg;
        map->precious_reg = config->precious_reg;
        map->cache_type = config->cache_type;
  
 +      regmap_debugfs_init(map);
 +
+       map->cache_bypass = false;
+       map->cache_only = false;
        ret = regcache_init(map, config);
  
        mutex_unlock(&map->lock);
@@@ -419,28 -371,23 +422,28 @@@ static int _regmap_raw_write(struct reg
         * send the work_buf directly, otherwise try to do a gather
         * write.
         */
 -      if (val == map->work_buf + map->format.reg_bytes)
 +      if (val == (map->work_buf + map->format.pad_bytes +
 +                  map->format.reg_bytes))
                ret = map->bus->write(map->dev, map->work_buf,
 -                                    map->format.reg_bytes + val_len);
 +                                    map->format.reg_bytes +
 +                                    map->format.pad_bytes +
 +                                    val_len);
        else if (map->bus->gather_write)
                ret = map->bus->gather_write(map->dev, map->work_buf,
 -                                           map->format.reg_bytes,
 +                                           map->format.reg_bytes +
 +                                           map->format.pad_bytes,
                                             val, val_len);
  
        /* If that didn't work fall back on linearising by hand. */
        if (ret == -ENOTSUPP) {
 -              len = map->format.reg_bytes + val_len;
 -              buf = kmalloc(len, GFP_KERNEL);
 +              len = map->format.reg_bytes + map->format.pad_bytes + val_len;
 +              buf = kzalloc(len, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
  
                memcpy(buf, map->work_buf, map->format.reg_bytes);
 -              memcpy(buf + map->format.reg_bytes, val, val_len);
 +              memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
 +                     val, val_len);
                ret = map->bus->write(map->dev, buf, len);
  
                kfree(buf);
@@@ -482,12 -429,10 +485,12 @@@ int _regmap_write(struct regmap *map, u
  
                return ret;
        } else {
 -              map->format.format_val(map->work_buf + map->format.reg_bytes,
 -                                     val);
 +              map->format.format_val(map->work_buf + map->format.reg_bytes
 +                                     + map->format.pad_bytes, val);
                return _regmap_raw_write(map, reg,
 -                                       map->work_buf + map->format.reg_bytes,
 +                                       map->work_buf +
 +                                       map->format.reg_bytes +
 +                                       map->format.pad_bytes,
                                         map->format.val_bytes);
        }
  }
@@@ -570,8 -515,7 +573,8 @@@ static int _regmap_raw_read(struct regm
        trace_regmap_hw_read_start(map->dev, reg,
                                   val_len / map->format.val_bytes);
  
 -      ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
 +      ret = map->bus->read(map->dev, map->work_buf,
 +                           map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
  
        trace_regmap_hw_read_done(map->dev, reg,
@@@ -644,32 -588,16 +647,32 @@@ EXPORT_SYMBOL_GPL(regmap_read)
  int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                    size_t val_len)
  {
 -      size_t val_count = val_len / map->format.val_bytes;
 -      int ret;
 -
 -      WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
 -              map->cache_type != REGCACHE_NONE);
 +      size_t val_bytes = map->format.val_bytes;
 +      size_t val_count = val_len / val_bytes;
 +      unsigned int v;
 +      int ret, i;
  
        mutex_lock(&map->lock);
  
 -      ret = _regmap_raw_read(map, reg, val, val_len);
 +      if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
 +          map->cache_type == REGCACHE_NONE) {
 +              /* Physical block read if there's no cache involved */
 +              ret = _regmap_raw_read(map, reg, val, val_len);
 +
 +      } else {
 +              /* Otherwise go word by word for the cache; should be low
 +               * cost as we expect to hit the cache.
 +               */
 +              for (i = 0; i < val_count; i++) {
 +                      ret = _regmap_read(map, reg + i, &v);
 +                      if (ret != 0)
 +                              goto out;
 +
 +                      map->format.format_val(val + (i * val_bytes), v);
 +              }
 +      }
  
 + out:
        mutex_unlock(&map->lock);
  
        return ret;
@@@ -783,6 -711,64 +786,64 @@@ int regmap_update_bits_check(struct reg
  }
  EXPORT_SYMBOL_GPL(regmap_update_bits_check);
  
+ /**
+  * regmap_register_patch: Register and apply register updates to be applied
+  *                        on device initialistion
+  *
+  * @map: Register map to apply updates to.
+  * @regs: Values to update.
+  * @num_regs: Number of entries in regs.
+  *
+  * Register a set of register updates to be applied to the device
+  * whenever the device registers are synchronised with the cache and
+  * apply them immediately.  Typically this is used to apply
+  * corrections to be applied to the device defaults on startup, such
+  * as the updates some vendors provide to undocumented registers.
+  */
+ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+                         int num_regs)
+ {
+       int i, ret;
+       bool bypass;
+       /* If needed the implementation can be extended to support this */
+       if (map->patch)
+               return -EBUSY;
+       mutex_lock(&map->lock);
+       bypass = map->cache_bypass;
+       map->cache_bypass = true;
+       /* Write out first; it's useful to apply even if we fail later. */
+       for (i = 0; i < num_regs; i++) {
+               ret = _regmap_write(map, regs[i].reg, regs[i].def);
+               if (ret != 0) {
+                       dev_err(map->dev, "Failed to write %x = %x: %d\n",
+                               regs[i].reg, regs[i].def, ret);
+                       goto out;
+               }
+       }
+       map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
+       if (map->patch != NULL) {
+               memcpy(map->patch, regs,
+                      num_regs * sizeof(struct reg_default));
+               map->patch_regs = num_regs;
+       } else {
+               ret = -ENOMEM;
+       }
+ out:
+       map->cache_bypass = bypass;
+       mutex_unlock(&map->lock);
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(regmap_register_patch);
  static int __init regmap_initcall(void)
  {
        regmap_debugfs_initcall();
diff --combined include/linux/regmap.h
index 5b0908a7f5bfa26e08f646da41b7eea90087d755,4a957fdb46f13c06156f4ded821d03287c11ba98..56ca477d5098fdbcb2f0122063b86b9195d0761d
@@@ -19,7 -19,6 +19,7 @@@
  struct module;
  struct i2c_client;
  struct spi_device;
 +struct regmap;
  
  /* An enum of all the supported cache types */
  enum regcache_type {
@@@ -41,13 -40,10 +41,13 @@@ struct reg_default 
        unsigned int def;
  };
  
 +#ifdef CONFIG_REGMAP
 +
  /**
   * Configuration for the register map of a device.
   *
   * @reg_bits: Number of bits in a register address, mandatory.
 + * @pad_bits: Number of bits of padding between register and value.
   * @val_bits: Number of bits in a register value, mandatory.
   *
   * @writeable_reg: Optional callback returning true if the register
@@@ -78,7 -74,6 +78,7 @@@
   */
  struct regmap_config {
        int reg_bits;
 +      int pad_bits;
        int val_bits;
  
        bool (*writeable_reg)(struct device *dev, unsigned int reg);
@@@ -162,6 -157,9 +162,9 @@@ void regcache_cache_only(struct regmap 
  void regcache_cache_bypass(struct regmap *map, bool enable);
  void regcache_mark_dirty(struct regmap *map);
  
+ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+                         int num_regs);
  /**
   * Description of an IRQ for the generic regmap irq_chip.
   *
@@@ -210,115 -208,4 +213,115 @@@ int regmap_add_irq_chip(struct regmap *
  void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
  int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
  
 +#else
 +
 +/*
 + * These stubs should only ever be called by generic code which has
 + * regmap based facilities, if they ever get called at runtime
 + * something is going wrong and something probably needs to select
 + * REGMAP.
 + */
 +
 +static inline int regmap_write(struct regmap *map, unsigned int reg,
 +                             unsigned int val)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
 +                                 const void *val, size_t val_len)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
 +                                  const void *val, size_t val_count)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_read(struct regmap *map, unsigned int reg,
 +                            unsigned int *val)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
 +                                void *val, size_t val_len)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
 +                                 void *val, size_t val_count)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
 +                                   unsigned int mask, unsigned int val)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_update_bits_check(struct regmap *map,
 +                                         unsigned int reg,
 +                                         unsigned int mask, unsigned int val,
 +                                         bool *change)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regmap_get_val_bytes(struct regmap *map)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regcache_sync(struct regmap *map)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline int regcache_sync_region(struct regmap *map, unsigned int min,
 +                                     unsigned int max)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +static inline void regcache_cache_only(struct regmap *map, bool enable)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +}
 +
 +static inline void regcache_cache_bypass(struct regmap *map, bool enable)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +}
 +
 +static inline void regcache_mark_dirty(struct regmap *map)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +}
 +
 +static inline int regmap_register_patch(struct regmap *map,
 +                                      const struct reg_default *regs,
 +                                      int num_regs)
 +{
 +      WARN_ONCE(1, "regmap API is disabled");
 +      return -EINVAL;
 +}
 +
 +#endif
 +
  #endif