[alsa-devel] [PATCH 0/4] ASoC: AC'97 regmap support and conversion
This series contains the final pieces for the AC'97 conversion to regmap. The first patch adds a regmap backend for AC'97 devices that will use the AC'97 bus of the device to perform reads and writes. The second patch adds a bit of plumbing to the ASoC framework that it makes it possible to assign a regmap instance to ASoC CODEC (or component) after it has been registered. This is necessary since for AC'97 drivers we allocate the AC'97 device in the CODEC drivers probe callback. For now the series only converts the ad1980 driver, others might follow later.
- Lars
Lars-Peter Clausen (3): ASoC: Add helper functions for deferred regmap setup ASoC: ad1980: Convert to regmap ASoC: ad1980: Remove ac97_read/ac97_write wrappers
Mark Brown (1): regmap: ac97: Add generic AC'97 callbacks
drivers/base/regmap/Kconfig | 5 +- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-ac97.c | 114 +++++++++++++++++++++++++ include/linux/regmap.h | 7 ++ include/sound/soc.h | 35 ++++++++ sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/ad1980.c | 173 +++++++++++++++++++++----------------- sound/soc/soc-core.c | 58 ++++++++++--- 8 files changed, 306 insertions(+), 88 deletions(-) create mode 100644 drivers/base/regmap/regmap-ac97.c
From: Mark Brown broonie@linaro.org
Use the recently added support for bus operations to provide a standard mapping for AC'97 register I/O.
Signed-off-by: Mark Brown broonie@linaro.org --- Changes from the original version: * Add ac97_regmap_bus and made regmap_ac97_reg_{write,read} static * Use ac97->bus->ops instead of passing the ops separately --- drivers/base/regmap/Kconfig | 5 +- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-ac97.c | 114 ++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 7 +++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-ac97.c
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 8a3f51f..db9d00c3 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -3,12 +3,15 @@ # subsystems should select the appropriate symbols.
config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) select LZO_COMPRESS select LZO_DECOMPRESS select IRQ_DOMAIN if REGMAP_IRQ bool
+config REGMAP_AC97 + tristate + config REGMAP_I2C tristate depends on I2C diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index a7c670b..0a53365 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_REGMAP) += regmap.o regcache.o obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o +obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c new file mode 100644 index 0000000..e4c45d2 --- /dev/null +++ b/drivers/base/regmap/regmap-ac97.c @@ -0,0 +1,114 @@ +/* + * Register map access API - AC'97 support + * + * Copyright 2013 Linaro Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include <sound/ac97_codec.h> + +bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_RESET: + case AC97_POWERDOWN: + case AC97_INT_PAGING: + case AC97_EXTENDED_ID: + case AC97_EXTENDED_STATUS: + case AC97_EXTENDED_MID: + case AC97_EXTENDED_MSTATUS: + case AC97_GPIO_STATUS: + case AC97_MISC_AFE: + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + case AC97_CODEC_CLASS_REV: + case AC97_PCI_SVID: + case AC97_PCI_SID: + case AC97_FUNC_SELECT: + case AC97_FUNC_INFO: + case AC97_SENSE_INFO: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile); + +static int regmap_ac97_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct snd_ac97 *ac97 = context; + + *val = ac97->bus->ops->read(ac97, reg); + + return 0; +} + +static int regmap_ac97_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct snd_ac97 *ac97 = context; + + ac97->bus->ops->write(ac97, reg, val); + + return 0; +} + +static const struct regmap_bus ac97_regmap_bus = { + .reg_write = regmap_ac97_reg_write, + .reg_read = regmap_ac97_reg_read, +}; + +/** + * regmap_init_ac97(): Initialise AC'97 register map + * + * @ac97: 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. + */ +struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config) +{ + return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); +} +EXPORT_SYMBOL_GPL(regmap_init_ac97); + +/** + * devm_regmap_init_ac97(): Initialise AC'97 register map + * + * @ac97: 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. + */ +struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config) +{ + return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); +} +EXPORT_SYMBOL_GPL(devm_regmap_init_ac97); + +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index c5ed83f..4419b99 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -27,6 +27,7 @@ struct spmi_device; struct regmap; struct regmap_range_cfg; struct regmap_field; +struct snd_ac97;
/* An enum of all the supported cache types */ enum regcache_type { @@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, void __iomem *regs, const struct regmap_config *config); +struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev, const struct regmap_bus *bus, @@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, void __iomem *regs, const struct regmap_config *config); +struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config); + +bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
/** * regmap_init_mmio(): Initialise register map
On 11/18/2014 07:45 PM, Lars-Peter Clausen wrote:
From: Mark Brown broonie@linaro.org
Use the recently added support for bus operations to provide a standard mapping for AC'97 register I/O.
Signed-off-by: Mark Brown broonie@linaro.org
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
Sorry for that.
Changes from the original version:
- Add ac97_regmap_bus and made regmap_ac97_reg_{write,read} static
- Use ac97->bus->ops instead of passing the ops separately
drivers/base/regmap/Kconfig | 5 +- drivers/base/regmap/Makefile | 1 + drivers/base/regmap/regmap-ac97.c | 114 ++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 7 +++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 drivers/base/regmap/regmap-ac97.c
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 8a3f51f..db9d00c3 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -3,12 +3,15 @@ # subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) select LZO_COMPRESS select LZO_DECOMPRESS select IRQ_DOMAIN if REGMAP_IRQ bool
+config REGMAP_AC97
- tristate
- config REGMAP_I2C tristate depends on I2C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index a7c670b..0a53365 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_REGMAP) += regmap.o regcache.o obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o +obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c new file mode 100644 index 0000000..e4c45d2 --- /dev/null +++ b/drivers/base/regmap/regmap-ac97.c @@ -0,0 +1,114 @@ +/*
- Register map access API - AC'97 support
- Copyright 2013 Linaro Ltd. All rights reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
- */
+#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/slab.h>
+#include <sound/ac97_codec.h>
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg) +{
- switch (reg) {
- case AC97_RESET:
- case AC97_POWERDOWN:
- case AC97_INT_PAGING:
- case AC97_EXTENDED_ID:
- case AC97_EXTENDED_STATUS:
- case AC97_EXTENDED_MID:
- case AC97_EXTENDED_MSTATUS:
- case AC97_GPIO_STATUS:
- case AC97_MISC_AFE:
- case AC97_VENDOR_ID1:
- case AC97_VENDOR_ID2:
- case AC97_CODEC_CLASS_REV:
- case AC97_PCI_SVID:
- case AC97_PCI_SID:
- case AC97_FUNC_SELECT:
- case AC97_FUNC_INFO:
- case AC97_SENSE_INFO:
return true;
- default:
return false;
- }
+} +EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
+static int regmap_ac97_reg_read(void *context, unsigned int reg,
- unsigned int *val)
+{
- struct snd_ac97 *ac97 = context;
- *val = ac97->bus->ops->read(ac97, reg);
- return 0;
+}
+static int regmap_ac97_reg_write(void *context, unsigned int reg,
- unsigned int val)
+{
- struct snd_ac97 *ac97 = context;
- ac97->bus->ops->write(ac97, reg, val);
- return 0;
+}
+static const struct regmap_bus ac97_regmap_bus = {
.reg_write = regmap_ac97_reg_write,
.reg_read = regmap_ac97_reg_read,
+};
+/**
- regmap_init_ac97(): Initialise AC'97 register map
- @ac97: 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.
- */
+struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
+{
- return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+} +EXPORT_SYMBOL_GPL(regmap_init_ac97);
+/**
- devm_regmap_init_ac97(): Initialise AC'97 register map
- @ac97: 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.
- */
+struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
+{
- return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+} +EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
+MODULE_LICENSE("GPL v2"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index c5ed83f..4419b99 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -27,6 +27,7 @@ struct spmi_device; struct regmap; struct regmap_range_cfg; struct regmap_field; +struct snd_ac97;
/* An enum of all the supported cache types */ enum regcache_type { @@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, void __iomem *regs, const struct regmap_config *config); +struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev, const struct regmap_bus *bus,
@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, void __iomem *regs, const struct regmap_config *config); +struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
/**
- regmap_init_mmio(): Initialise register map
On Tue, Nov 18, 2014 at 07:45:51PM +0100, Lars-Peter Clausen wrote:
From: Mark Brown broonie@linaro.org
Use the recently added support for bus operations to provide a standard mapping for AC'97 register I/O.
Applied, thanks.
Some drivers (most notably the AC'97 drivers) do not have access to their regmap struct when the component/codec is registered. For those drivers the automatic regmap setup will not work and needs to be done manually, typically from the component/CODEC drivers probe callback.
This patch adds a set of helper function to handle deferred regmap initialization as well as early regmap tear-down.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc.h | 35 +++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 58 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 82 insertions(+), 11 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 86b2c77..879e2b3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1283,6 +1283,41 @@ void snd_soc_component_async_complete(struct snd_soc_component *component); int snd_soc_component_test_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int value);
+void snd_soc_component_init_regmap(struct snd_soc_component *component, + struct regmap *regmap); +void snd_soc_component_exit_regmap(struct snd_soc_component *component); + +/** + * snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC + * @codec: The CODEC for which to initialize the regmap instance + * @regmap: The regmap instance that should be used by the CODEC + * + * This function allows deferred assignment of the regmap instance that is + * associated with the CODEC. Only use this if the regmap instance is not yet + * ready when the CODEC is registered. The function must also be called before + * the first IO attempt of the CODEC. + */ +static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec, + struct regmap *regmap) +{ + snd_soc_component_init_regmap(&codec->component, regmap); +} + +/** + * snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC + * @codec: The CODEC for which to de-initialize the regmap instance + * + * Calls regmap_exit() on the regmap instance associated to the CODEC and + * removes the regmap instance from the CODEC. + * + * This function should only be used if snd_soc_codec_init_regmap() was used to + * initialize the regmap instance. + */ +static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec) +{ + snd_soc_component_exit_regmap(&codec->component); +} + /* device driver data */
static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 649dd8b..cc52ea1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2603,22 +2603,58 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, return 0; }
-static void snd_soc_component_init_regmap(struct snd_soc_component *component) +static void snd_soc_component_setup_regmap(struct snd_soc_component *component) { - if (!component->regmap) - component->regmap = dev_get_regmap(component->dev, NULL); - if (component->regmap) { - int val_bytes = regmap_get_val_bytes(component->regmap); - /* Errors are legitimate for non-integer byte multiples */ - if (val_bytes > 0) - component->val_bytes = val_bytes; - } + int val_bytes = regmap_get_val_bytes(component->regmap); + + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; +} + +/** + * snd_soc_component_init_regmap() - Initialize regmap instance for the component + * @component: The component for which to initialize the regmap instance + * @regmap: The regmap instance that should be used by the component + * + * This function allows deferred assignment of the regmap instance that is + * associated with the component. Only use this if the regmap instance is not + * yet ready when the component is registered. The function must also be called + * before the first IO attempt of the component. + */ +void snd_soc_component_init_regmap(struct snd_soc_component *component, + struct regmap *regmap) +{ + component->regmap = regmap; + snd_soc_component_setup_regmap(component); } +EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); + +/** + * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component + * @component: The component for which to de-initialize the regmap instance + * + * Calls regmap_exit() on the regmap instance associated to the component and + * removes the regmap instance from the component. + * + * This function should only be used if snd_soc_component_init_regmap() was used + * to initialize the regmap instance. + */ +void snd_soc_component_exit_regmap(struct snd_soc_component *component) +{ + regmap_exit(component->regmap); + component->regmap = NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { - if (!component->write && !component->read) - snd_soc_component_init_regmap(component); + if (!component->write && !component->read) { + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) + snd_soc_component_setup_regmap(component); + }
list_add(&component->list, &component_list); }
On Tue, Nov 18, 2014 at 07:45:52PM +0100, Lars-Peter Clausen wrote:
Some drivers (most notably the AC'97 drivers) do not have access to their regmap struct when the component/codec is registered. For those drivers the automatic regmap setup will not work and needs to be done manually, typically from the component/CODEC drivers probe callback.
Applied, thanks.
This patch converts the ad1980 driver to use regmap for its IO.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/ad1980.c | 141 ++++++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 54 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 072b784..883c577 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -226,6 +226,7 @@ config SND_SOC_AD193X_I2C select SND_SOC_AD193X
config SND_SOC_AD1980 + select REGMAP_AC97 tristate
config SND_SOC_AD73311 diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 93bd47d..5fd4a29 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -24,32 +24,86 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> #include <sound/initval.h> #include <sound/soc.h>
-/* - * AD1980 register cache - */ -static const u16 ad1980_reg[] = { - 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ - 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ - 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ - 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ - 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ - 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ - 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ +static const struct reg_default ad1980_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x0c, 0x8008 }, + { 0x0e, 0x8008 }, + { 0x10, 0x8808 }, + { 0x12, 0x8808 }, + { 0x16, 0x8808 }, + { 0x18, 0x8808 }, + { 0x1a, 0x0000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x28, 0x03c7 }, + { 0x2c, 0xbb80 }, + { 0x2e, 0xbb80 }, + { 0x30, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x36, 0x8080 }, + { 0x38, 0x8080 }, + { 0x3a, 0x2000 }, + { 0x60, 0x0000 }, + { 0x62, 0x0000 }, + { 0x72, 0x0000 }, + { 0x74, 0x1001 }, + { 0x76, 0x0000 }, +}; + +static bool ad1980_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_RESET ... AC97_MASTER_MONO: + case AC97_PHONE ... AC97_CD: + case AC97_AUX ... AC97_GENERAL_PURPOSE: + case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE: + case AC97_SPDIF: + case AC97_CODEC_CLASS_REV: + case AC97_PCI_SVID: + case AC97_AD_CODEC_CFG: + case AC97_AD_JACK_SPDIF: + case AC97_AD_SERIAL_CFG: + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool ad1980_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return false; + default: + return ad1980_readable_reg(dev, reg); + } +} + +static const struct regmap_config ad1980_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = regmap_ac97_default_volatile, + .readable_reg = ad1980_readable_reg, + .writeable_reg = ad1980_writeable_reg, + + .reg_defaults = ad1980_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults), };
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", @@ -135,39 +189,13 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - switch (reg) { - case AC97_RESET: - case AC97_INT_PAGING: - case AC97_POWERDOWN: - case AC97_EXTENDED_STATUS: - case AC97_VENDOR_ID1: - case AC97_VENDOR_ID2: - return soc_ac97_ops->read(ac97, reg); - default: - reg = reg >> 1; - - if (reg >= ARRAY_SIZE(ad1980_reg)) - return -EINVAL; - - return cache[reg]; - } + return snd_soc_read(codec, reg); }
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - soc_ac97_ops->write(ac97, reg, val); - reg = reg >> 1; - if (reg < ARRAY_SIZE(ad1980_reg)) - cache[reg] = val; - - return 0; + return snd_soc_write(codec, reg, val); }
static struct snd_soc_dai_driver ad1980_dai = { @@ -219,6 +247,7 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) static int ad1980_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; + struct regmap *regmap; int ret; u16 vendor_id2; u16 ext_status; @@ -230,6 +259,13 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) return ret; }
+ regmap = regmap_init_ac97(ac97, &ad1980_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97; + } + + snd_soc_codec_init_regmap(codec, regmap); snd_soc_codec_set_drvdata(codec, ac97);
ret = ad1980_reset(codec, 0); @@ -268,6 +304,8 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) return 0;
reset_err: + snd_soc_codec_exit_regmap(codec); +err_free_ac97: snd_soc_free_ac97_codec(ac97); return ret; } @@ -276,6 +314,7 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+ snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(ac97); return 0; } @@ -283,12 +322,6 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .probe = ad1980_soc_probe, .remove = ad1980_soc_remove, - .reg_cache_size = ARRAY_SIZE(ad1980_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = ad1980_reg, - .reg_cache_step = 2, - .write = ac97_write, - .read = ac97_read,
.controls = ad1980_snd_ac97_controls, .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/ad1980.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-)
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 5fd4a29..2860eef 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -186,18 +186,6 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { { "HP_OUT_R", NULL, "Playback" }, };
-static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return snd_soc_read(codec, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - static struct snd_soc_dai_driver ad1980_dai = { .name = "ad1980-hifi", .playback = { @@ -222,7 +210,7 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) do { if (try_warm && soc_ac97_ops->warm_reset) { soc_ac97_ops->warm_reset(ac97); - if (ac97_read(codec, AC97_RESET) == 0x0090) + if (snd_soc_read(codec, AC97_RESET) == 0x0090) return 1; }
@@ -233,9 +221,9 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) * case the first nibble of data is eaten by the addr. (Tag is * always 16 bit) */ - ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); + snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
- if (ac97_read(codec, AC97_RESET) == 0x0090) + if (snd_soc_read(codec, AC97_RESET) == 0x0090) return 0; } while (retry_cnt++ < 10);
@@ -273,12 +261,12 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) goto reset_err;
/* Read out vendor ID to make sure it is ad1980 */ - if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { + if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { ret = -ENODEV; goto reset_err; }
- vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); + vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) { @@ -291,15 +279,15 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) }
/* unmute captures and playbacks volume */ - ac97_write(codec, AC97_MASTER, 0x0000); - ac97_write(codec, AC97_PCM, 0x0000); - ac97_write(codec, AC97_REC_GAIN, 0x0000); - ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); - ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); + snd_soc_write(codec, AC97_MASTER, 0x0000); + snd_soc_write(codec, AC97_PCM, 0x0000); + snd_soc_write(codec, AC97_REC_GAIN, 0x0000); + snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); + snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
/*power on LFE/CENTER/Surround DACs*/ - ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); + ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS); + snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
return 0;
On Tue, Nov 18, 2014 at 07:45:54PM +0100, Lars-Peter Clausen wrote:
Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers.
Applied, thanks.
participants (2)
-
Lars-Peter Clausen
-
Mark Brown