aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-08-18 10:41:34 -0400
committerMark Brown <broonie@linaro.org>2014-08-18 10:41:34 -0400
commitdc8fcd711610063681f1e9fd860823b1108182ca (patch)
tree1029bfc5360c6a7d8b285e7c3ac38c79f85dea25
parent7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff)
parent275876e208e28abf4b96ec89030e482b1331ee75 (diff)
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.
-rw-r--r--Documentation/devicetree/bindings/regmap/regmap.txt47
-rw-r--r--drivers/base/regmap/regmap-i2c.c2
-rw-r--r--drivers/base/regmap/regmap-spi.c2
-rw-r--r--drivers/base/regmap/regmap.c117
4 files changed, 157 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 @@
1Device-Tree binding for regmap
2
3The endianness mode of CPU & Device scenarios:
4Index Device Endianness properties
5---------------------------------------------------
61 BE 'big-endian'
72 LE 'little-endian'
8
9For one device driver, which will run in different scenarios above
10on different SoCs using the devicetree, we need one way to simplify
11this.
12
13Required 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
18Examples:
19Scenario 1 : CPU in LE mode & device in LE mode.
20dev: dev@40031000 {
21 compatible = "name";
22 reg = <0x40031000 0x1000>;
23 ...
24};
25
26Scenario 2 : CPU in LE mode & device in BE mode.
27dev: dev@40031000 {
28 compatible = "name";
29 reg = <0x40031000 0x1000>;
30 ...
31 big-endian;
32};
33
34Scenario 3 : CPU in BE mode & device in BE mode.
35dev: dev@40031000 {
36 compatible = "name";
37 reg = <0x40031000 0x1000>;
38 ...
39};
40
41Scenario 4 : CPU in BE mode & device in LE mode.
42dev: 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
173static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, 175static 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..e4e567e82b84 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,102 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
448} 449}
449EXPORT_SYMBOL_GPL(regmap_attach_dev); 450EXPORT_SYMBOL_GPL(regmap_attach_dev);
450 451
452enum regmap_endian_type {
453 REGMAP_ENDIAN_REG,
454 REGMAP_ENDIAN_VAL,
455};
456
457static int of_regmap_get_endian(struct device *dev,
458 const struct regmap_bus *bus,
459 const struct regmap_config *config,
460 enum regmap_endian_type type,
461 enum regmap_endian *endian)
462{
463 struct device_node *np = dev->of_node;
464
465 if (!endian || !config)
466 return -EINVAL;
467
468 /*
469 * Firstly, try to parse the endianness from driver's config,
470 * this is to be compatible with the none DT or the old drivers.
471 * From the driver's config the endianness value maybe:
472 * REGMAP_ENDIAN_BIG,
473 * REGMAP_ENDIAN_LITTLE,
474 * REGMAP_ENDIAN_NATIVE,
475 * REGMAP_ENDIAN_DEFAULT.
476 */
477 switch (type) {
478 case REGMAP_ENDIAN_REG:
479 *endian = config->reg_format_endian;
480 break;
481 case REGMAP_ENDIAN_VAL:
482 *endian = config->val_format_endian;
483 break;
484 default:
485 return -EINVAL;
486 }
487
488 /*
489 * If the endianness parsed from driver config is
490 * REGMAP_ENDIAN_DEFAULT, that means maybe we are using the DT
491 * node to specify the endianness information.
492 */
493 if (*endian != REGMAP_ENDIAN_DEFAULT)
494 return 0;
495
496 /*
497 * Secondly, try to parse the endianness from DT node if the
498 * driver config does not specify it.
499 * From the DT node the endianness value maybe:
500 * REGMAP_ENDIAN_BIG,
501 * REGMAP_ENDIAN_LITTLE,
502 * REGMAP_ENDIAN_NATIVE,
503 */
504 switch (type) {
505 case REGMAP_ENDIAN_VAL:
506 if (of_property_read_bool(np, "big-endian"))
507 *endian = REGMAP_ENDIAN_BIG;
508 else if (of_property_read_bool(np, "little-endian"))
509 *endian = REGMAP_ENDIAN_LITTLE;
510 else
511 *endian = REGMAP_ENDIAN_NATIVE;
512 break;
513 case REGMAP_ENDIAN_REG:
514 break;
515 default:
516 return -EINVAL;
517 }
518
519 /*
520 * If the endianness parsed from DT node is REGMAP_ENDIAN_NATIVE, that
521 * maybe means the DT does not care the endianness or it should use
522 * the regmap bus's default endianness, then we should try to check
523 * whether the regmap bus has specified the default endianness.
524 */
525 if (*endian != REGMAP_ENDIAN_NATIVE)
526 return 0;
527
528 /*
529 * Finally, try to parse the endianness from regmap bus config
530 * if in device's DT node the endianness property is absent.
531 */
532 switch (type) {
533 case REGMAP_ENDIAN_REG:
534 if (bus && bus->reg_format_endian_default)
535 *endian = bus->reg_format_endian_default;
536 break;
537 case REGMAP_ENDIAN_VAL:
538 if (bus && bus->val_format_endian_default)
539 *endian = bus->val_format_endian_default;
540 break;
541 default:
542 return -EINVAL;
543 }
544
545 return 0;
546}
547
451/** 548/**
452 * regmap_init(): Initialise register map 549 * regmap_init(): Initialise register map
453 * 550 *
@@ -551,17 +648,15 @@ struct regmap *regmap_init(struct device *dev,
551 map->reg_read = _regmap_bus_read; 648 map->reg_read = _regmap_bus_read;
552 } 649 }
553 650
554 reg_endian = config->reg_format_endian; 651 ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG,
555 if (reg_endian == REGMAP_ENDIAN_DEFAULT) 652 &reg_endian);
556 reg_endian = bus->reg_format_endian_default; 653 if (ret)
557 if (reg_endian == REGMAP_ENDIAN_DEFAULT) 654 return ERR_PTR(ret);
558 reg_endian = REGMAP_ENDIAN_BIG; 655
559 656 ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL,
560 val_endian = config->val_format_endian; 657 &val_endian);
561 if (val_endian == REGMAP_ENDIAN_DEFAULT) 658 if (ret)
562 val_endian = bus->val_format_endian_default; 659 return ERR_PTR(ret);
563 if (val_endian == REGMAP_ENDIAN_DEFAULT)
564 val_endian = REGMAP_ENDIAN_BIG;
565 660
566 switch (config->reg_bits + map->reg_shift) { 661 switch (config->reg_bits + map->reg_shift) {
567 case 2: 662 case 2: