]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'topic/cache' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 5 Dec 2011 13:18:50 +0000 (13:18 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 5 Dec 2011 13:18:50 +0000 (13:18 +0000)
1  2 
drivers/base/regmap/regmap.c
include/linux/regmap.h

index add5da6d9c0aa00c90ce666f23e39a21bb798f2d,579e85b8a68458842b6cc918b316742ea0aa1554..be10a4ff660915625454375ce9fb30a97d5b7ef9
@@@ -64,18 -64,6 +64,18 @@@ bool regmap_precious(struct regmap *map
        return false;
  }
  
 +static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
 +      unsigned int num)
 +{
 +      unsigned int i;
 +
 +      for (i = 0; i < num; i++)
 +              if (!regmap_volatile(map, reg + i))
 +                      return false;
 +
 +      return true;
 +}
 +
  static void regmap_format_4_12_write(struct regmap *map,
                                     unsigned int reg, unsigned int val)
  {
@@@ -90,16 -78,6 +90,16 @@@ static void regmap_format_7_9_write(str
        *out = cpu_to_be16((reg << 9) | val);
  }
  
 +static void regmap_format_10_14_write(struct regmap *map,
 +                                  unsigned int reg, unsigned int val)
 +{
 +      u8 *out = map->work_buf;
 +
 +      out[2] = val;
 +      out[1] = (val >> 8) | (reg << 6);
 +      out[0] = reg >> 2;
 +}
 +
  static void regmap_format_8(void *buf, unsigned int val)
  {
        u8 *b = buf;
@@@ -149,7 -127,7 +149,7 @@@ struct regmap *regmap_init(struct devic
        int ret = -EINVAL;
  
        if (!bus || !config)
 -              return NULL;
 +              goto err;
  
        map = kzalloc(sizeof(*map), GFP_KERNEL);
        if (map == NULL) {
        map->volatile_reg = config->volatile_reg;
        map->precious_reg = config->precious_reg;
        map->cache_type = config->cache_type;
 -      map->reg_defaults = config->reg_defaults;
 -      map->num_reg_defaults = config->num_reg_defaults;
 -      map->num_reg_defaults_raw = config->num_reg_defaults_raw;
 -      map->reg_defaults_raw = config->reg_defaults_raw;
 -      map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw;
 -      map->cache_word_size = config->val_bits / 8;
  
        if (config->read_flag_mask || config->write_flag_mask) {
                map->read_flag_mask = config->read_flag_mask;
                }
                break;
  
 +      case 10:
 +              switch (config->val_bits) {
 +              case 14:
 +                      map->format.format_write = regmap_format_10_14_write;
 +                      break;
 +              default:
 +                      goto err_map;
 +              }
 +              break;
 +
        case 8:
                map->format.format_reg = regmap_format_8;
                break;
                goto err_map;
        }
  
 -      ret = regcache_init(map);
 -      if (ret < 0)
 -              goto err_map;
 -
        regmap_debugfs_init(map);
  
 +      ret = regcache_init(map, config);
 +      if (ret < 0)
 +              goto err_free_workbuf;
 +
        return map;
  
 +err_free_workbuf:
 +      kfree(map->work_buf);
  err_map:
        kfree(map);
  err:
  }
  EXPORT_SYMBOL_GPL(regmap_init);
  
+ /**
+  * regmap_reinit_cache(): Reinitialise the current register cache
+  *
+  * @map: Register map to operate on.
+  * @config: New configuration.  Only the cache data will be used.
+  *
+  * Discard any existing register cache for the map and initialize a
+  * new cache.  This can be used to restore the cache to defaults or to
+  * update the cache configuration to reflect runtime discovery of the
+  * hardware.
+  */
+ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
+ {
+       int ret;
+       mutex_lock(&map->lock);
+       regcache_exit(map);
+       map->max_register = config->max_register;
+       map->writeable_reg = config->writeable_reg;
+       map->readable_reg = config->readable_reg;
+       map->volatile_reg = config->volatile_reg;
+       map->precious_reg = config->precious_reg;
+       map->cache_type = config->cache_type;
+       ret = regcache_init(map, config);
+       mutex_unlock(&map->lock);
+       return ret;
+ }
  /**
   * regmap_exit(): Free a previously allocated register map
   */
@@@ -405,11 -410,9 +438,11 @@@ EXPORT_SYMBOL_GPL(regmap_write)
  int regmap_raw_write(struct regmap *map, unsigned int reg,
                     const void *val, size_t val_len)
  {
 +      size_t val_count = val_len / map->format.val_bytes;
        int ret;
  
 -      WARN_ON(map->cache_type != REGCACHE_NONE);
 +      WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
 +              map->cache_type != REGCACHE_NONE);
  
        mutex_lock(&map->lock);
  
@@@ -454,15 -457,15 +487,15 @@@ static int _regmap_read(struct regmap *
  {
        int ret;
  
 -      if (!map->format.parse_val)
 -              return -EINVAL;
 -
        if (!map->cache_bypass) {
                ret = regcache_read(map, reg, val);
                if (ret == 0)
                        return 0;
        }
  
 +      if (!map->format.parse_val)
 +              return -EINVAL;
 +
        if (map->cache_only)
                return -EBUSY;
  
@@@ -513,11 -516,15 +546,11 @@@ 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;
 -      int i;
 -      bool vol = true;
  
 -      for (i = 0; i < val_len / map->format.val_bytes; i++)
 -              if (!regmap_volatile(map, reg + i))
 -                      vol = false;
 -
 -      WARN_ON(!vol && map->cache_type != REGCACHE_NONE);
 +      WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
 +              map->cache_type != REGCACHE_NONE);
  
        mutex_lock(&map->lock);
  
@@@ -545,11 -552,16 +578,11 @@@ int regmap_bulk_read(struct regmap *map
  {
        int ret, i;
        size_t val_bytes = map->format.val_bytes;
 -      bool vol = true;
 +      bool vol = regmap_volatile_range(map, reg, val_count);
  
        if (!map->format.parse_val)
                return -EINVAL;
  
 -      /* Is this a block of volatile registers? */
 -      for (i = 0; i < val_count; i++)
 -              if (!regmap_volatile(map, reg + i))
 -                      vol = false;
 -
        if (vol || map->cache_type == REGCACHE_NONE) {
                ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
                if (ret != 0)
  }
  EXPORT_SYMBOL_GPL(regmap_bulk_read);
  
 -/**
 - * remap_update_bits: Perform a read/modify/write cycle on the register map
 - *
 - * @map: Register map to update
 - * @reg: Register to update
 - * @mask: Bitmask to change
 - * @val: New value for bitmask
 - *
 - * Returns zero for success, a negative number on error.
 - */
 -int regmap_update_bits(struct regmap *map, unsigned int reg,
 -                     unsigned int mask, unsigned int val)
 +static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 +                             unsigned int mask, unsigned int val,
 +                             bool *change)
  {
        int ret;
 -      unsigned int tmp;
 +      unsigned int tmp, orig;
  
        mutex_lock(&map->lock);
  
 -      ret = _regmap_read(map, reg, &tmp);
 +      ret = _regmap_read(map, reg, &orig);
        if (ret != 0)
                goto out;
  
 -      tmp &= ~mask;
 +      tmp = orig & ~mask;
        tmp |= val & mask;
  
 -      ret = _regmap_write(map, reg, tmp);
 +      if (tmp != orig) {
 +              ret = _regmap_write(map, reg, tmp);
 +              *change = true;
 +      } else {
 +              *change = false;
 +      }
  
  out:
        mutex_unlock(&map->lock);
  
        return ret;
  }
 +
 +/**
 + * regmap_update_bits: Perform a read/modify/write cycle on the register map
 + *
 + * @map: Register map to update
 + * @reg: Register to update
 + * @mask: Bitmask to change
 + * @val: New value for bitmask
 + *
 + * Returns zero for success, a negative number on error.
 + */
 +int regmap_update_bits(struct regmap *map, unsigned int reg,
 +                     unsigned int mask, unsigned int val)
 +{
 +      bool change;
 +      return _regmap_update_bits(map, reg, mask, val, &change);
 +}
  EXPORT_SYMBOL_GPL(regmap_update_bits);
  
 +/**
 + * regmap_update_bits_check: Perform a read/modify/write cycle on the
 + *                           register map and report if updated
 + *
 + * @map: Register map to update
 + * @reg: Register to update
 + * @mask: Bitmask to change
 + * @val: New value for bitmask
 + * @change: Boolean indicating if a write was done
 + *
 + * Returns zero for success, a negative number on error.
 + */
 +int regmap_update_bits_check(struct regmap *map, unsigned int reg,
 +                           unsigned int mask, unsigned int val,
 +                           bool *change)
 +{
 +      return _regmap_update_bits(map, reg, mask, val, change);
 +}
 +EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 +
  static int __init regmap_initcall(void)
  {
        regmap_debugfs_initcall();
diff --combined include/linux/regmap.h
index a83e4a097abd0e5288e1ebc9ea7467f5d634f4d1,86923a98a7664e5dd3dcd1bfff0016bda56689e1..cfce3a358fbf114036f44af141f7e244034208ad
@@@ -23,6 -23,7 +23,6 @@@ struct spi_device
  /* An enum of all the supported cache types */
  enum regcache_type {
        REGCACHE_NONE,
 -      REGCACHE_INDEXED,
        REGCACHE_RBTREE,
        REGCACHE_COMPRESSED
  };
@@@ -82,7 -83,7 +82,7 @@@ struct regmap_config 
        bool (*precious_reg)(struct device *dev, unsigned int reg);
  
        unsigned int max_register;
 -      struct reg_default *reg_defaults;
 +      const struct reg_default *reg_defaults;
        unsigned int num_reg_defaults;
        enum regcache_type cache_type;
        const void *reg_defaults_raw;
@@@ -128,6 -129,8 +128,8 @@@ struct regmap *regmap_init_spi(struct s
                               const struct regmap_config *config);
  
  void regmap_exit(struct regmap *map);
+ int regmap_reinit_cache(struct regmap *map,
+                       const struct regmap_config *config);
  int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
  int regmap_raw_write(struct regmap *map, unsigned int reg,
                     const void *val, size_t val_len);
@@@ -138,60 -141,10 +140,60 @@@ int regmap_bulk_read(struct regmap *map
                     size_t val_count);
  int regmap_update_bits(struct regmap *map, unsigned int reg,
                       unsigned int mask, unsigned int val);
 +int regmap_update_bits_check(struct regmap *map, unsigned int reg,
 +                           unsigned int mask, unsigned int val,
 +                           bool *change);
  
  int regcache_sync(struct regmap *map);
  void regcache_cache_only(struct regmap *map, bool enable);
  void regcache_cache_bypass(struct regmap *map, bool enable);
  void regcache_mark_dirty(struct regmap *map);
  
 +/**
 + * Description of an IRQ for the generic regmap irq_chip.
 + *
 + * @reg_offset: Offset of the status/mask register within the bank
 + * @mask:       Mask used to flag/control the register.
 + */
 +struct regmap_irq {
 +      unsigned int reg_offset;
 +      unsigned int mask;
 +};
 +
 +/**
 + * Description of a generic regmap irq_chip.  This is not intended to
 + * handle every possible interrupt controller, but it should handle a
 + * substantial proportion of those that are found in the wild.
 + *
 + * @name:        Descriptive name for IRQ controller.
 + *
 + * @status_base: Base status register address.
 + * @mask_base:   Base mask register address.
 + * @ack_base:    Base ack address.  If zero then the chip is clear on read.
 + *
 + * @num_regs:    Number of registers in each control bank.
 + * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
 + *               assigned based on the index in the array of the interrupt.
 + * @num_irqs:    Number of descriptors.
 + */
 +struct regmap_irq_chip {
 +      const char *name;
 +
 +      unsigned int status_base;
 +      unsigned int mask_base;
 +      unsigned int ack_base;
 +
 +      int num_regs;
 +
 +      const struct regmap_irq *irqs;
 +      int num_irqs;
 +};
 +
 +struct regmap_irq_chip_data;
 +
 +int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 +                      int irq_base, struct regmap_irq_chip *chip,
 +                      struct regmap_irq_chip_data **data);
 +void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
 +
  #endif