diff options
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r-- | drivers/base/regmap/Kconfig | 6 | ||||
-rw-r--r-- | drivers/base/regmap/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 8 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-flat.c | 15 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 12 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-sdw.c | 88 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 47 |
7 files changed, 153 insertions, 24 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 3a1535d812d8..067073e4beb1 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -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 @@ -39,5 +38,6 @@ config REGMAP_MMIO config REGMAP_IRQ bool -config REGMAP_HWSPINLOCK - bool +config REGMAP_SOUNDWIRE + tristate + depends on SOUNDWIRE_BUS diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 0d298c446108..22d263cca395 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -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 diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 8641183cac2f..53785e0e297a 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -77,6 +77,7 @@ struct regmap { int async_ret; #ifdef CONFIG_DEBUG_FS + bool debugfs_disable; struct dentry *debugfs; const char *debugfs_name; @@ -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 */ diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c index 4d2e50bfc726..bc6cd88b8cc6 100644 --- a/drivers/base/regmap/regcache-flat.c +++ b/drivers/base/regmap/regcache-flat.c @@ -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; } @@ -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; } @@ -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; } diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 36ce3511c733..f3266334063e 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -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; diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c new file mode 100644 index 000000000000..50a66382d87d --- /dev/null +++ b/drivers/base/regmap/regmap-sdw.c @@ -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, ®map_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, ®map_sdw, + &sdw->dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw); + +MODULE_DESCRIPTION("Regmap SoundWire Module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 8d516a9bfc01..ee302ccdfbc8 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -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; @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -1116,8 +1126,10 @@ err_range: 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: @@ -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); @@ -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; } |