regmap: Device tree endianness support

This adds generic support for specifying endianess for register map in
 the DT.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJT8g7NAAoJELSic+t+oim9GC0P+wTr8/UEUvvW8tzE4XuyTWSD
 B+p/LwGe+ZGFxvq8bOpfVpmKzCxKvRRrjoDiKD6MyarssyO4DtSCnlz1tyJyG+Y8
 tqyPX8CPe7yZfx1m8I1POt0wYgI1FphLNZ1hsLFzutNSceaQr4++YA6P3046CMl5
 LrYeoekpmaIlhkG+3xMxSYamuTPPqANgMgRP63KVxbjxGAxFjMPV5N4+HY1S2kDc
 M00FwH+hbwx7T10+Rp0saGRKPCJCWwFfvLAjfbGo1O5dIepj92qOKEdmS+b1DrNv
 9tjw0cKmKgemzkZotF3mnVSPjm7Rn1MkV8jisbwBXvvZ2P3oI9rbn83Ot8Dw3bzM
 X77PogFG1wEhQScfBxfyZxFDc02VKmBiZtzxmDjHrHjZKCZm7vdtg1um8N1tboQW
 5A1p3IaML4LtXZrk6S6eDlA78ZFC2aSRbsrzLHMftUOwH3/SQZeR11HqenkABDxN
 J6liiy+AcDhDX+hcYmtqKffbsSyHcK09RfxBKTKunDMeNFsybHea+wbWaXnRsNfv
 tWTqJipn8anXVgy3j1cIbCd5mixxVCXleCfIzfhzPoPt3DQSWj6gRtjHntWXsN4R
 OxAc/zi8smirmrD4R9+0n+/E7OJhgSk8OY8tfDAymnyr2r73Q68uCPCGWHcBODeF
 2zTxC8Xag7SN08R5WQcJ
 =5ERR
 -----END PGP SIGNATURE-----

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.
This commit is contained in:
Mark Brown 2014-08-18 09:41:34 -05:00
Родитель 7d1311b93e 275876e208
Коммит dc8fcd7116
4 изменённых файлов: 156 добавлений и 10 удалений

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -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,

Просмотреть файл

@ -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,
};
/**

Просмотреть файл

@ -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>
@ -448,6 +449,102 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
}
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
*
@ -551,17 +648,15 @@ 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;
ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG,
&reg_endian);
if (ret)
return ERR_PTR(ret);
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;
ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL,
&val_endian);
if (ret)
return ERR_PTR(ret);
switch (config->reg_bits + map->reg_shift) {
case 2: