Skip to content

Commit c831dd7

Browse files
committed
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: [email protected] entry regmap: Add the DT binding documentation for endianness regmap: add DT endianness binding support.
2 parents 2b425a3 + f5b313a commit c831dd7

File tree

9 files changed

+149
-19
lines changed

9 files changed

+149
-19
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
};

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7595,6 +7595,7 @@ F: fs/reiserfs/
75957595

75967596
REGISTER MAP ABSTRACTION
75977597
M: Mark Brown <[email protected]>
7598+
75987599
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
75997600
S: Supported
76007601
F: drivers/base/regmap/

drivers/base/regmap/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ config REGMAP
1111

1212
config REGMAP_I2C
1313
tristate
14+
depends on I2C
1415

1516
config REGMAP_SPI
1617
tristate
18+
depends on SPI
1719

1820
config REGMAP_SPMI
1921
tristate
22+
depends on SPMI
2023

2124
config REGMAP_MMIO
2225
tristate

drivers/base/regmap/internal.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ struct regmap_async {
4949
};
5050

5151
struct regmap {
52-
struct mutex mutex;
53-
spinlock_t spinlock;
52+
union {
53+
struct mutex mutex;
54+
spinlock_t spinlock;
55+
};
5456
unsigned long spinlock_flags;
5557
regmap_lock lock;
5658
regmap_unlock unlock;

drivers/base/regmap/regcache.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,11 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
269269
map->cache_bypass = 1;
270270
ret = _regmap_write(map, reg, val);
271271
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);
273275
return ret;
276+
}
274277
dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
275278
}
276279

@@ -615,8 +618,11 @@ static int regcache_sync_block_single(struct regmap *map, void *block,
615618
ret = _regmap_write(map, regtmp, val);
616619

617620
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);
619624
return ret;
625+
}
620626
dev_dbg(map->dev, "Synced register %#x, value %#x\n",
621627
regtmp, val);
622628
}
@@ -641,6 +647,9 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
641647
map->cache_bypass = 1;
642648

643649
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);
644653

645654
map->cache_bypass = 0;
646655

drivers/base/regmap/regmap-debugfs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
473473
{
474474
struct rb_node *next;
475475
struct regmap_range_node *range_node;
476+
const char *devname = "dummy";
476477

477478
/* If we don't have the debugfs root yet, postpone init */
478479
if (!regmap_debugfs_root) {
@@ -491,12 +492,15 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
491492
INIT_LIST_HEAD(&map->debugfs_off_cache);
492493
mutex_init(&map->cache_lock);
493494

495+
if (map->dev)
496+
devname = dev_name(map->dev);
497+
494498
if (name) {
495499
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
496-
dev_name(map->dev), name);
500+
devname, name);
497501
name = map->debugfs_name;
498502
} else {
499-
name = dev_name(map->dev);
503+
name = devname;
500504
}
501505

502506
map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);

drivers/base/regmap/regmap-i2c.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = {
168168
.write = regmap_i2c_write,
169169
.gather_write = regmap_i2c_gather_write,
170170
.read = regmap_i2c_read,
171+
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
172+
.val_format_endian_default = REGMAP_ENDIAN_BIG,
171173
};
172174

173175
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,

drivers/base/regmap/regmap-spi.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = {
109109
.async_alloc = regmap_spi_async_alloc,
110110
.read = regmap_spi_read,
111111
.read_flag_mask = 0x80,
112+
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
113+
.val_format_endian_default = REGMAP_ENDIAN_BIG,
112114
};
113115

114116
/**

drivers/base/regmap/regmap.c

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/export.h>
1616
#include <linux/mutex.h>
1717
#include <linux/err.h>
18+
#include <linux/of.h>
1819
#include <linux/rbtree.h>
1920
#include <linux/sched.h>
2021

@@ -448,6 +449,71 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
448449
}
449450
EXPORT_SYMBOL_GPL(regmap_attach_dev);
450451

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+
451517
/**
452518
* regmap_init(): Initialise register map
453519
*
@@ -551,17 +617,8 @@ struct regmap *regmap_init(struct device *dev,
551617
map->reg_read = _regmap_bus_read;
552618
}
553619

554-
reg_endian = config->reg_format_endian;
555-
if (reg_endian == REGMAP_ENDIAN_DEFAULT)
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;
620+
reg_endian = regmap_get_reg_endian(bus, config);
621+
val_endian = regmap_get_val_endian(dev, bus, config);
565622

566623
switch (config->reg_bits + map->reg_shift) {
567624
case 2:
@@ -1408,7 +1465,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
14081465
}
14091466

14101467
#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)
14121469
dev_info(map->dev, "%x <= %x\n", reg, val);
14131470
#endif
14141471

@@ -1659,6 +1716,9 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
16591716
} else {
16601717
void *wval;
16611718

1719+
if (!val_count)
1720+
return -EINVAL;
1721+
16621722
wval = kmemdup(val, val_count * val_bytes, GFP_KERNEL);
16631723
if (!wval) {
16641724
dev_err(map->dev, "Error in memory allocation\n");
@@ -2058,7 +2118,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
20582118
ret = map->reg_read(context, reg, val);
20592119
if (ret == 0) {
20602120
#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)
20622122
dev_info(map->dev, "%x => %x\n", reg, *val);
20632123
#endif
20642124

0 commit comments

Comments
 (0)