diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 02:17:27 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 02:17:27 +0200 |
commit | 6214a9fe2aeca5e22184b20954774424e2efc1f6 (patch) | |
tree | d541f4b12762814750038a60b04654bdb81e7cca /drivers/base | |
parent | Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd (diff) | |
parent | Merge remote-tracking branches 'regmap/topic/noinc' and 'regmap/topic/single-... (diff) | |
download | linux-6214a9fe2aeca5e22184b20954774424e2efc1f6.tar.xz linux-6214a9fe2aeca5e22184b20954774424e2efc1f6.zip |
Merge tag 'regmap-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"A small update with a couple of new APIs that are useful for some
small sets of devices:
- Split up the single_rw flagging to map read and write separately as
some devices support bulk operations for only read or only write.
- Add a write version of the noinc API.
- Clean up the code for LOG_DEVICE a bit"
* tag 'regmap-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: use less #ifdef for LOG_DEVICE
regmap: Add regmap_noinc_write API
regmap: split up regmap_config.use_single_rw
regmap: fix comment for regmap.use_single_write
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/internal.h | 5 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 99 |
2 files changed, 95 insertions, 9 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a6bf34d6394e..a98fced9bff8 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -94,11 +94,13 @@ struct regmap { bool (*readable_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 (*writeable_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 *rd_table; const struct regmap_access_table *volatile_table; const struct regmap_access_table *precious_table; + const struct regmap_access_table *wr_noinc_table; const struct regmap_access_table *rd_noinc_table; int (*reg_read)(void *context, unsigned int reg, unsigned int *val); @@ -149,7 +151,7 @@ struct regmap { /* if set, converts bulk read to single read */ bool use_single_read; - /* if set, converts bulk read to single read */ + /* if set, converts bulk write to single write */ bool use_single_write; /* if set, the device supports multi write mode */ bool can_multi_write; @@ -183,6 +185,7 @@ bool regmap_writeable(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_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); int _regmap_write(struct regmap *map, unsigned int reg, diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0360a90ad6b6..4f822e087def 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -35,6 +35,16 @@ */ #undef LOG_DEVICE +#ifdef LOG_DEVICE +static inline bool regmap_should_log(struct regmap *map) +{ + return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0); +} +#else +static inline bool regmap_should_log(struct regmap *map) { return false; } +#endif + + static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write); @@ -168,6 +178,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg) 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) { if (map->readable_noinc_reg) @@ -762,8 +783,8 @@ struct regmap *__regmap_init(struct device *dev, map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; - map->use_single_read = config->use_single_rw || !bus || !bus->read; - map->use_single_write = config->use_single_rw || !bus || !bus->write; + map->use_single_read = config->use_single_read || !bus || !bus->read; + map->use_single_write = config->use_single_write || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; if (bus) { map->max_raw_read = bus->max_raw_read; @@ -777,11 +798,13 @@ struct regmap *__regmap_init(struct device *dev, map->rd_table = config->rd_table; map->volatile_table = config->volatile_table; map->precious_table = config->precious_table; + map->wr_noinc_table = config->wr_noinc_table; map->rd_noinc_table = config->rd_noinc_table; map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; + map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->cache_type = config->cache_type; @@ -1298,6 +1321,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; + map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->cache_type = config->cache_type; @@ -1755,10 +1779,8 @@ int _regmap_write(struct regmap *map, unsigned int reg, } } -#ifdef LOG_DEVICE - if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (regmap_should_log(map)) dev_info(map->dev, "%x <= %x\n", reg, val); -#endif trace_regmap_reg_write(map, reg, val); @@ -1898,6 +1920,69 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, 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 * register field. * @@ -2450,10 +2535,8 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ret = map->reg_read(context, reg, val); if (ret == 0) { -#ifdef LOG_DEVICE - if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) + if (regmap_should_log(map)) dev_info(map->dev, "%x => %x\n", reg, *val); -#endif trace_regmap_reg_read(map, reg, *val); |