diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index c130536e0ab0626866a41dd23f35d2c260bb9980..b33a4ff67adf4bbbb8e957093bc9effc1b2d7959 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -148,6 +148,7 @@ struct regcache_ops { int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); int (*write)(struct regmap *map, unsigned int reg, unsigned int value); int (*sync)(struct regmap *map, unsigned int min, unsigned int max); + int (*drop)(struct regmap *map, unsigned int min, unsigned int max); }; bool regmap_writeable(struct regmap *map, unsigned int reg); diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 75923f2396bd4f7b01727bae6cbedb4239b4ec18..8a0ab5fa75f57bbf8b9c8a72fd548e5d22033e73 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -358,6 +358,43 @@ int regcache_sync_region(struct regmap *map, unsigned int min, } EXPORT_SYMBOL_GPL(regcache_sync_region); +/** + * regcache_drop_region: Discard part of the register cache + * + * @map: map to operate on + * @min: first register to discard + * @max: last register to discard + * + * Discard part of the register cache. + * + * Return a negative value on failure, 0 on success. + */ +int regcache_drop_region(struct regmap *map, unsigned int min, + unsigned int max) +{ + unsigned int reg; + int ret = 0; + + if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop)) + return -EINVAL; + + map->lock(map); + + trace_regcache_drop_region(map->dev, min, max); + + if (map->cache_present) + for (reg = min; reg < max + 1; reg++) + clear_bit(reg, map->cache_present); + + if (map->cache_ops && map->cache_ops->drop) + ret = map->cache_ops->drop(map, min, max); + + map->unlock(map); + + return ret; +} +EXPORT_SYMBOL_GPL(regcache_drop_region); + /** * regcache_cache_only: Put a register map into cache only mode * diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 02d84e24b7c2083ff1a4ddf13a1b2ac7ad663261..5067ee94eb923170d41ee61ac5e2db46ec2a656a 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -394,6 +394,8 @@ bool regmap_can_raw_write(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, unsigned int max); +int regcache_drop_region(struct regmap *map, unsigned int min, + unsigned int max); 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); @@ -562,6 +564,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min, return -EINVAL; } +static inline int regcache_drop_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"); diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h index a43a2f67bd8e080d844a780a2255dc77af898762..23d561512f64fe65a5165a23d4620f7d457504a4 100644 --- a/include/trace/events/regmap.h +++ b/include/trace/events/regmap.h @@ -223,6 +223,29 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done, ); +TRACE_EVENT(regcache_drop_region, + + TP_PROTO(struct device *dev, unsigned int from, + unsigned int to), + + TP_ARGS(dev, from, to), + + TP_STRUCT__entry( + __string( name, dev_name(dev) ) + __field( unsigned int, from ) + __field( unsigned int, to ) + ), + + TP_fast_assign( + __assign_str(name, dev_name(dev)); + __entry->from = from; + __entry->to = to; + ), + + TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from, + (unsigned int)__entry->to) +); + #endif /* _TRACE_REGMAP_H */ /* This part must be outside protection */