Skip to content

Commit

Permalink
Merge tag 'regmap-v3.18' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "The main update this time around is the addition of a standard DT
  binding for specifying the endianness of devices.  This allows drivers
  to support any endianness of device register map without any code,
  useful for configurable IP blocks.

  There's also a few bug fixes that I didn't get round to sending, none
  of them terribly severe or new, and a reduction in size for struct
  regmap"

* tag 'regmap-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: Fix debugfs-file 'registers' mode
  regmap: fix possible ZERO_SIZE_PTR pointer dereferencing error.
  regmap: debugfs: fix possbile NULL pointer dereference
  regmap: fix NULL pointer dereference in _regmap_write/read
  regmap: fix NULL pointer dereference in regmap_get_val_endian
  regmap: cache: Do not fail silently from regcache_sync calls
  regmap: change struct regmap's internal locks as union
  regmap: Split regmap_get_endian() in two functions
  regmap: of_regmap_get_endian() cleanup
  regmap: Fix DT endianess parsing logic
  regmap: Add explicit dependencies to catch "select" misuse
  regmap: Restore L: linux-kernel@vger.kernel.org entry
  regmap: Add the DT binding documentation for endianness
  regmap: add DT endianness binding support.
  • Loading branch information
Linus Torvalds committed Oct 8, 2014
2 parents 2b425a3 + f5b313a commit c831dd7
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 19 deletions.
47 changes: 47 additions & 0 deletions Documentation/devicetree/bindings/regmap/regmap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Device-Tree binding for regmap

The endianness mode of CPU & Device scenarios:
Index Device Endianness properties
---------------------------------------------------
1 BE 'big-endian'
2 LE 'little-endian'

For one device driver, which will run in different scenarios above
on different SoCs using the devicetree, we need one way to simplify
this.

Required properties:
- {big,little}-endian: these are boolean properties, if absent
meaning that the CPU and the Device are in the same endianness mode,
these properties are for register values and all the buffers only.

Examples:
Scenario 1 : CPU in LE mode & device in LE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
};

Scenario 2 : CPU in LE mode & device in BE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
big-endian;
};

Scenario 3 : CPU in BE mode & device in BE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
};

Scenario 4 : CPU in BE mode & device in LE mode.
dev: dev@40031000 {
compatible = "name";
reg = <0x40031000 0x1000>;
...
little-endian;
};
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -7595,6 +7595,7 @@ F: fs/reiserfs/

REGISTER MAP ABSTRACTION
M: Mark Brown <broonie@kernel.org>
L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
S: Supported
F: drivers/base/regmap/
Expand Down
3 changes: 3 additions & 0 deletions drivers/base/regmap/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ config REGMAP

config REGMAP_I2C
tristate
depends on I2C

config REGMAP_SPI
tristate
depends on SPI

config REGMAP_SPMI
tristate
depends on SPMI

config REGMAP_MMIO
tristate
Expand Down
6 changes: 4 additions & 2 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ struct regmap_async {
};

struct regmap {
struct mutex mutex;
spinlock_t spinlock;
union {
struct mutex mutex;
spinlock_t spinlock;
};
unsigned long spinlock_flags;
regmap_lock lock;
regmap_unlock unlock;
Expand Down
13 changes: 11 additions & 2 deletions drivers/base/regmap/regcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
map->cache_bypass = 1;
ret = _regmap_write(map, reg, val);
map->cache_bypass = 0;
if (ret)
if (ret) {
dev_err(map->dev, "Unable to sync register %#x. %d\n",
reg, ret);
return ret;
}
dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
}

Expand Down Expand Up @@ -615,8 +618,11 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
ret = _regmap_write(map, regtmp, val);

map->cache_bypass = 0;
if (ret != 0)
if (ret != 0) {
dev_err(map->dev, "Unable to sync register %#x. %d\n",
regtmp, ret);
return ret;
}
dev_dbg(map->dev, "Synced register %#x, value %#x\n",
regtmp, val);
}
Expand All @@ -641,6 +647,9 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
map->cache_bypass = 1;

ret = _regmap_raw_write(map, base, *data, count * val_bytes);
if (ret)
dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n",
base, cur - map->reg_stride, ret);

map->cache_bypass = 0;

Expand Down
8 changes: 6 additions & 2 deletions drivers/base/regmap/regmap-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
{
struct rb_node *next;
struct regmap_range_node *range_node;
const char *devname = "dummy";

/* If we don't have the debugfs root yet, postpone init */
if (!regmap_debugfs_root) {
Expand All @@ -491,12 +492,15 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
INIT_LIST_HEAD(&map->debugfs_off_cache);
mutex_init(&map->cache_lock);

if (map->dev)
devname = dev_name(map->dev);

if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
dev_name(map->dev), name);
devname, name);
name = map->debugfs_name;
} else {
name = dev_name(map->dev);
name = devname;
}

map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
Expand Down
2 changes: 2 additions & 0 deletions drivers/base/regmap/regmap-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = {
.write = regmap_i2c_write,
.gather_write = regmap_i2c_gather_write,
.read = regmap_i2c_read,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};

static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
Expand Down
2 changes: 2 additions & 0 deletions drivers/base/regmap/regmap-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = {
.async_alloc = regmap_spi_async_alloc,
.read = regmap_spi_read,
.read_flag_mask = 0x80,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};

/**
Expand Down
86 changes: 73 additions & 13 deletions drivers/base/regmap/regmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/rbtree.h>
#include <linux/sched.h>

Expand Down Expand Up @@ -448,6 +449,71 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
}
EXPORT_SYMBOL_GPL(regmap_attach_dev);

static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
const struct regmap_config *config)
{
enum regmap_endian endian;

/* Retrieve the endianness specification from the regmap config */
endian = config->reg_format_endian;

/* If the regmap config specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;

/* Retrieve the endianness specification from the bus config */
if (bus && bus->reg_format_endian_default)
endian = bus->reg_format_endian_default;

/* If the bus specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;

/* Use this if no other value was found */
return REGMAP_ENDIAN_BIG;
}

static enum regmap_endian regmap_get_val_endian(struct device *dev,
const struct regmap_bus *bus,
const struct regmap_config *config)
{
struct device_node *np;
enum regmap_endian endian;

/* Retrieve the endianness specification from the regmap config */
endian = config->val_format_endian;

/* If the regmap config specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;

/* If the dev and dev->of_node exist try to get endianness from DT */
if (dev && dev->of_node) {
np = dev->of_node;

/* Parse the device's DT node for an endianness specification */
if (of_property_read_bool(np, "big-endian"))
endian = REGMAP_ENDIAN_BIG;
else if (of_property_read_bool(np, "little-endian"))
endian = REGMAP_ENDIAN_LITTLE;

/* If the endianness was specified in DT, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;
}

/* Retrieve the endianness specification from the bus config */
if (bus && bus->val_format_endian_default)
endian = bus->val_format_endian_default;

/* If the bus specified a non-default value, use that */
if (endian != REGMAP_ENDIAN_DEFAULT)
return endian;

/* Use this if no other value was found */
return REGMAP_ENDIAN_BIG;
}

/**
* regmap_init(): Initialise register map
*
Expand Down Expand Up @@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev,
map->reg_read = _regmap_bus_read;
}

reg_endian = config->reg_format_endian;
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
reg_endian = bus->reg_format_endian_default;
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
reg_endian = REGMAP_ENDIAN_BIG;

val_endian = config->val_format_endian;
if (val_endian == REGMAP_ENDIAN_DEFAULT)
val_endian = bus->val_format_endian_default;
if (val_endian == REGMAP_ENDIAN_DEFAULT)
val_endian = REGMAP_ENDIAN_BIG;
reg_endian = regmap_get_reg_endian(bus, config);
val_endian = regmap_get_val_endian(dev, bus, config);

switch (config->reg_bits + map->reg_shift) {
case 2:
Expand Down Expand Up @@ -1408,7 +1465,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
}

#ifdef LOG_DEVICE
if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
dev_info(map->dev, "%x <= %x\n", reg, val);
#endif

Expand Down Expand Up @@ -1659,6 +1716,9 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
} else {
void *wval;

if (!val_count)
return -EINVAL;

wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
if (!wval) {
dev_err(map->dev, "Error in memory allocation\n");
Expand Down Expand Up @@ -2058,7 +2118,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
ret = map->reg_read(context, reg, val);
if (ret == 0) {
#ifdef LOG_DEVICE
if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
dev_info(map->dev, "%x => %x\n", reg, *val);
#endif

Expand Down

0 comments on commit c831dd7

Please sign in to comment.