Commit cdf6b11d authored by Ben Whitten's avatar Ben Whitten Committed by Mark Brown

regmap: Add regmap_noinc_write API

The regmap API had a noinc_read function added for instances where devices
supported returning data from an internal FIFO in a single read.

This commit adds the noinc_write variant to allow writing to a non
incrementing register, this is used in devices such as the sx1301 for
loading firmware.
Signed-off-by: default avatarBen Whitten <ben.whitten@lairdtech.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 5b394b2d
...@@ -94,11 +94,13 @@ struct regmap { ...@@ -94,11 +94,13 @@ struct regmap {
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);
bool (*precious_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg);
bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg); bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
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;
const struct regmap_access_table *precious_table; const struct regmap_access_table *precious_table;
const struct regmap_access_table *wr_noinc_table;
const struct regmap_access_table *rd_noinc_table; const struct regmap_access_table *rd_noinc_table;
int (*reg_read)(void *context, unsigned int reg, unsigned int *val); int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
...@@ -183,6 +185,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg); ...@@ -183,6 +185,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg);
bool regmap_readable(struct regmap *map, unsigned int reg); bool regmap_readable(struct regmap *map, unsigned int reg);
bool regmap_volatile(struct regmap *map, unsigned int reg); bool regmap_volatile(struct regmap *map, unsigned int reg);
bool regmap_precious(struct regmap *map, unsigned int reg); bool regmap_precious(struct regmap *map, unsigned int reg);
bool regmap_writeable_noinc(struct regmap *map, unsigned int reg);
bool regmap_readable_noinc(struct regmap *map, unsigned int reg); bool regmap_readable_noinc(struct regmap *map, unsigned int reg);
int _regmap_write(struct regmap *map, unsigned int reg, int _regmap_write(struct regmap *map, unsigned int reg,
......
...@@ -168,6 +168,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg) ...@@ -168,6 +168,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return false; return false;
} }
bool regmap_writeable_noinc(struct regmap *map, unsigned int reg)
{
if (map->writeable_noinc_reg)
return map->writeable_noinc_reg(map->dev, reg);
if (map->wr_noinc_table)
return regmap_check_range_table(map, reg, map->wr_noinc_table);
return true;
}
bool regmap_readable_noinc(struct regmap *map, unsigned int reg) bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
{ {
if (map->readable_noinc_reg) if (map->readable_noinc_reg)
...@@ -777,11 +788,13 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -777,11 +788,13 @@ struct regmap *__regmap_init(struct device *dev,
map->rd_table = config->rd_table; map->rd_table = config->rd_table;
map->volatile_table = config->volatile_table; map->volatile_table = config->volatile_table;
map->precious_table = config->precious_table; map->precious_table = config->precious_table;
map->wr_noinc_table = config->wr_noinc_table;
map->rd_noinc_table = config->rd_noinc_table; map->rd_noinc_table = config->rd_noinc_table;
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;
map->precious_reg = config->precious_reg; map->precious_reg = config->precious_reg;
map->writeable_noinc_reg = config->writeable_noinc_reg;
map->readable_noinc_reg = config->readable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type; map->cache_type = config->cache_type;
...@@ -1298,6 +1311,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) ...@@ -1298,6 +1311,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->readable_reg = config->readable_reg; map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg; map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg; map->precious_reg = config->precious_reg;
map->writeable_noinc_reg = config->writeable_noinc_reg;
map->readable_noinc_reg = config->readable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type; map->cache_type = config->cache_type;
...@@ -1897,6 +1911,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -1897,6 +1911,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
} }
EXPORT_SYMBOL_GPL(regmap_raw_write); EXPORT_SYMBOL_GPL(regmap_raw_write);
/**
* regmap_noinc_write(): Write data from a register without incrementing the
* register number
*
* @map: Register map to write to
* @reg: Register to write to
* @val: Pointer to data buffer
* @val_len: Length of output buffer in bytes.
*
* The regmap API usually assumes that bulk bus write operations will write a
* range of registers. Some devices have certain registers for which a write
* operation can write to an internal FIFO.
*
* The target register must be volatile but registers after it can be
* completely unrelated cacheable registers.
*
* This will attempt multiple writes as required to write val_len bytes.
*
* A value of zero will be returned on success, a negative errno will be
* returned in error cases.
*/
int regmap_noinc_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len)
{
size_t write_len;
int ret;
if (!map->bus)
return -EINVAL;
if (!map->bus->write)
return -ENOTSUPP;
if (val_len % map->format.val_bytes)
return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (val_len == 0)
return -EINVAL;
map->lock(map->lock_arg);
if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) {
ret = -EINVAL;
goto out_unlock;
}
while (val_len) {
if (map->max_raw_write && map->max_raw_write < val_len)
write_len = map->max_raw_write;
else
write_len = val_len;
ret = _regmap_raw_write(map, reg, val, write_len);
if (ret)
goto out_unlock;
val = ((u8 *)val) + write_len;
val_len -= write_len;
}
out_unlock:
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_noinc_write);
/** /**
* regmap_field_update_bits_base() - Perform a read/modify/write cycle a * regmap_field_update_bits_base() - Perform a read/modify/write cycle a
* register field. * register field.
......
...@@ -268,6 +268,13 @@ typedef void (*regmap_unlock)(void *); ...@@ -268,6 +268,13 @@ typedef void (*regmap_unlock)(void *);
* field is NULL but precious_table (see below) is not, the * field is NULL but precious_table (see below) is not, the
* check is performed on such table (a register is precious if * check is performed on such table (a register is precious if
* it belongs to one of the ranges specified by precious_table). * it belongs to one of the ranges specified by precious_table).
* @writeable_noinc_reg: Optional callback returning true if the register
* supports multiple write operations without incrementing
* the register number. If this field is NULL but
* wr_noinc_table (see below) is not, the check is
* performed on such table (a register is no increment
* writeable if it belongs to one of the ranges specified
* by wr_noinc_table).
* @readable_noinc_reg: Optional callback returning true if the register * @readable_noinc_reg: Optional callback returning true if the register
* supports multiple read operations without incrementing * supports multiple read operations without incrementing
* the register number. If this field is NULL but * the register number. If this field is NULL but
...@@ -302,6 +309,7 @@ typedef void (*regmap_unlock)(void *); ...@@ -302,6 +309,7 @@ typedef void (*regmap_unlock)(void *);
* @rd_table: As above, for read access. * @rd_table: As above, for read access.
* @volatile_table: As above, for volatile registers. * @volatile_table: As above, for volatile registers.
* @precious_table: As above, for precious registers. * @precious_table: As above, for precious registers.
* @wr_noinc_table: As above, for no increment writeable registers.
* @rd_noinc_table: As above, for no increment readable registers. * @rd_noinc_table: As above, for no increment readable registers.
* @reg_defaults: Power on reset values for registers (for use with * @reg_defaults: Power on reset values for registers (for use with
* register cache support). * register cache support).
...@@ -352,6 +360,7 @@ struct regmap_config { ...@@ -352,6 +360,7 @@ struct regmap_config {
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);
bool (*precious_reg)(struct device *dev, unsigned int reg); bool (*precious_reg)(struct device *dev, unsigned int reg);
bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg); bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
bool disable_locking; bool disable_locking;
...@@ -369,6 +378,7 @@ struct regmap_config { ...@@ -369,6 +378,7 @@ struct regmap_config {
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;
const struct regmap_access_table *precious_table; const struct regmap_access_table *precious_table;
const struct regmap_access_table *wr_noinc_table;
const struct regmap_access_table *rd_noinc_table; const struct regmap_access_table *rd_noinc_table;
const struct reg_default *reg_defaults; const struct reg_default *reg_defaults;
unsigned int num_reg_defaults; unsigned int num_reg_defaults;
...@@ -979,6 +989,8 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val); ...@@ -979,6 +989,8 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val); int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val);
int regmap_raw_write(struct regmap *map, unsigned int reg, 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_noinc_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, int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
size_t val_count); size_t val_count);
int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
...@@ -1222,6 +1234,13 @@ static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg, ...@@ -1222,6 +1234,13 @@ static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg,
return -EINVAL; return -EINVAL;
} }
static inline int regmap_noinc_write(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)
{ {
......
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