From 7c22ce6e218403fc8746f7915b5a391d8227f7e1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 8 Jan 2018 15:50:59 +0530 Subject: [PATCH 1/2] regmap: Add SoundWire bus support SoundWire bus provides sdw_read() and sdw_write() APIs for Slave devices to program the registers. Provide support in regmap for SoundWire bus. Signed-off-by: Hardik T Shah Signed-off-by: Sanyog Kale Reviewed-by: Philippe Ombredanne Acked-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- drivers/base/regmap/Kconfig | 4 ++ drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-sdw.c | 88 ++++++++++++++++++++++++++++++++ include/linux/regmap.h | 37 ++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 drivers/base/regmap/regmap-sdw.c diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 0368fd7b3a414..067073e4beb1c 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -37,3 +37,7 @@ config REGMAP_MMIO config REGMAP_IRQ bool + +config REGMAP_SOUNDWIRE + tristate + depends on SOUNDWIRE_BUS diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 0d298c446108e..22d263cca3952 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/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c new file mode 100644 index 0000000000000..50a66382d87d0 --- /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 +#include +#include +#include +#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/include/linux/regmap.h b/include/linux/regmap.h index c78e0057df664..eab9c0a29837e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -30,6 +30,7 @@ struct regmap; struct regmap_range_cfg; struct regmap_field; struct snd_ac97; +struct sdw_slave; /* An enum of all the supported cache types */ enum regcache_type { @@ -526,6 +527,10 @@ struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +struct regmap *__regmap_init_sdw(struct sdw_slave *sdw, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); struct regmap *__devm_regmap_init(struct device *dev, const struct regmap_bus *bus, @@ -563,6 +568,10 @@ struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name); +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); /* * Wrapper for regmap_init macros to include a unique lockdep key and name @@ -711,6 +720,20 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, ac97, config) bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); +/** + * regmap_init_sdw() - Initialise register map + * + * @sdw: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer to + * a struct regmap. + */ +#define regmap_init_sdw(sdw, config) \ + __regmap_lockdep_wrapper(__regmap_init_sdw, #config, \ + sdw, config) + + /** * devm_regmap_init() - Initialise managed register map * @@ -841,6 +864,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); __regmap_lockdep_wrapper(__devm_regmap_init_ac97, #config, \ ac97, config) +/** + * devm_regmap_init_sdw() - Initialise managed register map + * + * @sdw: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap. The regmap will be automatically freed by the + * device management code. + */ +#define devm_regmap_init_sdw(sdw, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_sdw, #config, \ + sdw, config) + void regmap_exit(struct regmap *map); int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config); From 9bf485c955bcb707a5e679bcc74075deb0bc8531 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Sun, 7 Jan 2018 17:19:09 -0600 Subject: [PATCH 2/2] regmap: Allow empty read/write_flag_mask All zero read and write masks in the regmap config are used to signal no special mask is needed and the bus defaults are used. In some devices all zero read/write masks are the special mask and bus defaults should not be used. To signal this a new variable is added. For example SPI often sets bit 7 in address to signal to the device a read is requested. On TI AFE44xx parts with SPI interfaces no bit needs to be set as registers are either read or write only and the operation can be determined from the address only. For this case both masks must be zero to not effect the address. Signed-off-by: Andrew F. Davis Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 4 +++- include/linux/regmap.h | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 8d516a9bfc017..025c62358bd67 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -769,7 +769,9 @@ struct regmap *__regmap_init(struct device *dev, 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) { diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 15eddc1353bae..f8bff272c4298 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -296,7 +296,10 @@ typedef void (*regmap_unlock)(void *); * a read. * @write_flag_mask: Mask to be set in the top bytes of the register when doing * a write. If both read_flag_mask and write_flag_mask are - * empty the regmap_bus default masks are used. + * empty and zero_flag_mask is not set the regmap_bus default + * masks are used. + * @zero_flag_mask: If set, read_flag_mask and write_flag_mask are used even + * if they are both empty. * @use_single_rw: If set, converts the bulk read and write operations into * a series of single read and write operations. This is useful * for device that does not support bulk read and write. @@ -355,6 +358,7 @@ struct regmap_config { unsigned long read_flag_mask; unsigned long write_flag_mask; + bool zero_flag_mask; bool use_single_rw; bool can_multi_write;