Loading Documentation/devicetree/bindings/regmap/regmap.txt 0 → 100644 +47 −0 Original line number Diff line number Diff line 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; }; drivers/base/regmap/regmap-i2c.c +2 −0 Original line number Diff line number Diff line Loading @@ -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, Loading drivers/base/regmap/regmap-spi.c +2 −0 Original line number Diff line number Diff line Loading @@ -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, }; /** Loading drivers/base/regmap/regmap.c +68 −11 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 * Loading Loading @@ -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: Loading Loading
Documentation/devicetree/bindings/regmap/regmap.txt 0 → 100644 +47 −0 Original line number Diff line number Diff line 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; };
drivers/base/regmap/regmap-i2c.c +2 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
drivers/base/regmap/regmap-spi.c +2 −0 Original line number Diff line number Diff line Loading @@ -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, }; /** Loading
drivers/base/regmap/regmap.c +68 −11 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 * Loading Loading @@ -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: Loading