18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Register map access API internal header
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2011 Wolfson Microelectronics plc
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifndef _REGMAP_INTERNAL_H
118c2ecf20Sopenharmony_ci#define _REGMAP_INTERNAL_H
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci#include <linux/regmap.h>
158c2ecf20Sopenharmony_ci#include <linux/fs.h>
168c2ecf20Sopenharmony_ci#include <linux/list.h>
178c2ecf20Sopenharmony_ci#include <linux/wait.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct regmap;
208c2ecf20Sopenharmony_cistruct regcache_ops;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct regmap_debugfs_off_cache {
238c2ecf20Sopenharmony_ci	struct list_head list;
248c2ecf20Sopenharmony_ci	off_t min;
258c2ecf20Sopenharmony_ci	off_t max;
268c2ecf20Sopenharmony_ci	unsigned int base_reg;
278c2ecf20Sopenharmony_ci	unsigned int max_reg;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct regmap_format {
318c2ecf20Sopenharmony_ci	size_t buf_size;
328c2ecf20Sopenharmony_ci	size_t reg_bytes;
338c2ecf20Sopenharmony_ci	size_t pad_bytes;
348c2ecf20Sopenharmony_ci	size_t val_bytes;
358c2ecf20Sopenharmony_ci	void (*format_write)(struct regmap *map,
368c2ecf20Sopenharmony_ci			     unsigned int reg, unsigned int val);
378c2ecf20Sopenharmony_ci	void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
388c2ecf20Sopenharmony_ci	void (*format_val)(void *buf, unsigned int val, unsigned int shift);
398c2ecf20Sopenharmony_ci	unsigned int (*parse_val)(const void *buf);
408c2ecf20Sopenharmony_ci	void (*parse_inplace)(void *buf);
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct regmap_async {
448c2ecf20Sopenharmony_ci	struct list_head list;
458c2ecf20Sopenharmony_ci	struct regmap *map;
468c2ecf20Sopenharmony_ci	void *work_buf;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct regmap {
508c2ecf20Sopenharmony_ci	union {
518c2ecf20Sopenharmony_ci		struct mutex mutex;
528c2ecf20Sopenharmony_ci		struct {
538c2ecf20Sopenharmony_ci			spinlock_t spinlock;
548c2ecf20Sopenharmony_ci			unsigned long spinlock_flags;
558c2ecf20Sopenharmony_ci		};
568c2ecf20Sopenharmony_ci	};
578c2ecf20Sopenharmony_ci	regmap_lock lock;
588c2ecf20Sopenharmony_ci	regmap_unlock unlock;
598c2ecf20Sopenharmony_ci	void *lock_arg; /* This is passed to lock/unlock functions */
608c2ecf20Sopenharmony_ci	gfp_t alloc_flags;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	struct device *dev; /* Device we do I/O on */
638c2ecf20Sopenharmony_ci	void *work_buf;     /* Scratch buffer used to format I/O */
648c2ecf20Sopenharmony_ci	struct regmap_format format;  /* Buffer format */
658c2ecf20Sopenharmony_ci	const struct regmap_bus *bus;
668c2ecf20Sopenharmony_ci	void *bus_context;
678c2ecf20Sopenharmony_ci	const char *name;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	bool async;
708c2ecf20Sopenharmony_ci	spinlock_t async_lock;
718c2ecf20Sopenharmony_ci	wait_queue_head_t async_waitq;
728c2ecf20Sopenharmony_ci	struct list_head async_list;
738c2ecf20Sopenharmony_ci	struct list_head async_free;
748c2ecf20Sopenharmony_ci	int async_ret;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
778c2ecf20Sopenharmony_ci	bool debugfs_disable;
788c2ecf20Sopenharmony_ci	struct dentry *debugfs;
798c2ecf20Sopenharmony_ci	const char *debugfs_name;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	unsigned int debugfs_reg_len;
828c2ecf20Sopenharmony_ci	unsigned int debugfs_val_len;
838c2ecf20Sopenharmony_ci	unsigned int debugfs_tot_len;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	struct list_head debugfs_off_cache;
868c2ecf20Sopenharmony_ci	struct mutex cache_lock;
878c2ecf20Sopenharmony_ci#endif
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	unsigned int max_register;
908c2ecf20Sopenharmony_ci	bool (*writeable_reg)(struct device *dev, unsigned int reg);
918c2ecf20Sopenharmony_ci	bool (*readable_reg)(struct device *dev, unsigned int reg);
928c2ecf20Sopenharmony_ci	bool (*volatile_reg)(struct device *dev, unsigned int reg);
938c2ecf20Sopenharmony_ci	bool (*precious_reg)(struct device *dev, unsigned int reg);
948c2ecf20Sopenharmony_ci	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
958c2ecf20Sopenharmony_ci	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
968c2ecf20Sopenharmony_ci	const struct regmap_access_table *wr_table;
978c2ecf20Sopenharmony_ci	const struct regmap_access_table *rd_table;
988c2ecf20Sopenharmony_ci	const struct regmap_access_table *volatile_table;
998c2ecf20Sopenharmony_ci	const struct regmap_access_table *precious_table;
1008c2ecf20Sopenharmony_ci	const struct regmap_access_table *wr_noinc_table;
1018c2ecf20Sopenharmony_ci	const struct regmap_access_table *rd_noinc_table;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
1048c2ecf20Sopenharmony_ci	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
1058c2ecf20Sopenharmony_ci	int (*reg_update_bits)(void *context, unsigned int reg,
1068c2ecf20Sopenharmony_ci			       unsigned int mask, unsigned int val);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	bool defer_caching;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	unsigned long read_flag_mask;
1118c2ecf20Sopenharmony_ci	unsigned long write_flag_mask;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* number of bits to (left) shift the reg value when formatting*/
1148c2ecf20Sopenharmony_ci	int reg_shift;
1158c2ecf20Sopenharmony_ci	int reg_stride;
1168c2ecf20Sopenharmony_ci	int reg_stride_order;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* regcache specific members */
1198c2ecf20Sopenharmony_ci	const struct regcache_ops *cache_ops;
1208c2ecf20Sopenharmony_ci	enum regcache_type cache_type;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* number of bytes in reg_defaults_raw */
1238c2ecf20Sopenharmony_ci	unsigned int cache_size_raw;
1248c2ecf20Sopenharmony_ci	/* number of bytes per word in reg_defaults_raw */
1258c2ecf20Sopenharmony_ci	unsigned int cache_word_size;
1268c2ecf20Sopenharmony_ci	/* number of entries in reg_defaults */
1278c2ecf20Sopenharmony_ci	unsigned int num_reg_defaults;
1288c2ecf20Sopenharmony_ci	/* number of entries in reg_defaults_raw */
1298c2ecf20Sopenharmony_ci	unsigned int num_reg_defaults_raw;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* if set, only the cache is modified not the HW */
1328c2ecf20Sopenharmony_ci	bool cache_only;
1338c2ecf20Sopenharmony_ci	/* if set, only the HW is modified not the cache */
1348c2ecf20Sopenharmony_ci	bool cache_bypass;
1358c2ecf20Sopenharmony_ci	/* if set, remember to free reg_defaults_raw */
1368c2ecf20Sopenharmony_ci	bool cache_free;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	struct reg_default *reg_defaults;
1398c2ecf20Sopenharmony_ci	const void *reg_defaults_raw;
1408c2ecf20Sopenharmony_ci	void *cache;
1418c2ecf20Sopenharmony_ci	/* if set, the cache contains newer data than the HW */
1428c2ecf20Sopenharmony_ci	bool cache_dirty;
1438c2ecf20Sopenharmony_ci	/* if set, the HW registers are known to match map->reg_defaults */
1448c2ecf20Sopenharmony_ci	bool no_sync_defaults;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	struct reg_sequence *patch;
1478c2ecf20Sopenharmony_ci	int patch_regs;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* if set, converts bulk read to single read */
1508c2ecf20Sopenharmony_ci	bool use_single_read;
1518c2ecf20Sopenharmony_ci	/* if set, converts bulk write to single write */
1528c2ecf20Sopenharmony_ci	bool use_single_write;
1538c2ecf20Sopenharmony_ci	/* if set, the device supports multi write mode */
1548c2ecf20Sopenharmony_ci	bool can_multi_write;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	/* if set, raw reads/writes are limited to this size */
1578c2ecf20Sopenharmony_ci	size_t max_raw_read;
1588c2ecf20Sopenharmony_ci	size_t max_raw_write;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	struct rb_root range_tree;
1618c2ecf20Sopenharmony_ci	void *selector_work_buf;	/* Scratch buffer used for selector */
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	struct hwspinlock *hwlock;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* if set, the regmap core can sleep */
1668c2ecf20Sopenharmony_ci	bool can_sleep;
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistruct regcache_ops {
1708c2ecf20Sopenharmony_ci	const char *name;
1718c2ecf20Sopenharmony_ci	enum regcache_type type;
1728c2ecf20Sopenharmony_ci	int (*init)(struct regmap *map);
1738c2ecf20Sopenharmony_ci	int (*exit)(struct regmap *map);
1748c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
1758c2ecf20Sopenharmony_ci	void (*debugfs_init)(struct regmap *map);
1768c2ecf20Sopenharmony_ci#endif
1778c2ecf20Sopenharmony_ci	int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
1788c2ecf20Sopenharmony_ci	int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
1798c2ecf20Sopenharmony_ci	int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
1808c2ecf20Sopenharmony_ci	int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cibool regmap_cached(struct regmap *map, unsigned int reg);
1848c2ecf20Sopenharmony_cibool regmap_writeable(struct regmap *map, unsigned int reg);
1858c2ecf20Sopenharmony_cibool regmap_readable(struct regmap *map, unsigned int reg);
1868c2ecf20Sopenharmony_cibool regmap_volatile(struct regmap *map, unsigned int reg);
1878c2ecf20Sopenharmony_cibool regmap_precious(struct regmap *map, unsigned int reg);
1888c2ecf20Sopenharmony_cibool regmap_writeable_noinc(struct regmap *map, unsigned int reg);
1898c2ecf20Sopenharmony_cibool regmap_readable_noinc(struct regmap *map, unsigned int reg);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ciint _regmap_write(struct regmap *map, unsigned int reg,
1928c2ecf20Sopenharmony_ci		  unsigned int val);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistruct regmap_range_node {
1958c2ecf20Sopenharmony_ci	struct rb_node node;
1968c2ecf20Sopenharmony_ci	const char *name;
1978c2ecf20Sopenharmony_ci	struct regmap *map;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	unsigned int range_min;
2008c2ecf20Sopenharmony_ci	unsigned int range_max;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	unsigned int selector_reg;
2038c2ecf20Sopenharmony_ci	unsigned int selector_mask;
2048c2ecf20Sopenharmony_ci	int selector_shift;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	unsigned int window_start;
2078c2ecf20Sopenharmony_ci	unsigned int window_len;
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistruct regmap_field {
2118c2ecf20Sopenharmony_ci	struct regmap *regmap;
2128c2ecf20Sopenharmony_ci	unsigned int mask;
2138c2ecf20Sopenharmony_ci	/* lsb */
2148c2ecf20Sopenharmony_ci	unsigned int shift;
2158c2ecf20Sopenharmony_ci	unsigned int reg;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	unsigned int id_size;
2188c2ecf20Sopenharmony_ci	unsigned int id_offset;
2198c2ecf20Sopenharmony_ci};
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
2228c2ecf20Sopenharmony_ciextern void regmap_debugfs_initcall(void);
2238c2ecf20Sopenharmony_ciextern void regmap_debugfs_init(struct regmap *map);
2248c2ecf20Sopenharmony_ciextern void regmap_debugfs_exit(struct regmap *map);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic inline void regmap_debugfs_disable(struct regmap *map)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	map->debugfs_disable = true;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci#else
2328c2ecf20Sopenharmony_cistatic inline void regmap_debugfs_initcall(void) { }
2338c2ecf20Sopenharmony_cistatic inline void regmap_debugfs_init(struct regmap *map) { }
2348c2ecf20Sopenharmony_cistatic inline void regmap_debugfs_exit(struct regmap *map) { }
2358c2ecf20Sopenharmony_cistatic inline void regmap_debugfs_disable(struct regmap *map) { }
2368c2ecf20Sopenharmony_ci#endif
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/* regcache core declarations */
2398c2ecf20Sopenharmony_ciint regcache_init(struct regmap *map, const struct regmap_config *config);
2408c2ecf20Sopenharmony_civoid regcache_exit(struct regmap *map);
2418c2ecf20Sopenharmony_ciint regcache_read(struct regmap *map,
2428c2ecf20Sopenharmony_ci		       unsigned int reg, unsigned int *value);
2438c2ecf20Sopenharmony_ciint regcache_write(struct regmap *map,
2448c2ecf20Sopenharmony_ci			unsigned int reg, unsigned int value);
2458c2ecf20Sopenharmony_ciint regcache_sync(struct regmap *map);
2468c2ecf20Sopenharmony_ciint regcache_sync_block(struct regmap *map, void *block,
2478c2ecf20Sopenharmony_ci			unsigned long *cache_present,
2488c2ecf20Sopenharmony_ci			unsigned int block_base, unsigned int start,
2498c2ecf20Sopenharmony_ci			unsigned int end);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic inline const void *regcache_get_val_addr(struct regmap *map,
2528c2ecf20Sopenharmony_ci						const void *base,
2538c2ecf20Sopenharmony_ci						unsigned int idx)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	return base + (map->cache_word_size * idx);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ciunsigned int regcache_get_val(struct regmap *map, const void *base,
2598c2ecf20Sopenharmony_ci			      unsigned int idx);
2608c2ecf20Sopenharmony_cibool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
2618c2ecf20Sopenharmony_ci		      unsigned int val);
2628c2ecf20Sopenharmony_ciint regcache_lookup_reg(struct regmap *map, unsigned int reg);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint _regmap_raw_write(struct regmap *map, unsigned int reg,
2658c2ecf20Sopenharmony_ci		      const void *val, size_t val_len, bool noinc);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_civoid regmap_async_complete_cb(struct regmap_async *async, int ret);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cienum regmap_endian regmap_get_val_endian(struct device *dev,
2708c2ecf20Sopenharmony_ci					 const struct regmap_bus *bus,
2718c2ecf20Sopenharmony_ci					 const struct regmap_config *config);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciextern struct regcache_ops regcache_rbtree_ops;
2748c2ecf20Sopenharmony_ciextern struct regcache_ops regcache_lzo_ops;
2758c2ecf20Sopenharmony_ciextern struct regcache_ops regcache_flat_ops;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic inline const char *regmap_name(const struct regmap *map)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	if (map->dev)
2808c2ecf20Sopenharmony_ci		return dev_name(map->dev);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return map->name;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic inline unsigned int regmap_get_offset(const struct regmap *map,
2868c2ecf20Sopenharmony_ci					     unsigned int index)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	if (map->reg_stride_order >= 0)
2898c2ecf20Sopenharmony_ci		return index << map->reg_stride_order;
2908c2ecf20Sopenharmony_ci	else
2918c2ecf20Sopenharmony_ci		return index * map->reg_stride;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic inline unsigned int regcache_get_index_by_order(const struct regmap *map,
2958c2ecf20Sopenharmony_ci						       unsigned int reg)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	return reg >> map->reg_stride_order;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci#endif
301