Commit e12bdf0d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regmap-v4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "As well as a few fixes and updates for API changes there's two new
  features for the API:

   - Better support for handling a reset of the underlying hardware,
     marking the register map as needing a resync to the device when we
     need to do that automatically

   - Support for querying the size and stride of the register map,
     allowing higher level frameworks to configure themselves more
     readily"

* tag 'regmap-v4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Fix possible shift overflow in regmap_field_init()
  regmap: Fix regmap_bulk_read in BE mode
  regmap: kill off set_irq_flags usage
  regmap: irq: Fixed a typo error
  regmap: drop unneeded goto
  regmap: Introduce regmap_get_reg_stride
  regmap: Introduce regmap_get_max_register
  regmap: Use regcache_mark_dirty() to indicate power loss or reset
  regmap: Add a helper function for regcache sync test
  regmap: Constify irq_domain_ops
parents 1a13e36a 8ca006ad
...@@ -131,7 +131,10 @@ struct regmap { ...@@ -131,7 +131,10 @@ struct regmap {
struct reg_default *reg_defaults; struct reg_default *reg_defaults;
const void *reg_defaults_raw; const void *reg_defaults_raw;
void *cache; void *cache;
/* if set, the cache contains newer data than the HW */
u32 cache_dirty; u32 cache_dirty;
/* if set, the HW registers are known to match map->reg_defaults */
bool no_sync_defaults;
struct reg_default *patch; struct reg_default *patch;
int patch_regs; int patch_regs;
......
...@@ -249,6 +249,22 @@ int regcache_write(struct regmap *map, ...@@ -249,6 +249,22 @@ int regcache_write(struct regmap *map,
return 0; return 0;
} }
static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
unsigned int val)
{
int ret;
/* If we don't know the chip just got reset, then sync everything. */
if (!map->no_sync_defaults)
return true;
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, reg);
if (ret >= 0 && val == map->reg_defaults[ret].def)
return false;
return true;
}
static int regcache_default_sync(struct regmap *map, unsigned int min, static int regcache_default_sync(struct regmap *map, unsigned int min,
unsigned int max) unsigned int max)
{ {
...@@ -266,9 +282,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, ...@@ -266,9 +282,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
if (ret) if (ret)
return ret; return ret;
/* Is this the hardware default? If so skip. */ if (!regcache_reg_needs_sync(map, reg, val))
ret = regcache_lookup_reg(map, reg);
if (ret >= 0 && val == map->reg_defaults[ret].def)
continue; continue;
map->cache_bypass = 1; map->cache_bypass = 1;
...@@ -342,6 +356,7 @@ int regcache_sync(struct regmap *map) ...@@ -342,6 +356,7 @@ int regcache_sync(struct regmap *map)
/* Restore the bypass state */ /* Restore the bypass state */
map->async = false; map->async = false;
map->cache_bypass = bypass; map->cache_bypass = bypass;
map->no_sync_defaults = false;
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
regmap_async_complete(map); regmap_async_complete(map);
...@@ -397,6 +412,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, ...@@ -397,6 +412,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
/* Restore the bypass state */ /* Restore the bypass state */
map->cache_bypass = bypass; map->cache_bypass = bypass;
map->async = false; map->async = false;
map->no_sync_defaults = false;
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
regmap_async_complete(map); regmap_async_complete(map);
...@@ -461,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable) ...@@ -461,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
EXPORT_SYMBOL_GPL(regcache_cache_only); EXPORT_SYMBOL_GPL(regcache_cache_only);
/** /**
* regcache_mark_dirty: Mark the register cache as dirty * regcache_mark_dirty: Indicate that HW registers were reset to default values
* *
* @map: map to mark * @map: map to mark
* *
* Mark the register cache as dirty, for example due to the device * Inform regcache that the device has been powered down or reset, so that
* having been powered down for suspend. If the cache is not marked * on resume, regcache_sync() knows to write out all non-default values
* as dirty then the cache sync will be suppressed. * stored in the cache.
*
* If this function is not called, regcache_sync() will assume that
* the hardware state still matches the cache state, modulo any writes that
* happened when cache_only was true.
*/ */
void regcache_mark_dirty(struct regmap *map) void regcache_mark_dirty(struct regmap *map)
{ {
map->lock(map->lock_arg); map->lock(map->lock_arg);
map->cache_dirty = true; map->cache_dirty = true;
map->no_sync_defaults = true;
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
} }
EXPORT_SYMBOL_GPL(regcache_mark_dirty); EXPORT_SYMBOL_GPL(regcache_mark_dirty);
...@@ -613,10 +634,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block, ...@@ -613,10 +634,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
continue; continue;
val = regcache_get_val(map, block, i); val = regcache_get_val(map, block, i);
if (!regcache_reg_needs_sync(map, regtmp, val))
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, regtmp);
if (ret >= 0 && val == map->reg_defaults[ret].def)
continue; continue;
map->cache_bypass = 1; map->cache_bypass = 1;
...@@ -688,10 +706,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, ...@@ -688,10 +706,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
} }
val = regcache_get_val(map, block, i); val = regcache_get_val(map, block, i);
if (!regcache_reg_needs_sync(map, regtmp, val)) {
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, regtmp);
if (ret >= 0 && val == map->reg_defaults[ret].def) {
ret = regcache_sync_block_raw_flush(map, &data, ret = regcache_sync_block_raw_flush(map, &data,
base, regtmp); base, regtmp);
if (ret != 0) if (ret != 0)
......
...@@ -109,7 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -109,7 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if (!d->chip->init_ack_masked) if (!d->chip->init_ack_masked)
continue; continue;
/* /*
* Ack all the masked interrupts uncondictionly, * Ack all the masked interrupts unconditionally,
* OR if there is masked interrupt which hasn't been Acked, * OR if there is masked interrupt which hasn't been Acked,
* it'll be ignored in irq handler, then may introduce irq storm * it'll be ignored in irq handler, then may introduce irq storm
*/ */
...@@ -306,19 +306,12 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, ...@@ -306,19 +306,12 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_set_chip_data(virq, data); irq_set_chip_data(virq, data);
irq_set_chip(virq, &data->irq_chip); irq_set_chip(virq, &data->irq_chip);
irq_set_nested_thread(virq, 1); irq_set_nested_thread(virq, 1);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(virq); irq_set_noprobe(virq);
#endif
return 0; return 0;
} }
static struct irq_domain_ops regmap_domain_ops = { static const struct irq_domain_ops regmap_domain_ops = {
.map = regmap_irq_map, .map = regmap_irq_map,
.xlate = irq_domain_xlate_twocell, .xlate = irq_domain_xlate_twocell,
}; };
......
...@@ -945,11 +945,10 @@ EXPORT_SYMBOL_GPL(devm_regmap_init); ...@@ -945,11 +945,10 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
static void regmap_field_init(struct regmap_field *rm_field, static void regmap_field_init(struct regmap_field *rm_field,
struct regmap *regmap, struct reg_field reg_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->regmap = regmap;
rm_field->reg = reg_field.reg; rm_field->reg = reg_field.reg;
rm_field->shift = reg_field.lsb; rm_field->shift = reg_field.lsb;
rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
rm_field->id_size = reg_field.id_size; rm_field->id_size = reg_field.id_size;
rm_field->id_offset = reg_field.id_offset; rm_field->id_offset = reg_field.id_offset;
} }
...@@ -2318,7 +2317,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2318,7 +2317,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
&ival); &ival);
if (ret != 0) if (ret != 0)
return ret; return ret;
memcpy(val + (i * val_bytes), &ival, val_bytes); map->format.format_val(val + (i * val_bytes), ival, 0);
} }
} }
...@@ -2583,10 +2582,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, ...@@ -2583,10 +2582,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
map->async = true; map->async = true;
ret = _regmap_multi_reg_write(map, regs, num_regs); ret = _regmap_multi_reg_write(map, regs, num_regs);
if (ret != 0)
goto out;
out:
map->async = false; map->async = false;
map->cache_bypass = bypass; map->cache_bypass = bypass;
...@@ -2613,6 +2609,30 @@ int regmap_get_val_bytes(struct regmap *map) ...@@ -2613,6 +2609,30 @@ int regmap_get_val_bytes(struct regmap *map)
} }
EXPORT_SYMBOL_GPL(regmap_get_val_bytes); EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
/**
* regmap_get_max_register(): Report the max register value
*
* Report the max register value, mainly intended to for use by
* generic infrastructure built on top of regmap.
*/
int regmap_get_max_register(struct regmap *map)
{
return map->max_register ? map->max_register : -EINVAL;
}
EXPORT_SYMBOL_GPL(regmap_get_max_register);
/**
* regmap_get_reg_stride(): Report the register address stride
*
* Report the register address stride, mainly intended to for use by
* generic infrastructure built on top of regmap.
*/
int regmap_get_reg_stride(struct regmap *map)
{
return map->reg_stride;
}
EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
int regmap_parse_val(struct regmap *map, const void *buf, int regmap_parse_val(struct regmap *map, const void *buf,
unsigned int *val) unsigned int *val)
{ {
......
...@@ -433,6 +433,8 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, ...@@ -433,6 +433,8 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val, unsigned int mask, unsigned int val,
bool *change); bool *change);
int regmap_get_val_bytes(struct regmap *map); int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map);
int regmap_async_complete(struct regmap *map); int regmap_async_complete(struct regmap *map);
bool regmap_can_raw_write(struct regmap *map); bool regmap_can_raw_write(struct regmap *map);
...@@ -676,6 +678,18 @@ static inline int regmap_get_val_bytes(struct regmap *map) ...@@ -676,6 +678,18 @@ static inline int regmap_get_val_bytes(struct regmap *map)
return -EINVAL; return -EINVAL;
} }
static inline int regmap_get_max_register(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline int regmap_get_reg_stride(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");
return -EINVAL;
}
static inline int regcache_sync(struct regmap *map) static inline int regcache_sync(struct regmap *map)
{ {
WARN_ONCE(1, "regmap API is disabled"); WARN_ONCE(1, "regmap API is disabled");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment