diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-07 20:57:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-07 20:57:56 -0400 |
commit | c831dd7352c0eedb270b9b6430590da5991bb65c (patch) | |
tree | 89d808ddea1eeb039eeff2e5815d2ba3b55a1cba /drivers/base/regmap/regmap.c | |
parent | 2b425a3f112aa24666fc5f415c8bf0e9132bb6c0 (diff) | |
parent | f5b313a2bcd4c436560c044c726d9ad84a3e4bb3 (diff) |
Merge tag 'regmap-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"The main update this time around is the addition of a standard DT
binding for specifying the endianness of devices. This allows drivers
to support any endianness of device register map without any code,
useful for configurable IP blocks.
There's also a few bug fixes that I didn't get round to sending, none
of them terribly severe or new, and a reduction in size for struct
regmap"
* tag 'regmap-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: Fix debugfs-file 'registers' mode
regmap: fix possible ZERO_SIZE_PTR pointer dereferencing error.
regmap: debugfs: fix possbile NULL pointer dereference
regmap: fix NULL pointer dereference in _regmap_write/read
regmap: fix NULL pointer dereference in regmap_get_val_endian
regmap: cache: Do not fail silently from regcache_sync calls
regmap: change struct regmap's internal locks as union
regmap: Split regmap_get_endian() in two functions
regmap: of_regmap_get_endian() cleanup
regmap: Fix DT endianess parsing logic
regmap: Add explicit dependencies to catch "select" misuse
regmap: Restore L: linux-kernel@vger.kernel.org entry
regmap: Add the DT binding documentation for endianness
regmap: add DT endianness binding support.
Diffstat (limited to 'drivers/base/regmap/regmap.c')
-rw-r--r-- | drivers/base/regmap/regmap.c | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 1cf427bc0d4a..d2f8a818d200 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,71 @@ 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; | ||
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 | /* If the dev and dev->of_node exist try to get endianness from DT */ | ||
491 | if (dev && dev->of_node) { | ||
492 | np = dev->of_node; | ||
493 | |||
494 | /* Parse the device's DT node for an endianness specification */ | ||
495 | if (of_property_read_bool(np, "big-endian")) | ||
496 | endian = REGMAP_ENDIAN_BIG; | ||
497 | else if (of_property_read_bool(np, "little-endian")) | ||
498 | endian = REGMAP_ENDIAN_LITTLE; | ||
499 | |||
500 | /* If the endianness was specified in DT, use that */ | ||
501 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
502 | return endian; | ||
503 | } | ||
504 | |||
505 | /* Retrieve the endianness specification from the bus config */ | ||
506 | if (bus && bus->val_format_endian_default) | ||
507 | endian = bus->val_format_endian_default; | ||
508 | |||
509 | /* If the bus specified a non-default value, use that */ | ||
510 | if (endian != REGMAP_ENDIAN_DEFAULT) | ||
511 | return endian; | ||
512 | |||
513 | /* Use this if no other value was found */ | ||
514 | return REGMAP_ENDIAN_BIG; | ||
515 | } | ||
516 | |||
451 | /** | 517 | /** |
452 | * regmap_init(): Initialise register map | 518 | * regmap_init(): Initialise register map |
453 | * | 519 | * |
@@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev, | |||
551 | map->reg_read = _regmap_bus_read; | 617 | map->reg_read = _regmap_bus_read; |
552 | } | 618 | } |
553 | 619 | ||
554 | reg_endian = config->reg_format_endian; | 620 | reg_endian = regmap_get_reg_endian(bus, config); |
555 | if (reg_endian == REGMAP_ENDIAN_DEFAULT) | 621 | 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 | 622 | ||
566 | switch (config->reg_bits + map->reg_shift) { | 623 | switch (config->reg_bits + map->reg_shift) { |
567 | case 2: | 624 | case 2: |
@@ -1408,7 +1465,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
1408 | } | 1465 | } |
1409 | 1466 | ||
1410 | #ifdef LOG_DEVICE | 1467 | #ifdef LOG_DEVICE |
1411 | if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) | 1468 | if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) |
1412 | dev_info(map->dev, "%x <= %x\n", reg, val); | 1469 | dev_info(map->dev, "%x <= %x\n", reg, val); |
1413 | #endif | 1470 | #endif |
1414 | 1471 | ||
@@ -1659,6 +1716,9 @@ out: | |||
1659 | } else { | 1716 | } else { |
1660 | void *wval; | 1717 | void *wval; |
1661 | 1718 | ||
1719 | if (!val_count) | ||
1720 | return -EINVAL; | ||
1721 | |||
1662 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); | 1722 | wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL); |
1663 | if (!wval) { | 1723 | if (!wval) { |
1664 | dev_err(map->dev, "Error in memory allocation\n"); | 1724 | dev_err(map->dev, "Error in memory allocation\n"); |
@@ -2058,7 +2118,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, | |||
2058 | ret = map->reg_read(context, reg, val); | 2118 | ret = map->reg_read(context, reg, val); |
2059 | if (ret == 0) { | 2119 | if (ret == 0) { |
2060 | #ifdef LOG_DEVICE | 2120 | #ifdef LOG_DEVICE |
2061 | if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) | 2121 | if (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0) |
2062 | dev_info(map->dev, "%x => %x\n", reg, *val); | 2122 | dev_info(map->dev, "%x => %x\n", reg, *val); |
2063 | #endif | 2123 | #endif |
2064 | 2124 | ||