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 | |
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.
-rw-r--r-- | Documentation/devicetree/bindings/regmap/regmap.txt | 47 | ||||
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/base/regmap/Kconfig | 3 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 6 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 13 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 8 | ||||
-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 | 86 |
9 files changed, 149 insertions, 19 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/MAINTAINERS b/MAINTAINERS index f107230fc73d..8d9567186aa9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -7595,6 +7595,7 @@ F: fs/reiserfs/ | |||
7595 | 7595 | ||
7596 | REGISTER MAP ABSTRACTION | 7596 | REGISTER MAP ABSTRACTION |
7597 | M: Mark Brown <broonie@kernel.org> | 7597 | M: Mark Brown <broonie@kernel.org> |
7598 | L: linux-kernel@vger.kernel.org | ||
7598 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git | 7599 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git |
7599 | S: Supported | 7600 | S: Supported |
7600 | F: drivers/base/regmap/ | 7601 | F: drivers/base/regmap/ |
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 4251570610c9..8a3f51f7b1b9 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig | |||
@@ -11,12 +11,15 @@ config REGMAP | |||
11 | 11 | ||
12 | config REGMAP_I2C | 12 | config REGMAP_I2C |
13 | tristate | 13 | tristate |
14 | depends on I2C | ||
14 | 15 | ||
15 | config REGMAP_SPI | 16 | config REGMAP_SPI |
16 | tristate | 17 | tristate |
18 | depends on SPI | ||
17 | 19 | ||
18 | config REGMAP_SPMI | 20 | config REGMAP_SPMI |
19 | tristate | 21 | tristate |
22 | depends on SPMI | ||
20 | 23 | ||
21 | config REGMAP_MMIO | 24 | config REGMAP_MMIO |
22 | tristate | 25 | tristate |
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index bfc90b8547f2..0da5865df5b1 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -49,8 +49,10 @@ struct regmap_async { | |||
49 | }; | 49 | }; |
50 | 50 | ||
51 | struct regmap { | 51 | struct regmap { |
52 | struct mutex mutex; | 52 | union { |
53 | spinlock_t spinlock; | 53 | struct mutex mutex; |
54 | spinlock_t spinlock; | ||
55 | }; | ||
54 | unsigned long spinlock_flags; | 56 | unsigned long spinlock_flags; |
55 | regmap_lock lock; | 57 | regmap_lock lock; |
56 | regmap_unlock unlock; | 58 | regmap_unlock unlock; |
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 5617da6dc898..f1280dc356d0 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -269,8 +269,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, | |||
269 | map->cache_bypass = 1; | 269 | map->cache_bypass = 1; |
270 | ret = _regmap_write(map, reg, val); | 270 | ret = _regmap_write(map, reg, val); |
271 | map->cache_bypass = 0; | 271 | map->cache_bypass = 0; |
272 | if (ret) | 272 | if (ret) { |
273 | dev_err(map->dev, "Unable to sync register %#x. %d\n", | ||
274 | reg, ret); | ||
273 | return ret; | 275 | return ret; |
276 | } | ||
274 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val); | 277 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val); |
275 | } | 278 | } |
276 | 279 | ||
@@ -615,8 +618,11 @@ static int regcache_sync_block_single(struct regmap *map, void *block, | |||
615 | ret = _regmap_write(map, regtmp, val); | 618 | ret = _regmap_write(map, regtmp, val); |
616 | 619 | ||
617 | map->cache_bypass = 0; | 620 | map->cache_bypass = 0; |
618 | if (ret != 0) | 621 | if (ret != 0) { |
622 | dev_err(map->dev, "Unable to sync register %#x. %d\n", | ||
623 | regtmp, ret); | ||
619 | return ret; | 624 | return ret; |
625 | } | ||
620 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", | 626 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", |
621 | regtmp, val); | 627 | regtmp, val); |
622 | } | 628 | } |
@@ -641,6 +647,9 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, | |||
641 | map->cache_bypass = 1; | 647 | map->cache_bypass = 1; |
642 | 648 | ||
643 | ret = _regmap_raw_write(map, base, *data, count * val_bytes); | 649 | ret = _regmap_raw_write(map, base, *data, count * val_bytes); |
650 | if (ret) | ||
651 | dev_err(map->dev, "Unable to sync registers %#x-%#x. %d\n", | ||
652 | base, cur - map->reg_stride, ret); | ||
644 | 653 | ||
645 | map->cache_bypass = 0; | 654 | map->cache_bypass = 0; |
646 | 655 | ||
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 0c94b661c16f..5799a0b9e6cc 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -473,6 +473,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
473 | { | 473 | { |
474 | struct rb_node *next; | 474 | struct rb_node *next; |
475 | struct regmap_range_node *range_node; | 475 | struct regmap_range_node *range_node; |
476 | const char *devname = "dummy"; | ||
476 | 477 | ||
477 | /* If we don't have the debugfs root yet, postpone init */ | 478 | /* If we don't have the debugfs root yet, postpone init */ |
478 | if (!regmap_debugfs_root) { | 479 | if (!regmap_debugfs_root) { |
@@ -491,12 +492,15 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
491 | INIT_LIST_HEAD(&map->debugfs_off_cache); | 492 | INIT_LIST_HEAD(&map->debugfs_off_cache); |
492 | mutex_init(&map->cache_lock); | 493 | mutex_init(&map->cache_lock); |
493 | 494 | ||
495 | if (map->dev) | ||
496 | devname = dev_name(map->dev); | ||
497 | |||
494 | if (name) { | 498 | if (name) { |
495 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", | 499 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", |
496 | dev_name(map->dev), name); | 500 | devname, name); |
497 | name = map->debugfs_name; | 501 | name = map->debugfs_name; |
498 | } else { | 502 | } else { |
499 | name = dev_name(map->dev); | 503 | name = devname; |
500 | } | 504 | } |
501 | 505 | ||
502 | map->debugfs = debugfs_create_dir(name, regmap_debugfs_root); | 506 | map->debugfs = debugfs_create_dir(name, regmap_debugfs_root); |
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 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 | ||