Skip to content

Commit

Permalink
Merge remote-tracking branch 'regmap/topic/dt-endian' into regmap-next
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Brown committed Sep 29, 2014
2 parents 88507a2 + 6e64b6c commit 45942c3
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 11 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;
};
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
79 changes: 68 additions & 11 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

0 comments on commit 45942c3

Please sign in to comment.