From 2ac902ce17f9dfa0d4d1f0818be147b5d2515fb7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Dec 2012 14:51:55 +0000 Subject: regmap: flat: Add flat cache type While for I2C and SPI devices the overhead of using rbtree for devices with only one block of registers is negligible the same isn't always going to be true for MMIO devices where the I/O costs are very much lower. Cater for these devices by adding a simple flat array type for them where the lookups are simple array accesses, taking us right back to the original ASoC cache implementation. Thanks to Magnus Damm for the discussion which prompted this. Signed-off-by: Mark Brown --- include/linux/regmap.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux/regmap.h') diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..390d879d473a 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -28,7 +28,8 @@ struct regmap_range_cfg; enum regcache_type { REGCACHE_NONE, REGCACHE_RBTREE, - REGCACHE_COMPRESSED + REGCACHE_COMPRESSED, + REGCACHE_FLAT, }; /** -- cgit v1.2.3 From 9442490a02867088bcd5ed6231fa3b35a733c2b8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Jan 2013 16:35:07 +0000 Subject: regmap: irq: Support wake IRQ mask inversion Support devices which have an enable rather than mask register for wake sources. Signed-off-by: Mark Brown --- include/linux/regmap.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/regmap.h') diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..8c0b50df3d59 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -381,6 +381,7 @@ struct regmap_irq_chip { unsigned int wake_base; unsigned int irq_reg_stride; unsigned int mask_invert; + unsigned int wake_invert; bool runtime_pm; int num_regs; -- cgit v1.2.3 From d2a5884a64161b524cc6749ee11b95d252e497f3 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 27 Jan 2013 10:49:05 -0800 Subject: regmap: Add "no-bus" option for regmap API This commit adds provision for "no-bus" usage of the regmap API. In this configuration user can provide API with two callbacks 'reg_read' and 'reg_write' which are to be called when reads and writes to one of device's registers is performed. This is useful for devices that expose registers but whose register access sequence does not fit the 'bus' abstraction. Signed-off-by: Andrey Smirnov Signed-off-by: Mark Brown --- include/linux/regmap.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'include/linux/regmap.h') diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..28dde941c783 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -127,7 +127,18 @@ typedef void (*regmap_unlock)(void *); * @lock_arg: this field is passed as the only argument of lock/unlock * functions (ignored in case regular lock/unlock functions * are not overridden). - * + * @reg_read: Optional callback that if filled will be used to perform + * all the reads from the registers. Should only be provided for + * devices whos read operation cannot be represented as a simple read + * operation on a bus such as SPI, I2C, etc. Most of the devices do + * not need this. + * @reg_write: Same as above for writing. + * @fast_io: Register IO is fast. Use a spinlock instead of a mutex + * to perform locking. This field is ignored if custom lock/unlock + * functions are used (see fields lock/unlock of struct regmap_config). + * This field is a duplicate of a similar file in + * 'struct regmap_bus' and serves exact same purpose. + * Use it only for "no-bus" cases. * @max_register: Optional, specifies the maximum valid register index. * @wr_table: Optional, points to a struct regmap_access_table specifying * valid ranges for write access. @@ -177,6 +188,11 @@ struct regmap_config { regmap_unlock unlock; void *lock_arg; + int (*reg_read)(void *context, unsigned int reg, unsigned int *val); + int (*reg_write)(void *context, unsigned int reg, unsigned int val); + + bool fast_io; + unsigned int max_register; const struct regmap_access_table *wr_table; const struct regmap_access_table *rd_table; -- cgit v1.2.3 From 0d509f2b112b21411712f0bf789b372987967e49 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 27 Jan 2013 22:07:38 +0800 Subject: regmap: Add asynchronous I/O support Some use cases like firmware download can transfer a lot of data in quick succession. With high speed buses these use cases can benefit from having multiple transfers scheduled at once since this allows the bus to minimise the delay between transfers. Support this by adding regmap_raw_write_async(), allowing raw transfers to be scheduled, and regmap_async_complete() to wait for them to finish. Signed-off-by: Mark Brown --- include/linux/regmap.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/linux/regmap.h') diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..f9b7fbe35ab1 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -235,14 +235,21 @@ struct regmap_range_cfg { unsigned int window_len; }; +struct regmap_async; + typedef int (*regmap_hw_write)(void *context, const void *data, size_t count); typedef int (*regmap_hw_gather_write)(void *context, const void *reg, size_t reg_len, const void *val, size_t val_len); +typedef int (*regmap_hw_async_write)(void *context, + const void *reg, size_t reg_len, + const void *val, size_t val_len, + struct regmap_async *async); typedef int (*regmap_hw_read)(void *context, const void *reg_buf, size_t reg_size, void *val_buf, size_t val_size); +typedef struct regmap_async *(*regmap_hw_async_alloc)(void); typedef void (*regmap_hw_free_context)(void *context); /** @@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context); * @write: Write operation. * @gather_write: Write operation with split register/value, return -ENOTSUPP * if not implemented on a given device. + * @async_write: Write operation which completes asynchronously, optional and + * must serialise with respect to non-async I/O. * @read: Read operation. Data is returned in the buffer used to transmit * data. + * @async_alloc: Allocate a regmap_async() structure. * @read_flag_mask: Mask to be set in the top byte of the register when doing * a read. * @reg_format_endian_default: Default endianness for formatted register @@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context); * @val_format_endian_default: Default endianness for formatted register * values. Used when the regmap_config specifies DEFAULT. If this is * DEFAULT, BIG is assumed. + * @async_size: Size of struct used for async work. */ struct regmap_bus { bool fast_io; regmap_hw_write write; regmap_hw_gather_write gather_write; + regmap_hw_async_write async_write; regmap_hw_read read; regmap_hw_free_context free_context; + regmap_hw_async_alloc async_alloc; u8 read_flag_mask; enum regmap_endian reg_format_endian_default; enum regmap_endian val_format_endian_default; @@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count); +int regmap_raw_write_async(struct regmap *map, unsigned int reg, + const void *val, size_t val_len); int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len); @@ -321,6 +336,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change); int regmap_get_val_bytes(struct regmap *map); +int regmap_async_complete(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, @@ -422,6 +438,13 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg, + const void *val, size_t val_len) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count) { @@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map) WARN_ONCE(1, "regmap API is disabled"); } +static inline void regmap_async_complete(struct regmap *map) +{ + WARN_ONCE(1, "regmap API is disabled"); +} + static inline int regmap_register_patch(struct regmap *map, const struct reg_default *regs, int num_regs) -- cgit v1.2.3 From 878ec67b3ac528a2b6d44055f049cdbb9cfda30c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 14 Feb 2013 17:39:08 +0100 Subject: regmap: mmio: add register clock support Some mmio devices have a dedicated interface clock that needs to be enabled to access their registers. This patch optionally enables a clock before accessing registers in the regmap_bus callbacks. I added (devm_)regmap_init_mmio_clk variants of the init functions that have an added clk_id string parameter. This is passed to clk_get to request the clock from the clk framework. Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- include/linux/regmap.h | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'include/linux/regmap.h') diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..f0480a3297e4 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -285,9 +285,9 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c, const struct regmap_config *config); struct regmap *regmap_init_spi(struct spi_device *dev, const struct regmap_config *config); -struct regmap *regmap_init_mmio(struct device *dev, - void __iomem *regs, - const struct regmap_config *config); +struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, + void __iomem *regs, + const struct regmap_config *config); struct regmap *devm_regmap_init(struct device *dev, const struct regmap_bus *bus, @@ -297,9 +297,44 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, const struct regmap_config *config); struct regmap *devm_regmap_init_spi(struct spi_device *dev, const struct regmap_config *config); -struct regmap *devm_regmap_init_mmio(struct device *dev, - void __iomem *regs, - const struct regmap_config *config); +struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, + void __iomem *regs, + const struct regmap_config *config); + +/** + * regmap_init_mmio(): Initialise register map + * + * @dev: Device that will be interacted with + * @regs: Pointer to memory-mapped IO region + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer to + * a struct regmap. + */ +static inline struct regmap *regmap_init_mmio(struct device *dev, + void __iomem *regs, + const struct regmap_config *config) +{ + return regmap_init_mmio_clk(dev, NULL, regs, config); +} + +/** + * devm_regmap_init_mmio(): Initialise managed register map + * + * @dev: Device that will be interacted with + * @regs: Pointer to memory-mapped IO region + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap. The regmap will be automatically freed by the + * device management code. + */ +static inline struct regmap *devm_regmap_init_mmio(struct device *dev, + void __iomem *regs, + const struct regmap_config *config) +{ + return devm_regmap_init_mmio_clk(dev, NULL, regs, config); +} void regmap_exit(struct regmap *map); int regmap_reinit_cache(struct regmap *map, -- cgit v1.2.3