mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 13:11:45 +00:00
Merge remote-tracking branch 'regmap/topic/core' into regmap-next
This commit is contained in:
commit
a458a6d411
@ -139,11 +139,17 @@ struct regmap {
|
||||
struct reg_default *patch;
|
||||
int patch_regs;
|
||||
|
||||
/* if set, converts bulk rw to single rw */
|
||||
bool use_single_rw;
|
||||
/* if set, converts bulk read to single read */
|
||||
bool use_single_read;
|
||||
/* if set, converts bulk read to single read */
|
||||
bool use_single_write;
|
||||
/* if set, the device supports multi write mode */
|
||||
bool can_multi_write;
|
||||
|
||||
/* if set, raw reads/writes are limited to this size */
|
||||
size_t max_raw_read;
|
||||
size_t max_raw_write;
|
||||
|
||||
struct rb_root range_tree;
|
||||
void *selector_work_buf; /* Scratch buffer used for selector */
|
||||
};
|
||||
|
@ -729,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block,
|
||||
unsigned int block_base, unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
if (regmap_can_raw_write(map) && !map->use_single_rw)
|
||||
if (regmap_can_raw_write(map) && !map->use_single_write)
|
||||
return regcache_sync_block_raw(map, block, cache_present,
|
||||
block_base, start, end);
|
||||
else
|
||||
|
@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = {
|
||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
};
|
||||
|
||||
static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct i2c_client *i2c = to_i2c_client(dev);
|
||||
|
||||
if (count < 1)
|
||||
return -EINVAL;
|
||||
if (count >= I2C_SMBUS_BLOCK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
--count;
|
||||
return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
|
||||
((u8 *)data + 1));
|
||||
}
|
||||
|
||||
static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
|
||||
size_t reg_size, void *val,
|
||||
size_t val_size)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct i2c_client *i2c = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
if (reg_size != 1 || val_size < 1)
|
||||
return -EINVAL;
|
||||
if (val_size >= I2C_SMBUS_BLOCK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
|
||||
if (ret == val_size)
|
||||
return 0;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct regmap_bus regmap_i2c_smbus_i2c_block = {
|
||||
.write = regmap_i2c_smbus_i2c_write,
|
||||
.read = regmap_i2c_smbus_i2c_read,
|
||||
.max_raw_read = I2C_SMBUS_BLOCK_MAX,
|
||||
.max_raw_write = I2C_SMBUS_BLOCK_MAX,
|
||||
};
|
||||
|
||||
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
|
||||
return ®map_i2c;
|
||||
else if (config->reg_bits == 8 &&
|
||||
i2c_check_functionality(i2c->adapter,
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return ®map_i2c_smbus_i2c_block;
|
||||
else if (config->val_bits == 16 && config->reg_bits == 8 &&
|
||||
i2c_check_functionality(i2c->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
|
@ -209,7 +209,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
* Read in the statuses, using a single bulk read if possible
|
||||
* in order to reduce the I/O overheads.
|
||||
*/
|
||||
if (!map->use_single_rw && map->reg_stride == 1 &&
|
||||
if (!map->use_single_read && map->reg_stride == 1 &&
|
||||
data->irq_reg_stride == 1) {
|
||||
u8 *buf8 = data->status_reg_buf;
|
||||
u16 *buf16 = data->status_reg_buf;
|
||||
@ -398,7 +398,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
||||
else
|
||||
d->irq_reg_stride = 1;
|
||||
|
||||
if (!map->use_single_rw && map->reg_stride == 1 &&
|
||||
if (!map->use_single_read && map->reg_stride == 1 &&
|
||||
d->irq_reg_stride == 1) {
|
||||
d->status_reg_buf = kmalloc(map->format.val_bytes *
|
||||
chip->num_regs, GFP_KERNEL);
|
||||
|
@ -93,6 +93,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
|
||||
|
||||
bool regmap_readable(struct regmap *map, unsigned int reg)
|
||||
{
|
||||
if (!map->reg_read)
|
||||
return false;
|
||||
|
||||
if (map->max_register && reg > map->max_register)
|
||||
return false;
|
||||
|
||||
@ -573,8 +576,13 @@ struct regmap *regmap_init(struct device *dev,
|
||||
map->reg_stride = config->reg_stride;
|
||||
else
|
||||
map->reg_stride = 1;
|
||||
map->use_single_rw = config->use_single_rw;
|
||||
map->can_multi_write = config->can_multi_write;
|
||||
map->use_single_read = config->use_single_rw || !bus || !bus->read;
|
||||
map->use_single_write = config->use_single_rw || !bus || !bus->write;
|
||||
map->can_multi_write = config->can_multi_write && bus && bus->write;
|
||||
if (bus) {
|
||||
map->max_raw_read = bus->max_raw_read;
|
||||
map->max_raw_write = bus->max_raw_write;
|
||||
}
|
||||
map->dev = dev;
|
||||
map->bus = bus;
|
||||
map->bus_context = bus_context;
|
||||
@ -763,7 +771,7 @@ struct regmap *regmap_init(struct device *dev,
|
||||
if ((reg_endian != REGMAP_ENDIAN_BIG) ||
|
||||
(val_endian != REGMAP_ENDIAN_BIG))
|
||||
goto err_map;
|
||||
map->use_single_rw = true;
|
||||
map->use_single_write = true;
|
||||
}
|
||||
|
||||
if (!map->format.format_write &&
|
||||
@ -1382,10 +1390,33 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
*/
|
||||
bool regmap_can_raw_write(struct regmap *map)
|
||||
{
|
||||
return map->bus && map->format.format_val && map->format.format_reg;
|
||||
return map->bus && map->bus->write && map->format.format_val &&
|
||||
map->format.format_reg;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_can_raw_write);
|
||||
|
||||
/**
|
||||
* regmap_get_raw_read_max - Get the maximum size we can read
|
||||
*
|
||||
* @map: Map to check.
|
||||
*/
|
||||
size_t regmap_get_raw_read_max(struct regmap *map)
|
||||
{
|
||||
return map->max_raw_read;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_get_raw_read_max);
|
||||
|
||||
/**
|
||||
* regmap_get_raw_write_max - Get the maximum size we can read
|
||||
*
|
||||
* @map: Map to check.
|
||||
*/
|
||||
size_t regmap_get_raw_write_max(struct regmap *map)
|
||||
{
|
||||
return map->max_raw_write;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_get_raw_write_max);
|
||||
|
||||
static int _regmap_bus_formatted_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
@ -1555,6 +1586,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
return -EINVAL;
|
||||
if (val_len % map->format.val_bytes)
|
||||
return -EINVAL;
|
||||
if (map->max_raw_write && map->max_raw_write > val_len)
|
||||
return -E2BIG;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
@ -1669,6 +1702,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
{
|
||||
int ret = 0, i;
|
||||
size_t val_bytes = map->format.val_bytes;
|
||||
size_t total_size = val_bytes * val_count;
|
||||
|
||||
if (map->bus && !map->format.parse_inplace)
|
||||
return -EINVAL;
|
||||
@ -1677,9 +1711,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
|
||||
/*
|
||||
* Some devices don't support bulk write, for
|
||||
* them we have a series of single write operations.
|
||||
* them we have a series of single write operations in the first two if
|
||||
* blocks.
|
||||
*
|
||||
* The first if block is used for memory mapped io. It does not allow
|
||||
* val_bytes of 3 for example.
|
||||
* The second one is used for busses which do not have this limitation
|
||||
* and can write arbitrary value lengths.
|
||||
*/
|
||||
if (!map->bus || map->use_single_rw) {
|
||||
if (!map->bus) {
|
||||
map->lock(map->lock_arg);
|
||||
for (i = 0; i < val_count; i++) {
|
||||
unsigned int ival;
|
||||
@ -1711,6 +1751,38 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
}
|
||||
out:
|
||||
map->unlock(map->lock_arg);
|
||||
} else if (map->use_single_write ||
|
||||
(map->max_raw_write && map->max_raw_write < total_size)) {
|
||||
int chunk_stride = map->reg_stride;
|
||||
size_t chunk_size = val_bytes;
|
||||
size_t chunk_count = val_count;
|
||||
|
||||
if (!map->use_single_write) {
|
||||
chunk_size = map->max_raw_write;
|
||||
if (chunk_size % val_bytes)
|
||||
chunk_size -= chunk_size % val_bytes;
|
||||
chunk_count = total_size / chunk_size;
|
||||
chunk_stride *= chunk_size / val_bytes;
|
||||
}
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
/* Write as many bytes as possible with chunk_size */
|
||||
for (i = 0; i < chunk_count; i++) {
|
||||
ret = _regmap_raw_write(map,
|
||||
reg + (i * chunk_stride),
|
||||
val + (i * chunk_size),
|
||||
chunk_size);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write remaining bytes */
|
||||
if (!ret && chunk_size * i < total_size) {
|
||||
ret = _regmap_raw_write(map, reg + (i * chunk_stride),
|
||||
val + (i * chunk_size),
|
||||
total_size - i * chunk_size);
|
||||
}
|
||||
map->unlock(map->lock_arg);
|
||||
} else {
|
||||
void *wval;
|
||||
|
||||
@ -1740,7 +1812,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
|
||||
*
|
||||
* the (register,newvalue) pairs in regs have not been formatted, but
|
||||
* they are all in the same page and have been changed to being page
|
||||
* relative. The page register has been written if that was neccessary.
|
||||
* relative. The page register has been written if that was necessary.
|
||||
*/
|
||||
static int _regmap_raw_multi_reg_write(struct regmap *map,
|
||||
const struct reg_default *regs,
|
||||
@ -2050,7 +2122,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
||||
|
||||
/*
|
||||
* Some buses or devices flag reads by setting the high bits in the
|
||||
* register addresss; since it's always the high bits for all
|
||||
* register address; since it's always the high bits for all
|
||||
* current formats we can do this here rather than in
|
||||
* formatting. This may break if we get interesting formats.
|
||||
*/
|
||||
@ -2097,8 +2169,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
|
||||
int ret;
|
||||
void *context = _regmap_map_get_context(map);
|
||||
|
||||
WARN_ON(!map->reg_read);
|
||||
|
||||
if (!map->cache_bypass) {
|
||||
ret = regcache_read(map, reg, val);
|
||||
if (ret == 0)
|
||||
@ -2179,6 +2249,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
||||
return -EINVAL;
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
if (val_count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
@ -2188,6 +2260,10 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
if (map->max_raw_read && map->max_raw_read < val_len) {
|
||||
ret = -E2BIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Physical block read if there's no cache involved */
|
||||
ret = _regmap_raw_read(map, reg, val, val_len);
|
||||
@ -2297,20 +2373,51 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
||||
* Some devices does not support bulk read, for
|
||||
* them we have a series of single read operations.
|
||||
*/
|
||||
if (map->use_single_rw) {
|
||||
for (i = 0; i < val_count; i++) {
|
||||
ret = regmap_raw_read(map,
|
||||
reg + (i * map->reg_stride),
|
||||
val + (i * val_bytes),
|
||||
val_bytes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
size_t total_size = val_bytes * val_count;
|
||||
|
||||
if (!map->use_single_read &&
|
||||
(!map->max_raw_read || map->max_raw_read > total_size)) {
|
||||
ret = regmap_raw_read(map, reg, val,
|
||||
val_bytes * val_count);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
} else {
|
||||
/*
|
||||
* Some devices do not support bulk read or do not
|
||||
* support large bulk reads, for them we have a series
|
||||
* of read operations.
|
||||
*/
|
||||
int chunk_stride = map->reg_stride;
|
||||
size_t chunk_size = val_bytes;
|
||||
size_t chunk_count = val_count;
|
||||
|
||||
if (!map->use_single_read) {
|
||||
chunk_size = map->max_raw_read;
|
||||
if (chunk_size % val_bytes)
|
||||
chunk_size -= chunk_size % val_bytes;
|
||||
chunk_count = total_size / chunk_size;
|
||||
chunk_stride *= chunk_size / val_bytes;
|
||||
}
|
||||
|
||||
/* Read bytes that fit into a multiple of chunk_size */
|
||||
for (i = 0; i < chunk_count; i++) {
|
||||
ret = regmap_raw_read(map,
|
||||
reg + (i * chunk_stride),
|
||||
val + (i * chunk_size),
|
||||
chunk_size);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read remaining bytes */
|
||||
if (chunk_size * i < total_size) {
|
||||
ret = regmap_raw_read(map,
|
||||
reg + (i * chunk_stride),
|
||||
val + (i * chunk_size),
|
||||
total_size - i * chunk_size);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < val_count * val_bytes; i += val_bytes)
|
||||
@ -2322,7 +2429,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
||||
&ival);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
map->format.format_val(val + (i * val_bytes), ival, 0);
|
||||
|
||||
if (map->format.format_val) {
|
||||
map->format.format_val(val + (i * val_bytes), ival, 0);
|
||||
} else {
|
||||
/* Devices providing read and write
|
||||
* operations can use the bulk I/O
|
||||
* functions if they define a val_bytes,
|
||||
* we assume that the values are native
|
||||
* endian.
|
||||
*/
|
||||
u32 *u32 = val;
|
||||
u16 *u16 = val;
|
||||
u8 *u8 = val;
|
||||
|
||||
switch (map->format.val_bytes) {
|
||||
case 4:
|
||||
u32[i] = ival;
|
||||
break;
|
||||
case 2:
|
||||
u16[i] = ival;
|
||||
break;
|
||||
case 1:
|
||||
u8[i] = ival;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,8 +296,12 @@ typedef void (*regmap_hw_free_context)(void *context);
|
||||
* 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.
|
||||
* @reg_write: Write a single register value to the given register address. This
|
||||
* write operation has to complete when returning from the function.
|
||||
* @read: Read operation. Data is returned in the buffer used to transmit
|
||||
* data.
|
||||
* @reg_read: Read a single register value from a given register address.
|
||||
* @free_context: Free context.
|
||||
* @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.
|
||||
@ -307,7 +311,8 @@ 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.
|
||||
* @max_raw_read: Max raw read size that can be used on the bus.
|
||||
* @max_raw_write: Max raw write size that can be used on the bus.
|
||||
*/
|
||||
struct regmap_bus {
|
||||
bool fast_io;
|
||||
@ -322,6 +327,8 @@ struct regmap_bus {
|
||||
u8 read_flag_mask;
|
||||
enum regmap_endian reg_format_endian_default;
|
||||
enum regmap_endian val_format_endian_default;
|
||||
size_t max_raw_read;
|
||||
size_t max_raw_write;
|
||||
};
|
||||
|
||||
struct regmap *regmap_init(struct device *dev,
|
||||
@ -437,6 +444,8 @@ int regmap_get_max_register(struct regmap *map);
|
||||
int regmap_get_reg_stride(struct regmap *map);
|
||||
int regmap_async_complete(struct regmap *map);
|
||||
bool regmap_can_raw_write(struct regmap *map);
|
||||
size_t regmap_get_raw_read_max(struct regmap *map);
|
||||
size_t regmap_get_raw_write_max(struct regmap *map);
|
||||
|
||||
int regcache_sync(struct regmap *map);
|
||||
int regcache_sync_region(struct regmap *map, unsigned int min,
|
||||
|
Loading…
Reference in New Issue
Block a user