Skip to content

Commit

Permalink
Merge tag 'regmap-v4.16' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "A very busy release for regmap, all fairly specialist stuff but
  useful:

   - Support for disabling locking from Bartosz Golaszewski, allowing
     users that handle their own locking to save some overhead.

   - Support for hwspinlocks in syscons in MFD from Baolin Wang, this is
     going through the regmap tree since the first users turned up some
     some cases that needed interface tweaks with 0 being used as a
     syscon identifier.

   - Support for devices with no read or write flag from Andrew F.
     Davis.

   - Basic support for devices on SoundWire buses from Vinod Koul"

* tag 'regmap-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  mfd: syscon: Add hardware spinlock support
  regmap: Allow empty read/write_flag_mask
  regcache: flat: Un-inline index lookup from cache access
  regmap: Add SoundWire bus support
  regmap: Add one flag to indicate if a hwlock should be used
  regmap: debugfs: document why we don't create the debugfs entries
  regmap: debugfs: emit a debug message when locking is disabled
  regmap: use proper part of work_buf for storing val
  regmap: potentially duplicate the name string stored in regmap
  regmap: Disable debugfs when locking is disabled
  regmap: rename regmap_lock_unlock_empty() to regmap_lock_unlock_none()
  regmap: allow to disable all locking mechanisms
  regmap: Remove the redundant config to select hwspinlock
  • Loading branch information
Linus Torvalds committed Jan 29, 2018
2 parents dc38787 + a75de77 commit b5856f9
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 25 deletions.
8 changes: 8 additions & 0 deletions Documentation/devicetree/bindings/mfd/syscon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ Required properties:
Optional property:
- reg-io-width: the size (in bytes) of the IO accesses that should be
performed on the device.
- hwlocks: reference to a phandle of a hardware spinlock provider node.

Examples:
gpr: iomuxc-gpr@20e0000 {
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
reg = <0x020e0000 0x38>;
hwlocks = <&hwlock1 1>;
};

hwlock1: hwspinlock@40500000 {
...
reg = <0x40500000 0x1000>;
#hwlock-cells = <1>;
};
6 changes: 3 additions & 3 deletions drivers/base/regmap/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
select IRQ_DOMAIN if REGMAP_IRQ
select REGMAP_HWSPINLOCK if HWSPINLOCK=y
bool

config REGCACHE_COMPRESSED
Expand Down Expand Up @@ -39,5 +38,6 @@ config REGMAP_MMIO
config REGMAP_IRQ
bool

config REGMAP_HWSPINLOCK
bool
config REGMAP_SOUNDWIRE
tristate
depends on SOUNDWIRE_BUS
1 change: 1 addition & 0 deletions drivers/base/regmap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
8 changes: 8 additions & 0 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct regmap {
int async_ret;

#ifdef CONFIG_DEBUG_FS
bool debugfs_disable;
struct dentry *debugfs;
const char *debugfs_name;

Expand Down Expand Up @@ -215,10 +216,17 @@ struct regmap_field {
extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map, const char *name);
extern void regmap_debugfs_exit(struct regmap *map);

static inline void regmap_debugfs_disable(struct regmap *map)
{
map->debugfs_disable = true;
}

#else
static inline void regmap_debugfs_initcall(void) { }
static inline void regmap_debugfs_init(struct regmap *map, const char *name) { }
static inline void regmap_debugfs_exit(struct regmap *map) { }
static inline void regmap_debugfs_disable(struct regmap *map) { }
#endif

/* regcache core declarations */
Expand Down
15 changes: 10 additions & 5 deletions drivers/base/regmap/regcache-flat.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ static int regcache_flat_init(struct regmap *map)

cache = map->cache;

for (i = 0; i < map->num_reg_defaults; i++)
cache[regcache_flat_get_index(map, map->reg_defaults[i].reg)] =
map->reg_defaults[i].def;
for (i = 0; i < map->num_reg_defaults; i++) {
unsigned int reg = map->reg_defaults[i].reg;
unsigned int index = regcache_flat_get_index(map, reg);

cache[index] = map->reg_defaults[i].def;
}

return 0;
}
Expand All @@ -56,8 +59,9 @@ static int regcache_flat_read(struct regmap *map,
unsigned int reg, unsigned int *value)
{
unsigned int *cache = map->cache;
unsigned int index = regcache_flat_get_index(map, reg);

*value = cache[regcache_flat_get_index(map, reg)];
*value = cache[index];

return 0;
}
Expand All @@ -66,8 +70,9 @@ static int regcache_flat_write(struct regmap *map, unsigned int reg,
unsigned int value)
{
unsigned int *cache = map->cache;
unsigned int index = regcache_flat_get_index(map, reg);

cache[regcache_flat_get_index(map, reg)] = value;
cache[index] = value;

return 0;
}
Expand Down
12 changes: 12 additions & 0 deletions drivers/base/regmap/regmap-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,18 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
struct regmap_range_node *range_node;
const char *devname = "dummy";

/*
* Userspace can initiate reads from the hardware over debugfs.
* Normally internal regmap structures and buffers are protected with
* a mutex or a spinlock, but if the regmap owner decided to disable
* all locking mechanisms, this is no longer the case. For safety:
* don't create the debugfs entries if locking is disabled.
*/
if (map->debugfs_disable) {
dev_dbg(map->dev, "regmap locking disabled - not creating debugfs entries\n");
return;
}

/* If we don't have the debugfs root yet, postpone init */
if (!regmap_debugfs_root) {
struct regmap_debugfs_node *node;
Expand Down
88 changes: 88 additions & 0 deletions drivers/base/regmap/regmap-sdw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright(c) 2015-17 Intel Corporation.

#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
#include "internal.h"

static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val)
{
struct device *dev = context;
struct sdw_slave *slave = dev_to_sdw_dev(dev);

return sdw_write(slave, reg, val);
}

static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
{
struct device *dev = context;
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int read;

read = sdw_read(slave, reg);
if (read < 0)
return read;

*val = read;
return 0;
}

static struct regmap_bus regmap_sdw = {
.reg_read = regmap_sdw_read,
.reg_write = regmap_sdw_write,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};

static int regmap_sdw_config_check(const struct regmap_config *config)
{
/* All register are 8-bits wide as per MIPI Soundwire 1.0 Spec */
if (config->val_bits != 8)
return -ENOTSUPP;

/* Registers are 32 bits wide */
if (config->reg_bits != 32)
return -ENOTSUPP;

if (config->pad_bits != 0)
return -ENOTSUPP;

return 0;
}

struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
int ret;

ret = regmap_sdw_config_check(config);
if (ret)
return ERR_PTR(ret);

return __regmap_init(&sdw->dev, &regmap_sdw,
&sdw->dev, config, lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__regmap_init_sdw);

struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
int ret;

ret = regmap_sdw_config_check(config);
if (ret)
return ERR_PTR(ret);

return __devm_regmap_init(&sdw->dev, &regmap_sdw,
&sdw->dev, config, lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw);

MODULE_DESCRIPTION("Regmap SoundWire Module");
MODULE_LICENSE("GPL v2");
47 changes: 31 additions & 16 deletions drivers/base/regmap/regmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ static unsigned int regmap_parse_64_native(const void *buf)
}
#endif

#ifdef REGMAP_HWSPINLOCK
static void regmap_lock_hwlock(void *__map)
{
struct regmap *map = __map;
Expand Down Expand Up @@ -457,7 +456,11 @@ static void regmap_unlock_hwlock_irqrestore(void *__map)

hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);
}
#endif

static void regmap_lock_unlock_none(void *__map)
{

}

static void regmap_lock_mutex(void *__map)
{
Expand Down Expand Up @@ -669,16 +672,26 @@ struct regmap *__regmap_init(struct device *dev,
goto err;
}

if (config->lock && config->unlock) {
if (config->name) {
map->name = kstrdup_const(config->name, GFP_KERNEL);
if (!map->name) {
ret = -ENOMEM;
goto err_map;
}
}

if (config->disable_locking) {
map->lock = map->unlock = regmap_lock_unlock_none;
regmap_debugfs_disable(map);
} else if (config->lock && config->unlock) {
map->lock = config->lock;
map->unlock = config->unlock;
map->lock_arg = config->lock_arg;
} else if (config->hwlock_id) {
#ifdef REGMAP_HWSPINLOCK
} else if (config->use_hwlock) {
map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
if (!map->hwlock) {
ret = -ENXIO;
goto err_map;
goto err_name;
}

switch (config->hwlock_mode) {
Expand All @@ -697,10 +710,6 @@ struct regmap *__regmap_init(struct device *dev,
}

map->lock_arg = map;
#else
ret = -EINVAL;
goto err_map;
#endif
} else {
if ((bus && bus->fast_io) ||
config->fast_io) {
Expand Down Expand Up @@ -762,14 +771,15 @@ struct regmap *__regmap_init(struct device *dev,
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
map->cache_type = config->cache_type;
map->name = config->name;

spin_lock_init(&map->async_lock);
INIT_LIST_HEAD(&map->async_list);
INIT_LIST_HEAD(&map->async_free);
init_waitqueue_head(&map->async_waitq);

if (config->read_flag_mask || config->write_flag_mask) {
if (config->read_flag_mask ||
config->write_flag_mask ||
config->zero_flag_mask) {
map->read_flag_mask = config->read_flag_mask;
map->write_flag_mask = config->write_flag_mask;
} else if (bus) {
Expand Down Expand Up @@ -1116,8 +1126,10 @@ struct regmap *__regmap_init(struct device *dev,
regmap_range_exit(map);
kfree(map->work_buf);
err_hwlock:
if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock)
if (map->hwlock)
hwspin_lock_free(map->hwlock);
err_name:
kfree_const(map->name);
err_map:
kfree(map);
err:
Expand Down Expand Up @@ -1305,8 +1317,9 @@ void regmap_exit(struct regmap *map)
kfree(async->work_buf);
kfree(async);
}
if (IS_ENABLED(REGMAP_HWSPINLOCK) && map->hwlock)
if (map->hwlock)
hwspin_lock_free(map->hwlock);
kfree_const(map->name);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
Expand Down Expand Up @@ -2423,13 +2436,15 @@ static int _regmap_bus_read(void *context, unsigned int reg,
{
int ret;
struct regmap *map = context;
void *work_val = map->work_buf + map->format.reg_bytes +
map->format.pad_bytes;

if (!map->format.parse_val)
return -EINVAL;

ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes);
if (ret == 0)
*val = map->format.parse_val(map->work_buf);
*val = map->format.parse_val(work_val);

return ret;
}
Expand Down
19 changes: 19 additions & 0 deletions drivers/mfd/syscon.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

#include <linux/err.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/list.h>
Expand Down Expand Up @@ -87,6 +88,24 @@ static struct syscon *of_syscon_register(struct device_node *np)
if (ret)
reg_io_width = 4;

ret = of_hwspin_lock_get_id(np, 0);
if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0)) {
syscon_config.use_hwlock = true;
syscon_config.hwlock_id = ret;
syscon_config.hwlock_mode = HWLOCK_IRQSTATE;
} else if (ret < 0) {
switch (ret) {
case -ENOENT:
/* Ignore missing hwlock, it's optional. */
break;
default:
pr_err("Failed to retrieve valid hwlock: %d\n", ret);
/* fall-through */
case -EPROBE_DEFER:
goto err_regmap;
}
}

syscon_config.reg_stride = reg_io_width;
syscon_config.val_bits = reg_io_width * 8;
syscon_config.max_register = resource_size(&res) - reg_io_width;
Expand Down
Loading

0 comments on commit b5856f9

Please sign in to comment.