Merge tag 'regmap-v3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Jul 2013 22:44:58 +0000 (15:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 15 Jul 2013 22:44:58 +0000 (15:44 -0700)
Pull regmap fix from Mark Brown:
 "Fix regmap crash for async operation on busless maps

  This fixes a crash if something tries to do an asynchronous operation
  on busless maps which was introduced during the merge window"

* tag 'regmap-v3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: cache: bail in regmap_async_complete() for bus-less maps

1  2 
drivers/base/regmap/regmap.c

index 95920583e31e6dfb5cd0ad18cd9a599e9e34e155,d0c81d1f409c07bf2bb4eac3f34469a7b9626dd9..e0d0c7d8a5c527867fb4ba05f4f21e74c43fcff2
@@@ -65,8 -65,9 +65,8 @@@ bool regmap_reg_in_ranges(unsigned int 
  }
  EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
  
 -static bool _regmap_check_range_table(struct regmap *map,
 -                                    unsigned int reg,
 -                                    const struct regmap_access_table *table)
 +bool regmap_check_range_table(struct regmap *map, unsigned int reg,
 +                            const struct regmap_access_table *table)
  {
        /* Check "no ranges" first */
        if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
@@@ -79,7 -80,6 +79,7 @@@
        return regmap_reg_in_ranges(reg, table->yes_ranges,
                                    table->n_yes_ranges);
  }
 +EXPORT_SYMBOL_GPL(regmap_check_range_table);
  
  bool regmap_writeable(struct regmap *map, unsigned int reg)
  {
@@@ -90,7 -90,7 +90,7 @@@
                return map->writeable_reg(map->dev, reg);
  
        if (map->wr_table)
 -              return _regmap_check_range_table(map, reg, map->wr_table);
 +              return regmap_check_range_table(map, reg, map->wr_table);
  
        return true;
  }
@@@ -107,7 -107,7 +107,7 @@@ bool regmap_readable(struct regmap *map
                return map->readable_reg(map->dev, reg);
  
        if (map->rd_table)
 -              return _regmap_check_range_table(map, reg, map->rd_table);
 +              return regmap_check_range_table(map, reg, map->rd_table);
  
        return true;
  }
@@@ -121,12 -121,9 +121,12 @@@ bool regmap_volatile(struct regmap *map
                return map->volatile_reg(map->dev, reg);
  
        if (map->volatile_table)
 -              return _regmap_check_range_table(map, reg, map->volatile_table);
 +              return regmap_check_range_table(map, reg, map->volatile_table);
  
 -      return true;
 +      if (map->cache_ops)
 +              return false;
 +      else
 +              return true;
  }
  
  bool regmap_precious(struct regmap *map, unsigned int reg)
                return map->precious_reg(map->dev, reg);
  
        if (map->precious_table)
 -              return _regmap_check_range_table(map, reg, map->precious_table);
 +              return regmap_check_range_table(map, reg, map->precious_table);
  
        return false;
  }
@@@ -305,16 -302,13 +305,16 @@@ static void regmap_unlock_mutex(void *_
  static void regmap_lock_spinlock(void *__map)
  {
        struct regmap *map = __map;
 -      spin_lock(&map->spinlock);
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&map->spinlock, flags);
 +      map->spinlock_flags = flags;
  }
  
  static void regmap_unlock_spinlock(void *__map)
  {
        struct regmap *map = __map;
 -      spin_unlock(&map->spinlock);
 +      spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
  }
  
  static void dev_get_regmap_release(struct device *dev, void *res)
@@@ -807,95 -801,6 +807,95 @@@ struct regmap *devm_regmap_init(struct 
  }
  EXPORT_SYMBOL_GPL(devm_regmap_init);
  
 +static void regmap_field_init(struct regmap_field *rm_field,
 +      struct regmap *regmap, struct reg_field reg_field)
 +{
 +      int field_bits = reg_field.msb - reg_field.lsb + 1;
 +      rm_field->regmap = regmap;
 +      rm_field->reg = reg_field.reg;
 +      rm_field->shift = reg_field.lsb;
 +      rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
 +}
 +
 +/**
 + * devm_regmap_field_alloc(): Allocate and initialise a register field
 + * in a register map.
 + *
 + * @dev: Device that will be interacted with
 + * @regmap: regmap bank in which this register field is located.
 + * @reg_field: Register field with in the bank.
 + *
 + * The return value will be an ERR_PTR() on error or a valid pointer
 + * to a struct regmap_field. The regmap_field will be automatically freed
 + * by the device management code.
 + */
 +struct regmap_field *devm_regmap_field_alloc(struct device *dev,
 +              struct regmap *regmap, struct reg_field reg_field)
 +{
 +      struct regmap_field *rm_field = devm_kzalloc(dev,
 +                                      sizeof(*rm_field), GFP_KERNEL);
 +      if (!rm_field)
 +              return ERR_PTR(-ENOMEM);
 +
 +      regmap_field_init(rm_field, regmap, reg_field);
 +
 +      return rm_field;
 +
 +}
 +EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
 +
 +/**
 + * devm_regmap_field_free(): Free register field allocated using
 + * devm_regmap_field_alloc. Usally drivers need not call this function,
 + * as the memory allocated via devm will be freed as per device-driver
 + * life-cyle.
 + *
 + * @dev: Device that will be interacted with
 + * @field: regmap field which should be freed.
 + */
 +void devm_regmap_field_free(struct device *dev,
 +      struct regmap_field *field)
 +{
 +      devm_kfree(dev, field);
 +}
 +EXPORT_SYMBOL_GPL(devm_regmap_field_free);
 +
 +/**
 + * regmap_field_alloc(): Allocate and initialise a register field
 + * in a register map.
 + *
 + * @regmap: regmap bank in which this register field is located.
 + * @reg_field: Register field with in the bank.
 + *
 + * The return value will be an ERR_PTR() on error or a valid pointer
 + * to a struct regmap_field. The regmap_field should be freed by the
 + * user once its finished working with it using regmap_field_free().
 + */
 +struct regmap_field *regmap_field_alloc(struct regmap *regmap,
 +              struct reg_field reg_field)
 +{
 +      struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
 +
 +      if (!rm_field)
 +              return ERR_PTR(-ENOMEM);
 +
 +      regmap_field_init(rm_field, regmap, reg_field);
 +
 +      return rm_field;
 +}
 +EXPORT_SYMBOL_GPL(regmap_field_alloc);
 +
 +/**
 + * regmap_field_free(): Free register field allocated using regmap_field_alloc
 + *
 + * @field: regmap field which should be freed.
 + */
 +void regmap_field_free(struct regmap_field *field)
 +{
 +      kfree(field);
 +}
 +EXPORT_SYMBOL_GPL(regmap_field_free);
 +
  /**
   * regmap_reinit_cache(): Reinitialise the current register cache
   *
@@@ -1344,22 -1249,6 +1344,22 @@@ int regmap_raw_write(struct regmap *map
  }
  EXPORT_SYMBOL_GPL(regmap_raw_write);
  
 +/**
 + * regmap_field_write(): Write a value to a single register field
 + *
 + * @field: Register field to write to
 + * @val: Value to be written
 + *
 + * A value of zero will be returned on success, a negative errno will
 + * be returned in error cases.
 + */
 +int regmap_field_write(struct regmap_field *field, unsigned int val)
 +{
 +      return regmap_update_bits(field->regmap, field->reg,
 +                              field->mask, val << field->shift);
 +}
 +EXPORT_SYMBOL_GPL(regmap_field_write);
 +
  /*
   * regmap_bulk_write(): Write multiple registers to the device
   *
@@@ -1642,31 -1531,6 +1642,31 @@@ int regmap_raw_read(struct regmap *map
  }
  EXPORT_SYMBOL_GPL(regmap_raw_read);
  
 +/**
 + * regmap_field_read(): Read a value to a single register field
 + *
 + * @field: Register field to read from
 + * @val: Pointer to store read value
 + *
 + * A value of zero will be returned on success, a negative errno will
 + * be returned in error cases.
 + */
 +int regmap_field_read(struct regmap_field *field, unsigned int *val)
 +{
 +      int ret;
 +      unsigned int reg_val;
 +      ret = regmap_read(field->regmap, field->reg, &reg_val);
 +      if (ret != 0)
 +              return ret;
 +
 +      reg_val &= field->mask;
 +      reg_val >>= field->shift;
 +      *val = reg_val;
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(regmap_field_read);
 +
  /**
   * regmap_bulk_read(): Read multiple registers from the device
   *
@@@ -1853,7 -1717,7 +1853,7 @@@ int regmap_async_complete(struct regma
        int ret;
  
        /* Nothing to do with no async support */
-       if (!map->bus->async_write)
+       if (!map->bus || !map->bus->async_write)
                return 0;
  
        trace_regmap_async_complete_start(map->dev);