diff options
author | Mark Brown <broonie@linaro.org> | 2014-08-27 17:07:01 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-08-27 17:07:01 -0400 |
commit | 6ba42ba608df1e243d594a682073e783a57c95f5 (patch) | |
tree | 5b52ddf4d71f57d366af5f69ef2761164d355b68 | |
parent | c99428d035908b9c0b8be452f9b091bc5e090256 (diff) | |
parent | cf673fbc6342b1c2310cdfdc4ed99f18f866b8e4 (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-- | drivers/base/regmap/regmap.c | 143 |
1 files changed, 50 insertions, 93 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index e4e567e82b84..01ae4b829360 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -449,100 +449,64 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, | |||
449 | } | 449 | } |
450 | EXPORT_SYMBOL_GPL(regmap_attach_dev); | 450 | EXPORT_SYMBOL_GPL(regmap_attach_dev); |
451 | 451 | ||
452 | enum regmap_endian_type { | 452 | static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, |
453 | REGMAP_ENDIAN_REG, | 453 | const struct regmap_config *config) |
454 | REGMAP_ENDIAN_VAL, | 454 | { |
455 | }; | 455 | enum regmap_endian endian; |
456 | 456 | ||
457 | static int of_regmap_get_endian(struct device *dev, | 457 | /* Retrieve the endianness specification from the regmap config */ |
458 | const struct regmap_bus *bus, | 458 | endian = config->reg_format_endian; |
459 | const struct regmap_config *config, | 459 | |
460 | enum regmap_endian_type type, | 460 | /* If the regmap config specified a non-default value, use that */ |
461 | enum regmap_endian *endian) | 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) | ||
462 | { | 479 | { |
463 | struct device_node *np = dev->of_node; | 480 | struct device_node *np = dev->of_node; |
481 | enum regmap_endian endian; | ||
464 | 482 | ||
465 | if (!endian || !config) | 483 | /* Retrieve the endianness specification from the regmap config */ |
466 | return -EINVAL; | 484 | endian = config->val_format_endian; |
467 | 485 | ||
468 | /* | 486 | /* If the regmap config specified a non-default value, use that */ |
469 | * Firstly, try to parse the endianness from driver's config, | 487 | if (endian != REGMAP_ENDIAN_DEFAULT) |
470 | * this is to be compatible with the none DT or the old drivers. | 488 | return endian; |
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 | 489 | ||
488 | /* | 490 | /* Parse the device's DT node for an endianness specification */ |
489 | * If the endianness parsed from driver config is | 491 | if (of_property_read_bool(np, "big-endian")) |
490 | * REGMAP_ENDIAN_DEFAULT, that means maybe we are using the DT | 492 | endian = REGMAP_ENDIAN_BIG; |
491 | * node to specify the endianness information. | 493 | else if (of_property_read_bool(np, "little-endian")) |
492 | */ | 494 | endian = REGMAP_ENDIAN_LITTLE; |
493 | if (*endian != REGMAP_ENDIAN_DEFAULT) | ||
494 | return 0; | ||
495 | 495 | ||
496 | /* | 496 | /* If the endianness was specified in DT, use that */ |
497 | * Secondly, try to parse the endianness from DT node if the | 497 | if (endian != REGMAP_ENDIAN_DEFAULT) |
498 | * driver config does not specify it. | 498 | return endian; |
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 | 499 | ||
519 | /* | 500 | /* Retrieve the endianness specification from the bus config */ |
520 | * If the endianness parsed from DT node is REGMAP_ENDIAN_NATIVE, that | 501 | if (bus && bus->val_format_endian_default) |
521 | * maybe means the DT does not care the endianness or it should use | 502 | endian = bus->val_format_endian_default; |
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 | 503 | ||
528 | /* | 504 | /* If the bus specified a non-default value, use that */ |
529 | * Finally, try to parse the endianness from regmap bus config | 505 | if (endian != REGMAP_ENDIAN_DEFAULT) |
530 | * if in device's DT node the endianness property is absent. | 506 | return endian; |
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 | 507 | ||
545 | return 0; | 508 | /* Use this if no other value was found */ |
509 | return REGMAP_ENDIAN_BIG; | ||
546 | } | 510 | } |
547 | 511 | ||
548 | /** | 512 | /** |
@@ -648,15 +612,8 @@ struct regmap *regmap_init(struct device *dev, | |||
648 | map->reg_read = _regmap_bus_read; | 612 | map->reg_read = _regmap_bus_read; |
649 | } | 613 | } |
650 | 614 | ||
651 | ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG, | 615 | reg_endian = regmap_get_reg_endian(bus, config); |
652 | ®_endian); | 616 | val_endian = regmap_get_val_endian(dev, bus, config); |
653 | if (ret) | ||
654 | return ERR_PTR(ret); | ||
655 | |||
656 | ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL, | ||
657 | &val_endian); | ||
658 | if (ret) | ||
659 | return ERR_PTR(ret); | ||
660 | 617 | ||
661 | switch (config->reg_bits + map->reg_shift) { | 618 | switch (config->reg_bits + map->reg_shift) { |
662 | case 2: | 619 | case 2: |