diff options
author | Mark Brown <broonie@linaro.org> | 2014-08-27 14:14:25 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-08-27 14:14:25 -0400 |
commit | e94b8f50907c063de25ca52072e54b0581614995 (patch) | |
tree | 483ee5c8d176e58bde09e9e14565d25bd35d3f3b | |
parent | 38c6e4bb67760db1392b9c5ee0082af07c0db20d (diff) | |
parent | cf673fbc6342b1c2310cdfdc4ed99f18f866b8e4 (diff) |
Merge tag 'dt-endian' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into asoc-fsl
regmap: Device tree endianness support
This adds generic support for specifying endianess for register map in
the DT.
-rw-r--r-- | Documentation/devicetree/bindings/regmap/regmap.txt | 47 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi.c | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 74 |
4 files changed, 114 insertions, 11 deletions
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 @@ | |||
1 | Device-Tree binding for regmap | ||
2 | |||
3 | The endianness mode of CPU & Device scenarios: | ||
4 | Index Device Endianness properties | ||
5 | --------------------------------------------------- | ||
6 | 1 BE 'big-endian' | ||
7 | 2 LE 'little-endian' | ||
8 | |||
9 | For one device driver, which will run in different scenarios above | ||
10 | on different SoCs using the devicetree, we need one way to simplify | ||
11 | this. | ||
12 | |||
13 | Required properties: | ||
14 | - {big,little}-endian: these are boolean properties, if absent | ||
15 | meaning that the CPU and the Device are in the same endianness mode, | ||
16 | these properties are for register values and all the buffers only. | ||
17 | |||
18 | Examples: | ||
19 | Scenario 1 : CPU in LE mode & device in LE mode. | ||
20 | dev: dev@40031000 { | ||
21 | compatible = "name"; | ||
22 | reg = <0x40031000 0x1000>; | ||
23 | ... | ||
24 | }; | ||
25 | |||
26 | Scenario 2 : CPU in LE mode & device in BE mode. | ||
27 | dev: dev@40031000 { | ||
28 | compatible = "name"; | ||
29 | reg = <0x40031000 0x1000>; | ||
30 | ... | ||
31 | big-endian; | ||
32 | }; | ||
33 | |||
34 | Scenario 3 : CPU in BE mode & device in BE mode. | ||
35 | dev: dev@40031000 { | ||
36 | compatible = "name"; | ||
37 | reg = <0x40031000 0x1000>; | ||
38 | ... | ||
39 | }; | ||
40 | |||
41 | Scenario 4 : CPU in BE mode & device in LE mode. | ||
42 | dev: dev@40031000 { | ||
43 | compatible = "name"; | ||
44 | reg = <0x40031000 0x1000>; | ||
45 | ... | ||
46 | little-endian; | ||
47 | }; | ||
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 = { | |||
168 | .write = regmap_i2c_write, | 168 | .write = regmap_i2c_write, |
169 | .gather_write = regmap_i2c_gather_write, | 169 | .gather_write = regmap_i2c_gather_write, |
170 | .read = regmap_i2c_read, | 170 | .read = regmap_i2c_read, |
171 | .reg_format_endian_default = REGMAP_ENDIAN_BIG, | ||
172 | .val_format_endian_default = REGMAP_ENDIAN_BIG, | ||
171 | }; | 173 | }; |
172 | 174 | ||
173 | static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, | 175 | 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 = { | |||
109 | .async_alloc = regmap_spi_async_alloc, | 109 | .async_alloc = regmap_spi_async_alloc, |
110 | .read = regmap_spi_read, | 110 | .read = regmap_spi_read, |
111 | .read_flag_mask = 0x80, | 111 | .read_flag_mask = 0x80, |
112 | .reg_format_endian_default = REGMAP_ENDIAN_BIG, | ||
113 | .val_format_endian_default = REGMAP_ENDIAN_BIG, | ||
112 | }; | 114 | }; |
113 | 115 | ||
114 | /** | 116 | /** |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 78f43fb2fe84..01ae4b829360 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/of.h> | ||
18 | #include <linux/rbtree.h> | 19 | #include <linux/rbtree.h> |
19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
20 | 21 | ||
@@ -448,6 +449,66 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, | |||
448 | } | 449 | } |
449 | EXPORT_SYMBOL_GPL(regmap_attach_dev); | 450 | EXPORT_SYMBOL_GPL(regmap_attach_dev); |
450 | 451 | ||
452 | static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, | ||
453 | const struct regmap_config *config) | ||
454 | { | ||
455 | enum regmap_endian endian; | ||
456 | |||
457 | /* Retrieve the endianness specification from the regmap config */ | ||
458 | endian = config->reg_format_endian; | ||
459 | |||
460 | /* If the regmap config specified a non-default value, use that */ | ||
461 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
462 | return endian; | ||
463 | |||
464 | /* Retrieve the endianness specification from the bus config */ | ||
465 | if (bus && bus->reg_format_endian_default) | ||
466 | endian = bus->reg_format_endian_default; | ||
467 | |||
468 | /* If the bus specified a non-default value, use that */ | ||
469 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
470 | return endian; | ||
471 | |||
472 | /* Use this if no other value was found */ | ||
473 | return REGMAP_ENDIAN_BIG; | ||
474 | } | ||
475 | |||
476 | static enum regmap_endian regmap_get_val_endian(struct device *dev, | ||
477 | const struct regmap_bus *bus, | ||
478 | const struct regmap_config *config) | ||
479 | { | ||
480 | struct device_node *np = dev->of_node; | ||
481 | enum regmap_endian endian; | ||
482 | |||
483 | /* Retrieve the endianness specification from the regmap config */ | ||
484 | endian = config->val_format_endian; | ||
485 | |||
486 | /* If the regmap config specified a non-default value, use that */ | ||
487 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
488 | return endian; | ||
489 | |||
490 | /* Parse the device's DT node for an endianness specification */ | ||
491 | if (of_property_read_bool(np, "big-endian")) | ||
492 | endian = REGMAP_ENDIAN_BIG; | ||
493 | else if (of_property_read_bool(np, "little-endian")) | ||
494 | endian = REGMAP_ENDIAN_LITTLE; | ||
495 | |||
496 | /* If the endianness was specified in DT, use that */ | ||
497 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
498 | return endian; | ||
499 | |||
500 | /* Retrieve the endianness specification from the bus config */ | ||
501 | if (bus && bus->val_format_endian_default) | ||
502 | endian = bus->val_format_endian_default; | ||
503 | |||
504 | /* If the bus specified a non-default value, use that */ | ||
505 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
506 | return endian; | ||
507 | |||
508 | /* Use this if no other value was found */ | ||
509 | return REGMAP_ENDIAN_BIG; | ||
510 | } | ||
511 | |||
451 | /** | 512 | /** |
452 | * regmap_init(): Initialise register map | 513 | * regmap_init(): Initialise register map |
453 | * | 514 | * |
@@ -551,17 +612,8 @@ struct regmap *regmap_init(struct device *dev, | |||
551 | map->reg_read = _regmap_bus_read; | 612 | map->reg_read = _regmap_bus_read; |
552 | } | 613 | } |
553 | 614 | ||
554 | reg_endian = config->reg_format_endian; | 615 | reg_endian = regmap_get_reg_endian(bus, config); |
555 | if (reg_endian == REGMAP_ENDIAN_DEFAULT) | 616 | val_endian = regmap_get_val_endian(dev, bus, config); |
556 | reg_endian = bus->reg_format_endian_default; | ||
557 | if (reg_endian == REGMAP_ENDIAN_DEFAULT) | ||
558 | reg_endian = REGMAP_ENDIAN_BIG; | ||
559 | |||
560 | val_endian = config->val_format_endian; | ||
561 | if (val_endian == REGMAP_ENDIAN_DEFAULT) | ||
562 | val_endian = bus->val_format_endian_default; | ||
563 | if (val_endian == REGMAP_ENDIAN_DEFAULT) | ||
564 | val_endian = REGMAP_ENDIAN_BIG; | ||
565 | 617 | ||
566 | switch (config->reg_bits + map->reg_shift) { | 618 | switch (config->reg_bits + map->reg_shift) { |
567 | case 2: | 619 | case 2: |