forked from mirrors/linux
		
	regmap: rework ->max_register handling
When regmap consists of single register, 'regmap' subsystem is unable to understand whether ->max_register is set or not, because in both cases it is equal to zero. It leads to that the logic based on value of ->max_register doesn't work. For example using of REGCACHE_FLAT fails. This patch introduces an extra parameter to regmap config, indicating that zero value in ->max_register is authentic. Signed-off-by: Jan Dakinevich <jan.dakinevich@salutedevices.com> Link: https://lore.kernel.org/r/20240126200836.1829995-1-jan.dakinevich@salutedevices.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
		
							parent
							
								
									6613476e22
								
							
						
					
					
						commit
						0ec74ad3c1
					
				
					 5 changed files with 16 additions and 6 deletions
				
			
		| 
						 | 
					@ -93,6 +93,7 @@ struct regmap {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int max_register;
 | 
						unsigned int max_register;
 | 
				
			||||||
 | 
						bool max_register_is_set;
 | 
				
			||||||
	bool (*writeable_reg)(struct device *dev, unsigned int reg);
 | 
						bool (*writeable_reg)(struct device *dev, unsigned int reg);
 | 
				
			||||||
	bool (*readable_reg)(struct device *dev, unsigned int reg);
 | 
						bool (*readable_reg)(struct device *dev, unsigned int reg);
 | 
				
			||||||
	bool (*volatile_reg)(struct device *dev, unsigned int reg);
 | 
						bool (*volatile_reg)(struct device *dev, unsigned int reg);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ static int regcache_flat_init(struct regmap *map)
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	unsigned int *cache;
 | 
						unsigned int *cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!map || map->reg_stride_order < 0 || !map->max_register)
 | 
						if (!map || map->reg_stride_order < 0 || !map->max_register_is_set)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
 | 
						map->cache = kcalloc(regcache_flat_get_index(map, map->max_register)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,8 +187,10 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!map->max_register && map->num_reg_defaults_raw)
 | 
						if (!map->max_register_is_set && map->num_reg_defaults_raw) {
 | 
				
			||||||
		map->max_register = (map->num_reg_defaults_raw  - 1) * map->reg_stride;
 | 
							map->max_register = (map->num_reg_defaults_raw  - 1) * map->reg_stride;
 | 
				
			||||||
 | 
							map->max_register_is_set = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->cache_ops->init) {
 | 
						if (map->cache_ops->init) {
 | 
				
			||||||
		dev_dbg(map->dev, "Initializing %s cache\n",
 | 
							dev_dbg(map->dev, "Initializing %s cache\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(regmap_check_range_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool regmap_writeable(struct regmap *map, unsigned int reg)
 | 
					bool regmap_writeable(struct regmap *map, unsigned int reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (map->max_register && reg > map->max_register)
 | 
						if (map->max_register_is_set && reg > map->max_register)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->writeable_reg)
 | 
						if (map->writeable_reg)
 | 
				
			||||||
| 
						 | 
					@ -112,7 +112,7 @@ bool regmap_cached(struct regmap *map, unsigned int reg)
 | 
				
			||||||
	if (!map->cache_ops)
 | 
						if (!map->cache_ops)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->max_register && reg > map->max_register)
 | 
						if (map->max_register_is_set && reg > map->max_register)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map->lock(map->lock_arg);
 | 
						map->lock(map->lock_arg);
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
 | 
				
			||||||
	if (!map->reg_read)
 | 
						if (!map->reg_read)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->max_register && reg > map->max_register)
 | 
						if (map->max_register_is_set && reg > map->max_register)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (map->format.format_write)
 | 
						if (map->format.format_write)
 | 
				
			||||||
| 
						 | 
					@ -787,6 +787,7 @@ struct regmap *__regmap_init(struct device *dev,
 | 
				
			||||||
	map->bus = bus;
 | 
						map->bus = bus;
 | 
				
			||||||
	map->bus_context = bus_context;
 | 
						map->bus_context = bus_context;
 | 
				
			||||||
	map->max_register = config->max_register;
 | 
						map->max_register = config->max_register;
 | 
				
			||||||
 | 
						map->max_register_is_set = map->max_register ?: config->max_register_is_0;
 | 
				
			||||||
	map->wr_table = config->wr_table;
 | 
						map->wr_table = config->wr_table;
 | 
				
			||||||
	map->rd_table = config->rd_table;
 | 
						map->rd_table = config->rd_table;
 | 
				
			||||||
	map->volatile_table = config->volatile_table;
 | 
						map->volatile_table = config->volatile_table;
 | 
				
			||||||
| 
						 | 
					@ -1412,6 +1413,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 | 
				
			||||||
	regmap_debugfs_exit(map);
 | 
						regmap_debugfs_exit(map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	map->max_register = config->max_register;
 | 
						map->max_register = config->max_register;
 | 
				
			||||||
 | 
						map->max_register_is_set = map->max_register ?: config->max_register_is_0;
 | 
				
			||||||
	map->writeable_reg = config->writeable_reg;
 | 
						map->writeable_reg = config->writeable_reg;
 | 
				
			||||||
	map->readable_reg = config->readable_reg;
 | 
						map->readable_reg = config->readable_reg;
 | 
				
			||||||
	map->volatile_reg = config->volatile_reg;
 | 
						map->volatile_reg = config->volatile_reg;
 | 
				
			||||||
| 
						 | 
					@ -3383,7 +3385,7 @@ EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int regmap_get_max_register(struct regmap *map)
 | 
					int regmap_get_max_register(struct regmap *map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return map->max_register ? map->max_register : -EINVAL;
 | 
						return map->max_register_is_set ? map->max_register : -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(regmap_get_max_register);
 | 
					EXPORT_SYMBOL_GPL(regmap_get_max_register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -332,6 +332,10 @@ typedef void (*regmap_unlock)(void *);
 | 
				
			||||||
 * @io_port:	  Support IO port accessors. Makes sense only when MMIO vs. IO port
 | 
					 * @io_port:	  Support IO port accessors. Makes sense only when MMIO vs. IO port
 | 
				
			||||||
 *		  access can be distinguished.
 | 
					 *		  access can be distinguished.
 | 
				
			||||||
 * @max_register: Optional, specifies the maximum valid register address.
 | 
					 * @max_register: Optional, specifies the maximum valid register address.
 | 
				
			||||||
 | 
					 * @max_register_is_0: Optional, specifies that zero value in @max_register
 | 
				
			||||||
 | 
					 *                     should be taken into account. This is a workaround to
 | 
				
			||||||
 | 
					 *                     apply handling of @max_register for regmap that contains
 | 
				
			||||||
 | 
					 *                     only one register.
 | 
				
			||||||
 * @wr_table:     Optional, points to a struct regmap_access_table specifying
 | 
					 * @wr_table:     Optional, points to a struct regmap_access_table specifying
 | 
				
			||||||
 *                valid ranges for write access.
 | 
					 *                valid ranges for write access.
 | 
				
			||||||
 * @rd_table:     As above, for read access.
 | 
					 * @rd_table:     As above, for read access.
 | 
				
			||||||
| 
						 | 
					@ -422,6 +426,7 @@ struct regmap_config {
 | 
				
			||||||
	bool io_port;
 | 
						bool io_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int max_register;
 | 
						unsigned int max_register;
 | 
				
			||||||
 | 
						bool max_register_is_0;
 | 
				
			||||||
	const struct regmap_access_table *wr_table;
 | 
						const struct regmap_access_table *wr_table;
 | 
				
			||||||
	const struct regmap_access_table *rd_table;
 | 
						const struct regmap_access_table *rd_table;
 | 
				
			||||||
	const struct regmap_access_table *volatile_table;
 | 
						const struct regmap_access_table *volatile_table;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue