提交 dc8fcd71 编写于 作者: M Mark Brown

Merge tag 'dt-endian' of...

Merge tag 'dt-endian' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into spi-fsl-dspi

regmap: Device tree endianness support

This adds generic support for specifying endianess for register map in
the DT.
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,102 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, ...@@ -448,6 +449,102 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
} }
EXPORT_SYMBOL_GPL(regmap_attach_dev); EXPORT_SYMBOL_GPL(regmap_attach_dev);
enum regmap_endian_type {
REGMAP_ENDIAN_REG,
REGMAP_ENDIAN_VAL,
};
static int of_regmap_get_endian(struct device *dev,
const struct regmap_bus *bus,
const struct regmap_config *config,
enum regmap_endian_type type,
enum regmap_endian *endian)
{
struct device_node *np = dev->of_node;
if (!endian || !config)
return -EINVAL;
/*
* Firstly, try to parse the endianness from driver's config,
* this is to be compatible with the none DT or the old drivers.
* From the driver's config the endianness value maybe:
* REGMAP_ENDIAN_BIG,
* REGMAP_ENDIAN_LITTLE,
* REGMAP_ENDIAN_NATIVE,
* REGMAP_ENDIAN_DEFAULT.
*/
switch (type) {
case REGMAP_ENDIAN_REG:
*endian = config->reg_format_endian;
break;
case REGMAP_ENDIAN_VAL:
*endian = config->val_format_endian;
break;
default:
return -EINVAL;
}
/*
* If the endianness parsed from driver config is
* REGMAP_ENDIAN_DEFAULT, that means maybe we are using the DT
* node to specify the endianness information.
*/
if (*endian != REGMAP_ENDIAN_DEFAULT)
return 0;
/*
* Secondly, try to parse the endianness from DT node if the
* driver config does not specify it.
* From the DT node the endianness value maybe:
* REGMAP_ENDIAN_BIG,
* REGMAP_ENDIAN_LITTLE,
* REGMAP_ENDIAN_NATIVE,
*/
switch (type) {
case REGMAP_ENDIAN_VAL:
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;
else
*endian = REGMAP_ENDIAN_NATIVE;
break;
case REGMAP_ENDIAN_REG:
break;
default:
return -EINVAL;
}
/*
* If the endianness parsed from DT node is REGMAP_ENDIAN_NATIVE, that
* maybe means the DT does not care the endianness or it should use
* the regmap bus's default endianness, then we should try to check
* whether the regmap bus has specified the default endianness.
*/
if (*endian != REGMAP_ENDIAN_NATIVE)
return 0;
/*
* Finally, try to parse the endianness from regmap bus config
* if in device's DT node the endianness property is absent.
*/
switch (type) {
case REGMAP_ENDIAN_REG:
if (bus && bus->reg_format_endian_default)
*endian = bus->reg_format_endian_default;
break;
case REGMAP_ENDIAN_VAL:
if (bus && bus->val_format_endian_default)
*endian = bus->val_format_endian_default;
break;
default:
return -EINVAL;
}
return 0;
}
/** /**
* regmap_init(): Initialise register map * regmap_init(): Initialise register map
* *
...@@ -551,17 +648,15 @@ struct regmap *regmap_init(struct device *dev, ...@@ -551,17 +648,15 @@ 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; ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG,
if (reg_endian == REGMAP_ENDIAN_DEFAULT) &reg_endian);
reg_endian = bus->reg_format_endian_default; if (ret)
if (reg_endian == REGMAP_ENDIAN_DEFAULT) return ERR_PTR(ret);
reg_endian = REGMAP_ENDIAN_BIG;
val_endian = config->val_format_endian; ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL,
if (val_endian == REGMAP_ENDIAN_DEFAULT) &val_endian);
val_endian = bus->val_format_endian_default; if (ret)
if (val_endian == REGMAP_ENDIAN_DEFAULT) return ERR_PTR(ret);
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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册