diff --git a/Documentation/devicetree/bindings/regmap/regmap.txt b/Documentation/devicetree/bindings/regmap/regmap.txt new file mode 100644 index 000000000000..b494f8b8ef72 --- /dev/null +++ b/Documentation/devicetree/bindings/regmap/regmap.txt @@ -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; +}; diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index ca193d1ef47c..053150a7f9f2 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -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, diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 0eb3097c0d76..53d1148e80a0 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -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, }; /** diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 3a785a4f4ff6..d2f8a818d200 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -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 * @@ -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: