Commit 45942c31 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'regmap/topic/dt-endian' into regmap-next

parents 88507a2b 6e64b6cc
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;
};
...@@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = { ...@@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = {
.write = regmap_i2c_write, .write = regmap_i2c_write,
.gather_write = regmap_i2c_gather_write, .gather_write = regmap_i2c_gather_write,
.read = regmap_i2c_read, .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, static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
......
...@@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = { ...@@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = {
.async_alloc = regmap_spi_async_alloc, .async_alloc = regmap_spi_async_alloc,
.read = regmap_spi_read, .read = regmap_spi_read,
.read_flag_mask = 0x80, .read_flag_mask = 0x80,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
}; };
/** /**
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -448,6 +449,71 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, ...@@ -448,6 +449,71 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
} }
EXPORT_SYMBOL_GPL(regmap_attach_dev); 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 * regmap_init(): Initialise register map
* *
...@@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev, ...@@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev,
map->reg_read = _regmap_bus_read; map->reg_read = _regmap_bus_read;
} }
reg_endian = config->reg_format_endian; reg_endian = regmap_get_reg_endian(bus, config);
if (reg_endian == REGMAP_ENDIAN_DEFAULT) val_endian = regmap_get_val_endian(dev, bus, config);
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;
switch (config->reg_bits + map->reg_shift) { switch (config->reg_bits + map->reg_shift) {
case 2: case 2:
......
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