summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/internal.h6
-rw-r--r--drivers/base/regmap/regcache.c2
-rw-r--r--drivers/base/regmap/regmap-irq.c4
-rw-r--r--drivers/base/regmap/regmap.c49
4 files changed, 45 insertions, 16 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index b2b2849fc6d3..d744ae3926dd 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -139,8 +139,10 @@ 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;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index b9862d741a56..6f8a13ec32a4 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -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
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 2597600a5d26..38d1f72d869c 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -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);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 7111d04f2621..a6b6f7ee87ee 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -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,9 @@ 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;
map->dev = dev;
map->bus = bus;
map->bus_context = bus_context;
@@ -763,7 +767,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,7 +1386,8 @@ 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);
@@ -1677,9 +1682,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 +1722,17 @@ 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->lock(map->lock_arg);
+ for (i = 0; i < val_count; i++) {
+ ret = _regmap_raw_write(map,
+ reg + (i * map->reg_stride),
+ val + (i * val_bytes),
+ val_bytes);
+ if (ret)
+ break;
+ }
+ map->unlock(map->lock_arg);
} else {
void *wval;
@@ -1740,7 +1762,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 +2072,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 +2119,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,11 +2199,18 @@ 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);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) {
+ if (!map->bus->read) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
/* Physical block read if there's no cache involved */
ret = _regmap_raw_read(map, reg, val, val_len);
@@ -2292,7 +2319,7 @@ 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) {
+ if (map->use_single_read) {
for (i = 0; i < val_count; i++) {
ret = regmap_raw_read(map,
reg + (i * map->reg_stride),