Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regmap: add DT endianness binding support.

For many drivers which will support rich endianness of Devices
need define DT properties by itself with the binding support.

The endianness using regmap:
Index Device Properties if needs bytes-swap,
or just ignore it
-------------------------------------------------------------
1 BE 'big-endian'
2 LE 'little-endian'

The properties include all the register values and the buffers.
And these properties are very usful for the MMIO devices:

Such as: a memory-mapped device, on one SoC is in BE mode, while
in another SoC will be in LE mode, and the CPU will always in LE
mode.

For the first case, we must use cpu_to_be32/be32_to_cpu for
32-bit registers accessing, so the 'big-endian' property is needed.

For the second case, we can just ignore the bytes-swap
functions like cpu_to_le32/le32_to_cpu, so the 'little-endian'
property could be abscent.

And vice versa...

Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Xiubo Li and committed by
Mark Brown
d647c199 7d1311b9

+109 -10
+2
drivers/base/regmap/regmap-i2c.c
··· 168 168 .write = regmap_i2c_write, 169 169 .gather_write = regmap_i2c_gather_write, 170 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 175 static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
+2
drivers/base/regmap/regmap-spi.c
··· 109 109 .async_alloc = regmap_spi_async_alloc, 110 110 .read = regmap_spi_read, 111 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 /**
+105 -10
drivers/base/regmap/regmap.c
··· 15 15 #include <linux/export.h> 16 16 #include <linux/mutex.h> 17 17 #include <linux/err.h> 18 + #include <linux/of.h> 18 19 #include <linux/rbtree.h> 19 20 #include <linux/sched.h> 20 21 ··· 449 448 } 450 449 EXPORT_SYMBOL_GPL(regmap_attach_dev); 451 450 451 + enum regmap_endian_type { 452 + REGMAP_ENDIAN_REG, 453 + REGMAP_ENDIAN_VAL, 454 + }; 455 + 456 + static int of_regmap_get_endian(struct device *dev, 457 + const struct regmap_bus *bus, 458 + const struct regmap_config *config, 459 + enum regmap_endian_type type, 460 + enum regmap_endian *endian) 461 + { 462 + struct device_node *np = dev->of_node; 463 + 464 + if (!endian || !config) 465 + return -EINVAL; 466 + 467 + /* 468 + * Firstly, try to parse the endianness from driver's config, 469 + * this is to be compatible with the none DT or the old drivers. 470 + * From the driver's config the endianness value maybe: 471 + * REGMAP_ENDIAN_BIG, 472 + * REGMAP_ENDIAN_LITTLE, 473 + * REGMAP_ENDIAN_NATIVE, 474 + * REGMAP_ENDIAN_DEFAULT. 475 + */ 476 + switch (type) { 477 + case REGMAP_ENDIAN_REG: 478 + *endian = config->reg_format_endian; 479 + break; 480 + case REGMAP_ENDIAN_VAL: 481 + *endian = config->val_format_endian; 482 + break; 483 + default: 484 + return -EINVAL; 485 + } 486 + 487 + /* 488 + * If the endianness parsed from driver config is 489 + * REGMAP_ENDIAN_DEFAULT, that means maybe we are using the DT 490 + * node to specify the endianness information. 491 + */ 492 + if (*endian != REGMAP_ENDIAN_DEFAULT) 493 + return 0; 494 + 495 + /* 496 + * Secondly, try to parse the endianness from DT node if the 497 + * driver config does not specify it. 498 + * From the DT node the endianness value maybe: 499 + * REGMAP_ENDIAN_BIG, 500 + * REGMAP_ENDIAN_LITTLE, 501 + * REGMAP_ENDIAN_NATIVE, 502 + */ 503 + switch (type) { 504 + case REGMAP_ENDIAN_VAL: 505 + if (of_property_read_bool(np, "big-endian")) 506 + *endian = REGMAP_ENDIAN_BIG; 507 + else if (of_property_read_bool(np, "little-endian")) 508 + *endian = REGMAP_ENDIAN_LITTLE; 509 + else 510 + *endian = REGMAP_ENDIAN_NATIVE; 511 + break; 512 + case REGMAP_ENDIAN_REG: 513 + break; 514 + default: 515 + return -EINVAL; 516 + } 517 + 518 + /* 519 + * If the endianness parsed from DT node is REGMAP_ENDIAN_NATIVE, that 520 + * maybe means the DT does not care the endianness or it should use 521 + * the regmap bus's default endianness, then we should try to check 522 + * whether the regmap bus has specified the default endianness. 523 + */ 524 + if (*endian != REGMAP_ENDIAN_NATIVE) 525 + return 0; 526 + 527 + /* 528 + * Finally, try to parse the endianness from regmap bus config 529 + * if in device's DT node the endianness property is absent. 530 + */ 531 + switch (type) { 532 + case REGMAP_ENDIAN_REG: 533 + if (bus && bus->reg_format_endian_default) 534 + *endian = bus->reg_format_endian_default; 535 + break; 536 + case REGMAP_ENDIAN_VAL: 537 + if (bus && bus->val_format_endian_default) 538 + *endian = bus->val_format_endian_default; 539 + break; 540 + default: 541 + return -EINVAL; 542 + } 543 + 544 + return 0; 545 + } 546 + 452 547 /** 453 548 * regmap_init(): Initialise register map 454 549 * ··· 648 551 map->reg_read = _regmap_bus_read; 649 552 } 650 553 651 - reg_endian = config->reg_format_endian; 652 - if (reg_endian == REGMAP_ENDIAN_DEFAULT) 653 - reg_endian = bus->reg_format_endian_default; 654 - if (reg_endian == REGMAP_ENDIAN_DEFAULT) 655 - reg_endian = REGMAP_ENDIAN_BIG; 554 + ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_REG, 555 + &reg_endian); 556 + if (ret) 557 + return ERR_PTR(ret); 656 558 657 - val_endian = config->val_format_endian; 658 - if (val_endian == REGMAP_ENDIAN_DEFAULT) 659 - val_endian = bus->val_format_endian_default; 660 - if (val_endian == REGMAP_ENDIAN_DEFAULT) 661 - val_endian = REGMAP_ENDIAN_BIG; 559 + ret = of_regmap_get_endian(dev, bus, config, REGMAP_ENDIAN_VAL, 560 + &val_endian); 561 + if (ret) 562 + return ERR_PTR(ret); 662 563 663 564 switch (config->reg_bits + map->reg_shift) { 664 565 case 2: