Commit 4c47c2b0 authored by Mark Brown's avatar Mark Brown

Merge tag 'async' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into asoc-adsp

regmap: Add async I/O support

Allow drivers to take advantage of any support the underlying transports
may have for pipelining data.
parents 31522764 f804fb56
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/wait.h>
struct regmap; struct regmap;
struct regcache_ops; struct regcache_ops;
...@@ -39,6 +40,13 @@ struct regmap_format { ...@@ -39,6 +40,13 @@ struct regmap_format {
unsigned int (*parse_val)(void *buf); unsigned int (*parse_val)(void *buf);
}; };
struct regmap_async {
struct list_head list;
struct work_struct cleanup;
struct regmap *map;
void *work_buf;
};
struct regmap { struct regmap {
struct mutex mutex; struct mutex mutex;
spinlock_t spinlock; spinlock_t spinlock;
...@@ -53,6 +61,11 @@ struct regmap { ...@@ -53,6 +61,11 @@ struct regmap {
void *bus_context; void *bus_context;
const char *name; const char *name;
spinlock_t async_lock;
wait_queue_head_t async_waitq;
struct list_head async_list;
int async_ret;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
const char *debugfs_name; const char *debugfs_name;
...@@ -74,6 +87,9 @@ struct regmap { ...@@ -74,6 +87,9 @@ struct regmap {
const struct regmap_access_table *volatile_table; const struct regmap_access_table *volatile_table;
const struct regmap_access_table *precious_table; const struct regmap_access_table *precious_table;
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
u8 read_flag_mask; u8 read_flag_mask;
u8 write_flag_mask; u8 write_flag_mask;
...@@ -175,6 +191,8 @@ bool regcache_set_val(void *base, unsigned int idx, ...@@ -175,6 +191,8 @@ bool regcache_set_val(void *base, unsigned int idx,
unsigned int val, unsigned int word_size); unsigned int val, unsigned int word_size);
int regcache_lookup_reg(struct regmap *map, unsigned int reg); int regcache_lookup_reg(struct regmap *map, unsigned int reg);
void regmap_async_complete_cb(struct regmap_async *async, int ret);
extern struct regcache_ops regcache_rbtree_ops; extern struct regcache_ops regcache_rbtree_ops;
extern struct regcache_ops regcache_lzo_ops; extern struct regcache_ops regcache_lzo_ops;
......
...@@ -15,6 +15,21 @@ ...@@ -15,6 +15,21 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include "internal.h"
struct regmap_async_spi {
struct regmap_async core;
struct spi_message m;
struct spi_transfer t[2];
};
static void regmap_spi_complete(void *data)
{
struct regmap_async_spi *async = data;
regmap_async_complete_cb(&async->core, async->m.status);
}
static int regmap_spi_write(void *context, const void *data, size_t count) static int regmap_spi_write(void *context, const void *data, size_t count)
{ {
struct device *dev = context; struct device *dev = context;
...@@ -40,6 +55,41 @@ static int regmap_spi_gather_write(void *context, ...@@ -40,6 +55,41 @@ static int regmap_spi_gather_write(void *context,
return spi_sync(spi, &m); return spi_sync(spi, &m);
} }
static int regmap_spi_async_write(void *context,
const void *reg, size_t reg_len,
const void *val, size_t val_len,
struct regmap_async *a)
{
struct regmap_async_spi *async = container_of(a,
struct regmap_async_spi,
core);
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
async->t[0].tx_buf = reg;
async->t[0].len = reg_len;
async->t[1].tx_buf = val;
async->t[1].len = val_len;
spi_message_init(&async->m);
spi_message_add_tail(&async->t[0], &async->m);
spi_message_add_tail(&async->t[1], &async->m);
async->m.complete = regmap_spi_complete;
async->m.context = async;
return spi_async(spi, &async->m);
}
static struct regmap_async *regmap_spi_async_alloc(void)
{
struct regmap_async_spi *async_spi;
async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL);
return &async_spi->core;
}
static int regmap_spi_read(void *context, static int regmap_spi_read(void *context,
const void *reg, size_t reg_size, const void *reg, size_t reg_size,
void *val, size_t val_size) void *val, size_t val_size)
...@@ -53,6 +103,8 @@ static int regmap_spi_read(void *context, ...@@ -53,6 +103,8 @@ static int regmap_spi_read(void *context,
static struct regmap_bus regmap_spi = { static struct regmap_bus regmap_spi = {
.write = regmap_spi_write, .write = regmap_spi_write,
.gather_write = regmap_spi_gather_write, .gather_write = regmap_spi_gather_write,
.async_write = regmap_spi_async_write,
.async_alloc = regmap_spi_async_alloc,
.read = regmap_spi_read, .read = regmap_spi_read,
.read_flag_mask = 0x80, .read_flag_mask = 0x80,
}; };
......
This diff is collapsed.
...@@ -235,14 +235,21 @@ struct regmap_range_cfg { ...@@ -235,14 +235,21 @@ struct regmap_range_cfg {
unsigned int window_len; unsigned int window_len;
}; };
struct regmap_async;
typedef int (*regmap_hw_write)(void *context, const void *data, typedef int (*regmap_hw_write)(void *context, const void *data,
size_t count); size_t count);
typedef int (*regmap_hw_gather_write)(void *context, typedef int (*regmap_hw_gather_write)(void *context,
const void *reg, size_t reg_len, const void *reg, size_t reg_len,
const void *val, size_t val_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, typedef int (*regmap_hw_read)(void *context,
const void *reg_buf, size_t reg_size, const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_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); typedef void (*regmap_hw_free_context)(void *context);
/** /**
...@@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context); ...@@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context);
* @write: Write operation. * @write: Write operation.
* @gather_write: Write operation with split register/value, return -ENOTSUPP * @gather_write: Write operation with split register/value, return -ENOTSUPP
* if not implemented on a given device. * 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 * @read: Read operation. Data is returned in the buffer used to transmit
* data. * data.
* @async_alloc: Allocate a regmap_async() structure.
* @read_flag_mask: Mask to be set in the top byte of the register when doing * @read_flag_mask: Mask to be set in the top byte of the register when doing
* a read. * a read.
* @reg_format_endian_default: Default endianness for formatted register * @reg_format_endian_default: Default endianness for formatted register
...@@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context); ...@@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context);
* @val_format_endian_default: Default endianness for formatted register * @val_format_endian_default: Default endianness for formatted register
* values. Used when the regmap_config specifies DEFAULT. If this is * values. Used when the regmap_config specifies DEFAULT. If this is
* DEFAULT, BIG is assumed. * DEFAULT, BIG is assumed.
* @async_size: Size of struct used for async work.
*/ */
struct regmap_bus { struct regmap_bus {
bool fast_io; bool fast_io;
regmap_hw_write write; regmap_hw_write write;
regmap_hw_gather_write gather_write; regmap_hw_gather_write gather_write;
regmap_hw_async_write async_write;
regmap_hw_read read; regmap_hw_read read;
regmap_hw_free_context free_context; regmap_hw_free_context free_context;
regmap_hw_async_alloc async_alloc;
u8 read_flag_mask; u8 read_flag_mask;
enum regmap_endian reg_format_endian_default; enum regmap_endian reg_format_endian_default;
enum regmap_endian val_format_endian_default; enum regmap_endian val_format_endian_default;
...@@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len); const void *val, size_t val_len);
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
size_t val_count); 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_read(struct regmap *map, unsigned int reg, unsigned int *val);
int regmap_raw_read(struct regmap *map, unsigned int reg, int regmap_raw_read(struct regmap *map, unsigned int reg,
void *val, size_t val_len); void *val, size_t val_len);
...@@ -321,6 +336,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, ...@@ -321,6 +336,7 @@ int regmap_update_bits_check(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_async_complete(struct regmap *map);
int regcache_sync(struct regmap *map); int regcache_sync(struct regmap *map);
int regcache_sync_region(struct regmap *map, unsigned int min, 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, ...@@ -422,6 +438,13 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
return -EINVAL; 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, static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_count) const void *val, size_t val_count)
{ {
...@@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map) ...@@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map)
WARN_ONCE(1, "regmap API is disabled"); 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, static inline int regmap_register_patch(struct regmap *map,
const struct reg_default *regs, const struct reg_default *regs,
int num_regs) int num_regs)
......
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