From 0f68c396f6048cf87c662aab1ef9c9aa237153a8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 10:36:12 +0300 Subject: [PATCH 001/461] ASoC: cs4341: Add driver for CS4341 DAC This patch adds Cirrus Logic CS4341. This is a very simple, playback only, stereo DAC. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs4341.c | 346 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 sound/soc/codecs/cs4341.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 62bdb7e333b8..3f742753abd1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -65,6 +65,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CS43130 if I2C + select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI select SND_SOC_CS4349 if I2C select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CS53L30 if I2C @@ -542,6 +543,12 @@ config SND_SOC_CS43130 tristate "Cirrus Logic CS43130 CODEC" depends on I2C +config SND_SOC_CS4341 + tristate "Cirrus Logic CS4341 CODEC" + depends on I2C || SPI_MASTER + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + # Cirrus Logic CS4349 HiFi DAC config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 66f55d185620..fbe36e6177b0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -60,6 +60,7 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs43130-objs := cs43130.o +snd-soc-cs4341-objs := cs4341.o snd-soc-cs4349-objs := cs4349.o snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs53l30-objs := cs53l30.o @@ -326,6 +327,7 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o +obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c new file mode 100644 index 000000000000..d2e616a89fd4 --- /dev/null +++ b/sound/soc/codecs/cs4341.c @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Cirrus Logic CS4341A ALSA SoC Codec Driver + * Author: Alexander Shiyan + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CS4341_REG_MODE1 0x00 +#define CS4341_REG_MODE2 0x01 +#define CS4341_REG_MIX 0x02 +#define CS4341_REG_VOLA 0x03 +#define CS4341_REG_VOLB 0x04 + +#define CS4341_MODE2_DIF (7 << 4) +#define CS4341_MODE2_DIF_I2S_24 (0 << 4) +#define CS4341_MODE2_DIF_I2S_16 (1 << 4) +#define CS4341_MODE2_DIF_LJ_24 (2 << 4) +#define CS4341_MODE2_DIF_RJ_24 (3 << 4) +#define CS4341_MODE2_DIF_RJ_16 (5 << 4) +#define CS4341_VOLX_MUTE (1 << 7) + +struct cs4341_priv { + unsigned int fmt; + struct regmap *regmap; + struct regmap_config regcfg; +}; + +static const struct reg_default cs4341_reg_defaults[] = { + { CS4341_REG_MODE1, 0x00 }, + { CS4341_REG_MODE2, 0x82 }, + { CS4341_REG_MIX, 0x49 }, + { CS4341_REG_VOLA, 0x80 }, + { CS4341_REG_VOLB, 0x80 }, +}; + +static int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format) +{ + struct snd_soc_component *component = dai->component; + struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); + + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + cs4341->fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs4341_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); + unsigned int mode = 0; + int b24 = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S24_LE: + b24 = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + break; + default: + dev_err(component->dev, "Unsupported PCM format 0x%08x.\n", + params_format(params)); + return -EINVAL; + } + + switch (cs4341->fmt) { + case SND_SOC_DAIFMT_I2S: + mode = b24 ? CS4341_MODE2_DIF_I2S_24 : CS4341_MODE2_DIF_I2S_16; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode = CS4341_MODE2_DIF_LJ_24; + break; + case SND_SOC_DAIFMT_RIGHT_J: + mode = b24 ? CS4341_MODE2_DIF_RJ_24 : CS4341_MODE2_DIF_RJ_16; + break; + default: + dev_err(component->dev, "Unsupported DAI format 0x%08x.\n", + cs4341->fmt); + return -EINVAL; + } + + return snd_soc_component_update_bits(component, CS4341_REG_MODE2, + CS4341_MODE2_DIF, mode); +} + +static int cs4341_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + int ret; + + ret = snd_soc_component_update_bits(component, CS4341_REG_VOLA, + CS4341_VOLX_MUTE, + mute ? CS4341_VOLX_MUTE : 0); + if (ret < 0) + return ret; + + return snd_soc_component_update_bits(component, CS4341_REG_VOLB, + CS4341_VOLX_MUTE, + mute ? CS4341_VOLX_MUTE : 0); +} + +static DECLARE_TLV_DB_SCALE(out_tlv, -9000, 100, 0); + +static const char * const deemph[] = { + "None", "44.1k", "48k", "32k", +}; + +static const struct soc_enum deemph_enum = + SOC_ENUM_SINGLE(CS4341_REG_MODE2, 2, 4, deemph); + +static const char * const srzc[] = { + "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", +}; + +static const struct soc_enum srzc_enum = + SOC_ENUM_SINGLE(CS4341_REG_MIX, 5, 4, srzc); + + +static const struct snd_soc_dapm_widget cs4341_dapm_widgets[] = { + SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OutA"), + SND_SOC_DAPM_OUTPUT("OutB"), +}; + +static const struct snd_soc_dapm_route cs4341_routes[] = { + { "OutA", NULL, "HiFi DAC" }, + { "OutB", NULL, "HiFi DAC" }, + { "DAC Playback", NULL, "OutA" }, + { "DAC Playback", NULL, "OutB" }, +}; + +static const struct snd_kcontrol_new cs4341_controls[] = { + SOC_DOUBLE_R_TLV("Master Playback Volume", + CS4341_REG_VOLA, CS4341_REG_VOLB, 0, 90, 1, out_tlv), + SOC_ENUM("De-Emphasis Control", deemph_enum), + SOC_ENUM("Soft Ramp Zero Cross Control", srzc_enum), + SOC_SINGLE("Auto-Mute Switch", CS4341_REG_MODE2, 7, 1, 0), + SOC_SINGLE("Popguard Transient Switch", CS4341_REG_MODE2, 1, 1, 0), +}; + +static const struct snd_soc_dai_ops cs4341_dai_ops = { + .set_fmt = cs4341_set_fmt, + .hw_params = cs4341_hw_params, + .digital_mute = cs4341_digital_mute, +}; + +static struct snd_soc_dai_driver cs4341_dai = { + .name = "cs4341a-hifi", + .playback = { + .stream_name = "DAC Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &cs4341_dai_ops, + .symmetric_rates = 1, +}; + +static const struct snd_soc_component_driver soc_component_cs4341 = { + .controls = cs4341_controls, + .num_controls = ARRAY_SIZE(cs4341_controls), + .dapm_widgets = cs4341_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4341_dapm_widgets), + .dapm_routes = cs4341_routes, + .num_dapm_routes = ARRAY_SIZE(cs4341_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct of_device_id __maybe_unused cs4341_dt_ids[] = { + { .compatible = "cirrus,cs4341a", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4341_dt_ids); + +static int cs4341_probe(struct device *dev) +{ + struct cs4341_priv *cs4341 = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(cs4341_reg_defaults); i++) + regmap_write(cs4341->regmap, cs4341_reg_defaults[i].reg, + cs4341_reg_defaults[i].def); + + return devm_snd_soc_register_component(dev, &soc_component_cs4341, + &cs4341_dai, 1); +} + +#if defined(CONFIG_I2C) +static int cs4341_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct cs4341_priv *cs4341; + + cs4341 = devm_kzalloc(&i2c->dev, sizeof(*cs4341), GFP_KERNEL); + if (!cs4341) + return -ENOMEM; + + i2c_set_clientdata(i2c, cs4341); + + cs4341->regcfg.reg_bits = 8; + cs4341->regcfg.val_bits = 8; + cs4341->regcfg.max_register = CS4341_REG_VOLB; + cs4341->regcfg.cache_type = REGCACHE_FLAT; + cs4341->regcfg.reg_defaults = cs4341_reg_defaults; + cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); + cs4341->regmap = devm_regmap_init_i2c(i2c, &cs4341->regcfg); + if (IS_ERR(cs4341->regmap)) + return PTR_ERR(cs4341->regmap); + + return cs4341_probe(&i2c->dev); +} + +static const struct i2c_device_id cs4341_i2c_id[] = { + { "cs4341", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs4341_i2c_id); + +static struct i2c_driver cs4341_i2c_driver = { + .driver = { + .name = "cs4341-i2c", + .of_match_table = of_match_ptr(cs4341_dt_ids), + }, + .probe = cs4341_i2c_probe, + .id_table = cs4341_i2c_id, +}; +#endif + +#if defined(CONFIG_SPI_MASTER) +static bool cs4341_reg_readable(struct device *dev, unsigned int reg) +{ + return false; +} + +static int cs4341_spi_probe(struct spi_device *spi) +{ + struct cs4341_priv *cs4341; + int ret; + + cs4341 = devm_kzalloc(&spi->dev, sizeof(*cs4341), GFP_KERNEL); + if (!cs4341) + return -ENOMEM; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = 6000000; + ret = spi_setup(spi); + if (ret) + return ret; + + spi_set_drvdata(spi, cs4341); + + cs4341->regcfg.reg_bits = 16; + cs4341->regcfg.val_bits = 8; + cs4341->regcfg.write_flag_mask = 0x20; + cs4341->regcfg.max_register = CS4341_REG_VOLB; + cs4341->regcfg.cache_type = REGCACHE_FLAT; + cs4341->regcfg.readable_reg = cs4341_reg_readable; + cs4341->regcfg.reg_defaults = cs4341_reg_defaults; + cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); + cs4341->regmap = devm_regmap_init_spi(spi, &cs4341->regcfg); + if (IS_ERR(cs4341->regmap)) + return PTR_ERR(cs4341->regmap); + + return cs4341_probe(&spi->dev); +} + +static struct spi_driver cs4341_spi_driver = { + .driver = { + .name = "cs4341-spi", + .of_match_table = of_match_ptr(cs4341_dt_ids), + }, + .probe = cs4341_spi_probe, +}; +#endif + +static int __init cs4341_init(void) +{ + int ret = 0; + +#if defined(CONFIG_I2C) + ret = i2c_add_driver(&cs4341_i2c_driver); + if (ret) + return ret; +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&cs4341_spi_driver); +#endif + + return ret; +} +module_init(cs4341_init); + +static void __exit cs4341_exit(void) +{ +#if defined(CONFIG_I2C) + i2c_del_driver(&cs4341_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&cs4341_spi_driver); +#endif +} +module_exit(cs4341_exit); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("Cirrus Logic CS4341 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); From 0ddb46080a465fad99cff838682744f1f4848a4b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 10:37:08 +0300 Subject: [PATCH 002/461] ASoC: cs4341: Add DT bindings documentation for CS4341 DAC This patch adds DT bindings documentation for Cirrus Logic CS4341 DAC. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs4341.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs4341.txt diff --git a/Documentation/devicetree/bindings/sound/cs4341.txt b/Documentation/devicetree/bindings/sound/cs4341.txt new file mode 100644 index 000000000000..12b4aa8ef0db --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4341.txt @@ -0,0 +1,22 @@ +Cirrus Logic CS4341 audio DAC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + - compatible: "cirrus,cs4341a" + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +For required properties on I2C-bus, please consult +Documentation/devicetree/bindings/i2c/i2c.txt +For required properties on SPI-bus, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + codec: cs4341@0 { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4341a"; + reg = <0>; + spi-max-frequency = <6000000>; + }; From 2bb853f6f93775dc4dd4683a42f6934700d90d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Wed, 19 Dec 2018 21:11:15 +0100 Subject: [PATCH 003/461] ASoC: wm8904: make the driver visible in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For platforms that use the audio-graph-card driver, the codec is not selected by SoC-platform driver. Make it available. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3f742753abd1..d46de3e04ff6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1218,7 +1218,8 @@ config SND_SOC_WM8903 depends on I2C config SND_SOC_WM8904 - tristate + tristate "Wolfson Microelectronics WM8904 CODEC" + depends on I2C config SND_SOC_WM8940 tristate From fb82c6ed31902e651cc9324108f507babfabc890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Wed, 19 Dec 2018 21:11:16 +0100 Subject: [PATCH 004/461] ASoC: wm8904: save model id directly in of_device_id.data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save 2x unsigned int of .rodata. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 2a3e5fbd04e4..9283a2dc70aa 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2108,16 +2108,13 @@ static const struct regmap_config wm8904_regmap = { }; #ifdef CONFIG_OF -static enum wm8904_type wm8904_data = WM8904; -static enum wm8904_type wm8912_data = WM8912; - static const struct of_device_id wm8904_of_match[] = { { .compatible = "wlf,wm8904", - .data = &wm8904_data, + .data = (void *)WM8904, }, { .compatible = "wlf,wm8912", - .data = &wm8912_data, + .data = (void *)WM8912, }, { /* sentinel */ } @@ -2158,7 +2155,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, match = of_match_node(wm8904_of_match, i2c->dev.of_node); if (match == NULL) return -EINVAL; - wm8904->devtype = *((enum wm8904_type *)match->data); + wm8904->devtype = (enum wm8904_type)match->data; } else { wm8904->devtype = id->driver_data; } From 5489e81f981b1fb7c2fdaba332122fff3290e9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Wed, 19 Dec 2018 21:11:16 +0100 Subject: [PATCH 005/461] ASoC: wm8904: enable MCLK in STANDBY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCLK input is needed when accessing any register after enabling SYSCLK. This also fixes imbalance of clk_enable / clk_disable when transitioning between ON -> STANDBY -> ON bias levels. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9283a2dc70aa..9e0f96e0f8ec 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1837,9 +1837,6 @@ static int wm8904_set_bias_level(struct snd_soc_component *component, switch (level) { case SND_SOC_BIAS_ON: - ret = clk_prepare_enable(wm8904->mclk); - if (ret) - return ret; break; case SND_SOC_BIAS_PREPARE: @@ -1864,6 +1861,15 @@ static int wm8904_set_bias_level(struct snd_soc_component *component, return ret; } + ret = clk_prepare_enable(wm8904->mclk); + if (ret) { + dev_err(component->dev, + "Failed to enable MCLK: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + return ret; + } + regcache_cache_only(wm8904->regmap, false); regcache_sync(wm8904->regmap); From 431b67c27c57bc6a752482727c87f6dda988aae5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:02 -0600 Subject: [PATCH 006/461] ASoC: Intel: Skylake: remove useless cast Detected with Coccinelle sound/soc/intel/skylake/skl-topology.c:3106:16-20: WARNING: casting value returned by memory allocation function to (char *) is useless. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cf8848b779dc..389f1862bc43 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3103,7 +3103,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, ac->size = dfw_ac->max; if (ac->max) { - ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); if (!ac->params) return -ENOMEM; From d8747d30aa7f9e7dc6123709d7ca1d8429d648b0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:03 -0600 Subject: [PATCH 007/461] ASoC: Intel: Skylake: simplify boolean tests Detected with Coccinelle skl-messages.c:419:5-32: WARNING: Comparison to bool skl-pcm.c:1426:6-33: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index b0e6fb93eaf8..28c4806b196a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -416,7 +416,7 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot == true) + if (skl->skl_sst->is_first_boot) return 0; /* diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 557f80c0bfe5..8e589d698c58 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1423,7 +1423,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) if (!ops) return -EIO; - if (skl->skl_sst->is_first_boot == false) { + if (!skl->skl_sst->is_first_boot) { dev_err(component->dev, "DSP reports first boot done!!!\n"); return -EIO; } From 6c5414589721d696fe300dc0b8720e0368e3907a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:04 -0600 Subject: [PATCH 008/461] ASoC: Intel: Haswell: remove unneeded semicolon Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fe2c826e710c..fb9b8608eb3b 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -544,7 +544,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: invalid DAI ID %d\n", rtd->cpu_dai->id); return -EINVAL; - }; + } ret = sst_hsw_stream_format(hsw, pcm_data->stream, path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); From bf88b3c3c277c8138d688a0fc3199b57fecfaf56 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:05 -0600 Subject: [PATCH 009/461] ASoC: Intel: Haswell: assign booleans to true/false Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 2 +- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index d33bdaf92c57..31fcdf12c67d 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -1216,7 +1216,7 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) return ret; } - stream->commited = 1; + stream->commited = true; trace_hsw_stream_alloc_reply(stream); return 0; diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fb9b8608eb3b..2debcc2ed99a 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -861,7 +861,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } - pcm_data->allocated = 0; + pcm_data->allocated = false; pcm_data->stream = NULL; out: From 060d35be2dfa9202d37f967fd20f133c530505d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:06 -0600 Subject: [PATCH 010/461] ASoC: Intel: Baytrail: remove unneeded variable Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 260447da32b8..2cd8f9668b50 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -278,7 +278,6 @@ static int sst_byt_process_notification(struct sst_byt *byt, struct sst_byt_stream *stream; u64 header; u8 msg_id, stream_id; - int handled = 1; header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); msg_id = sst_byt_header_msg_id(header); @@ -298,7 +297,7 @@ static int sst_byt_process_notification(struct sst_byt *byt, break; } - return handled; + return 1; } static irqreturn_t sst_byt_irq_thread(int irq, void *context) From e295450dd86d974861e1e9e302d67b0a23457ea8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:07 -0600 Subject: [PATCH 011/461] ASoC: Intel: Baytrail: simplify boolean test Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index aabb35bf6b96..498fb5346f1a 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -188,7 +188,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: - if (pdata->restore_stream == true) + if (pdata->restore_stream) schedule_work(&pcm_data->work); else sst_byt_stream_resume(byt, pcm_data->stream); From 10583cdac237b32c0d3f6027b06c5eec8bf91211 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:08 -0600 Subject: [PATCH 012/461] ASoC: Intel: Atom: simplify boolean tests Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/atom/sst/sst_drv_interface.c | 2 +- sound/soc/intel/atom/sst/sst_loader.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 3672d36b4b66..d1207ea53523 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -647,7 +647,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, set_mixer = false; } - if (set_mixer == false) + if (!set_mixer) return 0; if (SND_SOC_DAPM_EVENT_ON(event) || diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index afc559866095..aefa5ce4cb59 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -190,7 +190,7 @@ int sst_fill_stream_params(void *substream, map = ctx->pdata->pdev_strm_map; map_size = ctx->pdata->strm_map_size; - if (is_compress == true) + if (is_compress) cstream = (struct snd_compr_stream *)substream; else pstream = (struct snd_pcm_substream *)substream; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ac542535b9d5..3a95ebbfc45d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -334,7 +334,7 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; ret = is_byt_cr(dev, &bytcr); - if (!((ret < 0) || (bytcr == false))) { + if (!(ret < 0 || !bytcr)) { dev_info(dev, "Detected Baytrail-CR platform\n"); /* override resource info */ diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 5455d6e0ab53..a592df06aa58 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -146,7 +146,7 @@ static int sst_power_control(struct device *dev, bool state) int ret = 0; int usage_count = 0; - if (state == true) { + if (state) { ret = pm_runtime_get_sync(dev); usage_count = GET_USAGE_COUNT(dev); dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index b8c456753f01..321c783cf833 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -269,7 +269,7 @@ static void sst_do_memcpy(struct list_head *memcpy_list) struct sst_memcpy_list *listnode; list_for_each_entry(listnode, memcpy_list, memcpylist) { - if (listnode->is_io == true) + if (listnode->is_io) memcpy32_toio((void __iomem *)listnode->dstn, listnode->src, listnode->size); else From 4e88068ed0888549acd1cbb2f6e271b007051203 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:10 -0600 Subject: [PATCH 013/461] ASoC: Intel: boards: use snd_mask_set_format in all machine drivers Fix Sparse warnings with two machine drivers which weren't updated Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c74c4f17316f..0739e3a75083 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -164,7 +164,7 @@ static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP to 24 bit */ snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 723a4935ed76..6dd5c69671b3 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -221,7 +221,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = 48000; channels->min = channels->max = 2; snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); } /* @@ -229,7 +229,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * thus changing the mask here */ if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } From a0c426fe143328760c9fd565cd203a37a7b4fde8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:42 +0900 Subject: [PATCH 014/461] ASoC: simple-card-utils: check "reg" property on asoc_simple_card_get_dai_id() We will get DAI ID from "reg" property if it has on DT, otherwise get it by counting port/endpoint. But in below case, we need to get DAI ID = 0 via port reg = <0>, but current implementation returns ID = 1, because it can't judge ID = 0 was from "non reg" or "reg = <0>". Thus, it will count port/endpoint number as "non reg" case. of_graph_parse_endpoint() implementation itself is not a problem, but because asoc_simple_card_get_dai_id() need to count port/endpoint number when "non reg" case, it need to know ID = 0 was from "non reg" or "reg = <0>". This patch fix this issue. port { reg = <0>; xxxx: endpoint@0 { }; => xxxx: endpoint@1 { }; }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b807a47515eb..336895f7fd1e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -283,12 +283,20 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) /* use endpoint/port reg if exist */ ret = of_graph_parse_endpoint(ep, &info); if (ret == 0) { - if (info.id) + /* + * Because it will count port/endpoint if it doesn't have "reg". + * But, we can't judge whether it has "no reg", or "reg = <0>" + * only of_graph_parse_endpoint(). + * We need to check "reg" property + */ + if (of_get_property(ep, "reg", NULL)) return info.id; - if (info.port) + + node = of_get_parent(ep); + of_node_put(node); + if (of_get_property(node, "reg", NULL)) return info.port; } - node = of_graph_get_port_parent(ep); /* From 40dfae169ad047535d566a4791daae3b08f71c0c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:48 +0900 Subject: [PATCH 015/461] ASoC: audio-graph-card: add asoc_graph_card_get_conversion() audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_graph_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0d6144560a1e..c3e80bc27e80 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -169,6 +169,22 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_graph_card_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *port = of_get_parent(ep); + struct device_node *ports = of_get_parent(port); + struct device_node *node = of_graph_get_port_parent(ep); + + asoc_simple_card_parse_convert(dev, top, NULL, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, ports, NULL, adata); + asoc_simple_card_parse_convert(dev, port, NULL, adata); + asoc_simple_card_parse_convert(dev, ep, NULL, adata); +} + static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -194,11 +210,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata); + asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); From e4f4fdfc57d9c846862ea6109e356b3a4542df5b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:27 +0900 Subject: [PATCH 016/461] ASoC: audio-graph-scu-card: remove audio-graph-scu-card on Doc It is already merged into audio-graph-card. audio-graph-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-scu-card.txt | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt deleted file mode 100644 index 62d42768a00b..000000000000 --- a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt +++ /dev/null @@ -1,123 +0,0 @@ -Audio-Graph-SCU-Card: - -Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM". - -It is based on common bindings for device graphs. -see ${LINUX}/Documentation/devicetree/bindings/graph.txt - -Basically, Audio-Graph-SCU-Card property is same as -Simple-Card / Simple-SCU-Card / Audio-Graph-Card. -see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt - ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt - ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt - -Below are same as Simple-Card / Audio-Graph-Card. - -- label -- dai-format -- frame-master -- bitclock-master -- bitclock-inversion -- frame-inversion -- dai-tdm-slot-num -- dai-tdm-slot-width -- clocks / system-clock-frequency - -Below are same as Simple-SCU-Card. - -- convert-rate -- convert-channels -- prefix -- routing - -Required properties: - -- compatible : "audio-graph-scu-card"; -- dais : list of CPU DAI port{s} - -Example 1. Sampling Rate Conversion - - sound_card { - compatible = "audio-graph-scu-card"; - - label = "sound-card"; - prefix = "codec"; - routing = "codec Playback", "DAI0 Playback", - "DAI0 Capture", "codec Capture"; - convert-rate = <48000>; - - dais = <&cpu_port>; - }; - - audio-codec { - ... - - port { - codec_endpoint: endpoint { - remote-endpoint = <&cpu_endpoint>; - }; - }; - }; - - dai-controller { - ... - cpu_port: port { - cpu_endpoint: endpoint { - remote-endpoint = <&codec_endpoint>; - - dai-format = "left_j"; - ... - }; - }; - }; - -Example 2. 2 CPU 1 Codec (Mixing) - - sound_card { - compatible = "audio-graph-scu-card"; - - label = "sound-card"; - routing = "codec Playback", "DAI0 Playback", - "codec Playback", "DAI1 Playback", - "DAI0 Capture", "codec Capture"; - - dais = <&cpu_port0 - &cpu_port1>; - }; - - audio-codec { - ... - - audio-graph-card,prefix = "codec"; - audio-graph-card,convert-rate = <48000>; - port { - codec_endpoint0: endpoint { - remote-endpoint = <&cpu_endpoint0>; - }; - codec_endpoint1: endpoint { - remote-endpoint = <&cpu_endpoint1>; - }; - }; - }; - - dai-controller { - ... - ports { - cpu_port0: port { - cpu_endpoint0: endpoint { - remote-endpoint = <&codec_endpoint0>; - - dai-format = "left_j"; - ... - }; - }; - cpu_port1: port { - cpu_endpoint1: endpoint { - remote-endpoint = <&codec_endpoint1>; - - dai-format = "left_j"; - ... - }; - }; - }; - }; From 61c263ac27a307cdf7f46aaee4810619103effad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:32 +0900 Subject: [PATCH 017/461] ASoC: audio-graph-scu-card: remove audio-graph-scu-card It is already merged into audio-graph-card. audio-graph-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 9 - sound/soc/generic/Makefile | 2 - sound/soc/generic/audio-graph-scu-card.c | 501 ----------------------- 3 files changed, 512 deletions(-) delete mode 100644 sound/soc/generic/audio-graph-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 92c2cf06f40a..59190f42fc08 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -24,12 +24,3 @@ config SND_AUDIO_GRAPH_CARD This option enables generic simple sound card support with OF-graph DT bindings. It also support DPCM of multi CPU single Codec ststem. - -config SND_AUDIO_GRAPH_SCU_CARD - tristate "ASoC Audio Graph SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support - with OF-graph DT bindings. - It supports DPCM of multi CPU single Codec ststem. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9dec293a4c4d..9fbfdd524b24 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -3,10 +3,8 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o -snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o -obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c deleted file mode 100644 index e1b192ea147b..000000000000 --- a/sound/soc/generic/audio-graph-scu-card.c +++ /dev/null @@ -1,501 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC audio graph SCU sound card support -// -// Copyright (C) 2017 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on -// ${LINUX}/sound/soc/generic/simple-scu-card.c -// ${LINUX}/sound/soc/generic/audio-graph-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct graph_card_data { - struct snd_soc_card snd_card; - struct graph_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define graph_priv_to_card(priv) (&(priv)->snd_card) -#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) -#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) - -#define PREFIX "audio-graph-card," - -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, -}; - -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep, - struct device_node *codec_ep, - struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe) -{ - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *ep = is_fe ? cpu_ep : codec_ep; - struct device_node *node = of_graph_get_port_parent(ep); - struct asoc_simple_dai *dai; - int ret; - - if (is_fe) { - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - /* card->num_links includes Codec */ - asoc_simple_card_canonicalize_cpu(dai_link, - of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_graph_codec(ep, dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(node, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - } - - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(ep, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; - - return 0; -} - -static int asoc_graph_card_parse_of(struct graph_card_data *priv) -{ - struct of_phandle_iterator it; - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - int dai_idx, link_idx, conf_idx, ret; - int rc, codec; - - if (!node) - return -EINVAL; - - /* - * we need to consider "widgets", "mclk-fs" around here - * see simple-card - */ - - ret = asoc_simple_card_of_parse_routing(card, NULL); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata); - - /* - * it supports multi CPU, single CODEC only here - * see asoc_graph_get_dais_count - */ - - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - codec_port_old = NULL; - for (codec = 0; codec < 2; codec++) { - /* - * To listup valid sounds continuously, - * detect all CPU-dummy first, and - * detect all dummy-Codec second - */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(cpu_port); - of_node_put(codec_port); - it.node = NULL; - - if (codec) { - if (codec_port_old == codec_port) - continue; - - codec_port_old = codec_port; - } - - ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep, - priv, &dai_idx, - link_idx++, &conf_idx, - !codec); - if (ret < 0) - goto parse_of_err; - } - } - - ret = asoc_simple_card_parse_card_name(card, NULL); - if (ret) - goto parse_of_err; - - if ((card->num_links != link_idx) || - (card->num_configs != conf_idx)) { - dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n", - card->num_links, link_idx, card->num_configs, conf_idx); - ret = -EINVAL; - goto parse_of_err; - } - - ret = 0; - -parse_of_err: - return ret; -} - -static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct device_node *codec_port_old2; - int rc; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for dummy-Codec - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - codec_port_old = NULL; - codec_port_old2 = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(codec_port); - - (*link_num)++; - (*dais_num)++; - - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } - - codec_port_old2 = codec_port_old; - continue; - } - - (*dais_num)++; - codec_port_old = codec_port; - } -} - -static int asoc_graph_card_probe(struct platform_device *pdev) -{ - struct graph_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct graph_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct device *dev = &pdev->dev; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; - int ret, i; - - /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_graph_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_graph_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_graph_of_match[] = { - { .compatible = "audio-graph-scu-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); - -static struct platform_driver asoc_graph_card = { - .driver = { - .name = "asoc-audio-graph-scu-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, - }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, -}; -module_platform_driver(asoc_graph_card); - -MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); From bb93487b85012b2232149888d260f935e4da680d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:37 +0900 Subject: [PATCH 018/461] ASoC: simple-scu-card: remove simple-scu-card on Doc It is already merged into simple-card. simple-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/simple-scu-card.txt | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/simple-scu-card.txt diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt deleted file mode 100644 index 3a2f71616cda..000000000000 --- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt +++ /dev/null @@ -1,94 +0,0 @@ -ASoC Simple SCU Sound Card - -Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM". -For example, you can use this driver if you want to exchange sampling rate convert, -Mixing, etc... - -Required properties: - -- compatible : "simple-scu-audio-card" - "renesas,rsrc-card" -Optional properties: - -- simple-audio-card,name : see simple-audio-card.txt -- simple-audio-card,cpu : see simple-audio-card.txt -- simple-audio-card,codec : see simple-audio-card.txt - -Optional subnode properties: - -- simple-audio-card,format : see simple-audio-card.txt -- simple-audio-card,frame-master : see simple-audio-card.txt -- simple-audio-card,bitclock-master : see simple-audio-card.txt -- simple-audio-card,bitclock-inversion : see simple-audio-card.txt -- simple-audio-card,frame-inversion : see simple-audio-card.txt -- simple-audio-card,convert-rate : platform specified sampling rate convert -- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) -- simple-audio-card,prefix : see routing -- simple-audio-card,widgets : Please refer to widgets.txt. -- simple-audio-card,routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources. - use audio-prefix if some components is using same sink/sources naming. - it can be used if compatible was "renesas,rsrc-card"; - -Required CPU/CODEC subnodes properties: - -- sound-dai : see simple-audio-card.txt - -Optional CPU/CODEC subnodes properties: - -- clocks / system-clock-frequency : see simple-audio-card.txt - -Example 1. Sampling Rate Conversion - -sound { - compatible = "simple-scu-audio-card"; - - simple-audio-card,name = "rsnd-ak4643"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcodec>; - simple-audio-card,frame-master = <&sndcodec>; - - simple-audio-card,convert-rate = <48000>; - - simple-audio-card,prefix = "ak4642"; - simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", - "DAI0 Capture", "ak4642 Capture"; - - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - - sndcodec: simple-audio-card,codec { - sound-dai = <&ak4643>; - system-clock-frequency = <11289600>; - }; -}; - -Example 2. 2 CPU 1 Codec (Mixing) - -sound { - compatible = "simple-scu-audio-card"; - - simple-audio-card,name = "rsnd-ak4643"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&dpcmcpu>; - simple-audio-card,frame-master = <&dpcmcpu>; - - simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", - "ak4642 Playback", "DAI1 Playback"; - - dpcmcpu: cpu@0 { - sound-dai = <&rcar_sound 0>; - }; - - cpu@1 { - sound-dai = <&rcar_sound 1>; - }; - - codec { - prefix = "ak4642"; - sound-dai = <&ak4643>; - clocks = <&audio_clock>; - }; -}; From c8ed6aca6b824018a39702a563f2f6591de20d64 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:42 +0900 Subject: [PATCH 019/461] ASoC: simple-scu-card: remove simple-scu-card It is already merged into simple-card. simple-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 8 - sound/soc/generic/Makefile | 2 - sound/soc/generic/simple-scu-card.c | 474 ---------------------------- 3 files changed, 484 deletions(-) delete mode 100644 sound/soc/generic/simple-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 59190f42fc08..83f1243145b0 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -8,14 +8,6 @@ config SND_SIMPLE_CARD This option enables generic simple sound card support It also support DPCM of multi CPU single Codec ststem. -config SND_SIMPLE_SCU_CARD - tristate "ASoC Simple SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support. - It supports DPCM of multi CPU single Codec system. - config SND_AUDIO_GRAPH_CARD tristate "ASoC Audio Graph sound card support" depends on OF diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9fbfdd524b24..21c29e5e0671 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o -snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o -obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c deleted file mode 100644 index 9d7299d536a8..000000000000 --- a/sound/soc/generic/simple-scu-card.c +++ /dev/null @@ -1,474 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC simple SCU sound card support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on ${LINUX}/sound/soc/generic/simple-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct simple_card_data { - struct snd_soc_card snd_card; - struct simple_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define simple_priv_to_card(priv) (&(priv)->snd_card) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) -#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) - -#define DAI "sound-dai" -#define CELL "#sound-dai-cells" -#define PREFIX "simple-audio-card," - -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, -}; - -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_simple_card_dai_link_of(struct device_node *link, - struct device_node *np, - struct device_node *codec, - struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, - bool is_top_level_node) -{ - struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); - struct snd_soc_card *card = simple_priv_to_card(priv); - struct asoc_simple_dai *dai; - char *prefix = ""; - int ret; - - /* For single DAI link & old style of DT node */ - if (is_top_level_node) - prefix = PREFIX; - - if (is_fe) { - int is_single_links = 0; - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, - &is_single_links); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(np, cconf, - dai_link->codecs->of_node, - "prefix"); - } - - asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(np, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, link, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; - - return 0; -} - -static int asoc_simple_card_parse_of(struct simple_card_data *priv) - -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct snd_soc_card *card = simple_priv_to_card(priv); - bool is_fe; - int ret, loop; - int dai_idx, link_idx, conf_idx; - - if (!top) - return -EINVAL; - - ret = asoc_simple_card_of_parse_widgets(card, PREFIX); - if (ret < 0) - return ret; - - ret = asoc_simple_card_of_parse_routing(card, PREFIX); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata); - - loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; - } - - do { - codec = of_get_child_by_name(node, - loop ? "codec" : PREFIX "codec"); - if (!codec) - return -ENODEV; - - for_each_child_of_node(node, np) { - is_fe = (np != codec); - - ret = asoc_simple_card_dai_link_of(node, np, codec, priv, - &dai_idx, link_idx++, - &conf_idx, - is_fe, !loop); - if (ret < 0) - return ret; - } - node = of_get_next_child(top, node); - } while (loop && node); - - ret = asoc_simple_card_parse_card_name(card, PREFIX); - if (ret < 0) - return ret; - - return 0; -} - -static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct device_node *top = dev->of_node; - struct device_node *node; - int loop; - int num; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for "dummy-Codec" - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; - return; - } - - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - (*dais_num) += num; - if (num > 2) { - (*link_num) += num; - (*ccnf_num)++; - } else { - (*link_num)++; - } - node = of_get_next_child(top, node); - } while (loop && node); -} - -static int asoc_simple_card_probe(struct platform_device *pdev) -{ - struct simple_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct simple_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - struct device *dev = &pdev->dev; - int ret, i; - int lnum = 0, dnum = 0, cnum = 0; - - /* Allocate the private data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_simple_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_simple_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_simple_of_match[] = { - { .compatible = "renesas,rsrc-card", }, - { .compatible = "simple-scu-audio-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); - -static struct platform_driver asoc_simple_card = { - .driver = { - .name = "simple-scu-audio-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, - }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, -}; - -module_platform_driver(asoc_simple_card); - -MODULE_ALIAS("platform:asoc-simple-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Simple SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); From e3e12ec09a18ad779b637f4a006a908cb6045aa7 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:27 +0530 Subject: [PATCH 020/461] dt-bindings: ASoC: xlnx, audio-formatter: Document audio formatter bindings Added documentation for audio formatter IP core DT bindings. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- .../bindings/sound/xlnx,audio-formatter.txt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt diff --git a/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt b/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt new file mode 100644 index 000000000000..cbc93c8f4963 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt @@ -0,0 +1,29 @@ +Device-Tree bindings for Xilinx PL audio formatter + +The IP core supports DMA, data formatting(AES<->PCM conversion) +of audio samples. + +Required properties: + - compatible: "xlnx,audio-formatter-1.0" + - interrupt-names: Names specified to list of interrupts in same + order mentioned under "interrupts". + List of supported interrupt names are: + "irq_mm2s" : interrupt from MM2S block + "irq_s2mm" : interrupt from S2MM block + - interrupts-parent: Phandle for interrupt controller. + - interrupts: List of Interrupt numbers. + - reg: Base address and size of the IP core instance. + - clock-names: List of input clocks. + Required elements: "s_axi_lite_aclk", "aud_mclk" + - clocks: Input clock specifier. Refer to common clock bindings. + +Example: + audio_ss_0_audio_formatter_0: audio_formatter@80010000 { + compatible = "xlnx,audio-formatter-1.0"; + interrupt-names = "irq_mm2s", "irq_s2mm"; + interrupt-parent = <&gic>; + interrupts = <0 104 4>, <0 105 4>; + reg = <0x0 0x80010000 0x0 0x1000>; + clock-names = "s_axi_lite_aclk", "aud_mclk"; + clocks = <&clk 71>, <&clk_wiz_1 0>; + }; From 6f6c3c36f0917be24587eeba818ab4fdfcb5465a Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:28 +0530 Subject: [PATCH 021/461] ASoC: xlnx: add pcm formatter platform driver The audio formatter PL IP supports DMA of two streams - mm2s and s2mm for playback and capture respectively. Apart from DMA, IP also does conversions like PCM to AES and viceversa. This patch adds DMA component driver for the IP. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 565 ++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_formatter_pcm.c diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c new file mode 100644 index 000000000000..f7235f7664d7 --- /dev/null +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Xilinx ASoC audio formatter support +// +// Copyright (C) 2018 Xilinx, Inc. +// +// Author: Maruthi Srinivas Bayyavarapu + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "xlnx_formatter_pcm" + +#define XLNX_S2MM_OFFSET 0 +#define XLNX_MM2S_OFFSET 0x100 + +#define XLNX_AUD_CORE_CONFIG 0x4 +#define XLNX_AUD_CTRL 0x10 +#define XLNX_AUD_STS 0x14 + +#define AUD_CTRL_RESET_MASK BIT(1) +#define AUD_CFG_MM2S_MASK BIT(15) +#define AUD_CFG_S2MM_MASK BIT(31) + +#define XLNX_AUD_FS_MULTIPLIER 0x18 +#define XLNX_AUD_PERIOD_CONFIG 0x1C +#define XLNX_AUD_BUFF_ADDR_LSB 0x20 +#define XLNX_AUD_BUFF_ADDR_MSB 0x24 +#define XLNX_AUD_XFER_COUNT 0x28 +#define XLNX_AUD_CH_STS_START 0x2C +#define XLNX_BYTES_PER_CH 0x44 + +#define AUD_STS_IOC_IRQ_MASK BIT(31) +#define AUD_STS_CH_STS_MASK BIT(29) +#define AUD_CTRL_IOC_IRQ_MASK BIT(13) +#define AUD_CTRL_TOUT_IRQ_MASK BIT(14) +#define AUD_CTRL_DMA_EN_MASK BIT(0) + +#define CFG_MM2S_CH_MASK GENMASK(11, 8) +#define CFG_MM2S_CH_SHIFT 8 +#define CFG_MM2S_XFER_MASK GENMASK(14, 13) +#define CFG_MM2S_XFER_SHIFT 13 +#define CFG_MM2S_PKG_MASK BIT(12) + +#define CFG_S2MM_CH_MASK GENMASK(27, 24) +#define CFG_S2MM_CH_SHIFT 24 +#define CFG_S2MM_XFER_MASK GENMASK(30, 29) +#define CFG_S2MM_XFER_SHIFT 29 +#define CFG_S2MM_PKG_MASK BIT(28) + +#define AUD_CTRL_DATA_WIDTH_SHIFT 16 +#define AUD_CTRL_ACTIVE_CH_SHIFT 19 +#define PERIOD_CFG_PERIODS_SHIFT 16 + +#define PERIODS_MIN 2 +#define PERIODS_MAX 6 +#define PERIOD_BYTES_MIN 192 +#define PERIOD_BYTES_MAX (50 * 1024) + +enum bit_depth { + BIT_DEPTH_8, + BIT_DEPTH_16, + BIT_DEPTH_20, + BIT_DEPTH_24, + BIT_DEPTH_32, +}; + +struct xlnx_pcm_drv_data { + void __iomem *mmio; + bool s2mm_presence; + bool mm2s_presence; + unsigned int s2mm_irq; + unsigned int mm2s_irq; + struct snd_pcm_substream *play_stream; + struct snd_pcm_substream *capture_stream; + struct clk *axi_clk; +}; + +/* + * struct xlnx_pcm_stream_param - stream configuration + * @mmio: base address offset + * @interleaved: audio channels arrangement in buffer + * @xfer_mode: data formatting mode during transfer + * @ch_limit: Maximum channels supported + * @buffer_size: stream ring buffer size + */ +struct xlnx_pcm_stream_param { + void __iomem *mmio; + bool interleaved; + u32 xfer_mode; + u32 ch_limit; + u64 buffer_size; +}; + +static const struct snd_pcm_hardware xlnx_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .buffer_bytes_max = PERIODS_MAX * PERIOD_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = PERIOD_BYTES_MAX, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, +}; + +static int xlnx_formatter_pcm_reset(void __iomem *mmio_base) +{ + u32 val, retries = 0; + + val = readl(mmio_base + XLNX_AUD_CTRL); + val |= AUD_CTRL_RESET_MASK; + writel(val, mmio_base + XLNX_AUD_CTRL); + + val = readl(mmio_base + XLNX_AUD_CTRL); + /* Poll for maximum timeout of approximately 100ms (1 * 100)*/ + while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) { + mdelay(1); + retries++; + val = readl(mmio_base + XLNX_AUD_CTRL); + } + if (val & AUD_CTRL_RESET_MASK) + return -ENODEV; + + return 0; +} + +static void xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream) +{ + u32 val; + + val = readl(mmio_base + XLNX_AUD_CTRL); + val &= ~AUD_CTRL_IOC_IRQ_MASK; + if (stream == SNDRV_PCM_STREAM_CAPTURE) + val &= ~AUD_CTRL_TOUT_IRQ_MASK; + + writel(val, mmio_base + XLNX_AUD_CTRL); +} + +static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg) +{ + u32 val; + void __iomem *reg; + struct device *dev = arg; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev); + + reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS; + val = readl(reg); + if (val & AUD_STS_IOC_IRQ_MASK) { + writel(val & AUD_STS_IOC_IRQ_MASK, reg); + if (adata->play_stream) + snd_pcm_period_elapsed(adata->play_stream); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) +{ + u32 val; + void __iomem *reg; + struct device *dev = arg; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev); + + reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS; + val = readl(reg); + if (val & AUD_STS_IOC_IRQ_MASK) { + writel(val & AUD_STS_IOC_IRQ_MASK, reg); + if (adata->capture_stream) + snd_pcm_period_elapsed(adata->capture_stream); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int xlnx_formatter_pcm_open(struct snd_pcm_substream *substream) +{ + int err; + u32 val, data_format_mode; + u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift; + struct xlnx_pcm_stream_param *stream_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + !adata->mm2s_presence) + return -ENODEV; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + !adata->s2mm_presence) + return -ENODEV; + + stream_data = kzalloc(sizeof(*stream_data), GFP_KERNEL); + if (!stream_data) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ch_count_mask = CFG_MM2S_CH_MASK; + ch_count_shift = CFG_MM2S_CH_SHIFT; + data_xfer_mode = CFG_MM2S_XFER_MASK; + data_xfer_shift = CFG_MM2S_XFER_SHIFT; + data_format_mode = CFG_MM2S_PKG_MASK; + stream_data->mmio = adata->mmio + XLNX_MM2S_OFFSET; + adata->play_stream = substream; + + } else { + ch_count_mask = CFG_S2MM_CH_MASK; + ch_count_shift = CFG_S2MM_CH_SHIFT; + data_xfer_mode = CFG_S2MM_XFER_MASK; + data_xfer_shift = CFG_S2MM_XFER_SHIFT; + data_format_mode = CFG_S2MM_PKG_MASK; + stream_data->mmio = adata->mmio + XLNX_S2MM_OFFSET; + adata->capture_stream = substream; + } + + val = readl(adata->mmio + XLNX_AUD_CORE_CONFIG); + + if (!(val & data_format_mode)) + stream_data->interleaved = true; + + stream_data->xfer_mode = (val & data_xfer_mode) >> data_xfer_shift; + stream_data->ch_limit = (val & ch_count_mask) >> ch_count_shift; + dev_info(component->dev, + "stream %d : format = %d mode = %d ch_limit = %d\n", + substream->stream, stream_data->interleaved, + stream_data->xfer_mode, stream_data->ch_limit); + + snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware); + runtime->private_data = stream_data; + + /* Resize the period size divisible by 64 */ + err = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err) { + dev_err(component->dev, + "unable to set constraint on period bytes\n"); + return err; + } + + /* enable DMA IOC irq */ + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val |= AUD_CTRL_IOC_IRQ_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + + return 0; +} + +static int xlnx_formatter_pcm_close(struct snd_pcm_substream *substream) +{ + int ret; + struct xlnx_pcm_stream_param *stream_data = + substream->runtime->private_data; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); + + ret = xlnx_formatter_pcm_reset(stream_data->mmio); + if (ret) { + dev_err(component->dev, "audio formatter reset failed\n"); + goto err_reset; + } + xlnx_formatter_disable_irqs(stream_data->mmio, substream->stream); + +err_reset: + kfree(stream_data); + return 0; +} + +static snd_pcm_uframes_t +xlnx_formatter_pcm_pointer(struct snd_pcm_substream *substream) +{ + u32 pos; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xlnx_pcm_stream_param *stream_data = runtime->private_data; + + pos = readl(stream_data->mmio + XLNX_AUD_XFER_COUNT); + + if (pos >= stream_data->buffer_size) + pos = 0; + + return bytes_to_frames(runtime, pos); +} + +static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; + int status; + u64 size; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xlnx_pcm_stream_param *stream_data = runtime->private_data; + + active_ch = params_channels(params); + if (active_ch > stream_data->ch_limit) + return -EINVAL; + + size = params_buffer_bytes(params); + status = snd_pcm_lib_malloc_pages(substream, size); + if (status < 0) + return status; + + stream_data->buffer_size = size; + + low = lower_32_bits(substream->dma_buffer.addr); + high = upper_32_bits(substream->dma_buffer.addr); + writel(low, stream_data->mmio + XLNX_AUD_BUFF_ADDR_LSB); + writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB); + + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + bits_per_sample = params_width(params); + switch (bits_per_sample) { + case 8: + val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 16: + val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 20: + val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 24: + val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 32: + val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + default: + return -EINVAL; + } + + val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + + val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT) + | params_period_bytes(params); + writel(val, stream_data->mmio + XLNX_AUD_PERIOD_CONFIG); + bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch); + writel(bytes_per_ch, stream_data->mmio + XLNX_BYTES_PER_CH); + + return 0; +} + +static int xlnx_formatter_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int xlnx_formatter_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + u32 val; + struct xlnx_pcm_stream_param *stream_data = + substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val |= AUD_CTRL_DMA_EN_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val &= ~AUD_CTRL_DMA_EN_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + break; + } + + return 0; +} + +static int xlnx_formatter_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, + DRV_NAME); + return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, component->dev, + xlnx_pcm_hardware.buffer_bytes_max, + xlnx_pcm_hardware.buffer_bytes_max); +} + +static const struct snd_pcm_ops xlnx_formatter_pcm_ops = { + .open = xlnx_formatter_pcm_open, + .close = xlnx_formatter_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = xlnx_formatter_pcm_hw_params, + .hw_free = xlnx_formatter_pcm_hw_free, + .trigger = xlnx_formatter_pcm_trigger, + .pointer = xlnx_formatter_pcm_pointer, +}; + +static const struct snd_soc_component_driver xlnx_asoc_component = { + .name = DRV_NAME, + .ops = &xlnx_formatter_pcm_ops, + .pcm_new = xlnx_formatter_pcm_new, +}; + +static int xlnx_formatter_pcm_probe(struct platform_device *pdev) +{ + int ret; + u32 val; + struct xlnx_pcm_drv_data *aud_drv_data; + struct resource *res; + struct device *dev = &pdev->dev; + + aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL); + if (!aud_drv_data) + return -ENOMEM; + + aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk"); + if (IS_ERR(aud_drv_data->axi_clk)) { + ret = PTR_ERR(aud_drv_data->axi_clk); + dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret); + return ret; + } + ret = clk_prepare_enable(aud_drv_data->axi_clk); + if (ret) { + dev_err(dev, + "failed to enable s_axi_lite_aclk(%d)\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "audio formatter node:addr to resource failed\n"); + ret = -ENXIO; + goto clk_err; + } + aud_drv_data->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(aud_drv_data->mmio)) { + dev_err(dev, "audio formatter ioremap failed\n"); + ret = PTR_ERR(aud_drv_data->mmio); + goto clk_err; + } + + val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG); + if (val & AUD_CFG_MM2S_MASK) { + aud_drv_data->mm2s_presence = true; + ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio + + XLNX_MM2S_OFFSET); + if (ret) { + dev_err(dev, "audio formatter reset failed\n"); + goto clk_err; + } + xlnx_formatter_disable_irqs(aud_drv_data->mmio + + XLNX_MM2S_OFFSET, + SNDRV_PCM_STREAM_PLAYBACK); + + aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev, + "irq_mm2s"); + if (aud_drv_data->mm2s_irq < 0) { + dev_err(dev, "xlnx audio mm2s irq resource failed\n"); + ret = aud_drv_data->mm2s_irq; + goto clk_err; + } + ret = devm_request_irq(dev, aud_drv_data->mm2s_irq, + xlnx_mm2s_irq_handler, 0, + "xlnx_formatter_pcm_mm2s_irq", dev); + if (ret) { + dev_err(dev, "xlnx audio mm2s irq request failed\n"); + goto clk_err; + } + } + if (val & AUD_CFG_S2MM_MASK) { + aud_drv_data->s2mm_presence = true; + ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio + + XLNX_S2MM_OFFSET); + if (ret) { + dev_err(dev, "audio formatter reset failed\n"); + goto clk_err; + } + xlnx_formatter_disable_irqs(aud_drv_data->mmio + + XLNX_S2MM_OFFSET, + SNDRV_PCM_STREAM_CAPTURE); + + aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev, + "irq_s2mm"); + if (aud_drv_data->s2mm_irq < 0) { + dev_err(dev, "xlnx audio s2mm irq resource failed\n"); + ret = aud_drv_data->s2mm_irq; + goto clk_err; + } + ret = devm_request_irq(dev, aud_drv_data->s2mm_irq, + xlnx_s2mm_irq_handler, 0, + "xlnx_formatter_pcm_s2mm_irq", + dev); + if (ret) { + dev_err(dev, "xlnx audio s2mm irq request failed\n"); + goto clk_err; + } + } + + dev_set_drvdata(dev, aud_drv_data); + + ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component, + NULL, 0); + if (ret) { + dev_err(dev, "pcm platform device register failed\n"); + goto clk_err; + } + + return 0; + +clk_err: + clk_disable_unprepare(aud_drv_data->axi_clk); + return ret; +} + +static int xlnx_formatter_pcm_remove(struct platform_device *pdev) +{ + int ret = 0; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(&pdev->dev); + + if (adata->s2mm_presence) + ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_S2MM_OFFSET); + + /* Try MM2S reset, even if S2MM reset fails */ + if (adata->mm2s_presence) + ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_MM2S_OFFSET); + + if (ret) + dev_err(&pdev->dev, "audio formatter reset failed\n"); + + clk_disable_unprepare(adata->axi_clk); + return ret; +} + +static const struct of_device_id xlnx_formatter_pcm_of_match[] = { + { .compatible = "xlnx,audio-formatter-1.0"}, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match); + +static struct platform_driver xlnx_formatter_pcm_driver = { + .probe = xlnx_formatter_pcm_probe, + .remove = xlnx_formatter_pcm_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = xlnx_formatter_pcm_of_match, + }, +}; + +module_platform_driver(xlnx_formatter_pcm_driver); +MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu "); +MODULE_LICENSE("GPL v2"); From b31daa15af760747b91dbb76c80306d77d8ae05f Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:29 +0530 Subject: [PATCH 022/461] ASoC: xlnx: enable audio formatter driver build Enable audio formatter driver build. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/Kconfig | 7 +++++++ sound/soc/xilinx/Makefile | 2 ++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index 723a583a8d57..ac48d6a00c36 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -6,3 +6,10 @@ config SND_SOC_XILINX_I2S mode, IP receives audio in AES format, extracts PCM and sends PCM data. In receiver mode, IP receives PCM audio and encapsulates PCM in AES format and sends AES data. + +config SND_SOC_XILINX_AUDIO_FORMATTER + tristate "Audio support for the the Xilinx audio formatter" + help + Select this option to enable Xilinx audio formatter + support. This provides DMA platform device support for + audio functionality. diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile index 6c1209b9ee75..432693b1cc79 100644 --- a/sound/soc/xilinx/Makefile +++ b/sound/soc/xilinx/Makefile @@ -1,2 +1,4 @@ snd-soc-xlnx-i2s-objs := xlnx_i2s.o obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o +snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o +obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o From de2949fe262197298036989924d05f5de6b9815a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:54 +0900 Subject: [PATCH 023/461] ASoC: audio-graph-card: add 1 CPU : 1 Codec support again audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 44 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c3e80bc27e80..638333cdac66 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -408,6 +408,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_ep = NULL; struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; + struct asoc_simple_card_data adata; int rc, ret; int link_idx, dai_idx, conf_idx; int cpu; @@ -453,7 +454,13 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - if (of_get_child_count(codec_port) > 1) { + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || + adata.convert_channels) { /* * for DPCM sound */ @@ -495,7 +502,7 @@ static void asoc_graph_get_dais_count(struct device *dev, struct device_node *codec_ep; struct device_node *codec_port; struct device_node *codec_port_old; - struct device_node *codec_port_old2; + struct asoc_simple_card_data adata; int rc; /* @@ -534,9 +541,17 @@ static void asoc_graph_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ codec_port_old = NULL; - codec_port_old2 = NULL; of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { cpu_port = it.node; cpu_ep = NULL; @@ -554,17 +569,22 @@ static void asoc_graph_get_dais_count(struct device *dev, (*link_num)++; (*dais_num)++; - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - codec_port_old2 = codec_port_old; - continue; + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) { + + if (codec_port_old == codec_port) + continue; + + (*link_num)++; + (*ccnf_num)++; + (*dais_num)++; + } else { + (*dais_num)++; } - - (*dais_num)++; codec_port_old = codec_port; } } From 1e4771a62fd7a6bab058529c450d3d87a8bd5b1a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:59 +0900 Subject: [PATCH 024/461] ASoC: audio-graph-card: add link_info Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 99 ++++++++++++++-------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 638333cdac66..cd9beb801fc1 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -39,6 +39,13 @@ struct graph_card_data { struct gpio_desc *pa_gpio; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define graph_priv_to_card(priv) (&(priv)->snd_card) #define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) @@ -189,13 +196,12 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_cpu) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct device_node *ep = is_cpu ? cpu_ep : codec_ep; + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *ep = li->cpu ? cpu_ep : codec_ep; struct device_node *port = of_get_parent(ep); struct device_node *ports = of_get_parent(port); struct device_node *node = of_graph_get_port_parent(ep); @@ -203,7 +209,9 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; - dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec"); + li->link++; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs); @@ -215,7 +223,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); - if (is_cpu) { + if (li->cpu) { /* BE is dummy */ codecs->of_node = NULL; @@ -227,7 +235,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); if (ret) @@ -259,10 +267,10 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_graph_codec(ep, dai_link); if (ret < 0) @@ -314,11 +322,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *cpu_port = of_get_parent(cpu_ep); struct device_node *codec_port = of_get_parent(codec_ep); struct device_node *cpu_ports = of_get_parent(cpu_port); @@ -327,12 +335,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct asoc_simple_dai *codec_dai; int ret; - dev_dbg(dev, "link_of\n"); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); + + li->link++; cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; /* Factor to mclk, used in hw_params() */ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); @@ -409,9 +419,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; + struct link_info li; int rc, ret; - int link_idx, dai_idx, conf_idx; - int cpu; ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) @@ -421,11 +430,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret < 0) return ret; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; + memset(&li, 0, sizeof(li)); codec_port_old = NULL; - for (cpu = 1; cpu >= 0; cpu--) { + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -464,22 +471,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!cpu) { + if (!li.cpu) { if (codec_port_old == codec_port) continue; codec_port_old = codec_port; } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++, - &conf_idx, cpu); - } else if (cpu) { + top, cpu_ep, codec_ep, priv, &li); + } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++); + top, cpu_ep, codec_ep, priv, &li); } if (ret < 0) return ret; @@ -491,9 +495,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) } static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct of_phandle_iterator it; struct device_node *node = dev->of_node; @@ -566,8 +568,8 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - (*link_num)++; - (*dais_num)++; + li->link++; + li->dais++; memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); @@ -579,11 +581,11 @@ static void asoc_graph_get_dais_count(struct device *dev, if (codec_port_old == codec_port) continue; - (*link_num)++; - (*ccnf_num)++; - (*dais_num)++; + li->link++; + li->conf++; + li->dais++; } else { - (*dais_num)++; + li->dais++; } codec_port_old = codec_port; } @@ -615,7 +617,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -623,14 +625,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_graph_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -640,7 +643,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -663,12 +666,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = dai_link; - card->num_links = lnum; + card->num_links = li.link; card->dapm_widgets = asoc_graph_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; ret = asoc_graph_card_parse_of(priv); if (ret < 0) { From dd98fbc558a035728beed08a16c443f9fd37eb2b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:05 +0900 Subject: [PATCH 025/461] ASoC: audio-graph-card: cleanup DAI link loop method - step1 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 134 ++++++++++++++++++--------- 1 file changed, 91 insertions(+), 43 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index cd9beb801fc1..fbd32129c518 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -192,23 +192,32 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, +static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, - struct link_info *li) + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); - struct device_node *node = of_graph_get_port_parent(ep); + struct device_node *port; + struct device_node *ports; + struct device_node *node; struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (!li->cpu && dup_codec) + return 0; + + port = of_get_parent(ep); + ports = of_get_parent(port); + node = of_graph_get_port_parent(ep); + li->link++; dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); @@ -222,6 +231,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); + of_node_put(node); if (li->cpu) { @@ -318,23 +328,32 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_graph_card_dai_link_of(struct device_node *top, +static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); - struct device_node *cpu_port = of_get_parent(cpu_ep); - struct device_node *codec_port = of_get_parent(codec_ep); - struct device_node *cpu_ports = of_get_parent(cpu_port); - struct device_node *codec_ports = of_get_parent(codec_port); + struct device_node *top = dev->of_node; + struct device_node *cpu_port; + struct device_node *codec_port; + struct device_node *cpu_ports; + struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; int ret; + /* Do it only CPU turn */ + if (!li->cpu) + return 0; + + cpu_port = of_get_parent(cpu_ep); + cpu_ports = of_get_parent(cpu_port); + codec_port = of_get_parent(codec_ep); + codec_ports = of_get_parent(codec_port); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); li->link++; @@ -471,22 +490,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!li.cpu) { - if (codec_port_old == codec_port) - continue; - codec_port_old = codec_port; - } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li, + (codec_port_old == codec_port)); } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li); } if (ret < 0) return ret; + codec_port_old = codec_port; } } } @@ -494,9 +510,47 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static void asoc_graph_get_dais_count(struct device *dev, +static int asoc_graph_card_count_noml(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, struct link_info *li) { + struct device *dev = graph_priv_to_dev(priv); + + li->link += 1; /* 1xCPU-Codec */ + li->dais += 2; /* 1xCPU + 1xCodec */ + + dev_dbg(dev, "Count As Normal\n"); + + return 0; +} + +static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) +{ + struct device *dev = graph_priv_to_dev(priv); + + li->link++; /* 1xCPU-dummy */ + li->dais++; /* 1xCPU */ + + if (!dup_codec) { + li->link++; /* 1xdummy-Codec */ + li->conf++; /* 1xdummy-Codec */ + li->dais++; /* 1xCodec */ + } + + dev_dbg(dev, "Count As DPCM\n"); + + return 0; +} + +static void asoc_graph_get_dais_count(struct graph_card_data *priv, + struct link_info *li) +{ + struct device *dev = graph_priv_to_dev(priv); struct of_phandle_iterator it; struct device_node *node = dev->of_node; struct device_node *cpu_port; @@ -568,24 +622,18 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - li->link++; - li->dais++; - memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); asoc_graph_card_get_conversion(dev, cpu_ep, &adata); if ((of_get_child_count(codec_port) > 1) || adata.convert_rate || adata.convert_channels) { - - if (codec_port_old == codec_port) - continue; - - li->link++; - li->conf++; - li->dais++; + asoc_graph_card_count_dpcm(priv, + cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); } else { - li->dais++; + asoc_graph_card_count_noml(priv, + cpu_ep, codec_ep, li); } codec_port_old = codec_port; } @@ -625,8 +673,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dapm_widgets = asoc_graph_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); + card->probe = asoc_graph_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(dev, &li); + asoc_graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -656,20 +711,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = dai_link; card->num_links = li.link; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; card->num_configs = li.conf; From fce9b90c1ab7e915553c57353355700c79b39c86 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:20 +0900 Subject: [PATCH 026/461] ASoC: audio-graph-card: cleanup DAI link loop method - step2 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_graph_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 168 ++++++++++++--------------- 1 file changed, 77 insertions(+), 91 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fbd32129c518..1152de37110e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -425,22 +425,80 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int asoc_graph_card_for_each_link(struct graph_card_data *priv, + struct link_info *li, + int (*func_noml)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li), + int (*func_dpcm)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, int dup_codec)) { struct of_phandle_iterator it; struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *top = dev->of_node; - struct device_node *node = top; + struct device_node *node = dev->of_node; struct device_node *cpu_port; - struct device_node *cpu_ep = NULL; - struct device_node *codec_ep = NULL; - struct device_node *codec_port = NULL; - struct device_node *codec_port_old = NULL; + struct device_node *cpu_ep; + struct device_node *codec_ep; + struct device_node *codec_port; + struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; - struct link_info li; int rc, ret; + /* loop for all listed CPU port */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = NULL; + + /* loop for all CPU endpoint */ + while (1) { + cpu_ep = of_get_next_child(cpu_port, cpu_ep); + if (!cpu_ep) + break; + + /* get codec */ + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_get_parent(codec_ep); + + of_node_put(codec_ep); + of_node_put(codec_port); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + /* + * It is DPCM + * if Codec port has many endpoints, + * or has convert-xxx property + */ + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); + /* else normal sound */ + else + ret = func_noml(priv, cpu_ep, codec_ep, li); + + if (ret < 0) + return ret; + + codec_port_old = codec_port; + } + } + + return 0; +} + +static int asoc_graph_card_parse_of(struct graph_card_data *priv) +{ + struct snd_soc_card *card = graph_priv_to_card(priv); + struct link_info li; + int ret; + ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) return ret; @@ -450,7 +508,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return ret; memset(&li, 0, sizeof(li)); - codec_port_old = NULL; for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. @@ -464,47 +521,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || - adata.convert_channels) { - /* - * for DPCM sound - */ - ret = asoc_graph_card_dai_link_of_dpcm( - priv, cpu_ep, codec_ep, &li, - (codec_port_old == codec_port)); - } else if (li.cpu) { - /* - * for Normal sound - */ - ret = asoc_graph_card_dai_link_of( - priv, cpu_ep, codec_ep, &li); - } - if (ret < 0) - return ret; - codec_port_old = codec_port; - } - } + ret = asoc_graph_card_for_each_link(priv, &li, + asoc_graph_card_dai_link_of, + asoc_graph_card_dai_link_of_dpcm); + if (ret < 0) + return ret; } return asoc_simple_card_parse_card_name(card, NULL); @@ -551,15 +572,6 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct asoc_simple_card_data adata; - int rc; /* * link_num : number of links. @@ -607,37 +619,11 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - codec_port_old = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || adata.convert_channels) { - asoc_graph_card_count_dpcm(priv, - cpu_ep, codec_ep, li, - (codec_port_old == codec_port)); - } else { - asoc_graph_card_count_noml(priv, - cpu_ep, codec_ep, li); - } - codec_port_old = codec_port; - } - } + asoc_graph_card_for_each_link(priv, li, + asoc_graph_card_count_noml, + asoc_graph_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_graph_soc_card_probe(struct snd_soc_card *card) From 97fe6ca4146583d8dccdde51c143c52b385c2682 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:33 +0900 Subject: [PATCH 027/461] ASoC: audio-graph-card: reduce naming prefix Current audio-graph-card is using asoc_graph_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_graph_card_xxx() to graph_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 164 +++++++++++++-------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 1152de37110e..3ec96cdc683b 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,7 +20,7 @@ #include #include -struct graph_card_data { +struct graph_priv { struct snd_soc_card snd_card; struct graph_dai_props { struct asoc_simple_dai *cpu_dai; @@ -53,12 +53,12 @@ struct link_info { #define PREFIX "audio-graph-card," -static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +static int graph_outdrv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -74,16 +74,16 @@ static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { +static const struct snd_soc_dapm_widget graph_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, asoc_graph_card_outdrv_event, + 0, 0, NULL, 0, graph_outdrv_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), }; -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +static int graph_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret; @@ -98,10 +98,10 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +static void graph_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_clk_disable(dai_props->cpu_dai); @@ -109,13 +109,13 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int graph_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -140,15 +140,15 @@ err: return ret; } -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, - .hw_params = asoc_graph_card_hw_params, +static const struct snd_soc_ops graph_ops = { + .startup = graph_startup, + .shutdown = graph_shutdown, + .hw_params = graph_hw_params, }; -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int graph_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret = 0; @@ -165,10 +165,10 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -176,9 +176,9 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_graph_card_get_conversion(struct device *dev, - struct device_node *ep, - struct asoc_simple_card_data *adata) +static void graph_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *port = of_get_parent(ep); @@ -192,11 +192,11 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_dai_link_of_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); @@ -227,7 +227,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); + graph_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); @@ -274,7 +274,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = graph_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -322,24 +322,24 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; return 0; } -static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_dai_link_of(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *cpu_port; - struct device_node *codec_port; struct device_node *cpu_ports; + struct device_node *codec_port; struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; @@ -416,8 +416,8 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, if (ret < 0) return ret; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); @@ -425,13 +425,13 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_for_each_link(struct graph_card_data *priv, +static int graph_for_each_link(struct graph_priv *priv, struct link_info *li, - int (*func_noml)(struct graph_card_data *priv, + int (*func_noml)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li), - int (*func_dpcm)(struct graph_card_data *priv, + int (*func_dpcm)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li, int dup_codec)) @@ -467,8 +467,8 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + graph_get_conversion(dev, codec_ep, &adata); + graph_get_conversion(dev, cpu_ep, &adata); /* * It is DPCM @@ -493,7 +493,7 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int graph_parse_of(struct graph_priv *priv) { struct snd_soc_card *card = graph_priv_to_card(priv); struct link_info li; @@ -521,9 +521,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_graph_card_for_each_link(priv, &li, - asoc_graph_card_dai_link_of, - asoc_graph_card_dai_link_of_dpcm); + ret = graph_for_each_link(priv, &li, + graph_dai_link_of, + graph_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -531,10 +531,10 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static int asoc_graph_card_count_noml(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_count_noml(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -546,11 +546,11 @@ static int asoc_graph_card_count_noml(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_count_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); @@ -568,8 +568,8 @@ static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, return 0; } -static void asoc_graph_get_dais_count(struct graph_card_data *priv, - struct link_info *li) +static void graph_get_dais_count(struct graph_priv *priv, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -619,16 +619,16 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - asoc_graph_card_for_each_link(priv, li, - asoc_graph_card_count_noml, - asoc_graph_card_count_dpcm); + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_graph_soc_card_probe(struct snd_soc_card *card) +static int graph_card_probe(struct snd_soc_card *card) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(card); + struct graph_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL); @@ -642,9 +642,9 @@ static int asoc_graph_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_graph_card_probe(struct platform_device *pdev) +static int graph_probe(struct platform_device *pdev) { - struct graph_card_data *priv; + struct graph_priv *priv; struct snd_soc_dai_link *dai_link; struct graph_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -662,12 +662,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card = graph_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; + card->dapm_widgets = graph_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); + card->probe = graph_card_probe; memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(priv, &li); + graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -707,7 +707,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->codec_conf = cconf; card->num_configs = li.conf; - ret = asoc_graph_card_parse_of(priv); + ret = graph_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -727,30 +727,30 @@ err: return ret; } -static int asoc_graph_card_remove(struct platform_device *pdev) +static int graph_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_graph_of_match[] = { +static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, { .compatible = "audio-graph-scu-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); +MODULE_DEVICE_TABLE(of, graph_of_match); -static struct platform_driver asoc_graph_card = { +static struct platform_driver graph_card = { .driver = { .name = "asoc-audio-graph-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, + .of_match_table = graph_of_match, }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, + .probe = graph_probe, + .remove = graph_remove, }; -module_platform_driver(asoc_graph_card); +module_platform_driver(graph_card); MODULE_ALIAS("platform:asoc-audio-graph-card"); MODULE_LICENSE("GPL v2"); From 7e5e1f8bbaa82e6877d8bc121cb1b44cb1ce7ddf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:42 +0900 Subject: [PATCH 028/461] ASoC: simple-card: add asoc_simple_card_get_conversion() simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_simple_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 37e001cf9cd1..52048069b25a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -165,6 +165,21 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_simple_card_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); + + asoc_simple_card_parse_convert(dev, top, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, NULL, adata); + asoc_simple_card_parse_convert(dev, np, NULL, adata); + + of_node_put(node); +} + static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *node, struct device_node *np, @@ -260,9 +275,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, "prefix"); } - asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata); - asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata); + asoc_simple_card_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) From 7adee60ee2732f23f703ff83ee35caad561490ba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:47 +0900 Subject: [PATCH 029/461] ASoC: simple-card: add 1 CPU : 1 Codec support again simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 52048069b25a..b15651409c7f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -453,6 +453,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *node; struct device_node *np; struct device_node *codec; + struct asoc_simple_card_data adata; bool is_fe; int ret, loop; int dai_idx, link_idx, conf_idx; @@ -480,8 +481,13 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + /* DPCM */ - if (of_get_child_count(node) > 2) { + if (of_get_child_count(node) > 2 || + adata.convert_rate || adata.convert_channels) { for_each_child_of_node(node, np) { codec = of_get_child_by_name(node, loop ? "codec" : @@ -495,14 +501,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) top, node, np, codec, priv, &dai_idx, link_idx++, &conf_idx, is_fe, !loop); + if (ret < 0) + return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, &dai_idx, link_idx++, !loop); + if (ret < 0) + return ret; } - if (ret < 0) - return ret; node = of_get_next_child(top, node); } while (loop && node); @@ -523,6 +531,8 @@ static void asoc_simple_card_get_dais_count(struct device *dev, { struct device_node *top = dev->of_node; struct device_node *node; + struct device_node *np; + struct asoc_simple_card_data adata; int loop; int num; @@ -562,6 +572,15 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ if (!top) { (*link_num) = 1; @@ -578,9 +597,14 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + num = of_get_child_count(node); (*dais_num) += num; - if (num > 2) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { (*link_num) += num; (*ccnf_num)++; } else { From 17029e494edc68337c9b99665e8f9b478f1d4ec5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:53 +0900 Subject: [PATCH 030/461] ASoC: simple-card: add link_info Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 94 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b15651409c7f..3820ad719059 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -33,6 +33,13 @@ struct simple_card_data { struct snd_soc_codec_conf *codec_conf; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) @@ -185,25 +192,27 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *np, struct device_node *codec, struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; - char prop[128]; char *prefix = ""; int ret; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + + li->link++; + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; - if (is_fe) { + if (np != codec) { int is_single_links = 0; /* BE is dummy */ @@ -216,7 +225,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, &is_single_links); @@ -247,10 +256,10 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); if (ret < 0) @@ -306,12 +315,12 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, static int asoc_simple_card_dai_link_of(struct device_node *top, struct device_node *node, struct simple_card_data *priv, - int *dai_idx, int link_idx, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct device_node *cpu = NULL; @@ -321,6 +330,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, char *prefix = ""; int ret, single_cpu; + li->link++; + + dev_dbg(dev, "link_of (%pOF)\n", node); + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; @@ -347,9 +360,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, } cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -454,9 +467,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *np; struct device_node *codec; struct asoc_simple_card_data adata; - bool is_fe; + struct link_info li; int ret, loop; - int dai_idx, link_idx, conf_idx; if (!top) return -EINVAL; @@ -470,10 +482,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; /* Single/Muti DAI link(s) & New style of DT node */ + memset(&li, 0, sizeof(li)); loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { node = dev->of_node; @@ -495,19 +505,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (!codec) return -ENODEV; - is_fe = (np != codec); - ret = asoc_simple_card_dai_link_of_dpcm( top, node, np, codec, priv, - &dai_idx, link_idx++, &conf_idx, - is_fe, !loop); + &li, !loop); if (ret < 0) return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, - &dai_idx, link_idx++, !loop); + &li, !loop); if (ret < 0) return ret; } @@ -525,9 +532,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct device_node *top = dev->of_node; struct device_node *node; @@ -583,9 +588,9 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 1 ccnf = 1xdummy-Codec */ if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; + li->link = 1; + li->dais = 2; + li->conf = 0; return; } @@ -602,13 +607,13 @@ static void asoc_simple_card_get_dais_count(struct device *dev, asoc_simple_card_get_conversion(dev, np, &adata); num = of_get_child_count(node); - (*dais_num) += num; + li->dais += num; if (num > 2 || adata.convert_rate || adata.convert_channels) { - (*link_num) += num; - (*ccnf_num)++; + li->link += num; + li->conf++; } else { - (*link_num)++; + li->link++; } node = of_get_next_child(top, node); } while (loop && node); @@ -640,7 +645,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -648,14 +653,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_simple_card_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -665,7 +671,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -681,9 +687,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = priv->dai_link; - card->num_links = lnum; + card->num_links = li.link; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { From d947cdfd4be29c48c6c529c2b5ce7b1988387c67 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:23 +0900 Subject: [PATCH 031/461] ASoC: simple-card: cleanup DAI link loop method - step1 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 208 +++++++++++++++++++++----------- 1 file changed, 136 insertions(+), 72 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 3820ad719059..4987db667165 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -187,32 +187,43 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, - struct device_node *node, +static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, struct device_node *np, struct device_node *codec, - struct simple_card_data *priv, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); char prop[128]; char *prefix = ""; int ret; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|Pass + * np + */ + if (li->cpu == (np == codec)) + return 0; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); li->link++; + of_node_put(node); + /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - if (np != codec) { + if (li->cpu) { int is_single_links = 0; /* BE is dummy */ @@ -312,53 +323,47 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *top, - struct device_node *node, - struct simple_card_data *priv, +static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; + struct device_node *top = dev->of_node; struct device_node *cpu = NULL; + struct device_node *node = NULL; struct device_node *plat = NULL; - struct device_node *codec = NULL; char prop[128]; char *prefix = ""; int ret, single_cpu; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!li->cpu || np == codec) + return 0; + + cpu = np; + node = of_get_parent(np); li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - snprintf(prop, sizeof(prop), "%scpu", prefix); - cpu = of_get_child_by_name(node, prop); - - if (!cpu) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - snprintf(prop, sizeof(prop), "%scodec", prefix); - codec = of_get_child_by_name(node, prop); - - if (!codec) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - cpu_dai = dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = @@ -421,8 +426,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: - of_node_put(cpu); - of_node_put(codec); + of_node_put(node); return ret; } @@ -464,9 +468,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; struct link_info li; int ret, loop; @@ -483,6 +484,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); + + /* FIXME */ + li.cpu = 1; +parse_loop: loop = 1; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { @@ -491,37 +496,59 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - /* DPCM */ - if (of_get_child_count(node) > 2 || - adata.convert_rate || adata.convert_channels) { - for_each_child_of_node(node, np) { - codec = of_get_child_by_name(node, - loop ? "codec" : - PREFIX "codec"); - if (!codec) - return -ENODEV; + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { ret = asoc_simple_card_dai_link_of_dpcm( - top, node, np, codec, priv, - &li, !loop); + priv, np, codec, &li, !loop); + if (ret < 0) + return ret; + } else { + ret = asoc_simple_card_dai_link_of( + priv, np, codec, &li, !loop); if (ret < 0) return ret; } - } else { - ret = asoc_simple_card_dai_link_of( - top, node, priv, - &li, !loop); - if (ret < 0) - return ret; } - node = of_get_next_child(top, node); } while (loop && node); + /* FIXME */ + li.cpu--; + if (li.cpu >= 0) + goto parse_loop; + ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) return ret; @@ -531,12 +558,39 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; } -static void asoc_simple_card_get_dais_count(struct device *dev, +static int asoc_simple_card_count_noml(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + if (np != codec) + li->link++; /* CPU-Codec */ + + return 0; +} + +static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + li->link++; /* CPU-dummy or dummy-Codec */ + if (np == codec) + li->conf++; + + return 0; +} + +static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, struct link_info *li) { + struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; struct device_node *np; + struct device_node *codec; struct asoc_simple_card_data adata; int loop; int num; @@ -602,18 +656,28 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + num = of_get_child_count(node); + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - num = of_get_child_count(node); - li->dais += num; - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - li->link += num; - li->conf++; - } else { - li->link++; + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { + asoc_simple_card_count_dpcm(priv, np, codec, + li, !loop); + } else { + asoc_simple_card_count_noml(priv, np, codec, + li, !loop); + } } node = of_get_next_child(top, node); } while (loop && node); @@ -653,8 +717,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->probe = asoc_simple_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(dev, &li); + asoc_simple_card_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -677,20 +746,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link[i].platform = &dai_props[i].platform; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = priv->dai_link; card->num_links = li.link; card->codec_conf = cconf; card->num_configs = li.conf; - card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { From c39291a76444e3177f7a89d603eae7f83fbdb9f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:28 +0900 Subject: [PATCH 032/461] ASoC: simple-card: cleanup DAI link loop method - step2 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_simple_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 174 +++++++++++++++----------------- 1 file changed, 81 insertions(+), 93 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 4987db667165..e796b1516b40 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -431,6 +431,74 @@ dai_link_of_err: return ret; } +static int asoc_simple_card_for_each_link(struct simple_card_data *priv, + struct link_info *li, + int (*func_noml)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top), + int (*func_dpcm)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top)) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct device_node *node; + bool is_top = 0; + + /* Check if it has dai-link */ + node = of_get_child_by_name(top, PREFIX "dai-link"); + if (!node) { + node = top; + is_top = 1; + } + + /* loop for all dai-link */ + do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + /* get codec */ + codec = of_get_child_by_name(node, is_top ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + /* + * It is DPCM + * if it has many CPUs, + * or has convert-xxx property + */ + if (num > 2 || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, np, codec, li, is_top); + /* else normal sound */ + else + ret = func_noml(priv, np, codec, li, is_top); + + if (ret < 0) + return ret; + } + + node = of_get_next_child(top, node); + } while (!is_top && node); + + return 0; +} + static int asoc_simple_card_parse_aux_devs(struct device_node *node, struct simple_card_data *priv) { @@ -467,9 +535,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); - struct device_node *node; struct link_info li; - int ret, loop; + int ret; if (!top) return -EINVAL; @@ -484,35 +551,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); - - /* FIXME */ - li.cpu = 1; -parse_loop: - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; - } - - do { - struct asoc_simple_card_data adata; - struct device_node *codec; - struct device_node *np; - int num = of_get_child_count(node); - int ret; - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return -ENODEV; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -525,29 +564,12 @@ parse_loop: * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - - /* loop for all CPU/Codec node */ - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - ret = asoc_simple_card_dai_link_of_dpcm( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } else { - ret = asoc_simple_card_dai_link_of( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } - } - node = of_get_next_child(top, node); - } while (loop && node); - - /* FIXME */ - li.cpu--; - if (li.cpu >= 0) - goto parse_loop; + ret = asoc_simple_card_for_each_link(priv, &li, + asoc_simple_card_dai_link_of, + asoc_simple_card_dai_link_of_dpcm); + if (ret < 0) + return ret; + } ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) @@ -588,12 +610,6 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; - int loop; - int num; /* * link_num : number of links. @@ -648,39 +664,11 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - asoc_simple_card_count_dpcm(priv, np, codec, - li, !loop); - } else { - asoc_simple_card_count_noml(priv, np, codec, - li, !loop); - } - } - node = of_get_next_child(top, node); - } while (loop && node); + asoc_simple_card_for_each_link(priv, li, + asoc_simple_card_count_noml, + asoc_simple_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_simple_soc_card_probe(struct snd_soc_card *card) From 2d01a84605a55cf07ea9c6886049cc85c5e98454 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:34 +0900 Subject: [PATCH 033/461] ASoC: simple-card: reduce naming prefix Current simple-card is using asoc_simple_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_simple_card_xxx() to simple_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 157 ++++++++++++++++---------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e796b1516b40..479de236e694 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -15,7 +15,7 @@ #include #include -struct simple_card_data { +struct simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { struct asoc_simple_dai *cpu_dai; @@ -49,10 +49,10 @@ struct link_info { #define CELL "#sound-dai-cells" #define PREFIX "simple-audio-card," -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) +static int simple_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -68,10 +68,10 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) +static void simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); @@ -80,8 +80,8 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai, + unsigned long rate) { if (!simple_dai) return 0; @@ -95,13 +95,13 @@ static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, return clk_set_rate(simple_dai->clk, rate); } -static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int simple_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; @@ -113,11 +113,11 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, if (mclk_fs) { mclk = params_rate(params) * mclk_fs; - ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); + ret = simple_set_clk_rate(dai_props->codec_dai, mclk); if (ret < 0) return ret; - ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); + ret = simple_set_clk_rate(dai_props->cpu_dai, mclk); if (ret < 0) return ret; @@ -136,15 +136,15 @@ err: return ret; } -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, - .hw_params = asoc_simple_card_hw_params, +static const struct snd_soc_ops simple_ops = { + .startup = simple_startup, + .shutdown = simple_shutdown, + .hw_params = simple_hw_params, }; -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int simple_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -161,10 +161,10 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -172,9 +172,9 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_simple_card_get_conversion(struct device *dev, - struct device_node *np, - struct asoc_simple_card_data *adata) +static void simple_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); @@ -187,11 +187,11 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -264,7 +264,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = simple_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -295,7 +295,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, "prefix"); } - asoc_simple_card_get_conversion(dev, np, &dai_props->adata); + simple_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) @@ -317,17 +317,17 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; return 0; } -static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -420,8 +420,8 @@ static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, if (ret < 0) goto dai_link_of_err; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); @@ -431,13 +431,13 @@ dai_link_of_err: return ret; } -static int asoc_simple_card_for_each_link(struct simple_card_data *priv, +static int simple_for_each_link(struct simple_priv *priv, struct link_info *li, - int (*func_noml)(struct simple_card_data *priv, + int (*func_noml)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top), - int (*func_dpcm)(struct simple_card_data *priv, + int (*func_dpcm)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top)) @@ -473,7 +473,7 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); + simple_get_conversion(dev, np, &adata); /* loop for all CPU/Codec node */ for_each_child_of_node(node, np) { @@ -499,8 +499,8 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_parse_aux_devs(struct device_node *node, - struct simple_card_data *priv) +static int simple_parse_aux_devs(struct device_node *node, + struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *aux_node; @@ -530,7 +530,7 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } -static int asoc_simple_card_parse_of(struct simple_card_data *priv) +static int simple_parse_of(struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -564,9 +564,9 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_simple_card_for_each_link(priv, &li, - asoc_simple_card_dai_link_of, - asoc_simple_card_dai_link_of_dpcm); + ret = simple_for_each_link(priv, &li, + simple_dai_link_of, + simple_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -575,15 +575,15 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (ret < 0) return ret; - ret = asoc_simple_card_parse_aux_devs(top, priv); + ret = simple_parse_aux_devs(top, priv); return ret; } -static int asoc_simple_card_count_noml(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_noml(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ if (np != codec) @@ -592,10 +592,10 @@ static int asoc_simple_card_count_noml(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ li->link++; /* CPU-dummy or dummy-Codec */ @@ -605,8 +605,8 @@ static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, return 0; } -static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, - struct link_info *li) +static void simple_get_dais_count(struct simple_priv *priv, + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -664,16 +664,17 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - asoc_simple_card_for_each_link(priv, li, - asoc_simple_card_count_noml, - asoc_simple_card_count_dpcm); + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_simple_soc_card_probe(struct snd_soc_card *card) +static int simple_soc_probe(struct snd_soc_card *card) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(card); + struct simple_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); @@ -687,9 +688,9 @@ static int asoc_simple_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_simple_card_probe(struct platform_device *pdev) +static int simple_probe(struct platform_device *pdev) { - struct simple_card_data *priv; + struct simple_priv *priv; struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -708,10 +709,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card = simple_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->probe = asoc_simple_soc_card_probe; + card->probe = simple_soc_probe; memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(priv, &li); + simple_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -746,7 +747,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(priv); + ret = simple_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -789,7 +790,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->stream_name = cinfo->name; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; - dai_link->init = asoc_simple_card_dai_init; + dai_link->init = simple_dai_init; memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, sizeof(*priv->dai_props->cpu_dai)); memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, @@ -809,28 +810,28 @@ err: return ret; } -static int asoc_simple_card_remove(struct platform_device *pdev) +static int simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_simple_of_match[] = { +static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, { .compatible = "simple-scu-audio-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); +MODULE_DEVICE_TABLE(of, simple_of_match); static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, + .of_match_table = simple_of_match, }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, + .probe = simple_probe, + .remove = simple_remove, }; module_platform_driver(asoc_simple_card); From c32759035ad246d3e4c65d23a07f9e6ba32caeaf Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Fri, 21 Dec 2018 00:36:35 +0900 Subject: [PATCH 034/461] ASoC: rockchip: support ACODEC for rk3328 This patch adds support for audio CODEC core of rk3328. Rockchip does not publish detail specification of this core but driver source code is opened on their GitHub repository. https://github.com/rockchip-linux/kernel So I ported this code to linux-next and added some trivial fixes. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- .../bindings/sound/rockchip,rk3328-codec.txt | 23 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rk3328_codec.c | 517 ++++++++++++++++++ sound/soc/codecs/rk3328_codec.h | 210 +++++++ 5 files changed, 757 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt create mode 100644 sound/soc/codecs/rk3328_codec.c create mode 100644 sound/soc/codecs/rk3328_codec.h diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt new file mode 100644 index 000000000000..2469588c7ccb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt @@ -0,0 +1,23 @@ +* Rockchip Rk3328 internal codec + +Required properties: + +- compatible: "rockchip,rk3328-codec" +- reg: physical base address of the controller and length of memory mapped + region. +- rockchip,grf: the phandle of the syscon node for GRF register. +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should be "pclk". +- spk-depop-time-ms: speak depop time msec. + +Example for rk3328 internal codec: + +codec: codec@ff410000 { + compatible = "rockchip,rk3328-codec"; + reg = <0x0 0xff410000 0x0 0x1000>; + rockchip,grf = <&grf>; + clocks = <&cru PCLK_ACODEC>; + clock-names = "pclk"; + spk-depop-time-ms = 100; + status = "disabled"; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d46de3e04ff6..87cb9c51e6f5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -130,6 +130,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM5102A select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_RK3328 select SND_SOC_RT274 if I2C select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C @@ -806,6 +807,10 @@ config SND_SOC_PCM512x_SPI select SND_SOC_PCM512x select REGMAP_SPI +config SND_SOC_RK3328 + tristate "Rockchip RK3328 audio CODEC" + select REGMAP_MMIO + config SND_SOC_RL6231 tristate default y if SND_SOC_RT5514=y diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fbe36e6177b0..9bb3346fab2f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -133,6 +133,7 @@ snd-soc-pcm5102a-objs := pcm5102a.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-rk3328-objs := rk3328_codec.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1305-objs := rt1305.o @@ -400,6 +401,7 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c new file mode 100644 index 000000000000..71f3fc2d970c --- /dev/null +++ b/sound/soc/codecs/rk3328_codec.c @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rk3328 ALSA SoC Audio driver +// +// Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk3328_codec.h" + +/* + * volume setting + * 0: -39dB + * 26: 0dB + * 31: 6dB + * Step: 1.5dB + */ +#define OUT_VOLUME (0x18) +#define RK3328_GRF_SOC_CON2 (0x0408) +#define RK3328_GRF_SOC_CON10 (0x0428) +#define INITIAL_FREQ (11289600) + +struct rk3328_codec_priv { + struct regmap *regmap; + struct regmap *grf; + struct clk *mclk; + struct clk *pclk; + unsigned int sclk; + int spk_depop_time; /* msec */ +}; + +static const struct reg_default rk3328_codec_reg_defaults[] = { + { CODEC_RESET, 0x03 }, + { DAC_INIT_CTRL1, 0x00 }, + { DAC_INIT_CTRL2, 0x50 }, + { DAC_INIT_CTRL3, 0x0e }, + { DAC_PRECHARGE_CTRL, 0x01 }, + { DAC_PWR_CTRL, 0x00 }, + { DAC_CLK_CTRL, 0x00 }, + { HPMIX_CTRL, 0x00 }, + { HPOUT_CTRL, 0x00 }, + { HPOUTL_GAIN_CTRL, 0x00 }, + { HPOUTR_GAIN_CTRL, 0x00 }, + { HPOUT_POP_CTRL, 0x11 }, +}; + +static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328) +{ + regmap_write(rk3328->regmap, CODEC_RESET, 0x00); + mdelay(10); + regmap_write(rk3328->regmap, CODEC_RESET, 0x03); + + return 0; +} + +static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1, + PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + val = DAC_MODE_PCM; + break; + case SND_SOC_DAIFMT_I2S: + val = DAC_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = DAC_MODE_RJM; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = DAC_MODE_LJM; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, + DAC_MODE_MASK, val); + + return 0; +} + +static void rk3328_analog_output(struct rk3328_codec_priv *rk3328, int mute) +{ + unsigned int val = BIT(17); + + if (mute) + val |= BIT(1); + + regmap_write(rk3328->grf, RK3328_GRF_SOC_CON10, val); +} + +static int rk3328_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + if (mute) + val = HPOUTL_MUTE | HPOUTR_MUTE; + else + val = HPOUTL_UNMUTE | HPOUTR_UNMUTE; + + regmap_update_bits(rk3328->regmap, HPOUT_CTRL, + HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val); + + return 0; +} + +static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms) +{ + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE); + mdelay(10); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_ALL_ON); + mdelay(wait_ms); + + return 0; +} + +static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms) +{ + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE); + mdelay(10); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_ALL_ON); + mdelay(wait_ms); + + return 0; +} + +static const struct rk3328_reg_msk_val playback_open_list[] = { + { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON }, + { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, + DACL_PATH_REFV_ON | DACR_PATH_REFV_ON }, + { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK, + HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON }, + { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, + HPOUTR_POP_WORK | HPOUTL_POP_WORK }, + { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN }, + { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, + HPMIXL_INIT_EN | HPMIXR_INIT_EN }, + { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN }, + { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, + HPOUTL_INIT_EN | HPOUTR_INIT_EN }, + { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, + DACL_REFV_ON | DACR_REFV_ON }, + { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, + DACL_CLK_ON | DACR_CLK_ON }, + { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON }, + { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, + DACL_INIT_ON | DACR_INIT_ON }, + { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, + DACL_SELECT | DACR_SELECT }, + { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, + HPMIXL_INIT2_EN | HPMIXR_INIT2_EN }, + { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, + HPOUTL_UNMUTE | HPOUTR_UNMUTE }, +}; + +static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328) +{ + int i; + + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_I); + + for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) { + regmap_update_bits(rk3328->regmap, + playback_open_list[i].reg, + playback_open_list[i].msk, + playback_open_list[i].val); + mdelay(1); + } + + msleep(rk3328->spk_depop_time); + rk3328_analog_output(rk3328, 1); + + regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, + HPOUTL_GAIN_MASK, OUT_VOLUME); + regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, + HPOUTR_GAIN_MASK, OUT_VOLUME); + + return 0; +} + +static const struct rk3328_reg_msk_val playback_close_list[] = { + { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, + HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS }, + { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, + DACL_UNSELECT | DACR_UNSELECT }, + { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, + HPOUTL_MUTE | HPOUTR_MUTE }, + { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, + HPOUTL_INIT_DIS | HPOUTR_INIT_DIS }, + { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS }, + { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS }, + { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF }, + { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, + DACL_CLK_OFF | DACR_CLK_OFF }, + { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, + DACL_REFV_OFF | DACR_REFV_OFF }, + { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, + HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE }, + { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, + DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF }, + { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF }, + { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, + HPMIXL_INIT_DIS | HPMIXR_INIT_DIS }, + { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, + DACL_INIT_OFF | DACR_INIT_OFF }, +}; + +static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328) +{ + size_t i; + + rk3328_analog_output(rk3328, 0); + + regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, + HPOUTL_GAIN_MASK, 0); + regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, + HPOUTR_GAIN_MASK, 0); + + for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) { + regmap_update_bits(rk3328->regmap, + playback_close_list[i].reg, + playback_close_list[i].msk, + playback_close_list[i].val); + mdelay(1); + } + + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_I); + + return 0; +} + +static int rk3328_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val = DAC_VDL_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val = DAC_VDL_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = DAC_VDL_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val = DAC_VDL_32BITS; + break; + default: + return -EINVAL; + } + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val); + + val = DAC_WL_32BITS | DAC_RST_DIS; + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3, + DAC_WL_MASK | DAC_RST_MASK, val); + + return 0; +} + +static int rk3328_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + + return rk3328_codec_open_playback(rk3328); +} + +static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + + rk3328_codec_close_playback(rk3328); +} + +static const struct snd_soc_dai_ops rk3328_dai_ops = { + .hw_params = rk3328_hw_params, + .set_fmt = rk3328_set_dai_fmt, + .digital_mute = rk3328_digital_mute, + .startup = rk3328_pcm_startup, + .shutdown = rk3328_pcm_shutdown, +}; + +static struct snd_soc_dai_driver rk3328_dai[] = { + { + .name = "rk3328-hifi", + .id = RK3328_HIFI, + .playback = { + .stream_name = "HIFI Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "HIFI Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &rk3328_dai_ops, + }, +}; + +static int rk3328_codec_probe(struct snd_soc_component *component) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(component); + + rk3328_codec_reset(rk3328); + rk3328_codec_power_on(rk3328, 0); + + return 0; +} + +static void rk3328_codec_remove(struct snd_soc_component *component) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(component); + + rk3328_codec_close_playback(rk3328); + rk3328_codec_power_off(rk3328, 0); +} + +static const struct snd_soc_component_driver soc_codec_rk3328 = { + .probe = rk3328_codec_probe, + .remove = rk3328_codec_remove, +}; + +static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CODEC_RESET: + case DAC_INIT_CTRL1: + case DAC_INIT_CTRL2: + case DAC_INIT_CTRL3: + case DAC_PRECHARGE_CTRL: + case DAC_PWR_CTRL: + case DAC_CLK_CTRL: + case HPMIX_CTRL: + case DAC_SELECT: + case HPOUT_CTRL: + case HPOUTL_GAIN_CTRL: + case HPOUTR_GAIN_CTRL: + case HPOUT_POP_CTRL: + return true; + default: + return false; + } +} + +static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CODEC_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_config rk3328_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = HPOUT_POP_CTRL, + .writeable_reg = rk3328_codec_write_read_reg, + .readable_reg = rk3328_codec_write_read_reg, + .volatile_reg = rk3328_codec_volatile_reg, + .reg_defaults = rk3328_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static int rk3328_platform_probe(struct platform_device *pdev) +{ + struct device_node *rk3328_np = pdev->dev.of_node; + struct rk3328_codec_priv *rk3328; + struct resource *res; + struct regmap *grf; + void __iomem *base; + int ret = 0; + + rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL); + if (!rk3328) + return -ENOMEM; + + grf = syscon_regmap_lookup_by_phandle(rk3328_np, + "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, "missing 'rockchip,grf'\n"); + return PTR_ERR(grf); + } + rk3328->grf = grf; + /* enable i2s_acodec_en */ + regmap_write(grf, RK3328_GRF_SOC_CON2, + (BIT(14) << 16 | BIT(14))); + + ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms", + &rk3328->spk_depop_time); + if (ret < 0) { + dev_info(&pdev->dev, "spk_depop_time use default value.\n"); + rk3328->spk_depop_time = 200; + } + + rk3328_analog_output(rk3328, 0); + + rk3328->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(rk3328->mclk)) + return PTR_ERR(rk3328->mclk); + + ret = clk_prepare_enable(rk3328->mclk); + if (ret) + return ret; + clk_set_rate(rk3328->mclk, INITIAL_FREQ); + + rk3328->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(rk3328->pclk)) { + dev_err(&pdev->dev, "can't get acodec pclk\n"); + return PTR_ERR(rk3328->pclk); + } + + ret = clk_prepare_enable(rk3328->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable acodec pclk\n"); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &rk3328_codec_regmap_config); + if (IS_ERR(rk3328->regmap)) + return PTR_ERR(rk3328->regmap); + + platform_set_drvdata(pdev, rk3328); + + return devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328, + rk3328_dai, + ARRAY_SIZE(rk3328_dai)); +} + +static const struct of_device_id rk3328_codec_of_match[] = { + { .compatible = "rockchip,rk3328-codec", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rk3328_codec_of_match); + +static struct platform_driver rk3328_codec_driver = { + .driver = { + .name = "rk3328-codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rk3328_codec_of_match), + }, + .probe = rk3328_platform_probe, +}; +module_platform_driver(rk3328_codec_driver); + +MODULE_AUTHOR("Sugar Zhang "); +MODULE_DESCRIPTION("ASoC rk3328 codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rk3328_codec.h b/sound/soc/codecs/rk3328_codec.h new file mode 100644 index 000000000000..655103586241 --- /dev/null +++ b/sound/soc/codecs/rk3328_codec.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rk3328 ALSA SoC Audio driver + * + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + */ + +#ifndef _RK3328_CODEC_H +#define _RK3328_CODEC_H + +#include + +/* codec register */ +#define CODEC_RESET (0x00 << 2) +#define DAC_INIT_CTRL1 (0x03 << 2) +#define DAC_INIT_CTRL2 (0x04 << 2) +#define DAC_INIT_CTRL3 (0x05 << 2) +#define DAC_PRECHARGE_CTRL (0x22 << 2) +#define DAC_PWR_CTRL (0x23 << 2) +#define DAC_CLK_CTRL (0x24 << 2) +#define HPMIX_CTRL (0x25 << 2) +#define DAC_SELECT (0x26 << 2) +#define HPOUT_CTRL (0x27 << 2) +#define HPOUTL_GAIN_CTRL (0x28 << 2) +#define HPOUTR_GAIN_CTRL (0x29 << 2) +#define HPOUT_POP_CTRL (0x2a << 2) + +/* REG00: CODEC_RESET */ +#define PWR_RST_BYPASS_DIS (0x0 << 6) +#define PWR_RST_BYPASS_EN (0x1 << 6) +#define DIG_CORE_RST (0x0 << 1) +#define DIG_CORE_WORK (0x1 << 1) +#define SYS_RST (0x0 << 0) +#define SYS_WORK (0x1 << 0) + +/* REG03: DAC_INIT_CTRL1 */ +#define PIN_DIRECTION_MASK BIT(5) +#define PIN_DIRECTION_IN (0x0 << 5) +#define PIN_DIRECTION_OUT (0x1 << 5) +#define DAC_I2S_MODE_MASK BIT(4) +#define DAC_I2S_MODE_SLAVE (0x0 << 4) +#define DAC_I2S_MODE_MASTER (0x1 << 4) + +/* REG04: DAC_INIT_CTRL2 */ +#define DAC_I2S_LRP_MASK BIT(7) +#define DAC_I2S_LRP_NORMAL (0x0 << 7) +#define DAC_I2S_LRP_REVERSAL (0x1 << 7) +#define DAC_VDL_MASK GENMASK(6, 5) +#define DAC_VDL_16BITS (0x0 << 5) +#define DAC_VDL_20BITS (0x1 << 5) +#define DAC_VDL_24BITS (0x2 << 5) +#define DAC_VDL_32BITS (0x3 << 5) +#define DAC_MODE_MASK GENMASK(4, 3) +#define DAC_MODE_RJM (0x0 << 3) +#define DAC_MODE_LJM (0x1 << 3) +#define DAC_MODE_I2S (0x2 << 3) +#define DAC_MODE_PCM (0x3 << 3) +#define DAC_LR_SWAP_MASK BIT(2) +#define DAC_LR_SWAP_DIS (0x0 << 2) +#define DAC_LR_SWAP_EN (0x1 << 2) + +/* REG05: DAC_INIT_CTRL3 */ +#define DAC_WL_MASK GENMASK(3, 2) +#define DAC_WL_16BITS (0x0 << 2) +#define DAC_WL_20BITS (0x1 << 2) +#define DAC_WL_24BITS (0x2 << 2) +#define DAC_WL_32BITS (0x3 << 2) +#define DAC_RST_MASK BIT(1) +#define DAC_RST_EN (0x0 << 1) +#define DAC_RST_DIS (0x1 << 1) +#define DAC_BCP_MASK BIT(0) +#define DAC_BCP_NORMAL (0x0 << 0) +#define DAC_BCP_REVERSAL (0x1 << 0) + +/* REG22: DAC_PRECHARGE_CTRL */ +#define DAC_CHARGE_XCHARGE_MASK BIT(7) +#define DAC_CHARGE_DISCHARGE (0x0 << 7) +#define DAC_CHARGE_PRECHARGE (0x1 << 7) +#define DAC_CHARGE_CURRENT_64I_MASK BIT(6) +#define DAC_CHARGE_CURRENT_64I (0x1 << 6) +#define DAC_CHARGE_CURRENT_32I_MASK BIT(5) +#define DAC_CHARGE_CURRENT_32I (0x1 << 5) +#define DAC_CHARGE_CURRENT_16I_MASK BIT(4) +#define DAC_CHARGE_CURRENT_16I (0x1 << 4) +#define DAC_CHARGE_CURRENT_08I_MASK BIT(3) +#define DAC_CHARGE_CURRENT_08I (0x1 << 3) +#define DAC_CHARGE_CURRENT_04I_MASK BIT(2) +#define DAC_CHARGE_CURRENT_04I (0x1 << 2) +#define DAC_CHARGE_CURRENT_02I_MASK BIT(1) +#define DAC_CHARGE_CURRENT_02I (0x1 << 1) +#define DAC_CHARGE_CURRENT_I_MASK BIT(0) +#define DAC_CHARGE_CURRENT_I (0x1 << 0) +#define DAC_CHARGE_CURRENT_ALL_MASK GENMASK(6, 0) +#define DAC_CHARGE_CURRENT_ALL_OFF 0x00 +#define DAC_CHARGE_CURRENT_ALL_ON 0x7f + +/* REG23: DAC_PWR_CTRL */ +#define DAC_PWR_MASK BIT(6) +#define DAC_PWR_OFF (0x0 << 6) +#define DAC_PWR_ON (0x1 << 6) +#define DACL_PATH_REFV_MASK BIT(5) +#define DACL_PATH_REFV_OFF (0x0 << 5) +#define DACL_PATH_REFV_ON (0x1 << 5) +#define HPOUTL_ZERO_CROSSING_MASK BIT(4) +#define HPOUTL_ZERO_CROSSING_OFF (0x0 << 4) +#define HPOUTL_ZERO_CROSSING_ON (0x1 << 4) +#define DACR_PATH_REFV_MASK BIT(1) +#define DACR_PATH_REFV_OFF (0x0 << 1) +#define DACR_PATH_REFV_ON (0x1 << 1) +#define HPOUTR_ZERO_CROSSING_MASK BIT(0) +#define HPOUTR_ZERO_CROSSING_OFF (0x0 << 0) +#define HPOUTR_ZERO_CROSSING_ON (0x1 << 0) + +/* REG24: DAC_CLK_CTRL */ +#define DACL_REFV_MASK BIT(7) +#define DACL_REFV_OFF (0x0 << 7) +#define DACL_REFV_ON (0x1 << 7) +#define DACL_CLK_MASK BIT(6) +#define DACL_CLK_OFF (0x0 << 6) +#define DACL_CLK_ON (0x1 << 6) +#define DACL_MASK BIT(5) +#define DACL_OFF (0x0 << 5) +#define DACL_ON (0x1 << 5) +#define DACL_INIT_MASK BIT(4) +#define DACL_INIT_OFF (0x0 << 4) +#define DACL_INIT_ON (0x1 << 4) +#define DACR_REFV_MASK BIT(3) +#define DACR_REFV_OFF (0x0 << 3) +#define DACR_REFV_ON (0x1 << 3) +#define DACR_CLK_MASK BIT(2) +#define DACR_CLK_OFF (0x0 << 2) +#define DACR_CLK_ON (0x1 << 2) +#define DACR_MASK BIT(1) +#define DACR_OFF (0x0 << 1) +#define DACR_ON (0x1 << 1) +#define DACR_INIT_MASK BIT(0) +#define DACR_INIT_OFF (0x0 << 0) +#define DACR_INIT_ON (0x1 << 0) + +/* REG25: HPMIX_CTRL*/ +#define HPMIXL_MASK BIT(6) +#define HPMIXL_DIS (0x0 << 6) +#define HPMIXL_EN (0x1 << 6) +#define HPMIXL_INIT_MASK BIT(5) +#define HPMIXL_INIT_DIS (0x0 << 5) +#define HPMIXL_INIT_EN (0x1 << 5) +#define HPMIXL_INIT2_MASK BIT(4) +#define HPMIXL_INIT2_DIS (0x0 << 4) +#define HPMIXL_INIT2_EN (0x1 << 4) +#define HPMIXR_MASK BIT(2) +#define HPMIXR_DIS (0x0 << 2) +#define HPMIXR_EN (0x1 << 2) +#define HPMIXR_INIT_MASK BIT(1) +#define HPMIXR_INIT_DIS (0x0 << 1) +#define HPMIXR_INIT_EN (0x1 << 1) +#define HPMIXR_INIT2_MASK BIT(0) +#define HPMIXR_INIT2_DIS (0x0 << 0) +#define HPMIXR_INIT2_EN (0x1 << 0) + +/* REG26: DAC_SELECT */ +#define DACL_SELECT_MASK BIT(4) +#define DACL_UNSELECT (0x0 << 4) +#define DACL_SELECT (0x1 << 4) +#define DACR_SELECT_MASK BIT(0) +#define DACR_UNSELECT (0x0 << 0) +#define DACR_SELECT (0x1 << 0) + +/* REG27: HPOUT_CTRL */ +#define HPOUTL_MASK BIT(7) +#define HPOUTL_DIS (0x0 << 7) +#define HPOUTL_EN (0x1 << 7) +#define HPOUTL_INIT_MASK BIT(6) +#define HPOUTL_INIT_DIS (0x0 << 6) +#define HPOUTL_INIT_EN (0x1 << 6) +#define HPOUTL_MUTE_MASK BIT(5) +#define HPOUTL_MUTE (0x0 << 5) +#define HPOUTL_UNMUTE (0x1 << 5) +#define HPOUTR_MASK BIT(4) +#define HPOUTR_DIS (0x0 << 4) +#define HPOUTR_EN (0x1 << 4) +#define HPOUTR_INIT_MASK BIT(3) +#define HPOUTR_INIT_DIS (0x0 << 3) +#define HPOUTR_INIT_EN (0x1 << 3) +#define HPOUTR_MUTE_MASK BIT(2) +#define HPOUTR_MUTE (0x0 << 2) +#define HPOUTR_UNMUTE (0x1 << 2) + +/* REG28: HPOUTL_GAIN_CTRL */ +#define HPOUTL_GAIN_MASK GENMASK(4, 0) + +/* REG29: HPOUTR_GAIN_CTRL */ +#define HPOUTR_GAIN_MASK GENMASK(4, 0) + +/* REG2a: HPOUT_POP_CTRL */ +#define HPOUTR_POP_MASK GENMASK(5, 4) +#define HPOUTR_POP_XCHARGE (0x1 << 4) +#define HPOUTR_POP_WORK (0x2 << 4) +#define HPOUTL_POP_MASK GENMASK(1, 0) +#define HPOUTL_POP_XCHARGE (0x1 << 0) +#define HPOUTL_POP_WORK (0x2 << 0) + +#define RK3328_HIFI 0 + +struct rk3328_reg_msk_val { + unsigned int reg; + unsigned int msk; + unsigned int val; +}; + +#endif From f5758544d98c8bec7793aeea28928f5e8bd45d47 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Fri, 21 Dec 2018 00:36:36 +0900 Subject: [PATCH 035/461] ASoC: rockchip: add workaround for silence of rk3288 ACODEC This patch adds reset and precharge in shutdown of PCM device. ACODEC goes to silence if we change Fs to 44.1kHz from 48kHz. This workaround seems to work but I don't know this workaround is correct sequence or not for ACODEC. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 71f3fc2d970c..f3442a2283ea 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -261,9 +261,12 @@ static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328) mdelay(1); } + /* Workaround for silence when changed Fs 48 -> 44.1kHz */ + rk3328_codec_reset(rk3328); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, DAC_CHARGE_CURRENT_ALL_MASK, - DAC_CHARGE_CURRENT_I); + DAC_CHARGE_CURRENT_ALL_ON); return 0; } From 1d38b4e903d577f05393eb0ac6727f40d90dd6c6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 26 Dec 2018 15:11:06 -0600 Subject: [PATCH 036/461] ASoC: xlnx: fix error handling in xlnx_formatter_pcm_probe Currently, if platform_get_irq_byname() fails, the returned error turns into a huge value, once it is being store into a variable of type unsigned int, hence never actually reporting any error and causing unexpected behavior when using the values stored in aud_drv_data->s2mm_irq and aud_drv_data->mm2s_irq. Fix this by changing the type of variables s2mm_irq and mm2s_irq in structure xlnx_pcm_drv_data from unsigned int to int. Addresses-Coverity-ID: 1476096 ("Unsigned compared against 0") Fixes: 796175a94a7f ("ASoC: xlnx: add pcm formatter platform driver") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index f7235f7664d7..d2194da928e7 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -76,8 +76,8 @@ struct xlnx_pcm_drv_data { void __iomem *mmio; bool s2mm_presence; bool mm2s_presence; - unsigned int s2mm_irq; - unsigned int mm2s_irq; + int s2mm_irq; + int mm2s_irq; struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; struct clk *axi_clk; From e1de3d237b5083fcd0da6fcf600848a4cef9cc67 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 25 Dec 2018 02:20:36 +0000 Subject: [PATCH 037/461] ASoC: rockchip: fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index f3442a2283ea..24f8f86d58e9 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -508,7 +508,6 @@ MODULE_DEVICE_TABLE(of, rk3328_codec_of_match); static struct platform_driver rk3328_codec_driver = { .driver = { .name = "rk3328-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rk3328_codec_of_match), }, .probe = rk3328_platform_probe, From 822257661031faa437336058d8a32bf1844ad9c6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:26 +0100 Subject: [PATCH 038/461] ASoC: es8316: Add jack-detect support Adding jack-detect support may seem weird for a codec with only a single output, but it is necessary. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. In order to enable/disable the speakers at the right time, we need jack-detect. The same goes for the microphone where we must correctly set the mux for the single ADC to either the internal or the headset microphone. All devices I have support the es8316's builtin jack-detect functionality. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 195 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/es8316.h | 7 ++ 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e97d12d578b0..26413851e434 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "es8316.h" /* In slave mode at single speed, the codec is documented as accepting 5 @@ -33,6 +35,11 @@ static const unsigned int supported_mclk_lrck_ratios[] = { }; struct es8316_priv { + struct mutex lock; + struct regmap *regmap; + struct snd_soc_component *component; + struct snd_soc_jack *jack; + int irq; unsigned int sysclk; unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; struct snd_pcm_hw_constraint_list sysclk_constraints; @@ -529,8 +536,162 @@ static struct snd_soc_dai_driver es8316_dai = { .symmetric_rates = 1, }; +static void es8316_enable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); + + msleep(20); +} + +static void es8316_disable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static irqreturn_t es8316_irq(int irq, void *data) +{ + struct es8316_priv *es8316 = data; + struct snd_soc_component *comp = es8316->component; + unsigned int flags; + + mutex_lock(&es8316->lock); + + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + if (flags == 0x00) + goto out; /* Powered-down / reset */ + + /* Catch spurious IRQ before set_jack is called */ + if (!es8316->jack) + goto out; + + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack removed, or spurious IRQ? */ + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + + if (es8316->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8316->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + dev_dbg(comp->dev, "jack unplugged\n"); + } + } else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted, determine type */ + es8316_enable_micbias_for_mic_gnd_short_detect(comp); + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack unplugged underneath us */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, headset */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADSET, + SND_JACK_HEADSET); + /* Keep mic-gnd-short detection on for button press */ + } else { + /* Shorted, headphones */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + /* No longer need mic-gnd-short detection */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } + } else if (es8316->jack->status & SND_JACK_MICROPHONE) { + /* Interrupt while jack inserted, report button state */ + if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, button release */ + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } else { + /* Short, button press */ + snd_soc_jack_report(es8316->jack, + SND_JACK_BTN_0, + SND_JACK_BTN_0); + } + } + +out: + mutex_unlock(&es8316->lock); + return IRQ_HANDLED; +} + +static void es8316_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8316->lock); + + es8316->jack = jack; + + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + + mutex_unlock(&es8316->lock); + + /* Enable irq and sync initial jack state */ + enable_irq(es8316->irq); + es8316_irq(es8316->irq, es8316); +} + +static void es8316_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + disable_irq(es8316->irq); + + mutex_lock(&es8316->lock); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, 0); + + if (es8316->jack->status & SND_JACK_MICROPHONE) { + es8316_disable_micbias_for_mic_gnd_short_detect(component); + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } + + es8316->jack = NULL; + + mutex_unlock(&es8316->lock); +} + +static int es8316_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8316_enable_jack_detect(component, jack); + else + es8316_disable_jack_detect(component); + + return 0; +} + static int es8316_probe(struct snd_soc_component *component) { + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + es8316->component = component; + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -555,6 +716,7 @@ static int es8316_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), .dapm_widgets = es8316_dapm_widgets, @@ -566,18 +728,29 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .non_legacy_dai_naming = 1, }; +static const struct regmap_range es8316_volatile_ranges[] = { + regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG), +}; + +static const struct regmap_access_table es8316_volatile_table = { + .yes_ranges = es8316_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges), +}; + static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = 0x53, + .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, }; static int es8316_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; - struct regmap *regmap; + int ret; es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv), GFP_KERNEL); @@ -586,9 +759,23 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, es8316); - regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); + if (IS_ERR(es8316->regmap)) + return PTR_ERR(es8316->regmap); + + es8316->irq = i2c_client->irq; + mutex_init(&es8316->lock); + + ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "es8316", es8316); + if (ret == 0) { + /* Gets re-enabled by es8316_set_jack() */ + disable_irq(es8316->irq); + } else { + dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret); + es8316->irq = -ENXIO; + } return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_es8316, diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h index 6bcdd63ea459..439a0130cbb7 100644 --- a/sound/soc/codecs/es8316.h +++ b/sound/soc/codecs/es8316.h @@ -126,4 +126,11 @@ #define ES8316_SERDATA2_LEN_16 0x0c #define ES8316_SERDATA2_LEN_32 0x10 +/* ES8316_GPIO_DEBOUNCE */ +#define ES8316_GPIO_ENABLE_INTERRUPT 0x02 + +/* ES8316_GPIO_FLAG */ +#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02 +#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04 + #endif From 24b53f17a3f24967b8b523243f9f7fc361427119 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:27 +0100 Subject: [PATCH 039/461] ASoC: es8316: Add DAC mono mix switch mixer control Export the DAC functionality to mix left + right together and then output the same (mixed) signal on both outputs. Various (x86) tablets with an ES8316 codec use a single speaker connected between the headhpone LOUT and ROUT pins, expecting the output to be in a mono differential mode. Presumably this is done to use the power of both the left and right outputs to allow the speaker to be louder. The ES8316 codec does not have a differential output mode, but we can emulate this by making both channels output the same through the mono mix switch, combined with setting the Playback Polarity control to "R Invert", which applias a 180 degrees phase inversion to the right channel. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 26413851e434..98464ba1046c 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -101,6 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0), SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0), SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0), + SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0), SOC_ENUM("Capture Polarity", adcpol), SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0), From 6ca382c4363d6c636200ccdd9ac95f44b1a498ea Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:28 +0100 Subject: [PATCH 040/461] ASoC: Intel: bytcht_es8316: Sort includes alphabetically For lack of a better (non-random) way of sorting includes more and more files in the kernel are moving over to sorting the includes alphabetically. Move the bytcht_es8316 driver over to this sorting before we add a bunch of more includes. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index adc26dfc7d65..5d8ecc100766 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,13 +19,13 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include +#include #include #include #include -#include #include #include -#include #include #include #include From 86909c8f77c5eda17a9b5dc954849e25df1ffe0f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:29 +0100 Subject: [PATCH 041/461] ASoC: Intel: bytcht_es8316: Minor refactoring Some minor refactoring: 1) Group the code setting the card dev and prive pointers together with registering the card 2) Properly put the comment about registering the card at the place where we actually register the card and add a new comment for getting the clk 3) Add a struct device *dev helper variable (this will be used more in follow up commits) 4) Reword error message to have the same "foo failed: %d" wording as others Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 5d8ecc100766..e29f00560b00 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -237,17 +237,18 @@ static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; int i; int ret = 0; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - mach = (&pdev->dev)->platform_data; + mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { if (!strcmp(byt_cht_es8316_dais[i].codec_name, @@ -265,26 +266,25 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } - /* register the soc card */ - byt_cht_es8316_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); - - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + /* get the clock */ + priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { ret = PTR_ERR(priv->mclk); - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); + dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); return ret; } - ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + /* register the soc card */ + byt_cht_es8316_card.dev = dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } platform_set_drvdata(pdev, &byt_cht_es8316_card); - return ret; + return 0; } static struct platform_driver snd_byt_cht_es8316_mc_driver = { From 349e13862c9975c613aac9dc7fa953e70cff9d06 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:30 +0100 Subject: [PATCH 042/461] ASoC: Intel: bytcht_es8316: Add support for SSP0 (BYTCR) Add support for having the codec connected to SSP0 instead of SSP2. This is controlled through a new quirk parameter, similar to how this is done in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Bay Trail CR (cost reduced) SoCs do not have an SSP2, so we default to SSP0 there. Note the SPP0 quirk gets BIT(16) because bits 0-15 are reserved for non boolean quirks like the input-map added in a later commit in this series. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 76 ++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e29f00560b00..3358d82499a3 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,6 +39,20 @@ struct byt_cht_es8316_private { struct clk *mclk; }; +#define BYT_CHT_ES8316_SSP0 BIT(16) + +static int quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (quirk & BYT_CHT_ES8316_SSP0) + dev_info(dev, "quirk SSP0 enabled"); +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -55,7 +71,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, +}; +static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { + {"Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "Capture"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -74,10 +99,23 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + const struct snd_soc_dapm_route *custom_map; + int num_routes; int ret; card->dapm.idle_bias_off = true; + if (quirk & BYT_CHT_ES8316_SSP0) { + custom_map = byt_cht_es8316_ssp0_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); + } else { + custom_map = byt_cht_es8316_ssp2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + /* * The firmware might enable the clock at boot (this information * may or may not be reflected in the enable clock register). @@ -123,14 +161,21 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; /* The DSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (quirk & BYT_CHT_ES8316_SSP0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * Default mode for SSP configuration is TDM 4 slot, override config @@ -147,7 +192,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -232,6 +277,11 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; +static const struct x86_cpu_id baytrail_cpu_ids[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Valleyview */ + {} +}; + static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) @@ -266,6 +316,24 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* Check for BYTCR or other platform and setup quirks */ + if (x86_match_cpu(baytrail_cpu_ids) && + mach->mach_params.acpi_ipc_irq_index == 0) { + /* On BYTCR default to SSP0 */ + quirk = BYT_CHT_ES8316_SSP0; + } else { + quirk = 0; + } + if (quirk_override != -1) { + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + if (quirk & BYT_CHT_ES8316_SSP0) + byt_cht_es8316_dais[dai_index].cpu_dai_name = "ssp0-port"; + /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { From 4bf538b42933253296daf86aab7ede56b5fb97bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:31 +0100 Subject: [PATCH 043/461] ASoC: Intel: bytcht_es8316: Add jack-detect support Hookup the jack-detect support added to the codec driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 67 +++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 3358d82499a3..905dd6904710 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ struct byt_cht_es8316_private { struct clk *mclk; + struct snd_soc_jack jack; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -55,6 +58,7 @@ static void log_quirks(struct device *dev) static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), /* * The codec supports two analog microphone inputs. I have only @@ -68,6 +72,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"MIC1", NULL, "Microphone 1"}, {"MIC2", NULL, "Microphone 2"}, + {"MIC1", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -91,12 +96,25 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), SOC_DAPM_PIN_SWITCH("Microphone 2"), }; +static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { + struct snd_soc_component *codec = runtime->codec_dai->component; struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -143,6 +161,18 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) return ret; } + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + return 0; } @@ -263,6 +293,39 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int byt_cht_es8316_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_cht_es8316_resume(struct snd_soc_card *card) +{ + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_cht_es8316_card = { .name = "bytcht-es8316", .owner = THIS_MODULE, @@ -275,6 +338,8 @@ static struct snd_soc_card byt_cht_es8316_card = { .controls = byt_cht_es8316_controls, .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), .fully_routed = true, + .suspend_pre = byt_cht_es8316_suspend, + .resume_post = byt_cht_es8316_resume, }; static const struct x86_cpu_id baytrail_cpu_ids[] = { @@ -282,8 +347,6 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; -static char codec_name[SND_ACPI_I2C_ID_LEN]; - static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; From 0d3e91da0750835cfd5c16487ffb3cdd752ea53a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:32 +0100 Subject: [PATCH 044/461] ASoC: Intel: bytcht_es8316: Add external speaker mux support The ES8316 only has a single (amplified) output. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. This commit adds support for this, modelling this as a separate speaker widget / dapm pin-switch which sets the mux to drive the speakers when selected. The intend is for userspace to use the recently added jack-detect support and then automatically select either the Headphone or Speaker output based on that. Note this commit includes a workaround for an ACPI table bug which is present on 2 of the 3 devices I have, see the added comment in the code. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 98 ++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 905dd6904710..8e504fca4624 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,8 +19,11 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include +#include +#include #include #include #include @@ -40,6 +43,8 @@ struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; + struct gpio_desc *speaker_en_gpio; + bool speaker_en; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -56,7 +61,24 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0 enabled"); } +static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + + if (SND_SOC_DAPM_EVENT_ON(event)) + priv->speaker_en = true; + else + priv->speaker_en = false; + + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + + return 0; +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -67,6 +89,10 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { */ SND_SOC_DAPM_MIC("Microphone 1", NULL), SND_SOC_DAPM_MIC("Microphone 2", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + byt_cht_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { @@ -76,6 +102,14 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" supply. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, }; static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { @@ -95,6 +129,7 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { }; static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), @@ -323,6 +358,25 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) } } + /* + * Some Cherry Trail boards with an ES8316 codec have a bug in their + * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods + * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown + * that this really is a bug and the GPIO has no influence on the + * touchscreen at all. + * + * The silead.c touchscreen driver does not support runtime suspend, so + * the GPIO can only be changed underneath us during a system suspend. + * This resume() function runs from a pm complete() callback, and thus + * is guaranteed to run after the touchscreen driver/ACPI-subsys has + * brought the touchscreen back up again (and thus changed the GPIO). + * + * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when + * requesting the GPIO and we set its value here to undo any changes + * done by the touchscreen's broken _PS0 ACPI method. + */ + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + return 0; } @@ -347,12 +401,20 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; +static const struct acpi_gpio_params first_gpio = { 0, 0, false }; + +static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { + { "speaker-enable-gpios", &first_gpio, 1 }, + { }, +}; + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; + struct device *codec_dev; int dai_index = 0; int i; int ret = 0; @@ -405,12 +467,39 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; } + /* get speaker enable GPIO */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); + if (!codec_dev) + return -EPROBE_DEFER; + + devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); + priv->speaker_en_gpio = + gpiod_get_index(codec_dev, "speaker-enable", 0, + /* see comment in byt_cht_es8316_resume */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + put_device(codec_dev); + + if (IS_ERR(priv->speaker_en_gpio)) { + ret = PTR_ERR(priv->speaker_en_gpio); + switch (ret) { + case -ENOENT: + priv->speaker_en_gpio = NULL; + break; + default: + dev_err(dev, "get speaker GPIO failed: %d\n", ret); + /* fall through */ + case -EPROBE_DEFER: + return ret; + } + } + /* register the soc card */ byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { + gpiod_put(priv->speaker_en_gpio); dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } @@ -418,11 +507,20 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return 0; } +static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) +{ + struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + + gpiod_put(priv->speaker_en_gpio); + return 0; +} + static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); From 730501a91d94b652275e049e101ed44cdbfdf31b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:33 +0100 Subject: [PATCH 045/461] ASoC: Intel: bytcht_es8316: Add input-map support After adding jack-detect support we have 3 microphone input switches: "Microphone 1", "Microphone 2" and "Headset Mic". But the ES8316 has only 2 microphone inputs. In the app-note explaining how to use the codec and on the 3 boards I have one input is used for an internal microphone and one for the headset microphone. On the 2 CHT boards I have the internal mic is on on MIC1 and the headset mic is on MIC2, on the BYTCR board I have it is the other way around. This commit replaces the 2 "Microphone 1" and "Microphone 2" input switches with a single "Internal Mic" switch and adds support for selecting either possible input mapping. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 58 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8e504fca4624..941a66f94660 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,6 +47,12 @@ struct byt_cht_es8316_private { bool speaker_en; }; +enum { + BYT_CHT_ES8316_INTMIC_IN1_MAP, + BYT_CHT_ES8316_INTMIC_IN2_MAP, +}; + +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) static int quirk; @@ -57,6 +63,10 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + dev_info(dev, "quirk IN1_MAP enabled"); + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); } @@ -81,14 +91,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - - /* - * The codec supports two analog microphone inputs. I have only - * tested MIC1. A DMIC route could also potentially be added - * if such functionality is found on another platform. - */ - SND_SOC_DAPM_MIC("Microphone 1", NULL), - SND_SOC_DAPM_MIC("Microphone 2", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, byt_cht_es8316_speaker_power_event, @@ -96,10 +99,6 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { - {"MIC1", NULL, "Microphone 1"}, - {"MIC2", NULL, "Microphone 2"}, - {"MIC1", NULL, "Headset Mic"}, - {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -112,6 +111,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Speaker", NULL, "Speaker Power"}, }; +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { + {"MIC2", NULL, "Internal Mic"}, + {"MIC1", NULL, "Headset Mic"}, +}; + static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { {"Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, @@ -132,8 +141,7 @@ static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Microphone 1"), - SOC_DAPM_PIN_SWITCH("Microphone 2"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), }; static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { @@ -158,6 +166,21 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) card->dapm.idle_bias_off = true; + switch (BYT_CHT_ES8316_MAP(quirk)) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: + default: + custom_map = byt_cht_es8316_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: + custom_map = byt_cht_es8316_intmic_in2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + if (quirk & BYT_CHT_ES8316_SSP0) { custom_map = byt_cht_es8316_ssp0_map; num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); @@ -444,10 +467,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0 */ - quirk = BYT_CHT_ES8316_SSP0; + /* On BYTCR default to SSP0, internal-mic-in2-map */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; } else { - quirk = 0; + /* Others default to internal-mic-in1-map */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, From 249d2fc9e55c324dda968252ea3ad0ac21c72b8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:34 +0100 Subject: [PATCH 046/461] ASoC: Intel: bytcht_es8316: Set card long_name based on quirks Depending on the input-map and on if 1 or 2 speakers are connected, userspace needs to use a different UCM profile. Since we already deal with quirks in the kernel driver and set the input-map from the kernel, add a quirk for devices with a single / mono speaker and set the card's long_name based on the input and speaker quirks, so that userspace can use the long_name to pick the right UCM profile. This change, including how the long_name is build-up mirrors how we do this in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Note since all devices I have access to use a mono speaker setup I've chosen to default the speaker setting to mono. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 941a66f94660..cdf2061e7613 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -54,6 +54,7 @@ enum { #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) +#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) static int quirk; @@ -69,6 +70,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); + if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) + dev_info(dev, "quirk MONO_SPEAKER enabled\n"); } static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, @@ -352,6 +355,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; +static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) { @@ -433,6 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; @@ -467,11 +472,13 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0, internal-mic-in2-map */ - quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; + /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } else { - /* Others default to internal-mic-in1-map */ - quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; + /* Others default to internal-mic-in1-map, mono-speaker */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, @@ -518,6 +525,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* register the soc card */ + snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", + (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", + mic_name[BYT_CHT_ES8316_MAP(quirk)]); + byt_cht_es8316_card.long_name = long_name; byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); From 5198baf8817d7e6e0fe2f3e74ea2ead714b74d9c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:35 +0100 Subject: [PATCH 047/461] ASoC: Intel: Add ACPI match table entry for ES8316 codec on BYTCR platform Some BYTCR devices use an ES8316 codec, add an ACPI match table entry for this. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 097dc06377ba..47a90909b956 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -154,6 +154,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .sof_tplg_filename = "intel/sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_es8316", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { .id = "10EC5645", From b97205ef95efddee018061dfee14c995be08dde3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:03 +0100 Subject: [PATCH 048/461] ASoC: Intel: sst: Simplify is_byt_cr() is_byt_cr() and its usage can be simplified by returning the bool directly, instead of through a pointer. This works because the return value is just treated as bytcr = false and is not used otherwise. This patch also removes the extra check of IS_ENABLED(CONFIG_IOSF_MBI) in favor of checking iosf_mbi_available() directly. The header already takes care of returning false if the config option is not enabled. No functional change. Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 33 ++++++++++++----------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 3a95ebbfc45d..9eaac450f864 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,18 +255,15 @@ static int is_byt(void) return status; } -static int is_byt_cr(struct device *dev, bool *bytcr) +static bool is_byt_cr(struct device *dev) { int status = 0; - if (IS_ENABLED(CONFIG_IOSF_MBI)) { + if (!is_byt()) + return false; + + if (iosf_mbi_available()) { u32 bios_status; - - if (!is_byt() || !iosf_mbi_available()) { - /* bail silently */ - return status; - } - status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ MBI_REG_READ, /* 0x10 */ 0x006, /* BIOS_CONFIG */ @@ -278,15 +275,17 @@ static int is_byt_cr(struct device *dev, bool *bytcr) /* bits 26:27 mirror PMIC options */ bios_status = (bios_status >> 26) & 3; - if ((bios_status == 1) || (bios_status == 3)) - *bytcr = true; - else - dev_info(dev, "BYT-CR not detected\n"); + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); } } else { - dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } - return status; + return false; } @@ -301,7 +300,6 @@ static int sst_acpi_probe(struct platform_device *pdev) struct platform_device *plat_dev; struct sst_platform_info *pdata; unsigned int dev_id; - bool bytcr = false; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) @@ -333,10 +331,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = is_byt_cr(dev, &bytcr); - if (!(ret < 0 || !bytcr)) { - dev_info(dev, "Detected Baytrail-CR platform\n"); - + if (is_byt_cr(dev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From fee15714552dbf420264da6f88dd813b8502592b Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:06 +0100 Subject: [PATCH 049/461] ASoC: Intel: sst: Fallback to BYT-CR if IRQ 5 is missing Some devices detected as BYT-T by the PMIC-type based detection have only a single IRQ listed in the 80860F28 ACPI device. This causes -ENXIO later when attempting to get the IRQ at index 5. It turns out these devices behave more like BYT-CR devices, and using the IRQ at index 0 makes sound work correctly. This patch adds a fallback for these devices to is_byt_cr(): If there is no IRQ resource at index 5, treating the device as BYT-T is guaranteed to fail later, so we can safely treat these devices as BYT-CR without breaking any working device. Link: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143176.html Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 9eaac450f864..ae17ce4677a5 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,8 +255,9 @@ static int is_byt(void) return status; } -static bool is_byt_cr(struct device *dev) +static bool is_byt_cr(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int status = 0; if (!is_byt()) @@ -285,6 +286,17 @@ static bool is_byt_cr(struct device *dev) } else { dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } + + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; + } + return false; } @@ -331,7 +343,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (is_byt_cr(dev)) { + if (is_byt_cr(pdev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From 51a13e401a83ef37aa98c049c2c30bba885676c2 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:08 +0100 Subject: [PATCH 050/461] ASoC: Intel: bytcr_rt5640: Add quirks for ASUS MeMO Pad 7 (ME176C) Add quirks to select the correct input map, jack-detect options and channel map to make sound work on the ASUS MeMO Pad 7 (ME176C). Note: Although sound works out of the box, jack detection currently requires overriding the ACPI DSDT table. This is necessary because the rt5640 ACPI device (10EC5640) has the wrong GPIO listed as interrupt (one of the Bluetooth GPIOs). The correct GPIO is GPO2 0x0004 (listed as the first GPIO in the Intel(R) Audio Machine Driver - AMCR0F28 device). Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a22366ce33c4..ca8b4d5ff70f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -428,6 +428,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), From 2130f15d6cd9898a68dc7244084985353030514f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 14:53:45 +0200 Subject: [PATCH 051/461] ASoC: ti: davinci-mcasp: No need for IS_MODULE/BUILTIN check for pcm driver Since the platform drivers are selected by the DAI drivers (including McASP) there is no longer a need to check whether the modules are built-in or module. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index eeda6d5565bc..ee9ab58d4d0c 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2149,26 +2149,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) ret = davinci_mcasp_get_dma_type(mcasp); switch (ret) { case PCM_EDMA: -#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \ - (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ - IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM)) ret = edma_pcm_platform_register(&pdev->dev); -#else - dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n"); - ret = -EINVAL; - goto err; -#endif break; case PCM_SDMA: -#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \ - (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ - IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM)) ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL); -#else - dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n"); - ret = -EINVAL; - goto err; -#endif break; default: dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); From 4664b94c98b4f9fdd3845da41d5c65288e59c66c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 16:05:51 +0200 Subject: [PATCH 052/461] ASoC: davinci-mcasp: Document GPIO support McASP pins can be used as GPIO, add optional section to enable GPIO support for McASP. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index b279b6072bd5..a58f79f5345c 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -45,6 +45,23 @@ Optional properties: - fck_parent : Should contain a valid clock name which will be used as parent for the McASP fck +Optional GPIO support: +If any McASP pin need to be used as GPIO then the McASP node must have: +... + gpio-controller + #gpio-cells = <2>; +... + +When requesting a GPIO, the first parameter is the PIN index in McASP_P* +registers. +For example to request the AXR2 pin of mcasp8: +function-gpios = <&mcasp8 2 0>; + +Or to request the ACLKR pin of mcasp8: +function-gpios = <&mcasp8 29 0>; + +For generic gpio information, please refer to bindings/gpio/gpio.txt + Example: mcasp0: mcasp0@1d00000 { From 540f1ba7b3a5596827a3bfeaae9c5e754347c933 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 16:05:52 +0200 Subject: [PATCH 053/461] ASoC: ti: davinci-mcasp: Add support for GPIO mode of the pins All McASP pin can be configured as GPIO. Add gpiochip support for McASP and only enable it when the gpio-controller is present in the DT node. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 159 ++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 3 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index a6a470a76900..a3a67a8f0f54 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ static u32 context_regs[] = { DAVINCI_MCASP_AHCLKXCTL_REG, DAVINCI_MCASP_AHCLKRCTL_REG, DAVINCI_MCASP_PDIR_REG, + DAVINCI_MCASP_PFUNC_REG, DAVINCI_MCASP_RXMASK_REG, DAVINCI_MCASP_TXMASK_REG, DAVINCI_MCASP_RXTDM_REG, @@ -108,6 +110,10 @@ struct davinci_mcasp { /* Used for comstraint setting on the second stream */ u32 channels; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif + #ifdef CONFIG_PM struct davinci_mcasp_context context; #endif @@ -818,9 +824,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (mcasp->version < MCASP_VERSION_3) mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); - /* All PINS as McASP */ - mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); @@ -1845,6 +1848,147 @@ static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata) return offset; } +#ifdef CONFIG_GPIOLIB +static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + if (mcasp->num_serializer && offset < mcasp->num_serializer && + mcasp->serial_dir[offset] != INACTIVE_MODE) { + dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset); + return -EBUSY; + } + + /* Do not change the PIN yet */ + + return pm_runtime_get_sync(mcasp->dev); +} + +static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + /* Set the direction to input */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + + /* Set the pin as McASP pin */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + + pm_runtime_put_sync(mcasp->dev); +} + +static int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + if (value) + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + else + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); + if (!(val & BIT(offset))) { + /* Set the pin as GPIO pin */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + + /* Set the direction to output */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + } + + return 0; +} + +static void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + if (value) + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + else + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); +} + +static int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip, + unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); + if (!(val & BIT(offset))) { + /* Set the direction to input */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + + /* Set the pin as GPIO pin */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + } + + return 0; +} + +static int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG); + if (val & BIT(offset)) + return 1; + + return 0; +} + +static int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip, + unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); + if (val & BIT(offset)) + return 0; + + return 1; +} + +static const struct gpio_chip davinci_mcasp_template_chip = { + .owner = THIS_MODULE, + .request = davinci_mcasp_gpio_request, + .free = davinci_mcasp_gpio_free, + .direction_output = davinci_mcasp_gpio_direction_out, + .set = davinci_mcasp_gpio_set, + .direction_input = davinci_mcasp_gpio_direction_in, + .get = davinci_mcasp_gpio_get, + .get_direction = davinci_mcasp_gpio_get_direction, + .base = -1, + .ngpio = 32, +}; + +static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) +{ + if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) + return 0; + + mcasp->gpio_chip = davinci_mcasp_template_chip; + mcasp->gpio_chip.label = dev_name(mcasp->dev); + mcasp->gpio_chip.parent = mcasp->dev; +#ifdef CONFIG_OF_GPIO + mcasp->gpio_chip.of_node = mcasp->dev->of_node; +#endif + + return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp); +} + +#else /* CONFIG_GPIOLIB */ +static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) +{ + return 0; +} +#endif /* CONFIG_GPIOLIB */ + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -2069,6 +2213,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); + /* All PINS as McASP */ + pm_runtime_get_sync(mcasp->dev); + mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); + pm_runtime_put(mcasp->dev); + + ret = davinci_mcasp_init_gpiochip(mcasp); + if (ret) + goto err; + ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); From 748b6ec359b02e962259182fd9576cb1b0851440 Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Thu, 20 Dec 2018 07:45:51 +0800 Subject: [PATCH 054/461] ALSA: virtuoso: add de-emphasis control Add control for the de-emphasis filter in the PCM179x DACs Signed-off-by: Tom Yan Signed-off-by: Takashi Iwai --- sound/pci/oxygen/pcm1796.h | 1 - sound/pci/oxygen/xonar_pcm179x.c | 71 +++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/sound/pci/oxygen/pcm1796.h b/sound/pci/oxygen/pcm1796.h index 34d07dd2d22e..d5dcb09e44cd 100644 --- a/sound/pci/oxygen/pcm1796.h +++ b/sound/pci/oxygen/pcm1796.h @@ -10,7 +10,6 @@ #define PCM1796_MUTE 0x01 #define PCM1796_DME 0x02 #define PCM1796_DMF_MASK 0x0c -#define PCM1796_DMF_DISABLED 0x00 #define PCM1796_DMF_48 0x04 #define PCM1796_DMF_441 0x08 #define PCM1796_DMF_32 0x0c diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 24109d37ca09..a1c6b98b191e 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -331,7 +331,7 @@ static void pcm1796_init(struct oxygen *chip) struct xonar_pcm179x *data = chip->model_data; data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = - PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; + PCM1796_FMT_24_I2S | PCM1796_ATLD; if (!data->broken_i2c) data->pcm1796_regs[0][18 - PCM1796_REG_BASE] |= PCM1796_MUTE; data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = @@ -621,6 +621,23 @@ static void update_pcm1796_oversampling(struct oxygen *chip) pcm1796_write_cached(chip, i, 20, reg); } +static void update_pcm1796_deemph(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + u8 reg; + + reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE] & ~PCM1796_DMF_MASK; + if (data->current_rate == 48000) + reg |= PCM1796_DMF_48; + else if (data->current_rate == 44100) + reg |= PCM1796_DMF_441; + else if (data->current_rate == 32000) + reg |= PCM1796_DMF_32; + for (i = 0; i < data->dacs; ++i) + pcm1796_write_cached(chip, i, 18, reg); +} + static void set_pcm1796_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -629,6 +646,7 @@ static void set_pcm1796_params(struct oxygen *chip, msleep(1); data->current_rate = params_rate(params); update_pcm1796_oversampling(chip); + update_pcm1796_deemph(chip); } static void update_pcm1796_volume(struct oxygen *chip) @@ -653,9 +671,11 @@ static void update_pcm1796_mute(struct oxygen *chip) unsigned int i; u8 value; - value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD; + value = data->pcm1796_regs[0][18 - PCM1796_REG_BASE]; if (chip->dac_mute) value |= PCM1796_MUTE; + else + value &= ~PCM1796_MUTE; for (i = 0; i < data->dacs; ++i) pcm1796_write_cached(chip, i, 18, value); } @@ -777,6 +797,49 @@ static const struct snd_kcontrol_new rolloff_control = { .put = rolloff_put, }; +static int deemph_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + + value->value.integer.value[0] = + !!(data->pcm1796_regs[0][18 - PCM1796_REG_BASE] & PCM1796_DME); + return 0; +} + +static int deemph_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + int changed; + u8 reg; + + mutex_lock(&chip->mutex); + reg = data->pcm1796_regs[0][18 - PCM1796_REG_BASE]; + if (!value->value.integer.value[0]) + reg &= ~PCM1796_DME; + else + reg |= PCM1796_DME; + changed = reg != data->pcm1796_regs[0][18 - PCM1796_REG_BASE]; + if (changed) { + for (i = 0; i < data->dacs; ++i) + pcm1796_write(chip, i, 18, reg); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new deemph_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "De-emphasis Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = deemph_get, + .put = deemph_put, +}; + static const struct snd_kcontrol_new hdav_hdmi_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "HDMI Playback Switch", @@ -1011,6 +1074,10 @@ static int add_pcm1796_controls(struct oxygen *chip) snd_ctl_new1(&rolloff_control, chip)); if (err < 0) return err; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&deemph_control, chip)); + if (err < 0) + return err; } return 0; } From 4bccb403f2ca06718ac3a3d9b02e89ca4e823d9f Mon Sep 17 00:00:00 2001 From: Tom Yan Date: Fri, 21 Dec 2018 20:52:57 +0800 Subject: [PATCH 055/461] ALSA: oxygen: initialize spdif_playback_enable to 0 There's no reason for us to do that while we initialize dac_mute to 1. Also oxygen_init() has been clearing the OXYGEN_SPDIF_OUT_ENABLE bit anyway. Signed-off-by: Tom Yan Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b4ef5804212d..6a743c878415 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -373,7 +373,7 @@ static void oxygen_init(struct oxygen *chip) for (i = 0; i < 8; ++i) chip->dac_volume[i] = chip->model.dac_volume_min; chip->dac_mute = 1; - chip->spdif_playback_enable = 1; + chip->spdif_playback_enable = 0; chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); chip->spdif_pcm_bits = chip->spdif_bits; From 0f25e000cb4398081748e54f62a902098aa79ec1 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 19:40:51 -0600 Subject: [PATCH 056/461] ALSA: gus: add a check of the status of snd_ctl_add snd_ctl_add() could fail, so let's check its status and issue an error message if it indeed fails. Signed-off-by: Kangjie Lu Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 3b8a0c880db5..33c8b66d5c8a 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -92,8 +92,17 @@ static const struct snd_kcontrol_new snd_gus_joystick_control = { static void snd_gus_init_control(struct snd_gus_card *gus) { - if (!gus->ace_flag) - snd_ctl_add(gus->card, snd_ctl_new1(&snd_gus_joystick_control, gus)); + int ret; + + if (!gus->ace_flag) { + ret = + snd_ctl_add(gus->card, + snd_ctl_new1(&snd_gus_joystick_control, + gus)); + if (ret) + snd_printk(KERN_ERR "gus: snd_ctl_add failed: %d\n", + ret); + } } /* From c99776cc4018e91c66bd448002e924edd4910947 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Sun, 6 Jan 2019 10:31:44 -0600 Subject: [PATCH 057/461] ALSA: ice1712: fix a missing check of snd_i2c_sendbytes snd_i2c_sendbytes could fail. The fix checks its return value: if it fails, issues an error message and returns with its error code. Signed-off-by: Aditya Pakki Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ews.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index b8af747ecb43..7646c93e8268 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -826,7 +826,12 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg snd_i2c_lock(ice->i2c); byte = reg; - snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1); + if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1)) { + snd_i2c_unlock(ice->i2c); + dev_err(ice->card->dev, "cannot send pca\n"); + return -EIO; + } + byte = 0; if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { snd_i2c_unlock(ice->i2c); From 02cc53e223d498010de5f114d72c11a2d55118e8 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Sun, 6 Jan 2019 11:01:47 -0600 Subject: [PATCH 058/461] ALSA: line6: fix check on snd_card_register The fix checks if snd_card_register() fails, and if so logs the error via dev_err() consistent with other patches. Signed-off-by: Aditya Pakki Signed-off-by: Takashi Iwai --- sound/usb/line6/pod.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 020c81818951..ce45b6dab651 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -320,7 +320,8 @@ static void pod_startup4(struct work_struct *work) line6_read_serial_number(&pod->line6, &pod->serial_number); /* ALSA audio interface: */ - snd_card_register(line6->card); + if (snd_card_register(line6->card)) + dev_err(line6->ifcdev, "Failed to register POD card.\n"); } /* POD special files: */ From beae77170c60aa786f3e4599c18ead2854d8694d Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Sun, 6 Jan 2019 11:16:00 -0600 Subject: [PATCH 059/461] ALSA: sb: fix a missing check of snd_ctl_add snd_ctl_add() could fail, so let's check its return value and return its error code upstream upon failure. Signed-off-by: Aditya Pakki Signed-off-by: Takashi Iwai --- sound/isa/sb/sb16_main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 37e6ce7b0b13..981d65d122b6 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -879,10 +879,14 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); - if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) - snd_ctl_add(card, snd_ctl_new1(&snd_sb16_dma_control, chip)); - else + if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) { + err = snd_ctl_add(card, snd_ctl_new1( + &snd_sb16_dma_control, chip)); + if (err) + return err; + } else { pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; + } snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), From ee6047b82888148e688e46f17017cae8e088b246 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 4 Jan 2019 16:27:03 +0000 Subject: [PATCH 060/461] ASoC: ak4458: Add support for AK4497 AK4497 is a 32-bit 2ch DAC and has the same register map as AK4458 with few exceptions: * AK4497 has one more register at the end of register space DFS_READ which is a read only register that allows users to read FS Auto Detection mode. We currently do not use this register so we use the same regmap structure as for ak4458. * Because AK4458 is an 8ch DAC there are some fields that are only used by AK4458 and marked as reserved for AK4497, so for this reason we need to have a distinct set of controls, widgets and routes. Datasheet for AK4497 is at: https://www.akm.com/akm/en/file/ev-board-manual/AK4497EQ.pdf Datasheet for AK4458 is at: https://www.akm.com/akm/en/file/datasheet/AK4458VN.pdf Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 79 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 70d4c89bd6fc..eab7c76cfcd9 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -21,6 +21,11 @@ #include "ak4458.h" +struct ak4458_drvdata { + struct snd_soc_dai_driver *dai_drv; + const struct snd_soc_component_driver *comp_drv; +}; + /* AK4458 Codec Private Data */ struct ak4458_priv { struct device *dev; @@ -258,6 +263,33 @@ static const struct snd_soc_dapm_route ak4458_intercon[] = { {"AK4458 AOUTD", NULL, "AK4458 DAC4"}, }; +/* ak4497 controls */ +static const struct snd_kcontrol_new ak4497_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC Playback Volume", AK4458_03_LCHATT, + AK4458_04_RCHATT, 0, 0xFF, 0, dac_tlv), + SOC_ENUM("AK4497 De-emphasis Response DAC", ak4458_dac1_dem_enum), + SOC_ENUM_EXT("AK4497 Digital Filter Setting", ak4458_digfil_enum, + get_digfil, set_digfil), + SOC_ENUM("AK4497 Inverting Enable of DZFB", ak4458_dzfb_enum), + SOC_ENUM("AK4497 Sound Mode", ak4458_sm_enum), + SOC_ENUM("AK4497 Attenuation transition Time Setting", + ak4458_ats_enum), +}; + +/* ak4497 dapm widgets */ +static const struct snd_soc_dapm_widget ak4497_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AK4497 DAC", NULL, AK4458_0A_CONTROL6, 2, 0), + SND_SOC_DAPM_AIF_IN("AK4497 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("AK4497 AOUT"), +}; + +/* ak4497 dapm routes */ +static const struct snd_soc_dapm_route ak4497_intercon[] = { + {"AK4497 DAC", NULL, "AK4497 SDTI"}, + {"AK4497 AOUT", NULL, "AK4497 DAC"}, + +}; + static int ak4458_rstn_control(struct snd_soc_component *component, int bit) { int ret; @@ -476,6 +508,18 @@ static struct snd_soc_dai_driver ak4458_dai = { .ops = &ak4458_dai_ops, }; +static struct snd_soc_dai_driver ak4497_dai = { + .name = "ak4497-aif", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = AK4458_FORMATS, + }, + .ops = &ak4458_dai_ops, +}; + static void ak4458_power_off(struct ak4458_priv *ak4458) { if (ak4458->reset_gpiod) { @@ -573,6 +617,21 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { + .probe = ak4458_probe, + .remove = ak4458_remove, + .controls = ak4497_snd_controls, + .num_controls = ARRAY_SIZE(ak4497_snd_controls), + .dapm_widgets = ak4497_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4497_dapm_widgets), + .dapm_routes = ak4497_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4497_intercon), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + static const struct regmap_config ak4458_regmap = { .reg_bits = 8, .val_bits = 8, @@ -583,6 +642,16 @@ static const struct regmap_config ak4458_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct ak4458_drvdata ak4458_drvdata = { + .dai_drv = &ak4458_dai, + .comp_drv = &soc_codec_dev_ak4458, +}; + +static const struct ak4458_drvdata ak4497_drvdata = { + .dai_drv = &ak4497_dai, + .comp_drv = &soc_codec_dev_ak4497, +}; + static const struct dev_pm_ops ak4458_pm = { SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, @@ -592,6 +661,7 @@ static const struct dev_pm_ops ak4458_pm = { static int ak4458_i2c_probe(struct i2c_client *i2c) { struct ak4458_priv *ak4458; + const struct ak4458_drvdata *drvdata; int ret; ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL); @@ -605,6 +675,8 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, ak4458); ak4458->dev = &i2c->dev; + drvdata = of_device_get_match_data(&i2c->dev); + ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ak4458->reset_gpiod)) @@ -615,8 +687,8 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) if (IS_ERR(ak4458->mute_gpiod)) return PTR_ERR(ak4458->mute_gpiod); - ret = devm_snd_soc_register_component(ak4458->dev, &soc_codec_dev_ak4458, - &ak4458_dai, 1); + ret = devm_snd_soc_register_component(ak4458->dev, drvdata->comp_drv, + drvdata->dai_drv, 1); if (ret < 0) { dev_err(ak4458->dev, "Failed to register CODEC: %d\n", ret); return ret; @@ -635,7 +707,8 @@ static int ak4458_i2c_remove(struct i2c_client *i2c) } static const struct of_device_id ak4458_of_match[] = { - { .compatible = "asahi-kasei,ak4458", }, + { .compatible = "asahi-kasei,ak4458", .data = &ak4458_drvdata}, + { .compatible = "asahi-kasei,ak4497", .data = &ak4497_drvdata}, { }, }; From 5d8d66077af12681441897a350f346c0da7f5576 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 4 Jan 2019 16:27:04 +0000 Subject: [PATCH 061/461] ASoC: dt-bindings: Document support for ak4497 ak4458 driver supports also ak4497 codec. Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak4458.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ak4458.txt b/Documentation/devicetree/bindings/sound/ak4458.txt index 7839be78448d..e5820235e0d5 100644 --- a/Documentation/devicetree/bindings/sound/ak4458.txt +++ b/Documentation/devicetree/bindings/sound/ak4458.txt @@ -4,7 +4,7 @@ This device supports I2C mode. Required properties: -- compatible : "asahi-kasei,ak4458" +- compatible : "asahi-kasei,ak4458" or "asahi-kasei,ak4497" - reg : The I2C address of the device for I2C Optional properties: From 902d82222270c957d12fa2e9856484d600a88d20 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:29 -0600 Subject: [PATCH 062/461] ASoC: dmic: declare trigger function as static No reason why this is global, fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/dmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index da921da50ef0..de041369e5a7 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -44,8 +44,8 @@ struct dmic { int modeswitch_delay; }; -int dmic_daiops_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct dmic *dmic = snd_soc_component_get_drvdata(component); From 97d8f6b71f56865e52d472247fe728700ef7128d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:30 -0600 Subject: [PATCH 063/461] ASoC: max98090: remove unused constant variables Fix warnings with W=1 If these variables are useful then this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index c97f21836c66..30c242c38d99 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -314,9 +314,6 @@ static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); @@ -817,18 +814,6 @@ static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); -static const char *max98090_micpre_text[] = { "Off", "On" }; - -static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, - M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PA1EN_SHIFT, - max98090_micpre_text); - -static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, - M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PA2EN_SHIFT, - max98090_micpre_text); - /* LINEA mixer switch */ static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG, From 37b6f0350374e6c683bc2c2d8a54d4504bc04ec1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:31 -0600 Subject: [PATCH 064/461] ASoC: es8316: remove unused constant variables Fix warnings with W=1 If these variables are useful this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 98464ba1046c..6d4a323f786b 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -167,8 +167,6 @@ static const char * const es8316_hpmux_texts[] = { "lin-rin with Boost and PGA" }; -static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL, 4, es8316_hpmux_texts); @@ -199,8 +197,6 @@ static const char * const es8316_dacsrc_texts[] = { "RDATA TO LDAC, LDATA TO RDAC", }; -static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1, 6, es8316_dacsrc_texts); From dc22a4093f5d2973bef5f72b00da74ce61458bc0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:32 -0600 Subject: [PATCH 065/461] ASoC: codecs: fix kernel doc descriptions Missing or spurious parameter descriptions. Fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 1 + sound/soc/codecs/rt5514.c | 1 + sound/soc/codecs/rt5677.c | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7bbcbf5f05c8..47e65cf99879 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -351,6 +351,7 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, * Computes log10 of a value; the result is round off to 3 decimal. This func- * tion takes reference to dvb-math. The source code locates as the following. * Linux/drivers/media/dvb-core/dvb_math.c + * @value: input for log10 * * return log10(value) * 1000 */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a67de68b6da6..f9ad6e36ab16 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -489,6 +489,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux = /** * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic. * + * @component: only used for dev_warn * @rate: base clock rate. * * Choose divider parameter that gives the highest possible DMIC frequency in diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9b7a1833d331..6fc70e441458 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -547,7 +547,7 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) * @rt5677: Private Data. * @addr: Address index. * @value: Address data. - * + * @opcode: opcode value * * Returns 0 for success or negative error code. */ @@ -602,7 +602,7 @@ err: /** * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @addr: Address index. * @value: Address data. * @@ -651,7 +651,7 @@ err: /** * rt5677_dsp_mode_i2c_write - Write register on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @reg: Register index. * @value: Register data. * @@ -667,7 +667,7 @@ static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read - Read register on DSP mode. - * @codec: SoC audio codec device. + * @rt5677: Private Data * @reg: Register index. * @value: Register data. * From c3db21324442137552041711a878d75358c993ae Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:33 -0600 Subject: [PATCH 066/461] ASoC: rt5645: remove unused mux define rt5645_if3_adc_in_mux, rt5645_inr_mux, and rt5645_inl_mux are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index be674688dc40..52ce380c8f3a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1288,30 +1288,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_dac_r2_mux = SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); - -/* INL/R source */ -static const char * const rt5645_inl_src[] = { - "IN2P", "MonoP" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inl_enum, RT5645_INL1_INR1_VOL, - RT5645_INL_SEL_SFT, rt5645_inl_src); - -static const struct snd_kcontrol_new rt5645_inl_mux = - SOC_DAPM_ENUM("INL source", rt5645_inl_enum); - -static const char * const rt5645_inr_src[] = { - "IN2N", "MonoN" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inr_enum, RT5645_INL1_INR1_VOL, - RT5645_INR_SEL_SFT, rt5645_inr_src); - -static const struct snd_kcontrol_new rt5645_inr_mux = - SOC_DAPM_ENUM("INR source", rt5645_inr_enum); - /* Stereo1 ADC source */ /* MX-27 [12] */ static const char * const rt5645_stereo_adc1_src[] = { @@ -1611,18 +1587,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); -/* MX-2F [1:0] */ -static const char * const rt5645_if3_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "VAD_ADC" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, - RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); - -static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = - SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5645_pdm_src[] = { "Mono DAC", "Stereo DAC" From 6606f9df60bcb632e047e0f8a268e327cebcc3db Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:34 -0600 Subject: [PATCH 067/461] ASoC: rt5670: remove unused mux/mixer define Some mux/mixer are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 54 --------------------------------------- 1 file changed, 54 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 453328c988c0..9a037108b1ae 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1057,20 +1057,6 @@ static const struct snd_kcontrol_new rt5670_lout_mix[] = { RT5670_M_OV_R_LM_SFT, 1, 1), }; -static const struct snd_kcontrol_new rt5670_hpl_mix[] = { - SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACL1_HML_SFT, 1, 1), - SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER, - RT5670_M_INL1_HML_SFT, 1, 1), -}; - -static const struct snd_kcontrol_new rt5670_hpr_mix[] = { - SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACR1_HMR_SFT, 1, 1), - SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER, - RT5670_M_INR1_HMR_SFT, 1, 1), -}; - static const struct snd_kcontrol_new lout_l_enable_control = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, RT5670_L_MUTE_SFT, 1, 1); @@ -1196,24 +1182,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux = SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum); - -/* MX-27 MX26 [10] */ -static const char * const rt5670_stereo_adc_src[] = { - "ADC1L ADC2R", "ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto_adc_mux = - SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum); - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto2_adc_mux = - SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum); - /* MX-27 MX-26 [9:8] */ static const char * const rt5670_stereo_dmic_src[] = { "DMIC1", "DMIC2", "DMIC3" @@ -1231,17 +1199,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_dmic_mux = SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum); -/* MX-27 [0] */ -static const char * const rt5670_stereo_dmic3_src[] = { - "DMIC3", "PDM ADC" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER, - RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src); - -static const struct snd_kcontrol_new rt5670_sto_dmic3_mux = - SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum); - /* Mono ADC source */ /* MX-28 [12] */ static const char * const rt5670_mono_adc_l1_src[] = { @@ -1334,17 +1291,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA, static const struct snd_kcontrol_new rt5670_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum); -/* MX-30 [5:4] */ -static const char * const rt5670_if4_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "IF_ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA, - RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src); - -static const struct snd_kcontrol_new rt5670_if4_adc_in_mux = - SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5670_pdm_src[] = { "Mono DAC", "Stereo DAC" From 7c3727ba7de2b94a066e38776660e648fa4ed28a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:35 -0600 Subject: [PATCH 068/461] ASoC: max98383: fix boolean assignments to true/false Reported by Coccinelle: sound/soc/codecs/max98373.c:411:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:922:2-27: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:924:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9c8616a7b61c..528695cd6a1c 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -408,7 +408,7 @@ static int max98373_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 0); - max98373->tdm_mode = 0; + max98373->tdm_mode = false; break; default: return 0; @@ -919,9 +919,9 @@ static int max98373_i2c_probe(struct i2c_client *i2c, /* update interleave mode info */ if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode")) - max98373->interleave_mode = 1; + max98373->interleave_mode = true; else - max98373->interleave_mode = 0; + max98373->interleave_mode = false; /* regmap initialization */ From 3c17bcfd35bca1bee34709e7509646b5bc88643f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:37 -0600 Subject: [PATCH 069/461] ASoC: cs4271: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/cs4271.c:226:2-16: WARNING: Assignment of bool to 0/1 sound/soc/codecs/cs4271.c:229:2-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 849fdb2cb260..1104830edaf8 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -223,10 +223,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - cs4271->master = 0; + cs4271->master = false; break; case SND_SOC_DAIFMT_CBM_CFM: - cs4271->master = 1; + cs4271->master = true; val |= CS4271_MODE1_MASTER; break; default: From b793a1e4ebad5c9066f404dee13fec875fb9b4e5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:38 -0600 Subject: [PATCH 070/461] ASoC: rt274: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt274.c:958:6-8: WARNING: Comparison to bool sound/soc/codecs/rt274.c:961:6-9: WARNING: Comparison to bool sound/soc/codecs/rt274.c:384:5-7: WARNING: Comparison to bool sound/soc/codecs/rt274.c:387:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index e2855ab9a2c6..9e88f7b25d38 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -381,10 +381,10 @@ static void rt274_jack_detect_work(struct work_struct *work) if (rt274_jack_detect(rt274, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, @@ -955,10 +955,10 @@ static irqreturn_t rt274_irq(int irq, void *data) ret = rt274_jack_detect(rt274, &hp, &mic); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, From af3b2b54cb294b997ad9a2a88ed3c6c9af7d03c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:39 -0600 Subject: [PATCH 071/461] ASoc: rt286: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt286.c:927:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:930:5-8: WARNING: Comparison to bool sound/soc/codecs/rt286.c:299:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:302:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 0b0f748bffbe..c9457c247a03 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -296,10 +296,10 @@ static void rt286_jack_detect_work(struct work_struct *work) rt286_jack_detect(rt286, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, @@ -924,10 +924,10 @@ static irqreturn_t rt286_irq(int irq, void *data) /* Clear IRQ */ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, From e0a99927ff5f395f24e09e6297858cd2006793f7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:40 -0600 Subject: [PATCH 072/461] ASoC: rt5640: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5640.c:980:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:984:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:2825:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index fc530481a6e4..b3580ecadecf 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -977,11 +977,11 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: rt5640_pmu_depop(component); - rt5640->hp_mute = 0; + rt5640->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5640->hp_mute = 1; + rt5640->hp_mute = true; msleep(70); break; @@ -2822,7 +2822,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET); - rt5640->hp_mute = 1; + rt5640->hp_mute = true; rt5640->irq = i2c->irq; INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work); From 091cd877d8d6b2b934d565134172db771907d50a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:41 -0600 Subject: [PATCH 073/461] ASoC: max98927: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/max98927.c:508:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:889:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:891:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:893:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 065303a46535..e53d2007f3be 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -505,7 +505,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - max98927->tdm_mode = 0; + max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: regmap_update_bits(max98927->regmap, @@ -886,11 +886,11 @@ static int max98927_i2c_probe(struct i2c_client *i2c, if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", &value)) { if (value > 0) - max98927->interleave_mode = 1; + max98927->interleave_mode = true; else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; } else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; /* regmap initialization */ max98927->regmap From 577dc32f9a6fc20cd404e0eb965659e9271c78be Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:42 -0600 Subject: [PATCH 074/461] ASoC: rt5651: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5651.c:750:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:754:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:2192:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b7ba64350a07..3882e238ff99 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -747,11 +747,11 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, RT5651_HP_CP_PD | RT5651_HP_SG_EN); regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); - rt5651->hp_mute = 0; + rt5651->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5651->hp_mute = 1; + rt5651->hp_mute = true; usleep_range(70000, 75000); break; @@ -2189,7 +2189,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); rt5651->irq = i2c->irq; - rt5651->hp_mute = 1; + rt5651->hp_mute = true; INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work); INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); From 290da7a7e349566f0e1541b14f25b722f58f236b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:43 -0600 Subject: [PATCH 075/461] ASoC: nau8824: fix boolean assignment Reported by Coccinelle: nau8824.c:810:6-12: ERROR: Assignment of bool to non-0/1 constant Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 468d5143e2c4..87ed3dc496dc 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -807,7 +807,7 @@ static const struct snd_soc_dapm_route nau8824_dapm_routes[] = { static bool nau8824_is_jack_inserted(struct nau8824 *nau8824) { struct snd_soc_jack *jack = nau8824->jack; - bool insert = FALSE; + bool insert = false; if (nau8824->irq && jack) insert = jack->status & SND_JACK_HEADPHONE; From f361ca36802031ae3abf9860a02e1d5931c04b63 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:44 -0600 Subject: [PATCH 076/461] ASoC: tscs42xx.c: fix boolean test Reported by Coccinelle: sound/soc/codecs/tscs42xx.c:392:5-31: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 7396a6e5277e..27b8c6ba72fa 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -389,7 +389,7 @@ static int dac_event(struct snd_soc_dapm_widget *w, mutex_lock(&tscs42xx->coeff_ram_lock); - if (tscs42xx->coeff_ram_synced == false) { + if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) From d61780c155e8bef8dceb3ac98d29f79c24e264eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:45 -0600 Subject: [PATCH 077/461] ASoC: mt6351: remove unneeded variable Reported by Coccinelle: mt6351.c:1418:5-8: Unneeded variable: "ret". Return "0" on line 1437 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/mt6351.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index f73dcd753584..4b3ce01c5a93 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1415,8 +1415,6 @@ static const struct snd_soc_dapm_route mt6351_dapm_routes[] = { static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) { - int ret = 0; - /* Disable CLKSQ 26MHz */ regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0); /* disable AUDGLB */ @@ -1434,7 +1432,7 @@ static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) /* Reverse the PMIC clock*/ regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2, 0x8000, 0x8000); - return ret; + return 0; } static int mt6351_codec_probe(struct snd_soc_component *cmpnt) From 123c3def3bc5ea9958b8191d8139f610ed972d18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:46 -0600 Subject: [PATCH 078/461] ASoC: da7219: fix endianness issues Reported by Sparse. da7219.c:440:44: warning: cast to restricted __le16 da7219.c:461:13: warning: incorrect type in assignment (different base types) da7219.c:461:13: expected unsigned short [unsigned] [usertype] val da7219.c:461:13: got restricted __le16 [usertype] da7219.c:1451:16: warning: incorrect type in assignment (different base types) da7219.c:1451:16: expected unsigned short [unsigned] [usertype] offset da7219.c:1451:16: got restricted __le16 [usertype] da7219-aad.c:150:37: warning: incorrect type in assignment (different base types) da7219-aad.c:150:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:150:37: got restricted __le16 [usertype] da7219-aad.c:157:37: warning: incorrect type in assignment (different base types) da7219-aad.c:157:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:157:37: got restricted __le16 [usertype] Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219-aad.c | 2 +- sound/soc/codecs/da7219.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2c7d5088e6f2..e0964b20a389 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -117,7 +117,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u16 tonegen_freq_hptest; + __le16 tonegen_freq_hptest; u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e46e9f4bc994..ce165047b9f9 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -423,7 +423,7 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; mutex_lock(&da7219->ctrl_lock); @@ -450,7 +450,7 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; /* @@ -1396,7 +1396,7 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 dai_bclks_per_wclk; - u16 offset; + __le16 offset; u32 frame_size; /* No channels enabled so disable TDM, revert to 64-bit frames */ From b468f379e1e01b723825267431d3ba60f824fda2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:47 -0600 Subject: [PATCH 079/461] ASoC: da7219: use logical AND Reported by Sparse: da7219.c:841:57: warning: dubious: x & !y Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index ce165047b9f9..513ec0368653 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -838,7 +838,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(component->dev, "SRM failed to lock\n"); From 60b52ed627213d1782e70b9810f5668f61bba3a8 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:48 -0600 Subject: [PATCH 080/461] ASoC: rt5645: store eq kcontrol byte in __be The eq parameters binary is stored in __be. However, it is unsigned short in rt5645_eq_param_s{} which will cause incorrect type assignment. So add struct rt5645_eq_param_s_be16{} to store the eq binary and convert it to unsigned short in rt5645->eq_param. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 52ce380c8f3a..9a0751978090 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -401,6 +401,11 @@ struct rt5645_eq_param_s { unsigned short val; }; +struct rt5645_eq_param_s_be16 { + __be16 reg; + __be16 val; +}; + static const char *const rt5645_supply_names[] = { "avdd", "cpvdd", @@ -672,8 +677,8 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { @@ -698,36 +703,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { - eq_param[i].reg = be16_to_cpu(eq_param[i].reg); - eq_param[i].val = be16_to_cpu(eq_param[i].val); + rt5645->eq_param[i].reg = be16_to_cpu(eq_param[i].reg); + rt5645->eq_param[i].val = be16_to_cpu(eq_param[i].val); } /* The final setting of the table should be RT5645_EQ_CTRL2 */ for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) { - if (eq_param[i].reg == 0) + if (rt5645->eq_param[i].reg == 0) continue; - else if (eq_param[i].reg != RT5645_EQ_CTRL2) + else if (rt5645->eq_param[i].reg != RT5645_EQ_CTRL2) return 0; else break; } for (i = 0; i < RT5645_HWEQ_NUM; i++) { - if (!rt5645_validate_hweq(eq_param[i].reg) && - eq_param[i].reg != 0) + if (!rt5645_validate_hweq(rt5645->eq_param[i].reg) && + rt5645->eq_param[i].reg != 0) return 0; - else if (eq_param[i].reg == 0) + else if (rt5645->eq_param[i].reg == 0) break; } - memcpy(rt5645->eq_param, eq_param, - RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s)); - return 0; } From b8e022e83ba99a0deb27e929033008402f863dd7 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:49 -0600 Subject: [PATCH 081/461] ASoC: rl6437a: use __be32 for a __be32 buf The buf in rl6347a_hw_read is __be32. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rl6347a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index 8f571cf8edd4..c0d729b45277 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -64,8 +64,8 @@ int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) struct i2c_client *client = context; struct i2c_msg xfer[2]; int ret; - __be32 be_reg; - unsigned int index, vid, buf = 0x0; + __be32 be_reg, buf = 0x0; + unsigned int index, vid; /* handle index registers */ if (reg <= 0xff) { From f0627d006047299e427f026942fed22b111f04f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:36 -0600 Subject: [PATCH 082/461] ASoC: rt298: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt298.c:992:6-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:995:6-9: WARNING: Comparison to bool sound/soc/codecs/rt298.c:317:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:320:5-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:348:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:351:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 06cdba4edfe2..bcf5bab31969 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -314,10 +314,10 @@ static void rt298_jack_detect_work(struct work_struct *work) if (rt298_jack_detect(rt298, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -345,10 +345,10 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); rt298_jack_detect(rt298, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -989,10 +989,10 @@ static irqreturn_t rt298_irq(int irq, void *data) regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, From e147c189c10911def4c3d98aa1111a474a64111c Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 4 Jan 2019 19:55:30 +0100 Subject: [PATCH 083/461] ASoC: eliminate left-over from Raumfeld machine driver removal Commit f84a6273dd9107c ("ASoC: pxa: remove raumfeld machine driver") removed the Raumfeld ASoC machine driver but forgot to kill one line in the Makefile. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/pxa/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 0ab2a9dcb720..ea4929d73318 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -30,7 +30,6 @@ snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o snd-soc-z2-objs := z2.o snd-soc-imote2-objs := imote2.o -snd-soc-raumfeld-objs := raumfeld.o snd-soc-brownstone-objs := brownstone.o snd-soc-ttc-dkb-objs := ttc-dkb.o From e595da28ecc87e7cec2681c01d5970e31153bddd Mon Sep 17 00:00:00 2001 From: Cosmin Samoila Date: Fri, 4 Jan 2019 09:17:37 +0000 Subject: [PATCH 084/461] ASoC: micfil: Add bindings for MICFIL DAI Document the bindings for MICFIL DAI. Signed-off-by: Cosmin-Gabriel Samoila Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,micfil.txt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,micfil.txt diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.txt b/Documentation/devicetree/bindings/sound/fsl,micfil.txt new file mode 100644 index 000000000000..53e227b15277 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,micfil.txt @@ -0,0 +1,32 @@ +NXP MICFIL Digital Audio Interface (MICFIL). + +The MICFIL digital interface provides a 16-bit audio signal from a PDM +microphone bitstream in a configurable output sampling rate. + +Required properties: + + - compatible : Compatible list, contains "fsl,imx8mm-micfil" + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the micfil interrupts. + + - clocks : Must contain an entry for each entry in clock-names. + + - clock-names : Must include the "ipg_clk" for register access and + "ipg_clk_app" for internal micfil clock. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + +Example: +micfil: micfil@30080000 { + compatible = "fsl,imx8mm-micfil"; + reg = <0x0 0x30080000 0x0 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MM_CLK_PDM_IPG>, + <&clk IMX8MM_CLK_PDM_ROOT>; + clock-names = "ipg_clk", "ipg_clk_app"; + dmas = <&sdma2 24 26 0x80000000>; +}; From 47a70e6fc9a80c8d5ef69e978d25582842f9777f Mon Sep 17 00:00:00 2001 From: Cosmin Samoila Date: Fri, 4 Jan 2019 09:17:38 +0000 Subject: [PATCH 085/461] ASoC: Add MICFIL SoC Digital Audio Interface driver. Add Digital Audio Interface driver that convers PDM bitstream to PCM format. Features: - Fixed filtering characteristics for audio application. - Full or partial set of channels operation with individual enable control. - Programmable PDM clock generator. - Programmable decimation rate. - 16-bit signed output result. - Overall stopband attenuation more than 80dB. - Overall passband ripple less than 0.2dB. Signed-off-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 9 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_micfil.c | 826 +++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_micfil.h | 283 +++++++++++++ 4 files changed, 1120 insertions(+) create mode 100644 sound/soc/fsl/fsl_micfil.c create mode 100644 sound/soc/fsl/fsl_micfil.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 2e75b5bc5f1d..7b1d9970be8b 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -57,6 +57,15 @@ config SND_SOC_FSL_ESAI This option is only useful for out-of-tree drivers since in-tree drivers select it automatically. +config SND_SOC_FSL_MICFIL + tristate "Pulse Density Modulation Microphone Interface (MICFIL) module support" + select REGMAP_MMIO + select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to add Pulse Density Modulation microphone + interface (MICFIL) support for NXP. + config SND_SOC_FSL_UTILS tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index de94fa057e24..3c0ff315b971 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -19,6 +19,7 @@ snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o +snd-soc-fsl-micfil-objs := fsl_micfil.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o +obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c new file mode 100644 index 000000000000..40c07e756481 --- /dev/null +++ b/sound/soc/fsl/fsl_micfil.c @@ -0,0 +1,826 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2018 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_micfil.h" +#include "imx-pcm.h" + +#define FSL_MICFIL_RATES SNDRV_PCM_RATE_8000_48000 +#define FSL_MICFIL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct fsl_micfil { + struct platform_device *pdev; + struct regmap *regmap; + const struct fsl_micfil_soc_data *soc; + struct clk *mclk; + struct snd_dmaengine_dai_dma_data dma_params_rx; + unsigned int dataline; + char name[32]; + int irq[MICFIL_IRQ_LINES]; + unsigned int mclk_streams; + int quality; /*QUALITY 2-0 bits */ + bool slave_mode; + int channel_gain[8]; +}; + +struct fsl_micfil_soc_data { + unsigned int fifos; + unsigned int fifo_depth; + unsigned int dataline; + bool imx; +}; + +static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { + .imx = true, + .fifos = 8, + .fifo_depth = 8, + .dataline = 0xf, +}; + +static const struct of_device_id fsl_micfil_dt_ids[] = { + { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids); + +/* Table 5. Quality Modes + * Medium 0 0 0 + * High 0 0 1 + * Very Low 2 1 0 0 + * Very Low 1 1 0 1 + * Very Low 0 1 1 0 + * Low 1 1 1 + */ +static const char * const micfil_quality_select_texts[] = { + "Medium", "High", + "N/A", "N/A", + "VLow2", "VLow1", + "VLow0", "Low", +}; + +static const struct soc_enum fsl_micfil_quality_enum = + SOC_ENUM_SINGLE(REG_MICFIL_CTRL2, + MICFIL_CTRL2_QSEL_SHIFT, + ARRAY_SIZE(micfil_quality_select_texts), + micfil_quality_select_texts); + +static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); + +static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv), + SOC_ENUM_EXT("MICFIL Quality Select", + fsl_micfil_quality_enum, + snd_soc_get_enum_double, snd_soc_put_enum_double), +}; + +static inline int get_pdm_clk(struct fsl_micfil *micfil, + unsigned int rate) +{ + u32 ctrl2_reg; + int qsel, osr; + int bclk; + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK) + >> MICFIL_CTRL2_CICOSR_SHIFT); + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + qsel = ctrl2_reg & MICFIL_CTRL2_QSEL_MASK; + + switch (qsel) { + case MICFIL_HIGH_QUALITY: + bclk = rate * 8 * osr / 2; /* kfactor = 0.5 */ + break; + case MICFIL_MEDIUM_QUALITY: + case MICFIL_VLOW0_QUALITY: + bclk = rate * 4 * osr * 1; /* kfactor = 1 */ + break; + case MICFIL_LOW_QUALITY: + case MICFIL_VLOW1_QUALITY: + bclk = rate * 2 * osr * 2; /* kfactor = 2 */ + break; + case MICFIL_VLOW2_QUALITY: + bclk = rate * osr * 4; /* kfactor = 4 */ + break; + default: + dev_err(&micfil->pdev->dev, + "Please make sure you select a valid quality.\n"); + bclk = -1; + break; + } + + return bclk; +} + +static inline int get_clk_div(struct fsl_micfil *micfil, + unsigned int rate) +{ + u32 ctrl2_reg; + long mclk_rate; + int osr; + int clk_div; + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK) + >> MICFIL_CTRL2_CICOSR_SHIFT); + + mclk_rate = clk_get_rate(micfil->mclk); + + clk_div = mclk_rate / (get_pdm_clk(micfil, rate) * 2); + + return clk_div; +} + +/* The SRES is a self-negated bit which provides the CPU with the + * capability to initialize the PDM Interface module through the + * slave-bus interface. This bit always reads as zero, and this + * bit is only effective when MDIS is cleared + */ +static int fsl_micfil_reset(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int ret; + + ret = regmap_update_bits(micfil->regmap, + REG_MICFIL_CTRL1, + MICFIL_CTRL1_MDIS_MASK, + 0); + if (ret) { + dev_err(dev, "failed to clear MDIS bit %d\n", ret); + return ret; + } + + ret = regmap_update_bits(micfil->regmap, + REG_MICFIL_CTRL1, + MICFIL_CTRL1_SRES_MASK, + MICFIL_CTRL1_SRES); + if (ret) { + dev_err(dev, "failed to reset MICFIL: %d\n", ret); + return ret; + } + + return 0; +} + +static int fsl_micfil_set_mclk_rate(struct fsl_micfil *micfil, + unsigned int freq) +{ + struct device *dev = &micfil->pdev->dev; + int ret; + + clk_disable_unprepare(micfil->mclk); + + ret = clk_set_rate(micfil->mclk, freq * 1024); + if (ret) + dev_warn(dev, "failed to set rate (%u): %d\n", + freq * 1024, ret); + + clk_prepare_enable(micfil->mclk); + + return ret; +} + +static int fsl_micfil_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + if (!micfil) { + dev_err(dai->dev, + "micfil dai priv_data not set\n"); + return -EINVAL; + } + + return 0; +} + +static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + struct device *dev = &micfil->pdev->dev; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = fsl_micfil_reset(dev); + if (ret) { + dev_err(dev, "failed to soft reset\n"); + return ret; + } + + /* DMA Interrupt Selection - DISEL bits + * 00 - DMA and IRQ disabled + * 01 - DMA req enabled + * 10 - IRQ enabled + * 11 - reserved + */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL_MASK, + (1 << MICFIL_CTRL1_DISEL_SHIFT)); + if (ret) { + dev_err(dev, "failed to update DISEL bits\n"); + return ret; + } + + /* Enable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, + MICFIL_CTRL1_PDMIEN); + if (ret) { + dev_err(dev, "failed to enable the module\n"); + return ret; + } + + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* Disable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, + 0); + if (ret) { + dev_err(dev, "failed to enable the module\n"); + return ret; + } + + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL_MASK, + (0 << MICFIL_CTRL1_DISEL_SHIFT)); + if (ret) { + dev_err(dev, "failed to update DISEL bits\n"); + return ret; + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int fsl_set_clock_params(struct device *dev, unsigned int rate) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int clk_div; + int ret = 0; + + ret = fsl_micfil_set_mclk_rate(micfil, rate); + if (ret < 0) + dev_err(dev, "failed to set mclk[%lu] to rate %u\n", + clk_get_rate(micfil->mclk), rate); + + /* set CICOSR */ + ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_CICOSR_MASK, + MICFIL_CTRL2_OSR_DEFAULT); + if (ret) + dev_err(dev, "failed to set CICOSR in reg 0x%X\n", + REG_MICFIL_CTRL2); + + /* set CLK_DIV */ + clk_div = get_clk_div(micfil, rate); + if (clk_div < 0) + ret = -EINVAL; + + ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_CLKDIV_MASK, clk_div); + if (ret) + dev_err(dev, "failed to set CLKDIV in reg 0x%X\n", + REG_MICFIL_CTRL2); + + return ret; +} + +static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + struct device *dev = &micfil->pdev->dev; + int ret; + + /* 1. Disable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, 0); + if (ret) { + dev_err(dev, "failed to disable the module\n"); + return ret; + } + + /* enable channels */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + 0xFF, ((1 << channels) - 1)); + if (ret) { + dev_err(dev, "failed to enable channels %d, reg 0x%X\n", ret, + REG_MICFIL_CTRL1); + return ret; + } + + ret = fsl_set_clock_params(dev, rate); + if (ret < 0) { + dev_err(dev, "Failed to set clock parameters [%d]\n", ret); + return ret; + } + + micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; + + return 0; +} + +static int fsl_micfil_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + struct device *dev = &micfil->pdev->dev; + + int ret; + + if (!freq) + return 0; + + ret = fsl_micfil_set_mclk_rate(micfil, freq); + if (ret < 0) + dev_err(dev, "failed to set mclk[%lu] to rate %u\n", + clk_get_rate(micfil->mclk), freq); + + return ret; +} + +static struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, + .set_sysclk = fsl_micfil_set_dai_sysclk, +}; + +static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); + struct device *dev = cpu_dai->dev; + unsigned int val; + int ret; + int i; + + /* set qsel to medium */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_QSEL_MASK, MICFIL_MEDIUM_QUALITY); + if (ret) { + dev_err(dev, "failed to set quality mode bits, reg 0x%X\n", + REG_MICFIL_CTRL2); + return ret; + } + + /* set default gain to max_gain */ + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777); + for (i = 0; i < 8; i++) + micfil->channel_gain[i] = 0xF; + + snd_soc_dai_init_dma_data(cpu_dai, NULL, + &micfil->dma_params_rx); + + /* FIFO Watermark Control - FIFOWMK*/ + val = MICFIL_FIFO_CTRL_FIFOWMK(micfil->soc->fifo_depth) - 1; + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_FIFO_CTRL, + MICFIL_FIFO_CTRL_FIFOWMK_MASK, + val); + if (ret) { + dev_err(dev, "failed to set FIFOWMK\n"); + return ret; + } + + snd_soc_dai_set_drvdata(cpu_dai, micfil); + + return 0; +} + +static struct snd_soc_dai_driver fsl_micfil_dai = { + .probe = fsl_micfil_dai_probe, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = FSL_MICFIL_RATES, + .formats = FSL_MICFIL_FORMATS, + }, + .ops = &fsl_micfil_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_micfil_component = { + .name = "fsl-micfil-dai", + .controls = fsl_micfil_snd_controls, + .num_controls = ARRAY_SIZE(fsl_micfil_snd_controls), + +}; + +/* REGMAP */ +static const struct reg_default fsl_micfil_reg_defaults[] = { + {REG_MICFIL_CTRL1, 0x00000000}, + {REG_MICFIL_CTRL2, 0x00000000}, + {REG_MICFIL_STAT, 0x00000000}, + {REG_MICFIL_FIFO_CTRL, 0x00000007}, + {REG_MICFIL_FIFO_STAT, 0x00000000}, + {REG_MICFIL_DATACH0, 0x00000000}, + {REG_MICFIL_DATACH1, 0x00000000}, + {REG_MICFIL_DATACH2, 0x00000000}, + {REG_MICFIL_DATACH3, 0x00000000}, + {REG_MICFIL_DATACH4, 0x00000000}, + {REG_MICFIL_DATACH5, 0x00000000}, + {REG_MICFIL_DATACH6, 0x00000000}, + {REG_MICFIL_DATACH7, 0x00000000}, + {REG_MICFIL_DC_CTRL, 0x00000000}, + {REG_MICFIL_OUT_CTRL, 0x00000000}, + {REG_MICFIL_OUT_STAT, 0x00000000}, + {REG_MICFIL_VAD0_CTRL1, 0x00000000}, + {REG_MICFIL_VAD0_CTRL2, 0x000A0000}, + {REG_MICFIL_VAD0_STAT, 0x00000000}, + {REG_MICFIL_VAD0_SCONFIG, 0x00000000}, + {REG_MICFIL_VAD0_NCONFIG, 0x80000000}, + {REG_MICFIL_VAD0_NDATA, 0x00000000}, + {REG_MICFIL_VAD0_ZCD, 0x00000004}, +}; + +static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_CTRL1: + case REG_MICFIL_CTRL2: + case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_CTRL: + case REG_MICFIL_FIFO_STAT: + case REG_MICFIL_DATACH0: + case REG_MICFIL_DATACH1: + case REG_MICFIL_DATACH2: + case REG_MICFIL_DATACH3: + case REG_MICFIL_DATACH4: + case REG_MICFIL_DATACH5: + case REG_MICFIL_DATACH6: + case REG_MICFIL_DATACH7: + case REG_MICFIL_DC_CTRL: + case REG_MICFIL_OUT_CTRL: + case REG_MICFIL_OUT_STAT: + case REG_MICFIL_VAD0_CTRL1: + case REG_MICFIL_VAD0_CTRL2: + case REG_MICFIL_VAD0_STAT: + case REG_MICFIL_VAD0_SCONFIG: + case REG_MICFIL_VAD0_NCONFIG: + case REG_MICFIL_VAD0_NDATA: + case REG_MICFIL_VAD0_ZCD: + return true; + default: + return false; + } +} + +static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_CTRL1: + case REG_MICFIL_CTRL2: + case REG_MICFIL_STAT: /* Write 1 to Clear */ + case REG_MICFIL_FIFO_CTRL: + case REG_MICFIL_FIFO_STAT: /* Write 1 to Clear */ + case REG_MICFIL_DC_CTRL: + case REG_MICFIL_OUT_CTRL: + case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ + case REG_MICFIL_VAD0_CTRL1: + case REG_MICFIL_VAD0_CTRL2: + case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ + case REG_MICFIL_VAD0_SCONFIG: + case REG_MICFIL_VAD0_NCONFIG: + case REG_MICFIL_VAD0_ZCD: + return true; + default: + return false; + } +} + +static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_STAT: + case REG_MICFIL_DATACH0: + case REG_MICFIL_DATACH1: + case REG_MICFIL_DATACH2: + case REG_MICFIL_DATACH3: + case REG_MICFIL_DATACH4: + case REG_MICFIL_DATACH5: + case REG_MICFIL_DATACH6: + case REG_MICFIL_DATACH7: + case REG_MICFIL_VAD0_STAT: + case REG_MICFIL_VAD0_NDATA: + return true; + default: + return false; + } +} + +static const struct regmap_config fsl_micfil_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = REG_MICFIL_VAD0_ZCD, + .reg_defaults = fsl_micfil_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_micfil_reg_defaults), + .readable_reg = fsl_micfil_readable_reg, + .volatile_reg = fsl_micfil_volatile_reg, + .writeable_reg = fsl_micfil_writeable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +/* END OF REGMAP */ + +static irqreturn_t micfil_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct platform_device *pdev = micfil->pdev; + u32 stat_reg; + u32 fifo_stat_reg; + u32 ctrl1_reg; + bool dma_enabled; + int i; + + regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); + regmap_read(micfil->regmap, REG_MICFIL_CTRL1, &ctrl1_reg); + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + + dma_enabled = MICFIL_DMA_ENABLED(ctrl1_reg); + + /* Channel 0-7 Output Data Flags */ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) { + if (stat_reg & MICFIL_STAT_CHXF_MASK(i)) + dev_dbg(&pdev->dev, + "Data available in Data Channel %d\n", i); + /* if DMA is not enabled, field must be written with 1 + * to clear + */ + if (!dma_enabled) + regmap_write_bits(micfil->regmap, + REG_MICFIL_STAT, + MICFIL_STAT_CHXF_MASK(i), + 1); + } + + for (i = 0; i < MICFIL_FIFO_NUM; i++) { + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_OVER_MASK(i)) + dev_dbg(&pdev->dev, + "FIFO Overflow Exception flag for channel %d\n", + i); + + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(i)) + dev_dbg(&pdev->dev, + "FIFO Underflow Exception flag for channel %d\n", + i); + } + + return IRQ_HANDLED; +} + +static irqreturn_t micfil_err_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct platform_device *pdev = micfil->pdev; + u32 stat_reg; + + regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); + + if (stat_reg & MICFIL_STAT_BSY_FIL_MASK) + dev_dbg(&pdev->dev, "isr: Decimation Filter is running\n"); + + if (stat_reg & MICFIL_STAT_FIR_RDY_MASK) + dev_dbg(&pdev->dev, "isr: FIR Filter Data ready\n"); + + if (stat_reg & MICFIL_STAT_LOWFREQF_MASK) { + dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); + regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, + MICFIL_STAT_LOWFREQF_MASK, 1); + } + + return IRQ_HANDLED; +} + +static int fsl_micfil_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + struct fsl_micfil *micfil; + struct resource *res; + void __iomem *regs; + int ret, i; + unsigned long irqflag = 0; + + micfil = devm_kzalloc(&pdev->dev, sizeof(*micfil), GFP_KERNEL); + if (!micfil) + return -ENOMEM; + + micfil->pdev = pdev; + strncpy(micfil->name, np->name, sizeof(micfil->name) - 1); + + of_id = of_match_device(fsl_micfil_dt_ids, &pdev->dev); + if (!of_id || !of_id->data) + return -EINVAL; + + micfil->soc = of_id->data; + + /* ipg_clk is used to control the registers + * ipg_clk_app is used to operate the filter + */ + micfil->mclk = devm_clk_get(&pdev->dev, "ipg_clk_app"); + if (IS_ERR(micfil->mclk)) { + dev_err(&pdev->dev, "failed to get core clock: %ld\n", + PTR_ERR(micfil->mclk)); + return PTR_ERR(micfil->mclk); + } + + /* init regmap */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + micfil->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "ipg_clk", + regs, + &fsl_micfil_regmap_config); + if (IS_ERR(micfil->regmap)) { + dev_err(&pdev->dev, "failed to init MICFIL regmap: %ld\n", + PTR_ERR(micfil->regmap)); + return PTR_ERR(micfil->regmap); + } + + /* dataline mask for RX */ + ret = of_property_read_u32_index(np, + "fsl,dataline", + 0, + &micfil->dataline); + if (ret) + micfil->dataline = 1; + + if (micfil->dataline & ~micfil->soc->dataline) { + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%X\n", + micfil->soc->dataline); + return -EINVAL; + } + + /* get IRQs */ + for (i = 0; i < MICFIL_IRQ_LINES; i++) { + micfil->irq[i] = platform_get_irq(pdev, i); + dev_err(&pdev->dev, "GET IRQ: %d\n", micfil->irq[i]); + if (micfil->irq[i] < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + return micfil->irq[i]; + } + } + + if (of_property_read_bool(np, "fsl,shared-interrupt")) + irqflag = IRQF_SHARED; + + /* Digital Microphone interface interrupt - IRQ 109 */ + ret = devm_request_irq(&pdev->dev, micfil->irq[0], + micfil_isr, irqflag, + micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim mic interface irq %u\n", + micfil->irq[0]); + return ret; + } + + /* Digital Microphone interface error interrupt - IRQ 110 */ + ret = devm_request_irq(&pdev->dev, micfil->irq[1], + micfil_err_isr, irqflag, + micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim mic interface error irq %u\n", + micfil->irq[1]); + return ret; + } + + micfil->dma_params_rx.chan_name = "rx"; + micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0; + micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX; + + + platform_set_drvdata(pdev, micfil); + + pm_runtime_enable(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_micfil_component, + &fsl_micfil_dai, 1); + if (ret) { + dev_err(&pdev->dev, "failed to register component %s\n", + fsl_micfil_component.name); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + dev_err(&pdev->dev, "failed to pcm register\n"); + + return ret; +} + +#ifdef CONFIG_PM +static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + + regcache_cache_only(micfil->regmap, true); + + clk_disable_unprepare(micfil->mclk); + + return 0; +} + +static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) + return ret; + + regcache_cache_only(micfil->regmap, false); + regcache_mark_dirty(micfil->regmap); + regcache_sync(micfil->regmap); + + return 0; +} +#endif /* CONFIG_PM*/ + +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused fsl_micfil_suspend(struct device *dev) +{ + pm_runtime_force_suspend(dev); + + return 0; +} + +static int __maybe_unused fsl_micfil_resume(struct device *dev) +{ + pm_runtime_force_resume(dev); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_micfil_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, + fsl_micfil_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend, + fsl_micfil_resume) +}; + +static struct platform_driver fsl_micfil_driver = { + .probe = fsl_micfil_probe, + .driver = { + .name = "fsl-micfil-dai", + .pm = &fsl_micfil_pm_ops, + .of_match_table = fsl_micfil_dt_ids, + }, +}; +module_platform_driver(fsl_micfil_driver); + +MODULE_AUTHOR("Cosmin-Gabriel Samoila "); +MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h new file mode 100644 index 000000000000..bac825c3135a --- /dev/null +++ b/sound/soc/fsl/fsl_micfil.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PDM Microphone Interface for the NXP i.MX SoC + * Copyright 2018 NXP + */ + +#ifndef _FSL_MICFIL_H +#define _FSL_MICFIL_H + +/* MICFIL Register Map */ +#define REG_MICFIL_CTRL1 0x00 +#define REG_MICFIL_CTRL2 0x04 +#define REG_MICFIL_STAT 0x08 +#define REG_MICFIL_FIFO_CTRL 0x10 +#define REG_MICFIL_FIFO_STAT 0x14 +#define REG_MICFIL_DATACH0 0x24 +#define REG_MICFIL_DATACH1 0x28 +#define REG_MICFIL_DATACH2 0x2C +#define REG_MICFIL_DATACH3 0x30 +#define REG_MICFIL_DATACH4 0x34 +#define REG_MICFIL_DATACH5 0x38 +#define REG_MICFIL_DATACH6 0x3C +#define REG_MICFIL_DATACH7 0x40 +#define REG_MICFIL_DC_CTRL 0x64 +#define REG_MICFIL_OUT_CTRL 0x74 +#define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_VAD0_CTRL1 0x90 +#define REG_MICFIL_VAD0_CTRL2 0x94 +#define REG_MICFIL_VAD0_STAT 0x98 +#define REG_MICFIL_VAD0_SCONFIG 0x9C +#define REG_MICFIL_VAD0_NCONFIG 0xA0 +#define REG_MICFIL_VAD0_NDATA 0xA4 +#define REG_MICFIL_VAD0_ZCD 0xA8 + +/* MICFIL Control Register 1 -- REG_MICFILL_CTRL1 0x00 */ +#define MICFIL_CTRL1_MDIS_SHIFT 31 +#define MICFIL_CTRL1_MDIS_MASK BIT(MICFIL_CTRL1_MDIS_SHIFT) +#define MICFIL_CTRL1_MDIS BIT(MICFIL_CTRL1_MDIS_SHIFT) +#define MICFIL_CTRL1_DOZEN_SHIFT 30 +#define MICFIL_CTRL1_DOZEN_MASK BIT(MICFIL_CTRL1_DOZEN_SHIFT) +#define MICFIL_CTRL1_DOZEN BIT(MICFIL_CTRL1_DOZEN_SHIFT) +#define MICFIL_CTRL1_PDMIEN_SHIFT 29 +#define MICFIL_CTRL1_PDMIEN_MASK BIT(MICFIL_CTRL1_PDMIEN_SHIFT) +#define MICFIL_CTRL1_PDMIEN BIT(MICFIL_CTRL1_PDMIEN_SHIFT) +#define MICFIL_CTRL1_DBG_SHIFT 28 +#define MICFIL_CTRL1_DBG_MASK BIT(MICFIL_CTRL1_DBG_SHIFT) +#define MICFIL_CTRL1_DBG BIT(MICFIL_CTRL1_DBG_SHIFT) +#define MICFIL_CTRL1_SRES_SHIFT 27 +#define MICFIL_CTRL1_SRES_MASK BIT(MICFIL_CTRL1_SRES_SHIFT) +#define MICFIL_CTRL1_SRES BIT(MICFIL_CTRL1_SRES_SHIFT) +#define MICFIL_CTRL1_DBGE_SHIFT 26 +#define MICFIL_CTRL1_DBGE_MASK BIT(MICFIL_CTRL1_DBGE_SHIFT) +#define MICFIL_CTRL1_DBGE BIT(MICFIL_CTRL1_DBGE_SHIFT) +#define MICFIL_CTRL1_DISEL_SHIFT 24 +#define MICFIL_CTRL1_DISEL_WIDTH 2 +#define MICFIL_CTRL1_DISEL_MASK ((BIT(MICFIL_CTRL1_DISEL_WIDTH) - 1) \ + << MICFIL_CTRL1_DISEL_SHIFT) +#define MICFIL_CTRL1_DISEL(v) (((v) << MICFIL_CTRL1_DISEL_SHIFT) \ + & MICFIL_CTRL1_DISEL_MASK) +#define MICFIL_CTRL1_ERREN_SHIFT 23 +#define MICFIL_CTRL1_ERREN_MASK BIT(MICFIL_CTRL1_ERREN_SHIFT) +#define MICFIL_CTRL1_ERREN BIT(MICFIL_CTRL1_ERREN_SHIFT) +#define MICFIL_CTRL1_CHEN_SHIFT 0 +#define MICFIL_CTRL1_CHEN_WIDTH 8 +#define MICFIL_CTRL1_CHEN_MASK(x) (BIT(x) << MICFIL_CTRL1_CHEN_SHIFT) +#define MICFIL_CTRL1_CHEN(x) (MICFIL_CTRL1_CHEN_MASK(x)) + +/* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ +#define MICFIL_CTRL2_QSEL_SHIFT 25 +#define MICFIL_CTRL2_QSEL_WIDTH 3 +#define MICFIL_CTRL2_QSEL_MASK ((BIT(MICFIL_CTRL2_QSEL_WIDTH) - 1) \ + << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_HIGH_QUALITY BIT(MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_MEDIUM_QUALITY (0 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_LOW_QUALITY (7 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW0_QUALITY (6 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW1_QUALITY (5 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW2_QUALITY (4 << MICFIL_CTRL2_QSEL_SHIFT) + +#define MICFIL_CTRL2_CICOSR_SHIFT 16 +#define MICFIL_CTRL2_CICOSR_WIDTH 4 +#define MICFIL_CTRL2_CICOSR_MASK ((BIT(MICFIL_CTRL2_CICOSR_WIDTH) - 1) \ + << MICFIL_CTRL2_CICOSR_SHIFT) +#define MICFIL_CTRL2_CICOSR(v) (((v) << MICFIL_CTRL2_CICOSR_SHIFT) \ + & MICFIL_CTRL2_CICOSR_MASK) +#define MICFIL_CTRL2_CLKDIV_SHIFT 0 +#define MICFIL_CTRL2_CLKDIV_WIDTH 8 +#define MICFIL_CTRL2_CLKDIV_MASK ((BIT(MICFIL_CTRL2_CLKDIV_WIDTH) - 1) \ + << MICFIL_CTRL2_CLKDIV_SHIFT) +#define MICFIL_CTRL2_CLKDIV(v) (((v) << MICFIL_CTRL2_CLKDIV_SHIFT) \ + & MICFIL_CTRL2_CLKDIV_MASK) + +/* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */ +#define MICFIL_STAT_BSY_FIL_SHIFT 31 +#define MICFIL_STAT_BSY_FIL_MASK BIT(MICFIL_STAT_BSY_FIL_SHIFT) +#define MICFIL_STAT_BSY_FIL BIT(MICFIL_STAT_BSY_FIL_SHIFT) +#define MICFIL_STAT_FIR_RDY_SHIFT 30 +#define MICFIL_STAT_FIR_RDY_MASK BIT(MICFIL_STAT_FIR_RDY_SHIFT) +#define MICFIL_STAT_FIR_RDY BIT(MICFIL_STAT_FIR_RDY_SHIFT) +#define MICFIL_STAT_LOWFREQF_SHIFT 29 +#define MICFIL_STAT_LOWFREQF_MASK BIT(MICFIL_STAT_LOWFREQF_SHIFT) +#define MICFIL_STAT_LOWFREQF BIT(MICFIL_STAT_LOWFREQF_SHIFT) +#define MICFIL_STAT_CHXF_SHIFT(v) (v) +#define MICFIL_STAT_CHXF_MASK(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) +#define MICFIL_STAT_CHXF(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) + +/* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ +#define MICFIL_FIFO_CTRL_FIFOWMK_SHIFT 0 +#define MICFIL_FIFO_CTRL_FIFOWMK_WIDTH 3 +#define MICFIL_FIFO_CTRL_FIFOWMK_MASK ((BIT(MICFIL_FIFO_CTRL_FIFOWMK_WIDTH) - 1) \ + << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) +#define MICFIL_FIFO_CTRL_FIFOWMK(v) (((v) << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) \ + & MICFIL_FIFO_CTRL_FIFOWMK_MASK) + +/* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ +#define MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v) (v) +#define MICFIL_FIFO_STAT_FIFOX_OVER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v)) +#define MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v) ((v) + 8) +#define MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v)) + +/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ +#define MICFIL_VAD0_CTRL1_CHSEL_SHIFT 24 +#define MICFIL_VAD0_CTRL1_CHSEL_WIDTH 3 +#define MICFIL_VAD0_CTRL1_CHSEL_MASK ((BIT(MICFIL_VAD0_CTRL1_CHSEL_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) +#define MICFIL_VAD0_CTRL1_CHSEL(v) (((v) << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) \ + & MICFIL_VAD0_CTRL1_CHSEL_MASK) +#define MICFIL_VAD0_CTRL1_CICOSR_SHIFT 16 +#define MICFIL_VAD0_CTRL1_CICOSR_WIDTH 4 +#define MICFIL_VAD0_CTRL1_CICOSR_MASK ((BIT(MICFIL_VAD0_CTRL1_CICOSR_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) +#define MICFIL_VAD0_CTRL1_CICOSR(v) (((v) << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) \ + & MICFIL_VAD0_CTRL1_CICOSR_MASK) +#define MICFIL_VAD0_CTRL1_INITT_SHIFT 8 +#define MICFIL_VAD0_CTRL1_INITT_WIDTH 5 +#define MICFIL_VAD0_CTRL1_INITT_MASK ((BIT(MICFIL_VAD0_CTRL1_INITT_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_INITT_SHIFT) +#define MICFIL_VAD0_CTRL1_INITT(v) (((v) << MICFIL_VAD0_CTRL1_INITT_SHIFT) \ + & MICFIL_VAD0_CTRL1_INITT_MASK) +#define MICFIL_VAD0_CTRL1_ST10_SHIFT 4 +#define MICFIL_VAD0_CTRL1_ST10_MASK BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) +#define MICFIL_VAD0_CTRL1_ST10 BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) +#define MICFIL_VAD0_CTRL1_ERIE_SHIFT 3 +#define MICFIL_VAD0_CTRL1_ERIE_MASK BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) +#define MICFIL_VAD0_CTRL1_ERIE BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) +#define MICFIL_VAD0_CTRL1_IE_SHIFT 2 +#define MICFIL_VAD0_CTRL1_IE_MASK BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) +#define MICFIL_VAD0_CTRL1_IE BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) +#define MICFIL_VAD0_CTRL1_RST_SHIFT 1 +#define MICFIL_VAD0_CTRL1_RST_MASK BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) +#define MICFIL_VAD0_CTRL1_RST BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) +#define MICFIL_VAD0_CTRL1_EN_SHIFT 0 +#define MICFIL_VAD0_CTRL1_EN_MASK BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) +#define MICFIL_VAD0_CTRL1_EN BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) + +/* MICFIL HWVAD0 Control 2 Register -- REG_MICFIL_VAD0_CTRL2*/ +#define MICFIL_VAD0_CTRL2_FRENDIS_SHIFT 31 +#define MICFIL_VAD0_CTRL2_FRENDIS_MASK BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FRENDIS BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_PREFEN_SHIFT 30 +#define MICFIL_VAD0_CTRL2_PREFEN_MASK BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) +#define MICFIL_VAD0_CTRL2_PREFEN BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) +#define MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT 28 +#define MICFIL_VAD0_CTRL2_FOUTDIS_MASK BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FRAMET_SHIFT 16 +#define MICFIL_VAD0_CTRL2_FRAMET_WIDTH 6 +#define MICFIL_VAD0_CTRL2_FRAMET_MASK ((BIT(MICFIL_VAD0_CTRL2_FRAMET_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) +#define MICFIL_VAD0_CTRL2_FRAMET(v) (((v) << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) \ + & MICFIL_VAD0_CTRL2_FRAMET_MASK) +#define MICFIL_VAD0_CTRL2_INPGAIN_SHIFT 8 +#define MICFIL_VAD0_CTRL2_INPGAIN_WIDTH 4 +#define MICFIL_VAD0_CTRL2_INPGAIN_MASK ((BIT(MICFIL_VAD0_CTRL2_INPGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) +#define MICFIL_VAD0_CTRL2_INPGAIN(v) (((v) << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) \ + & MICFIL_VAD0_CTRL2_INPGAIN_MASK) +#define MICFIL_VAD0_CTRL2_HPF_SHIFT 0 +#define MICFIL_VAD0_CTRL2_HPF_WIDTH 2 +#define MICFIL_VAD0_CTRL2_HPF_MASK ((BIT(MICFIL_VAD0_CTRL2_HPF_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_HPF_SHIFT) +#define MICFIL_VAD0_CTRL2_HPF(v) (((v) << MICFIL_VAD0_CTRL2_HPF_SHIFT) \ + & MICFIL_VAD0_CTRL2_HPF_MASK) + +/* MICFIL HWVAD0 Signal CONFIG Register -- REG_MICFIL_VAD0_SCONFIG */ +#define MICFIL_VAD0_SCONFIG_SFILEN_SHIFT 31 +#define MICFIL_VAD0_SCONFIG_SFILEN_MASK BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SFILEN BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT 30 +#define MICFIL_VAD0_SCONFIG_SMAXEN_MASK BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SGAIN_SHIFT 0 +#define MICFIL_VAD0_SCONFIG_SGAIN_WIDTH 4 +#define MICFIL_VAD0_SCONFIG_SGAIN_MASK ((BIT(MICFIL_VAD0_SCONFIG_SGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SGAIN(v) (((v) << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) \ + & MICFIL_VAD0_SCONFIG_SGAIN_MASK) + +/* MICFIL HWVAD0 Noise CONFIG Register -- REG_MICFIL_VAD0_NCONFIG */ +#define MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT 31 +#define MICFIL_VAD0_NCONFIG_NFILAUT_MASK BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) +#define MICFIL_VAD0_NCONFIG_NMINEN_SHIFT 30 +#define MICFIL_VAD0_NCONFIG_NMINEN_MASK BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NMINEN BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NDECEN_SHIFT 29 +#define MICFIL_VAD0_NCONFIG_NDECEN_MASK BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NDECEN BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NOREN_SHIFT 28 +#define MICFIL_VAD0_NCONFIG_NOREN BIT(MICFIL_VAD0_NCONFIG_NOREN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT 8 +#define MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH 5 +#define MICFIL_VAD0_NCONFIG_NFILADJ_MASK ((BIT(MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH) - 1) \ + << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILADJ(v) (((v) << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) \ + & MICFIL_VAD0_NCONFIG_NFILADJ_MASK) +#define MICFIL_VAD0_NCONFIG_NGAIN_SHIFT 0 +#define MICFIL_VAD0_NCONFIG_NGAIN_WIDTH 4 +#define MICFIL_VAD0_NCONFIG_NGAIN_MASK ((BIT(MICFIL_VAD0_NCONFIG_NGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NGAIN(v) (((v) << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) \ + & MICFIL_VAD0_NCONFIG_NGAIN_MASK) + +/* MICFIL HWVAD0 Zero-Crossing Detector - REG_MICFIL_VAD0_ZCD */ +#define MICFIL_VAD0_ZCD_ZCDTH_SHIFT 16 +#define MICFIL_VAD0_ZCD_ZCDTH_WIDTH 10 +#define MICFIL_VAD0_ZCD_ZCDTH_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDTH_WIDTH) - 1) \ + << MICFIL_VAD0_ZCD_ZCDTH_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDTH(v) (((v) << MICFIL_VAD0_ZCD_ZCDTH_SHIFT)\ + & MICFIL_VAD0_ZCD_ZCDTH_MASK) +#define MICFIL_VAD0_ZCD_ZCDADJ_SHIFT 8 +#define MICFIL_VAD0_ZCD_ZCDADJ_WIDTH 4 +#define MICFIL_VAD0_ZCD_ZCDADJ_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDADJ_WIDTH) - 1)\ + << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDADJ(v) (((v) << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT)\ + & MICFIL_VAD0_ZCD_ZCDADJ_MASK) +#define MICFIL_VAD0_ZCD_ZCDAND_SHIFT 4 +#define MICFIL_VAD0_ZCD_ZCDAND_MASK BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAND BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAUT_SHIFT 2 +#define MICFIL_VAD0_ZCD_ZCDAUT_MASK BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAUT BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDEN_SHIFT 0 +#define MICFIL_VAD0_ZCD_ZCDEN_MASK BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDEN BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) + +/* MICFIL HWVAD0 Status Register - REG_MICFIL_VAD0_STAT */ +#define MICFIL_VAD0_STAT_INITF_SHIFT 31 +#define MICFIL_VAD0_STAT_INITF_MASK BIT(MICFIL_VAD0_STAT_INITF_SHIFT) +#define MICFIL_VAD0_STAT_INITF BIT(MICFIL_VAD0_STAT_INITF_SHIFT) +#define MICFIL_VAD0_STAT_INSATF_SHIFT 16 +#define MICFIL_VAD0_STAT_INSATF_MASK BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) +#define MICFIL_VAD0_STAT_INSATF BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) +#define MICFIL_VAD0_STAT_EF_SHIFT 15 +#define MICFIL_VAD0_STAT_EF_MASK BIT(MICFIL_VAD0_STAT_EF_SHIFT) +#define MICFIL_VAD0_STAT_EF BIT(MICFIL_VAD0_STAT_EF_SHIFT) +#define MICFIL_VAD0_STAT_IF_SHIFT 0 +#define MICFIL_VAD0_STAT_IF_MASK BIT(MICFIL_VAD0_STAT_IF_SHIFT) +#define MICFIL_VAD0_STAT_IF BIT(MICFIL_VAD0_STAT_IF_SHIFT) + +/* MICFIL Output Control Register */ +#define MICFIL_OUTGAIN_CHX_SHIFT(v) (4 * (v)) + +/* Constants */ +#define MICFIL_DMA_IRQ_DISABLED(v) ((v) & MICFIL_CTRL1_DISEL_MASK) +#define MICFIL_DMA_ENABLED(v) ((0x1 << MICFIL_CTRL1_DISEL_SHIFT) \ + == ((v) & MICFIL_CTRL1_DISEL_MASK)) +#define MICFIL_IRQ_ENABLED(v) ((0x2 << MICFIL_CTRL1_DISEL_SHIFT) \ + == ((v) & MICFIL_CTRL1_DISEL_MASK)) +#define MICFIL_OUTPUT_CHANNELS 8 +#define MICFIL_FIFO_NUM 8 + +#define FIFO_PTRWID 3 +#define FIFO_LEN BIT(FIFO_PTRWID) + +#define MICFIL_IRQ_LINES 2 +#define MICFIL_MAX_RETRY 25 +#define MICFIL_SLEEP_MIN 90000 /* in us */ +#define MICFIL_SLEEP_MAX 100000 /* in us */ +#define MICFIL_DMA_MAXBURST_RX 6 +#define MICFIL_CTRL2_OSR_DEFAULT (0 << MICFIL_CTRL2_CICOSR_SHIFT) + +#endif /* _FSL_MICFIL_H */ From 2f00f7715e624d04e25d9cb8bb0f53884d3bcb59 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:51 +0530 Subject: [PATCH 086/461] dt-bindings: ASoC: xlnx, spdif: Document spdif bindings Added documentation for SPDIF IP DT bindings. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/xlnx,spdif.txt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/xlnx,spdif.txt diff --git a/Documentation/devicetree/bindings/sound/xlnx,spdif.txt b/Documentation/devicetree/bindings/sound/xlnx,spdif.txt new file mode 100644 index 000000000000..15c2d64d247c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/xlnx,spdif.txt @@ -0,0 +1,28 @@ +Device-Tree bindings for Xilinx SPDIF IP + +The IP supports playback and capture of SPDIF audio + +Required properties: + - compatible: "xlnx,spdif-2.0" + - clock-names: List of input clocks. + Required elements: "s_axi_aclk", "aud_clk_i" + - clocks: Input clock specifier. Refer to common clock bindings. + - reg: Base address and address length of the IP core instance. + - interrupts-parent: Phandle for interrupt controller. + - interrupts: List of Interrupt numbers. + - xlnx,spdif-mode: 0 :- receiver mode + 1 :- transmitter mode + - xlnx,aud_clk_i: input audio clock value. + +Example: + spdif_0: spdif@80010000 { + clock-names = "aud_clk_i", "s_axi_aclk"; + clocks = <&misc_clk_0>, <&clk 71>; + compatible = "xlnx,spdif-2.0"; + interrupt-names = "spdif_interrupt"; + interrupt-parent = <&gic>; + interrupts = <0 91 4>; + reg = <0x0 0x80010000 0x0 0x10000>; + xlnx,spdif-mode = <1>; + xlnx,aud_clk_i = <49152913>; + }; From b1d2a4cca20cb84ffe02116fd8d2b91a94d49d5e Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:52 +0530 Subject: [PATCH 087/461] ASoC: xlnx: add SPDIF audio driver Added SPDIF audio driver. This provides playback and capture of AES audio over SPDIF interface. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_spdif.c | 339 ++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_spdif.c diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c new file mode 100644 index 000000000000..3b9000fd8c49 --- /dev/null +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Xilinx ASoC SPDIF audio support +// +// Copyright (C) 2018 Xilinx, Inc. +// +// Author: Maruthi Srinivas Bayyavarapu +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#define XLNX_SPDIF_RATES \ + (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +#define XLNX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +#define XSPDIF_IRQ_STS_REG 0x20 +#define XSPDIF_IRQ_ENABLE_REG 0x28 +#define XSPDIF_SOFT_RESET_REG 0x40 +#define XSPDIF_CONTROL_REG 0x44 +#define XSPDIF_CHAN_0_STS_REG 0x4C +#define XSPDIF_GLOBAL_IRQ_ENABLE_REG 0x1C +#define XSPDIF_CH_A_USER_DATA_REG_0 0x64 + +#define XSPDIF_CORE_ENABLE_MASK BIT(0) +#define XSPDIF_FIFO_FLUSH_MASK BIT(1) +#define XSPDIF_CH_STS_MASK BIT(5) +#define XSPDIF_GLOBAL_IRQ_ENABLE BIT(31) +#define XSPDIF_CLOCK_CONFIG_BITS_MASK GENMASK(5, 2) +#define XSPDIF_CLOCK_CONFIG_BITS_SHIFT 2 +#define XSPDIF_SOFT_RESET_VALUE 0xA + +#define MAX_CHANNELS 2 +#define AES_SAMPLE_WIDTH 32 +#define CH_STATUS_UPDATE_TIMEOUT 40 + +struct spdif_dev_data { + u32 mode; + u32 aclk; + bool rx_chsts_updated; + void __iomem *base; + struct clk *axi_clk; + wait_queue_head_t chsts_q; +}; + +static irqreturn_t xlnx_spdifrx_irq_handler(int irq, void *arg) +{ + u32 val; + struct spdif_dev_data *ctx = arg; + + val = readl(ctx->base + XSPDIF_IRQ_STS_REG); + if (val & XSPDIF_CH_STS_MASK) { + writel(val & XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_STS_REG); + val = readl(ctx->base + + XSPDIF_IRQ_ENABLE_REG); + writel(val & ~XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_ENABLE_REG); + + ctx->rx_chsts_updated = true; + wake_up_interruptible(&ctx->chsts_q); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int xlnx_spdif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u32 val; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + val |= XSPDIF_FIFO_FLUSH_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + writel(XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_ENABLE_REG); + writel(XSPDIF_GLOBAL_IRQ_ENABLE, + ctx->base + XSPDIF_GLOBAL_IRQ_ENABLE_REG); + } + + return 0; +} + +static void xlnx_spdif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); +} + +static int xlnx_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u32 val, clk_div, clk_cfg; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + clk_div = DIV_ROUND_CLOSEST(ctx->aclk, MAX_CHANNELS * AES_SAMPLE_WIDTH * + params_rate(params)); + + switch (clk_div) { + case 4: + clk_cfg = 0; + break; + case 8: + clk_cfg = 1; + break; + case 16: + clk_cfg = 2; + break; + case 24: + clk_cfg = 3; + break; + case 32: + clk_cfg = 4; + break; + case 48: + clk_cfg = 5; + break; + case 64: + clk_cfg = 6; + break; + default: + return -EINVAL; + } + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + val &= ~XSPDIF_CLOCK_CONFIG_BITS_MASK; + val |= clk_cfg << XSPDIF_CLOCK_CONFIG_BITS_SHIFT; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + + return 0; +} + +static int rx_stream_detect(struct snd_soc_dai *dai) +{ + int err; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + unsigned long jiffies = msecs_to_jiffies(CH_STATUS_UPDATE_TIMEOUT); + + /* start capture only if stream is detected within 40ms timeout */ + err = wait_event_interruptible_timeout(ctx->chsts_q, + ctx->rx_chsts_updated, + jiffies); + if (!err) { + dev_err(dai->dev, "No streaming audio detected!\n"); + return -EINVAL; + } + ctx->rx_chsts_updated = false; + + return 0; +} + +static int xlnx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + u32 val; + int ret = 0; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val |= XSPDIF_CORE_ENABLE_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + ret = rx_stream_detect(dai); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val &= ~XSPDIF_CORE_ENABLE_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct snd_soc_dai_ops xlnx_spdif_dai_ops = { + .startup = xlnx_spdif_startup, + .shutdown = xlnx_spdif_shutdown, + .trigger = xlnx_spdif_trigger, + .hw_params = xlnx_spdif_hw_params, +}; + +static struct snd_soc_dai_driver xlnx_spdif_tx_dai = { + .name = "xlnx_spdif_tx", + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = XLNX_SPDIF_RATES, + .formats = XLNX_SPDIF_FORMATS, + }, + .ops = &xlnx_spdif_dai_ops, +}; + +static struct snd_soc_dai_driver xlnx_spdif_rx_dai = { + .name = "xlnx_spdif_rx", + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = XLNX_SPDIF_RATES, + .formats = XLNX_SPDIF_FORMATS, + }, + .ops = &xlnx_spdif_dai_ops, +}; + +static const struct snd_soc_component_driver xlnx_spdif_component = { + .name = "xlnx-spdif", +}; + +static const struct of_device_id xlnx_spdif_of_match[] = { + { .compatible = "xlnx,spdif-2.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_spdif_of_match); + +static int xlnx_spdif_probe(struct platform_device *pdev) +{ + int ret; + struct resource *res; + struct snd_soc_dai_driver *dai_drv; + struct spdif_dev_data *ctx; + + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->axi_clk = devm_clk_get(dev, "s_axi_aclk"); + if (IS_ERR(ctx->axi_clk)) { + ret = PTR_ERR(ctx->axi_clk); + dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret); + return ret; + } + ret = clk_prepare_enable(ctx->axi_clk); + if (ret) { + dev_err(dev, "failed to enable s_axi_aclk(%d)\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctx->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->base)) { + ret = PTR_ERR(ctx->base); + goto clk_err; + } + ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode); + if (ret < 0) { + dev_err(dev, "cannot get SPDIF mode\n"); + goto clk_err; + } + if (ctx->mode) { + dai_drv = &xlnx_spdif_tx_dai; + } else { + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "No IRQ resource found\n"); + ret = -ENODEV; + goto clk_err; + } + ret = devm_request_irq(dev, res->start, + xlnx_spdifrx_irq_handler, + 0, "XLNX_SPDIF_RX", ctx); + if (ret) { + dev_err(dev, "spdif rx irq request failed\n"); + ret = -ENODEV; + goto clk_err; + } + + init_waitqueue_head(&ctx->chsts_q); + dai_drv = &xlnx_spdif_rx_dai; + } + + ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk); + if (ret < 0) { + dev_err(dev, "cannot get aud_clk_i value\n"); + goto clk_err; + } + + dev_set_drvdata(dev, ctx); + + ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component, + dai_drv, 1); + if (ret) { + dev_err(dev, "SPDIF component registration failed\n"); + goto clk_err; + } + + writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); + dev_info(dev, "%s DAI registered\n", dai_drv->name); + +clk_err: + clk_disable_unprepare(ctx->axi_clk); + return ret; +} + +static int xlnx_spdif_remove(struct platform_device *pdev) +{ + struct spdif_dev_data *ctx = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(ctx->axi_clk); + return 0; +} + +static struct platform_driver xlnx_spdif_driver = { + .driver = { + .name = "xlnx-spdif", + .of_match_table = xlnx_spdif_of_match, + }, + .probe = xlnx_spdif_probe, + .remove = xlnx_spdif_remove, +}; +module_platform_driver(xlnx_spdif_driver); + +MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu "); +MODULE_DESCRIPTION("XILINX SPDIF driver"); +MODULE_LICENSE("GPL v2"); From 47caf048a017ecc95cdd0802bc3b015a1559e601 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:53 +0530 Subject: [PATCH 088/461] ASoC: xlnx: enable SPDIF driver build Added SPDIF driver build related changes. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/Kconfig | 7 +++++++ sound/soc/xilinx/Makefile | 2 ++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index ac48d6a00c36..47f606b924e4 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -13,3 +13,10 @@ config SND_SOC_XILINX_AUDIO_FORMATTER Select this option to enable Xilinx audio formatter support. This provides DMA platform device support for audio functionality. + +config SND_SOC_XILINX_SPDIF + tristate "Audio support for the the Xilinx SPDIF" + help + Select this option to enable Xilinx SPDIF Audio. + This provides playback and capture of SPDIF audio in + AES format. diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile index 432693b1cc79..d79fd38b094b 100644 --- a/sound/soc/xilinx/Makefile +++ b/sound/soc/xilinx/Makefile @@ -2,3 +2,5 @@ snd-soc-xlnx-i2s-objs := xlnx_i2s.o obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o +snd-soc-xlnx-spdif-objs := xlnx_spdif.o +obj-$(CONFIG_SND_SOC_XILINX_SPDIF) += snd-soc-xlnx-spdif.o From 5dc4ca2996840db569e43d00420c10499140274a Mon Sep 17 00:00:00 2001 From: Alison Wang Date: Wed, 26 Dec 2018 08:59:53 +0800 Subject: [PATCH 089/461] ASoC: sgtl5000: Allow SCLK pad drive strength to be changed This patch introduces "sclk-strength" property to allow SCLK pad drive strength to be changed via device tree. When running playback test on LS1028ARDB, Tx Frame sync error interrupt will occur sometimes. Some noises also exist. After changing SCLK pad drive strength to the maximum value, the issues are gone. Signed-off-by: Alison Wang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sgtl5000.txt | 9 +++++++++ sound/soc/codecs/sgtl5000.c | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 9c58f724396a..9d9ff5184939 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -37,6 +37,15 @@ VDDIO 1.8V 2.5V 3.3V 2 = 3.33 mA 5.74 mA 8.03 mA 3 = 4.99 mA 8.61 mA 12.05 mA +- sclk-strength: the SCLK pad strength. Possible values are: +0, 1, 2 and 3 as per the table below: + +VDDIO 1.8V 2.5V 3.3V +0 = Disable +1 = 1.66 mA 2.87 mA 4.02 mA +2 = 3.33 mA 5.74 mA 8.03 mA +3 = 4.99 mA 8.61 mA 12.05 mA + Example: sgtl5000: codec@a { diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index add18d6d77da..a6a4748c97f9 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -116,6 +116,13 @@ enum { I2S_LRCLK_STRENGTH_HIGH, }; +enum { + I2S_SCLK_STRENGTH_DISABLE, + I2S_SCLK_STRENGTH_LOW, + I2S_SCLK_STRENGTH_MEDIUM, + I2S_SCLK_STRENGTH_HIGH, +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -129,6 +136,7 @@ struct sgtl5000_priv { u8 micbias_resistor; u8 micbias_voltage; u8 lrclk_strength; + u8 sclk_strength; }; /* @@ -1302,7 +1310,9 @@ static int sgtl5000_probe(struct snd_soc_component *component) SGTL5000_DAC_MUTE_RIGHT | SGTL5000_DAC_MUTE_LEFT); - reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | 0x5f); + reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | + (sgtl5000->sclk_strength) << SGTL5000_PAD_I2S_SCLK_SHIFT | + 0x1f); snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg); snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL, @@ -1542,6 +1552,13 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, sgtl5000->lrclk_strength = value; } + sgtl5000->sclk_strength = I2S_SCLK_STRENGTH_LOW; + if (!of_property_read_u32(np, "sclk-strength", &value)) { + if (value > I2S_SCLK_STRENGTH_HIGH) + value = I2S_SCLK_STRENGTH_LOW; + sgtl5000->sclk_strength = value; + } + /* Ensure sgtl5000 will start with sane register values */ sgtl5000_fill_defaults(client); From 7674bec4fc09e85803a8f2bd26a013d0076a80a9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Dec 2018 14:05:28 +0900 Subject: [PATCH 090/461] ASoC: rsnd: update BSDSR/BSDISR handling Current BSDSR/BSDISR are using temporary/generic settings, but it can't handle all SRCx/SoC. It needs to handle correctry. Otherwise, sampling rate converted sound channel will be broken if it was TDM. One note is that it needs to overwrite settings on E3 case. Signed-off-by: Kuninori Morimoto Tested-by: chaoliang qin Tested-by: Yusuke Goda Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 125 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 50348a2c9203..db81e066b92e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -14,6 +14,7 @@ */ #include "rsnd.h" +#include #define SRC_NAME "src" @@ -134,20 +135,83 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, return rate; } +const static u32 bsdsr_table_pattern1[] = { + 0x01800000, /* 6 - 1/6 */ + 0x01000000, /* 6 - 1/4 */ + 0x00c00000, /* 6 - 1/3 */ + 0x00800000, /* 6 - 1/2 */ + 0x00600000, /* 6 - 2/3 */ + 0x00400000, /* 6 - 1 */ +}; + +const static u32 bsdsr_table_pattern2[] = { + 0x02400000, /* 6 - 1/6 */ + 0x01800000, /* 6 - 1/4 */ + 0x01200000, /* 6 - 1/3 */ + 0x00c00000, /* 6 - 1/2 */ + 0x00900000, /* 6 - 2/3 */ + 0x00600000, /* 6 - 1 */ +}; + +const static u32 bsisr_table[] = { + 0x00100060, /* 6 - 1/6 */ + 0x00100040, /* 6 - 1/4 */ + 0x00100030, /* 6 - 1/3 */ + 0x00100020, /* 6 - 1/2 */ + 0x00100020, /* 6 - 2/3 */ + 0x00100020, /* 6 - 1 */ +}; + +const static u32 chan288888[] = { + 0x00000006, /* 1 to 2 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan244888[] = { + 0x00000006, /* 1 to 2 */ + 0x0000001e, /* 1 to 4 */ + 0x0000001e, /* 1 to 4 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan222222[] = { + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ +}; + +static const struct soc_device_attribute ov_soc[] = { + { .soc_id = "r8a77990" }, /* E3 */ + { /* sentinel */ } +}; + static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + const struct soc_device_attribute *soc = soc_device_match(ov_soc); int is_play = rsnd_io_is_play(io); int use_src = 0; u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; - u32 bsdsr, bsisr; u32 i_busif, o_busif, tmp; + const u32 *bsdsr_table; + const u32 *chptn; uint ratio; + int chan; + int idx; if (!runtime) return; @@ -155,6 +219,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, fin = rsnd_src_get_in_rate(priv, io); fout = rsnd_src_get_out_rate(priv, io); + chan = rsnd_runtime_channel_original(io); + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ if (fin == fout) ratio = 0; @@ -173,8 +239,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_ADINR */ - adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_runtime_channel_original(io); + adinr = rsnd_get_adinr_bit(mod, io) | chan; /* * SRC_IFSCR / SRC_IFSVR @@ -207,21 +272,56 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_BSDSR / SRC_BSISR + * + * see + * Combination of Register Setting Related to + * FSO/FSI Ratio and Channel, Latency */ switch (rsnd_mod_id(mod)) { + case 0: + chptn = chan288888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 1: + case 3: + case 4: + chptn = chan244888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 2: + case 9: + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern1; + break; case 5: case 6: case 7: case 8: - bsdsr = 0x02400000; /* 6 - 1/6 */ - bsisr = 0x00100060; /* 6 - 1/6 */ + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern2; break; default: - bsdsr = 0x01800000; /* 6 - 1/6 */ - bsisr = 0x00100060 ;/* 6 - 1/6 */ - break; + goto convert_rate_err; } + /* + * E3 need to overwrite + */ + if (soc) + switch (rsnd_mod_id(mod)) { + case 0: + case 4: + chptn = chan222222; + } + + for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) + if (chptn[idx] & (1 << chan)) + break; + + if (chan > 8 || + idx >= ARRAY_SIZE(chan222222)) + goto convert_rate_err; + /* BUSIF_MODE */ tmp = rsnd_get_busif_shift(io, mod); i_busif = ( is_play ? tmp : 0) | 1; @@ -234,8 +334,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_IFSCR, ifscr); rsnd_mod_write(mod, SRC_IFSVR, fsrate); rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_BSDSR, bsdsr); - rsnd_mod_write(mod, SRC_BSISR, bsisr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); + rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); @@ -244,6 +344,11 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); + + return; + +convert_rate_err: + dev_err(dev, "unknown BSDSR/BSDIR settings\n"); } static int rsnd_src_irq(struct rsnd_mod *mod, From d3dcc5882ca95c9207b5232395c291d34a511627 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:19 +0100 Subject: [PATCH 091/461] ASoC: Intel: common: Add quirk for PoV P1006W tablet The Point of View TAB-P1006W-232 (v1.0) tablet uses 10EC5640 as ACPI HID, but it has a rt5651 codec add a quirk for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-byt-match.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 47a90909b956..96f9c553fe6c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -21,6 +21,7 @@ static unsigned long byt_machine_id; #define BYT_THINKPAD_10 1 +#define BYT_POV_P1006W 2 static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) { @@ -28,6 +29,11 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_machine_id = BYT_POV_P1006W; + return 1; +} static const struct dmi_system_id byt_table[] = { { @@ -58,6 +64,17 @@ static const struct dmi_system_id byt_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), }, }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + }, { } }; @@ -71,16 +88,30 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .asoc_plat_name = "sst-mfld-platform", }; +static struct snd_soc_acpi_mach byt_pov_p1006w = { + .id = "10EC5640", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .asoc_plat_name = "sst-mfld-platform", +}; + static struct snd_soc_acpi_mach *byt_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; dmi_check_system(byt_table); - if (byt_machine_id == BYT_THINKPAD_10) + switch (byt_machine_id) { + case BYT_THINKPAD_10: return &byt_thinkpad_10; - else + case BYT_POV_P1006W: + return &byt_pov_p1006w; + default: return mach; + } } struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[] = { From d306873589c5a4c13df7176cd73d66ebfa690064 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:20 +0100 Subject: [PATCH 092/461] ASoC: rt5651: Add ACPI ID 10EC5640 Some BYT platforms have a RT5651 codec while using an ACPI node with a HID of 10EC5640 to describe the coded. Add the 10EC5640 HID to the acpi_device_id list, so that the rt5651 will bind to the codec on these devices. Like the rt5645 and rt5670 drivers which also have the 10EC5640 ACPI HID in their acpi_device_id list for similar reasons, the rt5651 driver checks the codecs device-id register so that it will only bind if the codec actually is a rt5651 and it will ignore actual rt5640 codecs. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 3882e238ff99..9a007c162631 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2138,6 +2138,7 @@ MODULE_DEVICE_TABLE(of, rt5651_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { { "10EC5651", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); From c2ec9d957d2bf49d69afb1b872cb2363c6cb5862 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:21 +0100 Subject: [PATCH 093/461] ASoC: rt5651: Add support for jack detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Figuring out which GPIO to use is pretty much board specific so I've chosen to let the machine driver pass the gpio_desc as data argument to snd_soc_component_set_jack() rather then add support for getting the GPIO to the codec driver. This keeps the codec code nice and clean. Note that using an external GPIO for this conflicts with button-press support, so this commit disables button-press support when an external GPIO is used. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 54 +++++++++++++++++++++++++++------------ sound/soc/codecs/rt5651.h | 1 + 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 9a007c162631..75994297c896 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); int val; + if (rt5651->gpiod_hp_det) { + val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det); + dev_dbg(component->dev, "jack-detect gpio %d\n", val); + return val; + } + val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST); dev_dbg(component->dev, "irq status %#04x\n", val); @@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component) return SND_JACK_HEADPHONE; } +static bool rt5651_support_button_press(struct rt5651_priv *rt5651) +{ + /* Button press support only works with internal jack-detection */ + return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && + rt5651->gpiod_hp_det == NULL; +} + static void rt5651_jack_detect_work(struct work_struct *work) { struct rt5651_priv *rt5651 = @@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work) WARN_ON(rt5651->ovcd_irq_enabled); rt5651_enable_micbias1_for_ovcd(component); report = rt5651_detect_headset(component); - if (report == SND_JACK_HEADSET) { + dev_dbg(component->dev, "detect report %#02x\n", report); + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); + if (rt5651_support_button_press(rt5651)) { /* Enable ovcd IRQ for button press detect. */ rt5651_enable_micbias1_ovcd_irq(component); } else { /* No more need for overcurrent detect. */ rt5651_disable_micbias1_for_ovcd(component); } - dev_dbg(component->dev, "detect report %#02x\n", report); - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) { dev_dbg(component->dev, "OVCD IRQ\n"); @@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data) } static void rt5651_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *hp_jack) + struct snd_soc_jack *hp_jack, + struct gpio_desc *gpiod_hp_det) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); - - /* IRQ output on GPIO1 */ - snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, - RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + bool using_internal_jack_detect = true; /* Select jack detect source */ switch (rt5651->jd_src) { + case RT5651_JD_NULL: + rt5651->gpiod_hp_det = gpiod_hp_det; + if (!rt5651->gpiod_hp_det) + return; /* No jack detect */ + using_internal_jack_detect = false; + break; case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); @@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); break; - case RT5651_JD_NULL: - return; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); return; } - /* Enable jack detect power */ - snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, - RT5651_PWR_JD_M, RT5651_PWR_JD_M); + if (using_internal_jack_detect) { + /* IRQ output on GPIO1 */ + snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, + RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + + /* Enable jack detect power */ + snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, + RT5651_PWR_JD_M, RT5651_PWR_JD_M); + } /* Set OVCD threshold current and scale-factor */ snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4, @@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN); rt5651->hp_jack = hp_jack; - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_enable_micbias1_for_ovcd(component); rt5651_enable_micbias1_ovcd_irq(component); } @@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5651->irq); rt5651_cancel_work(rt5651); - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_disable_micbias1_ovcd_irq(component); rt5651_disable_micbias1_for_ovcd(component); snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0); @@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { if (jack) - rt5651_enable_jack_detect(component, jack); + rt5651_enable_jack_detect(component, jack, data); else rt5651_disable_jack_detect(component); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index ac6de6fb5414..41fcb8b5eb40 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2073,6 +2073,7 @@ struct rt5651_priv { struct regmap *regmap; /* Jack and button detect data */ struct snd_soc_jack *hp_jack; + struct gpio_desc *gpiod_hp_det; struct work_struct jack_detect_work; struct delayed_work bp_work; bool ovcd_irq_enabled; From aee48a9ffa5a128bf4e433c57c39e015ea5b0208 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:22 +0100 Subject: [PATCH 094/461] ASoC: Intel: bytcr_rt5651: Revert "Fix DMIC map headsetmic mapping" Commit 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map headsetmic mapping"), changed the headsetmic mapping from IN3P to IN2P, this was based on the observation that all bytcr_rt5651 devices I have access to (7 devices) where all using IN3P for the headsetmic. This was an attempt to unifify / simplify the mapping, but it was wrong. None of those devices was actually using a digital internal mic. Now I've access to a Point of View TAB-P1006W-232 (v1.0) tabler, which does use a DMIC and it does have its headsetmic connected to IN2P, showing that the original mapping was correct, so this commit reverts the change changing the mapping back to IN2P. Fixes: 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map ... mapping") Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e528995668b7..0ed844f2ad01 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -266,7 +266,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { {"DMIC L1", NULL, "Internal Mic"}, {"DMIC R1", NULL, "Internal Mic"}, - {"IN3P", NULL, "Headset Mic"}, + {"IN2P", NULL, "Headset Mic"}, }; static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { From 7eb187313eef4c8faa49f70c9c7d8918e1052207 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:23 +0100 Subject: [PATCH 095/461] ASoC: Intel: bytcr_rt5651: Add quirks module parameter Add quirks module parameter to allow manually specifying quirks from the kernel commandline (or modprobe.conf). Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 0ed844f2ad01..6d8ef9dd106e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -98,6 +98,10 @@ struct byt_rt5651_private { static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; +static unsigned int quirk_override; +module_param_named(quirk, quirk_override, uint, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + static void log_quirks(struct device *dev) { if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) @@ -973,6 +977,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); + if (quirk_override) { + dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)byt_rt5651_quirk, quirk_override); + byt_rt5651_quirk = quirk_override; + } + /* Must be called before register_card, also see declaration comment. */ ret_val = byt_rt5651_add_codec_device_props(codec_dev); if (ret_val) { From 90768eaf064041937ef4d6ca95c7e86774cd34a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:24 +0100 Subject: [PATCH 096/461] ASoC: Intel: bytcr_rt5651: Add support for jack-detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 43 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 6d8ef9dd106e..9a2ee9080897 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -91,6 +91,7 @@ enum { struct byt_rt5651_private { struct clk *mclk; struct gpio_desc *ext_amp_gpio; + struct gpio_desc *hp_detect; struct snd_soc_jack jack; }; @@ -499,6 +500,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; + int report; int ret; card->dapm.idle_bias_off = true; @@ -582,20 +584,27 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "unable to set MCLK rate\n"); } - if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { + report = 0; + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) + report = SND_JACK_HEADSET | SND_JACK_BTN_0; + else if (priv->hp_detect) + report = SND_JACK_HEADSET; + + if (report) { ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, bytcr_jack_pins, + report, &priv->jack, bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, - KEY_PLAYPAUSE); + if (report & SND_JACK_BTN_0) + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); - ret = snd_soc_component_set_jack(codec, &priv->jack, NULL); + ret = snd_soc_component_set_jack(codec, &priv->jack, + priv->hp_detect); if (ret) return ret; } @@ -767,7 +776,8 @@ static int byt_rt5651_resume(struct snd_soc_card *card) for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); - snd_soc_component_set_jack(component, &priv->jack, NULL); + snd_soc_component_set_jack(component, &priv->jack, + priv->hp_detect); break; } } @@ -1012,6 +1022,25 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) return ret_val; } } + priv->hp_detect = devm_fwnode_get_index_gpiod_from_child( + &pdev->dev, "hp-detect", 0, + codec_dev->fwnode, + GPIOD_IN, "hp-detect"); + if (IS_ERR(priv->hp_detect)) { + ret_val = PTR_ERR(priv->hp_detect); + switch (ret_val) { + case -ENOENT: + priv->hp_detect = NULL; + break; + default: + dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n", + ret_val); + /* fall through */ + case -EPROBE_DEFER: + put_device(codec_dev); + return ret_val; + } + } } put_device(codec_dev); From fee3e1cbd6cd74925286a571b567ec18728818a7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:25 +0100 Subject: [PATCH 097/461] ASoC: Intel: bytcr_rt5651: Add quirk for PoV TAB-P1006W-232 (v1.0) tablet Add a DMI quirk for the Point of View TAB-P1006W-232 (v1.0) tablet, this tablet is special in a number of ways: 1) It uses the 2nd GPIO resource in the ACPI tables for jack-detect rather then using the rt5651 codec's builtin jack-detect functionality 2) It uses the 3th GPIO resource in the ACPI tables to control the external amplifier rather then the usual first non GpioInt resource and the GPIO is active-low. 3) It is a BYTCR device, without a CHAN package and it uses SSP0-AIF1 rather then the default SSP0-AIF2. 4) Its internal mic is a digital mic (the first x86 rt5651 device that I'm aware of which does this), combined with having its headset-mic connected to IN2. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 9a2ee9080897..b618d984e2d5 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -95,6 +95,8 @@ struct byt_rt5651_private { struct snd_soc_jack jack; }; +static const struct acpi_gpio_mapping *byt_rt5651_gpios; + /* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */ static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; @@ -365,6 +367,22 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, bclk_ratio); } +static const struct acpi_gpio_params pov_p1006w_hp_detect = { 1, 0, false }; +static const struct acpi_gpio_params pov_p1006w_ext_amp_en = { 2, 0, true }; + +static const struct acpi_gpio_mapping byt_rt5651_pov_p1006w_gpios[] = { + { "hp-detect-gpios", &pov_p1006w_hp_detect, 1, }, + { "ext-amp-enable-gpios", &pov_p1006w_ext_amp_en, 1, }, + { }, +}; + +static int byt_rt5651_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5651_quirk = (unsigned long)id->driver_data; + byt_rt5651_gpios = byt_rt5651_pov_p1006w_gpios; + return 1; +} + static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) { byt_rt5651_quirk = (unsigned long)id->driver_data; @@ -440,6 +458,23 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { .driver_data = (void *)(BYT_RT5651_MCLK_EN | BYT_RT5651_IN1_MAP), }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_rt5651_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + .driver_data = (void *)(BYT_RT5651_DMIC_MAP | + BYT_RT5651_OVCD_TH_2000UA | + BYT_RT5651_OVCD_SF_0P75 | + BYT_RT5651_DMIC_EN | + BYT_RT5651_MCLK_EN | + BYT_RT5651_SSP0_AIF1), + }, { /* VIOS LTH17 */ .callback = byt_rt5651_quirk_cb, @@ -848,7 +883,7 @@ static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) return 0; } -static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) +static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) { struct byt_rt5651_acpi_resource_data data = { 0, -1 }; LIST_HEAD(resources); @@ -866,10 +901,10 @@ static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) switch (data.gpio_int_idx) { case 0: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second); + byt_rt5651_gpios = byt_rt5651_amp_en_second; break; case 1: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first); + byt_rt5651_gpios = byt_rt5651_amp_en_first; break; default: dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", @@ -1001,8 +1036,11 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* Cherry Trail devices use an external amplifier enable gpio */ - if (x86_match_cpu(cherrytrail_cpu_ids)) { - snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev); + if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) + snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + + if (byt_rt5651_gpios) { + devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child( &pdev->dev, "ext-amp-enable", 0, codec_dev->fwnode, From 7b57085a33ce55e28616f04fd9877ba2ca7e79de Mon Sep 17 00:00:00 2001 From: "Agrawal, Akshu" Date: Tue, 8 Jan 2019 10:24:40 +0000 Subject: [PATCH 098/461] ASoC: ADAU7002: Add optional delay before start of capture On capture through some of dmic we observe a glitch at the start of record. This is because we start capturing even before dmic is ready to send out data. The optional delay will be applied after enabling the mic. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/codecs/adau7002.c | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index fdff86878287..a8deb37fc78a 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -15,12 +16,55 @@ #include +struct adau7002_priv { + int wakeup_delay; +}; + +static int adau7002_aif_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct adau7002_priv *adau7002 = + snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (adau7002->wakeup_delay) + msleep(adau7002->wakeup_delay); + break; + } + + return 0; +} + +static int adau7002_component_probe(struct snd_soc_component *component) +{ + struct adau7002_priv *adau7002; + + adau7002 = devm_kzalloc(component->dev, sizeof(*adau7002), + GFP_KERNEL); + if (!adau7002) + return -ENOMEM; + + device_property_read_u32(component->dev, "wakeup-delay-ms", + &adau7002->wakeup_delay); + + snd_soc_component_set_drvdata(component, adau7002); + + return 0; +} + static const struct snd_soc_dapm_widget adau7002_widgets[] = { + SND_SOC_DAPM_AIF_OUT_E("ADAU AIF", "Capture", 0, + SND_SOC_NOPM, 0, 0, adau7002_aif_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_INPUT("PDM_DAT"), SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0), }; static const struct snd_soc_dapm_route adau7002_routes[] = { + { "ADAU AIF", NULL, "PDM_DAT"}, { "Capture", NULL, "PDM_DAT" }, { "Capture", NULL, "IOVDD" }, }; @@ -40,6 +84,7 @@ static struct snd_soc_dai_driver adau7002_dai = { }; static const struct snd_soc_component_driver adau7002_component_driver = { + .probe = adau7002_component_probe, .dapm_widgets = adau7002_widgets, .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), .dapm_routes = adau7002_routes, From 4a8191aa9e057ea38279ef9e809265ba3966be40 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Mon, 7 Jan 2019 12:12:32 -0800 Subject: [PATCH 099/461] ASoC: rt274: Variable "buf" in function rt274_jack_detect() could be uninitialized In function rt274_jack_detect(), local variable "buf" could be uninitialized if function regmap_read() returns -EINVAL. However, it will be used to calculate "hp" and "mic" and make their value unpredictable while those value are used in the caller. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 9e88f7b25d38..adf59039a3b6 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -353,6 +353,7 @@ static void rt274_index_sync(struct snd_soc_component *component) static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) { unsigned int buf; + int ret; *hp = false; *mic = false; @@ -360,9 +361,15 @@ static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) if (!rt274->component) return -EINVAL; - regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + if (ret) + return ret; + *hp = buf & 0x80000000; - regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + if (ret) + return ret; + *mic = buf & 0x80000000; pr_debug("*hp = %d *mic = %d\n", *hp, *mic); From 081e01f059ba03b25499cb4616ec58db0979406d Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Jan 2019 16:20:50 +0800 Subject: [PATCH 100/461] ALSA: hda: Fix mismatches for register mask and value in hdac controller E.g. for azx_int_enable(), we should set both mask and value to be "AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN"(the mask was 0) to enable controller CIE and GIE. We have similar issues on setting AZX_GCTL_RESET and AZX_GCTL_UNSOL, here try to correct all of them. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai --- sound/hda/hdac_controller.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 74244d8e2909..b2e9454f5816 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -376,7 +376,7 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus) { unsigned long timeout; - snd_hdac_chip_updateb(bus, GCTL, 0, AZX_GCTL_RESET); + snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout)) @@ -415,7 +415,7 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset) } /* Accept unsolicited responses */ - snd_hdac_chip_updatel(bus, GCTL, 0, AZX_GCTL_UNSOL); + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); /* detect codecs */ if (!bus->codec_mask) { @@ -431,7 +431,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_reset_link); static void azx_int_enable(struct hdac_bus *bus) { /* enable controller CIE and GIE */ - snd_hdac_chip_updatel(bus, INTCTL, 0, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); + snd_hdac_chip_updatel(bus, INTCTL, + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); } /* disable interrupts */ From fc2a6cf060d0c6feeb3719bf40088e48c5926e40 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Jan 2019 16:20:51 +0800 Subject: [PATCH 101/461] ALSA: hda: Fix a mask wrong issue in snd_hdac_stream_start() To enable SIE(Stream Interrupt Enable) in snd_hdac_stream_start(), we should set both mask and value to be "1 << azx_dev->index" for register update, the mask was 0, here fix it. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index eee422390d8e..ba73a33480b6 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -56,7 +56,9 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) azx_dev->start_wallclk -= azx_dev->period_wallclk; /* enable SIE */ - snd_hdac_chip_updatel(bus, INTCTL, 0, 1 << azx_dev->index); + snd_hdac_chip_updatel(bus, INTCTL, + 1 << azx_dev->index, + 1 << azx_dev->index); /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); From 36c346e1c5819115d3ffe6b81d853a061530fe4b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Jan 2019 02:20:16 +0000 Subject: [PATCH 102/461] ALSA: usb-audio: Remove set but not used variable 'first_ch_bits' Fixes gcc '-Wunused-but-set-variable' warning: sound/usb/mixer.c: In function 'parse_audio_feature_unit': sound/usb/mixer.c:1838:28: warning: variable 'first_ch_bits' set but not used [-Wunused-but-set-variable] It never used since 2.6 Signed-off-by: YueHaibing Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index e7d441d0e839..8ad1a24c8f28 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1835,7 +1835,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, { int channels, i, j; struct usb_audio_term iterm; - unsigned int master_bits, first_ch_bits; + unsigned int master_bits; int err, csize; struct uac_feature_unit_descriptor *hdr = _ftr; __u8 *bmaControls; @@ -1926,10 +1926,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, break; } - if (channels > 0) - first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); - else - first_ch_bits = 0; if (state->mixer->protocol == UAC_VERSION_1) { /* check all control types */ From a6028cc60aad18d5d7c25d99b5cb8c24399387c3 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 7 Jan 2019 16:11:46 +0000 Subject: [PATCH 103/461] ASoC: da7219: MCLK should be enabled before DAI clocks For platforms using the Common Clock Framework to control the codec's DAI clocks, MCLK should be enabled prior to DAI clocks being turned on. For some platforms the codec is already provided with an MCLK reference and can therefore control MCLK itself as it needs to. To improve functionality MCLK is now added as a parent to the DAI clocks, if MCLK was provided, so that if they are enabled MCLK will automatically be enabled as a prerequisite by the CCF. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 513ec0368653..a20a610c7ee5 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1804,7 +1804,7 @@ static const struct clk_ops da7219_dai_clks_ops = { .is_prepared = da7219_dai_clks_is_prepared, }; -static void da7219_register_dai_clks(struct snd_soc_component *component) +static int da7219_register_dai_clks(struct snd_soc_component *component) { struct device *dev = component->dev; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); @@ -1812,9 +1812,17 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) struct clk_init_data init = {}; struct clk *dai_clks; struct clk_lookup *dai_clks_lookup; + const char *parent_name; + + if (da7219->mclk) { + parent_name = __clk_get_name(da7219->mclk); + init.parent_names = &parent_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } - init.parent_names = NULL; - init.num_parents = 0; init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; da7219->dai_clks_hw.init = &init; @@ -1823,7 +1831,7 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) if (IS_ERR(dai_clks)) { dev_warn(dev, "Failed to register DAI clocks: %ld\n", PTR_ERR(dai_clks)); - return; + return PTR_ERR(dai_clks); } da7219->dai_clks = dai_clks; @@ -1835,13 +1843,18 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, "%s", dev_name(dev)); if (!dai_clks_lookup) - dev_warn(dev, "Failed to create DAI clkdev"); + return -ENOMEM; else da7219->dai_clks_lookup = dai_clks_lookup; } + + return 0; } #else -static inline void da7219_register_dai_clks(struct snd_soc_component *component) {} +static inline int da7219_register_dai_clks(struct snd_soc_component *component) +{ + return 0; +} #endif /* CONFIG_COMMON_CLK */ static void da7219_handle_pdata(struct snd_soc_component *component) @@ -1854,8 +1867,6 @@ static void da7219_handle_pdata(struct snd_soc_component *component) da7219->wakeup_source = pdata->wakeup_source; - da7219_register_dai_clks(component); - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1947,6 +1958,11 @@ static int da7219_probe(struct snd_soc_component *component) } } + /* Register CCF DAI clock control */ + ret = da7219_register_dai_clks(component); + if (ret) + return ret; + /* Default PC counter to free-running */ snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, DA7219_PC_FREERUN_MASK); From a58943abcb08cfbe6c36648602d796c5834ee8a9 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 8 Jan 2019 09:13:28 +0000 Subject: [PATCH 104/461] ASoC: da7219: Add recalc_rate function to return DAI clock rate By making MCLK parent of DAI clocks, when querying the rate of the clock the rate returned is now given from the parent clock so gives the MCLK rate rather than 0 as previously returned. This is a bit misleading, and actually there's no major reason why we can't at least return the DAI WCLK rate, as set in HW, so that's what we now do. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 45 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7219.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index a20a610c7ee5..b1df4bb36105 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1767,7 +1767,7 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, @@ -1780,7 +1780,7 @@ static void da7219_dai_clks_unprepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, 0); @@ -1790,7 +1790,7 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; u8 clk_reg; clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); @@ -1798,10 +1798,47 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); } +static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, dai_clks_hw); + struct snd_soc_component *component = da7219->component; + u8 fs = snd_soc_component_read32(component, DA7219_SR); + + switch (fs & DA7219_SR_MASK) { + case DA7219_SR_8000: + return 8000; + case DA7219_SR_11025: + return 11025; + case DA7219_SR_12000: + return 12000; + case DA7219_SR_16000: + return 16000; + case DA7219_SR_22050: + return 22050; + case DA7219_SR_24000: + return 24000; + case DA7219_SR_32000: + return 32000; + case DA7219_SR_44100: + return 44100; + case DA7219_SR_48000: + return 48000; + case DA7219_SR_88200: + return 88200; + case DA7219_SR_96000: + return 96000; + default: + return 0; + } +} + static const struct clk_ops da7219_dai_clks_ops = { .prepare = da7219_dai_clks_prepare, .unprepare = da7219_dai_clks_unprepare, .is_prepared = da7219_dai_clks_is_prepared, + .recalc_rate = da7219_dai_clks_recalc_rate, }; static int da7219_register_dai_clks(struct snd_soc_component *component) @@ -1825,6 +1862,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; + init.flags = CLK_GET_RATE_NOCACHE; da7219->dai_clks_hw.init = &init; dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); @@ -1912,6 +1950,7 @@ static int da7219_probe(struct snd_soc_component *component) unsigned int rev; int ret; + da7219->component = component; mutex_init(&da7219->ctrl_lock); mutex_init(&da7219->pll_lock); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 3a006862f0e7..366cf46118a0 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -809,6 +809,7 @@ struct da7219_aad_priv; /* Private data */ struct da7219_priv { + struct snd_soc_component *component; struct da7219_aad_priv *aad; struct da7219_pdata *pdata; From 04d979d7a7bac2f645cd827ea37e5ffa5b4e1f97 Mon Sep 17 00:00:00 2001 From: b-ak Date: Wed, 9 Jan 2019 22:41:21 +0530 Subject: [PATCH 105/461] ASoC: tlv320aic32x4: SND_SOC_DAPM_MICBIAS is deprecated SND_SOC_DAPM_MICBIAS is deprecated, replace it with SND_SOC_DAPM_SUPPLY. MICBIAS voltage wasn't supplied to the microphone with the older SND_SOC_DAPM_MICBIAS widget, hence the microphone wouldn't work. This patch fixes the problem. Signed-off-by: b-ak Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 30 +++++++++++++++++++++++++++++- sound/soc/codecs/tlv320aic32x4.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e2b5a11b16d1..521663d8b585 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -79,6 +79,32 @@ struct aic32x4_priv { struct device *dev; }; +static int mic_bias_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Change Mic Bias Registor */ + snd_soc_component_update_bits(component, AIC32X4_MICBIAS, + AIC32x4_MICBIAS_MASK, + AIC32X4_MICBIAS_LDOIN | + AIC32X4_MICBIAS_2075V); + printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, AIC32X4_MICBIAS, + AIC32x4_MICBIAS_MASK, 0); + printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n", + __func__); + break; + } + + return 0; +} + + static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -450,7 +476,9 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, in3r_to_lmixer_controls), - SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index e9df49edbf19..c2d74025bf4b 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -195,6 +195,7 @@ int aic32x4_remove(struct device *dev); /* AIC32X4_MICBIAS */ #define AIC32X4_MICBIAS_LDOIN BIT(3) #define AIC32X4_MICBIAS_2075V 0x60 +#define AIC32x4_MICBIAS_MASK GENMASK(6, 3) /* AIC32X4_LMICPGANIN */ #define AIC32X4_LMICPGANIN_IN2R_10K 0x10 From f833fe2056b3a6d69598ef029cede6e77dcc1b14 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 10 Jan 2019 01:43:09 +0000 Subject: [PATCH 106/461] ASoC: Intel: bytcht_es8316: use correct drvdata in snd_byt_cht_es8316_mc_remove() The snd_byt_cht_es8316_mc_remove() use the platform drvdata as a type of 'struct byt_cht_es8316_private', but snd_byt_cht_es8316_mc_probe() set it to 'struct snd_soc_card', as suggested by Dan Carpenter, fix the usage in snd_byt_cht_es8316_mc_remove(). Fixes: 0d3e91da0750 ("ASoC: Intel: bytcht_es8316: Add external speaker mux support") Signed-off-by: Wei Yongjun Acked-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index cdf2061e7613..fa9c4cf97686 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -544,7 +544,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) { - struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); gpiod_put(priv->speaker_en_gpio); return 0; From e6ce7943231fcba95a3c8842ab65f257cb5ab124 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:08 +0530 Subject: [PATCH 107/461] ALSA: hda: add verbs for stripe control Controllers can support multiple Serial Data Out(SDO) lines, for extended outbound bandwidth, to pump data to all codecs on the link. Codecs can sample data present on SDO. Add verbs AC_VERB_GET_STRIPE_CONTROL and AC_VERB_SET_STRIPE_CONTROL These can be used to program usage of SDO lines for codec. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/hda_verbs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h index 2a8573a00ea6..e36b77531c5c 100644 --- a/include/sound/hda_verbs.h +++ b/include/sound/hda_verbs.h @@ -66,6 +66,7 @@ enum { #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c /* f20: AFG/MFG */ #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 +#define AC_VERB_GET_STRIPE_CONTROL 0x0f24 #define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d #define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e #define AC_VERB_GET_HDMI_ELDD 0x0f2f @@ -110,6 +111,7 @@ enum { #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f #define AC_VERB_SET_EAPD 0x788 #define AC_VERB_SET_CODEC_RESET 0x7ff +#define AC_VERB_SET_STRIPE_CONTROL 0x724 #define AC_VERB_SET_CVT_CHAN_COUNT 0x72d #define AC_VERB_SET_HDMI_DIP_INDEX 0x730 #define AC_VERB_SET_HDMI_DIP_DATA 0x731 From 5dd3d271320d888bb708ca6252b8a9e416a7fe64 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:09 +0530 Subject: [PATCH 108/461] ALSA: hda: Add api to program stripe control bits Controllers and codecs can support striping of audio out across multiple SDO lines. The number of supported SDO lines can be specific to chip. GCAP register can be read to know the maximum supported SDO lines. snd_hdac_get_stream_stripe_ctl() is exposed to program stripe bits on controller and codec side. stripe value: 0 for 1SDO, 1 for 2SDO, 2 for 4SDO lines, etc., Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 3 +++ sound/hda/hdac_stream.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index b4fa1c775251..45f944d57982 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -539,6 +539,9 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, unsigned int streams); void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, unsigned int streams); +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, + struct snd_pcm_substream *substream); + /* * macros for easy use */ diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index ba73a33480b6..820694a2061e 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -12,6 +12,40 @@ #include #include "trace.h" +/** + * snd_hdac_get_stream_stripe_ctl - get stripe control value + * @bus: HD-audio core bus + * @substream: PCM substream + */ +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int channels = runtime->channels, + rate = runtime->rate, + bits_per_sample = runtime->sample_bits, + max_sdo_lines, value, sdo_line; + + /* T_AZA_GCAP_NSDO is 1:2 bitfields in GCAP */ + max_sdo_lines = snd_hdac_chip_readl(bus, GCAP) & AZX_GCAP_NSDO; + + /* following is from HD audio spec */ + for (sdo_line = max_sdo_lines; sdo_line > 0; sdo_line >>= 1) { + if (rate > 48000) + value = (channels * bits_per_sample * + (rate / 48000)) / sdo_line; + else + value = (channels * bits_per_sample) / sdo_line; + + if (value >= 8) + break; + } + + /* stripe value: 0 for 1SDO, 1 for 2SDO, 2 for 4SDO lines */ + return sdo_line >> 1; +} +EXPORT_SYMBOL_GPL(snd_hdac_get_stream_stripe_ctl); + /** * snd_hdac_stream_init - initialize each stream (aka device) * @bus: HD-audio core bus From b59c8e7a73160b11f99b9008a5f215dd54b9d581 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:10 +0530 Subject: [PATCH 109/461] ALSA: hda: add register offset for stripe control bits 16:17 in SD_CTL register refer to stripe control. Added an offset register(AZX_REG_SD_CTL_3B) to have exclusive read/write of corresponding register byte. This helps to avoid unnecessary 32-bit read/write of SD_CTL whenever only stripe or other bits of corresponding byte need to be updated. Also HD audio spec defines SD_CTL as 3 byte register. SD_CTL_STRIPE_MASK(0x3) can be used for stripe control programming and when updating AZX_REG_SD_CTL_3B. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- include/sound/hda_register.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 2ab39fb52d7a..0fd39295b426 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -79,6 +79,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* stream register offsets from stream base */ #define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_CTL_3B 0x02 /* 3rd byte of SD_CTL register */ #define AZX_REG_SD_STS 0x03 #define AZX_REG_SD_LPIB 0x04 #define AZX_REG_SD_CBL 0x08 @@ -165,6 +166,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_INT_COMPLETE 0x04 /* completion interrupt */ #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ SD_INT_COMPLETE) +#define SD_CTL_STRIPE_MASK 0x3 /* stripe control mask */ /* SD_STS */ #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ From 9b6f7e7a296e17990aae298c809b001e99ddd151 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:11 +0530 Subject: [PATCH 110/461] ALSA: hda: program stripe bits for controller Platforms having multiple SORs and hdmi/dp sinks require higher bandwidth to support simultaneous playbacks of higher resolution. If hda controller supports multiple SDO lines, STRIPE can be used to indicate how many of the SDO lines the stream should be striped across. During stream start stripe control bits are programmed to use given number of sdo lines and the same is cleared during stream stop. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 820694a2061e..f5dd288d1a7a 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -82,6 +82,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_init); void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) { struct hdac_bus *bus = azx_dev->bus; + int stripe_ctl; trace_snd_hdac_stream_start(bus, azx_dev); @@ -93,6 +94,10 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) snd_hdac_chip_updatel(bus, INTCTL, 1 << azx_dev->index, 1 << azx_dev->index); + /* set stripe control */ + stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, + stripe_ctl); /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); @@ -109,6 +114,7 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev) snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_DMA_START | SD_INT_MASK, 0); snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); azx_dev->running = false; } EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); From 053b055948e97268771de11f2ab9b2aa1640b68d Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:12 +0530 Subject: [PATCH 111/461] ALSA: hda: program stripe control for codec Program codec stripe through AC_VERB_SET_STRIPE_CONTROL to use multiple sdo lines if supported. Audio needs to be striped across number of sdo lines for simultaneous playbacks of higher resolutions to work. This needs to be implemented only for an Audio Output Converter and only if the stripe bit(AC_WCAP_STRIPE) of Audio Widget Capabilities parameter is 1. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 46f88dc7b7e8..73d7042ff884 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1865,7 +1865,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hda_nid_t pin_nid; struct snd_pcm_runtime *runtime = substream->runtime; bool non_pcm; - int pinctl; + int pinctl, stripe; int err = 0; mutex_lock(&spec->pcm_lock); @@ -1909,6 +1909,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, per_pin->channels = substream->runtime->channels; per_pin->setup = true; + if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) { + stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core, + substream); + snd_hda_codec_write(codec, cvt_nid, 0, + AC_VERB_SET_STRIPE_CONTROL, + stripe); + } + hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); mutex_unlock(&per_pin->lock); if (spec->dyn_pin_out) { From 3e8c45f57a90585cfc0b07ae81de8960a8366c1c Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 14 Jan 2019 10:55:40 +0100 Subject: [PATCH 112/461] ASoC: cs4341: fix waring unused-function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver cs4341 can be built with SPI and/or I2C, but it has to be one of them at least. When I2C is set as a module we see the warning below: sound/soc/codecs/cs4341.c:213:12: warning: ‘cs4341_probe’ defined but not used [-Wunused-function] static int cs4341_probe(struct device *dev) ^~~~~~~~~~~~ Rework so that we use IS_ENABLED instead of defined. Also change so SND_SOC_CS4341 depends on SND_SOC_I2C_AND_SPI to we dont' get a link error when SND_SOC_CS4341=y, I2C=m and REGMAP_I2C=m is set. Suggested-by: Arnd Bergmann Signed-off-by: Anders Roxell Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/cs4341.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 87cb9c51e6f5..87ecb38e57f4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -546,7 +546,7 @@ config SND_SOC_CS43130 config SND_SOC_CS4341 tristate "Cirrus Logic CS4341 CODEC" - depends on I2C || SPI_MASTER + depends on SND_SOC_I2C_AND_SPI select REGMAP_I2C if I2C select REGMAP_SPI if SPI_MASTER diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index d2e616a89fd4..ade7477d04f1 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -223,7 +223,7 @@ static int cs4341_probe(struct device *dev) &cs4341_dai, 1); } -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) static int cs4341_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -317,7 +317,7 @@ static int __init cs4341_init(void) { int ret = 0; -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&cs4341_i2c_driver); if (ret) return ret; @@ -332,7 +332,7 @@ module_init(cs4341_init); static void __exit cs4341_exit(void) { -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) i2c_del_driver(&cs4341_i2c_driver); #endif #if defined(CONFIG_SPI_MASTER) From fecd5c09ddf8711c0b17087cc7a40ac57680f8ed Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Jan 2019 14:36:40 +0000 Subject: [PATCH 113/461] ASoC: msm8916-wcd-digital: remove few unused variables This patch removes unused variables which also fixes below warnings: msm8916-wcd-digital.c:245:30: warning: 'rx2_mix2_inp1_chain_enum' defined but not used [-Wunused-const-variable=] static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( ^~~~~~~~~~~~~~~~~~~~~~~~ msm8916-wcd-digital.c:234:30: warning: 'rx_mix2_inp1_chain_enum' defined but not used [-Wunused-const-variable=] static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( ^~~~~~~~~~~~~~~~~~~~~~~ msm8916-wcd-digital.c:224:26: warning: 'adc2_mux_text' defined but not used [-Wunused-const-variable=] static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; ^~~~~~~~~~~~~ msm8916-wcd-digital.c:223:26: warning: 'rx_mix2_text' defined but not used [-Wunused-const-variable=] Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 3063dedd21cf..423bfebabed4 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -220,8 +220,6 @@ static const char *const dec_mux_text[] = { }; static const char *const cic_mux_text[] = { "AMIC", "DMIC" }; -static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; -static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; /* RX1 MIX1 */ static const struct soc_enum rx_mix1_inp_enum[] = { @@ -230,10 +228,6 @@ static const struct soc_enum rx_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), }; -/* RX1 MIX2 */ -static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( - LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); - /* RX2 MIX1 */ static const struct soc_enum rx2_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), @@ -241,10 +235,6 @@ static const struct soc_enum rx2_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text), }; -/* RX2 MIX2 */ -static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( - LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); - /* RX3 MIX1 */ static const struct soc_enum rx3_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), From 5b86fa6d2903c41c3c3dbff4def76a5b8bbe0660 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 11 Jan 2019 18:20:40 +0800 Subject: [PATCH 114/461] ASoC: msm8916-wcd-digital: Select REGMAP_MMIO to fix build error Fix below build error: ERROR: "__devm_regmap_init_mmio_clk" [sound/soc/codecs/snd-soc-msm8916-digital.ko] undefined! Signed-off-by: Axel Lin Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 87ecb38e57f4..71e6e123a115 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -706,6 +706,7 @@ config SND_SOC_MSM8916_WCD_ANALOG config SND_SOC_MSM8916_WCD_DIGITAL tristate "Qualcomm MSM8916 WCD DIGITAL Codec" + select REGMAP_MMIO config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" From c284d4e31a0b66e6fe3734b36080afd237ff9fb0 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 10 Jan 2019 18:44:43 +0530 Subject: [PATCH 115/461] ASoC: xlnx: parse AES audio parameters AES channel status carries various audio parameters. If channel status is detected, current patch extracts sample rate and bit depth parameters of the incoming stream during capture. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 143 ++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index d2194da928e7..97177d35652e 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -63,6 +64,7 @@ #define PERIODS_MAX 6 #define PERIOD_BYTES_MIN 192 #define PERIOD_BYTES_MAX (50 * 1024) +#define XLNX_PARAM_UNKNOWN 0 enum bit_depth { BIT_DEPTH_8, @@ -117,6 +119,129 @@ static const struct snd_pcm_hardware xlnx_pcm_hardware = { .periods_max = PERIODS_MAX, }; +enum { + AES_TO_AES, + AES_TO_PCM, + PCM_TO_PCM, + PCM_TO_AES +}; + +static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val, + struct device *dev) +{ + u32 padded, srate, bit_depth, status[2]; + + if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) { + status[0] = chsts_reg1_val & 0xff; + status[1] = (chsts_reg1_val >> 16) & 0xff; + + switch (status[0] & IEC958_AES0_PRO_FS) { + case IEC958_AES0_PRO_FS_44100: + srate = 44100; + break; + case IEC958_AES0_PRO_FS_48000: + srate = 48000; + break; + case IEC958_AES0_PRO_FS_32000: + srate = 32000; + break; + case IEC958_AES0_PRO_FS_NOTID: + default: + srate = XLNX_PARAM_UNKNOWN; + break; + } + + switch (status[1] & IEC958_AES2_PRO_SBITS) { + case IEC958_AES2_PRO_WORDLEN_NOTID: + case IEC958_AES2_PRO_SBITS_20: + padded = 0; + break; + case IEC958_AES2_PRO_SBITS_24: + padded = 4; + break; + default: + bit_depth = XLNX_PARAM_UNKNOWN; + goto log_params; + } + + switch (status[1] & IEC958_AES2_PRO_WORDLEN) { + case IEC958_AES2_PRO_WORDLEN_20_16: + bit_depth = 16 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_22_18: + bit_depth = 18 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_23_19: + bit_depth = 19 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_24_20: + bit_depth = 20 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_NOTID: + default: + bit_depth = XLNX_PARAM_UNKNOWN; + break; + } + + } else { + status[0] = (chsts_reg1_val >> 24) & 0xff; + status[1] = chsts_reg2_val & 0xff; + + switch (status[0] & IEC958_AES3_CON_FS) { + case IEC958_AES3_CON_FS_44100: + srate = 44100; + break; + case IEC958_AES3_CON_FS_48000: + srate = 48000; + break; + case IEC958_AES3_CON_FS_32000: + srate = 32000; + break; + default: + srate = XLNX_PARAM_UNKNOWN; + break; + } + + if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24) + padded = 4; + else + padded = 0; + + switch (status[1] & IEC958_AES4_CON_WORDLEN) { + case IEC958_AES4_CON_WORDLEN_20_16: + bit_depth = 16 + padded; + break; + case IEC958_AES4_CON_WORDLEN_22_18: + bit_depth = 18 + padded; + break; + case IEC958_AES4_CON_WORDLEN_23_19: + bit_depth = 19 + padded; + break; + case IEC958_AES4_CON_WORDLEN_24_20: + bit_depth = 20 + padded; + break; + case IEC958_AES4_CON_WORDLEN_21_17: + bit_depth = 17 + padded; + break; + case IEC958_AES4_CON_WORDLEN_NOTID: + default: + bit_depth = XLNX_PARAM_UNKNOWN; + break; + } + } + +log_params: + if (srate != XLNX_PARAM_UNKNOWN) + dev_info(dev, "sample rate = %d\n", srate); + else + dev_info(dev, "sample rate = unknown\n"); + + if (bit_depth != XLNX_PARAM_UNKNOWN) + dev_info(dev, "bit_depth = %d\n", bit_depth); + else + dev_info(dev, "bit_depth = unknown\n"); +} + static int xlnx_formatter_pcm_reset(void __iomem *mmio_base) { u32 val, retries = 0; @@ -302,8 +427,12 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; + u32 aes_reg1_val, aes_reg2_val; int status; u64 size; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct xlnx_pcm_stream_param *stream_data = runtime->private_data; @@ -311,6 +440,20 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, if (active_ch > stream_data->ch_limit) return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + stream_data->xfer_mode == AES_TO_PCM) { + val = readl(stream_data->mmio + XLNX_AUD_STS); + if (val & AUD_STS_CH_STS_MASK) { + aes_reg1_val = readl(stream_data->mmio + + XLNX_AUD_CH_STS_START); + aes_reg2_val = readl(stream_data->mmio + + XLNX_AUD_CH_STS_START + 0x4); + + xlnx_parse_aes_params(aes_reg1_val, aes_reg2_val, + component->dev); + } + } + size = params_buffer_bytes(params); status = snd_pcm_lib_malloc_pages(substream, size); if (status < 0) From 3d21ef0b49f84d3341984caafc5c658739674927 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 15:58:39 +0100 Subject: [PATCH 116/461] ALSA: pcm: Suspend streams globally via device type PM ops Until now we rely on each driver calling snd_pcm_suspend*() explicitly at its own PM handling. However, this can be done far more easily by setting the PM ops to each actual snd_pcm device object. This patch adds the device_type object for PCM stream and assigns to each PCM stream object. The type contains only the PM ops for system suspend; we don't need to deal with the resume in general. The suspend hook simply calls snd_pcm_suspend_all() for the given PCM streams. This implies that the PM order is correctly put, i.e. PCM is suspended before the main (or codec) driver, which should be true in general. If a special ordering is needed, you'd need to adjust the device PM order manually later. This patch introduces a new flag, snd_pcm.no_device_suspend, too. With this flag set, the PCM device object won't invoke snd_pcm_suspend_all() by itself. This is needed for ASoC who wants to manage the PM call orders in its serialized way, and the flag is set in soc_new_pcm() as default. For the non-ASoC world, we can get rid of the manual snd_pcm_suspend calls. This will be done in the later patches. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + sound/core/pcm.c | 26 ++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 1 + 3 files changed, 28 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d6bd3caf6878..04e97564949c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -538,6 +538,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); bool internal; /* pcm is for internal use only */ bool nonatomic; /* whole PCM operations are in non-atomic context */ + bool no_device_suspend; /* don't invoke device PM suspend */ #if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss oss; #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 01b9d62eef14..ca1ea3cf9350 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -683,6 +683,31 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea static const struct attribute_group *pcm_dev_attr_groups[]; +/* + * PM callbacks: we need to deal only with suspend here, as the resume is + * triggered either from user-space or the driver's resume callback + */ +#ifdef CONFIG_PM_SLEEP +static int do_pcm_suspend(struct device *dev) +{ + struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); + + if (!pstr->pcm->no_device_suspend) + snd_pcm_suspend_all(pstr->pcm); + return 0; +} +#endif + +static const struct dev_pm_ops pcm_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) +}; + +/* device type for PCM -- basically only for passing PM callbacks */ +static const struct device_type pcm_dev_type = { + .name = "pcm", + .pm = &pcm_dev_pm_ops, +}; + /** * snd_pcm_new_stream - create a new PCM stream * @pcm: the pcm instance @@ -713,6 +738,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) snd_device_initialize(&pstr->dev, pcm->card); pstr->dev.groups = pcm_dev_attr_groups; + pstr->dev.type = &pcm_dev_type; dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050..485eec5be608 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3155,6 +3155,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } pcm->private_free = soc_pcm_private_free; + pcm->no_device_suspend = true; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, From 435e25c67de7e0a21fbb32239bded0cefc488e20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 17:57:29 +0100 Subject: [PATCH 117/461] ALSA: atiixp: Move PCM suspend/resume code into trigger callback ATIIXP driver supports the full PCM resume and saves/restores the running PCM pointer. This used to be done in the suspend and resume callbacks together with snd_pcm_suspend() call. But since we moved the snd_pcm_supsend*() call in PCM device PM ops, this should be moved to a more appropriate place, i.e. the trigger callback. Along with the movement of the PCM suspend/resume code, remove the superfluous snd_pcm_suspend_all() call, too. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/atiixp.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 1a41f8c80243..7715d26916ac 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -733,6 +733,10 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + if (dma->running && dma->suspended && + cmd == SNDRV_PCM_TRIGGER_RESUME) + writel(dma->saved_curptr, chip->remap_addr + + dma->ops->dt_cur); dma->ops->enable_transfer(chip, 1); dma->running = 1; dma->suspended = 0; @@ -740,9 +744,12 @@ static int snd_atiixp_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: + dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND; + if (dma->running && dma->suspended) + dma->saved_curptr = readl(chip->remap_addr + + dma->ops->dt_cur); dma->ops->enable_transfer(chip, 0); dma->running = 0; - dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND; break; default: err = -EINVAL; @@ -1479,14 +1486,6 @@ static int snd_atiixp_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < NUM_ATI_PCMDEVS; i++) - if (chip->pcmdevs[i]) { - struct atiixp_dma *dma = &chip->dmas[i]; - if (dma->substream && dma->running) - dma->saved_curptr = readl(chip->remap_addr + - dma->ops->dt_cur); - snd_pcm_suspend_all(chip->pcmdevs[i]); - } for (i = 0; i < NUM_ATI_CODECS; i++) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); @@ -1514,8 +1513,6 @@ static int snd_atiixp_resume(struct device *dev) dma->substream->ops->prepare(dma->substream); writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN, chip->remap_addr + dma->ops->llp_offset); - writel(dma->saved_curptr, chip->remap_addr + - dma->ops->dt_cur); } } From 28394f0e8735a40ec4b68fac8f484cdc9a4a0569 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:01:18 +0100 Subject: [PATCH 118/461] ALSA: isa: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/isa/ad1816a/ad1816a_lib.c | 1 - sound/isa/als100.c | 1 - sound/isa/cmi8328.c | 1 - sound/isa/cmi8330.c | 1 - sound/isa/es1688/es1688.c | 2 -- sound/isa/es18xx.c | 2 -- sound/isa/sb/jazz16.c | 1 - sound/isa/sb/sb16.c | 1 - sound/isa/sb/sb8.c | 1 - sound/isa/wss/wss_lib.c | 1 - 10 files changed, 12 deletions(-) diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index fba6d22f7f4b..61e8c7e524db 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -518,7 +518,6 @@ void snd_ad1816a_suspend(struct snd_ad1816a *chip) int reg; unsigned long flags; - snd_pcm_suspend_all(chip->pcm); spin_lock_irqsave(&chip->lock, flags); for (reg = 0; reg < 48; reg++) chip->image[reg] = snd_ad1816a_read(chip, reg); diff --git a/sound/isa/als100.c b/sound/isa/als100.c index f63142ec287e..571108021e9d 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -322,7 +322,6 @@ static int snd_als100_pnp_suspend(struct pnp_card_link *pcard, pm_message_t stat struct snd_sb *chip = acard->chip; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); return 0; } diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index de6ef1b1cf0e..617977516201 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c @@ -434,7 +434,6 @@ static int snd_cmi8328_suspend(struct device *pdev, unsigned int n, cmi = card->private_data; snd_cmi8328_cfg_save(cmi->port, cmi->cfg); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(cmi->wss->pcm); cmi->wss->suspend(cmi->wss); return 0; diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 6b8c46942efb..7e5aa06414c4 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -484,7 +484,6 @@ static int snd_cmi8330_suspend(struct snd_card *card) struct snd_cmi8330 *acard = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(acard->pcm); acard->wss->suspend(acard->wss); snd_sbmixer_suspend(acard->sb); return 0; diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index 3dfe7e592c25..87527627e059 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -301,10 +301,8 @@ static int snd_es968_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) { struct snd_card *card = pnp_get_card_drvdata(pcard); - struct snd_es1688 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); return 0; } diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 0d103d6f805e..77aa9a27fb3b 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1731,8 +1731,6 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - /* power down */ chip->pm_reg = (unsigned char)snd_es18xx_read(chip, ES18XX_PM); chip->pm_reg |= (ES18XX_PM_FM | ES18XX_PM_SUS); diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index bfa0055e1fd6..7a313ff589c7 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -356,7 +356,6 @@ static int snd_jazz16_suspend(struct device *pdev, unsigned int n, struct snd_sb *chip = acard->chip; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); return 0; } diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 8f9ebeb998f6..3844d4c02f49 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -471,7 +471,6 @@ static int snd_sb16_suspend(struct snd_card *card, pm_message_t state) struct snd_sb *chip = acard->chip; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); return 0; } diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index d77dcba276b5..aa2a83eb81a9 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -218,7 +218,6 @@ static int snd_sb8_suspend(struct device *dev, unsigned int n, struct snd_sb *chip = acard->chip; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); return 0; } diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 3a5008837576..b11ef97bce1b 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1625,7 +1625,6 @@ static void snd_wss_suspend(struct snd_wss *chip) int reg; unsigned long flags; - snd_pcm_suspend_all(chip->pcm); spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) chip->image[reg] = snd_wss_in(chip, reg); From 3c40dfeb044943d2323d39c7348c910746a81add Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:02:20 +0100 Subject: [PATCH 119/461] ALSA: drivers: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 4 ---- sound/drivers/dummy.c | 2 -- sound/drivers/pcsp/pcsp.c | 1 - sound/drivers/vx/vx_core.c | 4 ---- 4 files changed, 11 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 1e34e6381baa..65c903b639c2 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1200,12 +1200,8 @@ static int loopback_remove(struct platform_device *devptr) static int loopback_suspend(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); - struct loopback *loopback = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - - snd_pcm_suspend_all(loopback->pcm[0]); - snd_pcm_suspend_all(loopback->pcm[1]); return 0; } diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 9af154db530a..c8d31550e9a1 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -1138,10 +1138,8 @@ static int snd_dummy_remove(struct platform_device *devptr) static int snd_dummy_suspend(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); - struct snd_dummy *dummy = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(dummy->pcm); return 0; } diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 0dd3f46eb03e..d83ad3820f02 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -197,7 +197,6 @@ static int pcsp_suspend(struct device *dev) { struct snd_pcsp *chip = dev_get_drvdata(dev); pcsp_stop_beep(chip); - snd_pcm_suspend_all(chip->pcm); return 0; } diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 04368dd59a4c..19496fa486aa 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -732,12 +732,8 @@ EXPORT_SYMBOL(snd_vx_dsp_load); */ int snd_vx_suspend(struct vx_core *chip) { - unsigned int i; - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); chip->chip_status |= VX_STAT_IN_SUSPEND; - for (i = 0; i < chip->hw->num_codecs; i++) - snd_pcm_suspend_all(chip->pcm[i]); return 0; } From 17bc4815de586d001c82d0ddf75247283c3f002a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:02:51 +0100 Subject: [PATCH 120/461] ALSA: pci: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ali5451/ali5451.c | 4 +--- sound/pci/als300.c | 1 - sound/pci/als4000.c | 1 - sound/pci/atiixp_modem.c | 2 -- sound/pci/azt3328.c | 4 ---- sound/pci/ca0106/ca0106_main.c | 3 --- sound/pci/cmipci.c | 4 ---- sound/pci/cs4281.c | 2 -- sound/pci/cs46xx/cs46xx_lib.c | 6 ------ sound/pci/cs5535audio/cs5535audio_pm.c | 1 - sound/pci/ctxfi/ctatc.c | 8 -------- sound/pci/echoaudio/echoaudio.c | 3 --- sound/pci/emu10k1/emu10k1.c | 6 ------ sound/pci/ens1370.c | 3 --- sound/pci/es1938.c | 1 - sound/pci/es1968.c | 1 - sound/pci/fm801.c | 1 - sound/pci/hda/hda_codec.c | 2 -- sound/pci/ice1712/ice1712.c | 3 --- sound/pci/ice1712/ice1724.c | 3 --- sound/pci/intel8x0.c | 2 -- sound/pci/intel8x0m.c | 3 --- sound/pci/maestro3.c | 1 - sound/pci/nm256/nm256.c | 1 - sound/pci/oxygen/oxygen_lib.c | 5 +---- sound/pci/riptide/riptide.c | 1 - sound/pci/rme96.c | 2 -- sound/pci/sis7019.c | 1 - sound/pci/trident/trident_main.c | 4 ---- sound/pci/via82xx.c | 2 -- sound/pci/via82xx_modem.c | 2 -- sound/pci/ymfpci/ymfpci_main.c | 4 ---- 32 files changed, 2 insertions(+), 85 deletions(-) diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 9f569379b77e..e781ccca1793 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1882,10 +1882,8 @@ static int ali_suspend(struct device *dev) return 0; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < chip->num_of_codecs; i++) { - snd_pcm_suspend_all(chip->pcm[i]); + for (i = 0; i < chip->num_of_codecs; i++) snd_ac97_suspend(chip->ac97[i]); - } spin_lock_irq(&chip->reg_lock); diff --git a/sound/pci/als300.c b/sound/pci/als300.c index eaa2d853d922..516b3d9cbfdf 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -731,7 +731,6 @@ static int snd_als300_suspend(struct device *dev) struct snd_als300 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); return 0; } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 26b097edec8c..45fa38382e79 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -994,7 +994,6 @@ static int snd_als4000_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_sbmixer_suspend(chip); return 0; } diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index dc1de860cedf..a357a8e2e73d 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1125,8 +1125,6 @@ static int snd_atiixp_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < NUM_ATI_PCMDEVS; i++) - snd_pcm_suspend_all(chip->pcmdevs[i]); for (i = 0; i < NUM_ATI_CODECS; i++) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index fc18c29a8173..90348817f096 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2699,10 +2699,6 @@ snd_azf3328_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - /* same pcm object for playback/capture */ - snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); - snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); - snd_azf3328_suspend_ac97(chip); snd_azf3328_suspend_regs(chip, chip->ctrl_io, diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index cd27b5536654..3d1b0bbff33b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1910,11 +1910,8 @@ static int snd_ca0106_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_ca0106 *chip = card->private_data; - int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < 4; i++) - snd_pcm_suspend_all(chip->pcm[i]); if (chip->details->ac97) snd_ac97_suspend(chip->ac97); snd_ca0106_mixer_suspend(chip); diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 452cc79b44af..5bbf31c1695c 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -3351,10 +3351,6 @@ static int snd_cmipci_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(cm->pcm); - snd_pcm_suspend_all(cm->pcm2); - snd_pcm_suspend_all(cm->pcm_spdif); - /* save registers */ for (i = 0; i < ARRAY_SIZE(saved_regs); i++) cm->saved_regs[i] = snd_cmipci_read(cm, saved_regs[i]); diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index ec4247638fa1..a9fb819cad1d 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -2002,8 +2002,6 @@ static int cs4281_suspend(struct device *dev) unsigned int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97_secondary); diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 750eec437a79..a77d4cc44028 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3781,12 +3781,6 @@ static int snd_cs46xx_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->in_suspend = 1; - snd_pcm_suspend_all(chip->pcm); -#ifdef CONFIG_SND_CS46XX_NEW_DSP - snd_pcm_suspend_all(chip->pcm_rear); - snd_pcm_suspend_all(chip->pcm_center_lfe); - snd_pcm_suspend_all(chip->pcm_iec958); -#endif // chip->ac97_powerdown = snd_cs46xx_codec_read(chip, AC97_POWER_CONTROL); // chip->ac97_general_purpose = snd_cs46xx_codec_read(chip, BA0_AC97_GENERAL_PURPOSE); diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 82bd10b68a77..446ef1f1b45a 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -62,7 +62,6 @@ static int __maybe_unused snd_cs5535audio_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(cs5535au->pcm); snd_ac97_suspend(cs5535au->ac97); for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 2ada8444abd9..e622613ea947 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1548,18 +1548,10 @@ static void atc_connect_resources(struct ct_atc *atc) #ifdef CONFIG_PM_SLEEP static int atc_suspend(struct ct_atc *atc) { - int i; struct hw *hw = atc->hw; snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); - for (i = FRONT; i < NUM_PCMS; i++) { - if (!atc->pcms[i]) - continue; - - snd_pcm_suspend_all(atc->pcms[i]); - } - atc_release_resources(atc); hw->suspend(hw); diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 907cf1a46712..18d30d479b6b 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -2165,9 +2165,6 @@ static int snd_echo_suspend(struct device *dev) { struct echoaudio *chip = dev_get_drvdata(dev); - snd_pcm_suspend_all(chip->analog_pcm); - snd_pcm_suspend_all(chip->digital_pcm); - #ifdef ECHOCARD_HAS_MIDI /* This call can sleep */ if (chip->midi_out) diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index d3203df50a1a..3c41a0edcfb0 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -224,12 +224,6 @@ static int snd_emu10k1_suspend(struct device *dev) cancel_delayed_work_sync(&emu->emu1010.firmware_work); - snd_pcm_suspend_all(emu->pcm); - snd_pcm_suspend_all(emu->pcm_mic); - snd_pcm_suspend_all(emu->pcm_efx); - snd_pcm_suspend_all(emu->pcm_multi); - snd_pcm_suspend_all(emu->pcm_p16v); - snd_ac97_suspend(emu->ac97); snd_emu10k1_efx_suspend(emu); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 727eb3da1fda..1f2960ecc57e 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -2037,9 +2037,6 @@ static int snd_ensoniq_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(ensoniq->pcm1); - snd_pcm_suspend_all(ensoniq->pcm2); - #ifdef CHIP1371 snd_ac97_suspend(ensoniq->u.es1371.ac97); #else diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 9d248eb2e26c..84d07bce581c 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1475,7 +1475,6 @@ static int es1938_suspend(struct device *dev) unsigned char *s, *d; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); /* save mixer-related registers */ for (s = saved_regs, d = chip->saved_regs; *s; s++, d++) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 0b1845ca6005..9dcb698fc8c7 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -2392,7 +2392,6 @@ static int es1968_suspend(struct device *dev) chip->in_suspend = 1; cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_es1968_bob_stop(chip); return 0; diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index e3fb9c61017c..1317f3183eb1 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1408,7 +1408,6 @@ static int snd_fm801_suspend(struct device *dev) if (chip->tea575x_tuner & TUNER_ONLY) { /* FIXME: tea575x suspend */ } else { - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97_sec); } diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9f8d59e7e89f..ff6dbed4d3cd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2927,8 +2927,6 @@ static int hda_codec_runtime_suspend(struct device *dev) unsigned int state; cancel_delayed_work_sync(&codec->jackpoll_work); - list_for_each_entry(pcm, &codec->pcm_list_head, list) - snd_pcm_suspend_all(pcm->pcm); state = hda_call_codec_suspend(codec); if (codec->link_down_at_suspend || (codec_has_clkstop(codec) && codec_has_epss(codec) && diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index f1fe497c2f9d..dda9b26192cb 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2792,9 +2792,6 @@ static int snd_ice1712_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(ice->pcm); - snd_pcm_suspend_all(ice->pcm_pro); - snd_pcm_suspend_all(ice->pcm_ds); snd_ac97_suspend(ice->ac97); spin_lock_irq(&ice->reg_lock); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 057c2f394ea7..42994cf36156 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2804,9 +2804,6 @@ static int snd_vt1724_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(ice->pcm); - snd_pcm_suspend_all(ice->pcm_pro); - snd_pcm_suspend_all(ice->pcm_ds); snd_ac97_suspend(ice->ac97); spin_lock_irq(&ice->reg_lock); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index ffddcdfe0c66..885e1d488ed6 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2614,8 +2614,6 @@ static int intel8x0_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < chip->pcm_devs; i++) - snd_pcm_suspend_all(chip->pcm[i]); for (i = 0; i < chip->ncodecs; i++) snd_ac97_suspend(chip->ac97[i]); if (chip->device_type == DEVICE_INTEL_ICH4) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index c84629190cba..44eb9e28a1eb 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1025,11 +1025,8 @@ static int intel8x0m_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct intel8x0m *chip = card->private_data; - int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < chip->pcm_devs; i++) - snd_pcm_suspend_all(chip->pcm[i]); snd_ac97_suspend(chip->ac97); if (chip->irq >= 0) { free_irq(chip->irq, chip); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 62962178a9d7..1a9468c14aaf 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -2422,7 +2422,6 @@ static int m3_suspend(struct device *dev) chip->in_suspend = 1; cancel_work_sync(&chip->hwvol_work); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); msleep(10); /* give the assp a chance to idle.. */ diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index b97f4ea6b56c..85e46ff44ac3 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1413,7 +1413,6 @@ static int nm256_suspend(struct device *dev) struct nm256 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); chip->coeffs_current = 0; return 0; diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index b4ef5804212d..6dce56c209aa 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -744,13 +744,10 @@ static int oxygen_pci_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct oxygen *chip = card->private_data; - unsigned int i, saved_interrupt_mask; + unsigned int saved_interrupt_mask; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < PCM_COUNT; ++i) - snd_pcm_suspend(chip->streams[i]); - if (chip->model.suspend) chip->model.suspend(chip); diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 23017e3bc76c..1d431c8052d6 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1158,7 +1158,6 @@ static int riptide_suspend(struct device *dev) chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); return 0; } diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index dcfa4d7a73e2..c56702e6cb60 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -2388,8 +2388,6 @@ static int rme96_suspend(struct device *dev) struct rme96 *rme96 = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend(rme96->playback_substream); - snd_pcm_suspend(rme96->capture_substream); /* save capture & playback pointers */ rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 964acf302479..6b27980d77a8 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1214,7 +1214,6 @@ static int sis_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(sis->pcm); if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) snd_ac97_suspend(sis->ac97[0]); if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 5523e193d556..f271ea436cff 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3915,10 +3915,6 @@ static int snd_trident_suspend(struct device *dev) trident->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(trident->pcm); - snd_pcm_suspend_all(trident->foldback); - snd_pcm_suspend_all(trident->spdif); - snd_ac97_suspend(trident->ac97); snd_ac97_suspend(trident->ac97_sec); return 0; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index c488c5afa195..736ac79901b3 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2278,8 +2278,6 @@ static int snd_via82xx_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < 2; i++) - snd_pcm_suspend_all(chip->pcms[i]); for (i = 0; i < chip->num_devs; i++) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index b13c8688cc8d..3f59e0279058 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1038,8 +1038,6 @@ static int snd_via82xx_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - for (i = 0; i < 2; i++) - snd_pcm_suspend_all(chip->pcms[i]); for (i = 0; i < chip->num_devs; i++) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index a4926fb03991..c688b7f481da 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2304,10 +2304,6 @@ static int snd_ymfpci_suspend(struct device *dev) unsigned int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_pcm_suspend_all(chip->pcm2); - snd_pcm_suspend_all(chip->pcm_spdif); - snd_pcm_suspend_all(chip->pcm_4ch); snd_ac97_suspend(chip->ac97); for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); From 2c76706843c998ceb136e8b04af1822832911e7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:03:16 +0100 Subject: [PATCH 121/461] ALSA: usb: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/card.c | 1 - sound/usb/line6/driver.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index a105947eaf55..dfa38b78c494 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -811,7 +811,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); if (!chip->num_suspended_intf++) { list_for_each_entry(as, &chip->pcm_list, list) { - snd_pcm_suspend_all(as->pcm); snd_usb_pcm_suspend(as); as->substream[0].need_setup_ep = as->substream[1].need_setup_ep = true; diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index c1376bfdc90b..7afe8fae4939 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -849,10 +849,8 @@ int line6_suspend(struct usb_interface *interface, pm_message_t message) if (line6->properties->capabilities & LINE6_CAP_CONTROL) line6_stop_listen(line6); - if (line6pcm != NULL) { - snd_pcm_suspend_all(line6pcm->pcm); + if (line6pcm != NULL) line6pcm->flags = 0; - } return 0; } From 0c3df9edb24d06af388f5ff648232ba2361717fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:03:39 +0100 Subject: [PATCH 122/461] ALSA: x86: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 00c92eb854ce..16ca91f57e7f 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1651,18 +1651,6 @@ static int had_create_jack(struct snd_intelhad *ctx, static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) { struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); - int port; - - for_each_port(card_ctx, port) { - struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; - struct snd_pcm_substream *substream; - - substream = had_substream_get(ctx); - if (substream) { - snd_pcm_suspend(substream); - had_substream_put(ctx); - } - } snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot); From ece984a63a8d2d9132c6198d47d0a4be8ea99d17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:03:52 +0100 Subject: [PATCH 123/461] ALSA: ppc: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/ppc/pmac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index d692e4070167..6d420bd3ae17 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1365,7 +1365,6 @@ void snd_pmac_suspend(struct snd_pmac *chip) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); if (chip->suspend) chip->suspend(chip); - snd_pcm_suspend_all(chip->pcm); spin_lock_irqsave(&chip->reg_lock, flags); snd_pmac_beep_stop(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); From d3bdf3f37ac39ed803535171e4d7208f48bf36fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:04:02 +0100 Subject: [PATCH 124/461] ALSA: aoa: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index c3f57a3fb1a5..33e82341c048 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -380,10 +380,6 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) int err, ret = 0; list_for_each_entry(i2sdev, &control->list, item) { - /* Notify Alsa */ - /* Suspend PCM streams */ - snd_pcm_suspend_all(i2sdev->sound.pcm); - /* Notify codecs */ list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { err = 0; From 793e0fca25fa756884851e445da11bae8099c09c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:04:10 +0100 Subject: [PATCH 125/461] ALSA: arm: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 1 - sound/arm/pxa2xx-ac97.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 0114ffed56dd..0c3f073e2600 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -757,7 +757,6 @@ static int aaci_do_suspend(struct snd_card *card) { struct aaci *aaci = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3cold); - snd_pcm_suspend_all(aaci->pcm); return 0; } diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 1f72672262d0..68fe5bb11eea 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -124,7 +124,6 @@ static int pxa2xx_ac97_do_suspend(struct snd_card *card) pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3cold); - snd_pcm_suspend_all(pxa2xx_ac97_pcm); snd_ac97_suspend(pxa2xx_ac97_ac97); if (platform_ops && platform_ops->suspend) platform_ops->suspend(platform_ops->priv); From 9833f1d050311b44860205cd7b4becd97a1c6a15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 18:04:19 +0100 Subject: [PATCH 126/461] ALSA: pcmcia: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index d724ab0653cf..eabf29252895 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -265,7 +265,6 @@ int snd_pdacf_suspend(struct snd_pdacf *chip) u16 val; snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); /* disable interrupts, but use direct write to preserve old register value in chip->regmap */ val = inw(chip->port + PDAUDIOCF_REG_IER); val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1); From ede63a8d45555d42c0e9564874568bbe9df3f8d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jan 2019 10:45:50 +0100 Subject: [PATCH 127/461] drm: bridge: dw-hdmi: Remove superfluous snd_pcm_suspend*() calls The call of snd_pcm_suspend_all() & co became superfluous since we call it in the PCM PM ops. Let's remove them. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index cf3f0caf9c63..ed7af7518b52 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -614,7 +614,6 @@ static int snd_dw_hdmi_suspend(struct device *dev) struct snd_dw_hdmi *dw = dev_get_drvdata(dev); snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); - snd_pcm_suspend_all(dw->pcm); return 0; } From 910e7e1923d52a74183d3aedd45f7fa4c3585400 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jan 2019 10:49:47 +0100 Subject: [PATCH 128/461] ALSA: doc: Update the description about PCM suspend procedure The PCM suspend procedure was changed for drivers, so that they don't have to call snd_pcm_suspend*() in each callback any longer. Update the documentation to adapt the changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- .../kernel-api/writing-an-alsa-driver.rst | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index b37234afdfa1..7c2f2032d30a 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3924,15 +3924,12 @@ The scheme of the real suspend job is as follows. 2. Call :c:func:`snd_power_change_state()` with ``SNDRV_CTL_POWER_D3hot`` to change the power status. -3. Call :c:func:`snd_pcm_suspend_all()` to suspend the running - PCM streams. - -4. If AC97 codecs are used, call :c:func:`snd_ac97_suspend()` for +3. If AC97 codecs are used, call :c:func:`snd_ac97_suspend()` for each codec. -5. Save the register values if necessary. +4. Save the register values if necessary. -6. Stop the hardware if necessary. +5. Stop the hardware if necessary. A typical code would be like: @@ -3946,12 +3943,10 @@ A typical code would be like: /* (2) */ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); /* (3) */ - snd_pcm_suspend_all(chip->pcm); - /* (4) */ snd_ac97_suspend(chip->ac97); - /* (5) */ + /* (4) */ snd_mychip_save_registers(chip); - /* (6) */ + /* (5) */ snd_mychip_stop_hardware(chip); return 0; } @@ -3994,13 +3989,9 @@ A typical code would be like: return 0; } -As shown in the above, it's better to save registers after suspending -the PCM operations via :c:func:`snd_pcm_suspend_all()` or -:c:func:`snd_pcm_suspend()`. It means that the PCM streams are -already stopped when the register snapshot is taken. But, remember that -you don't have to restart the PCM stream in the resume callback. It'll -be restarted via trigger call with ``SNDRV_PCM_TRIGGER_RESUME`` when -necessary. +Note that, at the time this callback gets called, the PCM stream has +been already suspended via its own PM ops calling +:c:func:`snd_pcm_suspend_all()` internally. OK, we have all callbacks now. Let's set them up. In the initialization of the card, make sure that you can get the chip data from the card From ce7f93e2bd6f649980846914e4a04ad6ba141fa6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jan 2019 10:54:02 +0100 Subject: [PATCH 129/461] ALSA: pcm: Make snd_pcm_suspend() local static snd_pcm_suspend() is no longer called from outside, so let's make it local static. Also drop a superfluous NULL check there. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 5 ----- sound/core/pcm_native.c | 11 +++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 04e97564949c..2c30c1ad1b0d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -582,13 +582,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status); int snd_pcm_drain_done(struct snd_pcm_substream *substream); int snd_pcm_stop_xrun(struct snd_pcm_substream *substream); #ifdef CONFIG_PM -int snd_pcm_suspend(struct snd_pcm_substream *substream); int snd_pcm_suspend_all(struct snd_pcm *pcm); #else -static inline int snd_pcm_suspend(struct snd_pcm_substream *substream) -{ - return 0; -} static inline int snd_pcm_suspend_all(struct snd_pcm *pcm) { return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 818dff1de545..26afb6b0889a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1460,29 +1460,24 @@ static const struct action_ops snd_pcm_action_suspend = { .post_action = snd_pcm_post_suspend }; -/** +/* * snd_pcm_suspend - trigger SUSPEND to all linked streams * @substream: the PCM substream * * After this call, all streams are changed to SUSPENDED state. * - * Return: Zero if successful (or @substream is %NULL), or a negative error - * code. + * Return: Zero if successful, or a negative error code. */ -int snd_pcm_suspend(struct snd_pcm_substream *substream) +static int snd_pcm_suspend(struct snd_pcm_substream *substream) { int err; unsigned long flags; - if (! substream) - return 0; - snd_pcm_stream_lock_irqsave(substream, flags); err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); snd_pcm_stream_unlock_irqrestore(substream, flags); return err; } -EXPORT_SYMBOL(snd_pcm_suspend); /** * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm From 0ddb0fb00a769ef85c788cb40627d09df6919833 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 15 Jan 2019 19:02:53 +0800 Subject: [PATCH 130/461] ASoC: qcom: Kconfig: select max98927 for sdm845 Select SND_SOC_MAX98927 for SND_SOC_SDM845. Acked-by: Srinivas Kandagatla Signed-off-by: Rohit kumar Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 804ae0d93058..7948e993adba 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -102,6 +102,7 @@ config SND_SOC_SDM845 select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON select SND_SOC_RT5663 + select SND_SOC_MAX98927 help To add support for audio on Qualcomm Technologies Inc. SDM845 SoC-based systems. From 9019ab102fe8d741f873e6f630fb7aa74c38818a Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 15 Jan 2019 16:41:59 +0800 Subject: [PATCH 131/461] ASoC: sdm845: Set DAI format for dmic codec Set codec DAI format for dmic codec in startup. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 6f66a58e23ca..882f52ed8231 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -248,12 +248,14 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) break; case SECONDARY_MI2S_TX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; if (++(data->sec_mi2s_clk_count) == 1) { snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); } snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; case QUATERNARY_TDM_RX_0: From 3ac1b2e4158c73175278a27c5551fa331c260b48 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 17 Jan 2019 06:08:53 +0800 Subject: [PATCH 132/461] ASoC: rt5682: add default pdata for i2s mode Add a default pdata which can fit most HW design. So we don't need to add a lot of DMI checking in this driver. Signed-off-by: Bard liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 89c43b26c379..bd45d0343913 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -43,6 +43,12 @@ static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "VBAT", }; +static const struct rt5682_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, + .jd_src = RT5682_JD1, +}; + struct rt5682_priv { struct snd_soc_component *component; struct rt5682_platform_data pdata; @@ -2534,6 +2540,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5682); + rt5682->pdata = i2s_default_platform_data; + if (pdata) rt5682->pdata = *pdata; else From d9866572486802bc598a3e8576a5231378d190de Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:52 +0100 Subject: [PATCH 133/461] ASoC: imx-sgtl5000: put of nodes if finding codec fails Make sure to properly put the of node in case finding the codec fails. Fixes: 81e8e4926167 ("ASoC: fsl: add sgtl5000 clock support for imx-sgtl5000") Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index c29200cf755a..594bde3b0ded 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -111,7 +111,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { dev_err(&pdev->dev, "failed to find codec platform device\n"); - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto fail; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); From 691beb02d9ff364000a8de4e74898600b9caee89 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:53 +0100 Subject: [PATCH 134/461] ASoC: imx-sgtl5000: lower log level for potential probe deferral cases Not finding the codec/SSI instance can be due to probe deferral. Do not print error messages in those cases. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 594bde3b0ded..9790a2a8ec2d 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -104,13 +104,13 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ssi_pdev = of_find_device_by_node(ssi_np); if (!ssi_pdev) { - dev_err(&pdev->dev, "failed to find SSI platform device\n"); + dev_dbg(&pdev->dev, "failed to find SSI platform device\n"); ret = -EPROBE_DEFER; goto fail; } codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { - dev_err(&pdev->dev, "failed to find codec platform device\n"); + dev_dbg(&pdev->dev, "failed to find codec platform device\n"); ret = -EPROBE_DEFER; goto fail; } From e379ee969ecbc807c5b233460c2a88b6ee06bde3 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:54 +0100 Subject: [PATCH 135/461] ASoC: imx-sgtl5000: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 9790a2a8ec2d..b6cb80480b60 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -157,7 +157,9 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); goto fail; } From 1aabff2508cbd184b0141f2d1b8712bacbb78cef Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:55 +0100 Subject: [PATCH 136/461] ASoC: fsl_spdif: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 740b90df44bb..a26686e7281c 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1320,7 +1320,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) } ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); - if (ret) + if (ret && ret != -EPROBE_DEFER) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); return ret; From 2363d85f4e04f7218efc66b6167a405cccbc8ff7 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:56 +0100 Subject: [PATCH 137/461] ASoC: imx-spdif: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Removing the goto would not be strictly necessary. However, if code gets added later, the cleanup in the EPROBE_DEFER case likely would get missed. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-spdif.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index fb896b2c9ba3..797d66e43d49 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -67,10 +67,8 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) goto end; ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) { + if (ret && ret != -EPROBE_DEFER) dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); - goto end; - } end: of_node_put(spdif_np); From 7c7e2d6a9ca3c74ba7ed4da2a75916b2f9ae38f0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:55:04 +0100 Subject: [PATCH 138/461] ASoC: soc-core: remove error due to probe deferral Deferred probes shouldn't cause error messages in the boot log, so change the dev_err() to the more harmless dev_info(). Signed-off-by: Stefan Agner Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0462b3ec977a..98bb05f6ed56 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -903,8 +903,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { - dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", + codecs[i].dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From e412fcb0db5c44a3450ca678b281ea9332e6bf82 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 18 Jan 2019 14:26:46 +0000 Subject: [PATCH 139/461] ASoC: fsl_sai: Remove expensive print in irq handler When stopping audio, ASoC will first stop DMA then CPU DAI. Sometimes there is a delay between DMA stop and CPU DAI stop, which triggers an underrun error. Now, because of the delay introduced by dev_err another underrun error will occur causing a vicious circle making impossible to stop CPU DAI. Signed-off-by: Shengjiu Wang Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 4163f2cfc06f..db9e0872f73d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -62,10 +62,10 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) dev_dbg(dev, "isr: Start of Tx word detected\n"); if (flags & FSL_SAI_CSR_SEF) - dev_warn(dev, "isr: Tx Frame sync error detected\n"); + dev_dbg(dev, "isr: Tx Frame sync error detected\n"); if (flags & FSL_SAI_CSR_FEF) { - dev_warn(dev, "isr: Transmit underrun detected\n"); + dev_dbg(dev, "isr: Transmit underrun detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } @@ -96,10 +96,10 @@ irq_rx: dev_dbg(dev, "isr: Start of Rx word detected\n"); if (flags & FSL_SAI_CSR_SEF) - dev_warn(dev, "isr: Rx Frame sync error detected\n"); + dev_dbg(dev, "isr: Rx Frame sync error detected\n"); if (flags & FSL_SAI_CSR_FEF) { - dev_warn(dev, "isr: Receive overflow detected\n"); + dev_dbg(dev, "isr: Receive overflow detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } From 62bc79d35ebb55451112979babea864975cfd16d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jan 2019 11:20:41 +0900 Subject: [PATCH 140/461] ASoC: soc.h: add explanation of legacy/modern style of dai_link Current ALSA SoC is assuming 1 CPU 1 Platform (= DMA) style system. Because of this background, it is directly using xxx_name / xxx_of_node / xxx_dai_name on dai_link. Let's call it as legacy style here. More complex style system like multi CPU multi Platform (= DMA) will coming. To supporting it, we can use snd_soc_dai_link_component on dai_link. Let's call it as modern style here. But current ALSA SoC can't support it so far. Thus, we need to have multi CPU / multi Codec / multi Platform style in the future on ALSA SoC. Currently we already have multi Codec support. Platform is starting to use modern style on dai_link, but still style only. Multi Platform is not yet implemented. And we still don't have multi CPU support on ALSA SoC, and not have modern style either. Currently, if driver is using legacy style Codec/Platform, it will be converted to modern style on soc-core. This means, we are using glue code for legacy vs modern style so far on ALSA SoC. We can fully switch to modern style on all drivers if ALSA SoC supported modern style for CPU, and then, legacy style code will be removed from ALSA SoC. Untile then, we need to keep both legacy/modern style and its glue code. This patch adds such future plan and background on soc.h Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 20 ++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e665f111b0d2..c31b6d122ff6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -891,6 +891,18 @@ struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ const char *stream_name; /* Stream name */ + + /* + * cpu_name + * cpu_of_node + * cpu_dai_name + * + * These are legacy style, and will be replaced to + * modern style (= snd_soc_dai_link_component) in the future, + * but, not yet supported so far. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's CPU-side device, either by device name, * or by DT/OF node, but not both. If this information is omitted, @@ -906,6 +918,19 @@ struct snd_soc_dai_link { * only, which only works well when that device exposes a single DAI. */ const char *cpu_dai_name; + + /* + * codec_name + * codec_of_node + * codec_dai_name + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MUST specify the link's codec, either by device name, or by * DT/OF node, but not both. @@ -918,6 +943,17 @@ struct snd_soc_dai_link { struct snd_soc_dai_link_component *codecs; unsigned int num_codecs; + /* + * platform_name + * platform_of_node + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's platform/PCM/DMA driver, either by * device name, or by DT/OF node, but not both. Some forms of link diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 890d6c9c2752..de2851f1b3df 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1029,9 +1029,14 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link_component *platform = dai_link->platform; /* - * FIXME + * REMOVE ME * - * this function should be removed in the future + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ if (!platform || dai_link->legacy_platform) { @@ -1059,6 +1064,17 @@ static int snd_soc_init_platform(struct snd_soc_card *card, static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + /* + * REMOVE ME + * + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link + */ + /* Legacy codec/codec_dai link is a single entry in multicodec */ if (dai_link->codec_name || dai_link->codec_of_node || dai_link->codec_dai_name) { From 3bb700e76914fe3a2f5b57704f23df593151521f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 21 Jan 2019 09:10:00 +0100 Subject: [PATCH 141/461] ALSA: hda - Fix unused variable warning The unused variable was forgotten to be removed and now we get a compiler warning: sound/pci/hda/hda_codec.c: In function 'hda_codec_runtime_suspend': sound/pci/hda/hda_codec.c:2926:18: warning: unused variable 'pcm' Fixes: 17bc4815de58 ("ALSA: pci: Remove superfluous snd_pcm_suspend*() calls") Reported-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ff6dbed4d3cd..e4704f5729d3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2923,7 +2923,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) static int hda_codec_runtime_suspend(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - struct hda_pcm *pcm; unsigned int state; cancel_delayed_work_sync(&codec->jackpoll_work); From e199d1eb7f5dbc8e5127af08726a8b6452e2641f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:45 +0900 Subject: [PATCH 142/461] ALSA: fireface: rename protocol layer for former models In a series of Fireface, later model supports different protocol from former models. This commit is a preparation to support both of protocols. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/Makefile | 2 +- .../{ff-protocol-ff800.c => ff-protocol-former.c} | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) rename sound/firewire/fireface/{ff-protocol-ff800.c => ff-protocol-former.c} (94%) diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 79a7d6d99d72..3fb586d32584 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,4 +1,4 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \ - ff-protocol-ff800.o + ff-protocol-former.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-former.c similarity index 94% rename from sound/firewire/fireface/ff-protocol-ff800.c rename to sound/firewire/fireface/ff-protocol-former.c index 2acbf6039770..a383fd5fc879 100644 --- a/sound/firewire/fireface/ff-protocol-ff800.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -1,10 +1,9 @@ -/* - * ff-protocol-ff800.c - a part of driver for RME Fireface series - * - * Copyright (c) 2018 Takashi Sakamoto - * - * Licensed under the terms of the GNU General Public License, version 2. - */ +// SPDX-License-Identifier: GPL-2.0 +// ff-protocol-former.c - a part of driver for RME Fireface series +// +// Copyright (c) 2019 Takashi Sakamoto +// +// Licensed under the terms of the GNU General Public License, version 2. #include From 9dd466aca377182b7ea77bc0058c64abba667f90 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:46 +0900 Subject: [PATCH 143/461] ALSA: fireface: unify protocol layer for FF400/FF800 This commit moves codes for Fireface 400 to a file of former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/Makefile | 3 +- sound/firewire/fireface/ff-protocol-ff400.c | 161 ------------------- sound/firewire/fireface/ff-protocol-former.c | 147 +++++++++++++++++ 3 files changed, 148 insertions(+), 163 deletions(-) delete mode 100644 sound/firewire/fireface/ff-protocol-ff400.c diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 3fb586d32584..62eb78962b93 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,4 +1,3 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ - ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \ - ff-protocol-former.o + ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-ff400.c b/sound/firewire/fireface/ff-protocol-ff400.c deleted file mode 100644 index 2280fab9b3c7..000000000000 --- a/sound/firewire/fireface/ff-protocol-ff400.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ff-protocol-ff400.c - a part of driver for RME Fireface series - * - * Copyright (c) 2015-2017 Takashi Sakamoto - * - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include "ff.h" - -#define FF400_STF 0x000080100500ull -#define FF400_RX_PACKET_FORMAT 0x000080100504ull -#define FF400_ISOC_COMM_START 0x000080100508ull -#define FF400_TX_PACKET_FORMAT 0x00008010050cull -#define FF400_ISOC_COMM_STOP 0x000080100510ull - -/* - * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, - * we can allocate between 0 and 7 channel. - */ -static int keep_resources(struct snd_ff *ff, unsigned int rate) -{ - enum snd_ff_stream_mode mode; - int i; - int err; - - // Check whether the given value is supported or not. - for (i = 0; i < CIP_SFC_COUNT; i++) { - if (amdtp_rate_table[i] == rate) - break; - } - if (i >= CIP_SFC_COUNT) - return -EINVAL; - - err = snd_ff_stream_get_multiplier_mode(i, &mode); - if (err < 0) - return err; - - /* Keep resources for in-stream. */ - ff->tx_resources.channels_mask = 0x00000000000000ffuLL; - err = fw_iso_resources_allocate(&ff->tx_resources, - amdtp_stream_get_max_payload(&ff->tx_stream), - fw_parent_device(ff->unit)->max_speed); - if (err < 0) - return err; - - /* Keep resources for out-stream. */ - err = amdtp_ff_set_parameters(&ff->rx_stream, rate, - ff->spec->pcm_playback_channels[mode]); - if (err < 0) - return err; - ff->rx_resources.channels_mask = 0x00000000000000ffuLL; - err = fw_iso_resources_allocate(&ff->rx_resources, - amdtp_stream_get_max_payload(&ff->rx_stream), - fw_parent_device(ff->unit)->max_speed); - if (err < 0) - fw_iso_resources_free(&ff->tx_resources); - - return err; -} - -static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) -{ - __le32 reg; - int err; - - err = keep_resources(ff, rate); - if (err < 0) - return err; - - /* Set the number of data blocks transferred in a second. */ - reg = cpu_to_le32(rate); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_STF, ®, sizeof(reg), 0); - if (err < 0) - return err; - - msleep(100); - - /* - * Set isochronous channel and the number of quadlets of received - * packets. - */ - reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | - ff->rx_resources.channel); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); - if (err < 0) - return err; - - /* - * Set isochronous channel and the number of quadlets of transmitted - * packet. - */ - /* TODO: investigate the purpose of this 0x80. */ - reg = cpu_to_le32((0x80 << 24) | - (ff->tx_resources.channel << 5) | - (ff->tx_stream.data_block_quadlets)); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); - if (err < 0) - return err; - - /* Allow to transmit packets. */ - reg = cpu_to_le32(0x00000001); - return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_ISOC_COMM_START, ®, sizeof(reg), 0); -} - -static void ff400_finish_session(struct snd_ff *ff) -{ - __le32 reg; - - reg = cpu_to_le32(0x80000000); - snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); -} - -static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) -{ - int i; - - for (i = 0; i < length / 4; i++) { - u32 quad = le32_to_cpu(buf[i]); - u8 byte; - unsigned int index; - struct snd_rawmidi_substream *substream; - - /* Message in first port. */ - /* - * This value may represent the index of this unit when the same - * units are on the same IEEE 1394 bus. This driver doesn't use - * it. - */ - index = (quad >> 8) & 0xff; - if (index > 0) { - substream = READ_ONCE(ff->tx_midi_substreams[0]); - if (substream != NULL) { - byte = quad & 0xff; - snd_rawmidi_receive(substream, &byte, 1); - } - } - - /* Message in second port. */ - index = (quad >> 24) & 0xff; - if (index > 0) { - substream = READ_ONCE(ff->tx_midi_substreams[1]); - if (substream != NULL) { - byte = (quad >> 16) & 0xff; - snd_rawmidi_receive(substream, &byte, 1); - } - } - } -} - -const struct snd_ff_protocol snd_ff_protocol_ff400 = { - .handle_midi_msg = ff400_handle_midi_msg, - .begin_session = ff400_begin_session, - .finish_session = ff400_finish_session, -}; diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index a383fd5fc879..ed1271a89484 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -140,3 +140,150 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = { .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, }; + +#define FF400_STF 0x000080100500ull +#define FF400_RX_PACKET_FORMAT 0x000080100504ull +#define FF400_ISOC_COMM_START 0x000080100508ull +#define FF400_TX_PACKET_FORMAT 0x00008010050cull +#define FF400_ISOC_COMM_STOP 0x000080100510ull + +/* + * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, + * we can allocate between 0 and 7 channel. + */ +static int keep_resources(struct snd_ff *ff, unsigned int rate) +{ + enum snd_ff_stream_mode mode; + int i; + int err; + + // Check whether the given value is supported or not. + for (i = 0; i < CIP_SFC_COUNT; i++) { + if (amdtp_rate_table[i] == rate) + break; + } + if (i >= CIP_SFC_COUNT) + return -EINVAL; + + err = snd_ff_stream_get_multiplier_mode(i, &mode); + if (err < 0) + return err; + + /* Keep resources for in-stream. */ + ff->tx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->tx_resources, + amdtp_stream_get_max_payload(&ff->tx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + return err; + + /* Keep resources for out-stream. */ + ff->rx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->rx_resources, + amdtp_stream_get_max_payload(&ff->rx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + fw_iso_resources_free(&ff->tx_resources); + + return err; +} + +static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) +{ + __le32 reg; + int err; + + err = keep_resources(ff, rate); + if (err < 0) + return err; + + /* Set the number of data blocks transferred in a second. */ + reg = cpu_to_le32(rate); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + msleep(100); + + /* + * Set isochronous channel and the number of quadlets of received + * packets. + */ + reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | + ff->rx_resources.channel); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); + if (err < 0) + return err; + + /* + * Set isochronous channel and the number of quadlets of transmitted + * packet. + */ + /* TODO: investigate the purpose of this 0x80. */ + reg = cpu_to_le32((0x80 << 24) | + (ff->tx_resources.channel << 5) | + (ff->tx_stream.data_block_quadlets)); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); + if (err < 0) + return err; + + /* Allow to transmit packets. */ + reg = cpu_to_le32(0x00000001); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_ISOC_COMM_START, ®, sizeof(reg), 0); +} + +static void ff400_finish_session(struct snd_ff *ff) +{ + __le32 reg; + + reg = cpu_to_le32(0x80000000); + snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); +} + +static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +{ + int i; + + for (i = 0; i < length / 4; i++) { + u32 quad = le32_to_cpu(buf[i]); + u8 byte; + unsigned int index; + struct snd_rawmidi_substream *substream; + + /* Message in first port. */ + /* + * This value may represent the index of this unit when the same + * units are on the same IEEE 1394 bus. This driver doesn't use + * it. + */ + index = (quad >> 8) & 0xff; + if (index > 0) { + substream = READ_ONCE(ff->tx_midi_substreams[0]); + if (substream != NULL) { + byte = quad & 0xff; + snd_rawmidi_receive(substream, &byte, 1); + } + } + + /* Message in second port. */ + index = (quad >> 24) & 0xff; + if (index > 0) { + substream = READ_ONCE(ff->tx_midi_substreams[1]); + if (substream != NULL) { + byte = (quad >> 16) & 0xff; + snd_rawmidi_receive(substream, &byte, 1); + } + } + } +} + +const struct snd_ff_protocol snd_ff_protocol_ff400 = { + .handle_midi_msg = ff400_handle_midi_msg, + .begin_session = ff400_begin_session, + .finish_session = ff400_finish_session, +}; From 2f8af5b3f09cd3d2b483b35a400bf2b827ada179 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:47 +0900 Subject: [PATCH 144/461] ALSA: fireface: obsolete proc node to leave one node In a series of Fireface, latter protocol has no way for drivers to retrieve current clock configuration. On the other hand, this driver has proc node for it. This commit removes a proc node to dump both clock configuration and synchronization status in one proc node. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index a0c550dabe9a..37f84b7fc432 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,10 +8,8 @@ #include "./ff.h" -static void proc_dump_clock_config(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) { - struct snd_ff *ff = entry->private_data; __le32 reg; u32 data; unsigned int rate; @@ -87,10 +85,8 @@ static void proc_dump_clock_config(struct snd_info_entry *entry, snd_iprintf(buffer, "Sync to clock source: %s\n", src); } -static void proc_dump_sync_status(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) { - struct snd_ff *ff = entry->private_data; __le32 reg; u32 data; int err; @@ -213,6 +209,15 @@ static void proc_dump_sync_status(struct snd_info_entry *entry, snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); } +static void proc_dump_status(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_ff *ff = entry->private_data; + + dump_clock_config(ff, buffer); + dump_sync_status(ff, buffer); +} + static void add_node(struct snd_ff *ff, struct snd_info_entry *root, const char *name, void (*op)(struct snd_info_entry *e, @@ -247,6 +252,5 @@ void snd_ff_proc_init(struct snd_ff *ff) return; } - add_node(ff, root, "clock-config", proc_dump_clock_config); - add_node(ff, root, "sync-status", proc_dump_sync_status); + add_node(ff, root, "status", proc_dump_status); } From e9e29cf8522093f146ab2c23194eee78dd84fa4e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:48 +0900 Subject: [PATCH 145/461] ALSA: fireface: add protocol-dependent operation to dump status This commit adds a member for a callback function to dump status and move existing code to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 204 +----------------- sound/firewire/fireface/ff-protocol-former.c | 212 +++++++++++++++++++ sound/firewire/fireface/ff.h | 2 +- 3 files changed, 214 insertions(+), 204 deletions(-) diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index 37f84b7fc432..8a7cfb6ccce6 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,214 +8,12 @@ #include "./ff.h" -static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) -{ - __le32 reg; - u32 data; - unsigned int rate; - const char *src; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); - if (err < 0) - return; - - data = le32_to_cpu(reg); - - snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", - (data & 0x20) ? "Professional" : "Consumer", - (data & 0x40) ? "on" : "off"); - - snd_iprintf(buffer, "Optical output interface format: %s\n", - ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); - - snd_iprintf(buffer, "Word output single speed: %s\n", - ((data >> 8) & 0x20) ? "on" : "off"); - - snd_iprintf(buffer, "S/PDIF input interface: %s\n", - ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); - - switch ((data >> 1) & 0x03) { - case 0x01: - rate = 32000; - break; - case 0x00: - rate = 44100; - break; - case 0x03: - rate = 48000; - break; - case 0x02: - default: - return; - } - - if (data & 0x08) - rate *= 2; - else if (data & 0x10) - rate *= 4; - - snd_iprintf(buffer, "Sampling rate: %d\n", rate); - - if (data & 0x01) { - src = "Internal"; - } else { - switch ((data >> 10) & 0x07) { - case 0x00: - src = "ADAT1"; - break; - case 0x01: - src = "ADAT2"; - break; - case 0x03: - src = "S/PDIF"; - break; - case 0x04: - src = "Word"; - break; - case 0x05: - src = "LTC"; - break; - default: - return; - } - } - - snd_iprintf(buffer, "Sync to clock source: %s\n", src); -} - -static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) -{ - __le32 reg; - u32 data; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - SND_FF_REG_SYNC_STATUS, ®, sizeof(reg), 0); - if (err < 0) - return; - - data = le32_to_cpu(reg); - - snd_iprintf(buffer, "External source detection:\n"); - - snd_iprintf(buffer, "Word Clock:"); - if ((data >> 24) & 0x20) { - if ((data >> 24) & 0x40) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "S/PDIF:"); - if ((data >> 16) & 0x10) { - if ((data >> 16) & 0x04) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT1:"); - if ((data >> 8) & 0x04) { - if ((data >> 8) & 0x10) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT2:"); - if ((data >> 8) & 0x08) { - if ((data >> 8) & 0x20) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "\nUsed external source:\n"); - - if (((data >> 22) & 0x07) == 0x07) { - snd_iprintf(buffer, "None\n"); - } else { - switch ((data >> 22) & 0x07) { - case 0x00: - snd_iprintf(buffer, "ADAT1:"); - break; - case 0x01: - snd_iprintf(buffer, "ADAT2:"); - break; - case 0x03: - snd_iprintf(buffer, "S/PDIF:"); - break; - case 0x04: - snd_iprintf(buffer, "Word:"); - break; - case 0x07: - snd_iprintf(buffer, "Nothing:"); - break; - case 0x02: - case 0x05: - case 0x06: - default: - snd_iprintf(buffer, "unknown:"); - break; - } - - if ((data >> 25) & 0x07) { - switch ((data >> 25) & 0x07) { - case 0x01: - snd_iprintf(buffer, "32000\n"); - break; - case 0x02: - snd_iprintf(buffer, "44100\n"); - break; - case 0x03: - snd_iprintf(buffer, "48000\n"); - break; - case 0x04: - snd_iprintf(buffer, "64000\n"); - break; - case 0x05: - snd_iprintf(buffer, "88200\n"); - break; - case 0x06: - snd_iprintf(buffer, "96000\n"); - break; - case 0x07: - snd_iprintf(buffer, "128000\n"); - break; - case 0x08: - snd_iprintf(buffer, "176400\n"); - break; - case 0x09: - snd_iprintf(buffer, "192000\n"); - break; - case 0x00: - snd_iprintf(buffer, "unknown\n"); - break; - } - } - } - - snd_iprintf(buffer, "Multiplied:"); - snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); -} - static void proc_dump_status(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_ff *ff = entry->private_data; - dump_clock_config(ff, buffer); - dump_sync_status(ff, buffer); + ff->spec->protocol->dump_status(ff, buffer); } static void add_node(struct snd_ff *ff, struct snd_info_entry *root, diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index ed1271a89484..5f97e7fc7281 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -9,6 +9,216 @@ #include "ff.h" +#define FORMER_REG_SYNC_STATUS 0x0000801c0000ull + +static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + __le32 reg; + u32 data; + unsigned int rate; + const char *src; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, + SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + if (err < 0) + return; + + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", + (data & 0x20) ? "Professional" : "Consumer", + (data & 0x40) ? "on" : "off"); + + snd_iprintf(buffer, "Optical output interface format: %s\n", + ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); + + snd_iprintf(buffer, "Word output single speed: %s\n", + ((data >> 8) & 0x20) ? "on" : "off"); + + snd_iprintf(buffer, "S/PDIF input interface: %s\n", + ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); + + switch ((data >> 1) & 0x03) { + case 0x01: + rate = 32000; + break; + case 0x00: + rate = 44100; + break; + case 0x03: + rate = 48000; + break; + case 0x02: + default: + return; + } + + if (data & 0x08) + rate *= 2; + else if (data & 0x10) + rate *= 4; + + snd_iprintf(buffer, "Sampling rate: %d\n", rate); + + if (data & 0x01) { + src = "Internal"; + } else { + switch ((data >> 10) & 0x07) { + case 0x00: + src = "ADAT1"; + break; + case 0x01: + src = "ADAT2"; + break; + case 0x03: + src = "S/PDIF"; + break; + case 0x04: + src = "Word"; + break; + case 0x05: + src = "LTC"; + break; + default: + return; + } + } + + snd_iprintf(buffer, "Sync to clock source: %s\n", src); +} + +static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + FORMER_REG_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return; + + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "External source detection:\n"); + + snd_iprintf(buffer, "Word Clock:"); + if ((data >> 24) & 0x20) { + if ((data >> 24) & 0x40) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "S/PDIF:"); + if ((data >> 16) & 0x10) { + if ((data >> 16) & 0x04) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "ADAT1:"); + if ((data >> 8) & 0x04) { + if ((data >> 8) & 0x10) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "ADAT2:"); + if ((data >> 8) & 0x08) { + if ((data >> 8) & 0x20) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "\nUsed external source:\n"); + + if (((data >> 22) & 0x07) == 0x07) { + snd_iprintf(buffer, "None\n"); + } else { + switch ((data >> 22) & 0x07) { + case 0x00: + snd_iprintf(buffer, "ADAT1:"); + break; + case 0x01: + snd_iprintf(buffer, "ADAT2:"); + break; + case 0x03: + snd_iprintf(buffer, "S/PDIF:"); + break; + case 0x04: + snd_iprintf(buffer, "Word:"); + break; + case 0x07: + snd_iprintf(buffer, "Nothing:"); + break; + case 0x02: + case 0x05: + case 0x06: + default: + snd_iprintf(buffer, "unknown:"); + break; + } + + if ((data >> 25) & 0x07) { + switch ((data >> 25) & 0x07) { + case 0x01: + snd_iprintf(buffer, "32000\n"); + break; + case 0x02: + snd_iprintf(buffer, "44100\n"); + break; + case 0x03: + snd_iprintf(buffer, "48000\n"); + break; + case 0x04: + snd_iprintf(buffer, "64000\n"); + break; + case 0x05: + snd_iprintf(buffer, "88200\n"); + break; + case 0x06: + snd_iprintf(buffer, "96000\n"); + break; + case 0x07: + snd_iprintf(buffer, "128000\n"); + break; + case 0x08: + snd_iprintf(buffer, "176400\n"); + break; + case 0x09: + snd_iprintf(buffer, "192000\n"); + break; + case 0x00: + snd_iprintf(buffer, "unknown\n"); + break; + } + } + } + + snd_iprintf(buffer, "Multiplied:"); + snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); +} + +static void former_dump_status(struct snd_ff *ff, + struct snd_info_buffer *buffer) +{ + dump_clock_config(ff, buffer); + dump_sync_status(ff, buffer); +} + #define FF800_STF 0x0000fc88f000 #define FF800_RX_PACKET_FORMAT 0x0000fc88f004 #define FF800_ALLOC_TX_STREAM 0x0000fc88f008 @@ -139,6 +349,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, + .dump_status = former_dump_status, }; #define FF400_STF 0x000080100500ull @@ -286,4 +497,5 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, + .dump_status = former_dump_status, }; diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 7dfc7745a914..3f22b8d84e36 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,7 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -#define SND_FF_REG_SYNC_STATUS 0x0000801c0000ull /* For block write request. */ #define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull @@ -111,6 +110,7 @@ struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); + void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer); }; extern const struct snd_ff_protocol snd_ff_protocol_ff800; From ae3053c28b86f4f9d4480f6d3ac27f43d8e657ef Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:49 +0900 Subject: [PATCH 146/461] ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame This commit adds a member for a callback function to switch frame fetching mode to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 38 ++++++++++++++++++++ sound/firewire/fireface/ff-stream.c | 38 ++------------------ sound/firewire/fireface/ff.h | 3 +- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 5f97e7fc7281..279bd032acf0 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -10,6 +10,42 @@ #include "ff.h" #define FORMER_REG_SYNC_STATUS 0x0000801c0000ull +/* For block write request. */ +#define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull + +static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) +{ + unsigned int count; + __le32 *reg; + int i; + int err; + + count = 0; + for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i) + count = max(count, ff->spec->pcm_playback_channels[i]); + + reg = kcalloc(count, sizeof(__le32), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + if (!enable) { + /* + * Each quadlet is corresponding to data channels in a data + * blocks in reverse order. Precisely, quadlets for available + * data channels should be enabled. Here, I take second best + * to fetch PCM frames from all of data channels regardless of + * stf. + */ + for (i = 0; i < count; ++i) + reg[i] = cpu_to_le32(0x00000001); + } + + err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST, + FORMER_REG_FETCH_PCM_FRAMES, reg, + sizeof(__le32) * count, 0); + kfree(reg); + return err; +} static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) { @@ -347,6 +383,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, + .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, .dump_status = former_dump_status, @@ -495,6 +532,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, .dump_status = former_dump_status, diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index a490e4553721..43e1e2679798 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -37,44 +37,10 @@ static void release_resources(struct snd_ff *ff) fw_iso_resources_free(&ff->rx_resources); } -static int switch_fetching_mode(struct snd_ff *ff, bool enable) -{ - unsigned int count; - __le32 *reg; - int i; - int err; - - count = 0; - for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i) - count = max(count, ff->spec->pcm_playback_channels[i]); - - reg = kcalloc(count, sizeof(__le32), GFP_KERNEL); - if (!reg) - return -ENOMEM; - - if (!enable) { - /* - * Each quadlet is corresponding to data channels in a data - * blocks in reverse order. Precisely, quadlets for available - * data channels should be enabled. Here, I take second best - * to fetch PCM frames from all of data channels regardless of - * stf. - */ - for (i = 0; i < count; ++i) - reg[i] = cpu_to_le32(0x00000001); - } - - err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST, - SND_FF_REG_FETCH_PCM_FRAMES, reg, - sizeof(__le32) * count, 0); - kfree(reg); - return err; -} - static inline void finish_session(struct snd_ff *ff) { ff->spec->protocol->finish_session(ff); - switch_fetching_mode(ff, false); + ff->spec->protocol->switch_fetching_mode(ff, false); } static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) @@ -206,7 +172,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) goto error; } - err = switch_fetching_mode(ff, true); + err = ff->spec->protocol->switch_fetching_mode(ff, true); if (err < 0) goto error; } diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 3f22b8d84e36..29f55518bf85 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,8 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -/* For block write request. */ -#define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull enum snd_ff_stream_mode { @@ -108,6 +106,7 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer); From b1d0cb0ae511c0558155c4d4cbb852c9e53bfb67 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:50 +0900 Subject: [PATCH 147/461] ALSA: fireface: add protocol-dependent operation to get clock status This commit adds a member for a callback function to get clock status to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-pcm.c | 2 +- sound/firewire/fireface/ff-protocol-former.c | 68 +++++++++++++++++++- sound/firewire/fireface/ff-stream.c | 2 +- sound/firewire/fireface/ff-transaction.c | 63 ------------------ sound/firewire/fireface/ff.h | 6 +- 5 files changed, 71 insertions(+), 70 deletions(-) diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index d0bc96b20a65..5adf04b95c04 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -152,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto release_lock; - err = snd_ff_transaction_get_clock(ff, &rate, &src); + err = ff->spec->protocol->get_clock(ff, &rate, &src); if (err < 0) goto release_lock; diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 279bd032acf0..d32104ed0c08 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -12,6 +12,70 @@ #define FORMER_REG_SYNC_STATUS 0x0000801c0000ull /* For block write request. */ #define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull +#define FORMER_REG_CLOCK_CONFIG 0x0000801c0004ull + +static int former_get_clock(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + if (err < 0) + return err; + data = le32_to_cpu(reg); + + /* Calculate sampling rate. */ + switch ((data >> 1) & 0x03) { + case 0x01: + *rate = 32000; + break; + case 0x00: + *rate = 44100; + break; + case 0x03: + *rate = 48000; + break; + case 0x02: + default: + return -EIO; + } + + if (data & 0x08) + *rate *= 2; + else if (data & 0x10) + *rate *= 4; + + /* Calculate source of clock. */ + if (data & 0x01) { + *src = SND_FF_CLOCK_SRC_INTERNAL; + } else { + /* TODO: 0x02, 0x06, 0x07? */ + switch ((data >> 10) & 0x07) { + case 0x00: + *src = SND_FF_CLOCK_SRC_ADAT1; + break; + case 0x01: + *src = SND_FF_CLOCK_SRC_ADAT2; + break; + case 0x03: + *src = SND_FF_CLOCK_SRC_SPDIF; + break; + case 0x04: + *src = SND_FF_CLOCK_SRC_WORD; + break; + case 0x05: + *src = SND_FF_CLOCK_SRC_LTC; + break; + default: + return -EIO; + } + } + + return 0; +} static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) { @@ -56,7 +120,7 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) int err; err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); if (err < 0) return; @@ -383,6 +447,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, + .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, @@ -532,6 +597,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 43e1e2679798..a8a90f1ae09e 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -113,7 +113,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) if (ff->substreams_counter == 0) return 0; - err = snd_ff_transaction_get_clock(ff, &curr_rate, &src); + err = ff->spec->protocol->get_clock(ff, &curr_rate, &src); if (err < 0) return err; if (curr_rate != rate || diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 5f4ddfd55403..065e045d3fb5 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -11,69 +11,6 @@ #define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull #define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull -int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate, - enum snd_ff_clock_src *src) -{ - __le32 reg; - u32 data; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); - if (err < 0) - return err; - data = le32_to_cpu(reg); - - /* Calculate sampling rate. */ - switch ((data >> 1) & 0x03) { - case 0x01: - *rate = 32000; - break; - case 0x00: - *rate = 44100; - break; - case 0x03: - *rate = 48000; - break; - case 0x02: - default: - return -EIO; - } - - if (data & 0x08) - *rate *= 2; - else if (data & 0x10) - *rate *= 4; - - /* Calculate source of clock. */ - if (data & 0x01) { - *src = SND_FF_CLOCK_SRC_INTERNAL; - } else { - /* TODO: 0x02, 0x06, 0x07? */ - switch ((data >> 10) & 0x07) { - case 0x00: - *src = SND_FF_CLOCK_SRC_ADAT1; - break; - case 0x01: - *src = SND_FF_CLOCK_SRC_ADAT2; - break; - case 0x03: - *src = SND_FF_CLOCK_SRC_SPDIF; - break; - case 0x04: - *src = SND_FF_CLOCK_SRC_WORD; - break; - case 0x05: - *src = SND_FF_CLOCK_SRC_LTC; - break; - default: - return -EIO; - } - } - - return 0; -} - static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, int rcode) { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 29f55518bf85..1de2f5ec26fd 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,8 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -#define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull - enum snd_ff_stream_mode { SND_FF_STREAM_MODE_LOW = 0, SND_FF_STREAM_MODE_MID, @@ -106,6 +104,8 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + int (*get_clock)(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); @@ -115,8 +115,6 @@ struct snd_ff_protocol { extern const struct snd_ff_protocol snd_ff_protocol_ff800; extern const struct snd_ff_protocol snd_ff_protocol_ff400; -int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate, - enum snd_ff_clock_src *src); int snd_ff_transaction_register(struct snd_ff *ff); int snd_ff_transaction_reregister(struct snd_ff *ff); void snd_ff_transaction_unregister(struct snd_ff *ff); From 22f745871408a58223e2f87e3d4e43d10229e61a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:51 +0900 Subject: [PATCH 148/461] ALSA: fireface: code refactoring for dump of sync status This commit adds refactoring for dump of sync status by adding tables for check bits. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 186 ++++++++----------- 1 file changed, 80 insertions(+), 106 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index d32104ed0c08..fb2af10d2690 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -190,126 +190,100 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) { - __le32 reg; - u32 data; + static const struct { + char *const label; + u32 locked_mask; + u32 synced_mask; + } *clk_entry, clk_entries[] = { + { "WDClk", 0x40000000, 0x20000000, }, + { "S/PDIF", 0x00080000, 0x00040000, }, + { "ADAT1", 0x00000400, 0x00001000, }, + { "ADAT2", 0x00000800, 0x00002000, }, + }; + static const struct { + char *const label; + u32 mask; + } *referred_entry, referred_entries[] = { + { "ADAT1", 0x00000000, }, + { "ADAT2", 0x00400000, }, + { "S/PDIF", 0x00c00000, }, + { "WDclk", 0x01000000, }, + { "TCO", 0x01400000, }, + }; + static const struct { + unsigned int rate; + u32 mask; + } *rate_entry, rate_entries[] = { + { 32000, 0x02000000, }, + { 44100, 0x04000000, }, + { 48000, 0x06000000, }, + { 64000, 0x08000000, }, + { 88200, 0x0a000000, }, + { 96000, 0x0c000000, }, + { 128000, 0x0e000000, }, + { 176400, 0x10000000, }, + { 192000, 0x12000000, }, + }; + __le32 reg[2]; + u32 data[2]; + int i; int err; - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - FORMER_REG_SYNC_STATUS, ®, sizeof(reg), 0); + err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, + FORMER_REG_SYNC_STATUS, reg, sizeof(reg), 0); if (err < 0) return; - - data = le32_to_cpu(reg); + data[0] = le32_to_cpu(reg[0]); + data[1] = le32_to_cpu(reg[1]); snd_iprintf(buffer, "External source detection:\n"); - snd_iprintf(buffer, "Word Clock:"); - if ((data >> 24) & 0x20) { - if ((data >> 24) & 0x40) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + const char *state; - snd_iprintf(buffer, "S/PDIF:"); - if ((data >> 16) & 0x10) { - if ((data >> 16) & 0x04) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT1:"); - if ((data >> 8) & 0x04) { - if ((data >> 8) & 0x10) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT2:"); - if ((data >> 8) & 0x08) { - if ((data >> 8) & 0x20) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "\nUsed external source:\n"); - - if (((data >> 22) & 0x07) == 0x07) { - snd_iprintf(buffer, "None\n"); - } else { - switch ((data >> 22) & 0x07) { - case 0x00: - snd_iprintf(buffer, "ADAT1:"); - break; - case 0x01: - snd_iprintf(buffer, "ADAT2:"); - break; - case 0x03: - snd_iprintf(buffer, "S/PDIF:"); - break; - case 0x04: - snd_iprintf(buffer, "Word:"); - break; - case 0x07: - snd_iprintf(buffer, "Nothing:"); - break; - case 0x02: - case 0x05: - case 0x06: - default: - snd_iprintf(buffer, "unknown:"); - break; + clk_entry = clk_entries + i; + if (data[0] & clk_entry->locked_mask) { + if (data[0] & clk_entry->synced_mask) + state = "sync"; + else + state = "lock"; + } else { + state = "none"; } - if ((data >> 25) & 0x07) { - switch ((data >> 25) & 0x07) { - case 0x01: - snd_iprintf(buffer, "32000\n"); - break; - case 0x02: - snd_iprintf(buffer, "44100\n"); - break; - case 0x03: - snd_iprintf(buffer, "48000\n"); - break; - case 0x04: - snd_iprintf(buffer, "64000\n"); - break; - case 0x05: - snd_iprintf(buffer, "88200\n"); - break; - case 0x06: - snd_iprintf(buffer, "96000\n"); - break; - case 0x07: - snd_iprintf(buffer, "128000\n"); - break; - case 0x08: - snd_iprintf(buffer, "176400\n"); - break; - case 0x09: - snd_iprintf(buffer, "192000\n"); - break; - case 0x00: - snd_iprintf(buffer, "unknown\n"); + snd_iprintf(buffer, "%s: %s\n", clk_entry->label, state); + } + + snd_iprintf(buffer, "Referred clock:\n"); + + if (data[1] & 0x00000001) { + snd_iprintf(buffer, "Internal\n"); + } else { + unsigned int rate; + const char *label; + + for (i = 0; i < ARRAY_SIZE(referred_entries); ++i) { + referred_entry = referred_entries + i; + if ((data[0] & 0x1e0000) == referred_entry->mask) { + label = referred_entry->label; break; } } - } + if (i == ARRAY_SIZE(referred_entries)) + label = "none"; - snd_iprintf(buffer, "Multiplied:"); - snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data[0] & 0x1e000000) == rate_entry->mask) { + rate = rate_entry->rate; + break; + } + } + if (i == ARRAY_SIZE(rate_entries)) + rate = 0; + + snd_iprintf(buffer, "%s %d\n", label, rate); + } } static void former_dump_status(struct snd_ff *ff, From 4c4871a8055a1ff95fbd415d426d7e1d4b763edb Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:52 +0900 Subject: [PATCH 149/461] ALSA: fireface: code refactoring to parse of clock configuration A procedure to retrieve clock configuration is used by two callers. Each of caller has duplicated code to parse bits. This commit adds refactoring to remove the duplicated code. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 17 ++ sound/firewire/fireface/ff-protocol-former.c | 170 ++++++++----------- sound/firewire/fireface/ff.h | 1 + 3 files changed, 88 insertions(+), 100 deletions(-) diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index 8a7cfb6ccce6..a55e68ec1832 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,6 +8,23 @@ #include "./ff.h" +const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src) +{ + static const char *const labels[] = { + "Internal", + "S/PDIF", + "ADAT1", + "ADAT2", + "Word", + "LTC", + }; + + if (src >= ARRAY_SIZE(labels)) + return NULL; + + return labels[src]; +} + static void proc_dump_status(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index fb2af10d2690..9c0ae50e88d1 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -14,6 +14,62 @@ #define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define FORMER_REG_CLOCK_CONFIG 0x0000801c0004ull +static int parse_clock_bits(u32 data, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + static const struct { + unsigned int rate; + u32 mask; + } *rate_entry, rate_entries[] = { + { 32000, 0x00000002, }, + { 44100, 0x00000000, }, + { 48000, 0x00000006, }, + { 64000, 0x0000000a, }, + { 88200, 0x00000008, }, + { 96000, 0x0000000e, }, + { 128000, 0x00000012, }, + { 176400, 0x00000010, }, + { 192000, 0x00000016, }, + }; + static const struct { + enum snd_ff_clock_src src; + u32 mask; + } *clk_entry, clk_entries[] = { + { SND_FF_CLOCK_SRC_ADAT1, 0x00000000, }, + { SND_FF_CLOCK_SRC_ADAT2, 0x00000400, }, + { SND_FF_CLOCK_SRC_SPDIF, 0x00000c00, }, + { SND_FF_CLOCK_SRC_WORD, 0x00001000, }, + { SND_FF_CLOCK_SRC_LTC, 0x00001800, }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data & 0x0000001e) == rate_entry->mask) { + *rate = rate_entry->rate; + break; + } + } + if (i == ARRAY_SIZE(rate_entries)) + return -EIO; + + if (data & 0x00000001) { + *src = SND_FF_CLOCK_SRC_INTERNAL; + } else { + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + if ((data & 0x00001c00) == clk_entry->mask) { + *src = clk_entry->src; + break; + } + } + if (i == ARRAY_SIZE(clk_entries)) + return -EIO; + } + + return 0; +} + static int former_get_clock(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src) { @@ -27,54 +83,7 @@ static int former_get_clock(struct snd_ff *ff, unsigned int *rate, return err; data = le32_to_cpu(reg); - /* Calculate sampling rate. */ - switch ((data >> 1) & 0x03) { - case 0x01: - *rate = 32000; - break; - case 0x00: - *rate = 44100; - break; - case 0x03: - *rate = 48000; - break; - case 0x02: - default: - return -EIO; - } - - if (data & 0x08) - *rate *= 2; - else if (data & 0x10) - *rate *= 4; - - /* Calculate source of clock. */ - if (data & 0x01) { - *src = SND_FF_CLOCK_SRC_INTERNAL; - } else { - /* TODO: 0x02, 0x06, 0x07? */ - switch ((data >> 10) & 0x07) { - case 0x00: - *src = SND_FF_CLOCK_SRC_ADAT1; - break; - case 0x01: - *src = SND_FF_CLOCK_SRC_ADAT2; - break; - case 0x03: - *src = SND_FF_CLOCK_SRC_SPDIF; - break; - case 0x04: - *src = SND_FF_CLOCK_SRC_WORD; - break; - case 0x05: - *src = SND_FF_CLOCK_SRC_LTC; - break; - default: - return -EIO; - } - } - - return 0; + return parse_clock_bits(data, rate, src); } static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) @@ -116,76 +125,37 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) __le32 reg; u32 data; unsigned int rate; - const char *src; + enum snd_ff_clock_src src; + const char *label; int err; err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); if (err < 0) return; - data = le32_to_cpu(reg); snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", - (data & 0x20) ? "Professional" : "Consumer", - (data & 0x40) ? "on" : "off"); + (data & 0x00000020) ? "Professional" : "Consumer", + (data & 0x00000040) ? "on" : "off"); snd_iprintf(buffer, "Optical output interface format: %s\n", - ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); + (data & 0x00000100) ? "S/PDIF" : "ADAT"); snd_iprintf(buffer, "Word output single speed: %s\n", - ((data >> 8) & 0x20) ? "on" : "off"); + (data & 0x00002000) ? "on" : "off"); snd_iprintf(buffer, "S/PDIF input interface: %s\n", - ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); + (data & 0x00000200) ? "Optical" : "Coaxial"); - switch ((data >> 1) & 0x03) { - case 0x01: - rate = 32000; - break; - case 0x00: - rate = 44100; - break; - case 0x03: - rate = 48000; - break; - case 0x02: - default: + err = parse_clock_bits(data, &rate, &src); + if (err < 0) + return; + label = snd_ff_proc_get_clk_label(src); + if (!label) return; - } - if (data & 0x08) - rate *= 2; - else if (data & 0x10) - rate *= 4; - - snd_iprintf(buffer, "Sampling rate: %d\n", rate); - - if (data & 0x01) { - src = "Internal"; - } else { - switch ((data >> 10) & 0x07) { - case 0x00: - src = "ADAT1"; - break; - case 0x01: - src = "ADAT2"; - break; - case 0x03: - src = "S/PDIF"; - break; - case 0x04: - src = "Word"; - break; - case 0x05: - src = "LTC"; - break; - default: - return; - } - } - - snd_iprintf(buffer, "Sync to clock source: %s\n", src); + snd_iprintf(buffer, "Clock configuration: %d %s\n", rate, label); } static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 1de2f5ec26fd..cdb16e931c31 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -139,6 +139,7 @@ int snd_ff_stream_lock_try(struct snd_ff *ff); void snd_ff_stream_lock_release(struct snd_ff *ff); void snd_ff_proc_init(struct snd_ff *ff); +const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src); int snd_ff_create_midi_devices(struct snd_ff *ff); From fd1cc9de64c2ca6c2b5b9061421580a22bfac023 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:53 +0900 Subject: [PATCH 150/461] ALSA: fireface: add support for Fireface UCX Fireface UFX was shipped by RME GmbH in 2012. This model supports later protocol for management of isochronous communication and synchronization of sampling transmission frequency. This commit adds support for the model. At present, it's not clear how to encode MIDI messages and decide destination address for asynchronous transaction, thus this commit adds support for isochronous communication for PCM frames only. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 1 + sound/firewire/fireface/Makefile | 3 +- sound/firewire/fireface/ff-protocol-latter.c | 273 +++++++++++++++++++ sound/firewire/fireface/ff.c | 41 ++- sound/firewire/fireface/ff.h | 1 + 5 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 sound/firewire/fireface/ff-protocol-latter.c diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 052e00590259..b9e96d0b3a0a 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -163,5 +163,6 @@ config SND_FIREFACE Say Y here to include support for RME fireface series. * Fireface 400 * Fireface 800 + * Fireface UCX endif # SND_FIREWIRE diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 62eb78962b93..d64f4e2a1096 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,3 +1,4 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ - ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o + ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o \ + ff-protocol-latter.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c new file mode 100644 index 000000000000..64767ba439db --- /dev/null +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +// ff-protocol-latter - a part of driver for RME Fireface series +// +// Copyright (c) 2019 Takashi Sakamoto +// +// Licensed under the terms of the GNU General Public License, version 2. + +#include + +#include "ff.h" + +#define LATTER_STF 0xffff00000004 +#define LATTER_ISOC_CHANNELS 0xffff00000008 +#define LATTER_ISOC_START 0xffff0000000c +#define LATTER_FETCH_MODE 0xffff00000010 +#define LATTER_SYNC_STATUS 0x0000801c0000 + +static int parse_clock_bits(u32 data, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + static const struct { + unsigned int rate; + u32 flag; + } *rate_entry, rate_entries[] = { + { 32000, 0x00000000, }, + { 44100, 0x01000000, }, + { 48000, 0x02000000, }, + { 64000, 0x04000000, }, + { 88200, 0x05000000, }, + { 96000, 0x06000000, }, + { 128000, 0x08000000, }, + { 176400, 0x09000000, }, + { 192000, 0x0a000000, }, + }; + static const struct { + enum snd_ff_clock_src src; + u32 flag; + } *clk_entry, clk_entries[] = { + { SND_FF_CLOCK_SRC_SPDIF, 0x00000200, }, + { SND_FF_CLOCK_SRC_ADAT1, 0x00000400, }, + { SND_FF_CLOCK_SRC_WORD, 0x00000600, }, + { SND_FF_CLOCK_SRC_INTERNAL, 0x00000e00, }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data & 0x0f000000) == rate_entry->flag) { + *rate = rate_entry->rate; + break; + } + } + if (i == ARRAY_SIZE(rate_entries)) + return -EIO; + + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + if ((data & 0x000e00) == clk_entry->flag) { + *src = clk_entry->src; + break; + } + } + if (i == ARRAY_SIZE(clk_entries)) + return -EIO; + + return 0; +} + +static int latter_get_clock(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + LATTER_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return err; + data = le32_to_cpu(reg); + + return parse_clock_bits(data, rate, src); +} + +static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable) +{ + u32 data; + __le32 reg; + + if (enable) + data = 0x00000000; + else + data = 0xffffffff; + reg = cpu_to_le32(data); + + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_FETCH_MODE, ®, sizeof(reg), 0); +} + +static int keep_resources(struct snd_ff *ff, unsigned int rate) +{ + enum snd_ff_stream_mode mode; + int i; + int err; + + // Check whether the given value is supported or not. + for (i = 0; i < CIP_SFC_COUNT; i++) { + if (amdtp_rate_table[i] == rate) + break; + } + if (i >= CIP_SFC_COUNT) + return -EINVAL; + + err = snd_ff_stream_get_multiplier_mode(i, &mode); + if (err < 0) + return err; + + /* Keep resources for in-stream. */ + ff->tx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->tx_resources, + amdtp_stream_get_max_payload(&ff->tx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + return err; + + /* Keep resources for out-stream. */ + ff->rx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->rx_resources, + amdtp_stream_get_max_payload(&ff->rx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + fw_iso_resources_free(&ff->tx_resources); + + return err; +} + +static int latter_begin_session(struct snd_ff *ff, unsigned int rate) +{ + static const struct { + unsigned int stf; + unsigned int code; + unsigned int flag; + } *entry, rate_table[] = { + { 32000, 0x00, 0x92, }, + { 44100, 0x02, 0x92, }, + { 48000, 0x04, 0x92, }, + { 64000, 0x08, 0x8e, }, + { 88200, 0x0a, 0x8e, }, + { 96000, 0x0c, 0x8e, }, + { 128000, 0x10, 0x8c, }, + { 176400, 0x12, 0x8c, }, + { 192000, 0x14, 0x8c, }, + }; + u32 data; + __le32 reg; + unsigned int count; + int i; + int err; + + for (i = 0; i < ARRAY_SIZE(rate_table); ++i) { + entry = rate_table + i; + if (entry->stf == rate) + break; + } + if (i == ARRAY_SIZE(rate_table)) + return -EINVAL; + + reg = cpu_to_le32(entry->code); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Confirm to shift transmission clock. + count = 0; + while (count++ < 10) { + unsigned int curr_rate; + enum snd_ff_clock_src src; + + err = latter_get_clock(ff, &curr_rate, &src); + if (err < 0) + return err; + + if (curr_rate == rate) + break; + } + if (count == 10) + return -ETIMEDOUT; + + err = keep_resources(ff, rate); + if (err < 0) + return err; + + data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel; + reg = cpu_to_le32(data); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_CHANNELS, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Always use the maximum number of data channels in data block of + // packet. + reg = cpu_to_le32(entry->flag); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_START, ®, sizeof(reg), 0); +} + +static void latter_finish_session(struct snd_ff *ff) +{ + __le32 reg; + + reg = cpu_to_le32(0x00000000); + snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_START, ®, sizeof(reg), 0); +} + +static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + static const struct { + char *const label; + u32 locked_mask; + u32 synced_mask; + } *clk_entry, clk_entries[] = { + { "S/PDIF", 0x00000001, 0x00000010, }, + { "ADAT", 0x00000002, 0x00000020, }, + { "WDClk", 0x00000004, 0x00000040, }, + }; + __le32 reg; + u32 data; + unsigned int rate; + enum snd_ff_clock_src src; + const char *label; + int i; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + LATTER_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return; + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "External source detection:\n"); + + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + snd_iprintf(buffer, "%s: ", clk_entry->label); + if (data & clk_entry->locked_mask) { + if (data & clk_entry->synced_mask) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + } + + err = parse_clock_bits(data, &rate, &src); + if (err < 0) + return; + label = snd_ff_proc_get_clk_label(src); + if (!label) + return; + + snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate); +} + +const struct snd_ff_protocol snd_ff_protocol_latter = { + .get_clock = latter_get_clock, + .switch_fetching_mode = latter_switch_fetching_mode, + .begin_session = latter_begin_session, + .finish_session = latter_finish_session, + .dump_status = latter_dump_status, +}; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 36575f4159d1..fd9c980e3cf4 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,7 +32,8 @@ static void ff_card_free(struct snd_card *card) struct snd_ff *ff = card->private_data; snd_ff_stream_destroy_duplex(ff); - snd_ff_transaction_unregister(ff); + if (ff->spec->midi_high_addr > 0) + snd_ff_transaction_unregister(ff); } static void do_registration(struct work_struct *work) @@ -50,9 +51,11 @@ static void do_registration(struct work_struct *work) ff->card->private_free = ff_card_free; ff->card->private_data = ff; - err = snd_ff_transaction_register(ff); - if (err < 0) - goto error; + if (ff->spec->midi_high_addr > 0) { + err = snd_ff_transaction_register(ff); + if (err < 0) + goto error; + } name_card(ff); @@ -62,9 +65,11 @@ static void do_registration(struct work_struct *work) snd_ff_proc_init(ff); - err = snd_ff_create_midi_devices(ff); - if (err < 0) - goto error; + if (ff->spec->midi_in_ports > 0 || ff->spec->midi_out_ports > 0) { + err = snd_ff_create_midi_devices(ff); + if (err < 0) + goto error; + } err = snd_ff_create_pcm_devices(ff); if (err < 0) @@ -119,7 +124,8 @@ static void snd_ff_update(struct fw_unit *unit) if (!ff->registered) snd_fw_schedule_registration(unit, &ff->dwork); - snd_ff_transaction_reregister(ff); + if (ff->spec->midi_high_addr > 0) + snd_ff_transaction_reregister(ff); if (ff->registered) snd_ff_stream_update_duplex(ff); @@ -165,6 +171,13 @@ static const struct snd_ff_spec spec_ff400 = { .midi_high_addr = 0x0000801003f4ull, }; +static const struct snd_ff_spec spec_ucx = { + .name = "FirefaceUCX", + .pcm_capture_channels = {18, 14, 12}, + .pcm_playback_channels = {18, 14, 12}, + .protocol = &snd_ff_protocol_latter, +}; + static const struct ieee1394_device_id snd_ff_id_table[] = { /* Fireface 800 */ { @@ -190,6 +203,18 @@ static const struct ieee1394_device_id snd_ff_id_table[] = { .model_id = 0x101800, .driver_data = (kernel_ulong_t)&spec_ff400, }, + // Fireface UCX. + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_RME, + .specifier_id = OUI_RME, + .version = 0x000004, + .model_id = 0x101800, + .driver_data = (kernel_ulong_t)&spec_ucx, + }, {} }; MODULE_DEVICE_TABLE(ieee1394, snd_ff_id_table); diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index cdb16e931c31..8aea7920b57f 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -114,6 +114,7 @@ struct snd_ff_protocol { extern const struct snd_ff_protocol snd_ff_protocol_ff800; extern const struct snd_ff_protocol snd_ff_protocol_ff400; +extern const struct snd_ff_protocol snd_ff_protocol_latter; int snd_ff_transaction_register(struct snd_ff *ff); int snd_ff_transaction_reregister(struct snd_ff *ff); From d819fb21eecc70972c4a3681f2542e1ddcc1ca13 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:25:42 +0100 Subject: [PATCH 151/461] ALSA: pcm: Call snd_card_unref() inside in_pcm_file() The snd_card_unref() call in snd_pcm_link() looks suspicious through a quick glance, but it's a correct usage; this is needed just because the file descriptor check in is_pcm_file() calls the helper snd_lookup_minor_data() that keeps the card refcount. Despite of the correctness, the code still looks confusing. Basically, keeping the card ref for the whole code isn't needed as fdget() blocks the release of the opened file. Hence it's more understandable if snd_card_unref() is moved into is_pcm_file(), then the caller doesn't have to take care after the call. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 818dff1de545..c72dfd1fc1ed 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1935,13 +1935,19 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) static bool is_pcm_file(struct file *file) { struct inode *inode = file_inode(file); + struct snd_pcm *pcm; unsigned int minor; if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major) return false; minor = iminor(inode); - return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) || - snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK); + if (!pcm) + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); + if (!pcm) + return false; + snd_card_unref(pcm->card); + return true; } /* @@ -1996,7 +2002,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: - snd_card_unref(substream1->pcm->card); kfree(group); _badf: fdput(f); From 73365cb10b280e539bad14e129e0d8434418bb79 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:35:17 +0100 Subject: [PATCH 152/461] ALSA: pcm: Unify snd_pcm_group initialization There are multiple open codes that initialize the same object. Create a common helper function instead. Also, use kzalloc() to be safer at creating a group object, and move the initialization out of the critical section. Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 4 +--- sound/core/pcm_local.h | 1 + sound/core/pcm_native.c | 13 +++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 01b9d62eef14..88a2998f4f9b 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -753,9 +753,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) } } substream->group = &substream->self_group; - spin_lock_init(&substream->self_group.lock); - mutex_init(&substream->self_group.mutex); - INIT_LIST_HEAD(&substream->self_group.substreams); + snd_pcm_group_init(&substream->self_group); list_add_tail(&substream->link_list, &substream->self_group.substreams); atomic_set(&substream->mmap_count, 0); prev = substream; diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index c515612969a4..0b4b5dfaec18 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -66,5 +66,6 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} #endif void __snd_pcm_xrun(struct snd_pcm_substream *substream); +void snd_pcm_group_init(struct snd_pcm_group *group); #endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c72dfd1fc1ed..9e4e289e5703 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -100,6 +100,13 @@ static inline void down_write_nonfifo(struct rw_semaphore *lock) msleep(1); } +void snd_pcm_group_init(struct snd_pcm_group *group) +{ + spin_lock_init(&group->lock); + mutex_init(&group->mutex); + INIT_LIST_HEAD(&group->substreams); +} + #define PCM_LOCK_DEFAULT 0 #define PCM_LOCK_IRQ 1 #define PCM_LOCK_IRQSAVE 2 @@ -1969,11 +1976,12 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) } pcm_file = f.file->private_data; substream1 = pcm_file->substream; - group = kmalloc(sizeof(*group), GFP_KERNEL); + group = kzalloc(sizeof(*group), GFP_KERNEL); if (!group) { res = -ENOMEM; goto _nolock; } + snd_pcm_group_init(group); down_write_nonfifo(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || @@ -1989,9 +1997,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) if (!snd_pcm_stream_linked(substream)) { substream->group = group; group = NULL; - spin_lock_init(&substream->group->lock); - mutex_init(&substream->group->mutex); - INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); substream->group->count = 1; } From a41c4cb913b53bf74f1ec66a4b96057626c87009 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:40:21 +0100 Subject: [PATCH 153/461] ALSA: pcm: Make PCM linked list consistent while re-grouping Make a common helper to re-assign the PCM link using list_move() instead of open code with manual list_del() and list_add_tail(). This assures the consistency and we can get rid of snd_pcm_group.count field -- its purpose is only to check whether the list is singular, and we can know it by list_is_singular() call now. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 - sound/core/pcm_native.c | 34 ++++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d6bd3caf6878..e1c747c70883 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -439,7 +439,6 @@ struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; struct mutex mutex; struct list_head substreams; - int count; }; struct pid; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9e4e289e5703..1a56bb1ad780 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1131,6 +1131,13 @@ static int snd_pcm_action_single(const struct action_ops *ops, return res; } +static void snd_pcm_group_assign(struct snd_pcm_substream *substream, + struct snd_pcm_group *new_group) +{ + substream->group = new_group; + list_move(&substream->link_list, &new_group->substreams); +} + /* * Note: call with stream lock */ @@ -1995,14 +2002,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _end; } if (!snd_pcm_stream_linked(substream)) { - substream->group = group; + snd_pcm_group_assign(substream, group); group = NULL; - list_add_tail(&substream->link_list, &substream->group->substreams); - substream->group->count = 1; } - list_add_tail(&substream1->link_list, &substream->group->substreams); - substream->group->count++; - substream1->group = substream->group; + snd_pcm_group_assign(substream1, substream->group); _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); @@ -2015,14 +2018,13 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) static void relink_to_local(struct snd_pcm_substream *substream) { - substream->group = &substream->self_group; - INIT_LIST_HEAD(&substream->self_group.substreams); - list_add_tail(&substream->link_list, &substream->self_group.substreams); + snd_pcm_group_assign(substream, &substream->self_group); } static int snd_pcm_unlink(struct snd_pcm_substream *substream) { struct snd_pcm_substream *s; + struct snd_pcm_group *group; int res = 0; down_write_nonfifo(&snd_pcm_link_rwsem); @@ -2031,16 +2033,20 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) res = -EALREADY; goto _end; } - list_del(&substream->link_list); - substream->group->count--; - if (substream->group->count == 1) { /* detach the last stream, too */ + + group = substream->group; + + relink_to_local(substream); + + /* detach the last stream, too */ + if (list_is_singular(&group->substreams)) { snd_pcm_group_for_each_entry(s, substream) { relink_to_local(s); break; } - kfree(substream->group); + kfree(group); } - relink_to_local(substream); + _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); From 7df5a5f66b8fc2cd51649b3f1b0b88dc59c49d2d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 10:19:32 +0100 Subject: [PATCH 154/461] ALSA: pcm: Avoid confusing loop in snd_pcm_unlink() The snd_pcm_group_for_each_entry() loop found in snd_pcm_unlink() is only for taking the first list entry. Use list_first_entry() to make clearer. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1a56bb1ad780..fb45386270d5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2023,7 +2023,6 @@ static void relink_to_local(struct snd_pcm_substream *substream) static int snd_pcm_unlink(struct snd_pcm_substream *substream) { - struct snd_pcm_substream *s; struct snd_pcm_group *group; int res = 0; @@ -2040,10 +2039,9 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) /* detach the last stream, too */ if (list_is_singular(&group->substreams)) { - snd_pcm_group_for_each_entry(s, substream) { - relink_to_local(s); - break; - } + relink_to_local(list_first_entry(&group->substreams, + struct snd_pcm_substream, + link_list)); kfree(group); } From 910fdcabedd2354d161b1beab6ad7dc7e859651d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:32 +0900 Subject: [PATCH 155/461] ASoC: soc-core: add .num_platform for dai_link Current snd_soc_dai_link is starting to use snd_soc_dai_link_component (= modern) style for Platform, but it is still assuming single Platform so far. We will need to have multi Platform support in the not far future. Currently only simple card is using it as sound card driver, and other drivers are converted to it from legacy style by snd_soc_init_platform(). To avoid future problem of multi Platform support, let's add num_platforms before it is too late. In the same time, to make it same naming mothed, "platform" should be "platforms". This patch fixup it too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- include/sound/soc.h | 3 ++- sound/soc/generic/audio-graph-card.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 4 ++-- sound/soc/generic/simple-card.c | 7 ++++--- sound/soc/soc-core.c | 23 ++++++++++++++++------- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 6d69ed2bd7b1..ab5a2ba09c07 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, dai_link->platform, \ + asoc_simple_card_parse_dai(node, dai_link->platforms, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/include/sound/soc.h b/include/sound/soc.h index c31b6d122ff6..3089257ead95 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -961,7 +961,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; - struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link_component *platforms; + unsigned int num_platforms; int id; /* optional ID for machine driver link identification */ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3ec96cdc683b..42b077c6be4c 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,7 +26,7 @@ struct graph_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -687,7 +687,8 @@ static int graph_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 336895f7fd1e..3c0901df5796 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -397,8 +397,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; + if (!dai_link->platforms->of_node) + dai_link->platforms->of_node = dai_link->cpu_of_node; return 0; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 479de236e694..d8a0d1ec256e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,7 +21,7 @@ struct simple_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -732,7 +732,8 @@ static int simple_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; @@ -782,7 +783,7 @@ static int simple_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; - platform = dai_link->platform; + platform = dai_link->platforms; platform->name = cinfo->platform; card->name = (cinfo->card) ? cinfo->card : cinfo->name; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index de2851f1b3df..2c63921675d5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -915,7 +915,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ for_each_component(component) { - if (!snd_soc_is_matching_component(dai_link->platform, + if (!snd_soc_is_matching_component(dai_link->platforms, component)) continue; @@ -1026,7 +1026,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *platform = dai_link->platform; + struct snd_soc_dai_link_component *platform = dai_link->platforms; /* * REMOVE ME @@ -1046,7 +1046,8 @@ static int snd_soc_init_platform(struct snd_soc_card *card, if (!platform) return -ENOMEM; - dai_link->platform = platform; + dai_link->platforms = platform; + dai_link->num_platforms = 1; dai_link->legacy_platform = 1; platform->name = dai_link->platform_name; platform->of_node = dai_link->platform_of_node; @@ -1136,11 +1137,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, } } + /* FIXME */ + if (link->num_platforms > 1) { + dev_err(card->dev, + "ASoC: multi platform is not yet supported %s\n", + link->name); + return -EINVAL; + } + /* * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform->name && link->platform->of_node) { + if (link->platforms->name && link->platforms->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); @@ -1151,8 +1160,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if platform dai component is not added to * component list. */ - if ((link->platform->of_node || link->platform->name) && - !soc_find_component(link->platform->of_node, link->platform->name)) + if ((link->platforms->of_node || link->platforms->name) && + !soc_find_component(link->platforms->of_node, link->platforms->name)) return -EPROBE_DEFER; /* @@ -1956,7 +1965,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dev_err(card->dev, "init platform error"); continue; } - dai_link->platform->name = component->name; + dai_link->platforms->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; From 65462e445f78cb2f9378443be7ba8b7e07300694 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:37 +0900 Subject: [PATCH 156/461] ASoC: soc-core: add new snd_soc_flush_all_delayed_work() soc-core is calling flush_delayed_work() many times for same purpose. Same code in many places makes code un-understandable. This patch adds new snd_soc_flush_all_delayed_work() for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c63921675d5..eeb794d8a262 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -425,6 +425,14 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); +static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + for_each_card_rtds(card, rtd) + flush_delayed_work(&rtd->delayed_work); +} + static void codec2codec_close_delayed_work(struct work_struct *work) { /* @@ -494,8 +502,7 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); for_each_card_rtds(card, rtd) { @@ -2228,11 +2235,8 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd; - /* make sure any delayed work runs */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); @@ -2275,8 +2279,7 @@ int snd_soc_poweroff(struct device *dev) * Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); snd_soc_dapm_shutdown(card); From 53e947a0e1f770b9707febb7054b856878945d50 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:42 +0900 Subject: [PATCH 157/461] ASoC: soc-core: merge card resources cleanup method We need to cleanup card resources when snd_soc_instantiate_card() was failed, or when snd_soc_unbind_card() was called. But they are cleanuping card resources on each way. Same code in many places makes code un-understandable. This patch reuses soc_cleanup_card_resources() for cleanuping code resource. Then, it makes avoiding cleanup order. It will be called from snd_soc_instantiate_card() and snd_soc_unbind_card(). Then, original soc_cleanup_card_resources() included snd_soc_flush_all_delayed_work(), but it is now separated. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 103 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeb794d8a262..d59b5ea9fa25 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2008,6 +2008,29 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) } } +static int soc_cleanup_card_resources(struct snd_soc_card *card) +{ + /* free the ALSA card at first; this syncs with pending operations */ + if (card->snd_card) + snd_card_free(card->snd_card); + + /* remove and free each DAI */ + soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); + + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + + snd_soc_dapm_free(&card->dapm); + soc_cleanup_card_debugfs(card); + + /* remove the card */ + if (card->remove) + card->remove(card); + + return 0; +} + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2017,6 +2040,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); + card->dapm.bias_level = SND_SOC_BIAS_OFF; + card->dapm.dev = card->dev; + card->dapm.card = card; + list_add(&card->dapm.list, &card->dapm_list); + /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); @@ -2024,14 +2052,14 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for_each_card_prelinks(card, i, dai_link) { ret = soc_bind_dai_link(card, dai_link); if (ret != 0) - goto base_error; + goto probe_end; } /* bind aux_devs too */ for (i = 0; i < card->num_aux_devs; i++) { ret = soc_bind_aux_dev(card, i); if (ret != 0) - goto base_error; + goto probe_end; } /* add predefined DAI links to the list */ @@ -2045,16 +2073,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: can't create sound card for card %s: %d\n", card->name, ret); - goto base_error; + goto probe_end; } soc_init_card_debugfs(card); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); - #ifdef CONFIG_DEBUG_FS snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); #endif @@ -2076,7 +2099,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->probe) { ret = card->probe(card); if (ret < 0) - goto card_probe_error; + goto probe_end; } /* probe all components used by DAI links on this card */ @@ -2087,7 +2110,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2095,7 +2118,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe auxiliary components */ ret = soc_probe_aux_devices(card); if (ret < 0) - goto probe_dai_err; + goto probe_end; /* * Find new DAI links added during probing components and bind them. @@ -2107,10 +2130,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; ret = soc_bind_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; } /* probe all DAI links on this card */ @@ -2121,7 +2144,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2168,7 +2191,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); - goto probe_aux_dev_err; + goto probe_end; } } @@ -2178,33 +2201,17 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: failed to register soundcard %d\n", ret); - goto probe_aux_dev_err; + goto probe_end; } card->instantiated = 1; dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&card->mutex); - mutex_unlock(&client_mutex); - return 0; +probe_end: + if (ret < 0) + soc_cleanup_card_resources(card); -probe_aux_dev_err: - soc_remove_aux_devices(card); - -probe_dai_err: - soc_remove_dai_links(card); - -card_probe_error: - if (card->remove) - card->remove(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - snd_card_free(card->snd_card); - -base_error: - soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -2233,31 +2240,6 @@ static int soc_probe(struct platform_device *pdev) return snd_soc_register_card(card); } -static int soc_cleanup_card_resources(struct snd_soc_card *card) -{ - /* make sure any delayed work runs */ - snd_soc_flush_all_delayed_work(card); - - /* free the ALSA card at first; this syncs with pending operations */ - snd_card_free(card->snd_card); - - /* remove and free each DAI */ - soc_remove_dai_links(card); - soc_remove_pcm_runtimes(card); - - /* remove auxiliary devices */ - soc_remove_aux_devices(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - - /* remove the card */ - if (card->remove) - card->remove(card); - - return 0; -} - /* removes a socdev */ static int soc_remove(struct platform_device *pdev) { @@ -2823,6 +2805,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); + snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From 52293596f5afff10d14e033aa3edfc801a31b3a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:50 +0900 Subject: [PATCH 158/461] ASoC: soc-core: reduce if/else nest on soc_probe_link_dais Deep nested codec is not readable. Let's reduce if/else nest. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d59b5ea9fa25..7fc10a41e0e9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1612,27 +1612,24 @@ static int soc_probe_link_dais(struct snd_soc_card *card, dai_link->stream_name); return ret; } - } else { - - if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + } else if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; + } else { + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); } return 0; From 22d1423187e5b4d9d5a9851f24466fc0f585a36f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:55 +0900 Subject: [PATCH 159/461] ASoC: soc-core: add soc_cleanup_component() We need to cleanup component when soc_probe_component() was failed, or when soc_remove_component() was called. But they are cleanuping component on each way. (And soc_probe_component() doesn't call snd_soc_dapm_free(), but it should). Same code in many places makes code un-understandable. This patch adds new soc_cleanup_component() and call it from snd_probe_component() and snd_remove_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7fc10a41e0e9..8a58fa86675a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -937,21 +937,24 @@ _err_defer: return -EPROBE_DEFER; } +static void soc_cleanup_component(struct snd_soc_component *component) +{ + list_del(&component->card_list); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); + soc_cleanup_component_debugfs(component); + component->card = NULL; + module_put(component->dev->driver->owner); +} + static void soc_remove_component(struct snd_soc_component *component) { if (!component->card) return; - list_del(&component->card_list); - if (component->driver->remove) component->driver->remove(component); - snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + soc_cleanup_component(component); } static void soc_remove_dai(struct snd_soc_dai *dai, int order) @@ -1360,6 +1363,8 @@ static int soc_probe_component(struct snd_soc_card *card, component->card = card; dapm->card = card; + INIT_LIST_HEAD(&component->card_list); + INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); soc_init_component_debugfs(component); @@ -1422,12 +1427,9 @@ static int soc_probe_component(struct snd_soc_card *card, /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); - return 0; - err_probe: - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + if (ret < 0) + soc_cleanup_component(component); return ret; } From 10dff9b0ddf70bebe9523fc311ec77a872ce0a9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:59 +0900 Subject: [PATCH 160/461] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675a..1c92b4aff57b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,9 +905,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { + for_each_link_codecs(dai_link, i, codecs) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From fe7ed4dec2e6289eab81dd18c0d613c0851d85a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 16:40:59 +0900 Subject: [PATCH 161/461] ASoC: simple-card: rename to asoc_simple_card_canonicalize_platform() Current simple-card is using asoc_simple_card_canonicalize_dailink(). Its naming is "dailink", but is for "platform". We already have asoc_simple_card_canonicalize_cpu() for "cpu", let's follow same naming rule. It never return error, so, void function is better idea. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 11 +++-------- sound/soc/generic/simple-card-utils.c | 7 ++----- sound/soc/generic/simple-card.c | 11 +++-------- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ab5a2ba09c07..7afe45389972 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -108,7 +108,7 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link); +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 42b077c6be4c..bb12351330e8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -307,14 +307,12 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv, "prefix"); } + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(ep, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); if (ret < 0) @@ -405,10 +403,6 @@ static int graph_dai_link_of(struct graph_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -419,6 +413,7 @@ static int graph_dai_link_of(struct graph_priv *priv, dai_link->ops = &graph_ops; dai_link->init = graph_dai_init; + asoc_simple_card_canonicalize_platform(dai_link); asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3c0901df5796..5c1424f03620 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -394,16 +394,13 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ if (!dai_link->platforms->of_node) dai_link->platforms->of_node = dai_link->cpu_of_node; - - return 0; - } -EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); +EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_platform); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d8a0d1ec256e..08df261024cf 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -297,14 +297,12 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv, simple_get_conversion(dev, np, &dai_props->adata); + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(node, prop, &dai_props->mclk_fs); @@ -409,10 +407,6 @@ static int simple_dai_link_of(struct simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - goto dai_link_of_err; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -424,6 +418,7 @@ static int simple_dai_link_of(struct simple_priv *priv, dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); + asoc_simple_card_canonicalize_platform(dai_link); dai_link_of_err: of_node_put(node); From 3f7e94e6d66b52bb6a86b7e06f5f2453491bf7c8 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:16 +0530 Subject: [PATCH 162/461] ALSA: hda/tegra: runtime power management support This patch enables runtime power management(runtime PM) support for hda. pm_runtime_enable() and pm_runtime_disable() are added during device probe and remove respectively. The runtime PM callbacks will be forbidden if hda controller does not have support for runtime PM. pm_runtime_get_sync() and pm_runtime_put() are added for hda register access. The callbacks for above will be added in subsequent patches. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 97a176d817a0..2f9dd23981fe 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -512,6 +513,11 @@ static int hda_tegra_probe(struct platform_device *pdev) card->private_data = chip; dev_set_drvdata(&pdev->dev, card); + + pm_runtime_enable(hda->dev); + if (!azx_has_pm_runtime(chip)) + pm_runtime_forbid(hda->dev); + schedule_work(&hda->probe_work); return 0; @@ -528,6 +534,7 @@ static void hda_tegra_probe_work(struct work_struct *work) struct platform_device *pdev = to_platform_device(hda->dev); int err; + pm_runtime_get_sync(hda->dev); err = hda_tegra_first_init(chip, pdev); if (err < 0) goto out_free; @@ -549,12 +556,18 @@ static void hda_tegra_probe_work(struct work_struct *work) snd_hda_set_power_save(&chip->bus, power_save * 1000); out_free: + pm_runtime_put(hda->dev); return; /* no error return from async probe */ } static int hda_tegra_remove(struct platform_device *pdev) { - return snd_card_free(dev_get_drvdata(&pdev->dev)); + int ret; + + ret = snd_card_free(dev_get_drvdata(&pdev->dev)); + pm_runtime_disable(&pdev->dev); + + return ret; } static void hda_tegra_shutdown(struct platform_device *pdev) From 65af2122e8727a6bf4890a0d2a1d79ea1db323c1 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:17 +0530 Subject: [PATCH 163/461] ALSA: hda/tegra: get clock handles early in probe Moved devm_clk_get() API calls to a separate function and the same can be called early in the probe. This is done before runtime PM for the device is enabled. The runtime resume/suspend callbacks can later enable/disable clocks respectively(the support would be added in subsequent patches). Clock handles should be available by the time runtime suspend/resume calls can happen. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 43 ++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 2f9dd23981fe..28e165612189 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -306,22 +306,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) struct resource *res; int err; - hda->hda_clk = devm_clk_get(dev, "hda"); - if (IS_ERR(hda->hda_clk)) { - dev_err(dev, "failed to get hda clock\n"); - return PTR_ERR(hda->hda_clk); - } - hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x"); - if (IS_ERR(hda->hda2codec_2x_clk)) { - dev_err(dev, "failed to get hda2codec_2x clock\n"); - return PTR_ERR(hda->hda2codec_2x_clk); - } - hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi"); - if (IS_ERR(hda->hda2hdmi_clk)) { - dev_err(dev, "failed to get hda2hdmi clock\n"); - return PTR_ERR(hda->hda2hdmi_clk); - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hda->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hda->regs)) @@ -341,6 +325,29 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) return 0; } +static int hda_tegra_init_clk(struct hda_tegra *hda) +{ + struct device *dev = hda->dev; + + hda->hda_clk = devm_clk_get(dev, "hda"); + if (IS_ERR(hda->hda_clk)) { + dev_err(dev, "failed to get hda clock\n"); + return PTR_ERR(hda->hda_clk); + } + hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x"); + if (IS_ERR(hda->hda2codec_2x_clk)) { + dev_err(dev, "failed to get hda2codec_2x clock\n"); + return PTR_ERR(hda->hda2codec_2x_clk); + } + hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi"); + if (IS_ERR(hda->hda2hdmi_clk)) { + dev_err(dev, "failed to get hda2hdmi clock\n"); + return PTR_ERR(hda->hda2hdmi_clk); + } + + return 0; +} + static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) { struct hdac_bus *bus = azx_bus(chip); @@ -507,6 +514,10 @@ static int hda_tegra_probe(struct platform_device *pdev) return err; } + err = hda_tegra_init_clk(hda); + if (err < 0) + goto out_free; + err = hda_tegra_create(card, driver_flags, hda); if (err < 0) goto out_free; From f2974aa21a414f9a2421fc69d2e289d3c74b2d3d Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:18 +0530 Subject: [PATCH 164/461] ALSA: hda/tegra: add runtime PM callbacks This patch adds skeleton of runtime suspend and resume callbacks. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 28e165612189..1189f972cb83 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -265,8 +265,23 @@ static int hda_tegra_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM +static int hda_tegra_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int hda_tegra_runtime_resume(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_PM */ + static const struct dev_pm_ops hda_tegra_pm = { SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) + SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend, + hda_tegra_runtime_resume, + NULL) }; static int hda_tegra_dev_disconnect(struct snd_device *device) From 091aa420530c1f0c93745dc9e506bfa96f898702 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:19 +0530 Subject: [PATCH 165/461] ALSA: hda/tegra: remove redundant clock enable API Explicit clock enable is not required during probe, as this would be managed by runtime PM calls. Clock can be enabled/disabled in runtime resume/suspend. This way it is easier to balance clock enable/disable counts. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 1189f972cb83..f068b1e7719b 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -319,7 +319,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) struct hdac_bus *bus = azx_bus(chip); struct device *dev = hda->dev; struct resource *res; - int err; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hda->regs = devm_ioremap_resource(dev, res); @@ -329,12 +328,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) bus->remap_addr = hda->regs + HDA_BAR0; bus->addr = res->start + HDA_BAR0; - err = hda_tegra_enable_clocks(hda); - if (err) { - dev_err(dev, "failed to get enable clocks\n"); - return err; - } - hda_tegra_init(hda); return 0; From 707e0759f2f4aefcc5c3f08ce5fb9e98495fdc93 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:20 +0530 Subject: [PATCH 166/461] ALSA: hda/tegra: implement runtime suspend/resume This patch moves clock enable/disable from system resume/suspend to runtime resume/suspend respectively. Along with this hda controller chip init or stop is also moved. System resume/suspend can invoke runtime callbacks and do necessary setup. chip->running can be used to check for probe completion and device access during runtime_resume or runtime_suspend can be avoided if probe is not yet finished. This helps to avoid kernel panic during boot where runtime PM callbacks can happen from system PM. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 49 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index f068b1e7719b..a7fd4c67ab8e 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -233,32 +233,24 @@ static void hda_tegra_disable_clocks(struct hda_tegra *data) static int hda_tegra_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - struct hdac_bus *bus = azx_bus(chip); + int rc; + rc = pm_runtime_force_suspend(dev); + if (rc < 0) + return rc; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_stop_chip(chip); - synchronize_irq(bus->irq); - azx_enter_link_reset(chip); - hda_tegra_disable_clocks(hda); - return 0; } static int hda_tegra_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); - struct azx *chip = card->private_data; - struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); - - hda_tegra_enable_clocks(hda); - - hda_tegra_init(hda); - - azx_init_chip(chip, 1); + int rc; + rc = pm_runtime_force_resume(dev); + if (rc < 0) + return rc; snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; @@ -268,11 +260,36 @@ static int hda_tegra_resume(struct device *dev) #ifdef CONFIG_PM static int hda_tegra_runtime_suspend(struct device *dev) { + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + struct hdac_bus *bus = azx_bus(chip); + + if (chip && chip->running) { + azx_stop_chip(chip); + synchronize_irq(bus->irq); + azx_enter_link_reset(chip); + } + hda_tegra_disable_clocks(hda); + return 0; } static int hda_tegra_runtime_resume(struct device *dev) { + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + int rc; + + rc = hda_tegra_enable_clocks(hda); + if (rc != 0) + return rc; + if (chip && chip->running) { + hda_tegra_init(hda); + azx_init_chip(chip, 1); + } + return 0; } #endif /* CONFIG_PM */ From 9935d55b02906dec1b0795873cc4a1a7bb55b8f1 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Tue, 22 Jan 2019 13:03:21 +0530 Subject: [PATCH 167/461] ALSA: hda/tegra: add driver flag for runtime PM AZX_DCAPS_PM_RUNTIME flag is added to indicate support for runtime PM. azx_has_pm_runtime() is used to check if above is enabled and thus forbid runtime PM calls if needed. Signed-off-by: Sameer Pujar Reviewed-by: Ravindra Lokhande Reviewed-by: Mohan Kumar D Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index a7fd4c67ab8e..c8d18dc4da2a 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -520,7 +520,8 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match); static int hda_tegra_probe(struct platform_device *pdev) { - const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR; + const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR | + AZX_DCAPS_PM_RUNTIME; struct snd_card *card; struct azx *chip; struct hda_tegra *hda; From 6c644e4e954ddae26880d82e7aa4f551662cdae3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:00 +0900 Subject: [PATCH 168/461] ALSA: fireface: change prototype of handler for async transaction with MIDI messages In a series of Fireface, devices transfer asynchronous transaction with MIDI messages. In the transaction, content is different depending on models. ALSA fireface driver has protocol-dependent handler to pick up MIDI messages from the content. In latter models of the series, the transaction is transferred to range of address sequentially. This seems to check continuity of transferred messages. This commit changes prototype of the handler to receive offset of address for received transactions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 6 ++++-- sound/firewire/fireface/ff-transaction.c | 4 +++- sound/firewire/fireface/ff.h | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 9c0ae50e88d1..266e4892a818 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -375,7 +375,8 @@ static void ff800_finish_session(struct snd_ff *ff) FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0); } -static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) { int i; @@ -502,7 +503,8 @@ static void ff400_finish_session(struct snd_ff *ff) FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); } -static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) { int i; diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 065e045d3fb5..d3fde813ce17 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -146,7 +146,9 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request, fw_send_response(card, request, RCODE_COMPLETE); - ff->spec->protocol->handle_midi_msg(ff, buf, length); + offset -= ff->async_handler.offset; + ff->spec->protocol->handle_midi_msg(ff, (unsigned int)offset, buf, + length); } static int allocate_own_address(struct snd_ff *ff, int i) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 8aea7920b57f..ddcffb8d85c6 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -103,7 +103,8 @@ enum snd_ff_clock_src { }; struct snd_ff_protocol { - void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length); int (*get_clock)(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); From 900896771a2f7ba126194911c58dc095fc0dd3d7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:01 +0900 Subject: [PATCH 169/461] ALSA: fireface: add model-dependent parameter for address range to receive async transaction In Fireface series, drivers can register destination address for asynchronous transaction which transfers MIDI messages from device. In former models, all of the transactions arrive at the registered address without any offset. In latter models, each of the transaction arrives at the registered address with sequential offset within 0x00 to 0x7f. This seems to be for discontinuity detection. This commit adds model-dependent member for the address range. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-transaction.c | 2 +- sound/firewire/fireface/ff.c | 2 ++ sound/firewire/fireface/ff.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index d3fde813ce17..0506755891ce 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -156,7 +156,7 @@ static int allocate_own_address(struct snd_ff *ff, int i) struct fw_address_region midi_msg_region; int err; - ff->async_handler.length = SND_FF_MAXIMIM_MIDI_QUADS * 4; + ff->async_handler.length = ff->spec->midi_addr_range; ff->async_handler.address_callback = handle_midi_msg; ff->async_handler.callback_data = ff; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index fd9c980e3cf4..c09a4875aa86 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -159,6 +159,7 @@ static const struct snd_ff_spec spec_ff800 = { .midi_out_ports = 1, .protocol = &snd_ff_protocol_ff800, .midi_high_addr = 0x000200000320ull, + .midi_addr_range = 12, }; static const struct snd_ff_spec spec_ff400 = { @@ -169,6 +170,7 @@ static const struct snd_ff_spec spec_ff400 = { .midi_out_ports = 2, .protocol = &snd_ff_protocol_ff400, .midi_high_addr = 0x0000801003f4ull, + .midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4, }; static const struct snd_ff_spec spec_ucx = { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index ddcffb8d85c6..b86ca4fb7d9b 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -54,6 +54,7 @@ struct snd_ff_spec { const struct snd_ff_protocol *protocol; u64 midi_high_addr; + u8 midi_addr_range; }; struct snd_ff { From 73f5537fb209e8dcd503c9ce140baa7e892fb65e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:02 +0900 Subject: [PATCH 170/461] ALSA: fireface: support tx MIDI functionality of Fireface UCX Fireface UCX transfers asynchronous transactions for MIDI messages. One transaction includes quadlet data therefore it can transfer 3 message bytes as maximum. Base address of the destination is configured by two settings; a register for higher 8 byte of the address, and a bitflag to option register indicates lower 8byte. The register for higher address is 0x'ffff'0000'0034. Unfortunately, firmware v24 includes a bug to ignore registered value for the destination address and transfers to 0x0001xxxxxxxx always. This driver doesn't work well if the bug exists, therefore users should install the latest firmware (v27). The bitflag is a part of value to be written to option register (0x'ffff'0000'0014). lower addr: bitflag (little endian) '0000'0000: 0x00002000 '0000'0080: 0x00004000 '0000'0100: 0x00008000 '0000'0180: 0x00010000 This register includes more options but they are not relevant to packet streaming or MIDI functionality. This driver don't touch it. Furthermore, the transaction is sent to address offset incremented by 4 byte to the offset in previous time. When it reaches base address plus 0x7c, next offset is the base address. Content of the transaction includes a prefix byte. Upper 4 bits of the byte indicates port number, and the rest 4 bits indicate the way to decode rest of bytes for MIDI message. Except for system exclusive messages, the rest bits are the same as status bits of the message without channel bits. For system exclusive messages, the rest bits are encoded according to included message bytes. For example: message: f0 7e 7f 09 01 f7 offset: content (little endian, port 0) '0000: 0x04f07e7f '0004: 0x070901f7 message: f0 00 00 66 14 20 00 00 00 f7 offset: content (little endian, port 1) '0014: 0x14f00000 '0018: 0x14661420 '001c: 0x14000000 '0020: 0x15f70000 message: f0 00 00 66 14 20 00 00 f7 offset: content (little endian, port 0) '0078: 0x04f00000 '007c: 0x04661420 '0000: 0x070000f7 This commit supports decoding scheme for the above and allows applications to receive MIDI messages via ALSA rawmidi interface. The lower 8 bytes of destination address is fixed to 0x'0000'0000, thus this driver expects userspace applications to configure option register with bitflag 0x00002000 in advance. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-latter.c | 43 ++++++++++++++++++++ sound/firewire/fireface/ff.c | 25 +++++------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 64767ba439db..a812ab6feb58 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -264,7 +264,50 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate); } +// NOTE: transactions are transferred within 0x00-0x7f in allocated range of +// address. This seems to be for check of discontinuity in receiver side. +static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) +{ + u32 data = le32_to_cpu(*buf); + unsigned int index = (data & 0x000000f0) >> 4; + u8 byte[3]; + struct snd_rawmidi_substream *substream; + unsigned int len; + + if (index > ff->spec->midi_in_ports) + return; + + switch (data & 0x0000000f) { + case 0x00000008: + case 0x00000009: + case 0x0000000a: + case 0x0000000b: + case 0x0000000e: + len = 3; + break; + case 0x0000000c: + case 0x0000000d: + len = 2; + break; + default: + len = data & 0x00000003; + if (len == 0) + len = 3; + break; + } + + byte[0] = (data & 0x0000ff00) >> 8; + byte[1] = (data & 0x00ff0000) >> 16; + byte[2] = (data & 0xff000000) >> 24; + + substream = READ_ONCE(ff->tx_midi_substreams[index]); + if (substream) + snd_rawmidi_receive(substream, byte, len); +} + const struct snd_ff_protocol snd_ff_protocol_latter = { + .handle_midi_msg = latter_handle_midi_msg, .get_clock = latter_get_clock, .switch_fetching_mode = latter_switch_fetching_mode, .begin_session = latter_begin_session, diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index c09a4875aa86..a2a9fd82f27d 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,8 +32,7 @@ static void ff_card_free(struct snd_card *card) struct snd_ff *ff = card->private_data; snd_ff_stream_destroy_duplex(ff); - if (ff->spec->midi_high_addr > 0) - snd_ff_transaction_unregister(ff); + snd_ff_transaction_unregister(ff); } static void do_registration(struct work_struct *work) @@ -51,11 +50,9 @@ static void do_registration(struct work_struct *work) ff->card->private_free = ff_card_free; ff->card->private_data = ff; - if (ff->spec->midi_high_addr > 0) { - err = snd_ff_transaction_register(ff); - if (err < 0) - goto error; - } + err = snd_ff_transaction_register(ff); + if (err < 0) + goto error; name_card(ff); @@ -65,11 +62,9 @@ static void do_registration(struct work_struct *work) snd_ff_proc_init(ff); - if (ff->spec->midi_in_ports > 0 || ff->spec->midi_out_ports > 0) { - err = snd_ff_create_midi_devices(ff); - if (err < 0) - goto error; - } + err = snd_ff_create_midi_devices(ff); + if (err < 0) + goto error; err = snd_ff_create_pcm_devices(ff); if (err < 0) @@ -124,8 +119,7 @@ static void snd_ff_update(struct fw_unit *unit) if (!ff->registered) snd_fw_schedule_registration(unit, &ff->dwork); - if (ff->spec->midi_high_addr > 0) - snd_ff_transaction_reregister(ff); + snd_ff_transaction_reregister(ff); if (ff->registered) snd_ff_stream_update_duplex(ff); @@ -177,7 +171,10 @@ static const struct snd_ff_spec spec_ucx = { .name = "FirefaceUCX", .pcm_capture_channels = {18, 14, 12}, .pcm_playback_channels = {18, 14, 12}, + .midi_in_ports = 2, .protocol = &snd_ff_protocol_latter, + .midi_high_addr = 0xffff00000034ull, + .midi_addr_range = 0x80, }; static const struct ieee1394_device_id snd_ff_id_table[] = { From 481e09ac9a82644af697884cc522b76b4dd07e4d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:03 +0900 Subject: [PATCH 171/461] ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages Between former and latter models, destination address to receive asynchronous transactions for MIDI messages is different. This commit adds model-dependent parameter for the addresses. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-transaction.c | 7 ++----- sound/firewire/fireface/ff.c | 3 +++ sound/firewire/fireface/ff.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 0506755891ce..92ca76ab7537 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -8,9 +8,6 @@ #include "ff.h" -#define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull -#define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull - static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, int rcode) { @@ -93,10 +90,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) fill_midi_buf(ff, port, i, buf[i]); if (port == 0) { - addr = SND_FF_REG_MIDI_RX_PORT_0; + addr = ff->spec->midi_rx_addrs[0]; callback = finish_transmit_midi0_msg; } else { - addr = SND_FF_REG_MIDI_RX_PORT_1; + addr = ff->spec->midi_rx_addrs[1]; callback = finish_transmit_midi1_msg; } diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index a2a9fd82f27d..675c6ab556eb 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -154,6 +154,7 @@ static const struct snd_ff_spec spec_ff800 = { .protocol = &snd_ff_protocol_ff800, .midi_high_addr = 0x000200000320ull, .midi_addr_range = 12, + .midi_rx_addrs = {0x000080180000ull, 0}, }; static const struct snd_ff_spec spec_ff400 = { @@ -165,6 +166,7 @@ static const struct snd_ff_spec spec_ff400 = { .protocol = &snd_ff_protocol_ff400, .midi_high_addr = 0x0000801003f4ull, .midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4, + .midi_rx_addrs = {0x000080180000ull, 0x000080190000ull}, }; static const struct snd_ff_spec spec_ucx = { @@ -175,6 +177,7 @@ static const struct snd_ff_spec spec_ucx = { .protocol = &snd_ff_protocol_latter, .midi_high_addr = 0xffff00000034ull, .midi_addr_range = 0x80, + .midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull}, }; static const struct ieee1394_device_id snd_ff_id_table[] = { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index b86ca4fb7d9b..edad75a4b260 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -55,6 +55,7 @@ struct snd_ff_spec { const struct snd_ff_protocol *protocol; u64 midi_high_addr; u8 midi_addr_range; + u64 midi_rx_addrs[SND_FF_OUT_MIDI_PORTS]; }; struct snd_ff { From 82b6297b4434d1bc523f3470be4875ab185c6663 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:04 +0900 Subject: [PATCH 172/461] ALSA: fireface: add protocol-specific operation to fill transaction buffer with MIDI messages Between former and latter models, content of asynchronous transaction for MIDI messages from driver to device is different. This commit is a preparation to support latter models. A protocol-specific operation is added to encode MIDI messages to the transaction. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 23 +++++++++++++++ sound/firewire/fireface/ff-transaction.c | 31 ++++++++------------ sound/firewire/fireface/ff.h | 3 ++ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 266e4892a818..e0acf40a02ee 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -263,6 +263,27 @@ static void former_dump_status(struct snd_ff *ff, dump_sync_status(ff, buffer); } +static int former_fill_midi_msg(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port) +{ + u8 *buf = (u8 *)ff->msg_buf[port]; + int len; + int i; + + len = snd_rawmidi_transmit_peek(substream, buf, + SND_FF_MAXIMIM_MIDI_QUADS); + if (len <= 0) + return len; + + // One quadlet includes one byte. + for (i = len - 1; i >= 0; --i) + ff->msg_buf[port][i] = cpu_to_le32(buf[i]); + ff->rx_bytes[port] = len; + + return len; +} + #define FF800_STF 0x0000fc88f000 #define FF800_RX_PACKET_FORMAT 0x0000fc88f004 #define FF800_ALLOC_TX_STREAM 0x0000fc88f008 @@ -392,6 +413,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, + .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, @@ -543,6 +565,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 92ca76ab7537..d8a8b01b39a1 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -51,23 +51,17 @@ static void finish_transmit_midi1_msg(struct fw_card *card, int rcode, finish_transmit_midi_msg(ff, 1, rcode); } -static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port, - unsigned int index, u8 byte) -{ - ff->msg_buf[port][index] = cpu_to_le32(byte); -} - static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) { struct snd_rawmidi_substream *substream = READ_ONCE(ff->rx_midi_substreams[port]); - u8 *buf = (u8 *)ff->msg_buf[port]; - int i, len; + int quad_count; struct fw_device *fw_dev = fw_parent_device(ff->unit); unsigned long long addr; int generation; fw_transaction_callback_t callback; + int tcode; if (substream == NULL || snd_rawmidi_transmit_empty(substream)) return; @@ -81,14 +75,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) return; } - len = snd_rawmidi_transmit_peek(substream, buf, - SND_FF_MAXIMIM_MIDI_QUADS); - if (len <= 0) + quad_count = ff->spec->protocol->fill_midi_msg(ff, substream, port); + if (quad_count <= 0) return; - for (i = len - 1; i >= 0; i--) - fill_midi_buf(ff, port, i, buf[i]); - if (port == 0) { addr = ff->spec->midi_rx_addrs[0]; callback = finish_transmit_midi0_msg; @@ -99,8 +89,12 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) /* Set interval to next transaction. */ ff->next_ktime[port] = ktime_add_ns(ktime_get(), - len * 8 * NSEC_PER_SEC / 31250); - ff->rx_bytes[port] = len; + ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250); + + if (quad_count == 1) + tcode = TCODE_WRITE_QUADLET_REQUEST; + else + tcode = TCODE_WRITE_BLOCK_REQUEST; /* * In Linux FireWire core, when generation is updated with memory @@ -112,10 +106,9 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) */ generation = fw_dev->generation; smp_rmb(); - fw_send_request(fw_dev->card, &ff->transactions[port], - TCODE_WRITE_BLOCK_REQUEST, + fw_send_request(fw_dev->card, &ff->transactions[port], tcode, fw_dev->node_id, generation, fw_dev->max_speed, - addr, &ff->msg_buf[port], len * 4, + addr, &ff->msg_buf[port], quad_count * 4, callback, &ff->transactions[port]); } diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index edad75a4b260..e52ad11803e0 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -107,6 +107,9 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length); + int (*fill_midi_msg)(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port); int (*get_clock)(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); From f0f9f497d44e2f696b4e16c41f3eaa13a009f22d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:05 +0900 Subject: [PATCH 173/461] ALSA: fireface: support rx MIDI functionality for Fireface UCX In latter model of Fireface series, asynchronous transaction includes a prefix byte to indicate the way to decode included MIDI bytes. Upper 4 bits of the prefix byte indicates port number, and the rest 4 bits indicate the way to decode rest of bytes for MIDI messages. Basically the rest bits indicates the number of bytes for MIDI message. However, if the last byte of each MIDi message is included, the rest bits are 0xf. For example: message: f0 00 00 66 14 20 00 00 f7 offset: content (big endian, port 0) '0030: 0x02f00000 '0030: 0x03006614 '0030: 0x03200000 '0030: 0x0ff70000 This commit supports encoding scheme for the above and allows applications to transfer MIDI messages via ALSA rawmidi interface. An unused member (running_status) is reused to keep state of transmission of system exclusive messages. For your information, this is a dump of config rom. $ sudo ./hinawa-config-rom-printer /dev/fw1 { 'bus-info': { 'bmc': False, 'chip_ID': 13225063715, 'cmc': False, 'cyc_clk_acc': 0, 'imc': False, 'isc': True, 'max_rec': 512, 'name': '1394', 'node_vendor_ID': 2613}, 'root-directory': [ [ 'NODE_CAPABILITIES', { 'addressing': {'64': True, 'fix': True, 'prv': False}, 'misc': {'int': False, 'ms': False, 'spt': True}, 'state': { 'atn': False, 'ded': False, 'drq': True, 'elo': False, 'init': False, 'lst': True, 'off': False}, 'testing': {'bas': False, 'ext': False}}], ['VENDOR', 2613], ['DESCRIPTOR', 'RME!'], ['EUI_64', 2873037108442403], [ 'UNIT', [ ['SPECIFIER_ID', 2613], ['VERSION', 4], ['MODEL', 1054720], ['DESCRIPTOR', 'Fireface UCX']]]]} Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-midi.c | 2 +- sound/firewire/fireface/ff-protocol-latter.c | 96 ++++++++++++++++++++ sound/firewire/fireface/ff.c | 1 + sound/firewire/fireface/ff.h | 2 +- 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c index 6a49611ee462..5b44e1c4569a 100644 --- a/sound/firewire/fireface/ff-midi.c +++ b/sound/firewire/fireface/ff-midi.c @@ -19,7 +19,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) struct snd_ff *ff = substream->rmidi->private_data; /* Initialize internal status. */ - ff->running_status[substream->number] = 0; + ff->on_sysex[substream->number] = 0; ff->rx_midi_error[substream->number] = false; WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream); diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index a812ab6feb58..817af4447349 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -306,8 +306,104 @@ static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, snd_rawmidi_receive(substream, byte, len); } +/* + * When return minus value, given argument is not MIDI status. + * When return 0, given argument is a beginning of system exclusive. + * When return the others, given argument is MIDI data. + */ +static inline int calculate_message_bytes(u8 status) +{ + switch (status) { + case 0xf6: /* Tune request. */ + case 0xf8: /* Timing clock. */ + case 0xfa: /* Start. */ + case 0xfb: /* Continue. */ + case 0xfc: /* Stop. */ + case 0xfe: /* Active sensing. */ + case 0xff: /* System reset. */ + return 1; + case 0xf1: /* MIDI time code quarter frame. */ + case 0xf3: /* Song select. */ + return 2; + case 0xf2: /* Song position pointer. */ + return 3; + case 0xf0: /* Exclusive. */ + return 0; + case 0xf7: /* End of exclusive. */ + break; + case 0xf4: /* Undefined. */ + case 0xf5: /* Undefined. */ + case 0xf9: /* Undefined. */ + case 0xfd: /* Undefined. */ + break; + default: + switch (status & 0xf0) { + case 0x80: /* Note on. */ + case 0x90: /* Note off. */ + case 0xa0: /* Polyphonic key pressure. */ + case 0xb0: /* Control change and Mode change. */ + case 0xe0: /* Pitch bend change. */ + return 3; + case 0xc0: /* Program change. */ + case 0xd0: /* Channel pressure. */ + return 2; + default: + break; + } + break; + } + + return -EINVAL; +} + +static int latter_fill_midi_msg(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port) +{ + u32 data = {0}; + u8 *buf = (u8 *)&data; + int consumed; + + buf[0] = port << 4; + consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3); + if (consumed <= 0) + return consumed; + + if (!ff->on_sysex[port]) { + if (buf[1] != 0xf0) { + if (consumed < calculate_message_bytes(buf[1])) + return 0; + } else { + // The beginning of exclusives. + ff->on_sysex[port] = true; + } + + buf[0] |= consumed; + } else { + if (buf[1] != 0xf7) { + if (buf[2] == 0xf7 || buf[3] == 0xf7) { + // Transfer end code at next time. + consumed -= 1; + } + + buf[0] |= consumed; + } else { + // The end of exclusives. + ff->on_sysex[port] = false; + consumed = 1; + buf[0] |= 0x0f; + } + } + + ff->msg_buf[port][0] = cpu_to_le32(data); + ff->rx_bytes[port] = consumed; + + return 1; +} + const struct snd_ff_protocol snd_ff_protocol_latter = { .handle_midi_msg = latter_handle_midi_msg, + .fill_midi_msg = latter_fill_midi_msg, .get_clock = latter_get_clock, .switch_fetching_mode = latter_switch_fetching_mode, .begin_session = latter_begin_session, diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 675c6ab556eb..a9611157f4c8 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -174,6 +174,7 @@ static const struct snd_ff_spec spec_ucx = { .pcm_capture_channels = {18, 14, 12}, .pcm_playback_channels = {18, 14, 12}, .midi_in_ports = 2, + .midi_out_ports = 2, .protocol = &snd_ff_protocol_latter, .midi_high_addr = 0xffff00000034ull, .midi_addr_range = 0x80, diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index e52ad11803e0..ed8fea0ff5e1 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -75,7 +75,7 @@ struct snd_ff { /* TO handle MIDI rx. */ struct snd_rawmidi_substream *rx_midi_substreams[SND_FF_OUT_MIDI_PORTS]; - u8 running_status[SND_FF_OUT_MIDI_PORTS]; + bool on_sysex[SND_FF_OUT_MIDI_PORTS]; __le32 msg_buf[SND_FF_OUT_MIDI_PORTS][SND_FF_MAXIMIM_MIDI_QUADS]; struct work_struct rx_midi_work[SND_FF_OUT_MIDI_PORTS]; struct fw_transaction transactions[SND_FF_OUT_MIDI_PORTS]; From 3f6a125230d8bfcbfe0c06ff0b8eaccbc727acd7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Jan 2019 17:36:11 +0000 Subject: [PATCH 174/461] ASoC: core: Fix multi-CODEC setups Revert 10dff9b0d (ASoC: soc-core: use for_each_link_codecs() for dai_link codecs) for now as Sylwester Nawrocki reports that it causes oopses on at least Odroid boards. Reported-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c92b4aff57b..8a58fa86675a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,8 +905,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for_each_link_codecs(dai_link, i, codecs) { + for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From f57f3df03a8e6010e321fa0258d3e054713c3cb7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:50:33 +0100 Subject: [PATCH 175/461] ALSA: pcm: More fine-grained PCM link locking We have currently two global locks, a rwlock and a rwsem, that are used for managing linking the PCM streams. Due to these global locks, once when a linked stream is used, the lock granularity suffers a lot. This patch attempts to eliminate the former global lock for atomic ops. The latter rwsem needs remaining because of the loosy way of the loop calls in snd_pcm_action_nonatomic(), as well as for avoiding the deadlock at linking. However, these are used far rarely, actually only by two actions (prepare and reset), where both are no timing critical ones. So this can be still seen as a good improvement. The basic strategy to eliminate the rwlock is to assure group->lock at adding or removing a stream to / from the group. Since we already takes the group lock whenever taking the all substream locks under the group, this shouldn't be a big problem. The reference to group pointer in snd_pcm_substream object is protected by the stream lock itself. However, there are still pitfalls: a race window at re-locking and the lifecycle of group object. The former is a small race window for dereferencing the substream group object opened while snd_pcm_action() performs re-locking to avoid ABBA deadlocks. This includes the unlink of group during that window, too. And the latter is the kfree performed after all streams are removed from the group while it's still dereferenced. For addressing these corner cases, two new tricks are introduced: - After re-locking, the group assigned to the stream is checked again; if the group is changed, we retry the whole procedure. - Introduce a refcount to snd_pcm_group object, so that it's freed only when it's empty and really no one refers to it. (Some readers might wonder why not RCU for the latter. RCU in this case would cost more than refcounting, unfortunately. We take the group lock sooner or later, hence the performance improvement by RCU would be negligible. Meanwhile, because we need to deal with schedulable context depending on the pcm->nonatomic flag, it'll become dynamic RCU/SRCU switch, and the grace period may become too long.) Along with these changes, there are a significant amount of code refactoring. The complex group re-lock & ref code is factored out to snd_pcm_stream_group_ref() function, for example. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 + sound/core/pcm_native.c | 166 +++++++++++++++++++++++++++++----------- 2 files changed, 124 insertions(+), 44 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e1c747c70883..3bde24575a99 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -30,6 +30,7 @@ #include #include #include +#include #define snd_pcm_substream_chip(substream) ((substream)->private_data) #define snd_pcm_chip(pcm) ((pcm)->private_data) @@ -439,6 +440,7 @@ struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; struct mutex mutex; struct list_head substreams; + refcount_t refs; }; struct pid; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index fb45386270d5..cbde23fc67a9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -85,7 +85,6 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); * */ -static DEFINE_RWLOCK(snd_pcm_link_rwlock); static DECLARE_RWSEM(snd_pcm_link_rwsem); /* Writer in rwsem may block readers even during its waiting in queue, @@ -105,8 +104,24 @@ void snd_pcm_group_init(struct snd_pcm_group *group) spin_lock_init(&group->lock); mutex_init(&group->mutex); INIT_LIST_HEAD(&group->substreams); + refcount_set(&group->refs, 0); } +/* define group lock helpers */ +#define DEFINE_PCM_GROUP_LOCK(action, mutex_action) \ +static void snd_pcm_group_ ## action(struct snd_pcm_group *group, bool nonatomic) \ +{ \ + if (nonatomic) \ + mutex_ ## mutex_action(&group->mutex); \ + else \ + spin_ ## action(&group->lock); \ +} + +DEFINE_PCM_GROUP_LOCK(lock, lock); +DEFINE_PCM_GROUP_LOCK(unlock, unlock); +DEFINE_PCM_GROUP_LOCK(lock_irq, lock); +DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock); + #define PCM_LOCK_DEFAULT 0 #define PCM_LOCK_IRQ 1 #define PCM_LOCK_IRQSAVE 2 @@ -116,21 +131,19 @@ static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substr { unsigned long flags = 0; if (substream->pcm->nonatomic) { - down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); mutex_lock(&substream->self_group.mutex); } else { switch (mode) { case PCM_LOCK_DEFAULT: - read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); break; case PCM_LOCK_IRQ: - read_lock_irq(&snd_pcm_link_rwlock); + spin_lock_irq(&substream->self_group.lock); break; case PCM_LOCK_IRQSAVE: - read_lock_irqsave(&snd_pcm_link_rwlock, flags); + spin_lock_irqsave(&substream->self_group.lock, flags); break; } - spin_lock(&substream->self_group.lock); } return flags; } @@ -140,19 +153,16 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, { if (substream->pcm->nonatomic) { mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); } else { - spin_unlock(&substream->self_group.lock); - switch (mode) { case PCM_LOCK_DEFAULT: - read_unlock(&snd_pcm_link_rwlock); + spin_unlock(&substream->self_group.lock); break; case PCM_LOCK_IRQ: - read_unlock_irq(&snd_pcm_link_rwlock); + spin_unlock_irq(&substream->self_group.lock); break; case PCM_LOCK_IRQSAVE: - read_unlock_irqrestore(&snd_pcm_link_rwlock, flags); + spin_unlock_irqrestore(&substream->self_group.lock, flags); break; } } @@ -1138,6 +1148,61 @@ static void snd_pcm_group_assign(struct snd_pcm_substream *substream, list_move(&substream->link_list, &new_group->substreams); } +/* + * Unref and unlock the group, but keep the stream lock; + * when the group becomes empty and no longer referred, destroy itself + */ +static void snd_pcm_group_unref(struct snd_pcm_group *group, + struct snd_pcm_substream *substream) +{ + bool do_free; + + if (!group) + return; + do_free = refcount_dec_and_test(&group->refs) && + list_empty(&group->substreams); + snd_pcm_group_unlock(group, substream->pcm->nonatomic); + if (do_free) + kfree(group); +} + +/* + * Lock the group inside a stream lock and reference it; + * return the locked group object, or NULL if not linked + */ +static struct snd_pcm_group * +snd_pcm_stream_group_ref(struct snd_pcm_substream *substream) +{ + bool nonatomic = substream->pcm->nonatomic; + struct snd_pcm_group *group; + bool trylock; + + for (;;) { + if (!snd_pcm_stream_linked(substream)) + return NULL; + group = substream->group; + /* block freeing the group object */ + refcount_inc(&group->refs); + + trylock = nonatomic ? mutex_trylock(&group->mutex) : + spin_trylock(&group->lock); + if (trylock) + break; /* OK */ + + /* re-lock for avoiding ABBA deadlock */ + snd_pcm_stream_unlock(substream); + snd_pcm_group_lock(group, nonatomic); + snd_pcm_stream_lock(substream); + + /* check the group again; the above opens a small race window */ + if (substream->group == group) + break; /* OK */ + /* group changed, try again */ + snd_pcm_group_unref(group, substream); + } + return group; +} + /* * Note: call with stream lock */ @@ -1145,28 +1210,15 @@ static int snd_pcm_action(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { + struct snd_pcm_group *group; int res; - if (!snd_pcm_stream_linked(substream)) - return snd_pcm_action_single(ops, substream, state); - - if (substream->pcm->nonatomic) { - if (!mutex_trylock(&substream->group->mutex)) { - mutex_unlock(&substream->self_group.mutex); - mutex_lock(&substream->group->mutex); - mutex_lock(&substream->self_group.mutex); - } + group = snd_pcm_stream_group_ref(substream); + if (group) res = snd_pcm_action_group(ops, substream, state, 1); - mutex_unlock(&substream->group->mutex); - } else { - if (!spin_trylock(&substream->group->lock)) { - spin_unlock(&substream->self_group.lock); - spin_lock(&substream->group->lock); - spin_lock(&substream->self_group.lock); - } - res = snd_pcm_action_group(ops, substream, state, 1); - spin_unlock(&substream->group->lock); - } + else + res = snd_pcm_action_single(ops, substream, state); + snd_pcm_group_unref(group, substream); return res; } @@ -1193,6 +1245,7 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, { int res; + /* Guarantee the group members won't change during non-atomic action */ down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, 0); @@ -1821,6 +1874,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_pcm_substream *s; + struct snd_pcm_group *group; wait_queue_entry_t wait; int result = 0; int nonblock = 0; @@ -1837,7 +1891,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, } else if (substream->f_flags & O_NONBLOCK) nonblock = 1; - down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); /* resume pause */ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) @@ -1862,6 +1915,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, } /* find a substream to drain */ to_check = NULL; + group = snd_pcm_stream_group_ref(substream); snd_pcm_group_for_each_entry(s, substream) { if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) continue; @@ -1871,12 +1925,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; } } + snd_pcm_group_unref(group, substream); if (!to_check) break; /* all drained */ init_waitqueue_entry(&wait, current); add_wait_queue(&to_check->sleep, &wait); snd_pcm_stream_unlock_irq(substream); - up_read(&snd_pcm_link_rwsem); if (runtime->no_period_wakeup) tout = MAX_SCHEDULE_TIMEOUT; else { @@ -1888,9 +1942,17 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, tout = msecs_to_jiffies(tout * 1000); } tout = schedule_timeout_interruptible(tout); - down_read(&snd_pcm_link_rwsem); + snd_pcm_stream_lock_irq(substream); - remove_wait_queue(&to_check->sleep, &wait); + group = snd_pcm_stream_group_ref(substream); + snd_pcm_group_for_each_entry(s, substream) { + if (s->runtime == to_check) { + remove_wait_queue(&to_check->sleep, &wait); + break; + } + } + snd_pcm_group_unref(group, substream); + if (card->shutdown) { result = -ENODEV; break; @@ -1910,7 +1972,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, unlock: snd_pcm_stream_unlock_irq(substream); - up_read(&snd_pcm_link_rwsem); return result; } @@ -1972,7 +2033,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) int res = 0; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; - struct snd_pcm_group *group; + struct snd_pcm_group *group, *target_group; + bool nonatomic = substream->pcm->nonatomic; struct fd f = fdget(fd); if (!f.file) @@ -1989,8 +2051,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _nolock; } snd_pcm_group_init(group); + down_write_nonfifo(&snd_pcm_link_rwsem); - write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || substream->pcm->nonatomic != substream1->pcm->nonatomic) { @@ -2001,13 +2063,21 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) res = -EALREADY; goto _end; } + + snd_pcm_stream_lock_irq(substream); if (!snd_pcm_stream_linked(substream)) { snd_pcm_group_assign(substream, group); - group = NULL; + group = NULL; /* assigned, don't free this one below */ } - snd_pcm_group_assign(substream1, substream->group); + target_group = substream->group; + snd_pcm_stream_unlock_irq(substream); + + snd_pcm_group_lock_irq(target_group, nonatomic); + snd_pcm_stream_lock(substream1); + snd_pcm_group_assign(substream1, target_group); + snd_pcm_stream_unlock(substream1); + snd_pcm_group_unlock_irq(target_group, nonatomic); _end: - write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: kfree(group); @@ -2018,22 +2088,27 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) static void relink_to_local(struct snd_pcm_substream *substream) { + snd_pcm_stream_lock(substream); snd_pcm_group_assign(substream, &substream->self_group); + snd_pcm_stream_unlock(substream); } static int snd_pcm_unlink(struct snd_pcm_substream *substream) { struct snd_pcm_group *group; + bool nonatomic = substream->pcm->nonatomic; + bool do_free = false; int res = 0; down_write_nonfifo(&snd_pcm_link_rwsem); - write_lock_irq(&snd_pcm_link_rwlock); + if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; goto _end; } group = substream->group; + snd_pcm_group_lock_irq(group, nonatomic); relink_to_local(substream); @@ -2042,11 +2117,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) relink_to_local(list_first_entry(&group->substreams, struct snd_pcm_substream, link_list)); - kfree(group); + do_free = !refcount_read(&group->refs); } + snd_pcm_group_unlock_irq(group, nonatomic); + if (do_free) + kfree(group); + _end: - write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); return res; } From ecb41f0f44cadfa90ef9acff3ffe95563274ec1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Jan 2019 14:29:51 +0100 Subject: [PATCH 176/461] ALSA: pcm: Remove down_write() hack for snd_pcm_link_rwsem Remove the hackish down_write_nonfifo() that was introduced as a workaround of rwsem deadlock. It used to be a problem for non-atomic PCM streams that take the rwsem for the locking and hit the high lock contention. Since the current PCM locking refactoring, we'll no longer hit it as the hot code-paths don't take global locks. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index cbde23fc67a9..f450083eb073 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -87,18 +87,6 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); static DECLARE_RWSEM(snd_pcm_link_rwsem); -/* Writer in rwsem may block readers even during its waiting in queue, - * and this may lead to a deadlock when the code path takes read sem - * twice (e.g. one in snd_pcm_action_nonatomic() and another in - * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to - * sleep until all the readers are completed without blocking by writer. - */ -static inline void down_write_nonfifo(struct rw_semaphore *lock) -{ - while (!down_write_trylock(lock)) - msleep(1); -} - void snd_pcm_group_init(struct snd_pcm_group *group) { spin_lock_init(&group->lock); @@ -2052,7 +2040,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) } snd_pcm_group_init(group); - down_write_nonfifo(&snd_pcm_link_rwsem); + down_write(&snd_pcm_link_rwsem); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || substream->pcm->nonatomic != substream1->pcm->nonatomic) { @@ -2100,7 +2088,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) bool do_free = false; int res = 0; - down_write_nonfifo(&snd_pcm_link_rwsem); + down_write(&snd_pcm_link_rwsem); if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; From ef2056b8f3945c78cc5a3a3ba7592e18a757ffd9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 10:15:03 +0100 Subject: [PATCH 177/461] ALSA: pcm: Cleanup snd_pcm_stream_lock() & co After the previous code refactoring, the PCM stream locking code became nothing but the PCM group lock with self_group object. Use the existing helper function for simplifying the code. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 68 ++++++++++------------------------------- 1 file changed, 16 insertions(+), 52 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f450083eb073..024e32acbc25 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -110,52 +110,6 @@ DEFINE_PCM_GROUP_LOCK(unlock, unlock); DEFINE_PCM_GROUP_LOCK(lock_irq, lock); DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock); -#define PCM_LOCK_DEFAULT 0 -#define PCM_LOCK_IRQ 1 -#define PCM_LOCK_IRQSAVE 2 - -static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream, - unsigned int mode) -{ - unsigned long flags = 0; - if (substream->pcm->nonatomic) { - mutex_lock(&substream->self_group.mutex); - } else { - switch (mode) { - case PCM_LOCK_DEFAULT: - spin_lock(&substream->self_group.lock); - break; - case PCM_LOCK_IRQ: - spin_lock_irq(&substream->self_group.lock); - break; - case PCM_LOCK_IRQSAVE: - spin_lock_irqsave(&substream->self_group.lock, flags); - break; - } - } - return flags; -} - -static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, - unsigned int mode, unsigned long flags) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - } else { - switch (mode) { - case PCM_LOCK_DEFAULT: - spin_unlock(&substream->self_group.lock); - break; - case PCM_LOCK_IRQ: - spin_unlock_irq(&substream->self_group.lock); - break; - case PCM_LOCK_IRQSAVE: - spin_unlock_irqrestore(&substream->self_group.lock, flags); - break; - } - } -} - /** * snd_pcm_stream_lock - Lock the PCM stream * @substream: PCM substream @@ -166,7 +120,7 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, */ void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT); + snd_pcm_group_lock(&substream->self_group, substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); @@ -178,7 +132,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); */ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0); + snd_pcm_group_unlock(&substream->self_group, substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); @@ -192,7 +146,8 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); */ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ); + snd_pcm_group_lock_irq(&substream->self_group, + substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); @@ -204,13 +159,19 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); */ void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0); + snd_pcm_group_unlock_irq(&substream->self_group, + substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) { - return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE); + unsigned long flags = 0; + if (substream->pcm->nonatomic) + mutex_lock(&substream->self_group.mutex); + else + spin_lock_irqsave(&substream->self_group.lock, flags); + return flags; } EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); @@ -224,7 +185,10 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags); + if (substream->pcm->nonatomic) + mutex_unlock(&substream->self_group.mutex); + else + spin_unlock_irqrestore(&substream->self_group.lock, flags); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); From d8002539ec7b8bc793a212b79db4a796ce9bce9c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 24 Jan 2019 18:32:03 +0900 Subject: [PATCH 178/461] ALSA: fireface: comment cleanup about destination address of async transactions for MIDI messages In Fireface series, registration of higher 4 bytes of destination address for asynchronous transaction of MIDI messages is done by a write transaction to model-specific register. On the other hand, registration of lower 4 bytes of the address is selectable from 4 options. A register for this registration includes the other purpose options such as input attenuation. Thus this driver expects userspace applications to configure the register. Actual behaviour for the asynchronous transaction is different depending on protocols. In former protocol, destination offset of each transaction is the same as the registered address even if it is block request. In latter models, destination offset of each transaction is the offset of previous transaction plus 4 byte and the transaction is quadlet request. This commit cleanups comments about the above mechanism. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 23 +++++++++++++ sound/firewire/fireface/ff-protocol-latter.c | 18 ++++++++++ sound/firewire/fireface/ff-transaction.c | 36 ++++---------------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index e0acf40a02ee..8d1c2c6e907b 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -396,6 +396,10 @@ static void ff800_finish_session(struct snd_ff *ff) FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0); } +// Fireface 800 doesn't allow drivers to register lower 4 bytes of destination +// address. +// A write transaction to clear registered higher 4 bytes of destination address +// has an effect to suppress asynchronous transaction from device. static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { @@ -525,6 +529,25 @@ static void ff400_finish_session(struct snd_ff *ff) FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); } +// For Fireface 400, lower 4 bytes of destination address is configured by bit +// flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can +// select one of 4 options: +// +// bit flags: offset of destination address +// - 0x04000000: 0x'....'....'0000'0000 +// - 0x08000000: 0x'....'....'0000'0080 +// - 0x10000000: 0x'....'....'0000'0100 +// - 0x20000000: 0x'....'....'0000'0180 +// +// Drivers can suppress the device to transfer asynchronous transactions by +// using below 2 bits. +// - 0x01000000: suppress transmission +// - 0x02000000: suppress transmission +// +// Actually, the register is write-only and includes the other options such as +// input attenuation. This driver allocates destination address with '0000'0000 +// in its lower offset and expects userspace application to configure the +// register for it. static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 817af4447349..0fbc1950327f 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -266,6 +266,24 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer // NOTE: transactions are transferred within 0x00-0x7f in allocated range of // address. This seems to be for check of discontinuity in receiver side. +// +// Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of +// destination address by bit flags in quadlet register (little endian) at +// 0x'ffff'0000'0014: +// +// bit flags: offset of destination address +// - 0x00002000: 0x'....'....'0000'0000 +// - 0x00004000: 0x'....'....'0000'0080 +// - 0x00008000: 0x'....'....'0000'0100 +// - 0x00010000: 0x'....'....'0000'0180 +// +// Drivers can suppress the device to transfer asynchronous transactions by +// clear these bit flags. +// +// Actually, the register is write-only and includes the other settings such as +// input attenuation. This driver allocates for the first option +// (0x'....'....'0000'0000) and expects userspace application to configure the +// register for it. static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index d8a8b01b39a1..0d6ad19363b8 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -165,35 +165,13 @@ static int allocate_own_address(struct snd_ff *ff, int i) return err; } -/* - * Controllers are allowed to register higher 4 bytes of address to receive - * the transactions. Different models have different registers for this purpose; - * e.g. 0x'0000'8010'03f4 for Fireface 400. - * The controllers are not allowed to register lower 4 bytes of the address. - * They are forced to select one of 4 options for the part of address by writing - * corresponding bits to 0x'0000'8010'051f. - * - * The 3rd-6th bits of this register are flags to indicate lower 4 bytes of - * address to which the device transferrs the transactions. In short: - * - 0x20: 0x'....'....'0000'0180 - * - 0x10: 0x'....'....'0000'0100 - * - 0x08: 0x'....'....'0000'0080 - * - 0x04: 0x'....'....'0000'0000 - * - * This driver configure 0x'....'....'0000'0000 to receive MIDI messages from - * units. The 3rd bit of the register should be configured, however this driver - * deligates this task to userspace applications due to a restriction that this - * register is write-only and the other bits have own effects. - * - * Unlike Fireface 800, Fireface 400 cancels transferring asynchronous - * transactions when the 1st and 2nd of the register stand. These two bits have - * the same effect. - * - 0x02, 0x01: cancel transferring - * - * On the other hand, the bits have no effect on Fireface 800. This model - * cancels asynchronous transactions when the higher 4 bytes of address is - * overwritten with zero. - */ +// Controllers are allowed to register higher 4 bytes of destination address to +// receive asynchronous transactions for MIDI messages, while the way to +// register lower 4 bytes of address is different depending on protocols. For +// details, please refer to comments in protocol implementations. +// +// This driver expects userspace applications to configure registers for the +// lower address because in most cases such registers has the other settings. int snd_ff_transaction_reregister(struct snd_ff *ff) { struct fw_card *fw_card = fw_parent_device(ff->unit)->card; From de89750c56f4bf2f04492c6ce298911381a7597a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 12:47:34 +0100 Subject: [PATCH 179/461] ALSA: pcm: Drop unused snd_pcm_substream.file field It's assigned but nowhere used. Let's remove it. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 - sound/core/oss/pcm_oss.c | 1 - sound/core/pcm_native.c | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2c30c1ad1b0d..a20d3a48df00 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -470,7 +470,6 @@ struct snd_pcm_substream { struct snd_pcm_group self_group; /* fake group for non linked substream (with substream lock inside) */ struct snd_pcm_group *group; /* pointer to current group */ /* -- assigned files -- */ - void *file; int ref_count; atomic_t mmap_count; unsigned int f_flags; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 467039b342b5..d5b0d7ba83c4 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2427,7 +2427,6 @@ static int snd_pcm_oss_open_file(struct file *file, } pcm_oss_file->streams[idx] = substream; - substream->file = pcm_oss_file; snd_pcm_oss_init_substream(substream, &setup[idx], minor); } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 26afb6b0889a..63640d3af9db 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2452,10 +2452,8 @@ static int snd_pcm_open_file(struct file *file, return -ENOMEM; } pcm_file->substream = substream; - if (substream->ref_count == 1) { - substream->file = pcm_file; + if (substream->ref_count == 1) substream->pcm_release = pcm_release_private; - } file->private_data = pcm_file; return 0; From 480e32ebd524ffdf3d50cc5cac179fb9e44a552d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 16:44:38 +0100 Subject: [PATCH 180/461] ALSA: pcm: Simplify proc file destruction The proc files are recursively freed by calling with the root snd_info_entry object, so we don't have to keep each object for releasing one by one. Move the release of the PCM stream proc root at the beginning, so that we can remove the redundant code and resource. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 11 ------- sound/core/pcm.c | 66 +++++++---------------------------------- sound/core/pcm_memory.c | 16 ++-------- 3 files changed, 13 insertions(+), 80 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index a20d3a48df00..eae6d2b82d7a 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -481,15 +481,6 @@ struct snd_pcm_substream { #endif #ifdef CONFIG_SND_VERBOSE_PROCFS struct snd_info_entry *proc_root; - struct snd_info_entry *proc_info_entry; - struct snd_info_entry *proc_hw_params_entry; - struct snd_info_entry *proc_sw_params_entry; - struct snd_info_entry *proc_status_entry; - struct snd_info_entry *proc_prealloc_entry; - struct snd_info_entry *proc_prealloc_max_entry; -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - struct snd_info_entry *proc_xrun_injection_entry; -#endif #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ unsigned int hw_opened: 1; @@ -511,10 +502,8 @@ struct snd_pcm_str { #endif #ifdef CONFIG_SND_VERBOSE_PROCFS struct snd_info_entry *proc_root; - struct snd_info_entry *proc_info_entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG unsigned int xrun_debug; /* 0 = disabled, 1 = verbose, 2 = stacktrace */ - struct snd_info_entry *proc_xrun_debug_entry; #endif #endif struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index ca1ea3cf9350..bca0bdf3e33c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -536,12 +536,9 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); if (entry) { snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - pstr->proc_info_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(pcm->card, "xrun_debug", @@ -551,24 +548,15 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= 0200; entry->private_data = pstr; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - pstr->proc_xrun_debug_entry = entry; #endif return 0; } static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - snd_info_free_entry(pstr->proc_xrun_debug_entry); - pstr->proc_xrun_debug_entry = NULL; -#endif - snd_info_free_entry(pstr->proc_info_entry); - pstr->proc_info_entry = NULL; snd_info_free_entry(pstr->proc_root); pstr->proc_root = NULL; return 0; @@ -597,45 +585,33 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_info_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_info_entry = entry; entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_hw_params_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_hw_params_entry = entry; entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_sw_params_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_sw_params_entry = entry; entry = snd_info_create_card_entry(card, "status", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_status_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_status_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(card, "xrun_injection", @@ -645,40 +621,18 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | 0200; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_xrun_injection_entry = entry; #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ return 0; } -static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) -{ - snd_info_free_entry(substream->proc_info_entry); - substream->proc_info_entry = NULL; - snd_info_free_entry(substream->proc_hw_params_entry); - substream->proc_hw_params_entry = NULL; - snd_info_free_entry(substream->proc_sw_params_entry); - substream->proc_sw_params_entry = NULL; - snd_info_free_entry(substream->proc_status_entry); - substream->proc_status_entry = NULL; -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - snd_info_free_entry(substream->proc_xrun_injection_entry); - substream->proc_xrun_injection_entry = NULL; -#endif - snd_info_free_entry(substream->proc_root); - substream->proc_root = NULL; - return 0; -} #else /* !CONFIG_SND_VERBOSE_PROCFS */ static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; } static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; } static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; } -static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; } #endif /* CONFIG_SND_VERBOSE_PROCFS */ static const struct attribute_group *pcm_dev_attr_groups[]; @@ -911,15 +865,17 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) #if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss_setup *setup, *setupn; #endif + + /* free all proc files under the stream */ + snd_pcm_stream_proc_done(pstr); + substream = pstr->substream; while (substream) { substream_next = substream->next; snd_pcm_timer_done(substream); - snd_pcm_substream_proc_done(substream); kfree(substream); substream = substream_next; } - snd_pcm_stream_proc_done(pstr); #if IS_ENABLED(CONFIG_SND_PCM_OSS) for (setup = pstr->oss.setup_list; setup; setup = setupn) { setupn = setup->next; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 4b5356a10315..9a98bc61461f 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -93,12 +93,6 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); -#ifdef CONFIG_SND_VERBOSE_PROCFS - snd_info_free_entry(substream->proc_prealloc_max_entry); - substream->proc_prealloc_max_entry = NULL; - snd_info_free_entry(substream->proc_prealloc_entry); - substream->proc_prealloc_entry = NULL; -#endif return 0; } @@ -203,21 +197,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) entry->c.text.write = snd_pcm_lib_preallocate_proc_write; entry->mode |= 0200; entry->private_data = substream; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_prealloc_entry = entry; if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; entry->private_data = substream; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_prealloc_max_entry = entry; } #else /* !CONFIG_SND_VERBOSE_PROCFS */ From 3a55437141a1d287dead685b37fe240185144f15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 17:59:40 +0100 Subject: [PATCH 181/461] ALSA: proc: Avoid possible leaks of snd_info_entry objects This patch changes the parent pointer assignment of snd_info_entry object to be always non-NULL. More specifically,check the parent argument in snd_info_create_module_entry() & co, and assign snd_proc_root if NULL is passed there. This assures that the proc object is always freed when the root is freed, so avoid possible memory leaks. For example, some error paths (e.g. snd_info_register() error at snd_minor_info_init()) may leave snd_info_entry object although the proc file itself is freed. Signed-off-by: Takashi Iwai --- sound/core/info.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index fe502bc5e6d2..2dfb6389c084 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -741,7 +741,11 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry *parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); + struct snd_info_entry *entry; + + if (!parent) + parent = snd_proc_root; + entry = snd_info_create_entry(name, parent); if (entry) entry->module = module; return entry; @@ -762,7 +766,11 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry * parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); + struct snd_info_entry *entry; + + if (!parent) + parent = card->proc_root; + entry = snd_info_create_entry(name, parent); if (entry) { entry->module = card->module; entry->card = card; From 4ffdca62e2deee7a27613571c9bd18c95b8eac84 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jan 2019 17:37:35 +0000 Subject: [PATCH 182/461] ASoC: Intel: make const arrays static, reduces object code size Don't populate the const arrays on the stack but instead make it static. Makes the object code smaller, for example: Before: text data bss dec hex filename 14107 8832 224 23163 5a7b bytcht_es8316.o After: text data bss dec hex filename 14015 8896 224 23135 5a5f bytcht_es8316.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index fa9c4cf97686..1364e4e601d8 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -437,7 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "in1", "in2" }; + static const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ca8b4d5ff70f..a79466c8fb29 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1149,7 +1149,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { - const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; + static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index b618d984e2d5..e6945d11c8ab 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -919,7 +919,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; + static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; struct device *codec_dev; From 2dee43ec3f31de39dc74e76e6ed65d976f486df0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 25 Jan 2019 15:44:18 +0300 Subject: [PATCH 183/461] ALSA: fireface: Off by one in latter_handle_midi_msg() The > should be >= or otherwise we potentially read one element beyond the end of the ff->tx_midi_substreams[] array. Fixes: 73f5537fb209 ("ALSA: fireface: support tx MIDI functionality of Fireface UCX") Signed-off-by: Dan Carpenter Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-latter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 0fbc1950327f..c8236ff89b7f 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -293,7 +293,7 @@ static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, struct snd_rawmidi_substream *substream; unsigned int len; - if (index > ff->spec->midi_in_ports) + if (index >= ff->spec->midi_in_ports) return; switch (data & 0x0000000f) { From 315d9f1bee40b20d399176acb1e27036abbd4384 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Jan 2019 17:31:59 +0100 Subject: [PATCH 184/461] ALSA: pcm: Use the common error path in __snd_pcm_lib_xfer() An open-coded error path in __snd_pcm_lib_xfer() can be replaced with the simple goto to the common error path. This also makes the error handling more consistent, i.e. when some samples have been already processed, return that size instead of the error code. Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 40013b26f671..f48efce937ad 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2219,9 +2219,8 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->twake = 0; - snd_pcm_stream_unlock_irq(substream); - return -EINVAL; + err = -EINVAL; + goto _end_unlock; } snd_pcm_stream_unlock_irq(substream); err = writer(substream, appl_ofs, data, offset, frames, From a94aec035a122bf6d1a05b14f02f34c34b99506a Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:08 +0800 Subject: [PATCH 185/461] ASoC: mediatek: mt8183: add platform driver add mt8183 audio platform and affiliated drivers. Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt8183/Makefile | 13 + sound/soc/mediatek/mt8183/mt8183-afe-clk.c | 611 ++++++ sound/soc/mediatek/mt8183/mt8183-afe-clk.h | 38 + sound/soc/mediatek/mt8183/mt8183-afe-common.h | 108 ++ sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 1237 ++++++++++++ sound/soc/mediatek/mt8183/mt8183-dai-adda.c | 501 +++++ .../soc/mediatek/mt8183/mt8183-dai-hostless.c | 118 ++ sound/soc/mediatek/mt8183/mt8183-dai-i2s.c | 1040 ++++++++++ sound/soc/mediatek/mt8183/mt8183-dai-pcm.c | 318 ++++ sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | 639 +++++++ .../mediatek/mt8183/mt8183-interconnection.h | 33 + sound/soc/mediatek/mt8183/mt8183-reg.h | 1666 +++++++++++++++++ 14 files changed, 6333 insertions(+) create mode 100644 sound/soc/mediatek/mt8183/Makefile create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-clk.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-clk.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-common.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-pcm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-adda.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-hostless.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-i2s.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-pcm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-tdm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-interconnection.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-reg.h diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index e731d40afcce..8bb360ee7234 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -105,3 +105,13 @@ config SND_SOC_MT8173_RT5650_RT5676 with the RT5650 and RT5676 codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MT8183 + tristate "ASoC support for Mediatek MT8183 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for Mediatek MT8183 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3bb2c47532f4..76032cae6d51 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ +obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile new file mode 100644 index 000000000000..f3ee6ac98fe8 --- /dev/null +++ b/sound/soc/mediatek/mt8183/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt8183-afe-objs := \ + mt8183-afe-pcm.o \ + mt8183-afe-clk.o \ + mt8183-dai-i2s.o \ + mt8183-dai-tdm.o \ + mt8183-dai-pcm.o \ + mt8183-dai-hostless.o \ + mt8183-dai-adda.o + +obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c new file mode 100644 index 000000000000..f523ad103acc --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8183-afe-clk.c -- Mediatek 8183 afe clock ctrl +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include + +#include "mt8183-afe-common.h" +#include "mt8183-afe-clk.h" +#include "mt8183-reg.h" + +enum { + CLK_AFE = 0, + CLK_TML, + CLK_APLL22M, + CLK_APLL24M, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + CLK_I2S1_BCLK_SW, + CLK_I2S2_BCLK_SW, + CLK_I2S3_BCLK_SW, + CLK_I2S4_BCLK_SW, + CLK_INFRA_SYS_AUDIO, + CLK_MUX_AUDIO, + CLK_MUX_AUDIOINTBUS, + CLK_TOP_SYSPLL_D2_D4, + /* apll related mux */ + CLK_TOP_MUX_AUD_1, + CLK_TOP_APLL1_CK, + CLK_TOP_MUX_AUD_2, + CLK_TOP_APLL2_CK, + CLK_TOP_MUX_AUD_ENG1, + CLK_TOP_APLL1_D8, + CLK_TOP_MUX_AUD_ENG2, + CLK_TOP_APLL2_D8, + CLK_TOP_I2S0_M_SEL, + CLK_TOP_I2S1_M_SEL, + CLK_TOP_I2S2_M_SEL, + CLK_TOP_I2S3_M_SEL, + CLK_TOP_I2S4_M_SEL, + CLK_TOP_I2S5_M_SEL, + CLK_TOP_APLL12_DIV0, + CLK_TOP_APLL12_DIV1, + CLK_TOP_APLL12_DIV2, + CLK_TOP_APLL12_DIV3, + CLK_TOP_APLL12_DIV4, + CLK_TOP_APLL12_DIVB, + CLK_CLK26M, + CLK_NUM +}; + +static const char *aud_clks[CLK_NUM] = { + [CLK_AFE] = "aud_afe_clk", + [CLK_TML] = "aud_tml_clk", + [CLK_APLL22M] = "aud_apll22m_clk", + [CLK_APLL24M] = "aud_apll24m_clk", + [CLK_APLL1_TUNER] = "aud_apll1_tuner_clk", + [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk", + [CLK_I2S1_BCLK_SW] = "aud_i2s1_bclk_sw", + [CLK_I2S2_BCLK_SW] = "aud_i2s2_bclk_sw", + [CLK_I2S3_BCLK_SW] = "aud_i2s3_bclk_sw", + [CLK_I2S4_BCLK_SW] = "aud_i2s4_bclk_sw", + [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk", + [CLK_MUX_AUDIO] = "top_mux_audio", + [CLK_MUX_AUDIOINTBUS] = "top_mux_aud_intbus", + [CLK_TOP_SYSPLL_D2_D4] = "top_syspll_d2_d4", + [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1", + [CLK_TOP_APLL1_CK] = "top_apll1_ck", + [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2", + [CLK_TOP_APLL2_CK] = "top_apll2_ck", + [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1", + [CLK_TOP_APLL1_D8] = "top_apll1_d8", + [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2", + [CLK_TOP_APLL2_D8] = "top_apll2_d8", + [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel", + [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel", + [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel", + [CLK_TOP_I2S3_M_SEL] = "top_i2s3_m_sel", + [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel", + [CLK_TOP_I2S5_M_SEL] = "top_i2s5_m_sel", + [CLK_TOP_APLL12_DIV0] = "top_apll12_div0", + [CLK_TOP_APLL12_DIV1] = "top_apll12_div1", + [CLK_TOP_APLL12_DIV2] = "top_apll12_div2", + [CLK_TOP_APLL12_DIV3] = "top_apll12_div3", + [CLK_TOP_APLL12_DIV4] = "top_apll12_div4", + [CLK_TOP_APLL12_DIVB] = "top_apll12_divb", + [CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8183_init_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int i; + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n", + __func__, aud_clks[i], + PTR_ERR(afe_priv->clk[i])); + return PTR_ERR(afe_priv->clk[i]); + } + } + + return 0; +} + +int mt8183_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret); + goto CLK_INFRA_SYS_AUDIO_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], ret); + goto CLK_MUX_AUDIO_ERR; + } + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], + aud_clks[CLK_CLK26M], ret); + goto CLK_MUX_AUDIO_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto CLK_MUX_AUDIO_INTBUS_ERR; + } + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS], + afe_priv->clk[CLK_TOP_SYSPLL_D2_D4]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[CLK_TOP_SYSPLL_D2_D4], ret); + goto CLK_MUX_AUDIO_INTBUS_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_AFE], ret); + goto CLK_AFE_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S1_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S1_BCLK_SW], ret); + goto CLK_I2S1_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S2_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S2_BCLK_SW], ret); + goto CLK_I2S2_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S3_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S3_BCLK_SW], ret); + goto CLK_I2S3_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S4_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S4_BCLK_SW], ret); + goto CLK_I2S4_BCLK_SW_ERR; + } + + return 0; + +CLK_I2S4_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]); +CLK_I2S3_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]); +CLK_I2S2_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]); +CLK_I2S1_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); +CLK_AFE_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); +CLK_MUX_AUDIO_INTBUS_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); +CLK_MUX_AUDIO_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +CLK_INFRA_SYS_AUDIO_ERR: + return ret; +} + +int mt8183_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + clk_disable_unprepare(afe_priv->clk[CLK_I2S4_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + + return 0; +} + +/* apll */ +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_1; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_TOP_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_TOP_APLL1_CK], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_1; + } + + /* 180.6336 / 8 = 22.5792MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_TOP_APLL1_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_TOP_APLL1_D8], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG1; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + } + + return 0; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG1: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1: +ERR_SELECT_CLK_TOP_MUX_AUD_1: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); +ERR_ENABLE_CLK_TOP_MUX_AUD_1: +EXIT: + return ret; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_2; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_2; + } + + /* 196.608 / 8 = 24.576MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_TOP_APLL2_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_TOP_APLL2_D8], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG2; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + } + + return 0; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG2: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2: +ERR_SELECT_CLK_TOP_MUX_AUD_2: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); +ERR_ENABLE_CLK_TOP_MUX_AUD_2: +EXIT: + return ret; +} + +int mt8183_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL22M], ret); + goto ERR_CLK_APLL22M; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto ERR_CLK_APLL1_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, + 0x0000FFF7, 0x00000832); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x1 << AFE_22M_ON_SFT); + + return 0; + +ERR_CLK_APLL1_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); +ERR_CLK_APLL22M: + return ret; +} + +void mt8183_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x0 << AFE_22M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + apll1_mux_setting(afe, false); +} + +int mt8183_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL24M], ret); + goto ERR_CLK_APLL24M; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto ERR_CLK_APLL2_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, + 0x0000FFF7, 0x00000634); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x1 << AFE_24M_ON_SFT); + + return 0; + +ERR_CLK_APLL2_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); +ERR_CLK_APLL24M: + return ret; +} + +void mt8183_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x0 << AFE_24M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + apll2_mux_setting(afe, false); +} + +int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8183_APLL1) ? 180633600 : 196608000; +} + +int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8183_APLL2 : MT8183_APLL1; +} + +int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8183_APLL1; + else + return MT8183_APLL2; +} + +/* mck */ +struct mt8183_mck_div { + int m_sel_id; + int div_clk_id; +}; + +static const struct mt8183_mck_div mck_div[MT8183_MCK_NUM] = { + [MT8183_I2S0_MCK] = { + .m_sel_id = CLK_TOP_I2S0_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV0, + }, + [MT8183_I2S1_MCK] = { + .m_sel_id = CLK_TOP_I2S1_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV1, + }, + [MT8183_I2S2_MCK] = { + .m_sel_id = CLK_TOP_I2S2_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV2, + }, + [MT8183_I2S3_MCK] = { + .m_sel_id = CLK_TOP_I2S3_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV3, + }, + [MT8183_I2S4_MCK] = { + .m_sel_id = CLK_TOP_I2S4_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV4, + }, + [MT8183_I2S4_BCK] = { + .m_sel_id = -1, + .div_clk_id = CLK_TOP_APLL12_DIVB, + }, + [MT8183_I2S5_MCK] = { + .m_sel_id = -1, + .div_clk_id = -1, + }, +}; + +int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int apll = mt8183_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8183_APLL1 ? + CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + int ret; + + /* i2s5 mck not support */ + if (mck_id == MT8183_I2S5_MCK) + return 0; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + goto ERR_ENABLE_MCLK; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + goto ERR_SELECT_MCLK; + } + } + + /* enable div, set rate */ + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + goto ERR_ENABLE_MCLK_DIV; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], + rate, ret); + goto ERR_SET_MCLK_RATE; + return ret; + } + + return 0; + +ERR_SET_MCLK_RATE: + clk_disable_unprepare(afe_priv->clk[div_clk_id]); +ERR_ENABLE_MCLK_DIV: +ERR_SELECT_MCLK: + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +ERR_ENABLE_MCLK: + return ret; +} + +void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +} diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.h b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h new file mode 100644 index 000000000000..2c510aa80fc7 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-afe-clk.h -- Mediatek 8183 afe clock ctrl definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_AFE_CLK_H_ +#define _MT8183_AFE_CLK_H_ + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8183_APLL1 = 0, + MT8183_APLL2, +}; + +struct mtk_base_afe; + +int mt8183_init_clock(struct mtk_base_afe *afe); +int mt8183_afe_enable_clock(struct mtk_base_afe *afe); +int mt8183_afe_disable_clock(struct mtk_base_afe *afe); + +int mt8183_apll1_enable(struct mtk_base_afe *afe); +void mt8183_apll1_disable(struct mtk_base_afe *afe); + +int mt8183_apll2_enable(struct mtk_base_afe *afe); +void mt8183_apll2_disable(struct mtk_base_afe *afe); + +int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id); +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-common.h b/sound/soc/mediatek/mt8183/mt8183-afe-common.h new file mode 100644 index 000000000000..b220e7a7db7e --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-common.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-afe-common.h -- Mediatek 8183 audio driver definitions + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT_8183_AFE_COMMON_H_ +#define _MT_8183_AFE_COMMON_H_ + +#include +#include +#include +#include "../common/mtk-base-afe.h" + +enum { + MT8183_MEMIF_DL1, + MT8183_MEMIF_DL2, + MT8183_MEMIF_DL3, + MT8183_MEMIF_VUL12, + MT8183_MEMIF_VUL2, + MT8183_MEMIF_AWB, + MT8183_MEMIF_AWB2, + MT8183_MEMIF_MOD_DAI, + MT8183_MEMIF_HDMI, + MT8183_MEMIF_NUM, + MT8183_DAI_ADDA = MT8183_MEMIF_NUM, + MT8183_DAI_PCM_1, + MT8183_DAI_PCM_2, + MT8183_DAI_I2S_0, + MT8183_DAI_I2S_1, + MT8183_DAI_I2S_2, + MT8183_DAI_I2S_3, + MT8183_DAI_I2S_5, + MT8183_DAI_TDM, + MT8183_DAI_HOSTLESS_LPBK, + MT8183_DAI_HOSTLESS_SPEECH, + MT8183_DAI_NUM, +}; + +enum { + MT8183_IRQ_0, + MT8183_IRQ_1, + MT8183_IRQ_2, + MT8183_IRQ_3, + MT8183_IRQ_4, + MT8183_IRQ_5, + MT8183_IRQ_6, + MT8183_IRQ_7, + MT8183_IRQ_8, /* hw bundle to TDM */ + MT8183_IRQ_11, + MT8183_IRQ_12, + MT8183_IRQ_NUM, +}; + +enum { + MT8183_MTKAIF_PROTOCOL_1 = 0, + MT8183_MTKAIF_PROTOCOL_2, + MT8183_MTKAIF_PROTOCOL_2_CLK_P2, +}; + +/* MCLK */ +enum { + MT8183_I2S0_MCK = 0, + MT8183_I2S1_MCK, + MT8183_I2S2_MCK, + MT8183_I2S3_MCK, + MT8183_I2S4_MCK, + MT8183_I2S4_BCK, + MT8183_I2S5_MCK, + MT8183_MCK_NUM, +}; + +struct clk; + +struct mt8183_afe_private { + struct clk **clk; + + int pm_runtime_bypass_reg_ctl; + + /* dai */ + void *dai_priv[MT8183_DAI_NUM]; + + /* adda */ + int mtkaif_protocol; + int mtkaif_calibration_ok; + int mtkaif_chosen_phase[4]; + int mtkaif_phase_cycle[4]; + int mtkaif_calibration_num_phase; + int mtkaif_dmic; + + /* mck */ + int mck_rate[MT8183_MCK_NUM]; +}; + +unsigned int mt8183_general_rate_transform(struct device *dev, + unsigned int rate); +unsigned int mt8183_rate_transform(struct device *dev, + unsigned int rate, int aud_blk); + +/* dai register */ +int mt8183_dai_adda_register(struct mtk_base_afe *afe); +int mt8183_dai_pcm_register(struct mtk_base_afe *afe); +int mt8183_dai_i2s_register(struct mtk_base_afe *afe); +int mt8183_dai_tdm_register(struct mtk_base_afe *afe); +int mt8183_dai_hostless_register(struct mtk_base_afe *afe); +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c new file mode 100644 index 000000000000..ff3111ec876c --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -0,0 +1,1237 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA SoC AFE platform driver for 8183 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include +#include +#include + +#include "mt8183-afe-common.h" +#include "mt8183-afe-clk.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_384K = 3, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_130K = 7, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 11, + MTK_AFE_RATE_96K = 12, + MTK_AFE_RATE_176K = 13, + MTK_AFE_RATE_192K = 14, + MTK_AFE_RATE_260K = 15, +}; + +enum { + MTK_AFE_DAI_MEMIF_RATE_8K = 0, + MTK_AFE_DAI_MEMIF_RATE_16K = 1, + MTK_AFE_DAI_MEMIF_RATE_32K = 2, + MTK_AFE_DAI_MEMIF_RATE_48K = 3, +}; + +enum { + MTK_AFE_PCM_RATE_8K = 0, + MTK_AFE_PCM_RATE_16K = 1, + MTK_AFE_PCM_RATE_32K = 2, + MTK_AFE_PCM_RATE_48K = 3, +}; + +unsigned int mt8183_general_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 130000: + return MTK_AFE_RATE_130K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + case 260000: + return MTK_AFE_RATE_260K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static unsigned int dai_memif_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_DAI_MEMIF_RATE_8K; + case 16000: + return MTK_AFE_DAI_MEMIF_RATE_16K; + case 32000: + return MTK_AFE_DAI_MEMIF_RATE_32K; + case 48000: + return MTK_AFE_DAI_MEMIF_RATE_48K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_DAI_MEMIF_RATE_16K); + return MTK_AFE_DAI_MEMIF_RATE_16K; + } +} + +unsigned int mt8183_rate_transform(struct device *dev, + unsigned int rate, int aud_blk) +{ + switch (aud_blk) { + case MT8183_MEMIF_MOD_DAI: + return dai_memif_rate_transform(dev, rate); + default: + return mt8183_general_rate_transform(dev, rate); + } +} + +static const struct snd_pcm_hardware mt8183_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt8183_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int id = rtd->cpu_dai->id; + + return mt8183_rate_transform(afe->dev, rate, id); +} + +static int mt8183_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt8183_general_rate_transform(afe->dev, rate); +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt8183_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8183_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL2", + .id = MT8183_MEMIF_DL2, + .playback = { + .stream_name = "DL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL3", + .id = MT8183_MEMIF_DL3, + .playback = { + .stream_name = "DL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT8183_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL2", + .id = MT8183_MEMIF_AWB, + .capture = { + .stream_name = "UL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL3", + .id = MT8183_MEMIF_VUL2, + .capture = { + .stream_name = "UL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL4", + .id = MT8183_MEMIF_AWB2, + .capture = { + .stream_name = "UL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL_MONO_1", + .id = MT8183_MEMIF_MOD_DAI, + .capture = { + .stream_name = "UL_MONO_1", + .channels_min = 1, + .channels_max = 1, + .rates = MTK_PCM_DAI_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "HDMI", + .id = MT8183_MEMIF_HDMI, + .playback = { + .stream_name = "HDMI", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +/* dma widget & routes*/ +static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN5, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5, + I_DL3_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN6, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6, + I_DL3_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN32, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN33, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN38, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN39, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN12, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN12, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt8183_memif_widgets[] = { + /* memif */ + SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)), + SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0, + memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0, + memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)), + SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0, + memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0, + memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)), + SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0, + memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0, + memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)), + SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0, + memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul_mono_1_mix, + ARRAY_SIZE(memif_ul_mono_1_mix)), +}; + +static const struct snd_soc_dapm_route mt8183_memif_routes[] = { + /* capture */ + {"UL1", NULL, "UL1_CH1"}, + {"UL1", NULL, "UL1_CH2"}, + {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL2", NULL, "UL2_CH1"}, + {"UL2", NULL, "UL2_CH2"}, + {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL3", NULL, "UL3_CH1"}, + {"UL3", NULL, "UL3_CH2"}, + {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL4", NULL, "UL4_CH1"}, + {"UL4", NULL, "UL4_CH2"}, + {"UL4_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL4_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL_MONO_1", NULL, "UL_MONO_1_CH1"}, + {"UL_MONO_1_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL_MONO_1_CH1", "ADDA_UL_CH2", "ADDA Capture"}, +}; + +static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = { + .name = "mt8183-afe-pcm-dai", +}; + +static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { + [MT8183_MEMIF_DL1] = { + .name = "DL1", + .id = MT8183_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = DL1_MODE_SFT, + .fs_maskbit = DL1_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL1_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL1_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL1_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_DL2] = { + .name = "DL2", + .id = MT8183_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = DL2_MODE_SFT, + .fs_maskbit = DL2_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_DL3] = { + .name = "DL3", + .id = MT8183_MEMIF_DL3, + .reg_ofs_base = AFE_DL3_BASE, + .reg_ofs_cur = AFE_DL3_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = DL3_MODE_SFT, + .fs_maskbit = DL3_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL3_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL3_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL3_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_VUL2] = { + .name = "VUL2", + .id = MT8183_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL2_BASE, + .reg_ofs_cur = AFE_VUL2_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = VUL2_MODE_SFT, + .fs_maskbit = VUL2_MODE_MASK, + .mono_reg = AFE_DAC_CON2, + .mono_shift = VUL2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = VUL2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_AWB] = { + .name = "AWB", + .id = MT8183_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = AWB_MODE_SFT, + .fs_maskbit = AWB_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = AWB_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = AWB_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_AWB2] = { + .name = "AWB2", + .id = MT8183_MEMIF_AWB2, + .reg_ofs_base = AFE_AWB2_BASE, + .reg_ofs_cur = AFE_AWB2_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = AWB2_MODE_SFT, + .fs_maskbit = AWB2_MODE_MASK, + .mono_reg = AFE_DAC_CON2, + .mono_shift = AWB2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = AWB2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT8183_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL_D2_BASE, + .reg_ofs_cur = AFE_VUL_D2_CUR, + .fs_reg = AFE_DAC_CON0, + .fs_shift = VUL12_MODE_SFT, + .fs_maskbit = VUL12_MODE_MASK, + .mono_reg = AFE_DAC_CON0, + .mono_shift = VUL12_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL12_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = VUL12_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_MOD_DAI] = { + .name = "MOD_DAI", + .id = MT8183_MEMIF_MOD_DAI, + .reg_ofs_base = AFE_MOD_DAI_BASE, + .reg_ofs_cur = AFE_MOD_DAI_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = MOD_DAI_MODE_SFT, + .fs_maskbit = MOD_DAI_MODE_MASK, + .mono_reg = -1, + .mono_shift = 0, + .enable_reg = AFE_DAC_CON0, + .enable_shift = MOD_DAI_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = MOD_DAI_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_HDMI] = { + .name = "HDMI", + .id = MT8183_MEMIF_HDMI, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .fs_reg = -1, + .fs_shift = -1, + .fs_maskbit = -1, + .mono_reg = -1, + .mono_shift = -1, + .enable_reg = -1, /* control in tdm for sync start */ + .enable_shift = -1, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = HDMI_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT8183_IRQ_NUM] = { + [MT8183_IRQ_0] = { + .id = MT8183_IRQ_0, + .irq_cnt_reg = AFE_IRQ_MCU_CNT0, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ0_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ0_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ0_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT8183_IRQ_1] = { + .id = MT8183_IRQ_1, + .irq_cnt_reg = AFE_IRQ_MCU_CNT1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ1_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ1_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ1_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT8183_IRQ_2] = { + .id = MT8183_IRQ_2, + .irq_cnt_reg = AFE_IRQ_MCU_CNT2, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ2_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ2_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ2_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, + [MT8183_IRQ_3] = { + .id = MT8183_IRQ_3, + .irq_cnt_reg = AFE_IRQ_MCU_CNT3, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ3_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ3_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ3_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ3_MCU_CLR_SFT, + }, + [MT8183_IRQ_4] = { + .id = MT8183_IRQ_4, + .irq_cnt_reg = AFE_IRQ_MCU_CNT4, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ4_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ4_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ4_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ4_MCU_CLR_SFT, + }, + [MT8183_IRQ_5] = { + .id = MT8183_IRQ_5, + .irq_cnt_reg = AFE_IRQ_MCU_CNT5, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ5_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ5_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ5_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ5_MCU_CLR_SFT, + }, + [MT8183_IRQ_6] = { + .id = MT8183_IRQ_6, + .irq_cnt_reg = AFE_IRQ_MCU_CNT6, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ6_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ6_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ6_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ6_MCU_CLR_SFT, + }, + [MT8183_IRQ_7] = { + .id = MT8183_IRQ_7, + .irq_cnt_reg = AFE_IRQ_MCU_CNT7, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ7_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ7_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ7_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ7_MCU_CLR_SFT, + }, + [MT8183_IRQ_8] = { + .id = MT8183_IRQ_8, + .irq_cnt_reg = AFE_IRQ_MCU_CNT8, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_fs_maskbit = -1, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ8_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ8_MCU_CLR_SFT, + }, + [MT8183_IRQ_11] = { + .id = MT8183_IRQ_11, + .irq_cnt_reg = AFE_IRQ_MCU_CNT11, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ11_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ11_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ11_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ11_MCU_CLR_SFT, + }, + [MT8183_IRQ_12] = { + .id = MT8183_IRQ_12, + .irq_cnt_reg = AFE_IRQ_MCU_CNT12, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ12_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ12_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ12_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ12_MCU_CLR_SFT, + }, +}; + +static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* these auto-gen reg has read-only bit, so put it as volatile */ + /* volatile reg cannot be cached, so cannot be set when power off */ + switch (reg) { + case AUDIO_TOP_CON0: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON1: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON3: + case AFE_DL1_CUR: + case AFE_DL1_END: + case AFE_DL2_CUR: + case AFE_DL2_END: + case AFE_AWB_END: + case AFE_AWB_CUR: + case AFE_VUL_END: + case AFE_VUL_CUR: + case AFE_MEMIF_MON0: + case AFE_MEMIF_MON1: + case AFE_MEMIF_MON2: + case AFE_MEMIF_MON3: + case AFE_MEMIF_MON4: + case AFE_MEMIF_MON5: + case AFE_MEMIF_MON6: + case AFE_MEMIF_MON7: + case AFE_MEMIF_MON8: + case AFE_MEMIF_MON9: + case AFE_ADDA_SRC_DEBUG_MON0: + case AFE_ADDA_SRC_DEBUG_MON1: + case AFE_ADDA_UL_SRC_MON0: + case AFE_ADDA_UL_SRC_MON1: + case AFE_SIDETONE_MON: + case AFE_SIDETONE_CON0: + case AFE_SIDETONE_COEFF: + case AFE_BUS_MON0: + case AFE_MRGIF_MON0: + case AFE_MRGIF_MON1: + case AFE_MRGIF_MON2: + case AFE_I2S_MON: + case AFE_DAC_MON: + case AFE_VUL2_END: + case AFE_VUL2_CUR: + case AFE_IRQ0_MCU_CNT_MON: + case AFE_IRQ6_MCU_CNT_MON: + case AFE_MOD_DAI_END: + case AFE_MOD_DAI_CUR: + case AFE_VUL_D2_END: + case AFE_VUL_D2_CUR: + case AFE_DL3_CUR: + case AFE_DL3_END: + case AFE_HDMI_OUT_CON0: + case AFE_HDMI_OUT_CUR: + case AFE_HDMI_OUT_END: + case AFE_IRQ3_MCU_CNT_MON: + case AFE_IRQ4_MCU_CNT_MON: + case AFE_IRQ_MCU_STATUS: + case AFE_IRQ_MCU_CLR: + case AFE_IRQ_MCU_MON2: + case AFE_IRQ1_MCU_CNT_MON: + case AFE_IRQ2_MCU_CNT_MON: + case AFE_IRQ1_MCU_EN_CNT_MON: + case AFE_IRQ5_MCU_CNT_MON: + case AFE_IRQ7_MCU_CNT_MON: + case AFE_GAIN1_CUR: + case AFE_GAIN2_CUR: + case AFE_SRAM_DELSEL_CON0: + case AFE_SRAM_DELSEL_CON2: + case AFE_SRAM_DELSEL_CON3: + case AFE_ASRC_2CH_CON12: + case AFE_ASRC_2CH_CON13: + case PCM_INTF_CON2: + case FPGA_CFG0: + case FPGA_CFG1: + case FPGA_CFG2: + case FPGA_CFG3: + case AUDIO_TOP_DBG_MON0: + case AUDIO_TOP_DBG_MON1: + case AFE_IRQ8_MCU_CNT_MON: + case AFE_IRQ11_MCU_CNT_MON: + case AFE_IRQ12_MCU_CNT_MON: + case AFE_CBIP_MON0: + case AFE_CBIP_SLV_MUX_MON0: + case AFE_CBIP_SLV_DECODER_MON0: + case AFE_ADDA6_SRC_DEBUG_MON0: + case AFE_ADD6A_UL_SRC_MON0: + case AFE_ADDA6_UL_SRC_MON1: + case AFE_DL1_CUR_MSB: + case AFE_DL2_CUR_MSB: + case AFE_AWB_CUR_MSB: + case AFE_VUL_CUR_MSB: + case AFE_VUL2_CUR_MSB: + case AFE_MOD_DAI_CUR_MSB: + case AFE_VUL_D2_CUR_MSB: + case AFE_DL3_CUR_MSB: + case AFE_HDMI_OUT_CUR_MSB: + case AFE_AWB2_END: + case AFE_AWB2_CUR: + case AFE_AWB2_CUR_MSB: + case AFE_ADDA_DL_SDM_FIFO_MON: + case AFE_ADDA_DL_SRC_LCH_MON: + case AFE_ADDA_DL_SRC_RCH_MON: + case AFE_ADDA_DL_SDM_OUT_MON: + case AFE_CONNSYS_I2S_MON: + case AFE_ASRC_2CH_CON0: + case AFE_ASRC_2CH_CON2: + case AFE_ASRC_2CH_CON3: + case AFE_ASRC_2CH_CON4: + case AFE_ASRC_2CH_CON5: + case AFE_ASRC_2CH_CON7: + case AFE_ASRC_2CH_CON8: + case AFE_MEMIF_MON12: + case AFE_MEMIF_MON13: + case AFE_MEMIF_MON14: + case AFE_MEMIF_MON15: + case AFE_MEMIF_MON16: + case AFE_MEMIF_MON17: + case AFE_MEMIF_MON18: + case AFE_MEMIF_MON19: + case AFE_MEMIF_MON20: + case AFE_MEMIF_MON21: + case AFE_MEMIF_MON22: + case AFE_MEMIF_MON23: + case AFE_MEMIF_MON24: + case AFE_ADDA_MTKAIF_MON0: + case AFE_ADDA_MTKAIF_MON1: + case AFE_AUD_PAD_TOP: + case AFE_GENERAL1_ASRC_2CH_CON0: + case AFE_GENERAL1_ASRC_2CH_CON2: + case AFE_GENERAL1_ASRC_2CH_CON3: + case AFE_GENERAL1_ASRC_2CH_CON4: + case AFE_GENERAL1_ASRC_2CH_CON5: + case AFE_GENERAL1_ASRC_2CH_CON7: + case AFE_GENERAL1_ASRC_2CH_CON8: + case AFE_GENERAL1_ASRC_2CH_CON12: + case AFE_GENERAL1_ASRC_2CH_CON13: + case AFE_GENERAL2_ASRC_2CH_CON0: + case AFE_GENERAL2_ASRC_2CH_CON2: + case AFE_GENERAL2_ASRC_2CH_CON3: + case AFE_GENERAL2_ASRC_2CH_CON4: + case AFE_GENERAL2_ASRC_2CH_CON5: + case AFE_GENERAL2_ASRC_2CH_CON7: + case AFE_GENERAL2_ASRC_2CH_CON8: + case AFE_GENERAL2_ASRC_2CH_CON12: + case AFE_GENERAL2_ASRC_2CH_CON13: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt8183_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .volatile_reg = mt8183_is_volatile_reg, + + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = AFE_MAX_REGISTER, + + .cache_type = REGCACHE_FLAT, +}; + +static irqreturn_t mt8183_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + unsigned int status; + unsigned int status_mcu; + unsigned int mcu_en; + int ret; + int i; + irqreturn_t irq_ret = IRQ_HANDLED; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + irq_ret = IRQ_NONE; + goto err_irq; + } + + for (i = 0; i < MT8183_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, + AFE_IRQ_MCU_CLR, + status_mcu); + + return irq_ret; +} + +static int mt8183_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + unsigned int value; + int ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0); + + ret = regmap_read_poll_timeout(afe->regmap, + AFE_DAC_MON, + value, + (value & AFE_ON_RETM_MASK_SFT) == 0, + 20, + 1 * 1000 * 1000); + if (ret) + dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret); + + /* make sure all irq status are cleared, twice intended */ + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + + /* cache only */ + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + +skip_regmap: + return mt8183_afe_disable_clock(afe); +} + +static int mt8183_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8183_afe_enable_clock(afe); + if (ret) + return ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + regcache_cache_only(afe->regmap, false); + regcache_sync(afe->regmap); + + /* enable audio sys DCM for power saving */ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29); + + /* force cpu use 8_24 format when writing 32bit data */ + regmap_update_bits(afe->regmap, AFE_MEMIF_MSB, + CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT); + + /* set all output port to 24bit */ + regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff); + regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); + +skip_regmap: + return 0; +} + +static int mt8183_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt8183_afe_component = { + .name = AFE_PCM_NAME, + .ops = &mtk_afe_pcm_ops, + .pcm_new = mtk_afe_pcm_new, + .pcm_free = mtk_afe_pcm_free, + .probe = mt8183_afe_component_probe, +}; + +static int mt8183_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt8183_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8183_memif_dai_driver); + + dai->dapm_widgets = mt8183_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8183_memif_widgets); + dai->dapm_routes = mt8183_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8183_memif_routes); + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8183_dai_adda_register, + mt8183_dai_i2s_register, + mt8183_dai_pcm_register, + mt8183_dai_tdm_register, + mt8183_dai_hostless_register, + mt8183_dai_memif_register, +}; + +static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt8183_afe_private *afe_priv; + struct device *dev; + int i, irq_id, ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + dev = afe->dev; + + /* initial audio related clock */ + ret = mt8183_init_clock(afe); + if (ret) { + dev_err(dev, "init clock error\n"); + return ret; + } + + pm_runtime_enable(dev); + + /* regmap init */ + afe->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(afe->regmap)) { + dev_err(dev, "could not get regmap from parent\n"); + return PTR_ERR(afe->regmap); + } + ret = regmap_attach_dev(dev, afe->regmap, &mt8183_afe_regmap_config); + if (ret) { + dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret); + return ret; + } + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + ret = regmap_reinit_cache(afe->regmap, &mt8183_afe_regmap_config); + if (ret) { + dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret); + return ret; + } + + pm_runtime_put_sync(&pdev->dev); + afe_priv->pm_runtime_bypass_reg_ctl = false; + + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + + pm_runtime_get_sync(&pdev->dev); + + /* init memif */ + afe->memif_size = MT8183_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = -1; + } + + afe->memif[MT8183_MEMIF_HDMI].irq_usage = MT8183_IRQ_8; + afe->memif[MT8183_MEMIF_HDMI].const_irq = 1; + + mutex_init(&afe->irq_alloc_lock); + + /* init memif */ + /* irq initialize */ + afe->irqs_size = MT8183_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (!irq_id) { + dev_err(dev, "%s no irq found\n", dev->of_node->name); + return -ENXIO; + } + ret = devm_request_irq(dev, irq_id, mt8183_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) { + dev_err(dev, "could not request_irq for asys-isr\n"); + return ret; + } + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) { + dev_warn(afe->dev, "dai register i %d fail, ret %d\n", + i, ret); + return ret; + } + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) { + dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", + ret); + return ret; + } + + afe->mtk_afe_hardware = &mt8183_afe_hardware; + afe->memif_fs = mt8183_memif_fs; + afe->irq_fs = mt8183_irq_fs; + + afe->runtime_resume = mt8183_afe_runtime_resume; + afe->runtime_suspend = mt8183_afe_runtime_suspend; + + /* register component */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt8183_afe_component, + NULL, 0); + if (ret) { + dev_warn(dev, "err_platform\n"); + return ret; + } + + ret = devm_snd_soc_register_component(afe->dev, + &mt8183_afe_pcm_dai_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) { + dev_warn(dev, "err_dai_component\n"); + return ret; + } + + return ret; +} + +static int mt8183_afe_pcm_dev_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt8183_afe_runtime_suspend(&pdev->dev); + return 0; +} + +static const struct of_device_id mt8183_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8183-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt8183_afe_pcm_dt_match); + +static const struct dev_pm_ops mt8183_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8183_afe_runtime_suspend, + mt8183_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt8183_afe_pcm_driver = { + .driver = { + .name = "mt8183-audio", + .of_match_table = mt8183_afe_pcm_dt_match, +#ifdef CONFIG_PM + .pm = &mt8183_afe_pm_ops, +#endif + }, + .probe = mt8183_afe_pcm_dev_probe, + .remove = mt8183_afe_pcm_dev_remove, +}; + +module_platform_driver(mt8183_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8183"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c new file mode 100644 index 000000000000..017d7d1d9148 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI ADDA Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 3, + MTK_AFE_ADDA_DL_RATE_22K = 4, + MTK_AFE_ADDA_DL_RATE_24K = 5, + MTK_AFE_ADDA_DL_RATE_32K = 6, + MTK_AFE_ADDA_DL_RATE_44K = 7, + MTK_AFE_ADDA_DL_RATE_48K = 8, + MTK_AFE_ADDA_DL_RATE_96K = 9, + MTK_AFE_ADDA_DL_RATE_192K = 10, +}; + +enum { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_DL_RATE_8K; + case 11025: + return MTK_AFE_ADDA_DL_RATE_11K; + case 12000: + return MTK_AFE_ADDA_DL_RATE_12K; + case 16000: + return MTK_AFE_ADDA_DL_RATE_16K; + case 22050: + return MTK_AFE_ADDA_DL_RATE_22K; + case 24000: + return MTK_AFE_ADDA_DL_RATE_24K; + case 32000: + return MTK_AFE_ADDA_DL_RATE_32K; + case 44100: + return MTK_AFE_ADDA_DL_RATE_44K; + case 48000: + return MTK_AFE_ADDA_DL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_DL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_DL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_DL_RATE_48K; + } +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_UL_RATE_48K; + } +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* update setting to dmic */ + if (afe_priv->mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x0, 0xf << 20); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x0, 0x1 << 5); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x0, 0x3 << 14); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x1 << 1, 0x1 << 1); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x3 << 21, 0x3 << 21); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +/* mtkaif dmic */ +static const char * const mt8183_adda_off_on_str[] = { + "Off", "On" +}; + +static const struct soc_enum mt8183_adda_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_adda_off_on_str), + mt8183_adda_off_on_str), +}; + +static int mt8183_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + + return 0; +} + +static int mt8183_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + afe_priv->mtkaif_dmic = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_dmic %d\n", + __func__, kcontrol->id.name, afe_priv->mtkaif_dmic); + + return 0; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_ENUM_EXT("MTKAIF_DMIC", mt8183_adda_enum[0], + mt8183_adda_dmic_get, mt8183_adda_dmic_set), +}; + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* adda */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_DL_SRC2_CON0, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"), +}; + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + /* adda enable */ + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + + /* clk */ + {"ADDA Playback", NULL, "mtkaif_26m_clk"}, + {"ADDA Playback", NULL, "aud_dac_clk"}, + {"ADDA Playback", NULL, "aud_dac_predis_clk"}, + + {"ADDA Capture", NULL, "mtkaif_26m_clk"}, + {"ADDA Capture", NULL, "aud_adc_clk"}, +}; + +static int set_mtkaif_rx(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (afe_priv->mtkaif_protocol) { + case MT8183_MTKAIF_PROTOCOL_2_CLK_P2: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38); + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39); + /* mtkaif_rxif_clkinv_adc inverse for calibration */ + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x80010000); + + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << MTKAIF_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << MTKAIF_RXIF_DELAY_CYCLE_SFT); + break; + case MT8183_MTKAIF_PROTOCOL_2: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x00010000); + break; + case MT8183_MTKAIF_PROTOCOL_1: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0); + default: + break; + } + + return 0; +} + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int dl_src2_con0 = 0; + unsigned int dl_src2_con1 = 0; + + /* clean predistortion */ + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); + + /* set sampling rate */ + dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28; + + /* set output mode */ + switch (rate) { + case 192000: + dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */ + dl_src2_con0 |= 1 << 14; + break; + case 96000: + dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */ + dl_src2_con0 |= 1 << 14; + break; + default: + dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */ + break; + } + + /* turn off mute function */ + dl_src2_con0 |= (0x03 << 11); + + /* set voice input data if input sample rate is 8k or 16k */ + if (rate == 8000 || rate == 16000) + dl_src2_con0 |= 0x01 << 5; + + /* SA suggest apply -0.3db to audio/speech path */ + dl_src2_con1 = 0xf74f0000; + + /* turn on down-link gain */ + dl_src2_con0 = dl_src2_con0 | (0x01 << 1); + + regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); + regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << ATTGAIN_CTL_SFT); + } else { + unsigned int voice_mode = 0; + unsigned int ul_src_con0 = 0; /* default value */ + + /* set mtkaif protocol */ + set_mtkaif_rx(afe); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, + AFE_ADDA_TOP_CON0, + 0x1 << 0, + 0x0 << 0); + + voice_mode = adda_ul_rate_transform(afe, rate); + + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + regmap_write(afe->regmap, AFE_ADDA_UL_SRC_CON0, ul_src_con0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8183_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8183_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c new file mode 100644 index 000000000000..1667ad352d34 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI Hostless Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include "mt8183-afe-common.h" + +/* dai component */ +static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = { + /* Hostless ADDA Loopback */ + {"ADDA_DL_CH1", "ADDA_UL_CH1", "Hostless LPBK DL"}, + {"ADDA_DL_CH1", "ADDA_UL_CH2", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH1", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH2", "Hostless LPBK DL"}, + {"Hostless LPBK UL", NULL, "ADDA Capture"}, + + /* Hostless Speech */ + {"ADDA_DL_CH1", "PCM_1_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_1_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_1_CAP_CH2", "Hostless Speech DL"}, + {"ADDA_DL_CH1", "PCM_2_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_2_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_2_CAP_CH2", "Hostless Speech DL"}, + {"PCM_1_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"}, + {"PCM_1_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"}, + {"PCM_2_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"}, + {"PCM_2_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"}, + + {"Hostless Speech UL", NULL, "PCM 1 Capture"}, + {"Hostless Speech UL", NULL, "PCM 2 Capture"}, + {"Hostless Speech UL", NULL, "ADDA Capture"}, +}; + +/* dai ops */ +static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware); +} + +static const struct snd_soc_dai_ops mtk_dai_hostless_ops = { + .startup = mtk_dai_hostless_startup, +}; + +/* dai driver */ +#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = { + { + .name = "Hostless LPBK DAI", + .id = MT8183_DAI_HOSTLESS_LPBK, + .playback = { + .stream_name = "Hostless LPBK DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless LPBK UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless Speech DAI", + .id = MT8183_DAI_HOSTLESS_SPEECH, + .playback = { + .stream_name = "Hostless Speech DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless Speech UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, +}; + +int mt8183_dai_hostless_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_hostless_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver); + + dai->dapm_routes = mtk_dai_hostless_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c new file mode 100644 index 000000000000..c25024f72e72 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -0,0 +1,1040 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include "mt8183-afe-clk.h" +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum { + I2S_FMT_EIAJ = 0, + I2S_FMT_I2S = 1, +}; + +enum { + I2S_WLEN_16_BIT = 0, + I2S_WLEN_32_BIT = 1, +}; + +enum { + I2S_HD_NORMAL = 0, + I2S_HD_LOW_JITTER = 1, +}; + +enum { + I2S1_SEL_O28_O29 = 0, + I2S1_SEL_O03_O04 = 1, +}; + +enum { + I2S_IN_PAD_CONNSYS = 0, + I2S_IN_PAD_IO_MUX = 1, +}; + +struct mtk_afe_i2s_priv { + int id; + int rate; /* for determine which apll to use */ + int low_jitter_en; + + const char *share_property_name; + int share_i2s_id; + + int mclk_id; + int mclk_rate; + int mclk_apll; +}; + +static unsigned int get_i2s_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + I2S_WLEN_16_BIT : I2S_WLEN_32_BIT; +} + +#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux" +#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux" +#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux" +#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux" +#define MTK_AFE_I2S5_KCONTROL_NAME "I2S5_HD_Mux" + +#define I2S0_HD_EN_W_NAME "I2S0_HD_EN" +#define I2S1_HD_EN_W_NAME "I2S1_HD_EN" +#define I2S2_HD_EN_W_NAME "I2S2_HD_EN" +#define I2S3_HD_EN_W_NAME "I2S3_HD_EN" +#define I2S5_HD_EN_W_NAME "I2S5_HD_EN" + +#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN" +#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN" +#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN" +#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN" +#define I2S5_MCLK_EN_W_NAME "I2S5_MCLK_EN" + +static int get_i2s_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (strncmp(name, "I2S0", 4) == 0) + return MT8183_DAI_I2S_0; + else if (strncmp(name, "I2S1", 4) == 0) + return MT8183_DAI_I2S_1; + else if (strncmp(name, "I2S2", 4) == 0) + return MT8183_DAI_I2S_2; + else if (strncmp(name, "I2S3", 4) == 0) + return MT8183_DAI_I2S_3; + else if (strncmp(name, "I2S5", 4) == 0) + return MT8183_DAI_I2S_5; + else + return -EINVAL; +} + +static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_i2s_id_by_name(afe, name); + + if (dai_id < 0) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +/* low jitter control */ +static const char * const mt8183_i2s_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static const struct soc_enum mt8183_i2s_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_i2s_hd_str), + mt8183_i2s_hd_str), +}; + +static int mt8183_i2s_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; + + return 0; +} + +static int mt8183_i2s_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->low_jitter_en = hd_en; + + return 0; +} + +static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = { + SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), +}; + +/* dai component */ +/* interconnection */ +static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN0, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN0, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN0, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN0, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN0, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN1, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN1, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN1, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN1, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN1, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN1, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN1, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN28, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN28, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN28, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN28, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN28, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN28, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN29, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN29, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN29, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN29, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN29, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN29, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN29, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN29, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN30, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN30, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN30, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN30, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN30, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN30, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN31, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN31, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN31, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN31, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN31, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN31, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN31, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN31, + I_PCM_2_CAP_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_I2S_MCLK_EN, + SUPPLY_SEQ_I2S_HD_EN, + SUPPLY_SEQ_I2S_EN, +}; + +static int mtk_apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8183_apll1_enable(afe); + else + mt8183_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8183_apll1_disable(afe); + else + mt8183_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + i2s_priv->mclk_rate = 0; + mt8183_mck_disable(afe, i2s_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch1_mix, + ARRAY_SIZE(mtk_i2s1_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch2_mix, + ARRAY_SIZE(mtk_i2s1_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch1_mix, + ARRAY_SIZE(mtk_i2s3_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch2_mix, + ARRAY_SIZE(mtk_i2s3_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S5_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch1_mix, + ARRAY_SIZE(mtk_i2s5_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S5_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch2_mix, + ARRAY_SIZE(mtk_i2s5_ch2_mix)), + + /* i2s en*/ + SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON1, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON2, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON3, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON4, I2S5_EN_SFT, 0, + NULL, 0), + /* i2s hd en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON, I2S1_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S5_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON4, I2S5_HD_EN_SFT, 0, + NULL, 0), + + /* i2s mclk en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S5_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (i2s_priv->share_i2s_id < 0) + return 0; + + return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name); +} + +static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + /* check if share i2s need hd en */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + return 0; +} + +static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + int i2s_need_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + /* choose APLL from i2s rate */ + i2s_need_apll = mt8183_get_apll_by_rate(afe, i2s_priv->rate); + + return (i2s_need_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + /* check if share i2s need mclk */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + return 0; +} + +static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + /* i2s0 */ + {"I2S0", NULL, "I2S0_EN"}, + {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s1 */ + {"I2S1_CH1", "DL1_CH1", "DL1"}, + {"I2S1_CH2", "DL1_CH2", "DL1"}, + + {"I2S1_CH1", "DL2_CH1", "DL2"}, + {"I2S1_CH2", "DL2_CH2", "DL2"}, + + {"I2S1_CH1", "DL3_CH1", "DL3"}, + {"I2S1_CH2", "DL3_CH2", "DL3"}, + + {"I2S1", NULL, "I2S1_CH1"}, + {"I2S1", NULL, "I2S1_CH2"}, + + {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S1_EN"}, + {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s2 */ + {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S2_EN"}, + {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s3 */ + {"I2S3_CH1", "DL1_CH1", "DL1"}, + {"I2S3_CH2", "DL1_CH2", "DL1"}, + + {"I2S3_CH1", "DL2_CH1", "DL2"}, + {"I2S3_CH2", "DL2_CH2", "DL2"}, + + {"I2S3_CH1", "DL3_CH1", "DL3"}, + {"I2S3_CH2", "DL3_CH2", "DL3"}, + + {"I2S3", NULL, "I2S3_CH1"}, + {"I2S3", NULL, "I2S3_CH2"}, + + {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S3_EN"}, + {"I2S3", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s5 */ + {"I2S5_CH1", "DL1_CH1", "DL1"}, + {"I2S5_CH2", "DL1_CH2", "DL1"}, + + {"I2S5_CH1", "DL2_CH1", "DL2"}, + {"I2S5_CH2", "DL2_CH2", "DL2"}, + + {"I2S5_CH1", "DL3_CH1", "DL3"}, + {"I2S5_CH2", "DL3_CH2", "DL3"}, + + {"I2S5", NULL, "I2S5_CH1"}, + {"I2S5", NULL, "I2S5_CH2"}, + + {"I2S5", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S5_EN"}, + + {"I2S5", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S5", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, +}; + +/* dai ops */ +static int mtk_dai_i2s_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + int i2s_id) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id]; + + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8183_rate_transform(afe->dev, + rate, i2s_id); + snd_pcm_format_t format = params_format(params); + unsigned int i2s_con = 0; + int ret = 0; + + dev_info(afe->dev, "%s(), id %d, rate %d, format %d\n", + __func__, + i2s_id, + rate, format); + + if (i2s_priv) + i2s_priv->rate = rate; + else + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + + switch (i2s_id) { + case MT8183_DAI_I2S_0: + regmap_update_bits(afe->regmap, AFE_DAC_CON1, + I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT); + i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_1: + i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT; + i2s_con |= rate_reg << I2S2_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_2: + i2s_con = 8 << I2S3_UPDATE_WORD_SFT; + i2s_con |= rate_reg << I2S3_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON2, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_3: + i2s_con = rate_reg << I2S4_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON3, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_5: + i2s_con = rate_reg << I2S5_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S5_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON4, + 0xffffeffe, i2s_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, i2s_id); + return -EINVAL; + } + + /* set share i2s */ + if (i2s_priv && i2s_priv->share_i2s_id >= 0) + ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); + + return ret; +} + +static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return mtk_dai_i2s_config(afe, params, dai->id); +} + +static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id]; + int apll; + int apll_rate; + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_info(afe->dev, "%s(), freq %d\n", __func__, freq); + + apll = mt8183_get_apll_by_rate(afe, freq); + apll_rate = mt8183_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + dev_warn(afe->dev, "%s(), freq > apll rate", __func__); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, "%s(), APLL cannot generate freq Hz", + __func__); + return -EINVAL; + } + + i2s_priv->mclk_rate = freq; + i2s_priv->mclk_apll = apll; + + if (i2s_priv->share_i2s_id > 0) { + struct mtk_afe_i2s_priv *share_i2s_priv; + + share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id]; + if (!share_i2s_priv) { + dev_warn(afe->dev, "%s(), share_i2s_priv == NULL", + __func__); + return -EINVAL; + } + + share_i2s_priv->mclk_rate = i2s_priv->mclk_rate; + share_i2s_priv->mclk_apll = i2s_priv->mclk_apll; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_i2s_ops = { + .hw_params = mtk_dai_i2s_hw_params, + .set_sysclk = mtk_dai_i2s_set_sysclk, +}; + +/* dai driver */ +#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "I2S0", + .id = MT8183_DAI_I2S_0, + .capture = { + .stream_name = "I2S0", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S1", + .id = MT8183_DAI_I2S_1, + .playback = { + .stream_name = "I2S1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S2", + .id = MT8183_DAI_I2S_2, + .capture = { + .stream_name = "I2S2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S3", + .id = MT8183_DAI_I2S_3, + .playback = { + .stream_name = "I2S3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S5", + .id = MT8183_DAI_I2S_5, + .playback = { + .stream_name = "I2S5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, +}; + +/* this enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S1, + DAI_I2S2, + DAI_I2S3, + DAI_I2S5, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8183_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8183_DAI_I2S_0, + .mclk_id = MT8183_I2S0_MCK, + .share_property_name = "i2s0-share", + .share_i2s_id = -1, + }, + [DAI_I2S1] = { + .id = MT8183_DAI_I2S_1, + .mclk_id = MT8183_I2S1_MCK, + .share_property_name = "i2s1-share", + .share_i2s_id = -1, + }, + [DAI_I2S2] = { + .id = MT8183_DAI_I2S_2, + .mclk_id = MT8183_I2S2_MCK, + .share_property_name = "i2s2-share", + .share_i2s_id = -1, + }, + [DAI_I2S3] = { + .id = MT8183_DAI_I2S_3, + .mclk_id = MT8183_I2S3_MCK, + .share_property_name = "i2s3-share", + .share_i2s_id = -1, + }, + [DAI_I2S5] = { + .id = MT8183_DAI_I2S_5, + .mclk_id = MT8183_I2S5_MCK, + .share_property_name = "i2s5-share", + .share_i2s_id = -1, + }, +}; + +int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + const struct device_node *of_node = afe->dev->of_node; + const char *of_str; + const char *property_name; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = afe_priv->dai_priv[mt8183_i2s_priv[i].id]; + property_name = mt8183_i2s_priv[i].share_property_name; + if (of_property_read_string(of_node, property_name, &of_str)) + continue; + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); + } + + return 0; +} + +int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = devm_kzalloc(afe->dev, + sizeof(struct mtk_afe_i2s_priv), + GFP_KERNEL); + if (!i2s_priv) + return -ENOMEM; + + memcpy(i2s_priv, &mt8183_i2s_priv[i], + sizeof(struct mtk_afe_i2s_priv)); + + afe_priv->dai_priv[mt8183_i2s_priv[i].id] = i2s_priv; + } + + return 0; +} + +int mt8183_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + + dai->controls = mtk_dai_i2s_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + ret = mt8183_dai_i2s_set_priv(afe); + if (ret) + return ret; + + /* parse share i2s */ + ret = mt8183_dai_i2s_get_share(afe); + if (ret) + return ret; + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c new file mode 100644 index 000000000000..bc3ba3228f08 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum AUD_TX_LCH_RPT { + AUD_TX_LCH_RPT_NO_REPEAT = 0, + AUD_TX_LCH_RPT_REPEAT = 1 +}; + +enum AUD_VBT_16K_MODE { + AUD_VBT_16K_MODE_DISABLE = 0, + AUD_VBT_16K_MODE_ENABLE = 1 +}; + +enum AUD_EXT_MODEM { + AUD_EXT_MODEM_SELECT_INTERNAL = 0, + AUD_EXT_MODEM_SELECT_EXTERNAL = 1 +}; + +enum AUD_PCM_SYNC_TYPE { + /* bck sync length = 1 */ + AUD_PCM_ONE_BCK_CYCLE_SYNC = 0, + /* bck sync length = PCM_INTF_CON1[9:13] */ + AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1 +}; + +enum AUD_BT_MODE { + AUD_BT_MODE_DUAL_MIC_ON_TX = 0, + AUD_BT_MODE_SINGLE_MIC_ON_TX = 1 +}; + +enum AUD_PCM_AFIFO_SRC { + /* slave mode & external modem uses different crystal */ + AUD_PCM_AFIFO_ASRC = 0, + /* slave mode & external modem uses the same crystal */ + AUD_PCM_AFIFO_AFIFO = 1 +}; + +enum AUD_PCM_CLOCK_SOURCE { + AUD_PCM_CLOCK_MASTER_MODE = 0, + AUD_PCM_CLOCK_SLAVE_MODE = 1 +}; + +enum AUD_PCM_WLEN { + AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0, + AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1 +}; + +enum AUD_PCM_MODE { + AUD_PCM_MODE_PCM_MODE_8K = 0, + AUD_PCM_MODE_PCM_MODE_16K = 1, + AUD_PCM_MODE_PCM_MODE_32K = 2, + AUD_PCM_MODE_PCM_MODE_48K = 3, +}; + +enum AUD_PCM_FMT { + AUD_PCM_FMT_I2S = 0, + AUD_PCM_FMT_EIAJ = 1, + AUD_PCM_FMT_PCM_MODE_A = 2, + AUD_PCM_FMT_PCM_MODE_B = 3 +}; + +enum AUD_BCLK_OUT_INV { + AUD_BCLK_OUT_INV_NO_INVERSE = 0, + AUD_BCLK_OUT_INV_INVERSE = 1 +}; + +enum AUD_PCM_EN { + AUD_PCM_EN_DISABLE = 0, + AUD_PCM_EN_ENABLE = 1 +}; + +/* dai component */ +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8, + I_DL2_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27, + I_DL1_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18, + I_DL2_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24, + I_DL1_CH1, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)), + + SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_INPUT("MD1_TO_AFE"), + SND_SOC_DAPM_INPUT("MD2_TO_AFE"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"), +}; + +static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { + {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"}, + + {"PCM 1 Playback", NULL, "PCM_1_EN"}, + {"PCM 2 Playback", NULL, "PCM_2_EN"}, + {"PCM 1 Capture", NULL, "PCM_1_EN"}, + {"PCM 2 Capture", NULL, "PCM_2_EN"}, + + {"AFE_TO_MD1", NULL, "PCM 2 Playback"}, + {"AFE_TO_MD2", NULL, "PCM 1 Playback"}, + {"PCM 2 Capture", NULL, "MD1_TO_AFE"}, + {"PCM 1 Capture", NULL, "MD2_TO_AFE"}, + + {"PCM_1_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_1_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_1_PB_CH4", "DL1_CH1", "DL1"}, + {"PCM_2_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_2_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_2_PB_CH4", "DL1_CH1", "DL1"}, +}; + +/* dai ops */ +static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8183_rate_transform(afe->dev, rate, dai->id); + unsigned int pcm_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n", + __func__, + dai->id, + substream->stream, + rate, + rate_reg, + dai->playback_widget->active, + dai->capture_widget->active); + + if (dai->playback_widget->active || dai->capture_widget->active) + return 0; + + switch (dai->id) { + case MT8183_DAI_PCM_1: + pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT; + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT; + pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT; + pcm_con |= 0 << PCM_SYNC_LENGTH_SFT; + pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT; + pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT; + pcm_con |= rate_reg << PCM_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + 0xfffffffe, pcm_con); + break; + case MT8183_DAI_PCM_2: + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT; + pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT; + pcm_con |= rate_reg << PCM2_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM2_INTF_CON, + 0xfffffffe, pcm_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { + .hw_params = mtk_dai_pcm_hw_params, +}; + +/* dai driver */ +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { + { + .name = "PCM 1", + .id = MT8183_DAI_PCM_1, + .playback = { + .stream_name = "PCM 1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "PCM 2", + .id = MT8183_DAI_PCM_2, + .playback = { + .stream_name = "PCM 2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, +}; + +int mt8183_dai_pcm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_pcm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); + + dai->dapm_widgets = mtk_dai_pcm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); + dai->dapm_routes = mtk_dai_pcm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c new file mode 100644 index 000000000000..8983d54a9b67 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI TDM Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-clk.h" +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +struct mtk_afe_tdm_priv { + int bck_id; + int bck_rate; + + int mclk_id; + int mclk_multiple; /* according to sample rate */ + int mclk_rate; + int mclk_apll; +}; + +enum { + TDM_WLEN_16_BIT = 1, + TDM_WLEN_32_BIT = 2, +}; + +enum { + TDM_CHANNEL_BCK_16 = 0, + TDM_CHANNEL_BCK_24 = 1, + TDM_CHANNEL_BCK_32 = 2, +}; + +enum { + TDM_CHANNEL_NUM_2 = 0, + TDM_CHANNEL_NUM_4 = 1, + TDM_CHANNEL_NUM_8 = 2, +}; + +enum { + TDM_CH_START_O30_O31 = 0, + TDM_CH_START_O32_O33, + TDM_CH_START_O34_O35, + TDM_CH_START_O36_O37, + TDM_CH_ZERO, +}; + +enum { + HDMI_BIT_WIDTH_16_BIT = 0, + HDMI_BIT_WIDTH_32_BIT = 1, +}; + +static unsigned int get_hdmi_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT; +} + +static unsigned int get_tdm_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_WLEN_16_BIT : TDM_WLEN_32_BIT; +} + +static unsigned int get_tdm_channel_bck(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32; +} + +static unsigned int get_tdm_lrck_width(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) - 1; +} + +static unsigned int get_tdm_ch(unsigned int ch) +{ + switch (ch) { + case 1: + case 2: + return TDM_CHANNEL_NUM_2; + case 3: + case 4: + return TDM_CHANNEL_NUM_4; + case 5: + case 6: + case 7: + case 8: + default: + return TDM_CHANNEL_NUM_8; + } +} + +/* interconnection */ +enum { + HDMI_CONN_CH0 = 0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static const char *const hdmi_conn_mux_map[] = { + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", +}; + +static int hdmi_conn_mux_map_value[] = { + HDMI_CONN_CH0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_0_SFT, + HDMI_O_0_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch0_mux_control = + SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_1_SFT, + HDMI_O_1_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch1_mux_control = + SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_2_SFT, + HDMI_O_2_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch2_mux_control = + SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_3_SFT, + HDMI_O_3_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch3_mux_control = + SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_4_SFT, + HDMI_O_4_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch4_mux_control = + SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_5_SFT, + HDMI_O_5_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch5_mux_control = + SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_6_SFT, + HDMI_O_6_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch6_mux_control = + SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_7_SFT, + HDMI_O_7_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch7_mux_control = + SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum); + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_TDM_MCK_EN, + SUPPLY_SEQ_TDM_BCK_EN, +}; + +static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate); + break; + case SND_SOC_DAPM_POST_PMD: + mt8183_mck_disable(afe, tdm_priv->bck_id); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + tdm_priv->mclk_rate = 0; + mt8183_mck_disable(afe, tdm_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { + SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch0_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch1_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch2_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch3_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch4_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch5_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch6_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch7_mux_control), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"), + + SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_bck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + int cur_apll; + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { + {"HDMI_CH0_MUX", "CH0", "HDMI"}, + {"HDMI_CH0_MUX", "CH1", "HDMI"}, + {"HDMI_CH0_MUX", "CH2", "HDMI"}, + {"HDMI_CH0_MUX", "CH3", "HDMI"}, + {"HDMI_CH0_MUX", "CH4", "HDMI"}, + {"HDMI_CH0_MUX", "CH5", "HDMI"}, + {"HDMI_CH0_MUX", "CH6", "HDMI"}, + {"HDMI_CH0_MUX", "CH7", "HDMI"}, + + {"HDMI_CH1_MUX", "CH0", "HDMI"}, + {"HDMI_CH1_MUX", "CH1", "HDMI"}, + {"HDMI_CH1_MUX", "CH2", "HDMI"}, + {"HDMI_CH1_MUX", "CH3", "HDMI"}, + {"HDMI_CH1_MUX", "CH4", "HDMI"}, + {"HDMI_CH1_MUX", "CH5", "HDMI"}, + {"HDMI_CH1_MUX", "CH6", "HDMI"}, + {"HDMI_CH1_MUX", "CH7", "HDMI"}, + + {"HDMI_CH2_MUX", "CH0", "HDMI"}, + {"HDMI_CH2_MUX", "CH1", "HDMI"}, + {"HDMI_CH2_MUX", "CH2", "HDMI"}, + {"HDMI_CH2_MUX", "CH3", "HDMI"}, + {"HDMI_CH2_MUX", "CH4", "HDMI"}, + {"HDMI_CH2_MUX", "CH5", "HDMI"}, + {"HDMI_CH2_MUX", "CH6", "HDMI"}, + {"HDMI_CH2_MUX", "CH7", "HDMI"}, + + {"HDMI_CH3_MUX", "CH0", "HDMI"}, + {"HDMI_CH3_MUX", "CH1", "HDMI"}, + {"HDMI_CH3_MUX", "CH2", "HDMI"}, + {"HDMI_CH3_MUX", "CH3", "HDMI"}, + {"HDMI_CH3_MUX", "CH4", "HDMI"}, + {"HDMI_CH3_MUX", "CH5", "HDMI"}, + {"HDMI_CH3_MUX", "CH6", "HDMI"}, + {"HDMI_CH3_MUX", "CH7", "HDMI"}, + + {"HDMI_CH4_MUX", "CH0", "HDMI"}, + {"HDMI_CH4_MUX", "CH1", "HDMI"}, + {"HDMI_CH4_MUX", "CH2", "HDMI"}, + {"HDMI_CH4_MUX", "CH3", "HDMI"}, + {"HDMI_CH4_MUX", "CH4", "HDMI"}, + {"HDMI_CH4_MUX", "CH5", "HDMI"}, + {"HDMI_CH4_MUX", "CH6", "HDMI"}, + {"HDMI_CH4_MUX", "CH7", "HDMI"}, + + {"HDMI_CH5_MUX", "CH0", "HDMI"}, + {"HDMI_CH5_MUX", "CH1", "HDMI"}, + {"HDMI_CH5_MUX", "CH2", "HDMI"}, + {"HDMI_CH5_MUX", "CH3", "HDMI"}, + {"HDMI_CH5_MUX", "CH4", "HDMI"}, + {"HDMI_CH5_MUX", "CH5", "HDMI"}, + {"HDMI_CH5_MUX", "CH6", "HDMI"}, + {"HDMI_CH5_MUX", "CH7", "HDMI"}, + + {"HDMI_CH6_MUX", "CH0", "HDMI"}, + {"HDMI_CH6_MUX", "CH1", "HDMI"}, + {"HDMI_CH6_MUX", "CH2", "HDMI"}, + {"HDMI_CH6_MUX", "CH3", "HDMI"}, + {"HDMI_CH6_MUX", "CH4", "HDMI"}, + {"HDMI_CH6_MUX", "CH5", "HDMI"}, + {"HDMI_CH6_MUX", "CH6", "HDMI"}, + {"HDMI_CH6_MUX", "CH7", "HDMI"}, + + {"HDMI_CH7_MUX", "CH0", "HDMI"}, + {"HDMI_CH7_MUX", "CH1", "HDMI"}, + {"HDMI_CH7_MUX", "CH2", "HDMI"}, + {"HDMI_CH7_MUX", "CH3", "HDMI"}, + {"HDMI_CH7_MUX", "CH4", "HDMI"}, + {"HDMI_CH7_MUX", "CH5", "HDMI"}, + {"HDMI_CH7_MUX", "CH6", "HDMI"}, + {"HDMI_CH7_MUX", "CH7", "HDMI"}, + + {"TDM", NULL, "HDMI_CH0_MUX"}, + {"TDM", NULL, "HDMI_CH1_MUX"}, + {"TDM", NULL, "HDMI_CH2_MUX"}, + {"TDM", NULL, "HDMI_CH3_MUX"}, + {"TDM", NULL, "HDMI_CH4_MUX"}, + {"TDM", NULL, "HDMI_CH5_MUX"}, + {"TDM", NULL, "HDMI_CH6_MUX"}, + {"TDM", NULL, "HDMI_CH7_MUX"}, + + {"TDM", NULL, "aud_tdm_clk"}, + {"TDM", NULL, "TDM_BCK"}, + {"TDM_BCK", NULL, "TDM_MCK"}, + {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, +}; + +/* dai ops */ +static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, + struct mtk_afe_tdm_priv *tdm_priv, + int freq) +{ + int apll; + int apll_rate; + + apll = mt8183_get_apll_by_rate(afe, freq); + apll_rate = mt8183_get_apll_rate(afe, apll); + + if (!freq || freq > apll_rate) { + dev_warn(afe->dev, + "%s(), freq(%d Hz) invalid\n", __func__, freq); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, + "%s(), APLL cannot generate %d Hz", __func__, freq); + return -EINVAL; + } + + tdm_priv->mclk_rate = freq; + tdm_priv->mclk_apll = apll; + + return 0; +} + +static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int tdm_id = dai->id; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + snd_pcm_format_t format = params_format(params); + unsigned int tdm_con = 0; + + /* calculate mclk_rate, if not set explicitly */ + if (!tdm_priv->mclk_rate) { + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; + mtk_dai_tdm_cal_mclk(afe, + tdm_priv, + tdm_priv->mclk_rate); + } + + /* calculate bck */ + tdm_priv->bck_rate = rate * + channels * + snd_pcm_format_physical_width(format); + + if (tdm_priv->bck_rate > tdm_priv->mclk_rate) + dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__); + + if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0) + dev_warn(afe->dev, "%s(), bck cannot generate", __func__); + + dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n", + __func__, + tdm_id, rate, channels, format, + tdm_priv->mclk_rate, tdm_priv->bck_rate); + + /* set tdm */ + tdm_con = 1 << BCK_INVERSE_SFT; + tdm_con |= 1 << LRCK_INVERSE_SFT; + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= 1 << LEFT_ALIGN_SFT; + tdm_con |= get_tdm_wlen(format) << WLEN_SFT; + tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); + + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); + + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_CH_NUM_MASK_SFT, + channels << AFE_HDMI_OUT_CH_NUM_SFT); + + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT, + get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_SFT); + return 0; +} + +static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* enable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_ON_MASK_SFT, + 0x1 << AFE_HDMI_OUT_ON_SFT); + /* enable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* disable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0); + /* disable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_ON_MASK_SFT, + 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_info(afe->dev, "%s(), freq %d\n", __func__, freq); + + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); +} + +static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { + .hw_params = mtk_dai_tdm_hw_params, + .trigger = mtk_dai_tdm_trigger, + .set_sysclk = mtk_dai_tdm_set_sysclk, +}; + +/* dai driver */ +#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { + { + .name = "TDM", + .id = MT8183_DAI_TDM, + .playback = { + .stream_name = "TDM", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, +}; + +int mt8183_dai_tdm_register(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv; + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_tdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); + + dai->dapm_widgets = mtk_dai_tdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); + dai->dapm_routes = mtk_dai_tdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); + + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), + GFP_KERNEL); + if (!tdm_priv) + return -ENOMEM; + + tdm_priv->mclk_multiple = 128; + tdm_priv->bck_id = MT8183_I2S4_BCK; + tdm_priv->mclk_id = MT8183_I2S4_MCK; + + afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv; + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-interconnection.h b/sound/soc/mediatek/mt8183/mt8183-interconnection.h new file mode 100644 index 000000000000..6332f5f3e987 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-interconnection.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Mediatek MT8183 audio driver interconnection definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_INTERCONNECTION_H_ +#define _MT8183_INTERCONNECTION_H_ + +#define I_I2S0_CH1 0 +#define I_I2S0_CH2 1 +#define I_ADDA_UL_CH1 3 +#define I_ADDA_UL_CH2 4 +#define I_DL1_CH1 5 +#define I_DL1_CH2 6 +#define I_DL2_CH1 7 +#define I_DL2_CH2 8 +#define I_PCM_1_CAP_CH1 9 +#define I_GAIN1_OUT_CH1 10 +#define I_GAIN1_OUT_CH2 11 +#define I_GAIN2_OUT_CH1 12 +#define I_GAIN2_OUT_CH2 13 +#define I_PCM_2_CAP_CH1 14 +#define I_PCM_2_CAP_CH2 21 +#define I_PCM_1_CAP_CH2 22 +#define I_DL3_CH1 23 +#define I_DL3_CH2 24 +#define I_I2S2_CH1 25 +#define I_I2S2_CH2 26 + +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-reg.h b/sound/soc/mediatek/mt8183/mt8183-reg.h new file mode 100644 index 000000000000..e0482f2826da --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-reg.h @@ -0,0 +1,1666 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-reg.h -- Mediatek 8183 audio driver reg definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_REG_H_ +#define _MT8183_REG_H_ + +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON1 0x0004 +#define AUDIO_TOP_CON3 0x000c +#define AFE_DAC_CON0 0x0010 +#define AFE_DAC_CON1 0x0014 +#define AFE_I2S_CON 0x0018 +#define AFE_DAIBT_CON0 0x001c +#define AFE_CONN0 0x0020 +#define AFE_CONN1 0x0024 +#define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c +#define AFE_CONN4 0x0030 +#define AFE_I2S_CON1 0x0034 +#define AFE_I2S_CON2 0x0038 +#define AFE_MRGIF_CON 0x003c +#define AFE_DL1_BASE 0x0040 +#define AFE_DL1_CUR 0x0044 +#define AFE_DL1_END 0x0048 +#define AFE_I2S_CON3 0x004c +#define AFE_DL2_BASE 0x0050 +#define AFE_DL2_CUR 0x0054 +#define AFE_DL2_END 0x0058 +#define AFE_CONN5 0x005c +#define AFE_CONN_24BIT 0x006c +#define AFE_AWB_BASE 0x0070 +#define AFE_AWB_END 0x0078 +#define AFE_AWB_CUR 0x007c +#define AFE_VUL_BASE 0x0080 +#define AFE_VUL_END 0x0088 +#define AFE_VUL_CUR 0x008c +#define AFE_CONN6 0x00bc +#define AFE_MEMIF_MSB 0x00cc +#define AFE_MEMIF_MON0 0x00d0 +#define AFE_MEMIF_MON1 0x00d4 +#define AFE_MEMIF_MON2 0x00d8 +#define AFE_MEMIF_MON3 0x00dc +#define AFE_MEMIF_MON4 0x00e0 +#define AFE_MEMIF_MON5 0x00e4 +#define AFE_MEMIF_MON6 0x00e8 +#define AFE_MEMIF_MON7 0x00ec +#define AFE_MEMIF_MON8 0x00f0 +#define AFE_MEMIF_MON9 0x00f4 +#define AFE_ADDA_DL_SRC2_CON0 0x0108 +#define AFE_ADDA_DL_SRC2_CON1 0x010c +#define AFE_ADDA_UL_SRC_CON0 0x0114 +#define AFE_ADDA_UL_SRC_CON1 0x0118 +#define AFE_ADDA_TOP_CON0 0x0120 +#define AFE_ADDA_UL_DL_CON0 0x0124 +#define AFE_ADDA_SRC_DEBUG 0x012c +#define AFE_ADDA_SRC_DEBUG_MON0 0x0130 +#define AFE_ADDA_SRC_DEBUG_MON1 0x0134 +#define AFE_ADDA_UL_SRC_MON0 0x0148 +#define AFE_ADDA_UL_SRC_MON1 0x014c +#define AFE_SIDETONE_DEBUG 0x01d0 +#define AFE_SIDETONE_MON 0x01d4 +#define AFE_SINEGEN_CON2 0x01dc +#define AFE_SIDETONE_CON0 0x01e0 +#define AFE_SIDETONE_COEFF 0x01e4 +#define AFE_SIDETONE_CON1 0x01e8 +#define AFE_SIDETONE_GAIN 0x01ec +#define AFE_SINEGEN_CON0 0x01f0 +#define AFE_TOP_CON0 0x0200 +#define AFE_BUS_CFG 0x0240 +#define AFE_BUS_MON0 0x0244 +#define AFE_ADDA_PREDIS_CON0 0x0260 +#define AFE_ADDA_PREDIS_CON1 0x0264 +#define AFE_MRGIF_MON0 0x0270 +#define AFE_MRGIF_MON1 0x0274 +#define AFE_MRGIF_MON2 0x0278 +#define AFE_I2S_MON 0x027c +#define AFE_ADDA_IIR_COEF_02_01 0x0290 +#define AFE_ADDA_IIR_COEF_04_03 0x0294 +#define AFE_ADDA_IIR_COEF_06_05 0x0298 +#define AFE_ADDA_IIR_COEF_08_07 0x029c +#define AFE_ADDA_IIR_COEF_10_09 0x02a0 +#define AFE_DAC_CON2 0x02e0 +#define AFE_IRQ_MCU_CON1 0x02e4 +#define AFE_IRQ_MCU_CON2 0x02e8 +#define AFE_DAC_MON 0x02ec +#define AFE_VUL2_BASE 0x02f0 +#define AFE_VUL2_END 0x02f8 +#define AFE_VUL2_CUR 0x02fc +#define AFE_IRQ_MCU_CNT0 0x0300 +#define AFE_IRQ_MCU_CNT6 0x0304 +#define AFE_IRQ_MCU_CNT8 0x0308 +#define AFE_IRQ_MCU_EN1 0x030c +#define AFE_IRQ0_MCU_CNT_MON 0x0310 +#define AFE_IRQ6_MCU_CNT_MON 0x0314 +#define AFE_MOD_DAI_BASE 0x0330 +#define AFE_MOD_DAI_END 0x0338 +#define AFE_MOD_DAI_CUR 0x033c +#define AFE_VUL_D2_BASE 0x0350 +#define AFE_VUL_D2_END 0x0358 +#define AFE_VUL_D2_CUR 0x035c +#define AFE_DL3_BASE 0x0360 +#define AFE_DL3_CUR 0x0364 +#define AFE_DL3_END 0x0368 +#define AFE_HDMI_OUT_CON0 0x0370 +#define AFE_HDMI_OUT_BASE 0x0374 +#define AFE_HDMI_OUT_CUR 0x0378 +#define AFE_HDMI_OUT_END 0x037c +#define AFE_HDMI_CONN0 0x0390 +#define AFE_IRQ3_MCU_CNT_MON 0x0398 +#define AFE_IRQ4_MCU_CNT_MON 0x039c +#define AFE_IRQ_MCU_CON0 0x03a0 +#define AFE_IRQ_MCU_STATUS 0x03a4 +#define AFE_IRQ_MCU_CLR 0x03a8 +#define AFE_IRQ_MCU_CNT1 0x03ac +#define AFE_IRQ_MCU_CNT2 0x03b0 +#define AFE_IRQ_MCU_EN 0x03b4 +#define AFE_IRQ_MCU_MON2 0x03b8 +#define AFE_IRQ_MCU_CNT5 0x03bc +#define AFE_IRQ1_MCU_CNT_MON 0x03c0 +#define AFE_IRQ2_MCU_CNT_MON 0x03c4 +#define AFE_IRQ1_MCU_EN_CNT_MON 0x03c8 +#define AFE_IRQ5_MCU_CNT_MON 0x03cc +#define AFE_MEMIF_MINLEN 0x03d0 +#define AFE_MEMIF_MAXLEN 0x03d4 +#define AFE_MEMIF_PBUF_SIZE 0x03d8 +#define AFE_IRQ_MCU_CNT7 0x03dc +#define AFE_IRQ7_MCU_CNT_MON 0x03e0 +#define AFE_IRQ_MCU_CNT3 0x03e4 +#define AFE_IRQ_MCU_CNT4 0x03e8 +#define AFE_IRQ_MCU_CNT11 0x03ec +#define AFE_APLL1_TUNER_CFG 0x03f0 +#define AFE_APLL2_TUNER_CFG 0x03f4 +#define AFE_MEMIF_HD_MODE 0x03f8 +#define AFE_MEMIF_HDALIGN 0x03fc +#define AFE_CONN33 0x0408 +#define AFE_IRQ_MCU_CNT12 0x040c +#define AFE_GAIN1_CON0 0x0410 +#define AFE_GAIN1_CON1 0x0414 +#define AFE_GAIN1_CON2 0x0418 +#define AFE_GAIN1_CON3 0x041c +#define AFE_CONN7 0x0420 +#define AFE_GAIN1_CUR 0x0424 +#define AFE_GAIN2_CON0 0x0428 +#define AFE_GAIN2_CON1 0x042c +#define AFE_GAIN2_CON2 0x0430 +#define AFE_GAIN2_CON3 0x0434 +#define AFE_CONN8 0x0438 +#define AFE_GAIN2_CUR 0x043c +#define AFE_CONN9 0x0440 +#define AFE_CONN10 0x0444 +#define AFE_CONN11 0x0448 +#define AFE_CONN12 0x044c +#define AFE_CONN13 0x0450 +#define AFE_CONN14 0x0454 +#define AFE_CONN15 0x0458 +#define AFE_CONN16 0x045c +#define AFE_CONN17 0x0460 +#define AFE_CONN18 0x0464 +#define AFE_CONN19 0x0468 +#define AFE_CONN20 0x046c +#define AFE_CONN21 0x0470 +#define AFE_CONN22 0x0474 +#define AFE_CONN23 0x0478 +#define AFE_CONN24 0x047c +#define AFE_CONN_RS 0x0494 +#define AFE_CONN_DI 0x0498 +#define AFE_CONN25 0x04b0 +#define AFE_CONN26 0x04b4 +#define AFE_CONN27 0x04b8 +#define AFE_CONN28 0x04bc +#define AFE_CONN29 0x04c0 +#define AFE_CONN30 0x04c4 +#define AFE_CONN31 0x04c8 +#define AFE_CONN32 0x04cc +#define AFE_SRAM_DELSEL_CON0 0x04f0 +#define AFE_SRAM_DELSEL_CON2 0x04f8 +#define AFE_SRAM_DELSEL_CON3 0x04fc +#define AFE_ASRC_2CH_CON12 0x0528 +#define AFE_ASRC_2CH_CON13 0x052c +#define PCM_INTF_CON1 0x0530 +#define PCM_INTF_CON2 0x0538 +#define PCM2_INTF_CON 0x053c +#define AFE_TDM_CON1 0x0548 +#define AFE_TDM_CON2 0x054c +#define AFE_CONN34 0x0580 +#define FPGA_CFG0 0x05b0 +#define FPGA_CFG1 0x05b4 +#define FPGA_CFG2 0x05c0 +#define FPGA_CFG3 0x05c4 +#define AUDIO_TOP_DBG_CON 0x05c8 +#define AUDIO_TOP_DBG_MON0 0x05cc +#define AUDIO_TOP_DBG_MON1 0x05d0 +#define AFE_IRQ8_MCU_CNT_MON 0x05e4 +#define AFE_IRQ11_MCU_CNT_MON 0x05e8 +#define AFE_IRQ12_MCU_CNT_MON 0x05ec +#define AFE_GENERAL_REG0 0x0800 +#define AFE_GENERAL_REG1 0x0804 +#define AFE_GENERAL_REG2 0x0808 +#define AFE_GENERAL_REG3 0x080c +#define AFE_GENERAL_REG4 0x0810 +#define AFE_GENERAL_REG5 0x0814 +#define AFE_GENERAL_REG6 0x0818 +#define AFE_GENERAL_REG7 0x081c +#define AFE_GENERAL_REG8 0x0820 +#define AFE_GENERAL_REG9 0x0824 +#define AFE_GENERAL_REG10 0x0828 +#define AFE_GENERAL_REG11 0x082c +#define AFE_GENERAL_REG12 0x0830 +#define AFE_GENERAL_REG13 0x0834 +#define AFE_GENERAL_REG14 0x0838 +#define AFE_GENERAL_REG15 0x083c +#define AFE_CBIP_CFG0 0x0840 +#define AFE_CBIP_MON0 0x0844 +#define AFE_CBIP_SLV_MUX_MON0 0x0848 +#define AFE_CBIP_SLV_DECODER_MON0 0x084c +#define AFE_CONN0_1 0x0900 +#define AFE_CONN1_1 0x0904 +#define AFE_CONN2_1 0x0908 +#define AFE_CONN3_1 0x090c +#define AFE_CONN4_1 0x0910 +#define AFE_CONN5_1 0x0914 +#define AFE_CONN6_1 0x0918 +#define AFE_CONN7_1 0x091c +#define AFE_CONN8_1 0x0920 +#define AFE_CONN9_1 0x0924 +#define AFE_CONN10_1 0x0928 +#define AFE_CONN11_1 0x092c +#define AFE_CONN12_1 0x0930 +#define AFE_CONN13_1 0x0934 +#define AFE_CONN14_1 0x0938 +#define AFE_CONN15_1 0x093c +#define AFE_CONN16_1 0x0940 +#define AFE_CONN17_1 0x0944 +#define AFE_CONN18_1 0x0948 +#define AFE_CONN19_1 0x094c +#define AFE_CONN20_1 0x0950 +#define AFE_CONN21_1 0x0954 +#define AFE_CONN22_1 0x0958 +#define AFE_CONN23_1 0x095c +#define AFE_CONN24_1 0x0960 +#define AFE_CONN25_1 0x0964 +#define AFE_CONN26_1 0x0968 +#define AFE_CONN27_1 0x096c +#define AFE_CONN28_1 0x0970 +#define AFE_CONN29_1 0x0974 +#define AFE_CONN30_1 0x0978 +#define AFE_CONN31_1 0x097c +#define AFE_CONN32_1 0x0980 +#define AFE_CONN33_1 0x0984 +#define AFE_CONN34_1 0x0988 +#define AFE_CONN_RS_1 0x098c +#define AFE_CONN_DI_1 0x0990 +#define AFE_CONN_24BIT_1 0x0994 +#define AFE_CONN_REG 0x0998 +#define AFE_CONN35 0x09a0 +#define AFE_CONN36 0x09a4 +#define AFE_CONN37 0x09a8 +#define AFE_CONN38 0x09ac +#define AFE_CONN35_1 0x09b0 +#define AFE_CONN36_1 0x09b4 +#define AFE_CONN37_1 0x09b8 +#define AFE_CONN38_1 0x09bc +#define AFE_CONN39 0x09c0 +#define AFE_CONN40 0x09c4 +#define AFE_CONN41 0x09c8 +#define AFE_CONN42 0x09cc +#define AFE_CONN39_1 0x09e0 +#define AFE_CONN40_1 0x09e4 +#define AFE_CONN41_1 0x09e8 +#define AFE_CONN42_1 0x09ec +#define AFE_I2S_CON4 0x09f8 +#define AFE_ADDA6_TOP_CON0 0x0a80 +#define AFE_ADDA6_UL_SRC_CON0 0x0a84 +#define AFE_ADD6_UL_SRC_CON1 0x0a88 +#define AFE_ADDA6_SRC_DEBUG 0x0a8c +#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90 +#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0 +#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4 +#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8 +#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac +#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0 +#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4 +#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8 +#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc +#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0 +#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4 +#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8 +#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc +#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0 +#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4 +#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8 +#define AFE_ADD6A_UL_SRC_MON0 0x0ae4 +#define AFE_ADDA6_UL_SRC_MON1 0x0ae8 +#define AFE_CONN43 0x0af8 +#define AFE_CONN43_1 0x0afc +#define AFE_DL1_BASE_MSB 0x0b00 +#define AFE_DL1_CUR_MSB 0x0b04 +#define AFE_DL1_END_MSB 0x0b08 +#define AFE_DL2_BASE_MSB 0x0b10 +#define AFE_DL2_CUR_MSB 0x0b14 +#define AFE_DL2_END_MSB 0x0b18 +#define AFE_AWB_BASE_MSB 0x0b20 +#define AFE_AWB_END_MSB 0x0b28 +#define AFE_AWB_CUR_MSB 0x0b2c +#define AFE_VUL_BASE_MSB 0x0b30 +#define AFE_VUL_END_MSB 0x0b38 +#define AFE_VUL_CUR_MSB 0x0b3c +#define AFE_VUL2_BASE_MSB 0x0b50 +#define AFE_VUL2_END_MSB 0x0b58 +#define AFE_VUL2_CUR_MSB 0x0b5c +#define AFE_MOD_DAI_BASE_MSB 0x0b60 +#define AFE_MOD_DAI_END_MSB 0x0b68 +#define AFE_MOD_DAI_CUR_MSB 0x0b6c +#define AFE_VUL_D2_BASE_MSB 0x0b80 +#define AFE_VUL_D2_END_MSB 0x0b88 +#define AFE_VUL_D2_CUR_MSB 0x0b8c +#define AFE_DL3_BASE_MSB 0x0b90 +#define AFE_DL3_CUR_MSB 0x0b94 +#define AFE_DL3_END_MSB 0x0b98 +#define AFE_HDMI_OUT_BASE_MSB 0x0ba4 +#define AFE_HDMI_OUT_CUR_MSB 0x0ba8 +#define AFE_HDMI_OUT_END_MSB 0x0bac +#define AFE_AWB2_BASE 0x0bd0 +#define AFE_AWB2_END 0x0bd8 +#define AFE_AWB2_CUR 0x0bdc +#define AFE_AWB2_BASE_MSB 0x0be0 +#define AFE_AWB2_END_MSB 0x0be8 +#define AFE_AWB2_CUR_MSB 0x0bec +#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50 +#define AFE_ADDA_DL_SDM_TEST 0x0c54 +#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58 +#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c +#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60 +#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64 +#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68 +#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c +#define AFE_CONNSYS_I2S_CON 0x0c78 +#define AFE_CONNSYS_I2S_MON 0x0c7c +#define AFE_ASRC_2CH_CON0 0x0c80 +#define AFE_ASRC_2CH_CON1 0x0c84 +#define AFE_ASRC_2CH_CON2 0x0c88 +#define AFE_ASRC_2CH_CON3 0x0c8c +#define AFE_ASRC_2CH_CON4 0x0c90 +#define AFE_ASRC_2CH_CON5 0x0c94 +#define AFE_ASRC_2CH_CON6 0x0c98 +#define AFE_ASRC_2CH_CON7 0x0c9c +#define AFE_ASRC_2CH_CON8 0x0ca0 +#define AFE_ASRC_2CH_CON9 0x0ca4 +#define AFE_ASRC_2CH_CON10 0x0ca8 +#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0 +#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4 +#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8 +#define AFE_ADDA6_IIR_COEF_08_07 0x0cec +#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0 +#define AFE_ADDA_PREDIS_CON2 0x0d40 +#define AFE_ADDA_PREDIS_CON3 0x0d44 +#define AFE_MEMIF_MON12 0x0d70 +#define AFE_MEMIF_MON13 0x0d74 +#define AFE_MEMIF_MON14 0x0d78 +#define AFE_MEMIF_MON15 0x0d7c +#define AFE_MEMIF_MON16 0x0d80 +#define AFE_MEMIF_MON17 0x0d84 +#define AFE_MEMIF_MON18 0x0d88 +#define AFE_MEMIF_MON19 0x0d8c +#define AFE_MEMIF_MON20 0x0d90 +#define AFE_MEMIF_MON21 0x0d94 +#define AFE_MEMIF_MON22 0x0d98 +#define AFE_MEMIF_MON23 0x0d9c +#define AFE_MEMIF_MON24 0x0da0 +#define AFE_HD_ENGEN_ENABLE 0x0dd0 +#define AFE_ADDA_MTKAIF_CFG0 0x0e00 +#define AFE_ADDA_MTKAIF_TX_CFG1 0x0e14 +#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20 +#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24 +#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28 +#define AFE_ADDA_MTKAIF_MON0 0x0e34 +#define AFE_ADDA_MTKAIF_MON1 0x0e38 +#define AFE_AUD_PAD_TOP 0x0e40 +#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80 +#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84 +#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88 +#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c +#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90 +#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94 +#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98 +#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c +#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0 +#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4 +#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8 +#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0 +#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4 +#define GENERAL_ASRC_MODE 0x0eb8 +#define GENERAL_ASRC_EN_ON 0x0ebc +#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00 +#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04 +#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08 +#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c +#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10 +#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14 +#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18 +#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c +#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20 +#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24 +#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28 +#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30 +#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34 + +#define AFE_MAX_REGISTER AFE_GENERAL2_ASRC_2CH_CON13 +#define AFE_IRQ_STATUS_BITS 0x1fff + +/* AFE_DAC_CON0 */ +#define AWB2_ON_SFT 29 +#define AWB2_ON_MASK 0x1 +#define AWB2_ON_MASK_SFT (0x1 << 29) +#define VUL2_ON_SFT 27 +#define VUL2_ON_MASK 0x1 +#define VUL2_ON_MASK_SFT (0x1 << 27) +#define MOD_DAI_DUP_WR_SFT 26 +#define MOD_DAI_DUP_WR_MASK 0x1 +#define MOD_DAI_DUP_WR_MASK_SFT (0x1 << 26) +#define VUL12_MODE_SFT 20 +#define VUL12_MODE_MASK 0xf +#define VUL12_MODE_MASK_SFT (0xf << 20) +#define VUL12_R_MONO_SFT 11 +#define VUL12_R_MONO_MASK 0x1 +#define VUL12_R_MONO_MASK_SFT (0x1 << 11) +#define VUL12_MONO_SFT 10 +#define VUL12_MONO_MASK 0x1 +#define VUL12_MONO_MASK_SFT (0x1 << 10) +#define VUL12_ON_SFT 9 +#define VUL12_ON_MASK 0x1 +#define VUL12_ON_MASK_SFT (0x1 << 9) +#define MOD_DAI_ON_SFT 7 +#define MOD_DAI_ON_MASK 0x1 +#define MOD_DAI_ON_MASK_SFT (0x1 << 7) +#define AWB_ON_SFT 6 +#define AWB_ON_MASK 0x1 +#define AWB_ON_MASK_SFT (0x1 << 6) +#define DL3_ON_SFT 5 +#define DL3_ON_MASK 0x1 +#define DL3_ON_MASK_SFT (0x1 << 5) +#define VUL_ON_SFT 3 +#define VUL_ON_MASK 0x1 +#define VUL_ON_MASK_SFT (0x1 << 3) +#define DL2_ON_SFT 2 +#define DL2_ON_MASK 0x1 +#define DL2_ON_MASK_SFT (0x1 << 2) +#define DL1_ON_SFT 1 +#define DL1_ON_MASK 0x1 +#define DL1_ON_MASK_SFT (0x1 << 1) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_DAC_CON1 */ +#define MOD_DAI_MODE_SFT 30 +#define MOD_DAI_MODE_MASK 0x3 +#define MOD_DAI_MODE_MASK_SFT (0x3 << 30) +#define VUL_R_MONO_SFT 28 +#define VUL_R_MONO_MASK 0x1 +#define VUL_R_MONO_MASK_SFT (0x1 << 28) +#define VUL_DATA_SFT 27 +#define VUL_DATA_MASK 0x1 +#define VUL_DATA_MASK_SFT (0x1 << 27) +#define AWB_R_MONO_SFT 25 +#define AWB_R_MONO_MASK 0x1 +#define AWB_R_MONO_MASK_SFT (0x1 << 25) +#define AWB_DATA_SFT 24 +#define AWB_DATA_MASK 0x1 +#define AWB_DATA_MASK_SFT (0x1 << 24) +#define DL3_DATA_SFT 23 +#define DL3_DATA_MASK 0x1 +#define DL3_DATA_MASK_SFT (0x1 << 23) +#define DL2_DATA_SFT 22 +#define DL2_DATA_MASK 0x1 +#define DL2_DATA_MASK_SFT (0x1 << 22) +#define DL1_DATA_SFT 21 +#define DL1_DATA_MASK 0x1 +#define DL1_DATA_MASK_SFT (0x1 << 21) +#define VUL_MODE_SFT 16 +#define VUL_MODE_MASK 0xf +#define VUL_MODE_MASK_SFT (0xf << 16) +#define AWB_MODE_SFT 12 +#define AWB_MODE_MASK 0xf +#define AWB_MODE_MASK_SFT (0xf << 12) +#define I2S_MODE_SFT 8 +#define I2S_MODE_MASK 0xf +#define I2S_MODE_MASK_SFT (0xf << 8) +#define DL2_MODE_SFT 4 +#define DL2_MODE_MASK 0xf +#define DL2_MODE_MASK_SFT (0xf << 4) +#define DL1_MODE_SFT 0 +#define DL1_MODE_MASK 0xf +#define DL1_MODE_MASK_SFT (0xf << 0) + +/* AFE_DAC_CON2 */ +#define AWB2_R_MONO_SFT 21 +#define AWB2_R_MONO_MASK 0x1 +#define AWB2_R_MONO_MASK_SFT (0x1 << 21) +#define AWB2_DATA_SFT 20 +#define AWB2_DATA_MASK 0x1 +#define AWB2_DATA_MASK_SFT (0x1 << 20) +#define AWB2_MODE_SFT 16 +#define AWB2_MODE_MASK 0xf +#define AWB2_MODE_MASK_SFT (0xf << 16) +#define DL3_MODE_SFT 8 +#define DL3_MODE_MASK 0xf +#define DL3_MODE_MASK_SFT (0xf << 8) +#define VUL2_MODE_SFT 4 +#define VUL2_MODE_MASK 0xf +#define VUL2_MODE_MASK_SFT (0xf << 4) +#define VUL2_R_MONO_SFT 1 +#define VUL2_R_MONO_MASK 0x1 +#define VUL2_R_MONO_MASK_SFT (0x1 << 1) +#define VUL2_DATA_SFT 0 +#define VUL2_DATA_MASK 0x1 +#define VUL2_DATA_MASK_SFT (0x1 << 0) + +/* AFE_DAC_MON */ +#define AFE_ON_RETM_SFT 0 +#define AFE_ON_RETM_MASK 0x1 +#define AFE_ON_RETM_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK 0x1 +#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S1_HD_EN_SFT 12 +#define I2S1_HD_EN_MASK 0x1 +#define I2S1_HD_EN_MASK_SFT (0x1 << 12) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK 0x1 +#define INV_PAD_CTRL_MASK_SFT (0x1 << 7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK 0x1 +#define I2S_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK 0x1 +#define I2S_FMT_MASK_SFT (0x1 << 3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK 0x1 +#define I2S_SRC_MASK_SFT (0x1 << 2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK 0x1 +#define I2S_WLEN_MASK_SFT (0x1 << 1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK 0x1 +#define I2S_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON1 */ +#define I2S2_LR_SWAP_SFT 31 +#define I2S2_LR_SWAP_MASK 0x1 +#define I2S2_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S2_SEL_O19_O20_SFT 18 +#define I2S2_SEL_O19_O20_MASK 0x1 +#define I2S2_SEL_O19_O20_MASK_SFT (0x1 << 18) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S2_SEL_O03_O04_SFT 16 +#define I2S2_SEL_O03_O04_MASK 0x1 +#define I2S2_SEL_O03_O04_MASK_SFT (0x1 << 16) +#define I2S2_32BIT_EN_SFT 13 +#define I2S2_32BIT_EN_MASK 0x1 +#define I2S2_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S2_HD_EN_SFT 12 +#define I2S2_HD_EN_MASK 0x1 +#define I2S2_HD_EN_MASK_SFT (0x1 << 12) +#define I2S2_OUT_MODE_SFT 8 +#define I2S2_OUT_MODE_MASK 0xf +#define I2S2_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S2_FMT_SFT 3 +#define I2S2_FMT_MASK 0x1 +#define I2S2_FMT_MASK_SFT (0x1 << 3) +#define I2S2_WLEN_SFT 1 +#define I2S2_WLEN_MASK 0x1 +#define I2S2_WLEN_MASK_SFT (0x1 << 1) +#define I2S2_EN_SFT 0 +#define I2S2_EN_MASK 0x1 +#define I2S2_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON2 */ +#define I2S3_LR_SWAP_SFT 31 +#define I2S3_LR_SWAP_MASK 0x1 +#define I2S3_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S3_UPDATE_WORD_SFT 24 +#define I2S3_UPDATE_WORD_MASK 0x1f +#define I2S3_UPDATE_WORD_MASK_SFT (0x1f << 24) +#define I2S3_BCK_INV_SFT 23 +#define I2S3_BCK_INV_MASK 0x1 +#define I2S3_BCK_INV_MASK_SFT (0x1 << 23) +#define I2S3_FPGA_BIT_TEST_SFT 22 +#define I2S3_FPGA_BIT_TEST_MASK 0x1 +#define I2S3_FPGA_BIT_TEST_MASK_SFT (0x1 << 22) +#define I2S3_FPGA_BIT_SFT 21 +#define I2S3_FPGA_BIT_MASK 0x1 +#define I2S3_FPGA_BIT_MASK_SFT (0x1 << 21) +#define I2S3_LOOPBACK_SFT 20 +#define I2S3_LOOPBACK_MASK 0x1 +#define I2S3_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S3_HD_EN_SFT 12 +#define I2S3_HD_EN_MASK 0x1 +#define I2S3_HD_EN_MASK_SFT (0x1 << 12) +#define I2S3_OUT_MODE_SFT 8 +#define I2S3_OUT_MODE_MASK 0xf +#define I2S3_OUT_MODE_MASK_SFT (0xf << 8) +#define I2S3_FMT_SFT 3 +#define I2S3_FMT_MASK 0x1 +#define I2S3_FMT_MASK_SFT (0x1 << 3) +#define I2S3_WLEN_SFT 1 +#define I2S3_WLEN_MASK 0x1 +#define I2S3_WLEN_MASK_SFT (0x1 << 1) +#define I2S3_EN_SFT 0 +#define I2S3_EN_MASK 0x1 +#define I2S3_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON3 */ +#define I2S4_LR_SWAP_SFT 31 +#define I2S4_LR_SWAP_MASK 0x1 +#define I2S4_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S4_32BIT_EN_SFT 13 +#define I2S4_32BIT_EN_MASK 0x1 +#define I2S4_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S4_HD_EN_SFT 12 +#define I2S4_HD_EN_MASK 0x1 +#define I2S4_HD_EN_MASK_SFT (0x1 << 12) +#define I2S4_OUT_MODE_SFT 8 +#define I2S4_OUT_MODE_MASK 0xf +#define I2S4_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S4_FMT_SFT 3 +#define I2S4_FMT_MASK 0x1 +#define I2S4_FMT_MASK_SFT (0x1 << 3) +#define I2S4_WLEN_SFT 1 +#define I2S4_WLEN_MASK 0x1 +#define I2S4_WLEN_MASK_SFT (0x1 << 1) +#define I2S4_EN_SFT 0 +#define I2S4_EN_MASK 0x1 +#define I2S4_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON4 */ +#define I2S5_LR_SWAP_SFT 31 +#define I2S5_LR_SWAP_MASK 0x1 +#define I2S5_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S5_32BIT_EN_SFT 13 +#define I2S5_32BIT_EN_MASK 0x1 +#define I2S5_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S5_HD_EN_SFT 12 +#define I2S5_HD_EN_MASK 0x1 +#define I2S5_HD_EN_MASK_SFT (0x1 << 12) +#define I2S5_OUT_MODE_SFT 8 +#define I2S5_OUT_MODE_MASK 0xf +#define I2S5_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S5_FMT_SFT 3 +#define I2S5_FMT_MASK 0x1 +#define I2S5_FMT_MASK_SFT (0x1 << 3) +#define I2S5_WLEN_SFT 1 +#define I2S5_WLEN_MASK 0x1 +#define I2S5_WLEN_MASK_SFT (0x1 << 1) +#define I2S5_EN_SFT 0 +#define I2S5_EN_MASK 0x1 +#define I2S5_EN_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON0 */ +#define GAIN1_SAMPLE_PER_STEP_SFT 8 +#define GAIN1_SAMPLE_PER_STEP_MASK 0xff +#define GAIN1_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN1_MODE_SFT 4 +#define GAIN1_MODE_MASK 0xf +#define GAIN1_MODE_MASK_SFT (0xf << 4) +#define GAIN1_ON_SFT 0 +#define GAIN1_ON_MASK 0x1 +#define GAIN1_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON1 */ +#define GAIN1_TARGET_SFT 0 +#define GAIN1_TARGET_MASK 0xfffff +#define GAIN1_TARGET_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN2_CON0 */ +#define GAIN2_SAMPLE_PER_STEP_SFT 8 +#define GAIN2_SAMPLE_PER_STEP_MASK 0xff +#define GAIN2_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN2_MODE_SFT 4 +#define GAIN2_MODE_MASK 0xf +#define GAIN2_MODE_MASK_SFT (0xf << 4) +#define GAIN2_ON_SFT 0 +#define GAIN2_ON_MASK 0x1 +#define GAIN2_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN2_CON1 */ +#define GAIN2_TARGET_SFT 0 +#define GAIN2_TARGET_MASK 0xfffff +#define GAIN2_TARGET_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN1_CUR */ +#define AFE_GAIN1_CUR_SFT 0 +#define AFE_GAIN1_CUR_MASK 0xfffff +#define AFE_GAIN1_CUR_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN2_CUR */ +#define AFE_GAIN2_CUR_SFT 0 +#define AFE_GAIN2_CUR_MASK 0xfffff +#define AFE_GAIN2_CUR_MASK_SFT (0xfffff << 0) + +/* AFE_MEMIF_HD_MODE */ +#define AWB2_HD_SFT 28 +#define AWB2_HD_MASK 0x3 +#define AWB2_HD_MASK_SFT (0x3 << 28) +#define HDMI_HD_SFT 20 +#define HDMI_HD_MASK 0x3 +#define HDMI_HD_MASK_SFT (0x3 << 20) +#define MOD_DAI_HD_SFT 18 +#define MOD_DAI_HD_MASK 0x3 +#define MOD_DAI_HD_MASK_SFT (0x3 << 18) +#define DAI_HD_SFT 16 +#define DAI_HD_MASK 0x3 +#define DAI_HD_MASK_SFT (0x3 << 16) +#define VUL2_HD_SFT 14 +#define VUL2_HD_MASK 0x3 +#define VUL2_HD_MASK_SFT (0x3 << 14) +#define VUL12_HD_SFT 12 +#define VUL12_HD_MASK 0x3 +#define VUL12_HD_MASK_SFT (0x3 << 12) +#define VUL_HD_SFT 10 +#define VUL_HD_MASK 0x3 +#define VUL_HD_MASK_SFT (0x3 << 10) +#define AWB_HD_SFT 8 +#define AWB_HD_MASK 0x3 +#define AWB_HD_MASK_SFT (0x3 << 8) +#define DL3_HD_SFT 6 +#define DL3_HD_MASK 0x3 +#define DL3_HD_MASK_SFT (0x3 << 6) +#define DL2_HD_SFT 4 +#define DL2_HD_MASK 0x3 +#define DL2_HD_MASK_SFT (0x3 << 4) +#define DL1_HD_SFT 0 +#define DL1_HD_MASK 0x3 +#define DL1_HD_MASK_SFT (0x3 << 0) + +/* AFE_MEMIF_HDALIGN */ +#define AWB2_NORMAL_MODE_SFT 30 +#define AWB2_NORMAL_MODE_MASK 0x1 +#define AWB2_NORMAL_MODE_MASK_SFT (0x1 << 30) +#define HDMI_NORMAL_MODE_SFT 26 +#define HDMI_NORMAL_MODE_MASK 0x1 +#define HDMI_NORMAL_MODE_MASK_SFT (0x1 << 26) +#define MOD_DAI_NORMAL_MODE_SFT 25 +#define MOD_DAI_NORMAL_MODE_MASK 0x1 +#define MOD_DAI_NORMAL_MODE_MASK_SFT (0x1 << 25) +#define DAI_NORMAL_MODE_SFT 24 +#define DAI_NORMAL_MODE_MASK 0x1 +#define DAI_NORMAL_MODE_MASK_SFT (0x1 << 24) +#define VUL2_NORMAL_MODE_SFT 23 +#define VUL2_NORMAL_MODE_MASK 0x1 +#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 23) +#define VUL12_NORMAL_MODE_SFT 22 +#define VUL12_NORMAL_MODE_MASK 0x1 +#define VUL12_NORMAL_MODE_MASK_SFT (0x1 << 22) +#define VUL_NORMAL_MODE_SFT 21 +#define VUL_NORMAL_MODE_MASK 0x1 +#define VUL_NORMAL_MODE_MASK_SFT (0x1 << 21) +#define AWB_NORMAL_MODE_SFT 20 +#define AWB_NORMAL_MODE_MASK 0x1 +#define AWB_NORMAL_MODE_MASK_SFT (0x1 << 20) +#define DL3_NORMAL_MODE_SFT 19 +#define DL3_NORMAL_MODE_MASK 0x1 +#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 19) +#define DL2_NORMAL_MODE_SFT 18 +#define DL2_NORMAL_MODE_MASK 0x1 +#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 18) +#define DL1_NORMAL_MODE_SFT 16 +#define DL1_NORMAL_MODE_MASK 0x1 +#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 16) +#define RESERVED1_SFT 15 +#define RESERVED1_MASK 0x1 +#define RESERVED1_MASK_SFT (0x1 << 15) +#define AWB2_ALIGN_SFT 14 +#define AWB2_ALIGN_MASK 0x1 +#define AWB2_ALIGN_MASK_SFT (0x1 << 14) +#define HDMI_HD_ALIGN_SFT 10 +#define HDMI_HD_ALIGN_MASK 0x1 +#define HDMI_HD_ALIGN_MASK_SFT (0x1 << 10) +#define MOD_DAI_HD_ALIGN_SFT 9 +#define MOD_DAI_HD_ALIGN_MASK 0x1 +#define MOD_DAI_HD_ALIGN_MASK_SFT (0x1 << 9) +#define VUL2_HD_ALIGN_SFT 7 +#define VUL2_HD_ALIGN_MASK 0x1 +#define VUL2_HD_ALIGN_MASK_SFT (0x1 << 7) +#define VUL12_HD_ALIGN_SFT 6 +#define VUL12_HD_ALIGN_MASK 0x1 +#define VUL12_HD_ALIGN_MASK_SFT (0x1 << 6) +#define VUL_HD_ALIGN_SFT 5 +#define VUL_HD_ALIGN_MASK 0x1 +#define VUL_HD_ALIGN_MASK_SFT (0x1 << 5) +#define AWB_HD_ALIGN_SFT 4 +#define AWB_HD_ALIGN_MASK 0x1 +#define AWB_HD_ALIGN_MASK_SFT (0x1 << 4) +#define DL3_HD_ALIGN_SFT 3 +#define DL3_HD_ALIGN_MASK 0x1 +#define DL3_HD_ALIGN_MASK_SFT (0x1 << 3) +#define DL2_HD_ALIGN_SFT 2 +#define DL2_HD_ALIGN_MASK 0x1 +#define DL2_HD_ALIGN_MASK_SFT (0x1 << 2) +#define DL1_HD_ALIGN_SFT 0 +#define DL1_HD_ALIGN_MASK 0x1 +#define DL1_HD_ALIGN_MASK_SFT (0x1 << 0) + +/* PCM_INTF_CON1 */ +#define PCM_FIX_VALUE_SEL_SFT 31 +#define PCM_FIX_VALUE_SEL_MASK 0x1 +#define PCM_FIX_VALUE_SEL_MASK_SFT (0x1 << 31) +#define PCM_BUFFER_LOOPBACK_SFT 30 +#define PCM_BUFFER_LOOPBACK_MASK 0x1 +#define PCM_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30) +#define PCM_PARALLEL_LOOPBACK_SFT 29 +#define PCM_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29) +#define PCM_SERIAL_LOOPBACK_SFT 28 +#define PCM_SERIAL_LOOPBACK_MASK 0x1 +#define PCM_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28) +#define PCM_DAI_PCM_LOOPBACK_SFT 27 +#define PCM_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 27) +#define PCM_I2S_PCM_LOOPBACK_SFT 26 +#define PCM_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 26) +#define PCM_SYNC_DELSEL_SFT 25 +#define PCM_SYNC_DELSEL_MASK 0x1 +#define PCM_SYNC_DELSEL_MASK_SFT (0x1 << 25) +#define PCM_TX_LR_SWAP_SFT 24 +#define PCM_TX_LR_SWAP_MASK 0x1 +#define PCM_TX_LR_SWAP_MASK_SFT (0x1 << 24) +#define PCM_SYNC_OUT_INV_SFT 23 +#define PCM_SYNC_OUT_INV_MASK 0x1 +#define PCM_SYNC_OUT_INV_MASK_SFT (0x1 << 23) +#define PCM_BCLK_OUT_INV_SFT 22 +#define PCM_BCLK_OUT_INV_MASK 0x1 +#define PCM_BCLK_OUT_INV_MASK_SFT (0x1 << 22) +#define PCM_SYNC_IN_INV_SFT 21 +#define PCM_SYNC_IN_INV_MASK 0x1 +#define PCM_SYNC_IN_INV_MASK_SFT (0x1 << 21) +#define PCM_BCLK_IN_INV_SFT 20 +#define PCM_BCLK_IN_INV_MASK 0x1 +#define PCM_BCLK_IN_INV_MASK_SFT (0x1 << 20) +#define PCM_TX_LCH_RPT_SFT 19 +#define PCM_TX_LCH_RPT_MASK 0x1 +#define PCM_TX_LCH_RPT_MASK_SFT (0x1 << 19) +#define PCM_VBT_16K_MODE_SFT 18 +#define PCM_VBT_16K_MODE_MASK 0x1 +#define PCM_VBT_16K_MODE_MASK_SFT (0x1 << 18) +#define PCM_EXT_MODEM_SFT 17 +#define PCM_EXT_MODEM_MASK 0x1 +#define PCM_EXT_MODEM_MASK_SFT (0x1 << 17) +#define PCM_24BIT_SFT 16 +#define PCM_24BIT_MASK 0x1 +#define PCM_24BIT_MASK_SFT (0x1 << 16) +#define PCM_WLEN_SFT 14 +#define PCM_WLEN_MASK 0x3 +#define PCM_WLEN_MASK_SFT (0x3 << 14) +#define PCM_SYNC_LENGTH_SFT 9 +#define PCM_SYNC_LENGTH_MASK 0x1f +#define PCM_SYNC_LENGTH_MASK_SFT (0x1f << 9) +#define PCM_SYNC_TYPE_SFT 8 +#define PCM_SYNC_TYPE_MASK 0x1 +#define PCM_SYNC_TYPE_MASK_SFT (0x1 << 8) +#define PCM_BT_MODE_SFT 7 +#define PCM_BT_MODE_MASK 0x1 +#define PCM_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM_BYP_ASRC_SFT 6 +#define PCM_BYP_ASRC_MASK 0x1 +#define PCM_BYP_ASRC_MASK_SFT (0x1 << 6) +#define PCM_SLAVE_SFT 5 +#define PCM_SLAVE_MASK 0x1 +#define PCM_SLAVE_MASK_SFT (0x1 << 5) +#define PCM_MODE_SFT 3 +#define PCM_MODE_MASK 0x3 +#define PCM_MODE_MASK_SFT (0x3 << 3) +#define PCM_FMT_SFT 1 +#define PCM_FMT_MASK 0x3 +#define PCM_FMT_MASK_SFT (0x3 << 1) +#define PCM_EN_SFT 0 +#define PCM_EN_MASK 0x1 +#define PCM_EN_MASK_SFT (0x1 << 0) + +/* PCM_INTF_CON2 */ +#define PCM1_TX_FIFO_OV_SFT 31 +#define PCM1_TX_FIFO_OV_MASK 0x1 +#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 31) +#define PCM1_RX_FIFO_OV_SFT 30 +#define PCM1_RX_FIFO_OV_MASK 0x1 +#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 30) +#define PCM2_TX_FIFO_OV_SFT 29 +#define PCM2_TX_FIFO_OV_MASK 0x1 +#define PCM2_TX_FIFO_OV_MASK_SFT (0x1 << 29) +#define PCM2_RX_FIFO_OV_SFT 28 +#define PCM2_RX_FIFO_OV_MASK 0x1 +#define PCM2_RX_FIFO_OV_MASK_SFT (0x1 << 28) +#define PCM1_SYNC_GLITCH_SFT 27 +#define PCM1_SYNC_GLITCH_MASK 0x1 +#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 27) +#define PCM2_SYNC_GLITCH_SFT 26 +#define PCM2_SYNC_GLITCH_MASK 0x1 +#define PCM2_SYNC_GLITCH_MASK_SFT (0x1 << 26) +#define TX3_RCH_DBG_MODE_SFT 17 +#define TX3_RCH_DBG_MODE_MASK 0x1 +#define TX3_RCH_DBG_MODE_MASK_SFT (0x1 << 17) +#define PCM1_PCM2_LOOPBACK_SFT 16 +#define PCM1_PCM2_LOOPBACK_MASK 0x1 +#define PCM1_PCM2_LOOPBACK_MASK_SFT (0x1 << 16) +#define DAI_PCM_LOOPBACK_CH_SFT 14 +#define DAI_PCM_LOOPBACK_CH_MASK 0x3 +#define DAI_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 14) +#define I2S_PCM_LOOPBACK_CH_SFT 12 +#define I2S_PCM_LOOPBACK_CH_MASK 0x3 +#define I2S_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 12) +#define TX_FIX_VALUE_SFT 0 +#define TX_FIX_VALUE_MASK 0xff +#define TX_FIX_VALUE_MASK_SFT (0xff << 0) + +/* PCM2_INTF_CON */ +#define PCM2_TX_FIX_VALUE_SFT 24 +#define PCM2_TX_FIX_VALUE_MASK 0xff +#define PCM2_TX_FIX_VALUE_MASK_SFT (0xff << 24) +#define PCM2_FIX_VALUE_SEL_SFT 23 +#define PCM2_FIX_VALUE_SEL_MASK 0x1 +#define PCM2_FIX_VALUE_SEL_MASK_SFT (0x1 << 23) +#define PCM2_BUFFER_LOOPBACK_SFT 22 +#define PCM2_BUFFER_LOOPBACK_MASK 0x1 +#define PCM2_BUFFER_LOOPBACK_MASK_SFT (0x1 << 22) +#define PCM2_PARALLEL_LOOPBACK_SFT 21 +#define PCM2_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM2_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 21) +#define PCM2_SERIAL_LOOPBACK_SFT 20 +#define PCM2_SERIAL_LOOPBACK_MASK 0x1 +#define PCM2_SERIAL_LOOPBACK_MASK_SFT (0x1 << 20) +#define PCM2_DAI_PCM_LOOPBACK_SFT 19 +#define PCM2_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 19) +#define PCM2_I2S_PCM_LOOPBACK_SFT 18 +#define PCM2_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 18) +#define PCM2_SYNC_DELSEL_SFT 17 +#define PCM2_SYNC_DELSEL_MASK 0x1 +#define PCM2_SYNC_DELSEL_MASK_SFT (0x1 << 17) +#define PCM2_TX_LR_SWAP_SFT 16 +#define PCM2_TX_LR_SWAP_MASK 0x1 +#define PCM2_TX_LR_SWAP_MASK_SFT (0x1 << 16) +#define PCM2_SYNC_IN_INV_SFT 15 +#define PCM2_SYNC_IN_INV_MASK 0x1 +#define PCM2_SYNC_IN_INV_MASK_SFT (0x1 << 15) +#define PCM2_BCLK_IN_INV_SFT 14 +#define PCM2_BCLK_IN_INV_MASK 0x1 +#define PCM2_BCLK_IN_INV_MASK_SFT (0x1 << 14) +#define PCM2_TX_LCH_RPT_SFT 13 +#define PCM2_TX_LCH_RPT_MASK 0x1 +#define PCM2_TX_LCH_RPT_MASK_SFT (0x1 << 13) +#define PCM2_VBT_16K_MODE_SFT 12 +#define PCM2_VBT_16K_MODE_MASK 0x1 +#define PCM2_VBT_16K_MODE_MASK_SFT (0x1 << 12) +#define PCM2_LOOPBACK_CH_SEL_SFT 10 +#define PCM2_LOOPBACK_CH_SEL_MASK 0x3 +#define PCM2_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 10) +#define PCM2_TX2_BT_MODE_SFT 8 +#define PCM2_TX2_BT_MODE_MASK 0x1 +#define PCM2_TX2_BT_MODE_MASK_SFT (0x1 << 8) +#define PCM2_BT_MODE_SFT 7 +#define PCM2_BT_MODE_MASK 0x1 +#define PCM2_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM2_AFIFO_SFT 6 +#define PCM2_AFIFO_MASK 0x1 +#define PCM2_AFIFO_MASK_SFT (0x1 << 6) +#define PCM2_WLEN_SFT 5 +#define PCM2_WLEN_MASK 0x1 +#define PCM2_WLEN_MASK_SFT (0x1 << 5) +#define PCM2_MODE_SFT 3 +#define PCM2_MODE_MASK 0x3 +#define PCM2_MODE_MASK_SFT (0x3 << 3) +#define PCM2_FMT_SFT 1 +#define PCM2_FMT_MASK 0x3 +#define PCM2_FMT_MASK_SFT (0x3 << 1) +#define PCM2_EN_SFT 0 +#define PCM2_EN_MASK 0x1 +#define PCM2_EN_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_CFG0 */ +#define MTKAIF_RXIF_CLKINV_ADC_SFT 31 +#define MTKAIF_RXIF_CLKINV_ADC_MASK 0x1 +#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT (0x1 << 31) +#define MTKAIF_RXIF_BYPASS_SRC_SFT 17 +#define MTKAIF_RXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17) +#define MTKAIF_RXIF_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_TXIF_BYPASS_SRC_SFT 5 +#define MTKAIF_TXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5) +#define MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define MTKAIF_TXIF_8TO5_SFT 2 +#define MTKAIF_TXIF_8TO5_MASK 0x1 +#define MTKAIF_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define MTKAIF_RXIF_8TO5_SFT 1 +#define MTKAIF_RXIF_8TO5_MASK 0x1 +#define MTKAIF_RXIF_8TO5_MASK_SFT (0x1 << 1) +#define MTKAIF_IF_LOOPBACK1_SFT 0 +#define MTKAIF_IF_LOOPBACK1_MASK 0x1 +#define MTKAIF_IF_LOOPBACK1_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG2 */ +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12 +#define MTKAIF_RXIF_DELAY_CYCLE_MASK 0xf +#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12) +#define MTKAIF_RXIF_DELAY_DATA_SFT 8 +#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1 +#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) + +/* AFE_ADDA_DL_SRC2_CON0 */ +#define DL_2_INPUT_MODE_CTL_SFT 28 +#define DL_2_INPUT_MODE_CTL_MASK 0xf +#define DL_2_INPUT_MODE_CTL_MASK_SFT (0xf << 28) +#define DL_2_CH1_SATURATION_EN_CTL_SFT 27 +#define DL_2_CH1_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 27) +#define DL_2_CH2_SATURATION_EN_CTL_SFT 26 +#define DL_2_CH2_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 26) +#define DL_2_OUTPUT_SEL_CTL_SFT 24 +#define DL_2_OUTPUT_SEL_CTL_MASK 0x3 +#define DL_2_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 24) +#define DL_2_FADEIN_0START_EN_SFT 16 +#define DL_2_FADEIN_0START_EN_MASK 0x3 +#define DL_2_FADEIN_0START_EN_MASK_SFT (0x3 << 16) +#define DL_DISABLE_HW_CG_CTL_SFT 15 +#define DL_DISABLE_HW_CG_CTL_MASK 0x1 +#define DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15) +#define C_DATA_EN_SEL_CTL_PRE_SFT 14 +#define C_DATA_EN_SEL_CTL_PRE_MASK 0x1 +#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT (0x1 << 14) +#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK 0x1 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT (0x1 << 13) +#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12) +#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11) +#define DL2_ARAMPSP_CTL_PRE_SFT 9 +#define DL2_ARAMPSP_CTL_PRE_MASK 0x3 +#define DL2_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9) +#define DL_2_IIRMODE_CTL_PRE_SFT 6 +#define DL_2_IIRMODE_CTL_PRE_MASK 0x7 +#define DL_2_IIRMODE_CTL_PRE_MASK_SFT (0x7 << 6) +#define DL_2_VOICE_MODE_CTL_PRE_SFT 5 +#define DL_2_VOICE_MODE_CTL_PRE_MASK 0x1 +#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5) +#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4) +#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3) +#define DL_2_IIR_ON_CTL_PRE_SFT 2 +#define DL_2_IIR_ON_CTL_PRE_MASK 0x1 +#define DL_2_IIR_ON_CTL_PRE_MASK_SFT (0x1 << 2) +#define DL_2_GAIN_ON_CTL_PRE_SFT 1 +#define DL_2_GAIN_ON_CTL_PRE_MASK 0x1 +#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1) +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_DL_SRC2_CON1 */ +#define DL_2_GAIN_CTL_PRE_SFT 16 +#define DL_2_GAIN_CTL_PRE_MASK 0xffff +#define DL_2_GAIN_CTL_PRE_MASK_SFT (0xffff << 16) +#define DL_2_GAIN_MODE_CTL_SFT 0 +#define DL_2_GAIN_MODE_CTL_MASK 0x1 +#define DL_2_GAIN_MODE_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON0 */ +#define ULCF_CFG_EN_CTL_SFT 31 +#define ULCF_CFG_EN_CTL_MASK 0x1 +#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31) +#define UL_MODE_3P25M_CH2_CTL_SFT 22 +#define UL_MODE_3P25M_CH2_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22) +#define UL_MODE_3P25M_CH1_CTL_SFT 21 +#define UL_MODE_3P25M_CH1_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21) +#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17) +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define UL_DISABLE_HW_CG_CTL_SFT 12 +#define UL_DISABLE_HW_CG_CTL_MASK 0x1 +#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12) +#define UL_IIR_ON_TMP_CTL_SFT 10 +#define UL_IIR_ON_TMP_CTL_MASK 0x1 +#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10) +#define UL_IIRMODE_CTL_SFT 7 +#define UL_IIRMODE_CTL_MASK 0x7 +#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON1 */ +#define C_DAC_EN_CTL_SFT 27 +#define C_DAC_EN_CTL_MASK 0x1 +#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27) +#define C_MUTE_SW_CTL_SFT 26 +#define C_MUTE_SW_CTL_MASK 0x1 +#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26) +#define ASDM_SRC_SEL_CTL_SFT 25 +#define ASDM_SRC_SEL_CTL_MASK 0x1 +#define ASDM_SRC_SEL_CTL_MASK_SFT (0x1 << 25) +#define C_AMP_DIV_CH2_CTL_SFT 21 +#define C_AMP_DIV_CH2_CTL_MASK 0x7 +#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21) +#define C_FREQ_DIV_CH2_CTL_SFT 16 +#define C_FREQ_DIV_CH2_CTL_MASK 0x1f +#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16) +#define C_SINE_MODE_CH2_CTL_SFT 12 +#define C_SINE_MODE_CH2_CTL_MASK 0xf +#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12) +#define C_AMP_DIV_CH1_CTL_SFT 9 +#define C_AMP_DIV_CH1_CTL_MASK 0x7 +#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9) +#define C_FREQ_DIV_CH1_CTL_SFT 4 +#define C_FREQ_DIV_CH1_CTL_MASK 0x1f +#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4) +#define C_SINE_MODE_CH1_CTL_SFT 0 +#define C_SINE_MODE_CH1_CTL_MASK 0xf +#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0) + +/* AFE_ADDA_TOP_CON0 */ +#define C_LOOP_BACK_MODE_CTL_SFT 12 +#define C_LOOP_BACK_MODE_CTL_MASK 0xf +#define C_LOOP_BACK_MODE_CTL_MASK_SFT (0xf << 12) +#define C_EXT_ADC_CTL_SFT 0 +#define C_EXT_ADC_CTL_MASK 0x1 +#define C_EXT_ADC_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA6_UL_LR_SWAP_SFT 15 +#define AFE_ADDA6_UL_LR_SWAP_MASK 0x1 +#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_ADDA6_CKDIV_RST_SFT 14 +#define AFE_ADDA6_CKDIV_RST_MASK 0x1 +#define AFE_ADDA6_CKDIV_RST_MASK_SFT (0x1 << 14) +#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK 0x1 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT (0x1 << 13) +#define UL_FIFO_DIGMIC_TESTIN_SFT 5 +#define UL_FIFO_DIGMIC_TESTIN_MASK 0x3 +#define UL_FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 5) +#define UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4 +#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1 +#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 4) +#define ADDA_AFE_ON_SFT 0 +#define ADDA_AFE_ON_MASK 0x1 +#define ADDA_AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_SIDETONE_CON0 */ +#define R_RDY_SFT 30 +#define R_RDY_MASK 0x1 +#define R_RDY_MASK_SFT (0x1 << 30) +#define W_RDY_SFT 29 +#define W_RDY_MASK 0x1 +#define W_RDY_MASK_SFT (0x1 << 29) +#define R_W_EN_SFT 25 +#define R_W_EN_MASK 0x1 +#define R_W_EN_MASK_SFT (0x1 << 25) +#define R_W_SEL_SFT 24 +#define R_W_SEL_MASK 0x1 +#define R_W_SEL_MASK_SFT (0x1 << 24) +#define SEL_CH2_SFT 23 +#define SEL_CH2_MASK 0x1 +#define SEL_CH2_MASK_SFT (0x1 << 23) +#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16 +#define SIDE_TONE_COEFFICIENT_ADDR_MASK 0x1f +#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT (0x1f << 16) +#define SIDE_TONE_COEFFICIENT_SFT 0 +#define SIDE_TONE_COEFFICIENT_MASK 0xffff +#define SIDE_TONE_COEFFICIENT_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_COEFF */ +#define SIDE_TONE_COEFF_SFT 0 +#define SIDE_TONE_COEFF_MASK 0xffff +#define SIDE_TONE_COEFF_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_CON1 */ +#define STF_BYPASS_MODE_SFT 31 +#define STF_BYPASS_MODE_MASK 0x1 +#define STF_BYPASS_MODE_MASK_SFT (0x1 << 31) +#define STF_BYPASS_MODE_O28_O29_SFT 30 +#define STF_BYPASS_MODE_O28_O29_MASK 0x1 +#define STF_BYPASS_MODE_O28_O29_MASK_SFT (0x1 << 30) +#define STF_BYPASS_MODE_I2S4_SFT 29 +#define STF_BYPASS_MODE_I2S4_MASK 0x1 +#define STF_BYPASS_MODE_I2S4_MASK_SFT (0x1 << 29) +#define STF_BYPASS_MODE_I2S5_SFT 28 +#define STF_BYPASS_MODE_I2S5_MASK 0x1 +#define STF_BYPASS_MODE_I2S5_MASK_SFT (0x1 << 28) +#define STF_INPUT_EN_SEL_SFT 13 +#define STF_INPUT_EN_SEL_MASK 0x1 +#define STF_INPUT_EN_SEL_MASK_SFT (0x1 << 13) +#define STF_SOURCE_FROM_O19O20_SFT 12 +#define STF_SOURCE_FROM_O19O20_MASK 0x1 +#define STF_SOURCE_FROM_O19O20_MASK_SFT (0x1 << 12) +#define SIDE_TONE_ON_SFT 8 +#define SIDE_TONE_ON_MASK 0x1 +#define SIDE_TONE_ON_MASK_SFT (0x1 << 8) +#define SIDE_TONE_HALF_TAP_NUM_SFT 0 +#define SIDE_TONE_HALF_TAP_NUM_MASK 0x3f +#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT (0x3f << 0) + +/* AFE_SIDETONE_GAIN */ +#define POSITIVE_GAIN_SFT 16 +#define POSITIVE_GAIN_MASK 0x7 +#define POSITIVE_GAIN_MASK_SFT (0x7 << 16) +#define SIDE_TONE_GAIN_SFT 0 +#define SIDE_TONE_GAIN_MASK 0xffff +#define SIDE_TONE_GAIN_MASK_SFT (0xffff << 0) + +/* AFE_ADDA_DL_SDM_DCCOMP_CON */ +#define AUD_DC_COMP_EN_SFT 8 +#define AUD_DC_COMP_EN_MASK 0x1 +#define AUD_DC_COMP_EN_MASK_SFT (0x1 << 8) +#define ATTGAIN_CTL_SFT 0 +#define ATTGAIN_CTL_MASK 0x3f +#define ATTGAIN_CTL_MASK_SFT (0x3f << 0) + +/* AFE_SINEGEN_CON0 */ +#define DAC_EN_SFT 26 +#define DAC_EN_MASK 0x1 +#define DAC_EN_MASK_SFT (0x1 << 26) +#define MUTE_SW_CH2_SFT 25 +#define MUTE_SW_CH2_MASK 0x1 +#define MUTE_SW_CH2_MASK_SFT (0x1 << 25) +#define MUTE_SW_CH1_SFT 24 +#define MUTE_SW_CH1_MASK 0x1 +#define MUTE_SW_CH1_MASK_SFT (0x1 << 24) +#define SINE_MODE_CH2_SFT 20 +#define SINE_MODE_CH2_MASK 0xf +#define SINE_MODE_CH2_MASK_SFT (0xf << 20) +#define AMP_DIV_CH2_SFT 17 +#define AMP_DIV_CH2_MASK 0x7 +#define AMP_DIV_CH2_MASK_SFT (0x7 << 17) +#define FREQ_DIV_CH2_SFT 12 +#define FREQ_DIV_CH2_MASK 0x1f +#define FREQ_DIV_CH2_MASK_SFT (0x1f << 12) +#define SINE_MODE_CH1_SFT 8 +#define SINE_MODE_CH1_MASK 0xf +#define SINE_MODE_CH1_MASK_SFT (0xf << 8) +#define AMP_DIV_CH1_SFT 5 +#define AMP_DIV_CH1_MASK 0x7 +#define AMP_DIV_CH1_MASK_SFT (0x7 << 5) +#define FREQ_DIV_CH1_SFT 0 +#define FREQ_DIV_CH1_MASK 0x1f +#define FREQ_DIV_CH1_MASK_SFT (0x1f << 0) + +/* AFE_SINEGEN_CON2 */ +#define INNER_LOOP_BACK_MODE_SFT 0 +#define INNER_LOOP_BACK_MODE_MASK 0x3f +#define INNER_LOOP_BACK_MODE_MASK_SFT (0x3f << 0) + +/* AFE_MEMIF_MINLEN */ +#define HDMI_MINLEN_SFT 24 +#define HDMI_MINLEN_MASK 0xf +#define HDMI_MINLEN_MASK_SFT (0xf << 24) +#define DL3_MINLEN_SFT 12 +#define DL3_MINLEN_MASK 0xf +#define DL3_MINLEN_MASK_SFT (0xf << 12) +#define DL2_MINLEN_SFT 8 +#define DL2_MINLEN_MASK 0xf +#define DL2_MINLEN_MASK_SFT (0xf << 8) +#define DL1_DATA2_MINLEN_SFT 4 +#define DL1_DATA2_MINLEN_MASK 0xf +#define DL1_DATA2_MINLEN_MASK_SFT (0xf << 4) +#define DL1_MINLEN_SFT 0 +#define DL1_MINLEN_MASK 0xf +#define DL1_MINLEN_MASK_SFT (0xf << 0) + +/* AFE_MEMIF_MAXLEN */ +#define HDMI_MAXLEN_SFT 24 +#define HDMI_MAXLEN_MASK 0xf +#define HDMI_MAXLEN_MASK_SFT (0xf << 24) +#define DL3_MAXLEN_SFT 8 +#define DL3_MAXLEN_MASK 0xf +#define DL3_MAXLEN_MASK_SFT (0xf << 8) +#define DL2_MAXLEN_SFT 4 +#define DL2_MAXLEN_MASK 0xf +#define DL2_MAXLEN_MASK_SFT (0xf << 4) +#define DL1_MAXLEN_SFT 0 +#define DL1_MAXLEN_MASK 0x3 +#define DL1_MAXLEN_MASK_SFT (0x3 << 0) + +/* AFE_MEMIF_PBUF_SIZE */ +#define VUL12_4CH_SFT 17 +#define VUL12_4CH_MASK 0x1 +#define VUL12_4CH_MASK_SFT (0x1 << 17) +#define DL3_PBUF_SIZE_SFT 10 +#define DL3_PBUF_SIZE_MASK 0x3 +#define DL3_PBUF_SIZE_MASK_SFT (0x3 << 10) +#define HDMI_PBUF_SIZE_SFT 4 +#define HDMI_PBUF_SIZE_MASK 0x3 +#define HDMI_PBUF_SIZE_MASK_SFT (0x3 << 4) +#define DL2_PBUF_SIZE_SFT 2 +#define DL2_PBUF_SIZE_MASK 0x3 +#define DL2_PBUF_SIZE_MASK_SFT (0x3 << 2) +#define DL1_PBUF_SIZE_SFT 0 +#define DL1_PBUF_SIZE_MASK 0x3 +#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_24M_ON_SFT 1 +#define AFE_24M_ON_MASK 0x1 +#define AFE_24M_ON_MASK_SFT (0x1 << 1) +#define AFE_22M_ON_SFT 0 +#define AFE_22M_ON_MASK 0x1 +#define AFE_22M_ON_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_CON0 */ +#define IRQ12_MCU_ON_SFT 12 +#define IRQ12_MCU_ON_MASK 0x1 +#define IRQ12_MCU_ON_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_ON_SFT 11 +#define IRQ11_MCU_ON_MASK 0x1 +#define IRQ11_MCU_ON_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_ON_SFT 10 +#define IRQ10_MCU_ON_MASK 0x1 +#define IRQ10_MCU_ON_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_ON_SFT 9 +#define IRQ9_MCU_ON_MASK 0x1 +#define IRQ9_MCU_ON_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_ON_SFT 8 +#define IRQ8_MCU_ON_MASK 0x1 +#define IRQ8_MCU_ON_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_ON_SFT 7 +#define IRQ7_MCU_ON_MASK 0x1 +#define IRQ7_MCU_ON_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_ON_SFT 6 +#define IRQ6_MCU_ON_MASK 0x1 +#define IRQ6_MCU_ON_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_ON_SFT 5 +#define IRQ5_MCU_ON_MASK 0x1 +#define IRQ5_MCU_ON_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_ON_SFT 4 +#define IRQ4_MCU_ON_MASK 0x1 +#define IRQ4_MCU_ON_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_ON_SFT 3 +#define IRQ3_MCU_ON_MASK 0x1 +#define IRQ3_MCU_ON_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_ON_SFT 2 +#define IRQ2_MCU_ON_MASK 0x1 +#define IRQ2_MCU_ON_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_ON_SFT 1 +#define IRQ1_MCU_ON_MASK 0x1 +#define IRQ1_MCU_ON_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_ON_SFT 0 +#define IRQ0_MCU_ON_MASK 0x1 +#define IRQ0_MCU_ON_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_CON1 */ +#define IRQ7_MCU_MODE_SFT 28 +#define IRQ7_MCU_MODE_MASK 0xf +#define IRQ7_MCU_MODE_MASK_SFT (0xf << 28) +#define IRQ6_MCU_MODE_SFT 24 +#define IRQ6_MCU_MODE_MASK 0xf +#define IRQ6_MCU_MODE_MASK_SFT (0xf << 24) +#define IRQ5_MCU_MODE_SFT 20 +#define IRQ5_MCU_MODE_MASK 0xf +#define IRQ5_MCU_MODE_MASK_SFT (0xf << 20) +#define IRQ4_MCU_MODE_SFT 16 +#define IRQ4_MCU_MODE_MASK 0xf +#define IRQ4_MCU_MODE_MASK_SFT (0xf << 16) +#define IRQ3_MCU_MODE_SFT 12 +#define IRQ3_MCU_MODE_MASK 0xf +#define IRQ3_MCU_MODE_MASK_SFT (0xf << 12) +#define IRQ2_MCU_MODE_SFT 8 +#define IRQ2_MCU_MODE_MASK 0xf +#define IRQ2_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ1_MCU_MODE_SFT 4 +#define IRQ1_MCU_MODE_MASK 0xf +#define IRQ1_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ0_MCU_MODE_SFT 0 +#define IRQ0_MCU_MODE_MASK 0xf +#define IRQ0_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CON2 */ +#define IRQ12_MCU_MODE_SFT 4 +#define IRQ12_MCU_MODE_MASK 0xf +#define IRQ12_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ11_MCU_MODE_SFT 0 +#define IRQ11_MCU_MODE_MASK 0xf +#define IRQ11_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CLR */ +#define IRQ12_MCU_MISS_CNT_CLR_SFT 28 +#define IRQ12_MCU_MISS_CNT_CLR_MASK 0x1 +#define IRQ12_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 28) +#define IRQ11_MCU_MISS_CNT_CLR_SFT 27 +#define IRQ11_MCU_MISS_CNT_CLR_MASK 0x1 +#define IRQ11_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 27) +#define IRQ10_MCU_MISS_CLR_SFT 26 +#define IRQ10_MCU_MISS_CLR_MASK 0x1 +#define IRQ10_MCU_MISS_CLR_MASK_SFT (0x1 << 26) +#define IRQ9_MCU_MISS_CLR_SFT 25 +#define IRQ9_MCU_MISS_CLR_MASK 0x1 +#define IRQ9_MCU_MISS_CLR_MASK_SFT (0x1 << 25) +#define IRQ8_MCU_MISS_CLR_SFT 24 +#define IRQ8_MCU_MISS_CLR_MASK 0x1 +#define IRQ8_MCU_MISS_CLR_MASK_SFT (0x1 << 24) +#define IRQ7_MCU_MISS_CLR_SFT 23 +#define IRQ7_MCU_MISS_CLR_MASK 0x1 +#define IRQ7_MCU_MISS_CLR_MASK_SFT (0x1 << 23) +#define IRQ6_MCU_MISS_CLR_SFT 22 +#define IRQ6_MCU_MISS_CLR_MASK 0x1 +#define IRQ6_MCU_MISS_CLR_MASK_SFT (0x1 << 22) +#define IRQ5_MCU_MISS_CLR_SFT 21 +#define IRQ5_MCU_MISS_CLR_MASK 0x1 +#define IRQ5_MCU_MISS_CLR_MASK_SFT (0x1 << 21) +#define IRQ4_MCU_MISS_CLR_SFT 20 +#define IRQ4_MCU_MISS_CLR_MASK 0x1 +#define IRQ4_MCU_MISS_CLR_MASK_SFT (0x1 << 20) +#define IRQ3_MCU_MISS_CLR_SFT 19 +#define IRQ3_MCU_MISS_CLR_MASK 0x1 +#define IRQ3_MCU_MISS_CLR_MASK_SFT (0x1 << 19) +#define IRQ2_MCU_MISS_CLR_SFT 18 +#define IRQ2_MCU_MISS_CLR_MASK 0x1 +#define IRQ2_MCU_MISS_CLR_MASK_SFT (0x1 << 18) +#define IRQ1_MCU_MISS_CLR_SFT 17 +#define IRQ1_MCU_MISS_CLR_MASK 0x1 +#define IRQ1_MCU_MISS_CLR_MASK_SFT (0x1 << 17) +#define IRQ0_MCU_MISS_CLR_SFT 16 +#define IRQ0_MCU_MISS_CLR_MASK 0x1 +#define IRQ0_MCU_MISS_CLR_MASK_SFT (0x1 << 16) +#define IRQ12_MCU_CLR_SFT 12 +#define IRQ12_MCU_CLR_MASK 0x1 +#define IRQ12_MCU_CLR_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_CLR_SFT 11 +#define IRQ11_MCU_CLR_MASK 0x1 +#define IRQ11_MCU_CLR_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_CLR_SFT 10 +#define IRQ10_MCU_CLR_MASK 0x1 +#define IRQ10_MCU_CLR_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_CLR_SFT 9 +#define IRQ9_MCU_CLR_MASK 0x1 +#define IRQ9_MCU_CLR_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_CLR_SFT 8 +#define IRQ8_MCU_CLR_MASK 0x1 +#define IRQ8_MCU_CLR_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_CLR_SFT 7 +#define IRQ7_MCU_CLR_MASK 0x1 +#define IRQ7_MCU_CLR_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_CLR_SFT 6 +#define IRQ6_MCU_CLR_MASK 0x1 +#define IRQ6_MCU_CLR_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_CLR_SFT 5 +#define IRQ5_MCU_CLR_MASK 0x1 +#define IRQ5_MCU_CLR_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_CLR_SFT 4 +#define IRQ4_MCU_CLR_MASK 0x1 +#define IRQ4_MCU_CLR_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_CLR_SFT 3 +#define IRQ3_MCU_CLR_MASK 0x1 +#define IRQ3_MCU_CLR_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT (0x1 << 0) + +/* AFE_MEMIF_MSB */ +#define CPU_COMPACT_MODE_SFT 29 +#define CPU_COMPACT_MODE_MASK 0x1 +#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 29) +#define CPU_HD_ALIGN_SFT 28 +#define CPU_HD_ALIGN_MASK 0x1 +#define CPU_HD_ALIGN_MASK_SFT (0x1 << 28) +#define AWB2_AXI_WR_SIGN_SFT 24 +#define AWB2_AXI_WR_SIGN_MASK 0x1 +#define AWB2_AXI_WR_SIGN_MASK_SFT (0x1 << 24) +#define VUL2_AXI_WR_SIGN_SFT 22 +#define VUL2_AXI_WR_SIGN_MASK 0x1 +#define VUL2_AXI_WR_SIGN_MASK_SFT (0x1 << 22) +#define VUL12_AXI_WR_SIGN_SFT 21 +#define VUL12_AXI_WR_SIGN_MASK 0x1 +#define VUL12_AXI_WR_SIGN_MASK_SFT (0x1 << 21) +#define VUL_AXI_WR_SIGN_SFT 20 +#define VUL_AXI_WR_SIGN_MASK 0x1 +#define VUL_AXI_WR_SIGN_MASK_SFT (0x1 << 20) +#define MOD_DAI_AXI_WR_SIGN_SFT 18 +#define MOD_DAI_AXI_WR_SIGN_MASK 0x1 +#define MOD_DAI_AXI_WR_SIGN_MASK_SFT (0x1 << 18) +#define AWB_MSTR_SIGN_SFT 17 +#define AWB_MSTR_SIGN_MASK 0x1 +#define AWB_MSTR_SIGN_MASK_SFT (0x1 << 17) +#define SYSRAM_SIGN_SFT 16 +#define SYSRAM_SIGN_MASK 0x1 +#define SYSRAM_SIGN_MASK_SFT (0x1 << 16) + +/* AFE_HDMI_CONN0 */ +#define HDMI_O_7_SFT 21 +#define HDMI_O_7_MASK 0x7 +#define HDMI_O_7_MASK_SFT (0x7 << 21) +#define HDMI_O_6_SFT 18 +#define HDMI_O_6_MASK 0x7 +#define HDMI_O_6_MASK_SFT (0x7 << 18) +#define HDMI_O_5_SFT 15 +#define HDMI_O_5_MASK 0x7 +#define HDMI_O_5_MASK_SFT (0x7 << 15) +#define HDMI_O_4_SFT 12 +#define HDMI_O_4_MASK 0x7 +#define HDMI_O_4_MASK_SFT (0x7 << 12) +#define HDMI_O_3_SFT 9 +#define HDMI_O_3_MASK 0x7 +#define HDMI_O_3_MASK_SFT (0x7 << 9) +#define HDMI_O_2_SFT 6 +#define HDMI_O_2_MASK 0x7 +#define HDMI_O_2_MASK_SFT (0x7 << 6) +#define HDMI_O_1_SFT 3 +#define HDMI_O_1_MASK 0x7 +#define HDMI_O_1_MASK_SFT (0x7 << 3) +#define HDMI_O_0_SFT 0 +#define HDMI_O_0_MASK 0x7 +#define HDMI_O_0_MASK_SFT (0x7 << 0) + +/* AFE_TDM_CON1 */ +#define TDM_EN_SFT 0 +#define TDM_EN_MASK 0x1 +#define TDM_EN_MASK_SFT (0x1 << 0) +#define BCK_INVERSE_SFT 1 +#define BCK_INVERSE_MASK 0x1 +#define BCK_INVERSE_MASK_SFT (0x1 << 1) +#define LRCK_INVERSE_SFT 2 +#define LRCK_INVERSE_MASK 0x1 +#define LRCK_INVERSE_MASK_SFT (0x1 << 2) +#define DELAY_DATA_SFT 3 +#define DELAY_DATA_MASK 0x1 +#define DELAY_DATA_MASK_SFT (0x1 << 3) +#define LEFT_ALIGN_SFT 4 +#define LEFT_ALIGN_MASK 0x1 +#define LEFT_ALIGN_MASK_SFT (0x1 << 4) +#define WLEN_SFT 8 +#define WLEN_MASK 0x3 +#define WLEN_MASK_SFT (0x3 << 8) +#define CHANNEL_NUM_SFT 10 +#define CHANNEL_NUM_MASK 0x3 +#define CHANNEL_NUM_MASK_SFT (0x3 << 10) +#define CHANNEL_BCK_CYCLES_SFT 12 +#define CHANNEL_BCK_CYCLES_MASK 0x3 +#define CHANNEL_BCK_CYCLES_MASK_SFT (0x3 << 12) +#define DAC_BIT_NUM_SFT 16 +#define DAC_BIT_NUM_MASK 0x1f +#define DAC_BIT_NUM_MASK_SFT (0x1f << 16) +#define LRCK_TDM_WIDTH_SFT 24 +#define LRCK_TDM_WIDTH_MASK 0xff +#define LRCK_TDM_WIDTH_MASK_SFT (0xff << 24) + +/* AFE_TDM_CON2 */ +#define ST_CH_PAIR_SOUT0_SFT 0 +#define ST_CH_PAIR_SOUT0_MASK 0x7 +#define ST_CH_PAIR_SOUT0_MASK_SFT (0x7 << 0) +#define ST_CH_PAIR_SOUT1_SFT 4 +#define ST_CH_PAIR_SOUT1_MASK 0x7 +#define ST_CH_PAIR_SOUT1_MASK_SFT (0x7 << 4) +#define ST_CH_PAIR_SOUT2_SFT 8 +#define ST_CH_PAIR_SOUT2_MASK 0x7 +#define ST_CH_PAIR_SOUT2_MASK_SFT (0x7 << 8) +#define ST_CH_PAIR_SOUT3_SFT 12 +#define ST_CH_PAIR_SOUT3_MASK 0x7 +#define ST_CH_PAIR_SOUT3_MASK_SFT (0x7 << 12) +#define TDM_FIX_VALUE_SEL_SFT 16 +#define TDM_FIX_VALUE_SEL_MASK 0x1 +#define TDM_FIX_VALUE_SEL_MASK_SFT (0x1 << 16) +#define TDM_I2S_LOOPBACK_SFT 20 +#define TDM_I2S_LOOPBACK_MASK 0x1 +#define TDM_I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define TDM_I2S_LOOPBACK_CH_SFT 21 +#define TDM_I2S_LOOPBACK_CH_MASK 0x3 +#define TDM_I2S_LOOPBACK_CH_MASK_SFT (0x3 << 21) +#define TDM_FIX_VALUE_SFT 24 +#define TDM_FIX_VALUE_MASK 0xff +#define TDM_FIX_VALUE_MASK_SFT (0xff << 24) + +/* AFE_HDMI_OUT_CON0 */ +#define AFE_HDMI_OUT_ON_RETM_SFT 8 +#define AFE_HDMI_OUT_ON_RETM_MASK 0x1 +#define AFE_HDMI_OUT_ON_RETM_MASK_SFT (0x1 << 8) +#define AFE_HDMI_OUT_CH_NUM_SFT 4 +#define AFE_HDMI_OUT_CH_NUM_MASK 0xf +#define AFE_HDMI_OUT_CH_NUM_MASK_SFT (0xf << 4) +#define AFE_HDMI_OUT_BIT_WIDTH_SFT 1 +#define AFE_HDMI_OUT_BIT_WIDTH_MASK 0x1 +#define AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT (0x1 << 1) +#define AFE_HDMI_OUT_ON_SFT 0 +#define AFE_HDMI_OUT_ON_MASK 0x1 +#define AFE_HDMI_OUT_ON_MASK_SFT (0x1 << 0) +#endif From bfd74e65c47ff325924fe5bd90789b1db422c9cc Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:09 +0800 Subject: [PATCH 186/461] ASoC: mediatek: mt8183: add audio afe document Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- .../bindings/sound/mt8183-afe-pcm.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt diff --git a/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt new file mode 100644 index 000000000000..396ba38619f6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt @@ -0,0 +1,36 @@ +Mediatek AFE PCM controller for mt8183 + +Required properties: +- compatible = "mediatek,mt68183-audio"; +- reg: register location and size +- interrupts: should contain AFE interrupt +- power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll3_d4", + "top_clk26m_clk"; + +Example: + + afe: mt8183-afe-pcm@11220000 { + compatible = "mediatek,mt8183-audio"; + reg = <0 0x11220000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8183_POWER_DOMAIN_AUDIO>; + clocks = <&infrasys CLK_INFRA_AUDIO>, + <&infrasys CLK_INFRA_AUDIO_26M_BCLK>, + <&topckgen CLK_TOP_MUX_AUDIO>, + <&topckgen CLK_TOP_MUX_AUD_INTBUS>, + <&topckgen CLK_TOP_SYSPLL_D2_D4>, + <&clk26m>; + clock-names = "infra_sys_audio_clk", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll_d2_d4", + "top_clk26m_clk"; + }; From 6a8d4198ca80deb2f978260a096fa651229cf4a2 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:10 +0800 Subject: [PATCH 187/461] ASoC: mediatek: mt6358: add codec driver add the mt6358 codec driver. Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/mt6358.c | 2336 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/mt6358.h | 2314 ++++++++++++++++++++++++++++++++++++ 4 files changed, 4659 insertions(+) create mode 100644 sound/soc/codecs/mt6358.c create mode 100644 sound/soc/codecs/mt6358.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 71e6e123a115..55fd58015c2d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -110,6 +110,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C select SND_SOC_MT6351 if MTK_PMIC_WRAP + select SND_SOC_MT6358 if MTK_PMIC_WRAP select SND_SOC_NAU8540 if I2C select SND_SOC_NAU8810 if I2C select SND_SOC_NAU8822 if I2C @@ -1339,6 +1340,12 @@ config SND_SOC_ML26124 config SND_SOC_MT6351 tristate "MediaTek MT6351 Codec" +config SND_SOC_MT6358 + tristate "MediaTek MT6358 Codec" + help + Enable support for the platform which uses MT6358 as + external codec device. + config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9bb3346fab2f..457f9ff5a2d4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,7 @@ snd-soc-ml26124-objs := ml26124.o snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o +snd-soc-mt6358-objs := mt6358.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8822-objs := nau8822.o @@ -375,6 +376,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o +obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c new file mode 100644 index 000000000000..d4c4fee6d3d9 --- /dev/null +++ b/sound/soc/codecs/mt6358.c @@ -0,0 +1,2336 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt6358.c -- mt6358 ALSA SoC audio codec driver +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mt6358.h" + +enum { + AUDIO_ANALOG_VOLUME_HSOUTL, + AUDIO_ANALOG_VOLUME_HSOUTR, + AUDIO_ANALOG_VOLUME_HPOUTL, + AUDIO_ANALOG_VOLUME_HPOUTR, + AUDIO_ANALOG_VOLUME_LINEOUTL, + AUDIO_ANALOG_VOLUME_LINEOUTR, + AUDIO_ANALOG_VOLUME_MICAMP1, + AUDIO_ANALOG_VOLUME_MICAMP2, + AUDIO_ANALOG_VOLUME_TYPE_MAX +}; + +enum { + MUX_ADC_L, + MUX_ADC_R, + MUX_PGA_L, + MUX_PGA_R, + MUX_MIC_TYPE, + MUX_HP_L, + MUX_HP_R, + MUX_NUM, +}; + +enum { + DEVICE_HP, + DEVICE_LO, + DEVICE_RCV, + DEVICE_MIC1, + DEVICE_MIC2, + DEVICE_NUM +}; + +/* Supply widget subseq */ +enum { + /* common */ + SUPPLY_SEQ_CLK_BUF, + SUPPLY_SEQ_AUD_GLB, + SUPPLY_SEQ_CLKSQ, + SUPPLY_SEQ_VOW_AUD_LPW, + SUPPLY_SEQ_AUD_VOW, + SUPPLY_SEQ_VOW_CLK, + SUPPLY_SEQ_VOW_LDO, + SUPPLY_SEQ_TOP_CK, + SUPPLY_SEQ_TOP_CK_LAST, + SUPPLY_SEQ_AUD_TOP, + SUPPLY_SEQ_AUD_TOP_LAST, + SUPPLY_SEQ_AFE, + /* capture */ + SUPPLY_SEQ_ADC_SUPPLY, +}; + +enum { + CH_L = 0, + CH_R, + NUM_CH, +}; + +#define REG_STRIDE 2 + +struct mt6358_priv { + struct device *dev; + struct regmap *regmap; + + unsigned int dl_rate; + unsigned int ul_rate; + + int ana_gain[AUDIO_ANALOG_VOLUME_TYPE_MAX]; + unsigned int mux_select[MUX_NUM]; + + int dev_counter[DEVICE_NUM]; + + int mtkaif_protocol; + + struct regulator *avdd_reg; +}; + +int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + priv->mtkaif_protocol = mtkaif_protocol; + return 0; +} + +static void playback_gpio_set(struct mt6358_priv *priv) +{ + /* set gpio mosi mode */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR, + 0x01f8, 0x01f8); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_SET, + 0xffff, 0x0249); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2, + 0xffff, 0x0249); +} + +static void playback_gpio_reset(struct mt6358_priv *priv) +{ + /* set pad_aud_*_mosi to GPIO mode and dir input + * reason: + * pad_aud_dat_mosi*, because the pin is used as boot strap + * don't clean clk/sync, for mtkaif protocol 2 + */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR, + 0x01f8, 0x01f8); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2, + 0x01f8, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0, + 0xf << 8, 0x0); +} + +static void capture_gpio_set(struct mt6358_priv *priv) +{ + /* set gpio miso mode */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR, + 0xffff, 0xffff); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_SET, + 0xffff, 0x0249); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, + 0xffff, 0x0249); +} + +static void capture_gpio_reset(struct mt6358_priv *priv) +{ + /* set pad_aud_*_miso to GPIO mode and dir input + * reason: + * pad_aud_clk_miso, because when playback only the miso_clk + * will also have 26m, so will have power leak + * pad_aud_dat_miso*, because the pin is used as boot strap + */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR, + 0xffff, 0xffff); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0, + 0xf << 12, 0x0); +} + +/* use only when not govern by DAPM */ +static int mt6358_set_dcxo(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, + 0x1 << RG_XO_AUDIO_EN_M_SFT, + (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_clksq(struct mt6358_priv *priv, bool enable) +{ + /* audio clk source from internal dcxo */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_IN_SEL_TEST_MASK_SFT, + 0x0); + + /* Enable/disable CLKSQ 26MHz */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_EN_MASK_SFT, + (enable ? 1 : 0) << RG_CLKSQ_EN_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_aud_global_bias(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA28_MASK_SFT, + (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA28_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_topck(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, + 0x0066, enable ? 0x0 : 0x66); + return 0; +} + +static int mt6358_mtkaif_tx_enable(struct mt6358_priv *priv) +{ + switch (priv->mtkaif_protocol) { + case MT6358_MTKAIF_PROTOCOL_2_CLK_P2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0010); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3800); + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3900); + break; + case MT6358_MTKAIF_PROTOCOL_2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0010); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + case MT6358_MTKAIF_PROTOCOL_1: + default: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0000); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + } + return 0; +} + +static int mt6358_mtkaif_tx_disable(struct mt6358_priv *priv) +{ + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3000); + return 0; +} + +int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + playback_gpio_set(priv); + capture_gpio_set(priv); + mt6358_mtkaif_tx_enable(priv); + + mt6358_set_dcxo(priv, true); + mt6358_set_aud_global_bias(priv, true); + mt6358_set_clksq(priv, true); + mt6358_set_topck(priv, true); + + /* set dat_miso_loopback on */ + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + return 0; +} + +int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + /* set dat_miso_loopback off */ + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + + mt6358_set_topck(priv, false); + mt6358_set_clksq(priv, false); + mt6358_set_aud_global_bias(priv, false); + mt6358_set_dcxo(priv, false); + + mt6358_mtkaif_tx_disable(priv); + playback_gpio_reset(priv); + capture_gpio_reset(priv); + return 0; +} + +int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT, + phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT, + phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); + return 0; +} + +/* dl pga gain */ +enum { + DL_GAIN_8DB = 0, + DL_GAIN_0DB = 8, + DL_GAIN_N_1DB = 9, + DL_GAIN_N_10DB = 18, + DL_GAIN_N_40DB = 0x1f, +}; + +#define DL_GAIN_N_10DB_REG (DL_GAIN_N_10DB << 7 | DL_GAIN_N_10DB) +#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) +#define DL_GAIN_REG_MASK 0x0f9f + +static void lo_store_gain(struct mt6358_priv *priv) +{ + unsigned int reg; + unsigned int gain_l, gain_r; + + regmap_read(priv->regmap, MT6358_ZCD_CON1, ®); + gain_l = (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK; + gain_r = (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK; + + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] = gain_l; + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = gain_r; +} + +static void hp_store_gain(struct mt6358_priv *priv) +{ + unsigned int reg; + unsigned int gain_l, gain_r; + + regmap_read(priv->regmap, MT6358_ZCD_CON2, ®); + gain_l = (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK; + gain_r = (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK; + + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = gain_l; + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = gain_r; +} + +static void hp_zcd_disable(struct mt6358_priv *priv) +{ + regmap_write(priv->regmap, MT6358_ZCD_CON0, 0x0000); +} + +static void hp_main_output_ramp(struct mt6358_priv *priv, bool up) +{ + int i = 0, stage = 0; + int target = 7; + + /* Enable/Reduce HPL/R main output stage step by step */ + for (i = 0; i <= target; i++) { + stage = up ? i : target - i; + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x7 << 8, stage << 8); + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x7 << 11, stage << 11); + usleep_range(100, 150); + } +} + +static void hp_aux_feedback_loop_gain_ramp(struct mt6358_priv *priv, bool up) +{ + int i = 0, stage = 0; + + /* Reduce HP aux feedback loop gain step by step */ + for (i = 0; i <= 0xf; i++) { + stage = up ? i : 0xf - i; + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xf << 12, stage << 12); + usleep_range(100, 150); + } +} + +static void hp_pull_down(struct mt6358_priv *priv, bool enable) +{ + int i; + + if (enable) { + for (i = 0x0; i <= 0x6; i++) { + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x7, i); + usleep_range(600, 700); + } + } else { + for (i = 0x6; i >= 0x1; i--) { + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x7, i); + usleep_range(600, 700); + } + } +} + +static bool is_valid_hp_pga_idx(int reg_idx) +{ + return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_10DB) || + reg_idx == DL_GAIN_N_40DB; +} + +static void headset_volume_ramp(struct mt6358_priv *priv, + int from, int to) +{ + int offset = 0, count = 1, reg_idx; + + if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) + dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n", + __func__, from, to); + + dev_info(priv->dev, "%s(), from %d, to %d\n", + __func__, from, to); + + if (to > from) + offset = to - from; + else + offset = from - to; + + while (offset > 0) { + if (to > from) + reg_idx = from + count; + else + reg_idx = from - count; + + if (is_valid_hp_pga_idx(reg_idx)) { + regmap_update_bits(priv->regmap, + MT6358_ZCD_CON2, + DL_GAIN_REG_MASK, + (reg_idx << 7) | reg_idx); + usleep_range(200, 300); + } + offset--; + count++; + } +} + +static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0); + +static const struct snd_kcontrol_new mt6358_snd_controls[] = { + /* dl pga gain */ + SOC_DOUBLE_TLV("Headphone Volume", + MT6358_ZCD_CON2, 0, 7, 0x12, 1, + playback_tlv), + SOC_DOUBLE_TLV("Lineout Volume", + MT6358_ZCD_CON1, 0, 7, 0x12, 1, + playback_tlv), + SOC_SINGLE_TLV("Handset Volume", + MT6358_ZCD_CON3, 0, 0x12, 1, + playback_tlv), + /* ul pga gain */ + SOC_DOUBLE_R_TLV("PGA Volume", + MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1, + 8, 4, 0, + pga_tlv), +}; + +/* MUX */ +/* LOL MUX */ +static const char * const lo_in_mux_map[] = { + "Open", "Mute", "Playback", "Test Mode" +}; + +static int lo_in_mux_map_value[] = { + 0x0, 0x1, 0x2, 0x3, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(lo_in_mux_map_enum, + MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLMUXINPUTSEL_VAUDP15_SFT, + RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK, + lo_in_mux_map, + lo_in_mux_map_value); + +static const struct snd_kcontrol_new lo_in_mux_control = + SOC_DAPM_ENUM("In Select", lo_in_mux_map_enum); + +/*HP MUX */ +enum { + HP_MUX_OPEN = 0, + HP_MUX_HPSPK, + HP_MUX_HP, + HP_MUX_TEST_MODE, + HP_MUX_HP_IMPEDANCE, + HP_MUX_MASK = 0x7, +}; + +static const char * const hp_in_mux_map[] = { + "Open", + "LoudSPK Playback", + "Audio Playback", + "Test Mode", + "HP Impedance", + "undefined1", + "undefined2", + "undefined3", +}; + +static int hp_in_mux_map_value[] = { + HP_MUX_OPEN, + HP_MUX_HPSPK, + HP_MUX_HP, + HP_MUX_TEST_MODE, + HP_MUX_HP_IMPEDANCE, + HP_MUX_OPEN, + HP_MUX_OPEN, + HP_MUX_OPEN, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hpl_in_mux_map_enum, + SND_SOC_NOPM, + 0, + HP_MUX_MASK, + hp_in_mux_map, + hp_in_mux_map_value); + +static const struct snd_kcontrol_new hpl_in_mux_control = + SOC_DAPM_ENUM("HPL Select", hpl_in_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hpr_in_mux_map_enum, + SND_SOC_NOPM, + 0, + HP_MUX_MASK, + hp_in_mux_map, + hp_in_mux_map_value); + +static const struct snd_kcontrol_new hpr_in_mux_control = + SOC_DAPM_ENUM("HPR Select", hpr_in_mux_map_enum); + +/* RCV MUX */ +enum { + RCV_MUX_OPEN = 0, + RCV_MUX_MUTE, + RCV_MUX_VOICE_PLAYBACK, + RCV_MUX_TEST_MODE, + RCV_MUX_MASK = 0x3, +}; + +static const char * const rcv_in_mux_map[] = { + "Open", "Mute", "Voice Playback", "Test Mode" +}; + +static int rcv_in_mux_map_value[] = { + RCV_MUX_OPEN, + RCV_MUX_MUTE, + RCV_MUX_VOICE_PLAYBACK, + RCV_MUX_TEST_MODE, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rcv_in_mux_map_enum, + SND_SOC_NOPM, + 0, + RCV_MUX_MASK, + rcv_in_mux_map, + rcv_in_mux_map_value); + +static const struct snd_kcontrol_new rcv_in_mux_control = + SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum); + +/* DAC In MUX */ +static const char * const dac_in_mux_map[] = { + "Normal Path", "Sgen" +}; + +static int dac_in_mux_map_value[] = { + 0x0, 0x1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum, + MT6358_AFE_TOP_CON0, + DL_SINE_ON_SFT, + DL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new dac_in_mux_control = + SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum); + +/* AIF Out MUX */ +static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum, + MT6358_AFE_TOP_CON0, + UL_SINE_ON_SFT, + UL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new aif_out_mux_control = + SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum); + +/* Mic Type MUX */ +enum { + MIC_TYPE_MUX_IDLE = 0, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, + MIC_TYPE_MUX_MASK = 0x7, +}; + +#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \ + (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ + (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) + +static const char * const mic_type_mux_map[] = { + "Idle", + "ACC", + "DMIC", + "DCC", + "DCC_ECM_DIFF", + "DCC_ECM_SINGLE", +}; + +static int mic_type_mux_map_value[] = { + MIC_TYPE_MUX_IDLE, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(mic_type_mux_map_enum, + SND_SOC_NOPM, + 0, + MIC_TYPE_MUX_MASK, + mic_type_mux_map, + mic_type_mux_map_value); + +static const struct snd_kcontrol_new mic_type_mux_control = + SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum); + +/* ADC L MUX */ +enum { + ADC_MUX_IDLE = 0, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, + ADC_MUX_MASK = 0x3, +}; + +static const char * const adc_left_mux_map[] = { + "Idle", "AIN0", "Left Preamplifier", "Idle_1" +}; + +static int adc_mux_map_value[] = { + ADC_MUX_IDLE, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum, + SND_SOC_NOPM, + 0, + ADC_MUX_MASK, + adc_left_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_left_mux_control = + SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum); + +/* ADC R MUX */ +static const char * const adc_right_mux_map[] = { + "Idle", "AIN0", "Right Preamplifier", "Idle_1" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum, + SND_SOC_NOPM, + 0, + ADC_MUX_MASK, + adc_right_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_right_mux_control = + SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum); + +/* PGA L MUX */ +enum { + PGA_MUX_NONE = 0, + PGA_MUX_AIN0, + PGA_MUX_AIN1, + PGA_MUX_AIN2, + PGA_MUX_MASK = 0x3, +}; + +static const char * const pga_mux_map[] = { + "None", "AIN0", "AIN1", "AIN2" +}; + +static int pga_mux_map_value[] = { + PGA_MUX_NONE, + PGA_MUX_AIN0, + PGA_MUX_AIN1, + PGA_MUX_AIN2, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum, + SND_SOC_NOPM, + 0, + PGA_MUX_MASK, + pga_mux_map, + pga_mux_map_value); + +static const struct snd_kcontrol_new pga_left_mux_control = + SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum); + +/* PGA R MUX */ +static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum, + SND_SOC_NOPM, + 0, + PGA_MUX_MASK, + pga_mux_map, + pga_mux_map_value); + +static const struct snd_kcontrol_new pga_right_mux_control = + SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum); + +static int mt_clksq_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* audio clk source from internal dcxo */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_IN_SEL_TEST_MASK_SFT, + 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_sgen_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xCBA1); + /* sdm power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B); + + regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG0, + 0xff3f, + 0x0000); + regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG1, + 0xffff, + 0x0001); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000); + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0); + break; + default: + break; + } + + return 0; +} + +static int mt_aif_in_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_info(priv->dev, "%s(), event 0x%x, rate %d\n", + __func__, event, priv->dl_rate); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + playback_gpio_set(priv); + + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xCBA1); + /* sdm power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000); + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0); + + playback_gpio_reset(priv); + break; + default: + break; + } + + return 0; +} + +static int mtk_hp_enable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + /* release HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x1 << 6); + + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* save target gain to restore after hardware open complete */ + hp_store_gain(priv); + /* Set HPR/HPL gain as minimum (~ -40dB) */ + regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable headphone short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HPP/N STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4033); + + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x000c); + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x003c); + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00); + /* Enable HP driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0); + /* Enable HP driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0); + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x00fc); + + /* Enable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00); + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0200); + + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HP main output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x00ff); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, true); + /* Disable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* apply volume setting */ + headset_volume_ramp(priv, + DL_GAIN_N_10DB, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]); + + /* Disable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Unshort HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3f03); + usleep_range(100, 120); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1); + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30ff); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0xf201); + usleep_range(100, 120); + + /* Switch HPL MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x32ff); + /* Switch HPR MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3aff); + + /* Disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mtk_hp_disable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + + /* HPR/HPL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x0f00, 0x0000); + + /* Disable low-noise mode of DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0x0001, 0x0000); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0); + + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* decrease HPL/R gain to normal gain step by step */ + headset_volume_ramp(priv, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL], + DL_GAIN_N_40DB); + + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0); + + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00); + + /* Disable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00); + + /* Unshort HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 6, 0x0); + + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 4, 0x0); + + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 6, 0x0); + + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000); + + /* Disable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 4, 0x0); + + /* Disable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 2, 0x0); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, + 0x1, 0x1); + + /* Increase ESD resistance of AU_REFN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2, + 0x1 << 14, 0x0); + + /* Set HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x0); + /* disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mtk_hp_spk_enable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + /* release HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x1 << 6); + + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* save target gain to restore after hardware open complete */ + hp_store_gain(priv); + /* Set HPR/HPL gain to -10dB */ + regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable headphone short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HPP/N STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4033); + + /* Disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + /* Enable HP driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0); + /* Enable HP driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0); + /* Enable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0200); + + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HP main output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0003); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + + /* Set LO gain as minimum (~ -40dB) */ + lo_store_gain(priv); + regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG); + /* apply volume setting */ + headset_volume_ramp(priv, + DL_GAIN_N_10DB, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]); + + /* Set LO STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0110); + /* Enable LO driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0112); + /* Enable LO driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0113); + + /* Set LOL gain to normal gain step by step */ + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + RG_AUDLOLGAIN_MASK_SFT, + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] << + RG_AUDLOLGAIN_SFT); + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + RG_AUDLORGAIN_MASK_SFT, + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] << + RG_AUDLORGAIN_SFT); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1); + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f9); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0201); + /* Switch LOL MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x011b); + /* Switch HPL/R MUX to Line-out */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x35f9); + + return 0; +} + +static int mtk_hp_spk_disable(struct mt6358_priv *priv) +{ + /* HPR/HPL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x0f00, 0x0000); + /* LOL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x3 << 2, 0x0000); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0); + + /* decrease HPL/R gain to normal gain step by step */ + headset_volume_ramp(priv, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL], + DL_GAIN_N_40DB); + + /* decrease LOL gain to minimum gain step by step */ + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + DL_GAIN_REG_MASK, DL_GAIN_N_40DB_REG); + + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0); + + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 4, 0x0); + /* Disable LO driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x1, 0x0); + + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 6, 0x0); + /* Disable LO driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x1 << 1, 0x0); + + /* Disable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x0000); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1); + + /* Set HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x0); + /* disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mt_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + int device = DEVICE_HP; + + dev_info(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n", + __func__, + event, + priv->dev_counter[device], + mux); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->dev_counter[device]++; + if (priv->dev_counter[device] > 1) + break; /* already enabled, do nothing */ + else if (priv->dev_counter[device] <= 0) + dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d <= 0\n", + __func__, + priv->dev_counter[device]); + + priv->mux_select[MUX_HP_L] = mux; + + if (mux == HP_MUX_HP) + mtk_hp_enable(priv); + else if (mux == HP_MUX_HPSPK) + mtk_hp_spk_enable(priv); + break; + case SND_SOC_DAPM_PRE_PMD: + priv->dev_counter[device]--; + if (priv->dev_counter[device] > 0) { + break; /* still being used, don't close */ + } else if (priv->dev_counter[device] < 0) { + dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d < 0\n", + __func__, + priv->dev_counter[device]); + priv->dev_counter[device] = 0; + break; + } + + if (priv->mux_select[MUX_HP_L] == HP_MUX_HP) + mtk_hp_disable(priv); + else if (priv->mux_select[MUX_HP_L] == HP_MUX_HPSPK) + mtk_hp_spk_disable(priv); + + priv->mux_select[MUX_HP_L] = mux; + break; + default: + break; + } + + return 0; +} + +static int mt_rcv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_info(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, + event, + dapm_kcontrol_get_value(w->kcontrols[0])); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable handset short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HS STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0090); + + /* Disable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000); + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HS driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0092); + /* Enable HS driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0093); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1, 0x1); + + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x0009); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0001); + /* Switch HS MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x009b); + break; + case SND_SOC_DAPM_PRE_PMD: + /* HS mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT, + RCV_MUX_OPEN); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1, 0x0); + + /* decrease HS gain to minimum gain step by step */ + regmap_write(priv->regmap, MT6358_ZCD_CON3, DL_GAIN_N_40DB); + + /* Disable HS driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + 0x1, 0x0); + + /* Disable HS driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + 0x1 << 1, 0x0000); + + /* Disable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x0); + + /* Enable HP main CMFB Switch */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x2 << 8); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, + 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, + 0x1, 0x1); + break; + default: + break; + } + + return 0; +} + +static int mt_aif_out_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n", + __func__, event, priv->ul_rate); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + capture_gpio_set(priv); + break; + case SND_SOC_DAPM_POST_PMD: + capture_gpio_reset(priv); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_supply_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x\n", + __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1 << 5, 0x1 << 5); + /* ADC CLK from CLKGEN (13MHz) */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, + 0x0000); + /* Enable LCLDO_ENC 1P8V */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0100); + /* LCLDO_ENC remote sense */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x2500); + break; + case SND_SOC_DAPM_POST_PMD: + /* LCLDO_ENC remote sense off */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0100); + /* disable LCLDO_ENC 1P8V */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0000); + + /* ADC CLK from CLKGEN (13MHz) */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, 0x0000); + /* disable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1 << 5, 0x0 << 5); + break; + default: + break; + } + + return 0; +} + +static int mt6358_amic_enable(struct mt6358_priv *priv) +{ + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE]; + unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L]; + unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R]; + + dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u\n", + __func__, mic_type, mux_pga_l, mux_pga_r); + + if (IS_DCC_BASE(mic_type)) { + /* DCC 50k CLK (from 26M) */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2061); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG1, 0x0100); + } + + /* mic bias 0 */ + if (mux_pga_l == PGA_MUX_AIN0 || mux_pga_l == PGA_MUX_AIN2 || + mux_pga_r == PGA_MUX_AIN0 || mux_pga_r == PGA_MUX_AIN2) { + switch (mic_type) { + case MIC_TYPE_MUX_DCC_ECM_DIFF: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x7700); + break; + case MIC_TYPE_MUX_DCC_ECM_SINGLE: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x1100); + break; + default: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x0000); + break; + } + /* Enable MICBIAS0, MISBIAS0 = 1P9V */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff, 0x21); + } + + /* mic bias 1 */ + if (mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1) { + /* Enable MICBIAS1, MISBIAS1 = 2P6V */ + if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE) + regmap_write(priv->regmap, + MT6358_AUDENC_ANA_CON10, 0x0161); + else + regmap_write(priv->regmap, + MT6358_AUDENC_ANA_CON10, 0x0061); + } + + if (IS_DCC_BASE(mic_type)) { + /* Audio L/R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf8ff, 0x0004); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf8ff, 0x0004); + } else { + /* reset reg */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf8ff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf8ff, 0x0000); + } + + if (mux_pga_l != PGA_MUX_NONE) { + /* L preamplifier input sel */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLINPUTSEL_MASK_SFT, + mux_pga_l << RG_AUDPREAMPLINPUTSEL_SFT); + + /* L preamplifier enable */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLON_MASK_SFT, + 0x1 << RG_AUDPREAMPLON_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPLDCCEN_SFT); + } + + /* L ADC input sel : L PGA. Enable audio L ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDADCLINPUTSEL_MASK_SFT, + ADC_MUX_PREAMPLIFIER << + RG_AUDADCLINPUTSEL_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDADCLPWRUP_MASK_SFT, + 0x1 << RG_AUDADCLPWRUP_SFT); + } + + if (mux_pga_r != PGA_MUX_NONE) { + /* R preamplifier input sel */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRINPUTSEL_MASK_SFT, + mux_pga_r << RG_AUDPREAMPRINPUTSEL_SFT); + + /* R preamplifier enable */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRON_MASK_SFT, + 0x1 << RG_AUDPREAMPRON_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPRDCCEN_SFT); + } + + /* R ADC input sel : R PGA. Enable audio R ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDADCRINPUTSEL_MASK_SFT, + ADC_MUX_PREAMPLIFIER << + RG_AUDADCRINPUTSEL_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDADCRPWRUP_MASK_SFT, + 0x1 << RG_AUDADCRPWRUP_SFT); + } + + if (IS_DCC_BASE(mic_type)) { + usleep_range(100, 150); + /* Audio L preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0); + /* Audio R preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCPRECHARGE_MASK_SFT, 0x0); + + /* Short body to ground in PGA */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON3, + 0x1 << 12, 0x0); + } + + /* here to set digital part */ + mt6358_mtkaif_tx_enable(priv); + + /* UL dmic setting off */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0000); + + /* UL turn on */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0001); + + return 0; +} + +static void mt6358_amic_disable(struct mt6358_priv *priv) +{ + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE]; + unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L]; + unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R]; + + dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u\n", + __func__, mic_type, mux_pga_l, mux_pga_r); + + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, + 0x0001, 0x0000); + + /* disable aud_pad TX fifos */ + mt6358_mtkaif_tx_disable(priv); + + /* L ADC input sel : off, disable L ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf000, 0x0000); + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0x1 << 1, 0x0); + /* L preamplifier input sel : off, L PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xfffb, 0x0000); + + /* disable L preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0x1 << 2, 0x0); + + /* R ADC input sel : off, disable R ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf000, 0x0000); + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x1 << 1, 0x0); + /* R preamplifier input sel : off, R PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x0ffb, 0x0000); + + /* disable R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x1 << 2, 0x0); + + /* mic bias */ + /* Disable MICBIAS0, MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); + + /* Disable MICBIAS1 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x0001, 0x0000); + + if (IS_DCC_BASE(mic_type)) { + /* dcclk_gen_on=1'b0 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060); + /* dcclk_pdn=1'b1 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + /* dcclk_ref_ck_sel=2'b00 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + /* dcclk_div=11'b00100000011 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + } +} + +static int mt6358_dmic_enable(struct mt6358_priv *priv) +{ + dev_info(priv->dev, "%s()\n", __func__); + + /* mic bias */ + /* Enable MICBIAS0, MISBIAS0 = 1P9V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0021); + + /* RG_BANDGAPGEN=1'b0 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x1 << 12, 0x0); + + /* DMIC enable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0005); + + /* here to set digital part */ + mt6358_mtkaif_tx_enable(priv); + + /* UL dmic setting */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0080); + + /* UL turn on */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003); + return 0; +} + +static void mt6358_dmic_disable(struct mt6358_priv *priv) +{ + dev_info(priv->dev, "%s()\n", __func__); + + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, + 0x0003, 0x0000); + + /* disable aud_pad TX fifos */ + mt6358_mtkaif_tx_disable(priv); + + /* DMIC disable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0000); + + /* mic bias */ + /* MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0001); + + /* RG_BANDGAPGEN=1'b0 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x1 << 12, 0x0); + + /* MICBIA0 disable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); +} + +static int mt_mic_type_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, event, mux); + + switch (event) { + case SND_SOC_DAPM_WILL_PMU: + priv->mux_select[MUX_MIC_TYPE] = mux; + break; + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case MIC_TYPE_MUX_DMIC: + mt6358_dmic_enable(priv); + break; + default: + mt6358_amic_enable(priv); + break; + } + + break; + case SND_SOC_DAPM_POST_PMD: + switch (priv->mux_select[MUX_MIC_TYPE]) { + case MIC_TYPE_MUX_DMIC: + mt6358_dmic_disable(priv); + break; + default: + mt6358_amic_disable(priv); + break; + } + + priv->mux_select[MUX_MIC_TYPE] = mux; + break; + default: + break; + } + + return 0; +} + +static int mt_adc_l_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_ADC_L] = mux; + + return 0; +} + +static int mt_adc_r_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_ADC_R] = mux; + + return 0; +} + +static int mt_pga_left_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_PGA_L] = mux; + + return 0; +} + +static int mt_pga_right_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_PGA_R] = mux; + + return 0; +} + +static int mt_delay_250_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(250, 270); + break; + case SND_SOC_DAPM_PRE_PMD: + usleep_range(250, 270); + break; + default: + break; + } + + return 0; +} + +/* DAPM Widgets */ +static const struct snd_soc_dapm_widget mt6358_dapm_widgets[] = { + /* Global Supply*/ + SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, + MT6358_DCXO_CW14, + RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, + MT6358_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ, + MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_EN_SFT, 0, + mt_clksq_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUDNCP_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_ZCD13M_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUD_CK_PDN_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUDIF_CK_PDN_SFT, 1, NULL, 0), + + /* Digital Clock */ + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, + MT6358_AUDIO_TOP_CON0, + PDN_AFE_CTL_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_DAC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_ADC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_I2S_DL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PWR_CLK_DIS_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_RESERVED_SFT, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* AFE ON */ + SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE, + MT6358_AFE_UL_DL_CON0, AFE_ON_SFT, 0, + NULL, 0), + + /* AIF Rx*/ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "AIF1 Playback", 0, + MT6358_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + mt_aif_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* DL Supply */ + SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* DAC */ + SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control), + + SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), + + /* LOL */ + SND_SOC_DAPM_MUX("LOL Mux", SND_SOC_NOPM, 0, 0, &lo_in_mux_control), + + SND_SOC_DAPM_SUPPLY("LO Stability Enh", MT6358_AUDDEC_ANA_CON7, + RG_LOOUTPUTSTBENH_VAUDP15_SFT, 0, NULL, 0), + + SND_SOC_DAPM_OUT_DRV("LOL Buffer", MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLPWRUP_VAUDP15_SFT, 0, NULL, 0), + + /* Headphone */ + SND_SOC_DAPM_MUX_E("HPL Mux", SND_SOC_NOPM, 0, 0, + &hpl_in_mux_control, + mt_hp_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX_E("HPR Mux", SND_SOC_NOPM, 0, 0, + &hpr_in_mux_control, + mt_hp_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Receiver */ + SND_SOC_DAPM_MUX_E("RCV Mux", SND_SOC_NOPM, 0, 0, + &rcv_in_mux_control, + mt_rcv_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("Receiver"), + SND_SOC_DAPM_OUTPUT("Headphone L"), + SND_SOC_DAPM_OUTPUT("Headphone R"), + SND_SOC_DAPM_OUTPUT("Headphone L Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("Headphone R Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("LINEOUT L"), + SND_SOC_DAPM_OUTPUT("LINEOUT L HSSPK"), + + /* SGEN */ + SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6358_AFE_SGEN_CFG0, + SGEN_DAC_EN_CTL_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6358_AFE_SGEN_CFG0, + SGEN_MUTE_SW_CTL_SFT, 1, + mt_sgen_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6358_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0), + + SND_SOC_DAPM_INPUT("SGEN DL"), + + /* Uplinks */ + SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "AIF1 Capture", 0, + SND_SOC_NOPM, 0, 0, + mt_aif_out_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY, + SND_SOC_NOPM, 0, 0, + mt_adc_supply_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Uplinks MUX */ + SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0, + &aif_out_mux_control), + + SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0, + &mic_type_mux_control, + mt_mic_type_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_MUX_E("ADC L Mux", SND_SOC_NOPM, 0, 0, + &adc_left_mux_control, + mt_adc_l_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("ADC R Mux", SND_SOC_NOPM, 0, 0, + &adc_right_mux_control, + mt_adc_r_event, + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0, + &pga_left_mux_control, + mt_pga_left_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0, + &pga_right_mux_control, + mt_pga_right_event, + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* UL input */ + SND_SOC_DAPM_INPUT("AIN0"), + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), +}; + +static const struct snd_soc_dapm_route mt6358_dapm_routes[] = { + /* Capture */ + {"AIF1TX", NULL, "AIF Out Mux"}, + {"AIF1TX", NULL, "CLK_BUF"}, + {"AIF1TX", NULL, "AUDGLB"}, + {"AIF1TX", NULL, "CLKSQ Audio"}, + + {"AIF1TX", NULL, "AUD_CK"}, + {"AIF1TX", NULL, "AUDIF_CK"}, + + {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"}, + {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"}, + {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"}, + + {"AIF1TX", NULL, "AFE_ON"}, + + {"AIF Out Mux", NULL, "Mic Type Mux"}, + + {"Mic Type Mux", "ACC", "ADC L"}, + {"Mic Type Mux", "ACC", "ADC R"}, + {"Mic Type Mux", "DCC", "ADC L"}, + {"Mic Type Mux", "DCC", "ADC R"}, + {"Mic Type Mux", "DCC_ECM_DIFF", "ADC L"}, + {"Mic Type Mux", "DCC_ECM_DIFF", "ADC R"}, + {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC L"}, + {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC R"}, + {"Mic Type Mux", "DMIC", "AIN0"}, + {"Mic Type Mux", "DMIC", "AIN2"}, + + {"ADC L", NULL, "ADC L Mux"}, + {"ADC L", NULL, "ADC Supply"}, + {"ADC R", NULL, "ADC R Mux"}, + {"ADC R", NULL, "ADC Supply"}, + + {"ADC L Mux", "Left Preamplifier", "PGA L"}, + + {"ADC R Mux", "Right Preamplifier", "PGA R"}, + + {"PGA L", NULL, "PGA L Mux"}, + {"PGA R", NULL, "PGA R Mux"}, + + {"PGA L Mux", "AIN0", "AIN0"}, + {"PGA L Mux", "AIN1", "AIN1"}, + {"PGA L Mux", "AIN2", "AIN2"}, + + {"PGA R Mux", "AIN0", "AIN0"}, + {"PGA R Mux", "AIN1", "AIN1"}, + {"PGA R Mux", "AIN2", "AIN2"}, + + /* DL Supply */ + {"DL Power Supply", NULL, "CLK_BUF"}, + {"DL Power Supply", NULL, "AUDGLB"}, + {"DL Power Supply", NULL, "CLKSQ Audio"}, + + {"DL Power Supply", NULL, "AUDNCP_CK"}, + {"DL Power Supply", NULL, "ZCD13M_CK"}, + {"DL Power Supply", NULL, "AUD_CK"}, + {"DL Power Supply", NULL, "AUDIF_CK"}, + + /* DL Digital Supply */ + {"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"}, + + {"DL Digital Clock", NULL, "AFE_ON"}, + + {"AIF_RX", NULL, "DL Digital Clock"}, + + /* DL Path */ + {"DAC In Mux", "Normal Path", "AIF_RX"}, + + {"DAC In Mux", "Sgen", "SGEN DL"}, + {"SGEN DL", NULL, "SGEN DL SRC"}, + {"SGEN DL", NULL, "SGEN MUTE"}, + {"SGEN DL", NULL, "SGEN DL Enable"}, + {"SGEN DL", NULL, "DL Digital Clock"}, + {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, + + {"DACL", NULL, "DAC In Mux"}, + {"DACL", NULL, "DL Power Supply"}, + + {"DACR", NULL, "DAC In Mux"}, + {"DACR", NULL, "DL Power Supply"}, + + /* Lineout Path */ + {"LOL Mux", "Playback", "DACL"}, + + {"LOL Buffer", NULL, "LOL Mux"}, + {"LOL Buffer", NULL, "LO Stability Enh"}, + + {"LINEOUT L", NULL, "LOL Buffer"}, + + /* Headphone Path */ + {"HPL Mux", "Audio Playback", "DACL"}, + {"HPR Mux", "Audio Playback", "DACR"}, + {"HPL Mux", "HP Impedance", "DACL"}, + {"HPR Mux", "HP Impedance", "DACR"}, + {"HPL Mux", "LoudSPK Playback", "DACL"}, + {"HPR Mux", "LoudSPK Playback", "DACR"}, + + {"Headphone L", NULL, "HPL Mux"}, + {"Headphone R", NULL, "HPR Mux"}, + {"Headphone L Ext Spk Amp", NULL, "HPL Mux"}, + {"Headphone R Ext Spk Amp", NULL, "HPR Mux"}, + {"LINEOUT L HSSPK", NULL, "HPL Mux"}, + + /* Receiver Path */ + {"RCV Mux", "Voice Playback", "DACL"}, + {"Receiver", NULL, "RCV Mux"}, +}; + +static int mt6358_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *cmpnt = dai->component; + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int rate = params_rate(params); + + dev_info(priv->dev, "%s(), substream->stream %d, rate %d, number %d\n", + __func__, + substream->stream, + rate, + substream->number); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + priv->dl_rate = rate; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + priv->ul_rate = rate; + + return 0; +} + +static const struct snd_soc_dai_ops mt6358_codec_dai_ops = { + .hw_params = mt6358_codec_dai_hw_params, +}; + +#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ + SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) + +static struct snd_soc_dai_driver mt6358_dai_driver[] = { + { + .name = "mt6358-snd-codec-aif1", + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = MT6358_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = MT6358_FORMATS, + }, + .ops = &mt6358_codec_dai_ops, + }, +}; + +static int mt6358_codec_init_reg(struct mt6358_priv *priv) +{ + int ret = 0; + + /* Disable HeadphoneL/HeadphoneR short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHPLSCDISABLE_VAUDP15_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHPRSCDISABLE_VAUDP15_SFT); + /* Disable voice short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHSSCDISABLE_VAUDP15_SFT); + /* disable LO buffer left short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDLOLSCDISABLE_VAUDP15_SFT); + + /* accdet s/w enable */ + regmap_update_bits(priv->regmap, MT6358_ACCDET_CON13, + 0xFFFF, 0x700E); + + /* gpio miso driving set to 4mA */ + regmap_write(priv->regmap, MT6358_DRV_CON3, 0x8888); + + /* set gpio */ + playback_gpio_reset(priv); + capture_gpio_reset(priv); + + return ret; +} + +static int mt6358_codec_probe(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int ret; + + snd_soc_component_init_regmap(cmpnt, priv->regmap); + + mt6358_codec_init_reg(priv); + + priv->avdd_reg = devm_regulator_get(priv->dev, "Avdd"); + if (IS_ERR(priv->avdd_reg)) { + dev_err(priv->dev, "%s() have no Avdd supply", __func__); + return PTR_ERR(priv->avdd_reg); + } + + ret = regulator_enable(priv->avdd_reg); + if (ret) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver mt6358_soc_component_driver = { + .probe = mt6358_codec_probe, + .controls = mt6358_snd_controls, + .num_controls = ARRAY_SIZE(mt6358_snd_controls), + .dapm_widgets = mt6358_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt6358_dapm_widgets), + .dapm_routes = mt6358_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(mt6358_dapm_routes), +}; + +static int mt6358_platform_driver_probe(struct platform_device *pdev) +{ + struct mt6358_priv *priv; + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + + priv = devm_kzalloc(&pdev->dev, + sizeof(struct mt6358_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, priv); + + priv->dev = &pdev->dev; + + priv->regmap = mt6397->regmap; + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + dev_info(priv->dev, "%s(), dev name %s\n", + __func__, dev_name(&pdev->dev)); + + return devm_snd_soc_register_component(&pdev->dev, + &mt6358_soc_component_driver, + mt6358_dai_driver, + ARRAY_SIZE(mt6358_dai_driver)); +} + +static const struct of_device_id mt6358_of_match[] = { + {.compatible = "mediatek,mt6358-sound",}, + {} +}; +MODULE_DEVICE_TABLE(of, mt6358_of_match); + +static struct platform_driver mt6358_platform_driver = { + .driver = { + .name = "mt6358-sound", + .of_match_table = mt6358_of_match, + }, + .probe = mt6358_platform_driver_probe, +}; + +module_platform_driver(mt6358_platform_driver) + +/* Module information */ +MODULE_DESCRIPTION("MT6358 ALSA SoC codec driver"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/mt6358.h b/sound/soc/codecs/mt6358.h new file mode 100644 index 000000000000..a5953315eaa2 --- /dev/null +++ b/sound/soc/codecs/mt6358.h @@ -0,0 +1,2314 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt6358.h -- mt6358 ALSA SoC audio codec driver + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef __MT6358_H__ +#define __MT6358_H__ + +/* Reg bit define */ +/* MT6358_DCXO_CW14 */ +#define RG_XO_AUDIO_EN_M_SFT 13 + +/* MT6358_DCXO_CW13 */ +#define RG_XO_VOW_EN_SFT 8 + +/* MT6358_AUD_TOP_CKPDN_CON0 */ +#define RG_VOW13M_CK_PDN_SFT 13 +#define RG_VOW13M_CK_PDN_MASK 0x1 +#define RG_VOW13M_CK_PDN_MASK_SFT (0x1 << 13) +#define RG_VOW32K_CK_PDN_SFT 12 +#define RG_VOW32K_CK_PDN_MASK 0x1 +#define RG_VOW32K_CK_PDN_MASK_SFT (0x1 << 12) +#define RG_AUD_INTRP_CK_PDN_SFT 8 +#define RG_AUD_INTRP_CK_PDN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_MASK_SFT (0x1 << 8) +#define RG_PAD_AUD_CLK_MISO_CK_PDN_SFT 7 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK 0x1 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK_SFT (0x1 << 7) +#define RG_AUDNCP_CK_PDN_SFT 6 +#define RG_AUDNCP_CK_PDN_MASK 0x1 +#define RG_AUDNCP_CK_PDN_MASK_SFT (0x1 << 6) +#define RG_ZCD13M_CK_PDN_SFT 5 +#define RG_ZCD13M_CK_PDN_MASK 0x1 +#define RG_ZCD13M_CK_PDN_MASK_SFT (0x1 << 5) +#define RG_AUDIF_CK_PDN_SFT 2 +#define RG_AUDIF_CK_PDN_MASK 0x1 +#define RG_AUDIF_CK_PDN_MASK_SFT (0x1 << 2) +#define RG_AUD_CK_PDN_SFT 1 +#define RG_AUD_CK_PDN_MASK 0x1 +#define RG_AUD_CK_PDN_MASK_SFT (0x1 << 1) +#define RG_ACCDET_CK_PDN_SFT 0 +#define RG_ACCDET_CK_PDN_MASK 0x1 +#define RG_ACCDET_CK_PDN_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CKPDN_CON0_SET */ +#define RG_AUD_TOP_CKPDN_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK_SFT (0x3fff << 0) + +/* MT6358_AUD_TOP_CKPDN_CON0_CLR */ +#define RG_AUD_TOP_CKPDN_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK_SFT (0x3fff << 0) + +/* MT6358_AUD_TOP_CKSEL_CON0 */ +#define RG_AUDIF_CK_CKSEL_SFT 3 +#define RG_AUDIF_CK_CKSEL_MASK 0x1 +#define RG_AUDIF_CK_CKSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_CKSEL_SFT 2 +#define RG_AUD_CK_CKSEL_MASK 0x1 +#define RG_AUD_CK_CKSEL_MASK_SFT (0x1 << 2) + +/* MT6358_AUD_TOP_CKSEL_CON0_SET */ +#define RG_AUD_TOP_CKSEL_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_CKSEL_CON0_CLR */ +#define RG_AUD_TOP_CKSEL_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_CKTST_CON0 */ +#define RG_VOW13M_CK_TSTSEL_SFT 9 +#define RG_VOW13M_CK_TSTSEL_MASK 0x1 +#define RG_VOW13M_CK_TSTSEL_MASK_SFT (0x1 << 9) +#define RG_VOW13M_CK_TST_DIS_SFT 8 +#define RG_VOW13M_CK_TST_DIS_MASK 0x1 +#define RG_VOW13M_CK_TST_DIS_MASK_SFT (0x1 << 8) +#define RG_AUD26M_CK_TSTSEL_SFT 4 +#define RG_AUD26M_CK_TSTSEL_MASK 0x1 +#define RG_AUD26M_CK_TSTSEL_MASK_SFT (0x1 << 4) +#define RG_AUDIF_CK_TSTSEL_SFT 3 +#define RG_AUDIF_CK_TSTSEL_MASK 0x1 +#define RG_AUDIF_CK_TSTSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_TSTSEL_SFT 2 +#define RG_AUD_CK_TSTSEL_MASK 0x1 +#define RG_AUD_CK_TSTSEL_MASK_SFT (0x1 << 2) +#define RG_AUD26M_CK_TST_DIS_SFT 0 +#define RG_AUD26M_CK_TST_DIS_MASK 0x1 +#define RG_AUD26M_CK_TST_DIS_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0 */ +#define RG_AUD_INTRP_CK_PDN_HWEN_SFT 0 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0_SET */ +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_SFT 0 +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK 0xffff +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0_CLR */ +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_SFT 0 +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK 0xffff +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_RST_CON0 */ +#define RG_AUDNCP_RST_SFT 3 +#define RG_AUDNCP_RST_MASK 0x1 +#define RG_AUDNCP_RST_MASK_SFT (0x1 << 3) +#define RG_ZCD_RST_SFT 2 +#define RG_ZCD_RST_MASK 0x1 +#define RG_ZCD_RST_MASK_SFT (0x1 << 2) +#define RG_ACCDET_RST_SFT 1 +#define RG_ACCDET_RST_MASK 0x1 +#define RG_ACCDET_RST_MASK_SFT (0x1 << 1) +#define RG_AUDIO_RST_SFT 0 +#define RG_AUDIO_RST_MASK 0x1 +#define RG_AUDIO_RST_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_RST_CON0_SET */ +#define RG_AUD_TOP_RST_CON0_SET_SFT 0 +#define RG_AUD_TOP_RST_CON0_SET_MASK 0xf +#define RG_AUD_TOP_RST_CON0_SET_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_RST_CON0_CLR */ +#define RG_AUD_TOP_RST_CON0_CLR_SFT 0 +#define RG_AUD_TOP_RST_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_RST_CON0_CLR_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_RST_BANK_CON0 */ +#define BANK_AUDZCD_SWRST_SFT 2 +#define BANK_AUDZCD_SWRST_MASK 0x1 +#define BANK_AUDZCD_SWRST_MASK_SFT (0x1 << 2) +#define BANK_AUDIO_SWRST_SFT 1 +#define BANK_AUDIO_SWRST_MASK 0x1 +#define BANK_AUDIO_SWRST_MASK_SFT (0x1 << 1) +#define BANK_ACCDET_SWRST_SFT 0 +#define BANK_ACCDET_SWRST_MASK 0x1 +#define BANK_ACCDET_SWRST_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_INT_CON0 */ +#define RG_INT_EN_AUDIO_SFT 0 +#define RG_INT_EN_AUDIO_MASK 0x1 +#define RG_INT_EN_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_EN_ACCDET_SFT 5 +#define RG_INT_EN_ACCDET_MASK 0x1 +#define RG_INT_EN_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_EN_ACCDET_EINT0_SFT 6 +#define RG_INT_EN_ACCDET_EINT0_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_EN_ACCDET_EINT1_SFT 7 +#define RG_INT_EN_ACCDET_EINT1_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_CON0_SET */ +#define RG_AUD_INT_CON0_SET_SFT 0 +#define RG_AUD_INT_CON0_SET_MASK 0xffff +#define RG_AUD_INT_CON0_SET_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_INT_CON0_CLR */ +#define RG_AUD_INT_CON0_CLR_SFT 0 +#define RG_AUD_INT_CON0_CLR_MASK 0xffff +#define RG_AUD_INT_CON0_CLR_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_INT_MASK_CON0 */ +#define RG_INT_MASK_AUDIO_SFT 0 +#define RG_INT_MASK_AUDIO_MASK 0x1 +#define RG_INT_MASK_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_MASK_ACCDET_SFT 5 +#define RG_INT_MASK_ACCDET_MASK 0x1 +#define RG_INT_MASK_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_MASK_ACCDET_EINT0_SFT 6 +#define RG_INT_MASK_ACCDET_EINT0_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_MASK_ACCDET_EINT1_SFT 7 +#define RG_INT_MASK_ACCDET_EINT1_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_MASK_CON0_SET */ +#define RG_AUD_INT_MASK_CON0_SET_SFT 0 +#define RG_AUD_INT_MASK_CON0_SET_MASK 0xff +#define RG_AUD_INT_MASK_CON0_SET_MASK_SFT (0xff << 0) + +/* MT6358_AUD_TOP_INT_MASK_CON0_CLR */ +#define RG_AUD_INT_MASK_CON0_CLR_SFT 0 +#define RG_AUD_INT_MASK_CON0_CLR_MASK 0xff +#define RG_AUD_INT_MASK_CON0_CLR_MASK_SFT (0xff << 0) + +/* MT6358_AUD_TOP_INT_STATUS0 */ +#define RG_INT_STATUS_AUDIO_SFT 0 +#define RG_INT_STATUS_AUDIO_MASK 0x1 +#define RG_INT_STATUS_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_STATUS_ACCDET_SFT 5 +#define RG_INT_STATUS_ACCDET_MASK 0x1 +#define RG_INT_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_RAW_STATUS0 */ +#define RG_INT_RAW_STATUS_AUDIO_SFT 0 +#define RG_INT_RAW_STATUS_AUDIO_MASK 0x1 +#define RG_INT_RAW_STATUS_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_RAW_STATUS_ACCDET_SFT 5 +#define RG_INT_RAW_STATUS_ACCDET_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_RAW_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_RAW_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_MISC_CON0 */ +#define RG_AUD_TOP_INT_POLARITY_SFT 0 +#define RG_AUD_TOP_INT_POLARITY_MASK 0x1 +#define RG_AUD_TOP_INT_POLARITY_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON0 */ +#define RG_DIVCKS_CHG_SFT 0 +#define RG_DIVCKS_CHG_MASK 0x1 +#define RG_DIVCKS_CHG_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON1 */ +#define RG_DIVCKS_ON_SFT 0 +#define RG_DIVCKS_ON_MASK 0x1 +#define RG_DIVCKS_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON2 */ +#define RG_DIVCKS_PRG_SFT 0 +#define RG_DIVCKS_PRG_MASK 0x1ff +#define RG_DIVCKS_PRG_MASK_SFT (0x1ff << 0) + +/* MT6358_AUDNCP_CLKDIV_CON3 */ +#define RG_DIVCKS_PWD_NCP_SFT 0 +#define RG_DIVCKS_PWD_NCP_MASK 0x1 +#define RG_DIVCKS_PWD_NCP_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON4 */ +#define RG_DIVCKS_PWD_NCP_ST_SEL_SFT 0 +#define RG_DIVCKS_PWD_NCP_ST_SEL_MASK 0x3 +#define RG_DIVCKS_PWD_NCP_ST_SEL_MASK_SFT (0x3 << 0) + +/* MT6358_AUD_TOP_MON_CON0 */ +#define RG_AUD_TOP_MON_SEL_SFT 0 +#define RG_AUD_TOP_MON_SEL_MASK 0x7 +#define RG_AUD_TOP_MON_SEL_MASK_SFT (0x7 << 0) +#define RG_AUD_CLK_INT_MON_FLAG_SEL_SFT 3 +#define RG_AUD_CLK_INT_MON_FLAG_SEL_MASK 0xff +#define RG_AUD_CLK_INT_MON_FLAG_SEL_MASK_SFT (0xff << 3) +#define RG_AUD_CLK_INT_MON_FLAG_EN_SFT 11 +#define RG_AUD_CLK_INT_MON_FLAG_EN_MASK 0x1 +#define RG_AUD_CLK_INT_MON_FLAG_EN_MASK_SFT (0x1 << 11) + +/* MT6358_AUDIO_DIG_DSN_ID */ +#define AUDIO_DIG_ANA_ID_SFT 0 +#define AUDIO_DIG_ANA_ID_MASK 0xff +#define AUDIO_DIG_ANA_ID_MASK_SFT (0xff << 0) +#define AUDIO_DIG_DIG_ID_SFT 8 +#define AUDIO_DIG_DIG_ID_MASK 0xff +#define AUDIO_DIG_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDIO_DIG_DSN_REV0 */ +#define AUDIO_DIG_ANA_MINOR_REV_SFT 0 +#define AUDIO_DIG_ANA_MINOR_REV_MASK 0xf +#define AUDIO_DIG_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDIO_DIG_ANA_MAJOR_REV_SFT 4 +#define AUDIO_DIG_ANA_MAJOR_REV_MASK 0xf +#define AUDIO_DIG_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDIO_DIG_DIG_MINOR_REV_SFT 8 +#define AUDIO_DIG_DIG_MINOR_REV_MASK 0xf +#define AUDIO_DIG_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDIO_DIG_DIG_MAJOR_REV_SFT 12 +#define AUDIO_DIG_DIG_MAJOR_REV_MASK 0xf +#define AUDIO_DIG_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDIO_DIG_DSN_DBI */ +#define AUDIO_DIG_DSN_CBS_SFT 0 +#define AUDIO_DIG_DSN_CBS_MASK 0x3 +#define AUDIO_DIG_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDIO_DIG_DSN_BIX_SFT 2 +#define AUDIO_DIG_DSN_BIX_MASK 0x3 +#define AUDIO_DIG_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDIO_DIG_ESP_SFT 8 +#define AUDIO_DIG_ESP_MASK 0xff +#define AUDIO_DIG_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDIO_DIG_DSN_DXI */ +#define AUDIO_DIG_DSN_FPI_SFT 0 +#define AUDIO_DIG_DSN_FPI_MASK 0xff +#define AUDIO_DIG_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AFE_UL_DL_CON0 */ +#define AFE_UL_LR_SWAP_SFT 15 +#define AFE_UL_LR_SWAP_MASK 0x1 +#define AFE_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_DL_LR_SWAP_SFT 14 +#define AFE_DL_LR_SWAP_MASK 0x1 +#define AFE_DL_LR_SWAP_MASK_SFT (0x1 << 14) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DL_SRC2_CON0_L */ +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_UL_SRC_CON0_H */ +#define C_DIGMIC_PHASE_SEL_CH1_CTL_SFT 11 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT (0x7 << 11) +#define C_DIGMIC_PHASE_SEL_CH2_CTL_SFT 8 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT (0x7 << 8) +#define C_TWO_DIGITAL_MIC_CTL_SFT 7 +#define C_TWO_DIGITAL_MIC_CTL_MASK 0x1 +#define C_TWO_DIGITAL_MIC_CTL_MASK_SFT (0x1 << 7) + +/* MT6358_AFE_UL_SRC_CON0_L */ +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_TOP_CON0 */ +#define MTKAIF_SINE_ON_SFT 2 +#define MTKAIF_SINE_ON_MASK 0x1 +#define MTKAIF_SINE_ON_MASK_SFT (0x1 << 2) +#define UL_SINE_ON_SFT 1 +#define UL_SINE_ON_MASK 0x1 +#define UL_SINE_ON_MASK_SFT (0x1 << 1) +#define DL_SINE_ON_SFT 0 +#define DL_SINE_ON_MASK 0x1 +#define DL_SINE_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AUDIO_TOP_CON0 */ +#define PDN_AFE_CTL_SFT 7 +#define PDN_AFE_CTL_MASK 0x1 +#define PDN_AFE_CTL_MASK_SFT (0x1 << 7) +#define PDN_DAC_CTL_SFT 6 +#define PDN_DAC_CTL_MASK 0x1 +#define PDN_DAC_CTL_MASK_SFT (0x1 << 6) +#define PDN_ADC_CTL_SFT 5 +#define PDN_ADC_CTL_MASK 0x1 +#define PDN_ADC_CTL_MASK_SFT (0x1 << 5) +#define PDN_I2S_DL_CTL_SFT 3 +#define PDN_I2S_DL_CTL_MASK 0x1 +#define PDN_I2S_DL_CTL_MASK_SFT (0x1 << 3) +#define PWR_CLK_DIS_CTL_SFT 2 +#define PWR_CLK_DIS_CTL_MASK 0x1 +#define PWR_CLK_DIS_CTL_MASK_SFT (0x1 << 2) +#define PDN_AFE_TESTMODEL_CTL_SFT 1 +#define PDN_AFE_TESTMODEL_CTL_MASK 0x1 +#define PDN_AFE_TESTMODEL_CTL_MASK_SFT (0x1 << 1) +#define PDN_RESERVED_SFT 0 +#define PDN_RESERVED_MASK 0x1 +#define PDN_RESERVED_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_MON_DEBUG0 */ +#define AUDIO_SYS_TOP_MON_SWAP_SFT 14 +#define AUDIO_SYS_TOP_MON_SWAP_MASK 0x3 +#define AUDIO_SYS_TOP_MON_SWAP_MASK_SFT (0x3 << 14) +#define AUDIO_SYS_TOP_MON_SEL_SFT 8 +#define AUDIO_SYS_TOP_MON_SEL_MASK 0x1f +#define AUDIO_SYS_TOP_MON_SEL_MASK_SFT (0x1f << 8) +#define AFE_MON_SEL_SFT 0 +#define AFE_MON_SEL_MASK 0xff +#define AFE_MON_SEL_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON0 */ +#define CCI_AUD_ANACK_SEL_SFT 15 +#define CCI_AUD_ANACK_SEL_MASK 0x1 +#define CCI_AUD_ANACK_SEL_MASK_SFT (0x1 << 15) +#define CCI_AUDIO_FIFO_WPTR_SFT 12 +#define CCI_AUDIO_FIFO_WPTR_MASK 0x7 +#define CCI_AUDIO_FIFO_WPTR_MASK_SFT (0x7 << 12) +#define CCI_SCRAMBLER_CG_EN_SFT 11 +#define CCI_SCRAMBLER_CG_EN_MASK 0x1 +#define CCI_SCRAMBLER_CG_EN_MASK_SFT (0x1 << 11) +#define CCI_LCH_INV_SFT 10 +#define CCI_LCH_INV_MASK 0x1 +#define CCI_LCH_INV_MASK_SFT (0x1 << 10) +#define CCI_RAND_EN_SFT 9 +#define CCI_RAND_EN_MASK 0x1 +#define CCI_RAND_EN_MASK_SFT (0x1 << 9) +#define CCI_SPLT_SCRMB_CLK_ON_SFT 8 +#define CCI_SPLT_SCRMB_CLK_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_CLK_ON_MASK_SFT (0x1 << 8) +#define CCI_SPLT_SCRMB_ON_SFT 7 +#define CCI_SPLT_SCRMB_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_ON_MASK_SFT (0x1 << 7) +#define CCI_AUD_IDAC_TEST_EN_SFT 6 +#define CCI_AUD_IDAC_TEST_EN_MASK 0x1 +#define CCI_AUD_IDAC_TEST_EN_MASK_SFT (0x1 << 6) +#define CCI_ZERO_PAD_DISABLE_SFT 5 +#define CCI_ZERO_PAD_DISABLE_MASK 0x1 +#define CCI_ZERO_PAD_DISABLE_MASK_SFT (0x1 << 5) +#define CCI_AUD_SPLIT_TEST_EN_SFT 4 +#define CCI_AUD_SPLIT_TEST_EN_MASK 0x1 +#define CCI_AUD_SPLIT_TEST_EN_MASK_SFT (0x1 << 4) +#define CCI_AUD_SDM_MUTEL_SFT 3 +#define CCI_AUD_SDM_MUTEL_MASK 0x1 +#define CCI_AUD_SDM_MUTEL_MASK_SFT (0x1 << 3) +#define CCI_AUD_SDM_MUTER_SFT 2 +#define CCI_AUD_SDM_MUTER_MASK 0x1 +#define CCI_AUD_SDM_MUTER_MASK_SFT (0x1 << 2) +#define CCI_AUD_SDM_7BIT_SEL_SFT 1 +#define CCI_AUD_SDM_7BIT_SEL_MASK 0x1 +#define CCI_AUD_SDM_7BIT_SEL_MASK_SFT (0x1 << 1) +#define CCI_SCRAMBLER_EN_SFT 0 +#define CCI_SCRAMBLER_EN_MASK 0x1 +#define CCI_SCRAMBLER_EN_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON1 */ +#define AUD_SDM_TEST_L_SFT 8 +#define AUD_SDM_TEST_L_MASK 0xff +#define AUD_SDM_TEST_L_MASK_SFT (0xff << 8) +#define AUD_SDM_TEST_R_SFT 0 +#define AUD_SDM_TEST_R_MASK 0xff +#define AUD_SDM_TEST_R_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON2 */ +#define CCI_AUD_DAC_ANA_MUTE_SFT 7 +#define CCI_AUD_DAC_ANA_MUTE_MASK 0x1 +#define CCI_AUD_DAC_ANA_MUTE_MASK_SFT (0x1 << 7) +#define CCI_AUD_DAC_ANA_RSTB_SEL_SFT 6 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK 0x1 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK_SFT (0x1 << 6) +#define CCI_AUDIO_FIFO_CLKIN_INV_SFT 4 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK 0x1 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK_SFT (0x1 << 4) +#define CCI_AUDIO_FIFO_ENABLE_SFT 3 +#define CCI_AUDIO_FIFO_ENABLE_MASK 0x1 +#define CCI_AUDIO_FIFO_ENABLE_MASK_SFT (0x1 << 3) +#define CCI_ACD_MODE_SFT 2 +#define CCI_ACD_MODE_MASK 0x1 +#define CCI_ACD_MODE_MASK_SFT (0x1 << 2) +#define CCI_AFIFO_CLK_PWDB_SFT 1 +#define CCI_AFIFO_CLK_PWDB_MASK 0x1 +#define CCI_AFIFO_CLK_PWDB_MASK_SFT (0x1 << 1) +#define CCI_ACD_FUNC_RSTB_SFT 0 +#define CCI_ACD_FUNC_RSTB_MASK 0x1 +#define CCI_ACD_FUNC_RSTB_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON3 */ +#define SDM_ANA13M_TESTCK_SEL_SFT 15 +#define SDM_ANA13M_TESTCK_SEL_MASK 0x1 +#define SDM_ANA13M_TESTCK_SEL_MASK_SFT (0x1 << 15) +#define SDM_ANA13M_TESTCK_SRC_SEL_SFT 12 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 12) +#define SDM_TESTCK_SRC_SEL_SFT 8 +#define SDM_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_TESTCK_SRC_SEL_MASK_SFT (0x7 << 8) +#define DIGMIC_TESTCK_SRC_SEL_SFT 4 +#define DIGMIC_TESTCK_SRC_SEL_MASK 0x7 +#define DIGMIC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 4) +#define DIGMIC_TESTCK_SEL_SFT 0 +#define DIGMIC_TESTCK_SEL_MASK 0x1 +#define DIGMIC_TESTCK_SEL_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON4 */ +#define UL_FIFO_WCLK_INV_SFT 8 +#define UL_FIFO_WCLK_INV_MASK 0x1 +#define UL_FIFO_WCLK_INV_MASK_SFT (0x1 << 8) +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_SFT 6 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 6) +#define UL_FIFO_WDATA_TESTEN_SFT 5 +#define UL_FIFO_WDATA_TESTEN_MASK 0x1 +#define UL_FIFO_WDATA_TESTEN_MASK_SFT (0x1 << 5) +#define UL_FIFO_WDATA_TESTSRC_SEL_SFT 4 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 4) +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_SFT 3 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK 0x1 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK_SFT (0x1 << 3) +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_SFT 0 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK 0x7 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 0) + +/* MT6358_AFUNC_AUD_CON5 */ +#define R_AUD_DAC_POS_LARGE_MONO_SFT 8 +#define R_AUD_DAC_POS_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_POS_LARGE_MONO_MASK_SFT (0xff << 8) +#define R_AUD_DAC_NEG_LARGE_MONO_SFT 0 +#define R_AUD_DAC_NEG_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_NEG_LARGE_MONO_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON6 */ +#define R_AUD_DAC_POS_SMALL_MONO_SFT 12 +#define R_AUD_DAC_POS_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_POS_SMALL_MONO_MASK_SFT (0xf << 12) +#define R_AUD_DAC_NEG_SMALL_MONO_SFT 8 +#define R_AUD_DAC_NEG_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_NEG_SMALL_MONO_MASK_SFT (0xf << 8) +#define R_AUD_DAC_POS_TINY_MONO_SFT 6 +#define R_AUD_DAC_POS_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_POS_TINY_MONO_MASK_SFT (0x3 << 6) +#define R_AUD_DAC_NEG_TINY_MONO_SFT 4 +#define R_AUD_DAC_NEG_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_NEG_TINY_MONO_MASK_SFT (0x3 << 4) +#define R_AUD_DAC_MONO_SEL_SFT 3 +#define R_AUD_DAC_MONO_SEL_MASK 0x1 +#define R_AUD_DAC_MONO_SEL_MASK_SFT (0x1 << 3) +#define R_AUD_DAC_SW_RSTB_SFT 0 +#define R_AUD_DAC_SW_RSTB_MASK 0x1 +#define R_AUD_DAC_SW_RSTB_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_MON0 */ +#define AUD_SCR_OUT_L_SFT 8 +#define AUD_SCR_OUT_L_MASK 0xff +#define AUD_SCR_OUT_L_MASK_SFT (0xff << 8) +#define AUD_SCR_OUT_R_SFT 0 +#define AUD_SCR_OUT_R_MASK 0xff +#define AUD_SCR_OUT_R_MASK_SFT (0xff << 0) + +/* MT6358_AUDRC_TUNE_MON0 */ +#define ASYNC_TEST_OUT_BCK_SFT 15 +#define ASYNC_TEST_OUT_BCK_MASK 0x1 +#define ASYNC_TEST_OUT_BCK_MASK_SFT (0x1 << 15) +#define RGS_AUDRCTUNE1READ_SFT 8 +#define RGS_AUDRCTUNE1READ_MASK 0x1f +#define RGS_AUDRCTUNE1READ_MASK_SFT (0x1f << 8) +#define RGS_AUDRCTUNE0READ_SFT 0 +#define RGS_AUDRCTUNE0READ_MASK 0x1f +#define RGS_AUDRCTUNE0READ_MASK_SFT (0x1f << 0) + +/* MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0 */ +#define AFE_RESERVED_SFT 1 +#define AFE_RESERVED_MASK 0x7fff +#define AFE_RESERVED_MASK_SFT (0x7fff << 1) +#define RG_MTKAIF_RXIF_FIFO_INTEN_SFT 0 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK 0x1 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 */ +#define MTKAIF_RXIF_WR_FULL_STATUS_SFT 1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK 0x1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK_SFT (0x1 << 1) +#define MTKAIF_RXIF_RD_EMPTY_STATUS_SFT 0 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK 0x1 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON0 */ +#define MTKAIFTX_V3_SYNC_OUT_SFT 14 +#define MTKAIFTX_V3_SYNC_OUT_MASK 0x1 +#define MTKAIFTX_V3_SYNC_OUT_MASK_SFT (0x1 << 14) +#define MTKAIFTX_V3_SDATA_OUT2_SFT 13 +#define MTKAIFTX_V3_SDATA_OUT2_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT2_MASK_SFT (0x1 << 13) +#define MTKAIFTX_V3_SDATA_OUT1_SFT 12 +#define MTKAIFTX_V3_SDATA_OUT1_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_FIFO_STATUS_SFT 0 +#define MTKAIF_RXIF_FIFO_STATUS_MASK 0xfff +#define MTKAIF_RXIF_FIFO_STATUS_MASK_SFT (0xfff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON1 */ +#define MTKAIFRX_V3_SYNC_IN_SFT 14 +#define MTKAIFRX_V3_SYNC_IN_MASK 0x1 +#define MTKAIFRX_V3_SYNC_IN_MASK_SFT (0x1 << 14) +#define MTKAIFRX_V3_SDATA_IN2_SFT 13 +#define MTKAIFRX_V3_SDATA_IN2_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN2_MASK_SFT (0x1 << 13) +#define MTKAIFRX_V3_SDATA_IN1_SFT 12 +#define MTKAIFRX_V3_SDATA_IN1_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_SFT 11 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK 0x1 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK_SFT (0x1 << 11) +#define MTKAIF_RXIF_INVALID_FLAG_SFT 8 +#define MTKAIF_RXIF_INVALID_FLAG_MASK 0x1 +#define MTKAIF_RXIF_INVALID_FLAG_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_INVALID_CYCLE_SFT 0 +#define MTKAIF_RXIF_INVALID_CYCLE_MASK 0xff +#define MTKAIF_RXIF_INVALID_CYCLE_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON2 */ +#define MTKAIF_TXIF_IN_CH2_SFT 8 +#define MTKAIF_TXIF_IN_CH2_MASK 0xff +#define MTKAIF_TXIF_IN_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_TXIF_IN_CH1_SFT 0 +#define MTKAIF_TXIF_IN_CH1_MASK 0xff +#define MTKAIF_TXIF_IN_CH1_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON3 */ +#define MTKAIF_RXIF_OUT_CH2_SFT 8 +#define MTKAIF_RXIF_OUT_CH2_MASK 0xff +#define MTKAIF_RXIF_OUT_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_RXIF_OUT_CH1_SFT 0 +#define MTKAIF_RXIF_OUT_CH1_MASK 0xff +#define MTKAIF_RXIF_OUT_CH1_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_CFG0 */ +#define RG_MTKAIF_RXIF_CLKINV_SFT 15 +#define RG_MTKAIF_RXIF_CLKINV_MASK 0x1 +#define RG_MTKAIF_RXIF_CLKINV_MASK_SFT (0x1 << 15) +#define RG_MTKAIF_RXIF_PROTOCOL2_SFT 8 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 8) +#define RG_MTKAIF_BYPASS_SRC_MODE_SFT 6 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK 0x3 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK_SFT (0x3 << 6) +#define RG_MTKAIF_BYPASS_SRC_TEST_SFT 5 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK 0x1 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK_SFT (0x1 << 5) +#define RG_MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define RG_MTKAIF_PMIC_TXIF_8TO5_SFT 2 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK 0x1 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define RG_MTKAIF_LOOPBACK_TEST2_SFT 1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK_SFT (0x1 << 1) +#define RG_MTKAIF_LOOPBACK_TEST1_SFT 0 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG0 */ +#define RG_MTKAIF_RXIF_VOICE_MODE_SFT 12 +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_DATA_BIT_SFT 8 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK 0x7 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK_SFT (0x7 << 8) +#define RG_MTKAIF_RXIF_FIFO_RSP_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK_SFT (0x1 << 3) +#define RG_MTKAIF_RXIF_DATA_MODE_SFT 0 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK 0x1 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG1 */ +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_SFT 12 +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_SFT 8 +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8) +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_SFT 4 +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4) +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_SFT 0 +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK_SFT (0xf << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG2 */ +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_SFT 12 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK 0x1 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK_SFT (0x1 << 12) +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_SFT 0 +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK 0xfff +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG3 */ +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_SFT 7 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK 0x1 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK_SFT (0x1 << 7) +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 3) + +/* MT6358_AFE_ADDA_MTKAIF_TX_CFG1 */ +#define RG_MTKAIF_SYNC_WORD2_SFT 4 +#define RG_MTKAIF_SYNC_WORD2_MASK 0x7 +#define RG_MTKAIF_SYNC_WORD2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_SYNC_WORD1_SFT 0 +#define RG_MTKAIF_SYNC_WORD1_MASK 0x7 +#define RG_MTKAIF_SYNC_WORD1_MASK_SFT (0x7 << 0) + +/* MT6358_AFE_SGEN_CFG0 */ +#define SGEN_AMP_DIV_CH1_CTL_SFT 12 +#define SGEN_AMP_DIV_CH1_CTL_MASK 0xf +#define SGEN_AMP_DIV_CH1_CTL_MASK_SFT (0xf << 12) +#define SGEN_DAC_EN_CTL_SFT 7 +#define SGEN_DAC_EN_CTL_MASK 0x1 +#define SGEN_DAC_EN_CTL_MASK_SFT (0x1 << 7) +#define SGEN_MUTE_SW_CTL_SFT 6 +#define SGEN_MUTE_SW_CTL_MASK 0x1 +#define SGEN_MUTE_SW_CTL_MASK_SFT (0x1 << 6) +#define R_AUD_SDM_MUTE_L_SFT 5 +#define R_AUD_SDM_MUTE_L_MASK 0x1 +#define R_AUD_SDM_MUTE_L_MASK_SFT (0x1 << 5) +#define R_AUD_SDM_MUTE_R_SFT 4 +#define R_AUD_SDM_MUTE_R_MASK 0x1 +#define R_AUD_SDM_MUTE_R_MASK_SFT (0x1 << 4) + +/* MT6358_AFE_SGEN_CFG1 */ +#define C_SGEN_RCH_INV_5BIT_SFT 15 +#define C_SGEN_RCH_INV_5BIT_MASK 0x1 +#define C_SGEN_RCH_INV_5BIT_MASK_SFT (0x1 << 15) +#define C_SGEN_RCH_INV_8BIT_SFT 14 +#define C_SGEN_RCH_INV_8BIT_MASK 0x1 +#define C_SGEN_RCH_INV_8BIT_MASK_SFT (0x1 << 14) +#define SGEN_FREQ_DIV_CH1_CTL_SFT 0 +#define SGEN_FREQ_DIV_CH1_CTL_MASK 0x1f +#define SGEN_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 0) + +/* MT6358_AFE_ADC_ASYNC_FIFO_CFG */ +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_SFT 5 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 5) +#define RG_UL_ASYNC_FIFO_SOFT_RST_SFT 4 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK_SFT (0x1 << 4) +#define RG_AMIC_UL_ADC_CLK_SEL_SFT 1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK 0x1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK_SFT (0x1 << 1) + +/* MT6358_AFE_DCCLK_CFG0 */ +#define DCCLK_DIV_SFT 5 +#define DCCLK_DIV_MASK 0x7ff +#define DCCLK_DIV_MASK_SFT (0x7ff << 5) +#define DCCLK_INV_SFT 4 +#define DCCLK_INV_MASK 0x1 +#define DCCLK_INV_MASK_SFT (0x1 << 4) +#define DCCLK_PDN_SFT 1 +#define DCCLK_PDN_MASK 0x1 +#define DCCLK_PDN_MASK_SFT (0x1 << 1) +#define DCCLK_GEN_ON_SFT 0 +#define DCCLK_GEN_ON_MASK 0x1 +#define DCCLK_GEN_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DCCLK_CFG1 */ +#define RESYNC_SRC_SEL_SFT 10 +#define RESYNC_SRC_SEL_MASK 0x3 +#define RESYNC_SRC_SEL_MASK_SFT (0x3 << 10) +#define RESYNC_SRC_CK_INV_SFT 9 +#define RESYNC_SRC_CK_INV_MASK 0x1 +#define RESYNC_SRC_CK_INV_MASK_SFT (0x1 << 9) +#define DCCLK_RESYNC_BYPASS_SFT 8 +#define DCCLK_RESYNC_BYPASS_MASK 0x1 +#define DCCLK_RESYNC_BYPASS_MASK_SFT (0x1 << 8) +#define DCCLK_PHASE_SEL_SFT 4 +#define DCCLK_PHASE_SEL_MASK 0xf +#define DCCLK_PHASE_SEL_MASK_SFT (0xf << 4) + +/* MT6358_AUDIO_DIG_CFG */ +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT 15 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT (0x1 << 15) +#define RG_AUD_PAD_TOP_PHASE_MODE2_SFT 8 +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT (0x7f << 8) +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT 7 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT (0x1 << 7) +#define RG_AUD_PAD_TOP_PHASE_MODE_SFT 0 +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT (0x7f << 0) + +/* MT6358_AFE_AUD_PAD_TOP */ +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_SFT 12 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK 0x7 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK_SFT (0x7 << 12) +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_SFT 11 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK 0x1 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK_SFT (0x1 << 11) +#define RG_AUD_PAD_TOP_TX_FIFO_ON_SFT 8 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK 0x1 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK_SFT (0x1 << 8) + +/* MT6358_AFE_AUD_PAD_TOP_MON */ +#define ADDA_AUD_PAD_TOP_MON_SFT 0 +#define ADDA_AUD_PAD_TOP_MON_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_AUD_PAD_TOP_MON1 */ +#define ADDA_AUD_PAD_TOP_MON1_SFT 0 +#define ADDA_AUD_PAD_TOP_MON1_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON1_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_DL_NLE_CFG */ +#define NLE_RCH_HPGAIN_SEL_SFT 10 +#define NLE_RCH_HPGAIN_SEL_MASK 0x1 +#define NLE_RCH_HPGAIN_SEL_MASK_SFT (0x1 << 10) +#define NLE_RCH_CH_SEL_SFT 9 +#define NLE_RCH_CH_SEL_MASK 0x1 +#define NLE_RCH_CH_SEL_MASK_SFT (0x1 << 9) +#define NLE_RCH_ON_SFT 8 +#define NLE_RCH_ON_MASK 0x1 +#define NLE_RCH_ON_MASK_SFT (0x1 << 8) +#define NLE_LCH_HPGAIN_SEL_SFT 2 +#define NLE_LCH_HPGAIN_SEL_MASK 0x1 +#define NLE_LCH_HPGAIN_SEL_MASK_SFT (0x1 << 2) +#define NLE_LCH_CH_SEL_SFT 1 +#define NLE_LCH_CH_SEL_MASK 0x1 +#define NLE_LCH_CH_SEL_MASK_SFT (0x1 << 1) +#define NLE_LCH_ON_SFT 0 +#define NLE_LCH_ON_MASK 0x1 +#define NLE_LCH_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DL_NLE_MON */ +#define NLE_MONITOR_SFT 0 +#define NLE_MONITOR_MASK 0x3fff +#define NLE_MONITOR_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_CG_EN_MON */ +#define CK_CG_EN_MON_SFT 0 +#define CK_CG_EN_MON_MASK 0x3f +#define CK_CG_EN_MON_MASK_SFT (0x3f << 0) + +/* MT6358_AFE_VOW_TOP */ +#define PDN_VOW_SFT 15 +#define PDN_VOW_MASK 0x1 +#define PDN_VOW_MASK_SFT (0x1 << 15) +#define VOW_1P6M_800K_SEL_SFT 14 +#define VOW_1P6M_800K_SEL_MASK 0x1 +#define VOW_1P6M_800K_SEL_MASK_SFT (0x1 << 14) +#define VOW_DIGMIC_ON_SFT 13 +#define VOW_DIGMIC_ON_MASK 0x1 +#define VOW_DIGMIC_ON_MASK_SFT (0x1 << 13) +#define VOW_CK_DIV_RST_SFT 12 +#define VOW_CK_DIV_RST_MASK 0x1 +#define VOW_CK_DIV_RST_MASK_SFT (0x1 << 12) +#define VOW_ON_SFT 11 +#define VOW_ON_MASK 0x1 +#define VOW_ON_MASK_SFT (0x1 << 11) +#define VOW_DIGMIC_CK_PHASE_SEL_SFT 8 +#define VOW_DIGMIC_CK_PHASE_SEL_MASK 0x7 +#define VOW_DIGMIC_CK_PHASE_SEL_MASK_SFT (0x7 << 8) +#define MAIN_DMIC_CK_VOW_SEL_SFT 7 +#define MAIN_DMIC_CK_VOW_SEL_MASK 0x1 +#define MAIN_DMIC_CK_VOW_SEL_MASK_SFT (0x1 << 7) +#define VOW_SDM_3_LEVEL_SFT 6 +#define VOW_SDM_3_LEVEL_MASK 0x1 +#define VOW_SDM_3_LEVEL_MASK_SFT (0x1 << 6) +#define VOW_LOOP_BACK_MODE_SFT 5 +#define VOW_LOOP_BACK_MODE_MASK 0x1 +#define VOW_LOOP_BACK_MODE_MASK_SFT (0x1 << 5) +#define VOW_INTR_SOURCE_SEL_SFT 4 +#define VOW_INTR_SOURCE_SEL_MASK 0x1 +#define VOW_INTR_SOURCE_SEL_MASK_SFT (0x1 << 4) +#define VOW_INTR_CLR_SFT 3 +#define VOW_INTR_CLR_MASK 0x1 +#define VOW_INTR_CLR_MASK_SFT (0x1 << 3) +#define S_N_VALUE_RST_SFT 2 +#define S_N_VALUE_RST_MASK 0x1 +#define S_N_VALUE_RST_MASK_SFT (0x1 << 2) +#define SAMPLE_BASE_MODE_SFT 1 +#define SAMPLE_BASE_MODE_MASK 0x1 +#define SAMPLE_BASE_MODE_MASK_SFT (0x1 << 1) +#define VOW_INTR_FLAG_SFT 0 +#define VOW_INTR_FLAG_MASK 0x1 +#define VOW_INTR_FLAG_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_CFG0 */ +#define AMPREF_SFT 0 +#define AMPREF_MASK 0xffff +#define AMPREF_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG1 */ +#define TIMERINI_SFT 0 +#define TIMERINI_MASK 0xffff +#define TIMERINI_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG2 */ +#define B_DEFAULT_SFT 12 +#define B_DEFAULT_MASK 0x7 +#define B_DEFAULT_MASK_SFT (0x7 << 12) +#define A_DEFAULT_SFT 8 +#define A_DEFAULT_MASK 0x7 +#define A_DEFAULT_MASK_SFT (0x7 << 8) +#define B_INI_SFT 4 +#define B_INI_MASK 0x7 +#define B_INI_MASK_SFT (0x7 << 4) +#define A_INI_SFT 0 +#define A_INI_MASK 0x7 +#define A_INI_MASK_SFT (0x7 << 0) + +/* MT6358_AFE_VOW_CFG3 */ +#define K_BETA_RISE_SFT 12 +#define K_BETA_RISE_MASK 0xf +#define K_BETA_RISE_MASK_SFT (0xf << 12) +#define K_BETA_FALL_SFT 8 +#define K_BETA_FALL_MASK 0xf +#define K_BETA_FALL_MASK_SFT (0xf << 8) +#define K_ALPHA_RISE_SFT 4 +#define K_ALPHA_RISE_MASK 0xf +#define K_ALPHA_RISE_MASK_SFT (0xf << 4) +#define K_ALPHA_FALL_SFT 0 +#define K_ALPHA_FALL_MASK 0xf +#define K_ALPHA_FALL_MASK_SFT (0xf << 0) + +/* MT6358_AFE_VOW_CFG4 */ +#define VOW_TXIF_SCK_INV_SFT 15 +#define VOW_TXIF_SCK_INV_MASK 0x1 +#define VOW_TXIF_SCK_INV_MASK_SFT (0x1 << 15) +#define VOW_ADC_TESTCK_SRC_SEL_SFT 12 +#define VOW_ADC_TESTCK_SRC_SEL_MASK 0x7 +#define VOW_ADC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 12) +#define VOW_ADC_TESTCK_SEL_SFT 11 +#define VOW_ADC_TESTCK_SEL_MASK 0x1 +#define VOW_ADC_TESTCK_SEL_MASK_SFT (0x1 << 11) +#define VOW_ADC_CLK_INV_SFT 10 +#define VOW_ADC_CLK_INV_MASK 0x1 +#define VOW_ADC_CLK_INV_MASK_SFT (0x1 << 10) +#define VOW_TXIF_MONO_SFT 9 +#define VOW_TXIF_MONO_MASK 0x1 +#define VOW_TXIF_MONO_MASK_SFT (0x1 << 9) +#define VOW_TXIF_SCK_DIV_SFT 4 +#define VOW_TXIF_SCK_DIV_MASK 0x1f +#define VOW_TXIF_SCK_DIV_MASK_SFT (0x1f << 4) +#define K_GAMMA_SFT 0 +#define K_GAMMA_MASK 0xf +#define K_GAMMA_MASK_SFT (0xf << 0) + +/* MT6358_AFE_VOW_CFG5 */ +#define N_MIN_SFT 0 +#define N_MIN_MASK 0xffff +#define N_MIN_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG6 */ +#define RG_WINDOW_SIZE_SEL_SFT 12 +#define RG_WINDOW_SIZE_SEL_MASK 0x1 +#define RG_WINDOW_SIZE_SEL_MASK_SFT (0x1 << 12) +#define RG_FLR_BYPASS_SFT 11 +#define RG_FLR_BYPASS_MASK 0x1 +#define RG_FLR_BYPASS_MASK_SFT (0x1 << 11) +#define RG_FLR_RATIO_SFT 8 +#define RG_FLR_RATIO_MASK 0x7 +#define RG_FLR_RATIO_MASK_SFT (0x7 << 8) +#define RG_BUCK_DVFS_DONE_SW_CTL_SFT 7 +#define RG_BUCK_DVFS_DONE_SW_CTL_MASK 0x1 +#define RG_BUCK_DVFS_DONE_SW_CTL_MASK_SFT (0x1 << 7) +#define RG_BUCK_DVFS_DONE_HW_MODE_SFT 6 +#define RG_BUCK_DVFS_DONE_HW_MODE_MASK 0x1 +#define RG_BUCK_DVFS_DONE_HW_MODE_MASK_SFT (0x1 << 6) +#define RG_BUCK_DVFS_HW_CNT_THR_SFT 0 +#define RG_BUCK_DVFS_HW_CNT_THR_MASK 0x3f +#define RG_BUCK_DVFS_HW_CNT_THR_MASK_SFT (0x3f << 0) + +/* MT6358_AFE_VOW_MON0 */ +#define VOW_DOWNCNT_SFT 0 +#define VOW_DOWNCNT_MASK 0xffff +#define VOW_DOWNCNT_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON1 */ +#define K_TMP_MON_SFT 10 +#define K_TMP_MON_MASK 0xf +#define K_TMP_MON_MASK_SFT (0xf << 10) +#define SLT_COUNTER_MON_SFT 7 +#define SLT_COUNTER_MON_MASK 0x7 +#define SLT_COUNTER_MON_MASK_SFT (0x7 << 7) +#define VOW_B_SFT 4 +#define VOW_B_MASK 0x7 +#define VOW_B_MASK_SFT (0x7 << 4) +#define VOW_A_SFT 1 +#define VOW_A_MASK 0x7 +#define VOW_A_MASK_SFT (0x7 << 1) +#define SECOND_CNT_START_SFT 0 +#define SECOND_CNT_START_MASK 0x1 +#define SECOND_CNT_START_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_MON2 */ +#define VOW_S_L_SFT 0 +#define VOW_S_L_MASK 0xffff +#define VOW_S_L_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON3 */ +#define VOW_S_H_SFT 0 +#define VOW_S_H_MASK 0xffff +#define VOW_S_H_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON4 */ +#define VOW_N_L_SFT 0 +#define VOW_N_L_MASK 0xffff +#define VOW_N_L_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON5 */ +#define VOW_N_H_SFT 0 +#define VOW_N_H_MASK 0xffff +#define VOW_N_H_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_SN_INI_CFG */ +#define VOW_SN_INI_CFG_EN_SFT 15 +#define VOW_SN_INI_CFG_EN_MASK 0x1 +#define VOW_SN_INI_CFG_EN_MASK_SFT (0x1 << 15) +#define VOW_SN_INI_CFG_VAL_SFT 0 +#define VOW_SN_INI_CFG_VAL_MASK 0x7fff +#define VOW_SN_INI_CFG_VAL_MASK_SFT (0x7fff << 0) + +/* MT6358_AFE_VOW_TGEN_CFG0 */ +#define VOW_TGEN_EN_SFT 15 +#define VOW_TGEN_EN_MASK 0x1 +#define VOW_TGEN_EN_MASK_SFT (0x1 << 15) +#define VOW_TGEN_MUTE_SW_SFT 14 +#define VOW_TGEN_MUTE_SW_MASK 0x1 +#define VOW_TGEN_MUTE_SW_MASK_SFT (0x1 << 14) +#define VOW_TGEN_FREQ_DIV_SFT 0 +#define VOW_TGEN_FREQ_DIV_MASK 0x3fff +#define VOW_TGEN_FREQ_DIV_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_POSDIV_CFG0 */ +#define BUCK_DVFS_DONE_SFT 15 +#define BUCK_DVFS_DONE_MASK 0x1 +#define BUCK_DVFS_DONE_MASK_SFT (0x1 << 15) +#define VOW_32K_MODE_SFT 13 +#define VOW_32K_MODE_MASK 0x1 +#define VOW_32K_MODE_MASK_SFT (0x1 << 13) +#define RG_BUCK_CLK_DIV_SFT 8 +#define RG_BUCK_CLK_DIV_MASK 0x1f +#define RG_BUCK_CLK_DIV_MASK_SFT (0x1f << 8) +#define RG_A1P6M_EN_SEL_SFT 7 +#define RG_A1P6M_EN_SEL_MASK 0x1 +#define RG_A1P6M_EN_SEL_MASK_SFT (0x1 << 7) +#define VOW_CLK_SEL_SFT 6 +#define VOW_CLK_SEL_MASK 0x1 +#define VOW_CLK_SEL_MASK_SFT (0x1 << 6) +#define VOW_INTR_SW_MODE_SFT 5 +#define VOW_INTR_SW_MODE_MASK 0x1 +#define VOW_INTR_SW_MODE_MASK_SFT (0x1 << 5) +#define VOW_INTR_SW_VAL_SFT 4 +#define VOW_INTR_SW_VAL_MASK 0x1 +#define VOW_INTR_SW_VAL_MASK_SFT (0x1 << 4) +#define VOW_CIC_MODE_SEL_SFT 2 +#define VOW_CIC_MODE_SEL_MASK 0x3 +#define VOW_CIC_MODE_SEL_MASK_SFT (0x3 << 2) +#define RG_VOW_POSDIV_SFT 0 +#define RG_VOW_POSDIV_MASK 0x3 +#define RG_VOW_POSDIV_MASK_SFT (0x3 << 0) + +/* MT6358_AFE_VOW_HPF_CFG0 */ +#define VOW_HPF_DC_TEST_SFT 12 +#define VOW_HPF_DC_TEST_MASK 0xf +#define VOW_HPF_DC_TEST_MASK_SFT (0xf << 12) +#define VOW_IRQ_LATCH_SNR_EN_SFT 10 +#define VOW_IRQ_LATCH_SNR_EN_MASK 0x1 +#define VOW_IRQ_LATCH_SNR_EN_MASK_SFT (0x1 << 10) +#define VOW_DMICCLK_PDN_SFT 9 +#define VOW_DMICCLK_PDN_MASK 0x1 +#define VOW_DMICCLK_PDN_MASK_SFT (0x1 << 9) +#define VOW_POSDIVCLK_PDN_SFT 8 +#define VOW_POSDIVCLK_PDN_MASK 0x1 +#define VOW_POSDIVCLK_PDN_MASK_SFT (0x1 << 8) +#define RG_BASELINE_ALPHA_ORDER_SFT 4 +#define RG_BASELINE_ALPHA_ORDER_MASK 0xf +#define RG_BASELINE_ALPHA_ORDER_MASK_SFT (0xf << 4) +#define RG_MTKAIF_HPF_BYPASS_SFT 2 +#define RG_MTKAIF_HPF_BYPASS_MASK 0x1 +#define RG_MTKAIF_HPF_BYPASS_MASK_SFT (0x1 << 2) +#define RG_SNRDET_HPF_BYPASS_SFT 1 +#define RG_SNRDET_HPF_BYPASS_MASK 0x1 +#define RG_SNRDET_HPF_BYPASS_MASK_SFT (0x1 << 1) +#define RG_HPF_ON_SFT 0 +#define RG_HPF_ON_MASK 0x1 +#define RG_HPF_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG0 */ +#define RG_PERIODIC_EN_SFT 15 +#define RG_PERIODIC_EN_MASK 0x1 +#define RG_PERIODIC_EN_MASK_SFT (0x1 << 15) +#define RG_PERIODIC_CNT_CLR_SFT 14 +#define RG_PERIODIC_CNT_CLR_MASK 0x1 +#define RG_PERIODIC_CNT_CLR_MASK_SFT (0x1 << 14) +#define RG_PERIODIC_CNT_PERIOD_SFT 0 +#define RG_PERIODIC_CNT_PERIOD_MASK 0x3fff +#define RG_PERIODIC_CNT_PERIOD_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG1 */ +#define RG_PERIODIC_CNT_SET_SFT 15 +#define RG_PERIODIC_CNT_SET_MASK 0x1 +#define RG_PERIODIC_CNT_SET_MASK_SFT (0x1 << 15) +#define RG_PERIODIC_CNT_PAUSE_SFT 14 +#define RG_PERIODIC_CNT_PAUSE_MASK 0x1 +#define RG_PERIODIC_CNT_PAUSE_MASK_SFT (0x1 << 14) +#define RG_PERIODIC_CNT_SET_VALUE_SFT 0 +#define RG_PERIODIC_CNT_SET_VALUE_MASK 0x3fff +#define RG_PERIODIC_CNT_SET_VALUE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG2 */ +#define AUDPREAMPLON_PERIODIC_MODE_SFT 15 +#define AUDPREAMPLON_PERIODIC_MODE_MASK 0x1 +#define AUDPREAMPLON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPREAMPLON_PERIODIC_INVERSE_SFT 14 +#define AUDPREAMPLON_PERIODIC_INVERSE_MASK 0x1 +#define AUDPREAMPLON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG3 */ +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_SFT 15 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_MASK 0x1 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_SFT 14 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_MASK 0x1 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG4 */ +#define AUDADCLPWRUP_PERIODIC_MODE_SFT 15 +#define AUDADCLPWRUP_PERIODIC_MODE_MASK 0x1 +#define AUDADCLPWRUP_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDADCLPWRUP_PERIODIC_INVERSE_SFT 14 +#define AUDADCLPWRUP_PERIODIC_INVERSE_MASK 0x1 +#define AUDADCLPWRUP_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_SFT 0 +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG5 */ +#define AUDGLBVOWLPWEN_PERIODIC_MODE_SFT 15 +#define AUDGLBVOWLPWEN_PERIODIC_MODE_MASK 0x1 +#define AUDGLBVOWLPWEN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_SFT 14 +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_MASK 0x1 +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG6 */ +#define AUDDIGMICEN_PERIODIC_MODE_SFT 15 +#define AUDDIGMICEN_PERIODIC_MODE_MASK 0x1 +#define AUDDIGMICEN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDDIGMICEN_PERIODIC_INVERSE_SFT 14 +#define AUDDIGMICEN_PERIODIC_INVERSE_MASK 0x1 +#define AUDDIGMICEN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG7 */ +#define AUDPWDBMICBIAS0_PERIODIC_MODE_SFT 15 +#define AUDPWDBMICBIAS0_PERIODIC_MODE_MASK 0x1 +#define AUDPWDBMICBIAS0_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_SFT 14 +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_MASK 0x1 +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG8 */ +#define AUDPWDBMICBIAS1_PERIODIC_MODE_SFT 15 +#define AUDPWDBMICBIAS1_PERIODIC_MODE_MASK 0x1 +#define AUDPWDBMICBIAS1_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_SFT 14 +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_MASK 0x1 +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG9 */ +#define XO_VOW_CK_EN_PERIODIC_MODE_SFT 15 +#define XO_VOW_CK_EN_PERIODIC_MODE_MASK 0x1 +#define XO_VOW_CK_EN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define XO_VOW_CK_EN_PERIODIC_INVERSE_SFT 14 +#define XO_VOW_CK_EN_PERIODIC_INVERSE_MASK 0x1 +#define XO_VOW_CK_EN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_SFT 0 +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG10 */ +#define AUDGLB_PWRDN_PERIODIC_MODE_SFT 15 +#define AUDGLB_PWRDN_PERIODIC_MODE_MASK 0x1 +#define AUDGLB_PWRDN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDGLB_PWRDN_PERIODIC_INVERSE_SFT 14 +#define AUDGLB_PWRDN_PERIODIC_INVERSE_MASK 0x1 +#define AUDGLB_PWRDN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG11 */ +#define VOW_ON_PERIODIC_MODE_SFT 15 +#define VOW_ON_PERIODIC_MODE_MASK 0x1 +#define VOW_ON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define VOW_ON_PERIODIC_INVERSE_SFT 14 +#define VOW_ON_PERIODIC_INVERSE_MASK 0x1 +#define VOW_ON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define VOW_ON_PERIODIC_ON_CYCLE_SFT 0 +#define VOW_ON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define VOW_ON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG12 */ +#define DMIC_ON_PERIODIC_MODE_SFT 15 +#define DMIC_ON_PERIODIC_MODE_MASK 0x1 +#define DMIC_ON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define DMIC_ON_PERIODIC_INVERSE_SFT 14 +#define DMIC_ON_PERIODIC_INVERSE_MASK 0x1 +#define DMIC_ON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define DMIC_ON_PERIODIC_ON_CYCLE_SFT 0 +#define DMIC_ON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define DMIC_ON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG13 */ +#define PDN_VOW_F32K_CK_SFT 15 +#define PDN_VOW_F32K_CK_MASK 0x1 +#define PDN_VOW_F32K_CK_MASK_SFT (0x1 << 15) +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG14 */ +#define VOW_SNRDET_PERIODIC_CFG_SFT 15 +#define VOW_SNRDET_PERIODIC_CFG_MASK 0x1 +#define VOW_SNRDET_PERIODIC_CFG_MASK_SFT (0x1 << 15) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG15 */ +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG16 */ +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG17 */ +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG18 */ +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG19 */ +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG20 */ +#define CLKSQ_EN_VOW_PERIODIC_MODE_SFT 15 +#define CLKSQ_EN_VOW_PERIODIC_MODE_MASK 0x1 +#define CLKSQ_EN_VOW_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_SFT 0 +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG21 */ +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG22 */ +#define VOW_ON_PERIODIC_OFF_CYCLE_SFT 0 +#define VOW_ON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define VOW_ON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG23 */ +#define DMIC_ON_PERIODIC_OFF_CYCLE_SFT 0 +#define DMIC_ON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define DMIC_ON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_MON0 */ +#define VOW_PERIODIC_MON_SFT 0 +#define VOW_PERIODIC_MON_MASK 0xffff +#define VOW_PERIODIC_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_PERIODIC_MON1 */ +#define VOW_PERIODIC_COUNT_MON_SFT 0 +#define VOW_PERIODIC_COUNT_MON_MASK 0xffff +#define VOW_PERIODIC_COUNT_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AUDENC_DSN_ID */ +#define AUDENC_ANA_ID_SFT 0 +#define AUDENC_ANA_ID_MASK 0xff +#define AUDENC_ANA_ID_MASK_SFT (0xff << 0) +#define AUDENC_DIG_ID_SFT 8 +#define AUDENC_DIG_ID_MASK 0xff +#define AUDENC_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDENC_DSN_REV0 */ +#define AUDENC_ANA_MINOR_REV_SFT 0 +#define AUDENC_ANA_MINOR_REV_MASK 0xf +#define AUDENC_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDENC_ANA_MAJOR_REV_SFT 4 +#define AUDENC_ANA_MAJOR_REV_MASK 0xf +#define AUDENC_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDENC_DIG_MINOR_REV_SFT 8 +#define AUDENC_DIG_MINOR_REV_MASK 0xf +#define AUDENC_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDENC_DIG_MAJOR_REV_SFT 12 +#define AUDENC_DIG_MAJOR_REV_MASK 0xf +#define AUDENC_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDENC_DSN_DBI */ +#define AUDENC_DSN_CBS_SFT 0 +#define AUDENC_DSN_CBS_MASK 0x3 +#define AUDENC_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDENC_DSN_BIX_SFT 2 +#define AUDENC_DSN_BIX_MASK 0x3 +#define AUDENC_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDENC_DSN_ESP_SFT 8 +#define AUDENC_DSN_ESP_MASK 0xff +#define AUDENC_DSN_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDENC_DSN_FPI */ +#define AUDENC_DSN_FPI_SFT 0 +#define AUDENC_DSN_FPI_MASK 0xff +#define AUDENC_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AUDENC_ANA_CON0 */ +#define RG_AUDPREAMPLON_SFT 0 +#define RG_AUDPREAMPLON_MASK 0x1 +#define RG_AUDPREAMPLON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPLDCCEN_SFT 1 +#define RG_AUDPREAMPLDCCEN_MASK 0x1 +#define RG_AUDPREAMPLDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPLDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPLDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPLPGATEST_SFT 3 +#define RG_AUDPREAMPLPGATEST_MASK 0x1 +#define RG_AUDPREAMPLPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPLVSCALE_SFT 4 +#define RG_AUDPREAMPLVSCALE_MASK 0x3 +#define RG_AUDPREAMPLVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPLINPUTSEL_SFT 6 +#define RG_AUDPREAMPLINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPLINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPLGAIN_SFT 8 +#define RG_AUDPREAMPLGAIN_MASK 0x7 +#define RG_AUDPREAMPLGAIN_MASK_SFT (0x7 << 8) +#define RG_AUDADCLPWRUP_SFT 12 +#define RG_AUDADCLPWRUP_MASK 0x1 +#define RG_AUDADCLPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCLINPUTSEL_SFT 13 +#define RG_AUDADCLINPUTSEL_MASK 0x3 +#define RG_AUDADCLINPUTSEL_MASK_SFT (0x3 << 13) + +/* MT6358_AUDENC_ANA_CON1 */ +#define RG_AUDPREAMPRON_SFT 0 +#define RG_AUDPREAMPRON_MASK 0x1 +#define RG_AUDPREAMPRON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPRDCCEN_SFT 1 +#define RG_AUDPREAMPRDCCEN_MASK 0x1 +#define RG_AUDPREAMPRDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPRDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPRDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPRDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPRPGATEST_SFT 3 +#define RG_AUDPREAMPRPGATEST_MASK 0x1 +#define RG_AUDPREAMPRPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPRVSCALE_SFT 4 +#define RG_AUDPREAMPRVSCALE_MASK 0x3 +#define RG_AUDPREAMPRVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPRINPUTSEL_SFT 6 +#define RG_AUDPREAMPRINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPRINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPRGAIN_SFT 8 +#define RG_AUDPREAMPRGAIN_MASK 0x7 +#define RG_AUDPREAMPRGAIN_MASK_SFT (0x7 << 8) +#define RG_AUDIO_VOW_EN_SFT 11 +#define RG_AUDIO_VOW_EN_MASK 0x1 +#define RG_AUDIO_VOW_EN_MASK_SFT (0x1 << 11) +#define RG_AUDADCRPWRUP_SFT 12 +#define RG_AUDADCRPWRUP_MASK 0x1 +#define RG_AUDADCRPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCRINPUTSEL_SFT 13 +#define RG_AUDADCRINPUTSEL_MASK 0x3 +#define RG_AUDADCRINPUTSEL_MASK_SFT (0x3 << 13) +#define RG_CLKSQ_EN_VOW_SFT 15 +#define RG_CLKSQ_EN_VOW_MASK 0x1 +#define RG_CLKSQ_EN_VOW_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON2 */ +#define RG_AUDULHALFBIAS_SFT 0 +#define RG_AUDULHALFBIAS_MASK 0x1 +#define RG_AUDULHALFBIAS_MASK_SFT (0x1 << 0) +#define RG_AUDGLBVOWLPWEN_SFT 1 +#define RG_AUDGLBVOWLPWEN_MASK 0x1 +#define RG_AUDGLBVOWLPWEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLPEN_SFT 2 +#define RG_AUDPREAMPLPEN_MASK 0x1 +#define RG_AUDPREAMPLPEN_MASK_SFT (0x1 << 2) +#define RG_AUDADC1STSTAGELPEN_SFT 3 +#define RG_AUDADC1STSTAGELPEN_MASK 0x1 +#define RG_AUDADC1STSTAGELPEN_MASK_SFT (0x1 << 3) +#define RG_AUDADC2NDSTAGELPEN_SFT 4 +#define RG_AUDADC2NDSTAGELPEN_MASK 0x1 +#define RG_AUDADC2NDSTAGELPEN_MASK_SFT (0x1 << 4) +#define RG_AUDADCFLASHLPEN_SFT 5 +#define RG_AUDADCFLASHLPEN_MASK 0x1 +#define RG_AUDADCFLASHLPEN_MASK_SFT (0x1 << 5) +#define RG_AUDPREAMPIDDTEST_SFT 6 +#define RG_AUDPREAMPIDDTEST_MASK 0x3 +#define RG_AUDPREAMPIDDTEST_MASK_SFT (0x3 << 6) +#define RG_AUDADC1STSTAGEIDDTEST_SFT 8 +#define RG_AUDADC1STSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC1STSTAGEIDDTEST_MASK_SFT (0x3 << 8) +#define RG_AUDADC2NDSTAGEIDDTEST_SFT 10 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK_SFT (0x3 << 10) +#define RG_AUDADCREFBUFIDDTEST_SFT 12 +#define RG_AUDADCREFBUFIDDTEST_MASK 0x3 +#define RG_AUDADCREFBUFIDDTEST_MASK_SFT (0x3 << 12) +#define RG_AUDADCFLASHIDDTEST_SFT 14 +#define RG_AUDADCFLASHIDDTEST_MASK 0x3 +#define RG_AUDADCFLASHIDDTEST_MASK_SFT (0x3 << 14) + +/* MT6358_AUDENC_ANA_CON3 */ +#define RG_AUDADCDAC0P25FS_SFT 0 +#define RG_AUDADCDAC0P25FS_MASK 0x1 +#define RG_AUDADCDAC0P25FS_MASK_SFT (0x1 << 0) +#define RG_AUDADCCLKSEL_SFT 1 +#define RG_AUDADCCLKSEL_MASK 0x1 +#define RG_AUDADCCLKSEL_MASK_SFT (0x1 << 1) +#define RG_AUDADCCLKSOURCE_SFT 2 +#define RG_AUDADCCLKSOURCE_MASK 0x3 +#define RG_AUDADCCLKSOURCE_MASK_SFT (0x3 << 2) +#define RG_AUDPREAMPAAFEN_SFT 8 +#define RG_AUDPREAMPAAFEN_MASK 0x1 +#define RG_AUDPREAMPAAFEN_MASK_SFT (0x1 << 8) +#define RG_DCCVCMBUFLPMODSEL_SFT 9 +#define RG_DCCVCMBUFLPMODSEL_MASK 0x1 +#define RG_DCCVCMBUFLPMODSEL_MASK_SFT (0x1 << 9) +#define RG_DCCVCMBUFLPSWEN_SFT 10 +#define RG_DCCVCMBUFLPSWEN_MASK 0x1 +#define RG_DCCVCMBUFLPSWEN_MASK_SFT (0x1 << 10) +#define RG_CMSTBENH_SFT 11 +#define RG_CMSTBENH_MASK 0x1 +#define RG_CMSTBENH_MASK_SFT (0x1 << 11) +#define RG_PGABODYSW_SFT 12 +#define RG_PGABODYSW_MASK 0x1 +#define RG_PGABODYSW_MASK_SFT (0x1 << 12) + +/* MT6358_AUDENC_ANA_CON4 */ +#define RG_AUDADC1STSTAGESDENB_SFT 0 +#define RG_AUDADC1STSTAGESDENB_MASK 0x1 +#define RG_AUDADC1STSTAGESDENB_MASK_SFT (0x1 << 0) +#define RG_AUDADC2NDSTAGERESET_SFT 1 +#define RG_AUDADC2NDSTAGERESET_MASK 0x1 +#define RG_AUDADC2NDSTAGERESET_MASK_SFT (0x1 << 1) +#define RG_AUDADC3RDSTAGERESET_SFT 2 +#define RG_AUDADC3RDSTAGERESET_MASK 0x1 +#define RG_AUDADC3RDSTAGERESET_MASK_SFT (0x1 << 2) +#define RG_AUDADCFSRESET_SFT 3 +#define RG_AUDADCFSRESET_MASK 0x1 +#define RG_AUDADCFSRESET_MASK_SFT (0x1 << 3) +#define RG_AUDADCWIDECM_SFT 4 +#define RG_AUDADCWIDECM_MASK 0x1 +#define RG_AUDADCWIDECM_MASK_SFT (0x1 << 4) +#define RG_AUDADCNOPATEST_SFT 5 +#define RG_AUDADCNOPATEST_MASK 0x1 +#define RG_AUDADCNOPATEST_MASK_SFT (0x1 << 5) +#define RG_AUDADCBYPASS_SFT 6 +#define RG_AUDADCBYPASS_MASK 0x1 +#define RG_AUDADCBYPASS_MASK_SFT (0x1 << 6) +#define RG_AUDADCFFBYPASS_SFT 7 +#define RG_AUDADCFFBYPASS_MASK 0x1 +#define RG_AUDADCFFBYPASS_MASK_SFT (0x1 << 7) +#define RG_AUDADCDACFBCURRENT_SFT 8 +#define RG_AUDADCDACFBCURRENT_MASK 0x1 +#define RG_AUDADCDACFBCURRENT_MASK_SFT (0x1 << 8) +#define RG_AUDADCDACIDDTEST_SFT 9 +#define RG_AUDADCDACIDDTEST_MASK 0x3 +#define RG_AUDADCDACIDDTEST_MASK_SFT (0x3 << 9) +#define RG_AUDADCDACNRZ_SFT 11 +#define RG_AUDADCDACNRZ_MASK 0x1 +#define RG_AUDADCDACNRZ_MASK_SFT (0x1 << 11) +#define RG_AUDADCNODEM_SFT 12 +#define RG_AUDADCNODEM_MASK 0x1 +#define RG_AUDADCNODEM_MASK_SFT (0x1 << 12) +#define RG_AUDADCDACTEST_SFT 13 +#define RG_AUDADCDACTEST_MASK 0x1 +#define RG_AUDADCDACTEST_MASK_SFT (0x1 << 13) + +/* MT6358_AUDENC_ANA_CON5 */ +#define RG_AUDRCTUNEL_SFT 0 +#define RG_AUDRCTUNEL_MASK 0x1f +#define RG_AUDRCTUNEL_MASK_SFT (0x1f << 0) +#define RG_AUDRCTUNELSEL_SFT 5 +#define RG_AUDRCTUNELSEL_MASK 0x1 +#define RG_AUDRCTUNELSEL_MASK_SFT (0x1 << 5) +#define RG_AUDRCTUNER_SFT 8 +#define RG_AUDRCTUNER_MASK 0x1f +#define RG_AUDRCTUNER_MASK_SFT (0x1f << 8) +#define RG_AUDRCTUNERSEL_SFT 13 +#define RG_AUDRCTUNERSEL_MASK 0x1 +#define RG_AUDRCTUNERSEL_MASK_SFT (0x1 << 13) + +/* MT6358_AUDENC_ANA_CON6 */ +#define RG_CLKSQ_EN_SFT 0 +#define RG_CLKSQ_EN_MASK 0x1 +#define RG_CLKSQ_EN_MASK_SFT (0x1 << 0) +#define RG_CLKSQ_IN_SEL_TEST_SFT 1 +#define RG_CLKSQ_IN_SEL_TEST_MASK 0x1 +#define RG_CLKSQ_IN_SEL_TEST_MASK_SFT (0x1 << 1) +#define RG_CM_REFGENSEL_SFT 2 +#define RG_CM_REFGENSEL_MASK 0x1 +#define RG_CM_REFGENSEL_MASK_SFT (0x1 << 2) +#define RG_AUDSPARE_SFT 4 +#define RG_AUDSPARE_MASK 0xf +#define RG_AUDSPARE_MASK_SFT (0xf << 4) +#define RG_AUDENCSPARE_SFT 8 +#define RG_AUDENCSPARE_MASK 0x3f +#define RG_AUDENCSPARE_MASK_SFT (0x3f << 8) + +/* MT6358_AUDENC_ANA_CON7 */ +#define RG_AUDENCSPARE2_SFT 0 +#define RG_AUDENCSPARE2_MASK 0xff +#define RG_AUDENCSPARE2_MASK_SFT (0xff << 0) + +/* MT6358_AUDENC_ANA_CON8 */ +#define RG_AUDDIGMICEN_SFT 0 +#define RG_AUDDIGMICEN_MASK 0x1 +#define RG_AUDDIGMICEN_MASK_SFT (0x1 << 0) +#define RG_AUDDIGMICBIAS_SFT 1 +#define RG_AUDDIGMICBIAS_MASK 0x3 +#define RG_AUDDIGMICBIAS_MASK_SFT (0x3 << 1) +#define RG_DMICHPCLKEN_SFT 3 +#define RG_DMICHPCLKEN_MASK 0x1 +#define RG_DMICHPCLKEN_MASK_SFT (0x1 << 3) +#define RG_AUDDIGMICPDUTY_SFT 4 +#define RG_AUDDIGMICPDUTY_MASK 0x3 +#define RG_AUDDIGMICPDUTY_MASK_SFT (0x3 << 4) +#define RG_AUDDIGMICNDUTY_SFT 6 +#define RG_AUDDIGMICNDUTY_MASK 0x3 +#define RG_AUDDIGMICNDUTY_MASK_SFT (0x3 << 6) +#define RG_DMICMONEN_SFT 8 +#define RG_DMICMONEN_MASK 0x1 +#define RG_DMICMONEN_MASK_SFT (0x1 << 8) +#define RG_DMICMONSEL_SFT 9 +#define RG_DMICMONSEL_MASK 0x7 +#define RG_DMICMONSEL_MASK_SFT (0x7 << 9) +#define RG_AUDSPAREVMIC_SFT 12 +#define RG_AUDSPAREVMIC_MASK 0xf +#define RG_AUDSPAREVMIC_MASK_SFT (0xf << 12) + +/* MT6358_AUDENC_ANA_CON9 */ +#define RG_AUDPWDBMICBIAS0_SFT 0 +#define RG_AUDPWDBMICBIAS0_MASK 0x1 +#define RG_AUDPWDBMICBIAS0_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS0BYPASSEN_SFT 1 +#define RG_AUDMICBIAS0BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS0BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS0LOWPEN_SFT 2 +#define RG_AUDMICBIAS0LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS0LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS0VREF_SFT 4 +#define RG_AUDMICBIAS0VREF_MASK 0x7 +#define RG_AUDMICBIAS0VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS0DCSW0P1EN_SFT 8 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS0DCSW0P2EN_SFT 9 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK_SFT (0x1 << 9) +#define RG_AUDMICBIAS0DCSW0NEN_SFT 10 +#define RG_AUDMICBIAS0DCSW0NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0NEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIAS0DCSW2P1EN_SFT 12 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK_SFT (0x1 << 12) +#define RG_AUDMICBIAS0DCSW2P2EN_SFT 13 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK_SFT (0x1 << 13) +#define RG_AUDMICBIAS0DCSW2NEN_SFT 14 +#define RG_AUDMICBIAS0DCSW2NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2NEN_MASK_SFT (0x1 << 14) + +/* MT6358_AUDENC_ANA_CON10 */ +#define RG_AUDPWDBMICBIAS1_SFT 0 +#define RG_AUDPWDBMICBIAS1_MASK 0x1 +#define RG_AUDPWDBMICBIAS1_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS1BYPASSEN_SFT 1 +#define RG_AUDMICBIAS1BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS1BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS1LOWPEN_SFT 2 +#define RG_AUDMICBIAS1LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS1LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS1VREF_SFT 4 +#define RG_AUDMICBIAS1VREF_MASK 0x7 +#define RG_AUDMICBIAS1VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS1DCSW1PEN_SFT 8 +#define RG_AUDMICBIAS1DCSW1PEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1PEN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS1DCSW1NEN_SFT 9 +#define RG_AUDMICBIAS1DCSW1NEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1NEN_MASK_SFT (0x1 << 9) +#define RG_BANDGAPGEN_SFT 12 +#define RG_BANDGAPGEN_MASK 0x1 +#define RG_BANDGAPGEN_MASK_SFT (0x1 << 12) +#define RG_MTEST_EN_SFT 13 +#define RG_MTEST_EN_MASK 0x1 +#define RG_MTEST_EN_MASK_SFT (0x1 << 13) +#define RG_MTEST_SEL_SFT 14 +#define RG_MTEST_SEL_MASK 0x1 +#define RG_MTEST_SEL_MASK_SFT (0x1 << 14) +#define RG_MTEST_CURRENT_SFT 15 +#define RG_MTEST_CURRENT_MASK 0x1 +#define RG_MTEST_CURRENT_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON11 */ +#define RG_AUDACCDETMICBIAS0PULLLOW_SFT 0 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK_SFT (0x1 << 0) +#define RG_AUDACCDETMICBIAS1PULLLOW_SFT 1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK_SFT (0x1 << 1) +#define RG_AUDACCDETVIN1PULLLOW_SFT 2 +#define RG_AUDACCDETVIN1PULLLOW_MASK 0x1 +#define RG_AUDACCDETVIN1PULLLOW_MASK_SFT (0x1 << 2) +#define RG_AUDACCDETVTHACAL_SFT 4 +#define RG_AUDACCDETVTHACAL_MASK 0x1 +#define RG_AUDACCDETVTHACAL_MASK_SFT (0x1 << 4) +#define RG_AUDACCDETVTHBCAL_SFT 5 +#define RG_AUDACCDETVTHBCAL_MASK 0x1 +#define RG_AUDACCDETVTHBCAL_MASK_SFT (0x1 << 5) +#define RG_AUDACCDETTVDET_SFT 6 +#define RG_AUDACCDETTVDET_MASK 0x1 +#define RG_AUDACCDETTVDET_MASK_SFT (0x1 << 6) +#define RG_ACCDETSEL_SFT 7 +#define RG_ACCDETSEL_MASK 0x1 +#define RG_ACCDETSEL_MASK_SFT (0x1 << 7) +#define RG_SWBUFMODSEL_SFT 8 +#define RG_SWBUFMODSEL_MASK 0x1 +#define RG_SWBUFMODSEL_MASK_SFT (0x1 << 8) +#define RG_SWBUFSWEN_SFT 9 +#define RG_SWBUFSWEN_MASK 0x1 +#define RG_SWBUFSWEN_MASK_SFT (0x1 << 9) +#define RG_EINTCOMPVTH_SFT 10 +#define RG_EINTCOMPVTH_MASK 0x1 +#define RG_EINTCOMPVTH_MASK_SFT (0x1 << 10) +#define RG_EINTCONFIGACCDET_SFT 11 +#define RG_EINTCONFIGACCDET_MASK 0x1 +#define RG_EINTCONFIGACCDET_MASK_SFT (0x1 << 11) +#define RG_EINTHIRENB_SFT 12 +#define RG_EINTHIRENB_MASK 0x1 +#define RG_EINTHIRENB_MASK_SFT (0x1 << 12) +#define RG_ACCDET2AUXRESBYPASS_SFT 13 +#define RG_ACCDET2AUXRESBYPASS_MASK 0x1 +#define RG_ACCDET2AUXRESBYPASS_MASK_SFT (0x1 << 13) +#define RG_ACCDET2AUXBUFFERBYPASS_SFT 14 +#define RG_ACCDET2AUXBUFFERBYPASS_MASK 0x1 +#define RG_ACCDET2AUXBUFFERBYPASS_MASK_SFT (0x1 << 14) +#define RG_ACCDET2AUXSWEN_SFT 15 +#define RG_ACCDET2AUXSWEN_MASK 0x1 +#define RG_ACCDET2AUXSWEN_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON12 */ +#define RGS_AUDRCTUNELREAD_SFT 0 +#define RGS_AUDRCTUNELREAD_MASK 0x1f +#define RGS_AUDRCTUNELREAD_MASK_SFT (0x1f << 0) +#define RGS_AUDRCTUNERREAD_SFT 8 +#define RGS_AUDRCTUNERREAD_MASK 0x1f +#define RGS_AUDRCTUNERREAD_MASK_SFT (0x1f << 8) + +/* MT6358_AUDDEC_DSN_ID */ +#define AUDDEC_ANA_ID_SFT 0 +#define AUDDEC_ANA_ID_MASK 0xff +#define AUDDEC_ANA_ID_MASK_SFT (0xff << 0) +#define AUDDEC_DIG_ID_SFT 8 +#define AUDDEC_DIG_ID_MASK 0xff +#define AUDDEC_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_DSN_REV0 */ +#define AUDDEC_ANA_MINOR_REV_SFT 0 +#define AUDDEC_ANA_MINOR_REV_MASK 0xf +#define AUDDEC_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDDEC_ANA_MAJOR_REV_SFT 4 +#define AUDDEC_ANA_MAJOR_REV_MASK 0xf +#define AUDDEC_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDDEC_DIG_MINOR_REV_SFT 8 +#define AUDDEC_DIG_MINOR_REV_MASK 0xf +#define AUDDEC_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDDEC_DIG_MAJOR_REV_SFT 12 +#define AUDDEC_DIG_MAJOR_REV_MASK 0xf +#define AUDDEC_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDDEC_DSN_DBI */ +#define AUDDEC_DSN_CBS_SFT 0 +#define AUDDEC_DSN_CBS_MASK 0x3 +#define AUDDEC_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDDEC_DSN_BIX_SFT 2 +#define AUDDEC_DSN_BIX_MASK 0x3 +#define AUDDEC_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDDEC_DSN_ESP_SFT 8 +#define AUDDEC_DSN_ESP_MASK 0xff +#define AUDDEC_DSN_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_DSN_FPI */ +#define AUDDEC_DSN_FPI_SFT 0 +#define AUDDEC_DSN_FPI_MASK 0xff +#define AUDDEC_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AUDDEC_ANA_CON0 */ +#define RG_AUDDACLPWRUP_VAUDP15_SFT 0 +#define RG_AUDDACLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDDACLPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDDACRPWRUP_VAUDP15_SFT 1 +#define RG_AUDDACRPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDDACRPWRUP_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUD_DAC_PWR_UP_VA28_SFT 2 +#define RG_AUD_DAC_PWR_UP_VA28_MASK 0x1 +#define RG_AUD_DAC_PWR_UP_VA28_MASK_SFT (0x1 << 2) +#define RG_AUD_DAC_PWL_UP_VA28_SFT 3 +#define RG_AUD_DAC_PWL_UP_VA28_MASK 0x1 +#define RG_AUD_DAC_PWL_UP_VA28_MASK_SFT (0x1 << 3) +#define RG_AUDHPLPWRUP_VAUDP15_SFT 4 +#define RG_AUDHPLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLPWRUP_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDHPRPWRUP_VAUDP15_SFT 5 +#define RG_AUDHPRPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPRPWRUP_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_SFT 6 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_SFT 7 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_SFT 8 +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 8) +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_SFT 10 +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 10) +#define RG_AUDHPLSCDISABLE_VAUDP15_SFT 12 +#define RG_AUDHPLSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT (0x1 << 12) +#define RG_AUDHPRSCDISABLE_VAUDP15_SFT 13 +#define RG_AUDHPRSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_AUDHPLBSCCURRENT_VAUDP15_SFT 14 +#define RG_AUDHPLBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHPLBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_AUDHPRBSCCURRENT_VAUDP15_SFT 15 +#define RG_AUDHPRBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHPRBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON1 */ +#define RG_AUDHPLOUTPWRUP_VAUDP15_SFT 0 +#define RG_AUDHPLOUTPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLOUTPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDHPROUTPWRUP_VAUDP15_SFT 1 +#define RG_AUDHPROUTPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPROUTPWRUP_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_SFT 2 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_MASK_SFT (0x1 << 2) +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_SFT 3 +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_MASK_SFT (0x1 << 3) +#define RG_HPLAUXFBRSW_EN_VAUDP15_SFT 4 +#define RG_HPLAUXFBRSW_EN_VAUDP15_MASK 0x1 +#define RG_HPLAUXFBRSW_EN_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_HPRAUXFBRSW_EN_VAUDP15_SFT 5 +#define RG_HPRAUXFBRSW_EN_VAUDP15_MASK 0x1 +#define RG_HPRAUXFBRSW_EN_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_SFT 6 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_MASK 0x1 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_SFT 7 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_MASK 0x1 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_HPLOUTSTGCTRL_VAUDP15_SFT 8 +#define RG_HPLOUTSTGCTRL_VAUDP15_MASK 0x7 +#define RG_HPLOUTSTGCTRL_VAUDP15_MASK_SFT (0x7 << 8) +#define RG_HPROUTSTGCTRL_VAUDP15_SFT 11 +#define RG_HPROUTSTGCTRL_VAUDP15_MASK 0x7 +#define RG_HPROUTSTGCTRL_VAUDP15_MASK_SFT (0x7 << 11) + +/* MT6358_AUDDEC_ANA_CON2 */ +#define RG_HPLOUTPUTSTBENH_VAUDP15_SFT 0 +#define RG_HPLOUTPUTSTBENH_VAUDP15_MASK 0x7 +#define RG_HPLOUTPUTSTBENH_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_HPROUTPUTSTBENH_VAUDP15_SFT 4 +#define RG_HPROUTPUTSTBENH_VAUDP15_MASK 0x7 +#define RG_HPROUTPUTSTBENH_VAUDP15_MASK_SFT (0x7 << 4) +#define RG_AUDHPSTARTUP_VAUDP15_SFT 13 +#define RG_AUDHPSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDHPSTARTUP_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_AUDREFN_DERES_EN_VAUDP15_SFT 14 +#define RG_AUDREFN_DERES_EN_VAUDP15_MASK 0x1 +#define RG_AUDREFN_DERES_EN_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_HPPSHORT2VCM_VAUDP15_SFT 15 +#define RG_HPPSHORT2VCM_VAUDP15_MASK 0x1 +#define RG_HPPSHORT2VCM_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON3 */ +#define RG_HPINPUTSTBENH_VAUDP15_SFT 13 +#define RG_HPINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HPINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_HPINPUTRESET0_VAUDP15_SFT 14 +#define RG_HPINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HPINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_HPOUTPUTRESET0_VAUDP15_SFT 15 +#define RG_HPOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HPOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON4 */ +#define RG_ABIDEC_RSVD0_VAUDP28_SFT 0 +#define RG_ABIDEC_RSVD0_VAUDP28_MASK 0xff +#define RG_ABIDEC_RSVD0_VAUDP28_MASK_SFT (0xff << 0) + +/* MT6358_AUDDEC_ANA_CON5 */ +#define RG_AUDHPDECMGAINADJ_VAUDP15_SFT 0 +#define RG_AUDHPDECMGAINADJ_VAUDP15_MASK 0x7 +#define RG_AUDHPDECMGAINADJ_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_AUDHPDEDMGAINADJ_VAUDP15_SFT 4 +#define RG_AUDHPDEDMGAINADJ_VAUDP15_MASK 0x7 +#define RG_AUDHPDEDMGAINADJ_VAUDP15_MASK_SFT (0x7 << 4) + +/* MT6358_AUDDEC_ANA_CON6 */ +#define RG_AUDHSPWRUP_VAUDP15_SFT 0 +#define RG_AUDHSPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHSPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_SFT 1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDHSMUXINPUTSEL_VAUDP15_SFT 2 +#define RG_AUDHSMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 2) +#define RG_AUDHSSCDISABLE_VAUDP15_SFT 4 +#define RG_AUDHSSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDHSBSCCURRENT_VAUDP15_SFT 5 +#define RG_AUDHSBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHSBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDHSSTARTUP_VAUDP15_SFT 6 +#define RG_AUDHSSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDHSSTARTUP_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_HSOUTPUTSTBENH_VAUDP15_SFT 7 +#define RG_HSOUTPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HSOUTPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_HSINPUTSTBENH_VAUDP15_SFT 8 +#define RG_HSINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HSINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 8) +#define RG_HSINPUTRESET0_VAUDP15_SFT 9 +#define RG_HSINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HSINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 9) +#define RG_HSOUTPUTRESET0_VAUDP15_SFT 10 +#define RG_HSOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HSOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 10) +#define RG_HSOUT_SHORTVCM_VAUDP15_SFT 11 +#define RG_HSOUT_SHORTVCM_VAUDP15_MASK 0x1 +#define RG_HSOUT_SHORTVCM_VAUDP15_MASK_SFT (0x1 << 11) + +/* MT6358_AUDDEC_ANA_CON7 */ +#define RG_AUDLOLPWRUP_VAUDP15_SFT 0 +#define RG_AUDLOLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDLOLPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_SFT 1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_SFT 2 +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 2) +#define RG_AUDLOLSCDISABLE_VAUDP15_SFT 4 +#define RG_AUDLOLSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDLOLBSCCURRENT_VAUDP15_SFT 5 +#define RG_AUDLOLBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDLOLBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDLOSTARTUP_VAUDP15_SFT 6 +#define RG_AUDLOSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDLOSTARTUP_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_LOINPUTSTBENH_VAUDP15_SFT 7 +#define RG_LOINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_LOINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_LOOUTPUTSTBENH_VAUDP15_SFT 8 +#define RG_LOOUTPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_LOOUTPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 8) +#define RG_LOINPUTRESET0_VAUDP15_SFT 9 +#define RG_LOINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_LOINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 9) +#define RG_LOOUTPUTRESET0_VAUDP15_SFT 10 +#define RG_LOOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_LOOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 10) +#define RG_LOOUT_SHORTVCM_VAUDP15_SFT 11 +#define RG_LOOUT_SHORTVCM_VAUDP15_MASK 0x1 +#define RG_LOOUT_SHORTVCM_VAUDP15_MASK_SFT (0x1 << 11) + +/* MT6358_AUDDEC_ANA_CON8 */ +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_SFT 0 +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_MASK 0xf +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_MASK_SFT (0xf << 0) +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_SFT 4 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_MASK 0x3 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_MASK_SFT (0x3 << 4) +#define RG_AUDTRIMBUF_EN_VAUDP15_SFT 6 +#define RG_AUDTRIMBUF_EN_VAUDP15_MASK 0x1 +#define RG_AUDTRIMBUF_EN_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_SFT 8 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_MASK_SFT (0x3 << 8) +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_SFT 10 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_MASK_SFT (0x3 << 10) +#define RG_AUDHPSPKDET_EN_VAUDP15_SFT 12 +#define RG_AUDHPSPKDET_EN_VAUDP15_MASK 0x1 +#define RG_AUDHPSPKDET_EN_VAUDP15_MASK_SFT (0x1 << 12) + +/* MT6358_AUDDEC_ANA_CON9 */ +#define RG_ABIDEC_RSVD0_VA28_SFT 0 +#define RG_ABIDEC_RSVD0_VA28_MASK 0xff +#define RG_ABIDEC_RSVD0_VA28_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD0_VAUDP15_SFT 8 +#define RG_ABIDEC_RSVD0_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD0_VAUDP15_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_ANA_CON10 */ +#define RG_ABIDEC_RSVD1_VAUDP15_SFT 0 +#define RG_ABIDEC_RSVD1_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD1_VAUDP15_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD2_VAUDP15_SFT 8 +#define RG_ABIDEC_RSVD2_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD2_VAUDP15_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_ANA_CON11 */ +#define RG_AUDZCDMUXSEL_VAUDP15_SFT 0 +#define RG_AUDZCDMUXSEL_VAUDP15_MASK 0x7 +#define RG_AUDZCDMUXSEL_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_AUDZCDCLKSEL_VAUDP15_SFT 3 +#define RG_AUDZCDCLKSEL_VAUDP15_MASK 0x1 +#define RG_AUDZCDCLKSEL_VAUDP15_MASK_SFT (0x1 << 3) +#define RG_AUDBIASADJ_0_VAUDP15_SFT 7 +#define RG_AUDBIASADJ_0_VAUDP15_MASK 0x1ff +#define RG_AUDBIASADJ_0_VAUDP15_MASK_SFT (0x1ff << 7) + +/* MT6358_AUDDEC_ANA_CON12 */ +#define RG_AUDBIASADJ_1_VAUDP15_SFT 0 +#define RG_AUDBIASADJ_1_VAUDP15_MASK 0xff +#define RG_AUDBIASADJ_1_VAUDP15_MASK_SFT (0xff << 0) +#define RG_AUDIBIASPWRDN_VAUDP15_SFT 8 +#define RG_AUDIBIASPWRDN_VAUDP15_MASK 0x1 +#define RG_AUDIBIASPWRDN_VAUDP15_MASK_SFT (0x1 << 8) + +/* MT6358_AUDDEC_ANA_CON13 */ +#define RG_RSTB_DECODER_VA28_SFT 0 +#define RG_RSTB_DECODER_VA28_MASK 0x1 +#define RG_RSTB_DECODER_VA28_MASK_SFT (0x1 << 0) +#define RG_SEL_DECODER_96K_VA28_SFT 1 +#define RG_SEL_DECODER_96K_VA28_MASK 0x1 +#define RG_SEL_DECODER_96K_VA28_MASK_SFT (0x1 << 1) +#define RG_SEL_DELAY_VCORE_SFT 2 +#define RG_SEL_DELAY_VCORE_MASK 0x1 +#define RG_SEL_DELAY_VCORE_MASK_SFT (0x1 << 2) +#define RG_AUDGLB_PWRDN_VA28_SFT 4 +#define RG_AUDGLB_PWRDN_VA28_MASK 0x1 +#define RG_AUDGLB_PWRDN_VA28_MASK_SFT (0x1 << 4) +#define RG_RSTB_ENCODER_VA28_SFT 5 +#define RG_RSTB_ENCODER_VA28_MASK 0x1 +#define RG_RSTB_ENCODER_VA28_MASK_SFT (0x1 << 5) +#define RG_SEL_ENCODER_96K_VA28_SFT 6 +#define RG_SEL_ENCODER_96K_VA28_MASK 0x1 +#define RG_SEL_ENCODER_96K_VA28_MASK_SFT (0x1 << 6) + +/* MT6358_AUDDEC_ANA_CON14 */ +#define RG_HCLDO_EN_VA18_SFT 0 +#define RG_HCLDO_EN_VA18_MASK 0x1 +#define RG_HCLDO_EN_VA18_MASK_SFT (0x1 << 0) +#define RG_HCLDO_PDDIS_EN_VA18_SFT 1 +#define RG_HCLDO_PDDIS_EN_VA18_MASK 0x1 +#define RG_HCLDO_PDDIS_EN_VA18_MASK_SFT (0x1 << 1) +#define RG_HCLDO_REMOTE_SENSE_VA18_SFT 2 +#define RG_HCLDO_REMOTE_SENSE_VA18_MASK 0x1 +#define RG_HCLDO_REMOTE_SENSE_VA18_MASK_SFT (0x1 << 2) +#define RG_LCLDO_EN_VA18_SFT 4 +#define RG_LCLDO_EN_VA18_MASK 0x1 +#define RG_LCLDO_EN_VA18_MASK_SFT (0x1 << 4) +#define RG_LCLDO_PDDIS_EN_VA18_SFT 5 +#define RG_LCLDO_PDDIS_EN_VA18_MASK 0x1 +#define RG_LCLDO_PDDIS_EN_VA18_MASK_SFT (0x1 << 5) +#define RG_LCLDO_REMOTE_SENSE_VA18_SFT 6 +#define RG_LCLDO_REMOTE_SENSE_VA18_MASK 0x1 +#define RG_LCLDO_REMOTE_SENSE_VA18_MASK_SFT (0x1 << 6) +#define RG_LCLDO_ENC_EN_VA28_SFT 8 +#define RG_LCLDO_ENC_EN_VA28_MASK 0x1 +#define RG_LCLDO_ENC_EN_VA28_MASK_SFT (0x1 << 8) +#define RG_LCLDO_ENC_PDDIS_EN_VA28_SFT 9 +#define RG_LCLDO_ENC_PDDIS_EN_VA28_MASK 0x1 +#define RG_LCLDO_ENC_PDDIS_EN_VA28_MASK_SFT (0x1 << 9) +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_SFT 10 +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_MASK 0x1 +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_MASK_SFT (0x1 << 10) +#define RG_VA33REFGEN_EN_VA18_SFT 12 +#define RG_VA33REFGEN_EN_VA18_MASK 0x1 +#define RG_VA33REFGEN_EN_VA18_MASK_SFT (0x1 << 12) +#define RG_VA28REFGEN_EN_VA28_SFT 13 +#define RG_VA28REFGEN_EN_VA28_MASK 0x1 +#define RG_VA28REFGEN_EN_VA28_MASK_SFT (0x1 << 13) +#define RG_HCLDO_VOSEL_VA18_SFT 14 +#define RG_HCLDO_VOSEL_VA18_MASK 0x1 +#define RG_HCLDO_VOSEL_VA18_MASK_SFT (0x1 << 14) +#define RG_LCLDO_VOSEL_VA18_SFT 15 +#define RG_LCLDO_VOSEL_VA18_MASK 0x1 +#define RG_LCLDO_VOSEL_VA18_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON15 */ +#define RG_NVREG_EN_VAUDP15_SFT 0 +#define RG_NVREG_EN_VAUDP15_MASK 0x1 +#define RG_NVREG_EN_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_NVREG_PULL0V_VAUDP15_SFT 1 +#define RG_NVREG_PULL0V_VAUDP15_MASK 0x1 +#define RG_NVREG_PULL0V_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDPMU_RSD0_VAUDP15_SFT 4 +#define RG_AUDPMU_RSD0_VAUDP15_MASK 0xf +#define RG_AUDPMU_RSD0_VAUDP15_MASK_SFT (0xf << 4) +#define RG_AUDPMU_RSD0_VA18_SFT 8 +#define RG_AUDPMU_RSD0_VA18_MASK 0xf +#define RG_AUDPMU_RSD0_VA18_MASK_SFT (0xf << 8) +#define RG_AUDPMU_RSD0_VA28_SFT 12 +#define RG_AUDPMU_RSD0_VA28_MASK 0xf +#define RG_AUDPMU_RSD0_VA28_MASK_SFT (0xf << 12) + +/* MT6358_ZCD_CON0 */ +#define RG_AUDZCDENABLE_SFT 0 +#define RG_AUDZCDENABLE_MASK 0x1 +#define RG_AUDZCDENABLE_MASK_SFT (0x1 << 0) +#define RG_AUDZCDGAINSTEPTIME_SFT 1 +#define RG_AUDZCDGAINSTEPTIME_MASK 0x7 +#define RG_AUDZCDGAINSTEPTIME_MASK_SFT (0x7 << 1) +#define RG_AUDZCDGAINSTEPSIZE_SFT 4 +#define RG_AUDZCDGAINSTEPSIZE_MASK 0x3 +#define RG_AUDZCDGAINSTEPSIZE_MASK_SFT (0x3 << 4) +#define RG_AUDZCDTIMEOUTMODESEL_SFT 6 +#define RG_AUDZCDTIMEOUTMODESEL_MASK 0x1 +#define RG_AUDZCDTIMEOUTMODESEL_MASK_SFT (0x1 << 6) + +/* MT6358_ZCD_CON1 */ +#define RG_AUDLOLGAIN_SFT 0 +#define RG_AUDLOLGAIN_MASK 0x1f +#define RG_AUDLOLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDLORGAIN_SFT 7 +#define RG_AUDLORGAIN_MASK 0x1f +#define RG_AUDLORGAIN_MASK_SFT (0x1f << 7) + +/* MT6358_ZCD_CON2 */ +#define RG_AUDHPLGAIN_SFT 0 +#define RG_AUDHPLGAIN_MASK 0x1f +#define RG_AUDHPLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDHPRGAIN_SFT 7 +#define RG_AUDHPRGAIN_MASK 0x1f +#define RG_AUDHPRGAIN_MASK_SFT (0x1f << 7) + +/* MT6358_ZCD_CON3 */ +#define RG_AUDHSGAIN_SFT 0 +#define RG_AUDHSGAIN_MASK 0x1f +#define RG_AUDHSGAIN_MASK_SFT (0x1f << 0) + +/* MT6358_ZCD_CON4 */ +#define RG_AUDIVLGAIN_SFT 0 +#define RG_AUDIVLGAIN_MASK 0x7 +#define RG_AUDIVLGAIN_MASK_SFT (0x7 << 0) +#define RG_AUDIVRGAIN_SFT 8 +#define RG_AUDIVRGAIN_MASK 0x7 +#define RG_AUDIVRGAIN_MASK_SFT (0x7 << 8) + +/* MT6358_ZCD_CON5 */ +#define RG_AUDINTGAIN1_SFT 0 +#define RG_AUDINTGAIN1_MASK 0x3f +#define RG_AUDINTGAIN1_MASK_SFT (0x3f << 0) +#define RG_AUDINTGAIN2_SFT 8 +#define RG_AUDINTGAIN2_MASK 0x3f +#define RG_AUDINTGAIN2_MASK_SFT (0x3f << 8) + +/* audio register */ +#define MT6358_DRV_CON3 0x3c +#define MT6358_GPIO_DIR0 0x88 + +#define MT6358_GPIO_MODE2 0xd8 /* mosi */ +#define MT6358_GPIO_MODE2_SET 0xda +#define MT6358_GPIO_MODE2_CLR 0xdc + +#define MT6358_GPIO_MODE3 0xde /* miso */ +#define MT6358_GPIO_MODE3_SET 0xe0 +#define MT6358_GPIO_MODE3_CLR 0xe2 + +#define MT6358_TOP_CKPDN_CON0 0x10c +#define MT6358_TOP_CKPDN_CON0_SET 0x10e +#define MT6358_TOP_CKPDN_CON0_CLR 0x110 + +#define MT6358_TOP_CKHWEN_CON0 0x12a +#define MT6358_TOP_CKHWEN_CON0_SET 0x12c +#define MT6358_TOP_CKHWEN_CON0_CLR 0x12e + +#define MT6358_OTP_CON0 0x38a +#define MT6358_OTP_CON8 0x39a +#define MT6358_OTP_CON11 0x3a0 +#define MT6358_OTP_CON12 0x3a2 +#define MT6358_OTP_CON13 0x3a4 + +#define MT6358_DCXO_CW13 0x7aa +#define MT6358_DCXO_CW14 0x7ac + +#define MT6358_AUXADC_CON10 0x11a0 + +/* audio register */ +#define MT6358_AUD_TOP_ID 0x2200 +#define MT6358_AUD_TOP_REV0 0x2202 +#define MT6358_AUD_TOP_DBI 0x2204 +#define MT6358_AUD_TOP_DXI 0x2206 +#define MT6358_AUD_TOP_CKPDN_TPM0 0x2208 +#define MT6358_AUD_TOP_CKPDN_TPM1 0x220a +#define MT6358_AUD_TOP_CKPDN_CON0 0x220c +#define MT6358_AUD_TOP_CKPDN_CON0_SET 0x220e +#define MT6358_AUD_TOP_CKPDN_CON0_CLR 0x2210 +#define MT6358_AUD_TOP_CKSEL_CON0 0x2212 +#define MT6358_AUD_TOP_CKSEL_CON0_SET 0x2214 +#define MT6358_AUD_TOP_CKSEL_CON0_CLR 0x2216 +#define MT6358_AUD_TOP_CKTST_CON0 0x2218 +#define MT6358_AUD_TOP_CLK_HWEN_CON0 0x221a +#define MT6358_AUD_TOP_CLK_HWEN_CON0_SET 0x221c +#define MT6358_AUD_TOP_CLK_HWEN_CON0_CLR 0x221e +#define MT6358_AUD_TOP_RST_CON0 0x2220 +#define MT6358_AUD_TOP_RST_CON0_SET 0x2222 +#define MT6358_AUD_TOP_RST_CON0_CLR 0x2224 +#define MT6358_AUD_TOP_RST_BANK_CON0 0x2226 +#define MT6358_AUD_TOP_INT_CON0 0x2228 +#define MT6358_AUD_TOP_INT_CON0_SET 0x222a +#define MT6358_AUD_TOP_INT_CON0_CLR 0x222c +#define MT6358_AUD_TOP_INT_MASK_CON0 0x222e +#define MT6358_AUD_TOP_INT_MASK_CON0_SET 0x2230 +#define MT6358_AUD_TOP_INT_MASK_CON0_CLR 0x2232 +#define MT6358_AUD_TOP_INT_STATUS0 0x2234 +#define MT6358_AUD_TOP_INT_RAW_STATUS0 0x2236 +#define MT6358_AUD_TOP_INT_MISC_CON0 0x2238 +#define MT6358_AUDNCP_CLKDIV_CON0 0x223a +#define MT6358_AUDNCP_CLKDIV_CON1 0x223c +#define MT6358_AUDNCP_CLKDIV_CON2 0x223e +#define MT6358_AUDNCP_CLKDIV_CON3 0x2240 +#define MT6358_AUDNCP_CLKDIV_CON4 0x2242 +#define MT6358_AUD_TOP_MON_CON0 0x2244 +#define MT6358_AUDIO_DIG_DSN_ID 0x2280 +#define MT6358_AUDIO_DIG_DSN_REV0 0x2282 +#define MT6358_AUDIO_DIG_DSN_DBI 0x2284 +#define MT6358_AUDIO_DIG_DSN_DXI 0x2286 +#define MT6358_AFE_UL_DL_CON0 0x2288 +#define MT6358_AFE_DL_SRC2_CON0_L 0x228a +#define MT6358_AFE_UL_SRC_CON0_H 0x228c +#define MT6358_AFE_UL_SRC_CON0_L 0x228e +#define MT6358_AFE_TOP_CON0 0x2290 +#define MT6358_AUDIO_TOP_CON0 0x2292 +#define MT6358_AFE_MON_DEBUG0 0x2294 +#define MT6358_AFUNC_AUD_CON0 0x2296 +#define MT6358_AFUNC_AUD_CON1 0x2298 +#define MT6358_AFUNC_AUD_CON2 0x229a +#define MT6358_AFUNC_AUD_CON3 0x229c +#define MT6358_AFUNC_AUD_CON4 0x229e +#define MT6358_AFUNC_AUD_CON5 0x22a0 +#define MT6358_AFUNC_AUD_CON6 0x22a2 +#define MT6358_AFUNC_AUD_MON0 0x22a4 +#define MT6358_AUDRC_TUNE_MON0 0x22a6 +#define MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0 0x22a8 +#define MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 0x22aa +#define MT6358_AFE_ADDA_MTKAIF_MON0 0x22ac +#define MT6358_AFE_ADDA_MTKAIF_MON1 0x22ae +#define MT6358_AFE_ADDA_MTKAIF_MON2 0x22b0 +#define MT6358_AFE_ADDA_MTKAIF_MON3 0x22b2 +#define MT6358_AFE_ADDA_MTKAIF_CFG0 0x22b4 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG0 0x22b6 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG1 0x22b8 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG2 0x22ba +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG3 0x22bc +#define MT6358_AFE_ADDA_MTKAIF_TX_CFG1 0x22be +#define MT6358_AFE_SGEN_CFG0 0x22c0 +#define MT6358_AFE_SGEN_CFG1 0x22c2 +#define MT6358_AFE_ADC_ASYNC_FIFO_CFG 0x22c4 +#define MT6358_AFE_DCCLK_CFG0 0x22c6 +#define MT6358_AFE_DCCLK_CFG1 0x22c8 +#define MT6358_AUDIO_DIG_CFG 0x22ca +#define MT6358_AFE_AUD_PAD_TOP 0x22cc +#define MT6358_AFE_AUD_PAD_TOP_MON 0x22ce +#define MT6358_AFE_AUD_PAD_TOP_MON1 0x22d0 +#define MT6358_AFE_DL_NLE_CFG 0x22d2 +#define MT6358_AFE_DL_NLE_MON 0x22d4 +#define MT6358_AFE_CG_EN_MON 0x22d6 +#define MT6358_AUDIO_DIG_2ND_DSN_ID 0x2300 +#define MT6358_AUDIO_DIG_2ND_DSN_REV0 0x2302 +#define MT6358_AUDIO_DIG_2ND_DSN_DBI 0x2304 +#define MT6358_AUDIO_DIG_2ND_DSN_DXI 0x2306 +#define MT6358_AFE_PMIC_NEWIF_CFG3 0x2308 +#define MT6358_AFE_VOW_TOP 0x230a +#define MT6358_AFE_VOW_CFG0 0x230c +#define MT6358_AFE_VOW_CFG1 0x230e +#define MT6358_AFE_VOW_CFG2 0x2310 +#define MT6358_AFE_VOW_CFG3 0x2312 +#define MT6358_AFE_VOW_CFG4 0x2314 +#define MT6358_AFE_VOW_CFG5 0x2316 +#define MT6358_AFE_VOW_CFG6 0x2318 +#define MT6358_AFE_VOW_MON0 0x231a +#define MT6358_AFE_VOW_MON1 0x231c +#define MT6358_AFE_VOW_MON2 0x231e +#define MT6358_AFE_VOW_MON3 0x2320 +#define MT6358_AFE_VOW_MON4 0x2322 +#define MT6358_AFE_VOW_MON5 0x2324 +#define MT6358_AFE_VOW_SN_INI_CFG 0x2326 +#define MT6358_AFE_VOW_TGEN_CFG0 0x2328 +#define MT6358_AFE_VOW_POSDIV_CFG0 0x232a +#define MT6358_AFE_VOW_HPF_CFG0 0x232c +#define MT6358_AFE_VOW_PERIODIC_CFG0 0x232e +#define MT6358_AFE_VOW_PERIODIC_CFG1 0x2330 +#define MT6358_AFE_VOW_PERIODIC_CFG2 0x2332 +#define MT6358_AFE_VOW_PERIODIC_CFG3 0x2334 +#define MT6358_AFE_VOW_PERIODIC_CFG4 0x2336 +#define MT6358_AFE_VOW_PERIODIC_CFG5 0x2338 +#define MT6358_AFE_VOW_PERIODIC_CFG6 0x233a +#define MT6358_AFE_VOW_PERIODIC_CFG7 0x233c +#define MT6358_AFE_VOW_PERIODIC_CFG8 0x233e +#define MT6358_AFE_VOW_PERIODIC_CFG9 0x2340 +#define MT6358_AFE_VOW_PERIODIC_CFG10 0x2342 +#define MT6358_AFE_VOW_PERIODIC_CFG11 0x2344 +#define MT6358_AFE_VOW_PERIODIC_CFG12 0x2346 +#define MT6358_AFE_VOW_PERIODIC_CFG13 0x2348 +#define MT6358_AFE_VOW_PERIODIC_CFG14 0x234a +#define MT6358_AFE_VOW_PERIODIC_CFG15 0x234c +#define MT6358_AFE_VOW_PERIODIC_CFG16 0x234e +#define MT6358_AFE_VOW_PERIODIC_CFG17 0x2350 +#define MT6358_AFE_VOW_PERIODIC_CFG18 0x2352 +#define MT6358_AFE_VOW_PERIODIC_CFG19 0x2354 +#define MT6358_AFE_VOW_PERIODIC_CFG20 0x2356 +#define MT6358_AFE_VOW_PERIODIC_CFG21 0x2358 +#define MT6358_AFE_VOW_PERIODIC_CFG22 0x235a +#define MT6358_AFE_VOW_PERIODIC_CFG23 0x235c +#define MT6358_AFE_VOW_PERIODIC_MON0 0x235e +#define MT6358_AFE_VOW_PERIODIC_MON1 0x2360 +#define MT6358_AUDENC_DSN_ID 0x2380 +#define MT6358_AUDENC_DSN_REV0 0x2382 +#define MT6358_AUDENC_DSN_DBI 0x2384 +#define MT6358_AUDENC_DSN_FPI 0x2386 +#define MT6358_AUDENC_ANA_CON0 0x2388 +#define MT6358_AUDENC_ANA_CON1 0x238a +#define MT6358_AUDENC_ANA_CON2 0x238c +#define MT6358_AUDENC_ANA_CON3 0x238e +#define MT6358_AUDENC_ANA_CON4 0x2390 +#define MT6358_AUDENC_ANA_CON5 0x2392 +#define MT6358_AUDENC_ANA_CON6 0x2394 +#define MT6358_AUDENC_ANA_CON7 0x2396 +#define MT6358_AUDENC_ANA_CON8 0x2398 +#define MT6358_AUDENC_ANA_CON9 0x239a +#define MT6358_AUDENC_ANA_CON10 0x239c +#define MT6358_AUDENC_ANA_CON11 0x239e +#define MT6358_AUDENC_ANA_CON12 0x23a0 +#define MT6358_AUDDEC_DSN_ID 0x2400 +#define MT6358_AUDDEC_DSN_REV0 0x2402 +#define MT6358_AUDDEC_DSN_DBI 0x2404 +#define MT6358_AUDDEC_DSN_FPI 0x2406 +#define MT6358_AUDDEC_ANA_CON0 0x2408 +#define MT6358_AUDDEC_ANA_CON1 0x240a +#define MT6358_AUDDEC_ANA_CON2 0x240c +#define MT6358_AUDDEC_ANA_CON3 0x240e +#define MT6358_AUDDEC_ANA_CON4 0x2410 +#define MT6358_AUDDEC_ANA_CON5 0x2412 +#define MT6358_AUDDEC_ANA_CON6 0x2414 +#define MT6358_AUDDEC_ANA_CON7 0x2416 +#define MT6358_AUDDEC_ANA_CON8 0x2418 +#define MT6358_AUDDEC_ANA_CON9 0x241a +#define MT6358_AUDDEC_ANA_CON10 0x241c +#define MT6358_AUDDEC_ANA_CON11 0x241e +#define MT6358_AUDDEC_ANA_CON12 0x2420 +#define MT6358_AUDDEC_ANA_CON13 0x2422 +#define MT6358_AUDDEC_ANA_CON14 0x2424 +#define MT6358_AUDDEC_ANA_CON15 0x2426 +#define MT6358_AUDDEC_ELR_NUM 0x2428 +#define MT6358_AUDDEC_ELR_0 0x242a +#define MT6358_AUDZCD_DSN_ID 0x2480 +#define MT6358_AUDZCD_DSN_REV0 0x2482 +#define MT6358_AUDZCD_DSN_DBI 0x2484 +#define MT6358_AUDZCD_DSN_FPI 0x2486 +#define MT6358_ZCD_CON0 0x2488 +#define MT6358_ZCD_CON1 0x248a +#define MT6358_ZCD_CON2 0x248c +#define MT6358_ZCD_CON3 0x248e +#define MT6358_ZCD_CON4 0x2490 +#define MT6358_ZCD_CON5 0x2492 +#define MT6358_ACCDET_CON13 0x2522 + +#define MT6358_MAX_REGISTER MT6358_ZCD_CON5 + +enum { + MT6358_MTKAIF_PROTOCOL_1 = 0, + MT6358_MTKAIF_PROTOCOL_2, + MT6358_MTKAIF_PROTOCOL_2_CLK_P2, +}; + +/* set only during init */ +int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol); +int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt); +int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt); +int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2); +#endif /* __MT6358_H__ */ From 7ca80f232e810b758ba72daef8f189c34a20bd32 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:11 +0800 Subject: [PATCH 188/461] ASoC: mediatek: mt6358: add codec document Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt6358.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt6358.txt diff --git a/Documentation/devicetree/bindings/sound/mt6358.txt b/Documentation/devicetree/bindings/sound/mt6358.txt new file mode 100644 index 000000000000..5465730013a1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt6358.txt @@ -0,0 +1,18 @@ +Mediatek MT6358 Audio Codec + +The communication between MT6358 and SoC is through Mediatek PMIC wrapper. +For more detail, please visit Mediatek PMIC wrapper documentation. + +Must be a child node of PMIC wrapper. + +Required properties: + +- compatible : "mediatek,mt6358-sound". +- Avdd-supply : power source of AVDD + +Example: + +mt6358_snd { + compatible = "mediatek,mt6358-sound"; + Avdd-supply = <&mt6358_vaud28_reg>; +}; From 141474c6ac7f279824780453d3f9c75d6193dc85 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 11:24:34 +0900 Subject: [PATCH 189/461] ASoC: Fixup build error for mt6358 This patch fixup build error for commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Fixes: commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 55fd58015c2d..83ef965cbff1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1344,7 +1344,7 @@ config SND_SOC_MT6358 tristate "MediaTek MT6358 Codec" help Enable support for the platform which uses MT6358 as - external codec device. + external codec device. config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" From 720734a0b66f9ca42ec6663a48702b16e49552ee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 10:40:24 +0900 Subject: [PATCH 190/461] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs V2 We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro. Fixes: 50acc7e49 ("ASoC: core: Fix multi-CODEC setups") Fixes: 10dff9b0d ("ASoC: soc-core: use for_each_link_codecs() for dai_link codecs") Signed-off-by: Kuninori Morimoto Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675a..93efab486736 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,13 +905,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dais[i] = snd_soc_find_dai(&codecs[i]); + for_each_link_codecs(dai_link, i, codecs) { + codec_dais[i] = snd_soc_find_dai(codecs); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + codecs->dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From ccc8d6c7b6d2f521a4b10c7f6d027f46c7a686bf Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:17:01 +0200 Subject: [PATCH 191/461] ASoC: pcm512x: Implement the set_bclk_ratio interface Some boards, such as the HiFiBerry DAC+ Pro, use a pair of external oscillators, to generate 44.1 or 48kHz multiples and are forced to resort to hacks [1] in order to support 24-bit data without ending up with fractional dividers. This patch allows the machine driver to use 32-bit frames for 24-bit data to avoid such issues. Although the datasheet (p. 15) seems to suggest that only a handful of ratios are supported, it's not very explicit about it, so we allow the full range of values supported by the underlying register in the callback, to avoid needlessly rejecting potentially usable configurations. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143442.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4cc24a5d5c31..ce8c5dbd2164 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -55,6 +55,7 @@ struct pcm512x_priv { unsigned long overclock_dsp; int mute; struct mutex mutex; + unsigned int bclk_ratio; }; /* @@ -915,10 +916,15 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, int fssp; int gpio; - lrclk_div = snd_soc_params_to_frame_size(params); - if (lrclk_div == 0) { - dev_err(dev, "No LRCLK?\n"); - return -EINVAL; + if (pcm512x->bclk_ratio > 0) { + lrclk_div = pcm512x->bclk_ratio; + } else { + lrclk_div = snd_soc_params_to_frame_size(params); + + if (lrclk_div == 0) { + dev_err(dev, "No LRCLK?\n"); + return -EINVAL; + } } if (!pcm512x->pll_out) { @@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + if (ratio > 256) + return -EINVAL; + + pcm512x->bclk_ratio = ratio; + + return 0; +} + static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; @@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = { .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .digital_mute = pcm512x_digital_mute, + .set_bclk_ratio = pcm512x_set_bclk_ratio, }; static struct snd_soc_dai_driver pcm512x_dai = { From 51b033c2608147efe3a5368bfa64837e772d8c55 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:23:45 +0200 Subject: [PATCH 192/461] ASoC: pcm512x: Fix clocking calculations when not using the PLL The rationale behind the current calculation is somewhat obscure [1] and can yield slightly wrong dividers in certain cases, which the machine drivers for some boards (like the HiFiBerry DAC+ Pro) seemingly try to circumvent, by updating the rate fraction so as to suit this calculation. The updated calculation should correctly yield the smallest bit clock rate that would fit the frame. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144219.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ce8c5dbd2164..ae3bd533eadb 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -929,8 +929,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, if (!pcm512x->pll_out) { sck_rate = clk_get_rate(pcm512x->sclk); - bclk_div = params->rate_den * 64 / lrclk_div; - bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); + bclk_rate = params_rate(params) * lrclk_div; + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); mck_rate = sck_rate; } else { From 5e484ec1758b95e6420787fc17f0e8c5e152c264 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:16:17 -0600 Subject: [PATCH 193/461] ASoC: soc-acpi: add static inline fallbacks when CONFIG_ACPI=n Fix compilation issues reported by 0day-Kbuild with sparc64 w/ SOF. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 266e64e3c24c..6cbbeed9cdd0 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -22,20 +22,37 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) +/* acpi match */ +struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); + bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); + +/* check all codecs */ +struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); + #else +/* acpi match */ +static inline struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) +{ + return NULL; +} + static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) { return false; } -#endif -/* acpi match */ -struct snd_soc_acpi_mach * -snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/* check all codecs */ +static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) +{ + return NULL; +} +#endif /** * snd_soc_acpi_mach_params: interface for machine driver configuration @@ -105,7 +122,4 @@ struct snd_soc_acpi_codecs { u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; }; -/* check all codecs */ -struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); - #endif From e20bfeb0b7d808bc05e7c4cb1f492cd31d837da0 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jan 2019 10:45:37 -0800 Subject: [PATCH 194/461] ASoC: rt5651: Variable "ret" in function rt5651_i2c_probe() could be uninitialized In function rt5651_i2c_probe(), local variable "ret" could be uninitialized if function regmap_read() returns -EINVAL. However, this value is used in if statement. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 75994297c896..29b2d60076b0 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2181,6 +2181,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, { struct rt5651_priv *rt5651; int ret; + int err; rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), GFP_KERNEL); @@ -2197,7 +2198,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + err = regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (err) + return err; + if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5651\n", ret); From b2e9e1c8810ee05c95f4d55800b8afae70ab01b4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 28 Jan 2019 20:40:58 +0900 Subject: [PATCH 195/461] ALSA: dice: add support for Solid State Logic Duende Classic/Mini Duende Classic was produced by Solid State Logic in 2006, as a first model of Duende DSP series. The following model, Duende Mini was produced in 2008. They are designed to receive isochronous packets for PCM frames via IEEE 1394 bus, perform signal processing by downloaded program, then transfer isochronous packets for converted PCM frames. These two models includes the same embedded board, consists of several ICs below: - Texus Instruments Inc, TSB41AB3 for physical layer of IEEE 1394 bus - WaveFront semiconductor, DICE II STD ASIC for link/protocol layer - Altera MAX 3000A CPLD for programs - Analog devices, SHARC ADSP-21363 for signal processing (4 chips) This commit adds support for the two models to ALSA dice driver. Like support for the other devices, packet streaming is just available. Userspace applications should be developed if full features became available; e.g. program uploader and parameter controller. $ ./hinawa-config-rom-printer /dev/fw1 { 'bus-info': { 'adj': False, 'bmc': False, 'chip_ID': 349771402425, 'cmc': True, 'cyc_clk_acc': 255, 'generation': 1, 'imc': True, 'isc': True, 'link_spd': 2, 'max_ROM': 1, 'max_rec': 512, 'name': '1394', 'node_vendor_ID': 20674, 'pmc': False}, 'root-directory': [ ['VENDOR', 20674], ['DESCRIPTOR', 'Solid State Logic'], ['MODEL', 112], ['DESCRIPTOR', 'Duende board'], [ 'NODE_CAPABILITIES', { 'addressing': {'64': True, 'fix': True, 'prv': True}, 'misc': {'int': False, 'ms': False, 'spt': True}, 'state': { 'atn': False, 'ded': False, 'drq': True, 'elo': False, 'init': False, 'lst': True, 'off': False}, 'testing': {'bas': False, 'ext': False}}], [ 'UNIT', [ ['SPECIFIER_ID', 20674], ['VERSION', 1], ['MODEL', 112], ['DESCRIPTOR', 'Duende board']]]]} Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index ed50b222d36e..eee184b05d93 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -18,6 +18,7 @@ MODULE_LICENSE("GPL v2"); #define OUI_ALESIS 0x000595 #define OUI_MAUDIO 0x000d6c #define OUI_MYTEK 0x001ee8 +#define OUI_SSL 0x0050c2 // Actually ID reserved by IEEE. #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 @@ -196,7 +197,7 @@ static int dice_probe(struct fw_unit *unit, struct snd_dice *dice; int err; - if (!entry->driver_data) { + if (!entry->driver_data && entry->vendor_id != OUI_SSL) { err = check_dice_category(unit); if (err < 0) return -ENODEV; @@ -361,6 +362,15 @@ static const struct ieee1394_device_id dice_id_table[] = { .model_id = 0x000002, .driver_data = (kernel_ulong_t)snd_dice_detect_mytek_formats, }, + // Solid State Logic, Duende Classic and Mini. + // NOTE: each field of GUID in config ROM is not compliant to standard + // DICE scheme. + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_SSL, + .model_id = 0x000070, + }, { .match_flags = IEEE1394_MATCH_VERSION, .version = DICE_INTERFACE, From cb50358b83846e4dcb37137c431327c4dd68561b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:55 -0600 Subject: [PATCH 196/461] ASoC: add helper to change platform name for all dailinks To reuse the same machine drivers with Atom/SST, Skylake and SOF, we need to change the default platform_name (or platforms->name in the "modern" representation). So far, this override was done with an automatic override, which was broken by a set of changes for DT platforms related to deferred probe handling. This automatic override is actually not really needed, the machine driver can already receive the platform name as a platform_data parameter. This is used e.g. for HDaudio support where we have different PCI aliases used for different platforms. We can reuse the same mechanism and modify the machine drivers to override the dailinks prior to registrating the card. This will require additional work for SOF, but with this helper it'll be just two lines of additional code per machine driver which is reused, not the end of the world. This helper can be simplified when all drivers have transitioned to the "modern" representation of dailinks. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3089257ead95..95689680336b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1580,6 +1580,37 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card, return NULL; } +static inline +int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, + const char *platform_name) +{ + struct snd_soc_dai_link *dai_link; + const char *name; + int i; + + if (!platform_name) /* nothing to do */ + return 0; + + /* set platform name for each dailink */ + for_each_card_prelinks(card, i, dai_link) { + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (dai_link->platforms) + /* only single platform is supported for now */ + dai_link->platforms->name = name; + else + /* + * legacy mode, this case will be removed when all + * derivers are switched to modern style dai_link. + */ + dai_link->platform_name = name; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS extern struct dentry *snd_soc_debugfs_root; #endif From e87055d732e34d8f5fa95da686958b30a03da5b4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:56 -0600 Subject: [PATCH 197/461] ASoC: Intel: haswell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/haswell.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index a4022983a7ce..971226d42042 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../common/sst-dsp.h" @@ -189,8 +190,22 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + haswell_rt5640.dev = &pdev->dev; + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } From 2d067b2807f9d3381a37acef1b2f43682a868c7a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:57 -0600 Subject: [PATCH 198/461] ASoC: Intel: broadwell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 99f2a0156ae8..b86c746d9b7a 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -267,7 +268,22 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + broadwell_rt286.dev = &pdev->dev; + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } From 7e40ddcf974a970e750420f88365174cfd207b24 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:58 -0600 Subject: [PATCH 199/461] ASoC: Intel: bdw-rt5677: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index efcfd906c856..1844c88ea4e2 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -339,6 +340,9 @@ static struct snd_soc_card bdw_rt5677_card = { static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -350,6 +354,16 @@ static int bdw_rt5677_probe(struct platform_device *pdev) return -ENOMEM; } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); From bd7661b761bc7f585aad4fc6e5b62d684bdad75b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:59 -0600 Subject: [PATCH 200/461] ASoC: Intel: bytcr_rt5640: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a79466c8fb29..940eb27158da 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1153,6 +1153,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int ret_val = 0; int dai_index = 0; @@ -1317,6 +1318,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { From 0b2c2093fc3a1f89f2ef15d945c0439ce7b9dd9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:00 -0600 Subject: [PATCH 201/461] ASoC: Intel: bytcr_rt5651: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e6945d11c8ab..c3b7732929cc 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -922,6 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; @@ -1137,6 +1138,14 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); byt_rt5651_card.long_name = byt_rt5651_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { From 686338c12a2bd2d27f8444901fb9ce1a4c0c0b58 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:01 -0600 Subject: [PATCH 202/461] ASoC: Intel: bytcht_da7213: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_da7213.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad..b8e884803777 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -225,6 +225,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0; @@ -250,6 +251,13 @@ static int bytcht_da7213_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, From e4bc6b1195f64d345646709c4a65edf1fc4d3228 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:02 -0600 Subject: [PATCH 203/461] ASoC: Intel: bytcht_es8316: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1364e4e601d8..d2a7e6ba11ae 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -441,6 +441,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; struct device *codec_dev; int dai_index = 0; @@ -469,6 +470,14 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, + platform_name); + if (ret) + return ret; + /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { From 7e7e24d7c7ff0e85956288915aaa7e682e2ccd55 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:03 -0600 Subject: [PATCH 204/461] ASoC: Intel: cht_bsw_max98090_ti: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 08a5152e635a..3263b0495853 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../codecs/max98090.h" #include "../atom/sst-atom-controls.h" @@ -420,6 +421,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; const char *mclk_name; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int quirks = 0; dmi_id = dmi_first_match(cht_max98090_quirk_table); @@ -442,6 +445,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); From 4506db8043341f2351e03d45c0e96c8e1a141dfa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:04 -0600 Subject: [PATCH 205/461] ASoC: Intel: cht_bsw_nau8824: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_nau8824.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 30c46977d53c..02c2fa239331 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "../atom/sst-atom-controls.h" @@ -246,6 +247,8 @@ static struct snd_soc_card snd_soc_card_cht = { static int snd_cht_mc_probe(struct platform_device *pdev) { struct cht_mc_private *drv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -253,6 +256,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); From 3a934e7c75b446a104bdea3dd676d7199db9a7bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:05 -0600 Subject: [PATCH 206/461] ASoC: Intel: cht_bsw_rt5645: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 250a356a0cbf..cbc2d458483f 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -530,6 +530,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct cht_mc_private *drv; const char *i2c_name = NULL; bool found = false; @@ -663,6 +664,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_rt5645_cpu_dai_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From f403906da05cdea38c222ef472fdc4df29ece47f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:06 -0600 Subject: [PATCH 207/461] ASoC: Intel: cht_bsw_rt5672: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9de64f447e7b..f1c1f9dd5353 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -400,6 +400,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + const char *platform_name; const char *i2c_name; int i; @@ -426,6 +427,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 7ebf2528eacae2a9c1edff575c3c58b75095ce08 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:07 -0600 Subject: [PATCH 208/461] ASoC: Intel: bxt_da7219_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e2..c00925f9da73 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" @@ -584,6 +585,9 @@ static struct snd_soc_card broxton_audio_card = { static int broxton_audio_probe(struct platform_device *pdev) { struct bxt_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -594,6 +598,15 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } From fbe2c2736e295bf866110c9278504c42498318c5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:08 -0600 Subject: [PATCH 209/461] ASoC: Intel: bxt_rt298: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 27308337ab12..e91057f83d20 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "../../codecs/hdac_hdmi.h" @@ -576,6 +577,9 @@ static int broxton_audio_probe(struct platform_device *pdev) struct bxt_rt286_private *ctx; struct snd_soc_card *card = (struct snd_soc_card *)pdev->id_entry->driver_data; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; int i; for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { @@ -602,6 +606,15 @@ static int broxton_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; snd_soc_card_set_drvdata(card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, card); } From 5b14aa718f5993b0ecee3bbd61557468ac2420bf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:09 -0600 Subject: [PATCH 210/461] ASoC: Intel: glk_rt5682_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index f6597c216fa8..d17126f7757c 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../skylake/skl.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -571,6 +572,10 @@ static struct snd_soc_card glk_audio_card_rt5682_m98357a = { static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -578,11 +583,19 @@ static int geminilake_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - glk_audio_card_rt5682_m98357a.dev = &pdev->dev; - snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx); + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); - return devm_snd_soc_register_card(&pdev->dev, - &glk_audio_card_rt5682_m98357a); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; + + return devm_snd_soc_register_card(&pdev->dev, card); } static const struct platform_device_id glk_board_ids[] = { From 262ff68fce8fe388bfa60efc95e394cf0a149563 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:46 +0000 Subject: [PATCH 211/461] ASoC: dt-bindings: update wcd9335 bindings. This patch updates wcd9335 bindings with recommended properties. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,wcd9335.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt index 1d8d49e30af7..5d6ea66a863f 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt +++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt @@ -34,12 +34,12 @@ Required properties with SLIMbus Interface: Definition: Interrupt names of WCD INTR1 and INTR2 Should be: "intr1", "intr2" -- reset-gpio: +- reset-gpios: Usage: required Value type: Definition: Reset gpio line -- qcom,ifd: +- slim-ifc-dev: Usage: required Value type: Definition: SLIM interface device @@ -104,13 +104,13 @@ Required properties with SLIMbus Interface: Value type: Definition: Must be 1 -codec@1{ +audio-codec@1{ compatible = "slim217,1a0"; reg = <1 0>; interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "intr2" - reset-gpio = <&msmgpio 64 0>; - qcom,ifd = <&wc9335_ifd>; + reset-gpios = <&msmgpio 64 0>; + slim-ifc-dev = <&wc9335_ifd>; clock-names = "mclk", "native"; clocks = <&rpmcc RPM_SMD_DIV_CLK1>, <&rpmcc RPM_SMD_BB_CLK1>; From 20aedafdf4926e7a957f8b302a18c8fb75c7e332 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:47 +0000 Subject: [PATCH 212/461] ASoC: wcd9335: add support to wcd9335 codec Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, It supports both I2S/I2C and SLIMbus audio interfaces. On slimbus interface it supports two data lanes; 16 Tx ports and 8 Rx ports. It has Seven DACs and nine dedicated interpolators, Seven (six audio ADCs, and one VBAT ADC), Multibutton headset control (MBHC), Active noise cancellation and Sidetone paths and processing. This patchset adds very basic support for playback and capture via the 9 interpolators and ADC respectively. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wcd9335.c | 1483 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd9335.h | 640 ++++++++++++++++ 4 files changed, 2134 insertions(+) create mode 100644 sound/soc/codecs/wcd9335.c create mode 100644 sound/soc/codecs/wcd9335.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 83ef965cbff1..9b904f81863d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -188,6 +188,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL6040 if TWL6040_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C + select SND_SOC_WCD9335 if SLIMBUS select SND_SOC_WL1273 if MFD_WL1273_CORE select SND_SOC_WM0010 if SPI_MASTER select SND_SOC_WM1250_EV1 if I2C @@ -1114,6 +1115,14 @@ config SND_SOC_UDA1380 tristate depends on I2C +config SND_SOC_WCD9335 + tristate "WCD9335 Codec" + select REGMAP_SLIMBUS + help + The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports + Qualcomm Technologies, Inc. (QTI) multimedia solutions, + including the MSM8996, MSM8976, and MSM8956 chipsets. + config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 457f9ff5a2d4..342d057cd7fc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -201,6 +201,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wcd9335-objs := wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -469,6 +470,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c new file mode 100644 index 000000000000..d6b690af7f09 --- /dev/null +++ b/sound/soc/codecs/wcd9335.c @@ -0,0 +1,1483 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9335.h" + +#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100) +#define WCD9335_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* slave port water mark level + * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes) + */ +#define SLAVE_PORT_WATER_MARK_6BYTES 0 +#define SLAVE_PORT_WATER_MARK_9BYTES 1 +#define SLAVE_PORT_WATER_MARK_12BYTES 2 +#define SLAVE_PORT_WATER_MARK_15BYTES 3 +#define SLAVE_PORT_WATER_MARK_SHIFT 1 +#define SLAVE_PORT_ENABLE 1 +#define SLAVE_PORT_DISABLE 0 +#define WCD9335_SLIM_WATER_MARK_VAL \ + ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \ + (SLAVE_PORT_ENABLE)) + +#define WCD9335_SLIM_NUM_PORT_REG 3 +#define WCD9335_SLIM_PGD_PORT_INT_TX_EN0 (WCD9335_SLIM_PGD_PORT_INT_EN0 + 2) + +#define WCD9335_MCLK_CLK_12P288MHZ 12288000 +#define WCD9335_MCLK_CLK_9P6MHZ 9600000 + +#define WCD9335_SLIM_CLOSE_TIMEOUT 1000 +#define WCD9335_SLIM_IRQ_OVERFLOW (1 << 0) +#define WCD9335_SLIM_IRQ_UNDERFLOW (1 << 1) +#define WCD9335_SLIM_IRQ_PORT_CLOSED (1 << 2) + +#define WCD9335_NUM_INTERPOLATORS 9 +#define WCD9335_RX_START 16 +#define WCD9335_SLIM_CH_START 128 + +#define WCD9335_SLIM_RX_CH(p) \ + {.port = p + WCD9335_RX_START, .shift = p,} + +/* vout step value */ +#define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) + +enum { + WCD9335_RX0 = 0, + WCD9335_RX1, + WCD9335_RX2, + WCD9335_RX3, + WCD9335_RX4, + WCD9335_RX5, + WCD9335_RX6, + WCD9335_RX7, + WCD9335_RX8, + WCD9335_RX9, + WCD9335_RX10, + WCD9335_RX11, + WCD9335_RX12, + WCD9335_RX_MAX, +}; + +enum { + SIDO_SOURCE_INTERNAL = 0, + SIDO_SOURCE_RCO_BG, +}; + +enum wcd9335_sido_voltage { + SIDO_VOLTAGE_SVS_MV = 950, + SIDO_VOLTAGE_NOMINAL_MV = 1100, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + NUM_CODEC_DAIS, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTn_1_MIX_INP_SEL_ZERO = 0, + INTn_1_MIX_INP_SEL_DEC0, + INTn_1_MIX_INP_SEL_DEC1, + INTn_1_MIX_INP_SEL_IIR0, + INTn_1_MIX_INP_SEL_IIR1, + INTn_1_MIX_INP_SEL_RX0, + INTn_1_MIX_INP_SEL_RX1, + INTn_1_MIX_INP_SEL_RX2, + INTn_1_MIX_INP_SEL_RX3, + INTn_1_MIX_INP_SEL_RX4, + INTn_1_MIX_INP_SEL_RX5, + INTn_1_MIX_INP_SEL_RX6, + INTn_1_MIX_INP_SEL_RX7, + +}; + +enum wcd_clock_type { + WCD_CLK_OFF, + WCD_CLK_RCO, + WCD_CLK_MCLK, +}; + +struct wcd9335_slim_ch { + u32 ch_num; + u16 port; + u16 shift; + struct list_head list; +}; + +struct wcd_slim_codec_dai_data { + struct list_head slim_ch_list; + struct slim_stream_config sconfig; + struct slim_stream_runtime *sruntime; +}; + +struct wcd9335_codec { + struct device *dev; + struct clk *mclk; + struct clk *native_clk; + u32 mclk_rate; + u8 version; + + struct slim_device *slim; + struct slim_device *slim_ifc_dev; + struct regmap *regmap; + struct regmap *if_regmap; + struct regmap_irq_chip_data *irq_data; + + struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + u32 num_rx_port; + + int sido_input_src; + enum wcd9335_sido_voltage sido_voltage; + + struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS]; + struct snd_soc_component *component; + + int master_bias_users; + int clk_mclk_users; + int clk_rco_users; + int sido_ccl_cnt; + enum wcd_clock_type clk_type; + + u32 hph_mode; + int intr1; + int reset_gpio; + struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; +}; + +struct wcd9335_irq { + int irq; + irqreturn_t (*handler)(int irq, void *data); + char *name; +}; + +static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { + WCD9335_SLIM_RX_CH(0), /* 16 */ + WCD9335_SLIM_RX_CH(1), /* 17 */ + WCD9335_SLIM_RX_CH(2), + WCD9335_SLIM_RX_CH(3), + WCD9335_SLIM_RX_CH(4), + WCD9335_SLIM_RX_CH(5), + WCD9335_SLIM_RX_CH(6), + WCD9335_SLIM_RX_CH(7), + WCD9335_SLIM_RX_CH(8), + WCD9335_SLIM_RX_CH(9), + WCD9335_SLIM_RX_CH(10), + WCD9335_SLIM_RX_CH(11), + WCD9335_SLIM_RX_CH(12), +}; + +struct interp_sample_rate { + int rate; + int rate_val; +}; + +static struct interp_sample_rate int_mix_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +static struct interp_sample_rate int_prim_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +struct wcd9335_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = { + /* Rbuckfly/R_EAR(32) */ + {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, + {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00}, + {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, + {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD9335_EAR_CMBUFF, 0x08, 0x00}, + {WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08}, + {WCD9335_RCO_CTRL_2, 0x0F, 0x08}, + {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10}, + {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20}, + {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A}, + {WCD9335_HPH_L_TEST, 0x01, 0x01}, + {WCD9335_HPH_R_TEST, 0x01, 0x01}, + {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45}, + {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, +}; + +static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, + int rate_val, + u32 rate) +{ + struct snd_soc_component *component = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + int val, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + val = snd_soc_component_read32(component, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if (val == (ch->shift + INTn_2_INP_SEL_RX0)) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX_PATH_MIX_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + + return 0; +} + +static int wcd9335_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_val, + u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + struct wcd9335_slim_ch *ch; + u8 cfg0, cfg1, inp0_sel, inp1_sel, inp2_sel; + int inp, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + inp = ch->shift + INTn_1_MIX_INP_SEL_RX0; + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + cfg0 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(j)); + cfg1 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)); + + inp0_sel = cfg0 & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp1_sel = (cfg0 >> 4) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp2_sel = (cfg1 >> 4) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if ((inp0_sel == inp) || (inp1_sel == inp) || + (inp2_sel == inp)) { + /* rate is in Hz */ + if ((j == 0) && (rate == 44100)) + dev_info(wcd->dev, + "Cannot set 44.1KHz on INT0\n"); + else + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX_PATH_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + } + + return 0; +} + +static int wcd9335_set_interpolator_rate(struct snd_soc_dai *dai, u32 rate) +{ + int i; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_rate_val); i++) { + if (rate == int_mix_rate_val[i].rate) { + wcd9335_set_mix_interpolator_rate(dai, + int_mix_rate_val[i].rate_val, rate); + break; + } + } + + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_rate_val); i++) { + if (rate == int_prim_rate_val[i].rate) { + wcd9335_set_prim_interpolator_rate(dai, + int_prim_rate_val[i].rate_val, rate); + break; + } + } + + return 0; +} + +static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, + struct wcd_slim_codec_dai_data *dai_data, + int direction) +{ + struct list_head *slim_ch_list = &dai_data->slim_ch_list; + struct slim_stream_config *cfg = &dai_data->sconfig; + struct wcd9335_slim_ch *ch; + u16 payload = 0; + int ret, i; + + cfg->ch_count = 0; + cfg->direction = direction; + cfg->port_mask = 0; + + /* Configure slave interface device */ + list_for_each_entry(ch, slim_ch_list, list) { + cfg->ch_count++; + payload |= 1 << ch->shift; + cfg->port_mask |= BIT(ch->port); + } + + cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL); + if (!cfg->chs) + return -ENOMEM; + + i = 0; + list_for_each_entry(ch, slim_ch_list, list) { + cfg->chs[i++] = ch->ch_num; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + /* write to interface device */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(ch->port), + payload); + + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + if (ret < 0) + goto err; + } + } + + dai_data->sruntime = slim_stream_allocate(wcd->slim, "WCD9335-SLIM"); + + return 0; + +err: + dev_err(wcd->dev, "Error Setting slim hw params\n"); + kfree(cfg->chs); + cfg->chs = NULL; + + return ret; +} + +static int wcd9335_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd9335_codec *wcd; + int ret; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = wcd9335_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(wcd->dev, "cannot set sample rate: %u\n", + params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16 ... 24: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + default: + dev_err(wcd->dev, "Invalid stream type %d\n", + substream->stream); + return -EINVAL; + }; + + wcd->dai[dai->id].sconfig.rate = params_rate(params); + wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream); + + return 0; +} + +static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct wcd_slim_codec_dai_data *dai_data; + struct wcd9335_codec *wcd; + struct slim_stream_config *cfg; + + wcd = snd_soc_component_get_drvdata(dai->component); + + dai_data = &wcd->dai[dai->id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + cfg = &dai_data->sconfig; + slim_stream_prepare(dai_data->sruntime, cfg); + slim_stream_enable(dai_data->sruntime); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + slim_stream_unprepare(dai_data->sruntime); + slim_stream_disable(dai_data->sruntime); + break; + default: + break; + } + + return 0; +} + +static int wcd9335_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct wcd9335_codec *wcd; + int i; + + wcd = snd_soc_component_get_drvdata(dai->component); + + if (!tx_slot || !rx_slot) { + dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n", + tx_slot, rx_slot); + return -EINVAL; + } + + if (wcd->rx_chs) { + wcd->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd->rx_chs[i].list); + } + } + + return 0; +} + +static int wcd9335_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct wcd9335_slim_ch *ch; + struct wcd9335_codec *wcd; + int i = 0; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + if (!rx_slot || !rx_num) { + dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n", + rx_slot, rx_num); + return -EINVAL; + } + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + rx_slot[i++] = ch->ch_num; + + *rx_num = i; + break; + default: + dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); + break; + } + + return 0; +} + +static struct snd_soc_dai_ops wcd9335_dai_ops = { + .hw_params = wcd9335_hw_params, + .trigger = wcd9335_trigger, + .set_channel_map = wcd9335_set_channel_map, + .get_channel_map = wcd9335_get_channel_map, +}; + +static struct snd_soc_dai_driver wcd9335_slim_dais[] = { + [0] = { + .name = "wcd9335_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [1] = { + .name = "wcd9335_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [2] = { + .name = "wcd9335_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [3] = { + .name = "wcd9335_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [4] = { + .name = "wcd9335_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [5] = { + .name = "wcd9335_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [6] = { + .name = "wcd9335_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, +}; + +static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) +{ + struct wcd9335_codec *wcd = data; + unsigned long status = 0; + int i, j, port_id; + unsigned int val, int_val = 0; + irqreturn_t ret = IRQ_NONE; + bool tx; + unsigned short reg = 0; + + for (i = WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + regmap_read(wcd->if_regmap, i, &val); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + regmap_read(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val); + if (val) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + + if (val & WCD9335_SLIM_IRQ_OVERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + + if (val & WCD9335_SLIM_IRQ_UNDERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + + if ((val & WCD9335_SLIM_IRQ_OVERFLOW) || + (val & WCD9335_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + regmap_write(wcd->if_regmap, + reg, int_val); + } + } + + regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8), + BIT(j % 8)); + ret = IRQ_HANDLED; + } + + return ret; +} + +static struct wcd9335_irq wcd9335_irqs[] = { + { + .irq = WCD9335_IRQ_SLIMBUS, + .handler = wcd9335_slimbus_irq, + .name = "SLIM Slave", + }, +}; + +static int wcd9335_setup_irqs(struct wcd9335_codec *wcd) +{ + int irq, ret, i; + + for (i = 0; i < ARRAY_SIZE(wcd9335_irqs); i++) { + irq = regmap_irq_get_virq(wcd->irq_data, wcd9335_irqs[i].irq); + if (irq < 0) { + dev_err(wcd->dev, "Failed to get %s\n", + wcd9335_irqs[i].name); + return irq; + } + + ret = devm_request_threaded_irq(wcd->dev, irq, NULL, + wcd9335_irqs[i].handler, + IRQF_TRIGGER_RISING, + wcd9335_irqs[i].name, wcd); + if (ret) { + dev_err(wcd->dev, "Failed to request %s\n", + wcd9335_irqs[i].name); + return ret; + } + } + + /* enable interrupts on all slave ports */ + for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++) + regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i, + 0xFF); + + return ret; +} + +static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_codec *wcd, + bool ccl_flag) +{ + struct snd_soc_component *comp = wcd->component; + + if (ccl_flag) { + if (++wcd->sido_ccl_cnt == 1) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_DEF_VALUE); + } else { + if (wcd->sido_ccl_cnt == 0) { + dev_err(wcd->dev, "sido_ccl already disabled\n"); + return; + } + if (--wcd->sido_ccl_cnt == 0) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF); + } +} + +static int wcd9335_enable_master_bias(struct wcd9335_codec *wcd) +{ + wcd->master_bias_users++; + if (wcd->master_bias_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_ENABLE); + /* + * 1ms delay is required after pre-charge is enabled + * as per HW requirement + */ + usleep_range(1000, 1100); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + + return 0; +} + +static int wcd9335_enable_mclk(struct wcd9335_codec *wcd) +{ + /* Enable mclk requires master bias to be enabled first */ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + if (((wcd->clk_mclk_users == 0) && (wcd->clk_type == WCD_CLK_MCLK)) || + ((wcd->clk_mclk_users > 0) && (wcd->clk_type != WCD_CLK_MCLK))) { + dev_err(wcd->dev, "Error enabling MCLK, clk_type: %d\n", + wcd->clk_type); + return -EINVAL; + } + + if (++wcd->clk_mclk_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE); + /* + * 10us sleep is required after clock is enabled + * as per HW requirement + */ + usleep_range(10, 15); + } + + wcd->clk_type = WCD_CLK_MCLK; + + return 0; +} + +static int wcd9335_disable_mclk(struct wcd9335_codec *wcd) +{ + if (wcd->clk_mclk_users <= 0) + return -EINVAL; + + if (--wcd->clk_mclk_users == 0) { + if (wcd->clk_rco_users > 0) { + /* MCLK to RCO switch */ + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_RCO); + wcd->clk_type = WCD_CLK_RCO; + } else { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_DISABLE); + wcd->clk_type = WCD_CLK_OFF; + } + + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE); + } + + return 0; +} + +static int wcd9335_disable_master_bias(struct wcd9335_codec *wcd) +{ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + wcd->master_bias_users--; + if (wcd->master_bias_users == 0) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + return 0; +} + +static int wcd9335_cdc_req_mclk_enable(struct wcd9335_codec *wcd, + bool enable) +{ + int ret = 0; + + if (enable) { + wcd9335_cdc_sido_ccl_enable(wcd, true); + ret = clk_prepare_enable(wcd->mclk); + if (ret) { + dev_err(wcd->dev, "%s: ext clk enable failed\n", + __func__); + goto err; + } + /* get BG */ + wcd9335_enable_master_bias(wcd); + /* get MCLK */ + wcd9335_enable_mclk(wcd); + + } else { + /* put MCLK */ + wcd9335_disable_mclk(wcd); + /* put BG */ + wcd9335_disable_master_bias(wcd); + clk_disable_unprepare(wcd->mclk); + wcd9335_cdc_sido_ccl_enable(wcd, false); + } +err: + return ret; +} + +static void wcd9335_codec_apply_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + struct snd_soc_component *comp = wcd->component; + int vout_d_val; + + if (req_mv == wcd->sido_voltage) + return; + + /* compute the vout_d step value */ + vout_d_val = WCD9335_CALCULATE_VOUT_D(req_mv) & + WCD9335_ANA_BUCK_VOUT_MASK; + snd_soc_component_write(comp, WCD9335_ANA_BUCK_VOUT_D, vout_d_val); + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE); + + /* 1 msec sleep required after SIDO Vout_D voltage change */ + usleep_range(1000, 1100); + wcd->sido_voltage = req_mv; + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE); +} + +static int wcd9335_codec_update_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + int ret = 0; + + /* enable mclk before setting SIDO voltage */ + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) { + dev_err(wcd->dev, "Ext clk enable failed\n"); + goto err; + } + + wcd9335_codec_apply_sido_voltage(wcd, req_mv); + wcd9335_cdc_req_mclk_enable(wcd, false); + +err: + return ret; +} + +static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, + int enable) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int ret; + + if (enable) { + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) + return ret; + + wcd9335_codec_apply_sido_voltage(wcd, + SIDO_VOLTAGE_NOMINAL_MV); + } else { + wcd9335_codec_update_sido_voltage(wcd, + wcd->sido_voltage); + wcd9335_cdc_req_mclk_enable(wcd, false); + } + + return 0; +} + +static void wcd9335_enable_sido_buck(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + snd_soc_component_update_bits(component, WCD9335_ANA_RCO, + WCD9335_ANA_RCO_BG_EN_MASK, + WCD9335_ANA_RCO_BG_ENABLE); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT); + /* 100us sleep needed after IREF settings */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT); + /* 100us sleep needed after VREF settings */ + usleep_range(100, 110); + wcd->sido_input_src = SIDO_SOURCE_RCO_BG; +} + +static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp) +{ + _wcd9335_codec_enable_mclk(comp, true); + snd_soc_component_update_bits(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK, + WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE); + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + + if (!(snd_soc_component_read32(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK)) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + wcd9335_enable_sido_buck(comp); + _wcd9335_codec_enable_mclk(comp, false); + + return 0; +} + +static void wcd9335_codec_init(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + /* ungate MCLK and set clk rate */ + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_GATE, + WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK, 0); + + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init); i++) + snd_soc_component_update_bits(component, + wcd9335_codec_reg_init[i].reg, + wcd9335_codec_reg_init[i].mask, + wcd9335_codec_reg_init[i].val); + + wcd9335_enable_efuse_sensing(component); +} + +static int wcd9335_codec_probe(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + snd_soc_component_init_regmap(component, wcd->regmap); + wcd->component = component; + + wcd9335_codec_init(component); + + for (i = 0; i < NUM_CODEC_DAIS; i++) + INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list); + + return wcd9335_setup_irqs(wcd); +} + +static void wcd9335_codec_remove(struct snd_soc_component *comp) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); +} + +static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + wcd->mclk_rate = freq; + + if (wcd->mclk_rate == WCD9335_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ); + else if (wcd->mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + return clk_set_rate(wcd->mclk, freq); +} + +static const struct snd_soc_component_driver wcd9335_component_drv = { + .probe = wcd9335_codec_probe, + .remove = wcd9335_codec_remove, + .set_sysclk = wcd9335_codec_set_sysclk, +}; + +static int wcd9335_probe(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + + memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + + wcd->sido_input_src = SIDO_SOURCE_INTERNAL; + wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; + + return devm_snd_soc_register_component(dev, &wcd9335_component_drv, + wcd9335_slim_dais, + ARRAY_SIZE(wcd9335_slim_dais)); +} + +static const struct regmap_range_cfg wcd9335_ranges[] = { + { + .name = "WCD9335", + .range_min = 0x0, + .range_max = WCD9335_MAX_REGISTER, + .selector_reg = WCD9335_REG(0x0, 0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD9335_INTR_PIN1_STATUS0...WCD9335_INTR_PIN2_CLEAR3: + case WCD9335_ANA_MBHC_RESULT_3: + case WCD9335_ANA_MBHC_RESULT_2: + case WCD9335_ANA_MBHC_RESULT_1: + case WCD9335_ANA_MBHC_MECH: + case WCD9335_ANA_MBHC_ELECT: + case WCD9335_ANA_MBHC_ZDET: + case WCD9335_ANA_MICB2: + case WCD9335_ANA_RCO: + case WCD9335_ANA_BIAS: + return true; + default: + return false; + } +} + +static struct regmap_config wcd9335_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = WCD9335_MAX_REGISTER, + .can_multi_write = true, + .ranges = wcd9335_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ranges), + .volatile_reg = wcd9335_is_volatile_register, +}; + +static const struct regmap_range_cfg wcd9335_ifc_ranges[] = { + { + .name = "WCD9335-IFC-DEV", + .range_min = 0x0, + .range_max = WCD9335_REG(0, 0x7ff), + .selector_reg = WCD9335_REG(0, 0x0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +static struct regmap_config wcd9335_ifc_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .can_multi_write = true, + .max_register = WCD9335_REG(0, 0x7FF), + .ranges = wcd9335_ifc_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ifc_ranges), +}; + +static const struct regmap_irq wcd9335_codec_irqs[] = { + /* INTR_REG 0 */ + [WCD9335_IRQ_SLIMBUS] = { + .reg_offset = 0, + .mask = BIT(0), + .type = { + .type_reg_offset = 0, + .types_supported = IRQ_TYPE_EDGE_BOTH, + .type_reg_mask = BIT(0), + }, + }, +}; + +static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { + .name = "wcd9335_pin1_irq", + .status_base = WCD9335_INTR_PIN1_STATUS0, + .mask_base = WCD9335_INTR_PIN1_MASK0, + .ack_base = WCD9335_INTR_PIN1_CLEAR0, + .type_base = WCD9335_INTR_LEVEL0, + .num_type_reg = 4, + .num_regs = 4, + .irqs = wcd9335_codec_irqs, + .num_irqs = ARRAY_SIZE(wcd9335_codec_irqs), +}; + +static int wcd9335_parse_dt(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + struct device_node *np = dev->of_node; + int ret; + + wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (wcd->reset_gpio < 0) { + dev_err(dev, "Reset GPIO missing from DT\n"); + return wcd->reset_gpio; + } + + wcd->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(wcd->mclk)) { + dev_err(dev, "mclk not found\n"); + return PTR_ERR(wcd->mclk); + } + + wcd->native_clk = devm_clk_get(dev, "slimbus"); + if (IS_ERR(wcd->native_clk)) { + dev_err(dev, "slimbus clock not found\n"); + return PTR_ERR(wcd->native_clk); + } + + wcd->supplies[0].supply = "vdd-buck"; + wcd->supplies[1].supply = "vdd-buck-sido"; + wcd->supplies[2].supply = "vdd-tx"; + wcd->supplies[3].supply = "vdd-rx"; + wcd->supplies[4].supply = "vdd-io"; + + ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + return 0; +} + +static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + int ret; + + ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + /* + * For WCD9335, it takes about 600us for the Vout_A and + * Vout_D to be ready after BUCK_SIDO is powered up. + * SYS_RST_N shouldn't be pulled high during this time + * Toggle the reset line to make sure the reset pulse is + * correctly applied + */ + usleep_range(600, 650); + + gpio_direction_output(wcd->reset_gpio, 0); + msleep(20); + gpio_set_value(wcd->reset_gpio, 1); + msleep(20); + + return 0; +} + +static int wcd9335_bring_up(struct wcd9335_codec *wcd) +{ + struct regmap *rm = wcd->regmap; + int val, byte0; + + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val); + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0); + + if ((val < 0) || (byte0 < 0)) { + dev_err(wcd->dev, "WCD9335 CODEC version detection fail!\n"); + return -EINVAL; + } + + if (byte0 == 0x1) { + dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n"); + wcd->version = WCD9335_VERSION_2_0; + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00); + regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F); + regmap_write(rm, WCD9335_BIAS_VBG_FINE_ADJ, 0x65); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else { + dev_err(wcd->dev, "WCD9335 CODEC version not supported\n"); + return -EINVAL; + } + + return 0; +} + +static int wcd9335_irq_init(struct wcd9335_codec *wcd) +{ + int ret; + + /* + * INTR1 consists of all possible interrupt sources Ear OCP, + * HPH OCP, MBHC, MAD, VBAT, and SVA + * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA + */ + wcd->intr1 = of_irq_get_byname(wcd->dev->of_node, "intr1"); + if (wcd->intr1 < 0) { + if (wcd->intr1 != -EPROBE_DEFER) + dev_err(wcd->dev, "Unable to configure IRQ\n"); + + return wcd->intr1; + } + + ret = devm_regmap_add_irq_chip(wcd->dev, wcd->regmap, wcd->intr1, + IRQF_TRIGGER_HIGH, 0, + &wcd9335_regmap_irq1_chip, &wcd->irq_data); + if (ret) + dev_err(wcd->dev, "Failed to register IRQ chip: %d\n", ret); + + return ret; +} + +static int wcd9335_slim_probe(struct slim_device *slim) +{ + struct device *dev = &slim->dev; + struct wcd9335_codec *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + wcd->dev = dev; + ret = wcd9335_parse_dt(wcd); + if (ret) { + dev_err(dev, "Error parsing DT: %d\n", ret); + return ret; + } + + ret = wcd9335_power_on_reset(wcd); + if (ret) + return ret; + + dev_set_drvdata(dev, wcd); + + return 0; +} + +static int wcd9335_slim_status(struct slim_device *sdev, + enum slim_device_status status) +{ + struct device *dev = &sdev->dev; + struct device_node *ifc_dev_np; + struct wcd9335_codec *wcd; + int ret; + + wcd = dev_get_drvdata(dev); + + ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0); + if (!ifc_dev_np) { + dev_err(dev, "No Interface device found\n"); + return -EINVAL; + } + + wcd->slim = sdev; + wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np); + if (!wcd->slim_ifc_dev) { + dev_err(dev, "Unable to get SLIM Interface device\n"); + return -EINVAL; + } + + slim_get_logical_addr(wcd->slim_ifc_dev); + + wcd->regmap = regmap_init_slimbus(sdev, &wcd9335_regmap_config); + if (IS_ERR(wcd->regmap)) { + dev_err(dev, "Failed to allocate slim register map\n"); + return PTR_ERR(wcd->regmap); + } + + wcd->if_regmap = regmap_init_slimbus(wcd->slim_ifc_dev, + &wcd9335_ifc_regmap_config); + if (IS_ERR(wcd->if_regmap)) { + dev_err(dev, "Failed to allocate ifc register map\n"); + return PTR_ERR(wcd->if_regmap); + } + + ret = wcd9335_bring_up(wcd); + if (ret) { + dev_err(dev, "Failed to bringup WCD9335\n"); + return ret; + } + + ret = wcd9335_irq_init(wcd); + if (ret) + return ret; + + wcd9335_probe(wcd); + + return ret; +} + +static const struct slim_device_id wcd9335_slim_id[] = { + {SLIM_MANF_ID_QCOM, SLIM_PROD_CODE_WCD9335, 0x1, 0x0}, + {} +}; +MODULE_DEVICE_TABLE(slim, wcd9335_slim_id); + +static struct slim_driver wcd9335_slim_driver = { + .driver = { + .name = "wcd9335-slim", + }, + .probe = wcd9335_slim_probe, + .device_status = wcd9335_slim_status, + .id_table = wcd9335_slim_id, +}; + +module_slim_driver(wcd9335_slim_driver); +MODULE_DESCRIPTION("WCD9335 slim driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("slim:217:1a0:*"); diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h new file mode 100644 index 000000000000..4d9be2496c30 --- /dev/null +++ b/sound/soc/codecs/wcd9335.h @@ -0,0 +1,640 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __WCD9335_H__ +#define __WCD9335_H__ + +/* + * WCD9335 register base can change according to the mode it works in + * in slimbus mode the reg base starts from 0x800 + * in i2s/i2c mode the reg base is 0x0 + */ +#define WCD9335_REG(pg, r) ((pg << 12) | (r) | 0x800) +#define WCD9335_REG_OFFSET(r) (r & 0xFF) +#define WCD9335_PAGE_OFFSET(r) ((r >> 12) & 0xFF) + +/* Page-0 Registers */ +#define WCD9335_PAGE0_PAGE_REGISTER WCD9335_REG(0x00, 0x000) +#define WCD9335_CODEC_RPM_CLK_GATE WCD9335_REG(0x00, 0x002) +#define WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG WCD9335_REG(0x00, 0x003) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_RST_CTL WCD9335_REG(0x00, 0x009) +#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL WCD9335_REG(0x00, 0x011) +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 WCD9335_REG(0x00, 0x021) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL WCD9335_REG(0x00, 0x025) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_SSTATE_MASK GENMASK(4, 1) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 WCD9335_REG(0x00, 0x029) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS WCD9335_REG(0x00, 0x039) +#define WCD9335_INTR_CFG WCD9335_REG(0x00, 0x081) +#define WCD9335_INTR_CLR_COMMIT WCD9335_REG(0x00, 0x082) +#define WCD9335_INTR_PIN1_MASK0 WCD9335_REG(0x00, 0x089) +#define WCD9335_INTR_PIN1_MASK1 WCD9335_REG(0x00, 0x08a) +#define WCD9335_INTR_PIN1_MASK2 WCD9335_REG(0x00, 0x08b) +#define WCD9335_INTR_PIN1_MASK3 WCD9335_REG(0x00, 0x08c) +#define WCD9335_INTR_PIN1_STATUS0 WCD9335_REG(0x00, 0x091) +#define WCD9335_INTR_PIN1_STATUS1 WCD9335_REG(0x00, 0x092) +#define WCD9335_INTR_PIN1_STATUS2 WCD9335_REG(0x00, 0x093) +#define WCD9335_INTR_PIN1_STATUS3 WCD9335_REG(0x00, 0x094) +#define WCD9335_INTR_PIN1_CLEAR0 WCD9335_REG(0x00, 0x099) +#define WCD9335_INTR_PIN1_CLEAR1 WCD9335_REG(0x00, 0x09a) +#define WCD9335_INTR_PIN1_CLEAR2 WCD9335_REG(0x00, 0x09b) +#define WCD9335_INTR_PIN1_CLEAR3 WCD9335_REG(0x00, 0x09c) +#define WCD9335_INTR_PIN2_MASK0 WCD9335_REG(0x00, 0x0a1) +#define WCD9335_INTR_PIN2_MASK1 WCD9335_REG(0x00, 0x0a2) +#define WCD9335_INTR_PIN2_MASK2 WCD9335_REG(0x00, 0x0a3) +#define WCD9335_INTR_PIN2_MASK3 WCD9335_REG(0x00, 0x0a4) +#define WCD9335_INTR_PIN2_STATUS0 WCD9335_REG(0x00, 0x0a9) +#define WCD9335_INTR_PIN2_STATUS1 WCD9335_REG(0x00, 0x0aa) +#define WCD9335_INTR_PIN2_STATUS2 WCD9335_REG(0x00, 0x0ab) +#define WCD9335_INTR_PIN2_STATUS3 WCD9335_REG(0x00, 0x0ac) +#define WCD9335_INTR_PIN2_CLEAR0 WCD9335_REG(0x00, 0x0b1) +#define WCD9335_INTR_PIN2_CLEAR1 WCD9335_REG(0x00, 0x0b2) +#define WCD9335_INTR_PIN2_CLEAR2 WCD9335_REG(0x00, 0x0b3) +#define WCD9335_INTR_PIN2_CLEAR3 WCD9335_REG(0x00, 0x0b4) +#define WCD9335_INTR_LEVEL0 WCD9335_REG(0x00, 0x0e1) +#define WCD9335_INTR_LEVEL1 WCD9335_REG(0x00, 0x0e2) +#define WCD9335_INTR_LEVEL2 WCD9335_REG(0x00, 0x0e3) +#define WCD9335_INTR_LEVEL3 WCD9335_REG(0x00, 0x0e4) + +/* Page-1 Registers */ +#define WCD9335_CPE_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x001) +#define WCD9335_CPE_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x002) +#define WCD9335_CPE_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x003) +#define WCD9335_CPE_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x004) +#define WCD9335_CPE_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x005) +#define WCD9335_CPE_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x006) +#define WCD9335_CPE_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x007) +#define WCD9335_CPE_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x008) +#define WCD9335_CPE_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x009) +#define WCD9335_CPE_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x00a) +#define WCD9335_CPE_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x00b) +#define WCD9335_CPE_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x00c) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x00d) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x00e) +#define WCD9335_CPE_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x00f) +#define WCD9335_CPE_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x010) +#define WCD9335_CPE_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x011) +#define WCD9335_CPE_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x012) +#define WCD9335_CPE_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x013) +#define WCD9335_CPE_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x014) +#define WCD9335_CPE_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x015) +#define WCD9335_CPE_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x016) +#define WCD9335_CPE_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x017) +#define WCD9335_CPE_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x018) +#define WCD9335_CPE_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x019) +#define WCD9335_CPE_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x01a) +#define WCD9335_CPE_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x01b) +#define WCD9335_CPE_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x01c) +#define WCD9335_CPE_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x01d) +#define WCD9335_CPE_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x01e) +#define WCD9335_CPE_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x01f) +#define WCD9335_CPE_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x020) +#define WCD9335_CPE_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x021) +#define WCD9335_CPE_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x022) +#define WCD9335_CPE_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x023) +#define WCD9335_CPE_FLL_FLL_MODE WCD9335_REG(0x01, 0x024) +#define WCD9335_CPE_FLL_STATUS_0 WCD9335_REG(0x01, 0x025) +#define WCD9335_CPE_FLL_STATUS_1 WCD9335_REG(0x01, 0x026) +#define WCD9335_CPE_FLL_STATUS_2 WCD9335_REG(0x01, 0x027) +#define WCD9335_CPE_FLL_STATUS_3 WCD9335_REG(0x01, 0x028) +#define WCD9335_I2S_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x041) +#define WCD9335_I2S_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x042) +#define WCD9335_I2S_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x043) +#define WCD9335_I2S_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x044) +#define WCD9335_I2S_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x045) +#define WCD9335_I2S_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x046) +#define WCD9335_I2S_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x047) +#define WCD9335_I2S_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x048) +#define WCD9335_I2S_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x049) +#define WCD9335_I2S_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x04a) +#define WCD9335_I2S_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x04b) +#define WCD9335_I2S_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x04c) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x04d) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x04e) +#define WCD9335_I2S_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x04f) +#define WCD9335_I2S_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x050) +#define WCD9335_I2S_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x051) +#define WCD9335_I2S_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x052) +#define WCD9335_I2S_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x053) +#define WCD9335_I2S_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x054) +#define WCD9335_I2S_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x055) +#define WCD9335_I2S_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x056) +#define WCD9335_I2S_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x057) +#define WCD9335_I2S_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x058) +#define WCD9335_I2S_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x059) +#define WCD9335_I2S_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x05a) +#define WCD9335_I2S_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x05b) +#define WCD9335_I2S_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x05c) +#define WCD9335_I2S_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x05d) +#define WCD9335_I2S_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x05e) +#define WCD9335_I2S_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x05f) +#define WCD9335_I2S_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x060) +#define WCD9335_I2S_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x061) +#define WCD9335_I2S_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x062) +#define WCD9335_I2S_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x063) +#define WCD9335_I2S_FLL_FLL_MODE WCD9335_REG(0x01, 0x064) +#define WCD9335_I2S_FLL_STATUS_0 WCD9335_REG(0x01, 0x065) +#define WCD9335_I2S_FLL_STATUS_1 WCD9335_REG(0x01, 0x066) +#define WCD9335_I2S_FLL_STATUS_2 WCD9335_REG(0x01, 0x067) +#define WCD9335_I2S_FLL_STATUS_3 WCD9335_REG(0x01, 0x068) +#define WCD9335_SB_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x081) +#define WCD9335_SB_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x082) +#define WCD9335_SB_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x083) +#define WCD9335_SB_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x084) +#define WCD9335_SB_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x085) +#define WCD9335_SB_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x086) +#define WCD9335_SB_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x087) +#define WCD9335_SB_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x088) +#define WCD9335_SB_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x089) +#define WCD9335_SB_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x08a) +#define WCD9335_SB_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x08b) +#define WCD9335_SB_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x08c) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x08d) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x08e) +#define WCD9335_SB_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x08f) +#define WCD9335_SB_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x090) +#define WCD9335_SB_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x091) +#define WCD9335_SB_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x092) +#define WCD9335_SB_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x093) +#define WCD9335_SB_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x094) +#define WCD9335_SB_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x095) +#define WCD9335_SB_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x096) +#define WCD9335_SB_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x097) +#define WCD9335_SB_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x098) +#define WCD9335_SB_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x099) +#define WCD9335_SB_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x09a) +#define WCD9335_SB_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x09b) +#define WCD9335_SB_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x09c) +#define WCD9335_SB_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x09d) +#define WCD9335_SB_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x09e) +#define WCD9335_SB_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x09f) +#define WCD9335_SB_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x0a0) +#define WCD9335_SB_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x0a1) +#define WCD9335_SB_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x0a2) +#define WCD9335_SB_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x0a3) +#define WCD9335_SB_FLL_FLL_MODE WCD9335_REG(0x01, 0x0a4) +#define WCD9335_SB_FLL_STATUS_0 WCD9335_REG(0x01, 0x0a5) +#define WCD9335_SB_FLL_STATUS_1 WCD9335_REG(0x01, 0x0a6) +#define WCD9335_SB_FLL_STATUS_2 WCD9335_REG(0x01, 0x0a7) +#define WCD9335_SB_FLL_STATUS_3 WCD9335_REG(0x01, 0x0a8) + +/* Page-2 Registers */ +#define WCD9335_PAGE2_PAGE_REGISTER WCD9335_REG(0x02, 0x000) +#define WCD9335_CPE_SS_DMIC0_CTL WCD9335_REG(0x02, 0x063) +#define WCD9335_CPE_SS_DMIC1_CTL WCD9335_REG(0x02, 0x064) +#define WCD9335_CPE_SS_DMIC2_CTL WCD9335_REG(0x02, 0x065) +#define WCD9335_CPE_SS_DMIC_CFG WCD9335_REG(0x02, 0x066) +#define WCD9335_SOC_MAD_AUDIO_CTL_2 WCD9335_REG(0x02, 0x084) + +/* Page-6 Registers */ +#define WCD9335_PAGE6_PAGE_REGISTER WCD9335_REG(0x06, 0x000) +#define WCD9335_ANA_BIAS WCD9335_REG(0x06, 0x001) +#define WCD9335_ANA_BIAS_EN_MASK BIT(7) +#define WCD9335_ANA_BIAS_ENABLE BIT(7) +#define WCD9335_ANA_BIAS_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_EN_MASK BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_ENABLE BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_AUTO BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL 0 +#define WCD9335_ANA_CLK_TOP WCD9335_REG(0x06, 0x002) +#define WCD9335_ANA_CLK_MCLK_EN_MASK BIT(2) +#define WCD9335_ANA_CLK_MCLK_ENABLE BIT(2) +#define WCD9335_ANA_CLK_MCLK_DISABLE 0 +#define WCD9335_ANA_CLK_MCLK_SRC_MASK BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_RCO BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL 0 +#define WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE 0 +#define WCD9335_ANA_RCO WCD9335_REG(0x06, 0x003) +#define WCD9335_ANA_RCO_BG_EN_MASK BIT(7) +#define WCD9335_ANA_RCO_BG_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_VOUT_D WCD9335_REG(0x06, 0x005) +#define WCD9335_ANA_BUCK_VOUT_MASK GENMASK(7, 0) +#define WCD9335_ANA_BUCK_CTL WCD9335_REG(0x06, 0x006) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_RAMP_START_MASK BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE 0 +#define WCD9335_ANA_RX_SUPPLIES WCD9335_REG(0x06, 0x008) +#define WCD9335_ANA_RX_BIAS_ENABLE_MASK BIT(0) +#define WCD9335_ANA_RX_BIAS_ENABLE BIT(0) +#define WCD9335_ANA_RX_BIAS_DISABLE 0 +#define WCD9335_ANA_HPH WCD9335_REG(0x06, 0x009) +#define WCD9335_ANA_EAR WCD9335_REG(0x06, 0x00a) +#define WCD9335_ANA_LO_1_2 WCD9335_REG(0x06, 0x00b) +#define WCD9335_ANA_LO_3_4 WCD9335_REG(0x06, 0x00c) +#define WCD9335_ANA_AMIC1 WCD9335_REG(0x06, 0x00e) +#define WCD9335_ANA_AMIC2 WCD9335_REG(0x06, 0x00f) +#define WCD9335_ANA_AMIC3 WCD9335_REG(0x06, 0x010) +#define WCD9335_ANA_AMIC4 WCD9335_REG(0x06, 0x011) +#define WCD9335_ANA_AMIC5 WCD9335_REG(0x06, 0x012) +#define WCD9335_ANA_AMIC6 WCD9335_REG(0x06, 0x013) +#define WCD9335_ANA_MBHC_MECH WCD9335_REG(0x06, 0x014) +#define WCD9335_MBHC_L_DET_EN_MASK BIT(7) +#define WCD9335_MBHC_L_DET_EN BIT(7) +#define WCD9335_MBHC_GND_DET_EN_MASK BIT(6) +#define WCD9335_MBHC_MECH_DETECT_TYPE_MASK BIT(5) +#define WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT 5 +#define WCD9335_MBHC_HPHL_PLUG_TYPE_MASK BIT(4) +#define WCD9335_MBHC_HPHL_PLUG_TYPE_NO BIT(4) +#define WCD9335_MBHC_GND_PLUG_TYPE_MASK BIT(3) +#define WCD9335_MBHC_GND_PLUG_TYPE_NO BIT(3) +#define WCD9335_MBHC_HSL_PULLUP_COMP_EN BIT(2) +#define WCD9335_MBHC_HPHL_100K_TO_GND_EN BIT(0) + +#define WCD9335_ANA_MBHC_ELECT WCD9335_REG(0x06, 0x015) +#define WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4) +#define WCD9335_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4) +#define WCD9335_ANA_MBHC_BD_ISRC_OFF 0 +#define WCD9335_ANA_MBHC_BIAS_EN_MASK BIT(0) +#define WCD9335_ANA_MBHC_BIAS_EN BIT(0) +#define WCD9335_ANA_MBHC_ZDET WCD9335_REG(0x06, 0x016) +#define WCD9335_ANA_MBHC_RESULT_1 WCD9335_REG(0x06, 0x017) +#define WCD9335_ANA_MBHC_RESULT_2 WCD9335_REG(0x06, 0x018) +#define WCD9335_ANA_MBHC_RESULT_3 WCD9335_REG(0x06, 0x019) +#define WCD9335_MBHC_BTN_RESULT_MASK GENMASK(2, 0) +#define WCD9335_ANA_MBHC_BTN0 WCD9335_REG(0x06, 0x01a) +#define WCD9335_ANA_MBHC_BTN1 WCD9335_REG(0x06, 0x01b) +#define WCD9335_ANA_MBHC_BTN2 WCD9335_REG(0x06, 0x01c) +#define WCD9335_ANA_MBHC_BTN3 WCD9335_REG(0x06, 0x01d) +#define WCD9335_ANA_MBHC_BTN4 WCD9335_REG(0x06, 0x01e) +#define WCD9335_ANA_MBHC_BTN5 WCD9335_REG(0x06, 0x01f) +#define WCD9335_ANA_MBHC_BTN6 WCD9335_REG(0x06, 0x020) +#define WCD9335_ANA_MBHC_BTN7 WCD9335_REG(0x06, 0x021) +#define WCD9335_ANA_MICB1 WCD9335_REG(0x06, 0x022) +#define WCD9335_ANA_MICB2 WCD9335_REG(0x06, 0x023) +#define WCD9335_ANA_MICB2_ENABLE BIT(6) +#define WCD9335_ANA_MICB2_RAMP WCD9335_REG(0x06, 0x024) +#define WCD9335_ANA_MICB3 WCD9335_REG(0x06, 0x025) +#define WCD9335_ANA_MICB4 WCD9335_REG(0x06, 0x026) +#define WCD9335_ANA_VBADC WCD9335_REG(0x06, 0x027) +#define WCD9335_BIAS_VBG_FINE_ADJ WCD9335_REG(0x06, 0x029) +#define WCD9335_RCO_CTRL_2 WCD9335_REG(0x06, 0x02f) +#define WCD9335_SIDO_SIDO_CCL_2 WCD9335_REG(0x06, 0x042) +#define WCD9335_SIDO_SIDO_CCL_4 WCD9335_REG(0x06, 0x044) +#define WCD9335_SIDO_SIDO_CCL_8 WCD9335_REG(0x06, 0x048) +#define WCD9335_SIDO_SIDO_CCL_10 WCD9335_REG(0x06, 0x04a) +#define WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF 0x2 +/* Comparator 1 and 2 Bias current at 1P0UA with start pulse width of C320FF */ +#define WCD9335_SIDO_SIDO_CCL_DEF_VALUE 0x6e +#define WCD9335_SIDO_SIDO_TEST_2 WCD9335_REG(0x06, 0x055) +#define WCD9335_MBHC_CTL_1 WCD9335_REG(0x06, 0x056) +#define WCD9335_MBHC_BTN_DBNC_MASK GENMASK(1, 0) +#define WCD9335_MBHC_BTN_DBNC_T_16_MS 0x2 +#define WCD9335_MBHC_CTL_RCO_EN_MASK BIT(7) +#define WCD9335_MBHC_CTL_RCO_EN BIT(7) + +#define WCD9335_MBHC_CTL_2 WCD9335_REG(0x06, 0x057) +#define WCD9335_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0) +#define WCD9335_MBHC_HS_VREF_1P5_V 0x1 +#define WCD9335_MBHC_PLUG_DETECT_CTL WCD9335_REG(0x06, 0x058) +#define WCD9335_MBHC_HSDET_PULLUP_CTL_MASK GENMASK(7, 6) +#define WCD9335_MBHC_HSDET_PULLUP_CTL_SHIFT 6 +#define WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA 0x80 +#define WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6 + +#define WCD9335_MBHC_ZDET_RAMP_CTL WCD9335_REG(0x06, 0x05a) +#define WCD9335_VBADC_IBIAS_FE WCD9335_REG(0x06, 0x05e) +#define WCD9335_FLYBACK_CTRL_1 WCD9335_REG(0x06, 0x0b1) +#define WCD9335_RX_BIAS_HPH_PA WCD9335_REG(0x06, 0x0bb) +#define WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 WCD9335_REG(0x06, 0x0bc) +#define WCD9335_RX_BIAS_HPH_RDAC_LDO WCD9335_REG(0x06, 0x0bd) +#define WCD9335_RX_BIAS_FLYB_BUFF WCD9335_REG(0x06, 0x0c7) +#define WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_FLYB_I_0P0_UA 0 +#define WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9335_RX_BIAS_FLYB_MID_RST WCD9335_REG(0x06, 0x0c8) +#define WCD9335_HPH_CNP_WG_CTL WCD9335_REG(0x06, 0x0cc) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK GENMASK(2, 0) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500 0x2 +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000 0x3 +#define WCD9335_HPH_OCP_CTL WCD9335_REG(0x06, 0x0ce) +#define WCD9335_HPH_AUTO_CHOP WCD9335_REG(0x06, 0x0cf) +#define WCD9335_HPH_AUTO_CHOP_MASK BIT(5) +#define WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE BIT(5) +#define WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN 0 +#define WCD9335_HPH_PA_CTL1 WCD9335_REG(0x06, 0x0d1) +#define WCD9335_HPH_PA_GM3_IB_SCALE_MASK GENMASK(3, 1) +#define WCD9335_HPH_PA_CTL2 WCD9335_REG(0x06, 0x0d2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE 0 +#define WCD9335_HPH_L_EN WCD9335_REG(0x06, 0x0d3) +#define WCD9335_HPH_CONST_SEL_L_MASK GENMASK(7, 6) +#define WCD9335_HPH_CONST_SEL_L_BYPASS 0 +#define WCD9335_HPH_CONST_SEL_L_LP_PATH 0x40 +#define WCD9335_HPH_CONST_SEL_L_HQ_PATH 0x80 +#define WCD9335_HPH_PA_GAIN_MASK GENMASK(4, 0) +#define WCD9335_HPH_GAIN_SRC_SEL_MASK BIT(5) +#define WCD9335_HPH_GAIN_SRC_SEL_COMPANDER 0 +#define WCD9335_HPH_GAIN_SRC_SEL_REGISTER BIT(5) +#define WCD9335_HPH_L_TEST WCD9335_REG(0x06, 0x0d4) +#define WCD9335_HPH_R_EN WCD9335_REG(0x06, 0x0d6) +#define WCD9335_HPH_R_TEST WCD9335_REG(0x06, 0x0d7) +#define WCD9335_HPH_R_ATEST WCD9335_REG(0x06, 0x0d8) +#define WCD9335_HPH_RDAC_LDO_CTL WCD9335_REG(0x06, 0x0db) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK GENMASK(2, 0) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60 0x1 +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK GENMASK(6, 4) +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60 0x10 +#define WCD9335_HPH_REFBUFF_LP_CTL WCD9335_REG(0x06, 0x0de) +#define WCD9335_HPH_L_DAC_CTL WCD9335_REG(0x06, 0x0df) +#define WCD9335_HPH_DAC_LDO_POWERMODE_MASK BIT(0) +#define WCD9335_HPH_DAC_LDO_POWERMODE_LOWPOWER 0 +#define WCD9335_HPH_DAC_LDO_POWERMODE_UHQA BIT(0) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_MASK BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_ENABLE BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_DISABLE 0 + +#define WCD9335_EAR_CMBUFF WCD9335_REG(0x06, 0x0e2) +#define WCD9335_DIFF_LO_LO2_COMPANDER WCD9335_REG(0x06, 0x0ea) +#define WCD9335_DIFF_LO_LO1_COMPANDER WCD9335_REG(0x06, 0x0eb) +#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ WCD9335_REG(0x06, 0x0f1) +#define WCD9335_DIFF_LO_COM_PA_FREQ WCD9335_REG(0x06, 0x0f2) +#define WCD9335_SE_LO_LO3_GAIN WCD9335_REG(0x06, 0x0f8) +#define WCD9335_SE_LO_LO3_CTRL WCD9335_REG(0x06, 0x0f9) +#define WCD9335_SE_LO_LO4_GAIN WCD9335_REG(0x06, 0x0fa) + +/* Page-10 Registers */ +#define WCD9335_CDC_TX0_TX_PATH_CTL WCD9335_REG(0x0a, 0x031) +#define WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_TX_PATH_CTL(dec) WCD9335_REG(0xa, (0x31 + dec * 0x10)) +#define WCD9335_CDC_TX0_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x032) +#define WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK BIT(7) +#define WCD9335_CDC_TX_ADC_DMIC_SEL BIT(7) +#define WCD9335_CDC_TX_ADC_AMIC_SEL 0 +#define WCD9335_CDC_TX0_TX_VOL_CTL WCD9335_REG(0x0a, 0x034) +#define WCD9335_CDC_TX0_TX_PATH_SEC2 WCD9335_REG(0x0a, 0x039) +#define WCD9335_CDC_TX0_TX_PATH_SEC7 WCD9335_REG(0x0a, 0x03e) +#define WCD9335_CDC_TX1_TX_PATH_CTL WCD9335_REG(0x0a, 0x041) +#define WCD9335_CDC_TX1_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x042) +#define WCD9335_CDC_TX2_TX_PATH_CTL WCD9335_REG(0x0a, 0x051) +#define WCD9335_CDC_TX2_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x052) +#define WCD9335_CDC_TX2_TX_VOL_CTL WCD9335_REG(0x0a, 0x054) +#define WCD9335_CDC_TX3_TX_PATH_CTL WCD9335_REG(0x0a, 0x061) +#define WCD9335_CDC_TX3_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x062) +#define WCD9335_CDC_TX3_TX_VOL_CTL WCD9335_REG(0x0a, 0x064) +#define WCD9335_CDC_TX4_TX_PATH_CTL WCD9335_REG(0x0a, 0x071) +#define WCD9335_CDC_TX4_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x072) +#define WCD9335_CDC_TX4_TX_VOL_CTL WCD9335_REG(0x0a, 0x074) +#define WCD9335_CDC_TX5_TX_PATH_CTL WCD9335_REG(0x0a, 0x081) +#define WCD9335_CDC_TX5_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x082) +#define WCD9335_CDC_TX5_TX_VOL_CTL WCD9335_REG(0x0a, 0x084) +#define WCD9335_CDC_TX6_TX_PATH_CTL WCD9335_REG(0x0a, 0x091) +#define WCD9335_CDC_TX6_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x092) +#define WCD9335_CDC_TX6_TX_VOL_CTL WCD9335_REG(0x0a, 0x094) +#define WCD9335_CDC_TX7_TX_PATH_CTL WCD9335_REG(0x0a, 0x0a1) +#define WCD9335_CDC_TX7_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0a2) +#define WCD9335_CDC_TX7_TX_VOL_CTL WCD9335_REG(0x0a, 0x0a4) +#define WCD9335_CDC_TX8_TX_PATH_CTL WCD9335_REG(0x0a, 0x0b1) +#define WCD9335_CDC_TX8_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0b2) +#define WCD9335_CDC_TX8_TX_VOL_CTL WCD9335_REG(0x0a, 0x0b4) +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c3) +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c7) +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cb) +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cf) + +/* Page-11 Registers */ +#define WCD9335_PAGE11_PAGE_REGISTER WCD9335_REG(0x0b, 0x000) +#define WCD9335_CDC_COMPANDER1_CTL0 WCD9335_REG(0x0b, 0x001) +#define WCD9335_CDC_COMPANDER1_CTL(c) WCD9335_REG(0x0b, (0x001 + c * 0x8)) +#define WCD9335_CDC_COMPANDER_CLK_EN_MASK BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_ENABLE BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_DISABLE 0 +#define WCD9335_CDC_COMPANDER_SOFT_RST_MASK BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE 0 +#define WCD9335_CDC_COMPANDER_HALT_MASK BIT(2) +#define WCD9335_CDC_COMPANDER_HALT BIT(2) +#define WCD9335_CDC_COMPANDER_NOHALT 0 +#define WCD9335_CDC_COMPANDER7_CTL3 WCD9335_REG(0x0b, 0x034) +#define WCD9335_CDC_COMPANDER7_CTL7 WCD9335_REG(0x0b, 0x038) +#define WCD9335_CDC_COMPANDER8_CTL3 WCD9335_REG(0x0b, 0x03c) +#define WCD9335_CDC_COMPANDER8_CTL7 WCD9335_REG(0x0b, 0x040) +#define WCD9335_CDC_RX0_RX_PATH_CTL WCD9335_REG(0x0b, 0x041) +#define WCD9335_CDC_RX_PGA_MUTE_EN_MASK BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_ENABLE BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_DISABLE 0 +#define WCD9335_CDC_RX_CLK_EN_MASK BIT(5) +#define WCD9335_CDC_RX_CLK_ENABLE BIT(5) +#define WCD9335_CDC_RX_CLK_DISABLE 0 +#define WCD9335_CDC_RX_RESET_MASK BIT(6) +#define WCD9335_CDC_RX_RESET_ENABLE BIT(6) +#define WCD9335_CDC_RX_RESET_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CTL(rx) WCD9335_REG(0x0b, (0x041 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x042) +#define WCD9335_CDC_RX0_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x043) +#define WCD9335_CDC_RX0_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x044) +#define WCD9335_CDC_RX0_RX_VOL_CTL WCD9335_REG(0x0b, 0x045) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x046) +#define WCD9335_CDC_MIX_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_PATH_MIX_CTL(rx) WCD9335_REG(0x0b, (0x46 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x047) +#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x048) +#define WCD9335_CDC_RX0_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x049) +#define WCD9335_CDC_RX0_RX_PATH_SEC7 WCD9335_REG(0x0b, 0x050) +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 WCD9335_REG(0x0b, 0x051) +#define WCD9335_CDC_RX1_RX_PATH_CTL WCD9335_REG(0x0b, 0x055) +#define WCD9335_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x056) +#define WCD9335_CDC_RX1_RX_PATH_CFG(c) WCD9335_REG(0x0b, (0x056 + c * 0x14)) +#define WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_DISABLE 0 +#define WCD9335_CDC_RX1_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x058) +#define WCD9335_CDC_RX1_RX_VOL_CTL WCD9335_REG(0x0b, 0x059) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x05a) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x05b) +#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x05c) +#define WCD9335_CDC_RX1_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x05d) +#define WCD9335_CDC_RX1_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x060) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2 0x1 +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1 0 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK GENMASK(5, 2) +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500 0x10 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000 0 +#define WCD9335_CDC_RX2_RX_PATH_CTL WCD9335_REG(0x0b, 0x069) +#define WCD9335_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x06a) +#define WCD9335_CDC_RX2_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x06c) +#define WCD9335_CDC_RX2_RX_VOL_CTL WCD9335_REG(0x0b, 0x06d) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x06e) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x06f) +#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x070) +#define WCD9335_CDC_RX2_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x071) +#define WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX2_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x074) +#define WCD9335_CDC_RX3_RX_PATH_CTL WCD9335_REG(0x0b, 0x07d) +#define WCD9335_CDC_RX3_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x07e) +#define WCD9335_CDC_RX3_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x080) +#define WCD9335_CDC_RX3_RX_VOL_CTL WCD9335_REG(0x0b, 0x081) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x082) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x083) +#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x084) +#define WCD9335_CDC_RX4_RX_PATH_CTL WCD9335_REG(0x0b, 0x091) +#define WCD9335_CDC_RX4_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x092) +#define WCD9335_CDC_RX4_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x094) +#define WCD9335_CDC_RX4_RX_VOL_CTL WCD9335_REG(0x0b, 0x095) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x096) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x097) +#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x098) +#define WCD9335_CDC_RX5_RX_PATH_CTL WCD9335_REG(0x0b, 0x0a5) +#define WCD9335_CDC_RX5_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0a6) +#define WCD9335_CDC_RX5_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0a8) +#define WCD9335_CDC_RX5_RX_VOL_CTL WCD9335_REG(0x0b, 0x0a9) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0aa) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0ab) +#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0ac) +#define WCD9335_CDC_RX6_RX_PATH_CTL WCD9335_REG(0x0b, 0x0b9) +#define WCD9335_CDC_RX6_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ba) +#define WCD9335_CDC_RX6_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0bc) +#define WCD9335_CDC_RX6_RX_VOL_CTL WCD9335_REG(0x0b, 0x0bd) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0be) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0bf) +#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0c0) +#define WCD9335_CDC_RX7_RX_PATH_CTL WCD9335_REG(0x0b, 0x0cd) +#define WCD9335_CDC_RX7_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ce) +#define WCD9335_CDC_RX7_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0cf) +#define WCD9335_CDC_RX7_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0d0) +#define WCD9335_CDC_RX7_RX_VOL_CTL WCD9335_REG(0x0b, 0x0d1) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0d2) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0d3) +#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0d4) +#define WCD9335_CDC_RX8_RX_PATH_CTL WCD9335_REG(0x0b, 0x0e1) +#define WCD9335_CDC_RX8_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0e2) +#define WCD9335_CDC_RX8_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0e3) +#define WCD9335_CDC_RX8_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0e4) +#define WCD9335_CDC_RX8_RX_VOL_CTL WCD9335_REG(0x0b, 0x0e5) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0e6) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0e7) +#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0e8) + +/* Page-12 Registers */ +#define WCD9335_PAGE12_PAGE_REGISTER WCD9335_REG(0x0c, 0x000) +#define WCD9335_CDC_CLSH_K2_MSB WCD9335_REG(0x0c, 0x00a) +#define WCD9335_CDC_CLSH_K2_LSB WCD9335_REG(0x0c, 0x00b) +#define WCD9335_CDC_BOOST0_BOOST_CTL WCD9335_REG(0x0c, 0x01a) +#define WCD9335_CDC_BOOST0_BOOST_CFG1 WCD9335_REG(0x0c, 0x01b) +#define WCD9335_CDC_BOOST0_BOOST_CFG2 WCD9335_REG(0x0c, 0x01c) +#define WCD9335_CDC_BOOST1_BOOST_CTL WCD9335_REG(0x0c, 0x022) +#define WCD9335_CDC_BOOST1_BOOST_CFG1 WCD9335_REG(0x0c, 0x023) +#define WCD9335_CDC_BOOST1_BOOST_CFG2 WCD9335_REG(0x0c, 0x024) + +/* Page-13 Registers */ +#define WCD9335_PAGE13_PAGE_REGISTER WCD9335_REG(0x0d, 0x000) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 WCD9335_REG(0x0d, 0x001) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(i) WCD9335_REG(0xd, (0x1 + i * 0x2)) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 WCD9335_REG(0xd, 0x002) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(i) WCD9335_REG(0xd, (0x2 + i * 0x2)) + +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 WCD9335_REG(0x0d, 0x003) +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 WCD9335_REG(0x0d, 0x004) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 WCD9335_REG(0x0d, 0x005) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 WCD9335_REG(0x0d, 0x006) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 WCD9335_REG(0x0d, 0x007) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 WCD9335_REG(0x0d, 0x008) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 WCD9335_REG(0x0d, 0x009) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 WCD9335_REG(0x0d, 0x00a) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 WCD9335_REG(0x0d, 0x00b) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 WCD9335_REG(0x0d, 0x00c) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 WCD9335_REG(0x0d, 0x00d) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 WCD9335_REG(0x0d, 0x00e) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 WCD9335_REG(0x0d, 0x00f) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 WCD9335_REG(0x0d, 0x010) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 WCD9335_REG(0x0d, 0x011) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 WCD9335_REG(0x0d, 0x012) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 WCD9335_REG(0x0d, 0x01d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 WCD9335_REG(0x0d, 0x01e) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 WCD9335_REG(0x0d, 0x01f) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 WCD9335_REG(0x0d, 0x020) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 WCD9335_REG(0x0d, 0x021) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 WCD9335_REG(0x0d, 0x022) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 WCD9335_REG(0x0d, 0x023) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 WCD9335_REG(0x0d, 0x024) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 WCD9335_REG(0x0d, 0x025) +#define WCD9335_CDC_TX_INP_MUX_SEL_AMIC 0x1 +#define WCD9335_CDC_TX_INP_MUX_SEL_DMIC 0 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 WCD9335_REG(0x0d, 0x026) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 WCD9335_REG(0x0d, 0x027) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 WCD9335_REG(0x0d, 0x028) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 WCD9335_REG(0x0d, 0x029) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 WCD9335_REG(0x0d, 0x02b) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 WCD9335_REG(0x0d, 0x02c) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 WCD9335_REG(0x0d, 0x02d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 WCD9335_REG(0x0d, 0x02e) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 WCD9335_REG(0x0d, 0x03a) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 WCD9335_REG(0x0d, 0x03b) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 WCD9335_REG(0x0d, 0x03c) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 WCD9335_REG(0x0d, 0x03d) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0x0d, 0x041) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_DISABLE 0 +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL WCD9335_REG(0x0d, 0x042) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_DISABLE 0 +#define WCD9335_CDC_TOP_TOP_CFG1 WCD9335_REG(0x0d, 0x082) +#define WCD9335_MAX_REGISTER WCD9335_REG(0x80, 0x0FF) + +/* SLIMBUS Slave Registers */ +#define WCD9335_SLIM_PGD_PORT_INT_EN0 WCD9335_REG(0, 0x30) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0 WCD9335_REG(0, 0x34) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1 WCD9335_REG(0, 0x35) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0 WCD9335_REG(0, 0x36) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1 WCD9335_REG(0, 0x37) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 WCD9335_REG(0, 0x38) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1 WCD9335_REG(0, 0x39) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0 WCD9335_REG(0, 0x3A) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1 WCD9335_REG(0, 0x3B) +#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 WCD9335_REG(0, 0x60) +#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0 WCD9335_REG(0, 0x70) +#define WCD9335_SLIM_PGD_RX_PORT_CFG(p) WCD9335_REG(0, (0x30 + p)) +#define WCD9335_SLIM_PGD_PORT_CFG(p) WCD9335_REG(0, (0x40 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_CFG(p) WCD9335_REG(0, (0x50 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_SRC(p) WCD9335_REG(0, (0x60 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS(p) WCD9335_REG(0, (0x80 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x100 + 4 * p)) +/* ports range from 10-16 */ +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p) WCD9335_REG(0, (0x101 + 4 * p)) +#define WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x140 + 4 * p)) + +#define WCD9335_IRQ_SLIMBUS 0 +#define WCD9335_IRQ_MBHC_SW_DET 8 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_DET 9 +#define WCD9335_IRQ_MBHC_BUTTON_PRESS_DET 10 +#define WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET 11 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET 12 + +#define SLIM_MANF_ID_QCOM 0x217 +#define SLIM_PROD_CODE_WCD9335 0x1a0 + +#define WCD9335_VERSION_2_0 2 +#define WCD9335_MAX_SUPPLY 5 + +#endif /* __WCD9335_H__ */ From cc2e324d39b26d62599d056f5cb905a025b909a3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:48 +0000 Subject: [PATCH 213/461] ASoC: wcd9335: add CLASS-H Controller support CLASS-H controller/Amplifier is common accorss Qualcomm WCD codec series. This patchset adds basic CLASS-H controller apis for WCD codecs after wcd9335 to use. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/wcd-clsh-v2.c | 576 +++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd-clsh-v2.h | 49 +++ sound/soc/codecs/wcd9335.c | 10 + 4 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/wcd-clsh-v2.c create mode 100644 sound/soc/codecs/wcd-clsh-v2.h diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 342d057cd7fc..4cf29e3dbff6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -201,7 +201,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o -snd-soc-wcd9335-objs := wcd9335.o +snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c new file mode 100644 index 000000000000..1bd70c5a7b63 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#include +#include +#include +#include +#include "wcd9335.h" +#include "wcd-clsh-v2.h" + +struct wcd_clsh_ctrl { + int state; + int mode; + int flyback_users; + int buck_users; + int clsh_users; + int codec_version; + struct snd_soc_component *comp; +}; + +/* Class-H registers for codecs from and above WCD9335 */ +#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 +#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) +#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) +#define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) +#define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) +#define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) +#define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) +#define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 +#define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 +#define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 +#define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 +#define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 +#define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 +#define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) +#define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) +#define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 +#define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 +#define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) +#define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(0, 3) +#define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) +#define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) +#define WCD9XXX_HPH_CONST_SEL_BYPASS 0 +#define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 +#define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 +#define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) +#define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) +#define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) +#define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) +#define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 +#define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) +#define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) +#define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 + +#define CLSH_REQ_ENABLE true +#define CLSH_REQ_DISABLE false +#define WCD_USLEEP_RANGE 50 + +enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_0P2DB, + DAC_GAIN_0P4DB, + DAC_GAIN_0P6DB, + DAC_GAIN_0P8DB, + DAC_GAIN_M0P2DB, + DAC_GAIN_M0P4DB, + DAC_GAIN_M0P6DB, +}; + +static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + if ((enable && ++ctrl->clsh_users == 1) || + (!enable && --ctrl->clsh_users == 0)) + snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC, + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, + enable); + if (ctrl->clsh_users < 0) + ctrl->clsh_users = 0; +} + +static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) +{ + return snd_soc_component_read32(comp, WCD9XXX_A_CDC_CLSH_CRC) & + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; +} + +static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); +} + +static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); +} + +static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + /* enable/disable buck */ + if ((enable && (++ctrl->buck_users == 1)) || + (!enable && (--ctrl->buck_users == 0))) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + /* enable/disable flyback */ + if ((enable && (++ctrl->flyback_users == 1)) || + (!enable && (--ctrl->flyback_users == 0))) { + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + } + /* + * 500us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + int val = 0; + + switch (mode) { + case CLS_H_NORMAL: + case CLS_AB: + val = WCD9XXX_HPH_CONST_SEL_BYPASS; + break; + case CLS_H_HIFI: + val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; + break; + case CLS_H_LP: + val = WCD9XXX_HPH_CONST_SEL_LP_PATH; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); +} + +static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, + int mode) +{ + int val = 0, gain = 0, res_val; + int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; + switch (mode) { + case CLS_H_NORMAL: + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_AB: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_HIFI: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; + gain = DAC_GAIN_M0P2DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_LP: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, + WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2, + WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, + res_val); + if (mode != CLS_H_LP) + snd_soc_component_update_bits(comp, + WCD9XXX_HPH_REFBUFF_UHQA_CTL, + WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, + gain); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1, + WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, + ipeak); +} + +static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, + int mode) +{ + + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, + int mode) +{ + if (mode == CLS_AB) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); +} + +static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_AB) { + dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* buck and flyback set to default mode and disable */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* set buck and flyback to Default Mode */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_H_NORMAL) { + dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + } +} + +static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + switch (req_state) { + case WCD_CLSH_STATE_EAR: + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHL: + wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHR: + wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); + break; + break; + case WCD_CLSH_STATE_LO: + wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + break; + default: + break; + } + + return 0; +} + +/* + * Function: wcd_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool wcd_clsh_is_state_valid(int state) +{ + switch (state) { + case WCD_CLSH_STATE_IDLE: + case WCD_CLSH_STATE_EAR: + case WCD_CLSH_STATE_HPHL: + case WCD_CLSH_STATE_HPHR: + case WCD_CLSH_STATE_LO: + return true; + default: + return false; + }; +} + +/* + * Function: wcd_clsh_fsm + * Params: ctrl, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. ctrl will contain current + * class h state information + */ +int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event clsh_event, + int nstate, + enum wcd_clsh_mode mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (nstate == ctrl->state) + return 0; + + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; + } + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); + break; + case WCD_CLSH_EVENT_POST_PA: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); + break; + }; + + ctrl->state = nstate; + ctrl->mode = mode; + + return 0; +} + +int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) +{ + return ctrl->state; +} + +struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, + int version) +{ + struct wcd_clsh_ctrl *ctrl; + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + ctrl->state = WCD_CLSH_STATE_IDLE; + ctrl->comp = comp; + + return ctrl; +} + +void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) +{ + kfree(ctrl); +} diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h new file mode 100644 index 000000000000..a902f9893467 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _WCD_CLSH_V2_H_ +#define _WCD_CLSH_V2_H_ +#include + +enum wcd_clsh_event { + WCD_CLSH_EVENT_PRE_DAC = 1, + WCD_CLSH_EVENT_POST_PA, +}; + +/* + * Basic states for Class H state machine. + * represented as a bit mask within a u8 data type + * bit 0: EAR mode + * bit 1: HPH Left mode + * bit 2: HPH Right mode + * bit 3: Lineout mode + */ +#define WCD_CLSH_STATE_IDLE 0 +#define WCD_CLSH_STATE_EAR BIT(0) +#define WCD_CLSH_STATE_HPHL BIT(1) +#define WCD_CLSH_STATE_HPHR BIT(2) +#define WCD_CLSH_STATE_LO BIT(3) +#define WCD_CLSH_STATE_MAX 4 +#define NUM_CLSH_STATES_V2 BIT(WCD_CLSH_STATE_MAX) + +enum wcd_clsh_mode { + CLS_H_NORMAL = 0, /* Class-H Default */ + CLS_H_HIFI, /* Class-H HiFi */ + CLS_H_LP, /* Class-H Low Power */ + CLS_AB, /* Class-AB */ + CLS_H_LOHIFI, /* LoHIFI */ + CLS_NONE, /* None of the above modes */ +}; + +struct wcd_clsh_ctrl; + +extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( + struct snd_soc_component *component, + int version); +extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event event, + int state, + enum wcd_clsh_mode mode); + +#endif /* _WCD_CLSH_V2_H_ */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index d6b690af7f09..3fdf4d8f310f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -22,6 +22,7 @@ #include #include #include "wcd9335.h" +#include "wcd-clsh-v2.h" #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -181,6 +182,7 @@ struct wcd9335_codec { int sido_ccl_cnt; enum wcd_clock_type clk_type; + struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; int intr1; int reset_gpio; @@ -1109,6 +1111,13 @@ static int wcd9335_codec_probe(struct snd_soc_component *component) int i; snd_soc_component_init_regmap(component, wcd->regmap); + /* Class-H Init*/ + wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version); + if (IS_ERR(wcd->clsh_ctrl)) + return PTR_ERR(wcd->clsh_ctrl); + + /* Default HPH Mode to Class-H HiFi */ + wcd->hph_mode = CLS_H_HIFI; wcd->component = component; wcd9335_codec_init(component); @@ -1123,6 +1132,7 @@ static void wcd9335_codec_remove(struct snd_soc_component *comp) { struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + wcd_clsh_ctrl_free(wcd->clsh_ctrl); free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); } From 8c4f021d806ac52902856d7cbd148a4b24a88f59 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:49 +0000 Subject: [PATCH 214/461] ASoC: wcd9335: add basic controls This patch adds basic controls found in wcd9335 codec. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 325 +++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 3fdf4d8f310f..66d634764d28 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -105,6 +105,18 @@ enum { NUM_CODEC_DAIS, }; +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE */ + COMPANDER_6, /* LO4_SE */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + enum { INTn_2_INP_SEL_ZERO = 0, INTn_2_INP_SEL_RX0, @@ -184,6 +196,8 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int comp_enabled[COMPANDER_MAX]; + int intr1; int reset_gpio; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; @@ -301,6 +315,111 @@ static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = { {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, }; +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const char * const rx_hph_mode_mux_text[] = { + "Class H Invalid", "Class-H Hi-Fi", "Class-H Low Power", "Class-AB", + "Class-H Hi-Fi Low Power" +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); +static const DECLARE_TLV_DB_SCALE(ear_pa_gain, 0, 150, 0); + +static const struct soc_enum cf_dec0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_int0_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int1_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int2_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int3_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int4_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int5_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int6_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int7_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int8_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -697,6 +816,210 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { }, }; +static int wcd9335_get_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + int comp = ((struct soc_mixer_control *)kc->private_value)->shift; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.integer.value[0] = wcd->comp_enabled[comp]; + return 0; +} + +static int wcd9335_set_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp = ((struct soc_mixer_control *) kc->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + int sel; + + wcd->comp_enabled[comp] = value; + sel = value ? WCD9335_HPH_GAIN_SRC_SEL_COMPANDER : + WCD9335_HPH_GAIN_SRC_SEL_REGISTER; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_5: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_6: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + default: + break; + }; + + return 0; +} + +static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.enumerated.item[0] = wcd->hph_mode; + + return 0; +} + +static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + if (mode_val == 0) { + dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); + mode_val = CLS_H_HIFI; + } + wcd->hph_mode = mode_val; + + return 0; +} + +static const struct snd_kcontrol_new wcd9335_snd_controls[] = { + /* -84dB min - 40dB max */ + SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", + WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", + WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", + WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", + WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", + WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", + WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", + WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", + WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", + WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum), + SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum), + SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum), + SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd9335_rx_hph_mode_get, wcd9335_rx_hph_mode_put), + + /* Gain Controls */ + SOC_SINGLE_TLV("EAR PA Volume", WCD9335_ANA_EAR, 4, 4, 1, + ear_pa_gain), + SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1, + line_gain), + + SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0, + analog_gain), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), +}; + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1162,6 +1485,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .probe = wcd9335_codec_probe, .remove = wcd9335_codec_remove, .set_sysclk = wcd9335_codec_set_sysclk, + .controls = wcd9335_snd_controls, + .num_controls = ARRAY_SIZE(wcd9335_snd_controls), }; static int wcd9335_probe(struct wcd9335_codec *wcd) From 354461486f66e4311d9412c53205d773aac85b78 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:50 +0000 Subject: [PATCH 215/461] ASoC: wcd9335: add playback dapm widgets This patch adds required dapm widgets for playback. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 1795 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1795 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 66d634764d28..aa430cf27b19 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -147,6 +147,18 @@ enum { }; +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3, + INTERP_LO4, + INTERP_SPKR1, + INTERP_SPKR2, +}; + enum wcd_clock_type { WCD_CLK_OFF, WCD_CLK_RCO, @@ -196,11 +208,19 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int prim_int_users[WCD9335_NUM_INTERPOLATORS]; + int comp_enabled[COMPANDER_MAX]; int intr1; int reset_gpio; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; + + unsigned int rx_port_value; + int hph_l_gain; + int hph_r_gain; + u32 rx_bias_count; + }; struct wcd9335_irq { @@ -325,11 +345,70 @@ static const char * const rx_cf_text[] = { "CF_NEG_3DB_0P48HZ" }; +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_interp_mux_text[] = { + "ZERO", "RX INT0 MIX2", +}; + +static const char * const rx_int1_interp_mux_text[] = { + "ZERO", "RX INT1 MIX2", +}; + +static const char * const rx_int2_interp_mux_text[] = { + "ZERO", "RX INT2 MIX2", +}; + +static const char * const rx_int3_interp_mux_text[] = { + "ZERO", "RX INT3 MIX2", +}; + +static const char * const rx_int4_interp_mux_text[] = { + "ZERO", "RX INT4 MIX2", +}; + +static const char * const rx_int5_interp_mux_text[] = { + "ZERO", "RX INT5 MIX2", +}; + +static const char * const rx_int6_interp_mux_text[] = { + "ZERO", "RX INT6 MIX2", +}; + +static const char * const rx_int7_interp_mux_text[] = { + "ZERO", "RX INT7 MIX2", +}; + +static const char * const rx_int8_interp_mux_text[] = { + "ZERO", "RX INT8 SEC MIX" +}; + static const char * const rx_hph_mode_mux_text[] = { "Class H Invalid", "Class-H Hi-Fi", "Class-H Low Power", "Class-AB", "Class-H Hi-Fi Low Power" }; +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -420,6 +499,455 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text); +static const struct soc_enum slim_rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text); + +static const struct soc_enum rx_int0_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int1_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int2_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int3_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int4_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int5_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int6_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int7_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int8_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int0_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int1_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int2_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int0_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2, + rx_int0_interp_mux_text); + +static const struct soc_enum rx_int1_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2, + rx_int1_interp_mux_text); + +static const struct soc_enum rx_int2_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2, + rx_int2_interp_mux_text); + +static const struct soc_enum rx_int3_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2, + rx_int3_interp_mux_text); + +static const struct soc_enum rx_int4_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2, + rx_int4_interp_mux_text); + +static const struct soc_enum rx_int5_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2, + rx_int5_interp_mux_text); + +static const struct soc_enum rx_int6_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2, + rx_int6_interp_mux_text); + +static const struct soc_enum rx_int7_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2, + rx_int7_interp_mux_text); + +static const struct soc_enum rx_int8_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, + rx_int8_interp_mux_text); + +static const struct snd_kcontrol_new rx_int0_2_mux = + SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int1_2_mux = + SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int2_2_mux = + SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int3_2_mux = + SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int4_2_mux = + SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int5_2_mux = + SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int6_2_mux = + SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int7_2_mux = + SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int8_2_mux = + SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int0_interp_mux = + SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int1_interp_mux = + SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int2_interp_mux = + SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int3_interp_mux = + SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int4_interp_mux = + SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int5_interp_mux = + SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int6_interp_mux = + SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int7_interp_mux = + SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int8_interp_mux = + SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); + +static int slim_rx_mux_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.enumerated.item[0] = wcd->rx_port_value; + + return 0; +} + +static int slim_rx_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 port_id = w->shift; + + wcd->rx_port_value = ucontrol->value.enumerated.item[0]; + + switch (wcd->rx_port_value) { + case 0: + list_del_init(&wcd->rx_chs[port_id].list); + break; + case 1: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF1_PB].slim_ch_list); + break; + case 2: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF2_PB].slim_ch_list); + break; + case 3: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF3_PB].slim_ch_list); + break; + case 4: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF4_PB].slim_ch_list); + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value); + goto err; + } + + snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value, + e, update); + + return 0; +err: + return -EINVAL; +} + +static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { + SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), +}; + +static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_component *component; + int reg, val; + + component = snd_soc_dapm_kcontrol_component(kc); + val = ucontrol->value.enumerated.item[0]; + + if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0) + reg = WCD9335_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0) + reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0) + reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + else + return -EINVAL; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK, + val ? WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN : 0); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + +static const struct snd_kcontrol_new rx_int0_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int1_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int2_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1020,6 +1548,986 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, + struct snd_soc_component *component) +{ + int port_num = 0; + unsigned short reg = 0; + unsigned int val = 0; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + + list_for_each_entry(ch, &dai->slim_ch_list, list) { + if (ch->port >= WCD9335_RX_START) { + port_num = ch->port - WCD9335_RX_START; + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + (port_num / 8); + } else { + port_num = ch->port; + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + } + + regmap_read(wcd->if_regmap, reg, &val); + if (!(val & BIT(port_num % 8))) + regmap_write(wcd->if_regmap, reg, + val | BIT(port_num % 8)); + } +} + +static int wcd9335_codec_enable_slim(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + struct wcd_slim_codec_dai_data *dai = &wcd->dai[w->shift]; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + wcd9335_codec_enable_int_port(dai, comp); + break; + case SND_SOC_DAPM_POST_PMD: + kfree(dai->sconfig.chs); + + break; + } + + return ret; +} + +static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + switch (w->reg) { + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL; + break; + default: + dev_err(comp->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + }; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + break; + }; + + return 0; +} + +static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + + switch (reg) { + case WCD9335_CDC_RX0_RX_PATH_CTL: + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + *ind = 0; + break; + case WCD9335_CDC_RX1_RX_PATH_CTL: + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + *ind = 1; + break; + case WCD9335_CDC_RX2_RX_PATH_CTL: + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL; + *ind = 2; + break; + case WCD9335_CDC_RX3_RX_PATH_CTL: + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + *ind = 3; + break; + case WCD9335_CDC_RX4_RX_PATH_CTL: + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + *ind = 4; + break; + case WCD9335_CDC_RX5_RX_PATH_CTL: + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + *ind = 5; + break; + case WCD9335_CDC_RX6_RX_PATH_CTL: + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + *ind = 6; + break; + case WCD9335_CDC_RX7_RX_PATH_CTL: + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL; + *ind = 7; + break; + case WCD9335_CDC_RX8_RX_PATH_CTL: + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL; + *ind = 8; + break; + }; + + return prim_int_reg; +} + +static void wcd9335_codec_hd2_control(struct snd_soc_component *component, + u16 prim_int_reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2); + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000); + } +} + +static int wcd9335_codec_enable_prim_interpolator( + struct snd_soc_component *comp, + u16 reg, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + u16 ind = 0; + int prim_int_reg = wcd9335_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->prim_int_users[ind]++; + if (wcd->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_ENABLE); + } + + if ((reg != prim_int_reg) && + ((snd_soc_component_read32(comp, prim_int_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK)) + snd_soc_component_update_bits(comp, reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + wcd->prim_int_users[ind]--; + if (wcd->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_DISABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_ENABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_DISABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + } + break; + }; + + return 0; +} + +static int wcd9335_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + if (!wcd->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL(comp); + rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG(comp); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_ENABLE); + /* Reset comander */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + /* Enables DRE in this path */ + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_HALT); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE); + + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_NOHALT); + } + + return 0; +} + +static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + if (!(strcmp(w->name, "RX INT0 INTERP"))) { + reg = WCD9335_CDC_RX0_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT1 INTERP"))) { + reg = WCD9335_CDC_RX1_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT2 INTERP"))) { + reg = WCD9335_CDC_RX2_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT3 INTERP"))) { + reg = WCD9335_CDC_RX3_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT4 INTERP"))) { + reg = WCD9335_CDC_RX4_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT5 INTERP"))) { + reg = WCD9335_CDC_RX5_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT6 INTERP"))) { + reg = WCD9335_CDC_RX6_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT7 INTERP"))) { + reg = WCD9335_CDC_RX7_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT8 INTERP"))) { + reg = WCD9335_CDC_RX8_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL; + } else { + dev_err(comp->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + wcd9335_config_compander(comp, w->shift, event); + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_config_compander(comp, w->shift, event); + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + }; + + return 0; +} + +static void wcd9335_codec_hph_mode_gain_opt(struct snd_soc_component *component, + u8 gain) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u8 hph_l_en, hph_r_en; + u8 l_val, r_val; + u8 hph_pa_status; + bool is_hphl_pa, is_hphr_pa; + + hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH); + is_hphl_pa = hph_pa_status >> 7; + is_hphr_pa = (hph_pa_status & 0x40) >> 6; + + hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN); + hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN); + + l_val = (hph_l_en & 0xC0) | 0x20 | gain; + r_val = (hph_r_en & 0xC0) | 0x20 | gain; + + /* + * Set HPH_L & HPH_R gain source selection to REGISTER + * for better click and pop only if corresponding PAs are + * not enabled. Also cache the values of the HPHL/R + * PA gains to be applied after PAs are enabled + */ + if ((l_val != hph_l_en) && !is_hphl_pa) { + snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val); + wcd->hph_l_gain = hph_l_en & 0x1F; + } + + if ((r_val != hph_r_en) && !is_hphr_pa) { + snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val); + wcd->hph_r_gain = hph_r_en & 0x1F; + } +} + +static void wcd9335_codec_hph_lohifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x06); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0xF0, 0x40); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0x8A); + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x0A); + } +} + +static void wcd9335_codec_hph_lp_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x10); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x0F, 0x01); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0xF0, 0x10); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDAC_LDO, + 0x88); + snd_soc_component_write(comp, WCD9335_HPH_RDAC_LDO_CTL, + 0x33); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_update_bits(comp, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + snd_soc_component_update_bits(comp, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + } +} + +static void wcd9335_codec_hph_hifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + } +} + +static void wcd9335_codec_hph_mode_config(struct snd_soc_component *component, + int event, int mode) +{ + switch (mode) { + case CLS_H_LP: + wcd9335_codec_hph_lp_config(component, event); + break; + case CLS_H_LOHIFI: + wcd9335_codec_hph_lohifi_config(component, event); + break; + case CLS_H_HIFI: + wcd9335_codec_hph_hifi_config(component, event); + break; + } +} + +static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_SEC0) & 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "Incorrect DEM Input\n"); + return -EINVAL; + } + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_PRE_PMD: + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHR)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, CLS_AB); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, CLS_AB); + break; + } + + return 0; +} + +static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + break; + }; + + return ret; +} + +static void wcd9335_codec_hph_post_pa_config(struct wcd9335_codec *wcd, + int mode, int event) +{ + u8 scale_val = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (mode) { + case CLS_H_HIFI: + scale_val = 0x3; + break; + case CLS_H_LOHIFI: + scale_val = 0x1; + break; + } + break; + case SND_SOC_DAPM_PRE_PMD: + scale_val = 0x6; + break; + } + + if (scale_val) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + scale_val << 1); + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (wcd->comp_enabled[COMPANDER_1] || + wcd->comp_enabled[COMPANDER_2]) { + /* GAIN Source Selection */ + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE); + } + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_l_gain); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_r_gain); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN); +} + +static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_SEC0) & + WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "DEM Input not set correctly, hph_mode: %d\n", + hph_mode); + return -EINVAL; + } + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHL)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int vol_reg = 0, mix_vol_reg = 0; + int ret = 0; + + if (w->reg == WCD9335_ANA_LO_1_2) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL; + } + } else if (w->reg == WCD9335_ANA_LO_3_4) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL; + } + } else { + dev_err(comp->dev, "Error enabling lineout PA\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, mix_vol_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, mix_vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static void wcd9335_codec_init_flyback(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); +} + +static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->rx_bias_count++; + if (wcd->rx_bias_count == 1) { + wcd9335_codec_init_flyback(comp); + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_ENABLE); + } + break; + case SND_SOC_DAPM_POST_PMD: + wcd->rx_bias_count--; + if (!wcd->rx_bias_count) + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_DISABLE); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + break; + }; + + return ret; +} + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1362,6 +2870,291 @@ static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, return 0; } +static int wcd9335_codec_enable_mclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return _wcd9335_codec_enable_mclk(comp, true); + case SND_SOC_DAPM_POST_PMD: + return _wcd9335_codec_enable_mclk(comp, false); + } + + return 0; +} + +static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { + /* TODO SPK1 & SPK2 OUT*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("LINEOUT3"), + SND_SOC_DAPM_OUTPUT("LINEOUT4"), + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD9335_RX0, 0, + &slim_rx_mux[WCD9335_RX0]), + SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD9335_RX1, 0, + &slim_rx_mux[WCD9335_RX1]), + SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD9335_RX2, 0, + &slim_rx_mux[WCD9335_RX2]), + SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD9335_RX3, 0, + &slim_rx_mux[WCD9335_RX3]), + SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD9335_RX4, 0, + &slim_rx_mux[WCD9335_RX4]), + SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD9335_RX5, 0, + &slim_rx_mux[WCD9335_RX5]), + SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD9335_RX6, 0, + &slim_rx_mux[WCD9335_RX6]), + SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD9335_RX7, 0, + &slim_rx_mux[WCD9335_RX7]), + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + 5, 0, &rx_int0_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 5, 0, &rx_int1_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 5, 0, &rx_int2_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL, + 5, 0, &rx_int3_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL, + 5, 0, &rx_int4_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL, + 5, 0, &rx_int5_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL, + 5, 0, &rx_int6_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL, + 5, 0, &rx_int7_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL, + 5, 0, &rx_int8_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int0_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int1_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int2_dem_inp_mux), + + SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM, + INTERP_EAR, 0, &rx_int0_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM, + INTERP_HPHL, 0, &rx_int1_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM, + INTERP_HPHR, 0, &rx_int2_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM, + INTERP_LO1, 0, &rx_int3_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM, + INTERP_LO2, 0, &rx_int4_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM, + INTERP_LO3, 0, &rx_int5_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM, + INTERP_LO4, 0, &rx_int6_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM, + INTERP_SPKR1, 0, &rx_int7_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM, + INTERP_SPKR2, 0, &rx_int8_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD9335_ANA_HPH, + 5, 0, wcd9335_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD9335_ANA_HPH, + 4, 0, wcd9335_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0, + wcd9335_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0, + wcd9335_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0, + wcd9335_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + +}; + static void wcd9335_enable_sido_buck(struct snd_soc_component *component) { struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); @@ -1487,6 +3280,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .set_sysclk = wcd9335_codec_set_sysclk, .controls = wcd9335_snd_controls, .num_controls = ARRAY_SIZE(wcd9335_snd_controls), + .dapm_widgets = wcd9335_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), }; static int wcd9335_probe(struct wcd9335_codec *wcd) From 6ccc25f6696cb603ead89b797825d305c7b27798 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:51 +0000 Subject: [PATCH 216/461] ASoC: wcd9335: add capture dapm widgets This patch adds required dapm widgets for capture path. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 1448 +++++++++++++++++++++++++++++++++++- 1 file changed, 1447 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index aa430cf27b19..887352398f70 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -60,10 +60,43 @@ #define WCD9335_NUM_INTERPOLATORS 9 #define WCD9335_RX_START 16 #define WCD9335_SLIM_CH_START 128 +#define WCD9335_MAX_MICBIAS 4 +#define WCD9335_MAX_VALID_ADC_MUX 13 +#define WCD9335_INVALID_ADC_MUX 9 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 +#define WCD9335_DMIC_CLK_DIV_2 0x0 +#define WCD9335_DMIC_CLK_DIV_3 0x1 +#define WCD9335_DMIC_CLK_DIV_4 0x2 +#define WCD9335_DMIC_CLK_DIV_6 0x3 +#define WCD9335_DMIC_CLK_DIV_8 0x4 +#define WCD9335_DMIC_CLK_DIV_16 0x5 +#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02 +#define WCD9335_AMIC_PWR_LEVEL_LP 0 +#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD9335_AMIC_PWR_LEVEL_HP 2 +#define WCD9335_AMIC_PWR_LVL_MASK 0x60 +#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD9335_DEC_PWR_LVL_MASK 0x06 +#define WCD9335_DEC_PWR_LVL_LP 0x02 +#define WCD9335_DEC_PWR_LVL_HP 0x04 +#define WCD9335_DEC_PWR_LVL_DF 0x00 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 #define WCD9335_SLIM_RX_CH(p) \ {.port = p + WCD9335_RX_START, .shift = p,} +#define WCD9335_SLIM_TX_CH(p) \ + {.port = p, .shift = p,} + /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) @@ -84,6 +117,26 @@ enum { WCD9335_RX_MAX, }; +enum { + WCD9335_TX0 = 0, + WCD9335_TX1, + WCD9335_TX2, + WCD9335_TX3, + WCD9335_TX4, + WCD9335_TX5, + WCD9335_TX6, + WCD9335_TX7, + WCD9335_TX8, + WCD9335_TX9, + WCD9335_TX10, + WCD9335_TX11, + WCD9335_TX12, + WCD9335_TX13, + WCD9335_TX14, + WCD9335_TX15, + WCD9335_TX_MAX, +}; + enum { SIDO_SOURCE_INTERNAL = 0, SIDO_SOURCE_RCO_BG, @@ -165,6 +218,20 @@ enum wcd_clock_type { WCD_CLK_MCLK, }; +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + struct wcd9335_slim_ch { u32 ch_num; u16 port; @@ -192,7 +259,9 @@ struct wcd9335_codec { struct regmap_irq_chip_data *irq_data; struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + struct wcd9335_slim_ch tx_chs[WCD9335_TX_MAX]; u32 num_rx_port; + u32 num_tx_port; int sido_input_src; enum wcd9335_sido_voltage sido_voltage; @@ -217,10 +286,22 @@ struct wcd9335_codec { struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; unsigned int rx_port_value; + unsigned int tx_port_value; int hph_l_gain; int hph_r_gain; u32 rx_bias_count; + /*TX*/ + int micb_ref[WCD9335_MAX_MICBIAS]; + int pullup_ref[WCD9335_MAX_MICBIAS]; + + int dmic_0_1_clk_cnt; + int dmic_2_3_clk_cnt; + int dmic_4_5_clk_cnt; + int dmic_sample_rate; + int mad_dmic_sample_rate; + + int native_clk_users; }; struct wcd9335_irq { @@ -229,6 +310,25 @@ struct wcd9335_irq { char *name; }; +static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = { + WCD9335_SLIM_TX_CH(0), + WCD9335_SLIM_TX_CH(1), + WCD9335_SLIM_TX_CH(2), + WCD9335_SLIM_TX_CH(3), + WCD9335_SLIM_TX_CH(4), + WCD9335_SLIM_TX_CH(5), + WCD9335_SLIM_TX_CH(6), + WCD9335_SLIM_TX_CH(7), + WCD9335_SLIM_TX_CH(8), + WCD9335_SLIM_TX_CH(9), + WCD9335_SLIM_TX_CH(10), + WCD9335_SLIM_TX_CH(11), + WCD9335_SLIM_TX_CH(12), + WCD9335_SLIM_TX_CH(13), + WCD9335_SLIM_TX_CH(14), + WCD9335_SLIM_TX_CH(15), +}; + static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { WCD9335_SLIM_RX_CH(0), /* 16 */ WCD9335_SLIM_RX_CH(1), /* 17 */ @@ -409,6 +509,59 @@ static const char *const slim_rx_mux_text[] = { "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", }; +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", + "SMIC0", "SMIC1", "SMIC2", "SMIC3" +}; + +static const char * const dmic_mux_alt_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6" +}; + +static const char * const sb_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; + +static const char * const sb_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; + +static const char * const sb_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; + +static const char * const sb_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; + +static const char * const sb_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; + +static const char * const sb_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; + +static const char * const sb_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; + +static const char * const sb_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; + +static const char * const sb_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -697,6 +850,150 @@ static const struct soc_enum rx_int8_interp_mux_enum = SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, rx_int8_interp_mux_text); +static const struct soc_enum tx_adc_mux0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux3_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux4_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux5_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux6_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux7_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux8_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_dmic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_amic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum sb_tx0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4, + sb_tx0_mux_text); + +static const struct soc_enum sb_tx1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4, + sb_tx1_mux_text); + +static const struct soc_enum sb_tx2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4, + sb_tx2_mux_text); + +static const struct soc_enum sb_tx3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4, + sb_tx3_mux_text); + +static const struct soc_enum sb_tx4_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4, + sb_tx4_mux_text); + +static const struct soc_enum sb_tx5_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4, + sb_tx5_mux_text); + +static const struct soc_enum sb_tx6_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4, + sb_tx6_mux_text); + +static const struct soc_enum sb_tx7_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4, + sb_tx7_mux_text); + +static const struct soc_enum sb_tx8_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4, + sb_tx8_mux_text); + static const struct snd_kcontrol_new rx_int0_2_mux = SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); @@ -832,6 +1129,87 @@ static const struct snd_kcontrol_new rx_int7_interp_mux = static const struct snd_kcontrol_new rx_int8_interp_mux = SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); +static const struct snd_kcontrol_new tx_dmic_mux0 = + SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum); + +static const struct snd_kcontrol_new tx_dmic_mux1 = + SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum); + +static const struct snd_kcontrol_new tx_dmic_mux2 = + SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum); + +static const struct snd_kcontrol_new tx_dmic_mux3 = + SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum); + +static const struct snd_kcontrol_new tx_dmic_mux4 = + SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum); + +static const struct snd_kcontrol_new tx_dmic_mux5 = + SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum); + +static const struct snd_kcontrol_new tx_dmic_mux6 = + SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum); + +static const struct snd_kcontrol_new tx_dmic_mux7 = + SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum); + +static const struct snd_kcontrol_new tx_dmic_mux8 = + SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum); + +static const struct snd_kcontrol_new tx_amic_mux0 = + SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum); + +static const struct snd_kcontrol_new tx_amic_mux1 = + SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum); + +static const struct snd_kcontrol_new tx_amic_mux2 = + SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum); + +static const struct snd_kcontrol_new tx_amic_mux3 = + SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum); + +static const struct snd_kcontrol_new tx_amic_mux4 = + SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum); + +static const struct snd_kcontrol_new tx_amic_mux5 = + SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum); + +static const struct snd_kcontrol_new tx_amic_mux6 = + SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum); + +static const struct snd_kcontrol_new tx_amic_mux7 = + SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum); + +static const struct snd_kcontrol_new tx_amic_mux8 = + SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum); + +static const struct snd_kcontrol_new sb_tx0_mux = + SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum); + +static const struct snd_kcontrol_new sb_tx1_mux = + SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum); + +static const struct snd_kcontrol_new sb_tx2_mux = + SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum); + +static const struct snd_kcontrol_new sb_tx3_mux = + SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum); + +static const struct snd_kcontrol_new sb_tx4_mux = + SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum); + +static const struct snd_kcontrol_new sb_tx5_mux = + SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum); + +static const struct snd_kcontrol_new sb_tx6_mux = + SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum); + +static const struct snd_kcontrol_new sb_tx7_mux = + SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum); + +static const struct snd_kcontrol_new sb_tx8_mux = + SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum); + static int slim_rx_mux_get(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -887,6 +1265,55 @@ err: return -EINVAL; } +static int slim_tx_mixer_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.integer.value[0] = wcd->tx_port_value; + + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(widget->dapm->dev); + struct snd_soc_dapm_update *update = NULL; + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kc->private_value; + int enable = ucontrol->value.integer.value[0]; + int dai_id = widget->shift; + int port_id = mixer->shift; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value |= BIT(port_id); + list_add_tail(&wcd->tx_chs[port_id].list, + &wcd->dai[dai_id].slim_ch_list); + } else if (!enable && (wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value &= ~BIT(port_id); + list_del_init(&wcd->tx_chs[port_id].list); + } + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", dai_id); + return -EINVAL; + } + + snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update); + + return 0; +} + static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, slim_rx_mux_get, slim_rx_mux_put), @@ -906,6 +1333,136 @@ static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { slim_rx_mux_get, slim_rx_mux_put), }; +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static int wcd9335_put_dec_enum(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + unsigned int val, reg, sel; + + val = ucontrol->value.enumerated.item[0]; + + switch (e->reg) { + case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + reg = WCD9335_CDC_TX0_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + reg = WCD9335_CDC_TX1_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + reg = WCD9335_CDC_TX2_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + reg = WCD9335_CDC_TX3_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + reg = WCD9335_CDC_TX4_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + reg = WCD9335_CDC_TX5_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + reg = WCD9335_CDC_TX6_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + reg = WCD9335_CDC_TX7_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0: + reg = WCD9335_CDC_TX8_TX_PATH_CFG0; + break; + default: + return -EINVAL; + } + + /* AMIC: 0, DMIC: 1 */ + sel = val ? WCD9335_CDC_TX_ADC_AMIC_SEL : WCD9335_CDC_TX_ADC_DMIC_SEL; + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK, + sel); + + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -948,6 +1505,51 @@ static const struct snd_kcontrol_new rx_int2_dem_inp_mux = snd_soc_dapm_get_enum_double, wcd9335_int_dem_inp_mux_put); +static const struct snd_kcontrol_new tx_adc_mux0 = + SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux1 = + SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux2 = + SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux3 = + SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux4 = + SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux5 = + SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux6 = + SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux7 = + SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux8 = + SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1090,6 +1692,27 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, WCD9335_SLIM_WATER_MARK_VAL); if (ret < 0) goto err; + } else { + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(ch->port), + payload & 0x00FF); + if (ret < 0) + goto err; + + /* ports 8,9 */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(ch->port), + (payload & 0xFF00)>>8); + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + + if (ret < 0) + goto err; } } @@ -1105,12 +1728,91 @@ err: return ret; } +static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, + u8 rate_val, u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 shift = 0, shift_val = 0, tx_mux_sel; + struct wcd9335_slim_ch *ch; + int tx_port, tx_port_reg; + int decimator = -1; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + tx_port = ch->port; + if ((tx_port == 12) || (tx_port >= 14)) { + dev_err(wcd->dev, "Invalid SLIM TX%u port DAI ID:%d\n", + tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } else { + return -EINVAL; + } + + tx_mux_sel = snd_soc_component_read32(comp, tx_port_reg) & + (shift_val << shift); + + tx_mux_sel = tx_mux_sel >> shift; + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + snd_soc_component_update_bits(comp, + WCD9335_CDC_TX_PATH_CTL(decimator), + WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK, + rate_val); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_err(wcd->dev, "RX_MIX_TX%u going to SLIM TX%u\n", + tx_port, tx_port); + } else { + dev_err(wcd->dev, "ERROR: Invalid decimator: %d\n", + decimator); + return -EINVAL; + } + } + + return 0; +} + static int wcd9335_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct wcd9335_codec *wcd; - int ret; + int ret, tx_fs_rate = 0; wcd = snd_soc_component_get_drvdata(dai->component); @@ -1132,6 +1834,53 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } break; + + case SNDRV_PCM_STREAM_CAPTURE: + switch (params_rate(params)) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(wcd->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + + }; + + ret = wcd9335_set_decimator_rate(dai, tx_fs_rate, + params_rate(params)); + if (ret < 0) { + dev_err(wcd->dev, "Cannot set TX Decimator rate\n"); + return ret; + } + switch (params_width(params)) { + case 16 ... 32: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + break; default: dev_err(wcd->dev, "Invalid stream type %d\n", substream->stream); @@ -1199,6 +1948,14 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, } } + if (wcd->tx_chs) { + wcd->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd->tx_chs[i].list); + } + } + return 0; } @@ -1228,6 +1985,19 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai, *rx_num = i; break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + if (!tx_slot || !tx_num) { + dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n", + tx_slot, tx_num); + return -EINVAL; + } + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + tx_slot[i++] = ch->ch_num; + + *tx_num = i; + break; default: dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); break; @@ -1548,6 +2318,496 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static int wcd9335_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + if ((micb_index < 0) || (micb_index > WCD9335_MAX_MICBIAS - 1)) { + dev_err(wcd->dev, "Invalid micbias index, micb_ind:%d\n", + micb_index); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD9335_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD9335_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD9335_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD9335_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd->pullup_ref[micb_index]++; + if ((wcd->pullup_ref[micb_index] == 1) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + wcd->pullup_ref[micb_index]--; + if ((wcd->pullup_ref[micb_index] == 0) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + wcd->micb_ref[micb_index]++; + if (wcd->micb_ref[micb_index] == 1) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + break; + case MICB_DISABLE: + wcd->micb_ref[micb_index]--; + if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] == 0)) { + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + } + break; + }; + + return 0; +} + +static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + wcd9335_micbias_control(comp, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + return __wcd9335_codec_enable_micbias(w, event); +} + +static void wcd9335_codec_set_tx_hold(struct snd_soc_component *comp, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD9335_ANA_AMIC1 || amic_reg == WCD9335_ANA_AMIC3 || + amic_reg == WCD9335_ANA_AMIC5) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD9335_ANA_AMIC1: + case WCD9335_ANA_AMIC2: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC2, mask, + val); + break; + case WCD9335_ANA_AMIC3: + case WCD9335_ANA_AMIC4: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC4, mask, + val); + break; + case WCD9335_ANA_AMIC5: + case WCD9335_ANA_AMIC6: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC6, mask, + val); + break; + default: + dev_err(comp->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int wcd9335_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9335_codec_set_tx_hold(comp, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int wcd9335_codec_find_amic_input(struct snd_soc_component *comp, + int adc_mux_n) +{ + int mux_sel, reg, mreg; + + if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX || + adc_mux_n == WCD9335_INVALID_ADC_MUX) + return 0; + + /* Check whether adc mux input is AMIC or DMIC */ + if (adc_mux_n < 4) { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + 2 * adc_mux_n; + mreg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + 2 * adc_mux_n; + mux_sel = snd_soc_component_read32(comp, reg) & 0x3; + } else { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + adc_mux_n - 4; + mreg = reg; + mux_sel = snd_soc_component_read32(comp, reg) >> 6; + } + + if (mux_sel != WCD9335_CDC_TX_INP_MUX_SEL_AMIC) + return 0; + + return snd_soc_component_read32(comp, mreg) & 0x07; +} + +static u16 wcd9335_codec_get_amic_pwlvl_reg(struct snd_soc_component *comp, + int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD9335_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD9335_ANA_AMIC3; + break; + + case 5: + case 6: + pwr_level_reg = WCD9335_ANA_AMIC5; + break; + default: + dev_err(comp->dev, "invalid amic: %d\n", amic); + break; + } + + return pwr_level_reg; +} + +static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + char *dec; + u8 hpf_coff_freq; + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(comp->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = wcd9335_codec_find_amic_input(comp, decimator); + if (amic_n) + pwr_level_reg = wcd9335_codec_get_amic_pwlvl_reg(comp, + amic_n); + + if (pwr_level_reg) { + switch ((snd_soc_component_read32(comp, pwr_level_reg) & + WCD9335_AMIC_PWR_LVL_MASK) >> + WCD9335_AMIC_PWR_LVL_SHIFT) { + case WCD9335_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_LP); + break; + + case WCD9335_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_HP); + break; + case WCD9335_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_DF); + break; + } + } + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + if (hpf_coff_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x10); + /* Enable APC */ + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x08); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00); + + if (decimator == 0) { + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x03); + } + + snd_soc_component_update_bits(comp, hpf_gate_reg, + 0x01, 0x01); + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_write(comp, tx_gain_ctl_reg, + snd_soc_component_read32(comp, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10); + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00); + if (hpf_coff_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_coff_freq << 5); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); + break; + }; +out: + kfree(wname); + return ret; +} + +static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_err(component->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(component->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16; + break; + default: + dev_err(component->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(comp->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(wcd->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(wcd->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(comp->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, struct snd_soc_component *component) { @@ -3153,6 +4413,191 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* TX */ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux0), + SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux1), + SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux2), + SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux3), + SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux4), + SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux5), + SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux6), + SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux7), + SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux8), + + SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_amic_mux0), + SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_amic_mux1), + SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_amic_mux2), + SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_amic_mux3), + SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_amic_mux4), + SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_amic_mux5), + SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_amic_mux6), + SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_amic_mux7), + SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_amic_mux8), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + + SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, WCD9335_TX0, 0, + &sb_tx0_mux), + SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, WCD9335_TX1, 0, + &sb_tx1_mux), + SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, WCD9335_TX2, 0, + &sb_tx2_mux), + SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, WCD9335_TX3, 0, + &sb_tx3_mux), + SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, WCD9335_TX4, 0, + &sb_tx4_mux), + SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, WCD9335_TX5, 0, + &sb_tx5_mux), + SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, WCD9335_TX6, 0, + &sb_tx6_mux), + SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, WCD9335_TX7, 0, + &sb_tx7_mux), + SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, WCD9335_TX8, 0, + &sb_tx8_mux), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), }; static void wcd9335_enable_sido_buck(struct snd_soc_component *component) @@ -3289,6 +4734,7 @@ static int wcd9335_probe(struct wcd9335_codec *wcd) struct device *dev = wcd->dev; memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs)); wcd->sido_input_src = SIDO_SOURCE_INTERNAL; wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; From 93f97ff1911a34e2a4662f16b6266b2c309f918b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:52 +0000 Subject: [PATCH 217/461] ASoC: wcd9335: add audio routings This patch adds audio routing for both playback and capture. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 189 +++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 887352398f70..3878187bb512 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -100,6 +100,67 @@ /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) +#define WCD9335_INTERPOLATOR_PATH(id) \ + {"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_2 MUX", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_2 MUX", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_2 MUX", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_2 MUX", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_2 MUX", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_2 MUX", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_2 MUX", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_2 MUX", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP0"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP1"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP2"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_2 MUX"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_1 MIX1"}, \ + {"RX INT" #id " MIX2", NULL, "RX INT" #id " SEC MIX"}, \ + {"RX INT" #id " INTERP", NULL, "RX INT" #id " MIX2"} + +#define WCD9335_ADC_MUX_PATH(id) \ + {"AIF1_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF2_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"SLIM TX" #id " MUX", "DEC" #id, "ADC MUX" #id}, \ + {"ADC MUX" #id, "DMIC", "DMIC MUX" #id}, \ + {"ADC MUX" #id, "AMIC", "AMIC MUX" #id}, \ + {"DMIC MUX" #id, "DMIC0", "DMIC0"}, \ + {"DMIC MUX" #id, "DMIC1", "DMIC1"}, \ + {"DMIC MUX" #id, "DMIC2", "DMIC2"}, \ + {"DMIC MUX" #id, "DMIC3", "DMIC3"}, \ + {"DMIC MUX" #id, "DMIC4", "DMIC4"}, \ + {"DMIC MUX" #id, "DMIC5", "DMIC5"}, \ + {"AMIC MUX" #id, "ADC1", "ADC1"}, \ + {"AMIC MUX" #id, "ADC2", "ADC2"}, \ + {"AMIC MUX" #id, "ADC3", "ADC3"}, \ + {"AMIC MUX" #id, "ADC4", "ADC4"}, \ + {"AMIC MUX" #id, "ADC5", "ADC5"}, \ + {"AMIC MUX" #id, "ADC6", "ADC6"} + enum { WCD9335_RX0 = 0, WCD9335_RX1, @@ -2318,6 +2379,132 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static const struct snd_soc_dapm_route wcd9335_audio_map[] = { + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + + WCD9335_INTERPOLATOR_PATH(0), + WCD9335_INTERPOLATOR_PATH(1), + WCD9335_INTERPOLATOR_PATH(2), + WCD9335_INTERPOLATOR_PATH(3), + WCD9335_INTERPOLATOR_PATH(4), + WCD9335_INTERPOLATOR_PATH(5), + WCD9335_INTERPOLATOR_PATH(6), + WCD9335_INTERPOLATOR_PATH(7), + WCD9335_INTERPOLATOR_PATH(8), + + /* EAR PA */ + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + /* HPHL */ + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + /* HPHR */ + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + /* LINEOUT1 */ + {"RX INT3 DAC", NULL, "RX INT3 INTERP"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + /* LINEOUT2 */ + {"RX INT4 DAC", NULL, "RX INT4 INTERP"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + /* LINEOUT3 */ + {"RX INT5 DAC", NULL, "RX INT5 INTERP"}, + {"RX INT5 DAC", NULL, "RX_BIAS"}, + {"LINEOUT3 PA", NULL, "RX INT5 DAC"}, + {"LINEOUT3", NULL, "LINEOUT3 PA"}, + + /* LINEOUT4 */ + {"RX INT6 DAC", NULL, "RX INT6 INTERP"}, + {"RX INT6 DAC", NULL, "RX_BIAS"}, + {"LINEOUT4 PA", NULL, "RX INT6 DAC"}, + {"LINEOUT4", NULL, "LINEOUT4 PA"}, + + /* SLIMBUS Connections */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* ADC Mux */ + WCD9335_ADC_MUX_PATH(0), + WCD9335_ADC_MUX_PATH(1), + WCD9335_ADC_MUX_PATH(2), + WCD9335_ADC_MUX_PATH(3), + WCD9335_ADC_MUX_PATH(4), + WCD9335_ADC_MUX_PATH(5), + WCD9335_ADC_MUX_PATH(6), + WCD9335_ADC_MUX_PATH(7), + WCD9335_ADC_MUX_PATH(8), + + /* ADC Connections */ + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4"}, + {"ADC5", NULL, "AMIC5"}, + {"ADC6", NULL, "AMIC6"}, +}; + static int wcd9335_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm) { @@ -4727,6 +4914,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .num_controls = ARRAY_SIZE(wcd9335_snd_controls), .dapm_widgets = wcd9335_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), + .dapm_routes = wcd9335_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map), }; static int wcd9335_probe(struct wcd9335_codec *wcd) From 9f11d233d98aa7570210fbfd6cc6e11f5df8906d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:53 +0000 Subject: [PATCH 218/461] ASoC: apq8096: add slim support Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/apq8096.c | 71 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index fb45f396ab4a..94363fd6846a 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -9,6 +9,10 @@ #include #include "common.h" +#define SLIM_MAX_TX_PORTS 16 +#define SLIM_MAX_RX_PORTS 16 +#define WCD9335_DEFAULT_MCLK_RATE 9600000 + static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -23,14 +27,79 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret = 0; + + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) { + pr_err("failed to get codec chan map, err:%d\n", ret); + goto end; + } else if (ret == -ENOTSUPP) { + return 0; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + rx_ch_cnt, rx_ch); + else + ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, + 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) + pr_err("Failed to set cpu chan map, err:%d\n", ret); + else if (ret == -ENOTSUPP) + ret = 0; +end: + return ret; +} + +static struct snd_soc_ops apq8096_ops = { + .hw_params = msm_snd_hw_params, +}; + +static int apq8096_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + /* + * Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156}; + unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + + return 0; +} + static void apq8096_add_be_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; int i; for_each_card_prelinks(card, i, link) { - if (link->no_pcm == 1) + if (link->no_pcm == 1) { link->be_hw_params_fixup = apq8096_be_hw_params_fixup; + link->init = apq8096_init; + link->ops = &apq8096_ops; + } } } From 202e69e645545e8dcec5e239658125276a7a315a Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Tue, 29 Jan 2019 00:47:01 +0200 Subject: [PATCH 219/461] ALSA: usb-audio: Cleanup DSD whitelist XMOS/Thesycon family of USB Audio Class firmware flags DSD altsetting separate from the PCM ones. Thus the DSD altsetting can be auto-detected based on the flag and doesn't need maintaining specific altsetting whitelist. In addition, static VID:PID-to-altsetting whitelisting causes problems when firmware update changes the altsetting, or same VID:PID is reused for another device that has different kind of firmware. This patch removes existing explicit whitelist mappings for XMOS VID (0x20b1) and Thesycon VID (0x152a). Also corrects placement of Hegel HD12 and NuPrime DAC-10 to keep list sorted based on VID. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index bb8372833fc2..ef67d19117c4 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1479,10 +1479,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, /* XMOS based USB DACs */ switch (chip->usb_id) { case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */ - case USB_ID(0x20b1, 0x0002): /* Wyred 4 Sound DAC-2 DSD */ - case USB_ID(0x20b1, 0x2004): /* Matrix Audio X-SPDIF 2 */ - case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ - case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */ case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */ @@ -1492,23 +1488,13 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; - case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */ - case USB_ID(0x152a, 0x85de): /* SMSL D1 DAC */ - case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */ case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */ + case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */ case USB_ID(0x16b0, 0x06b2): /* NuPrime DAC-10 */ + case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */ case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */ case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */ case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */ - case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */ - case USB_ID(0x20b1, 0x2005): /* Denafrips Ares DAC */ - case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ - case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ - case USB_ID(0x20b1, 0x3021): /* Eastern El. MiniMax Tube DAC Supreme */ - case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ - case USB_ID(0x20b1, 0x302d): /* Unison Research Unico CD Due */ - case USB_ID(0x20b1, 0x307b): /* CH Precision C1 DAC */ - case USB_ID(0x20b1, 0x3086): /* Singxer F-1 converter board */ case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */ case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */ case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */ From a8233b6c1972e1959cf84a021aeb61ddcd23cc26 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 29 Jan 2019 12:02:29 +0000 Subject: [PATCH 220/461] ASoC: wcd9335: Fix missing slimbus dependency Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9b904f81863d..d47d321bfb96 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1117,6 +1117,7 @@ config SND_SOC_UDA1380 config SND_SOC_WCD9335 tristate "WCD9335 Codec" + depends on SLIMBUS select REGMAP_SLIMBUS help The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports From 494a3503d684b6fc497623bc01e3e16f8def0499 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Sat, 19 Jan 2019 19:33:31 +0800 Subject: [PATCH 221/461] ASoC: Documentation: Add google, cros-ec-codec Add documentation for Chrome EC codec driver. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- .../bindings/sound/google,cros-ec-codec.txt | 26 +++++++++++++++++++ MAINTAINERS | 7 +++++ 2 files changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt diff --git a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt new file mode 100644 index 000000000000..1084f7f22eea --- /dev/null +++ b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt @@ -0,0 +1,26 @@ +* Audio codec controlled by ChromeOS EC + +Google's ChromeOS EC codec is a digital mic codec provided by the +Embedded Controller (EC) and is controlled via a host-command interface. + +An EC codec node should only be found as a sub-node of the EC node (see +Documentation/devicetree/bindings/mfd/cros-ec.txt). + +Required properties: +- compatible: Must contain "google,cros-ec-codec" +- #sound-dai-cells: Should be 1. The cell specifies number of DAIs. +- max-dmic-gain: A number for maximum gain in dB on digital microphone. + +Example: + +cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + cros_ec_codec: ec-codec { + compatible = "google,cros-ec-codec"; + #sound-dai-cells = <1>; + max-dmic-gain = <43>; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 9f64f8d3740e..3bcc5465e460 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3687,6 +3687,13 @@ N: cros_ec N: cros-ec F: drivers/power/supply/cros_usbpd-charger.c +CHROMEOS EC CODEC DRIVER +M: Cheng-Yi Chiang +S: Maintained +R: Enric Balletbo i Serra +R: Guenter Roeck +F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt + CIRRUS LOGIC AUDIO CODEC DRIVERS M: Brian Austin M: Paul Handrigan From b291f42a37187cbd78ff59a34f2751164baad8bf Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Sat, 19 Jan 2019 19:33:33 +0800 Subject: [PATCH 222/461] ASoC: cros_ec_codec: Add codec driver for Cros EC Add a codec driver to control ChromeOS EC codec. Use EC Host command to enable/disable I2S recording and control other configurations. Signed-off-by: Cheng-Yi Chiang Reviewed-by: Enric Balletbo i Serra Signed-off-by: Mark Brown --- MAINTAINERS | 1 + sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cros_ec_codec.c | 441 +++++++++++++++++++++++++++++++ 4 files changed, 452 insertions(+) create mode 100644 sound/soc/codecs/cros_ec_codec.c diff --git a/MAINTAINERS b/MAINTAINERS index 3bcc5465e460..9d846fb07442 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3693,6 +3693,7 @@ S: Maintained R: Enric Balletbo i Serra R: Guenter Roeck F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt +F: sound/soc/codecs/cros_ec_codec.* CIRRUS LOGIC AUDIO CODEC DRIVERS M: Brian Austin diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d47d321bfb96..a15710c8a95f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -50,6 +50,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_BD28623 select SND_SOC_CQ0093VC + select SND_SOC_CROS_EC_CODEC if MFD_CROS_EC select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C @@ -459,6 +460,13 @@ config SND_SOC_CPCAP config SND_SOC_CQ0093VC tristate +config SND_SOC_CROS_EC_CODEC + tristate "codec driver for ChromeOS EC" + depends on MFD_CROS_EC + help + If you say yes here you will get support for the + ChromeOS Embedded Controller's Audio Codec. + config SND_SOC_CS35L32 tristate "Cirrus Logic CS35L32 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4cf29e3dbff6..3d7a59761c08 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -42,6 +42,7 @@ snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-cpcap-objs := cpcap.o snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cros-ec-codec-objs := cros_ec_codec.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o +obj-$(CONFIG_SND_SOC_CROS_EC_CODEC) += snd-soc-cros-ec-codec.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c new file mode 100644 index 000000000000..b14100b6a939 --- /dev/null +++ b/sound/soc/codecs/cros_ec_codec.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for ChromeOS Embedded Controller codec. + * + * This driver uses the cros-ec interface to communicate with the ChromeOS + * EC for audio function. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "cros-ec-codec" + +/** + * struct cros_ec_codec_data - ChromeOS EC codec driver data. + * @dev: Device structure used in sysfs. + * @ec_device: cros_ec_device structure to talk to the physical device. + * @component: Pointer to the component. + * @max_dmic_gain: Maximum gain in dB supported by EC codec. + */ +struct cros_ec_codec_data { + struct device *dev; + struct cros_ec_device *ec_device; + struct snd_soc_component *component; + unsigned int max_dmic_gain; +}; + +static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0); + +static int ec_command_get_gain(struct snd_soc_component *component, + struct ec_param_codec_i2s *param, + struct ec_response_codec_gain *resp) +{ + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + struct cros_ec_device *ec_device = codec_data->ec_device; + u8 buffer[sizeof(struct cros_ec_command) + + max(sizeof(struct ec_param_codec_i2s), + sizeof(struct ec_response_codec_gain))]; + struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; + int ret; + + msg->version = 0; + msg->command = EC_CMD_CODEC_I2S; + msg->outsize = sizeof(struct ec_param_codec_i2s); + msg->insize = sizeof(struct ec_response_codec_gain); + + memcpy(msg->data, param, msg->outsize); + + ret = cros_ec_cmd_xfer_status(ec_device, msg); + if (ret > 0) + memcpy(resp, msg->data, msg->insize); + + return ret; +} + +/* + * Wrapper for EC command without response. + */ +static int ec_command_no_resp(struct snd_soc_component *component, + struct ec_param_codec_i2s *param) +{ + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + struct cros_ec_device *ec_device = codec_data->ec_device; + u8 buffer[sizeof(struct cros_ec_command) + + sizeof(struct ec_param_codec_i2s)]; + struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; + + msg->version = 0; + msg->command = EC_CMD_CODEC_I2S; + msg->outsize = sizeof(struct ec_param_codec_i2s); + msg->insize = 0; + + memcpy(msg->data, param, msg->outsize); + + return cros_ec_cmd_xfer_status(ec_device, msg); +} + +static int set_i2s_config(struct snd_soc_component *component, + enum ec_i2s_config i2s_config) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set I2S format to %u\n", __func__, + i2s_config); + + param.cmd = EC_CODEC_I2S_SET_CONFIG; + param.i2s_config = i2s_config; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + enum ec_i2s_config i2s_config; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + i2s_config = EC_DAI_FMT_I2S; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + i2s_config = EC_DAI_FMT_RIGHT_J; + break; + + case SND_SOC_DAIFMT_LEFT_J: + i2s_config = EC_DAI_FMT_LEFT_J; + break; + + case SND_SOC_DAIFMT_DSP_A: + i2s_config = EC_DAI_FMT_PCM_A; + break; + + case SND_SOC_DAIFMT_DSP_B: + i2s_config = EC_DAI_FMT_PCM_B; + break; + + default: + return -EINVAL; + } + + return set_i2s_config(component, i2s_config); +} + +static int set_i2s_sample_depth(struct snd_soc_component *component, + enum ec_sample_depth_value depth) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set depth to %u\n", __func__, depth); + + param.cmd = EC_CODEC_SET_SAMPLE_DEPTH; + param.depth = depth; + + return ec_command_no_resp(component, ¶m); +} + +static int set_i2s_bclk(struct snd_soc_component *component, uint32_t bclk) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set i2s bclk to %u\n", __func__, bclk); + + param.cmd = EC_CODEC_I2S_SET_BCLK; + param.bclk = bclk; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + unsigned int rate, bclk; + int ret; + + rate = params_rate(params); + if (rate != 48000) + return -EINVAL; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_16); + break; + case SNDRV_PCM_FORMAT_S24_LE: + ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_24); + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + + bclk = snd_soc_params_to_bclk(params); + return set_i2s_bclk(component, bclk); +} + +static const struct snd_soc_dai_ops cros_ec_i2s_dai_ops = { + .hw_params = cros_ec_i2s_hw_params, + .set_fmt = cros_ec_i2s_set_dai_fmt, +}; + +struct snd_soc_dai_driver cros_ec_dai[] = { + { + .name = "cros_ec_codec I2S", + .id = 0, + .capture = { + .stream_name = "I2S Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &cros_ec_i2s_dai_ops, + } +}; + +static int get_ec_mic_gain(struct snd_soc_component *component, + u8 *left, u8 *right) +{ + struct ec_param_codec_i2s param; + struct ec_response_codec_gain resp; + int ret; + + param.cmd = EC_CODEC_GET_GAIN; + + ret = ec_command_get_gain(component, ¶m, &resp); + if (ret < 0) + return ret; + + *left = resp.left; + *right = resp.right; + + return 0; +} + +static int mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u8 left, right; + int ret; + + ret = get_ec_mic_gain(component, &left, &right); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = left; + ucontrol->value.integer.value[1] = right; + + return 0; +} + +static int set_ec_mic_gain(struct snd_soc_component *component, + u8 left, u8 right) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set mic gain to %u, %u\n", + __func__, left, right); + + param.cmd = EC_CODEC_SET_GAIN; + param.gain.left = left; + param.gain.right = right; + + return ec_command_no_resp(component, ¶m); +} + +static int mic_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + int left = ucontrol->value.integer.value[0]; + int right = ucontrol->value.integer.value[1]; + unsigned int max_dmic_gain = codec_data->max_dmic_gain; + + if (left > max_dmic_gain || right > max_dmic_gain) + return -EINVAL; + + return set_ec_mic_gain(component, (u8)left, (u8)right); +} + +static struct snd_kcontrol_new mic_gain_control = + SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, 0, 0, 0, + mic_gain_get, mic_gain_put, ec_mic_gain_tlv); + +static int enable_i2s(struct snd_soc_component *component, int enable) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set i2s to %u\n", __func__, enable); + + param.cmd = EC_CODEC_I2S_ENABLE; + param.i2s_enable = enable; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_enable_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dev_dbg(component->dev, + "%s got SND_SOC_DAPM_PRE_PMU event\n", __func__); + return enable_i2s(component, 1); + + case SND_SOC_DAPM_PRE_PMD: + dev_dbg(component->dev, + "%s got SND_SOC_DAPM_PRE_PMD event\n", __func__); + return enable_i2s(component, 0); + } + + return 0; +} + +/* + * The goal of this DAPM route is to turn on/off I2S using EC + * host command when capture stream is started/stopped. + */ +static const struct snd_soc_dapm_widget cros_ec_codec_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC"), + + /* + * Control EC to enable/disable I2S. + */ + SND_SOC_DAPM_SUPPLY("I2S Enable", SND_SOC_NOPM, + 0, 0, cros_ec_i2s_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT("I2STX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route cros_ec_codec_dapm_routes[] = { + { "I2STX", NULL, "DMIC" }, + { "I2STX", NULL, "I2S Enable" }, +}; + +/* + * Read maximum gain from device property and set it to mixer control. + */ +static int cros_ec_set_gain_range(struct device *dev) +{ + struct soc_mixer_control *control; + struct cros_ec_codec_data *codec_data = dev_get_drvdata(dev); + int rc; + + rc = device_property_read_u32(dev, "max-dmic-gain", + &codec_data->max_dmic_gain); + if (rc) + return rc; + + control = (struct soc_mixer_control *) + mic_gain_control.private_value; + control->max = codec_data->max_dmic_gain; + control->platform_max = codec_data->max_dmic_gain; + + return 0; +} + +static int cros_ec_codec_probe(struct snd_soc_component *component) +{ + int rc; + + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + + rc = cros_ec_set_gain_range(codec_data->dev); + if (rc) + return rc; + + return snd_soc_add_component_controls(component, &mic_gain_control, 1); +} + +static const struct snd_soc_component_driver cros_ec_component_driver = { + .probe = cros_ec_codec_probe, + .dapm_widgets = cros_ec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cros_ec_codec_dapm_widgets), + .dapm_routes = cros_ec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cros_ec_codec_dapm_routes), +}; + +/* + * Platform device and platform driver fro cros-ec-codec. + */ +static int cros_ec_codec_platform_probe(struct platform_device *pd) +{ + struct device *dev = &pd->dev; + struct cros_ec_device *ec_device = dev_get_drvdata(pd->dev.parent); + struct cros_ec_codec_data *codec_data; + + codec_data = devm_kzalloc(dev, sizeof(struct cros_ec_codec_data), + GFP_KERNEL); + if (!codec_data) + return -ENOMEM; + + codec_data->dev = dev; + codec_data->ec_device = ec_device; + + platform_set_drvdata(pd, codec_data); + + return snd_soc_register_component(dev, &cros_ec_component_driver, + cros_ec_dai, ARRAY_SIZE(cros_ec_dai)); +} + +#ifdef CONFIG_OF +static const struct of_device_id cros_ec_codec_of_match[] = { + { .compatible = "google,cros-ec-codec" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match); +#endif + +static struct platform_driver cros_ec_codec_platform_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(cros_ec_codec_of_match), + }, + .probe = cros_ec_codec_platform_probe, +}; + +module_platform_driver(cros_ec_codec_platform_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS EC codec driver"); +MODULE_AUTHOR("Cheng-Yi Chiang "); +MODULE_ALIAS("platform:" DRV_NAME); From 53b6d0adffb0505db5332589e78da1c66f7e626a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Jan 2019 09:42:20 -0600 Subject: [PATCH 223/461] ASoC: Intel: cht_bsw_rt5672: remove useless test For some reason we test if the machine is passed as a parameter before fixing up the codec name. This is unnecessary, generates false positives in static analysis tools and done only in this machine driver, remove and adjust indentation. Reported-by: Colin Ian King Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f1c1f9dd5353..3d5a2b3a06f0 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -411,18 +411,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ - if (mach) { - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { - snprintf(drv->codec_name, sizeof(drv->codec_name), - "i2c-%s", i2c_name); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codec_name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codec_name = - drv->codec_name; - break; - } + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + snprintf(drv->codec_name, sizeof(drv->codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = drv->codec_name; + break; } } } From 98081ca62cbac31fb0f7efaf90b2e7384ce22257 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Jan 2019 14:03:33 +0100 Subject: [PATCH 224/461] ALSA: hda - Record the current power state before suspend/resume calls Currently we deal with single codec and suspend codec callbacks for all S3, S4 and runtime PM handling. But it turned out that we want distinguish the call patterns sometimes, e.g. for applying some init sequence only at probing and restoring from hibernate. This patch slightly modifies the common PM callbacks for HD-audio codec and stores the currently processed PM event in power_state of the codec's device.power field, which is currently unused. The codec callback can take a look at this event value and judges which purpose it's being called. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 43 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9f8d59e7e89f..dbc9eaa81358 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2917,6 +2917,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_jackpoll_work(&codec->jackpoll_work.work); else snd_hda_jack_report_sync(codec); + codec->core.dev.power.power_state = PMSG_ON; snd_hdac_leave_pm(&codec->core); } @@ -2950,10 +2951,48 @@ static int hda_codec_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_SLEEP +static int hda_codec_pm_suspend(struct device *dev) +{ + dev->power.power_state = PMSG_SUSPEND; + return pm_runtime_force_suspend(dev); +} + +static int hda_codec_pm_resume(struct device *dev) +{ + dev->power.power_state = PMSG_RESUME; + return pm_runtime_force_resume(dev); +} + +static int hda_codec_pm_freeze(struct device *dev) +{ + dev->power.power_state = PMSG_FREEZE; + return pm_runtime_force_suspend(dev); +} + +static int hda_codec_pm_thaw(struct device *dev) +{ + dev->power.power_state = PMSG_THAW; + return pm_runtime_force_resume(dev); +} + +static int hda_codec_pm_restore(struct device *dev) +{ + dev->power.power_state = PMSG_RESTORE; + return pm_runtime_force_resume(dev); +} +#endif /* CONFIG_PM_SLEEP */ + /* referred in hda_bind.c */ const struct dev_pm_ops hda_codec_driver_pm = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) +#ifdef CONFIG_PM_SLEEP + .suspend = hda_codec_pm_suspend, + .resume = hda_codec_pm_resume, + .freeze = hda_codec_pm_freeze, + .thaw = hda_codec_pm_thaw, + .poweroff = hda_codec_pm_suspend, + .restore = hda_codec_pm_restore, +#endif /* CONFIG_PM_SLEEP */ SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL) }; From f6ef4e0e284251ff795c541db1129c84515ed044 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Jan 2019 14:14:51 +0100 Subject: [PATCH 225/461] ALSA: hda/realtek - Apply ALC294 hp init also for S4 resume The init sequence for ALC294 headphone stuff is needed not only for the boot up time but also for the resume from hibernation, where the device is switched from the boot kernel without sound driver to the suspended image. Since we record the PM event in the device power_state field, we can now recognize the call pattern and apply the sequence conditionally. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4139aced63f8..e9dc9408d9bc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3408,7 +3408,9 @@ static void alc294_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (!spec->done_hp_init) { + /* required only at boot or S4 resume time */ + if (!spec->done_hp_init || + codec->core.dev.power.power_state.event == PM_EVENT_RESTORE) { alc294_hp_init(codec); spec->done_hp_init = true; } From 45571bb871b217f1031045a27d935ea7c6ea5d12 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 24 Jan 2019 09:45:36 +0100 Subject: [PATCH 226/461] ALSA: hda - Use standard device registration for beep Currently the registration and free of beep input device was done manually from the register and the disconnect callbacks of the assigned codec object. This seems working in most cases, but this may be a cause of some races at probe. Moreover, due to these manual calls, the total code became unnecessarily lengthy. This patch rewrites the beep registration code to follow the standard sound device object style. This allows us reducing the code, in addition to avoiding the nested device registration calls. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 151 ++++++++++++++++++-------------------- sound/pci/hda/hda_beep.h | 5 -- sound/pci/hda/hda_codec.c | 10 --- 3 files changed, 72 insertions(+), 94 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 066b5b59c4d7..b7d9160ed868 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -127,44 +127,6 @@ static void turn_off_beep(struct hda_beep *beep) } } -static void snd_hda_do_detach(struct hda_beep *beep) -{ - if (beep->registered) - input_unregister_device(beep->dev); - else - input_free_device(beep->dev); - beep->dev = NULL; - turn_off_beep(beep); -} - -static int snd_hda_do_attach(struct hda_beep *beep) -{ - struct input_dev *input_dev; - struct hda_codec *codec = beep->codec; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - /* setup digital beep device */ - input_dev->name = "HDA Digital PCBeep"; - input_dev->phys = beep->phys; - input_dev->id.bustype = BUS_PCI; - input_dev->dev.parent = &codec->card->card_dev; - - input_dev->id.vendor = codec->core.vendor_id >> 16; - input_dev->id.product = codec->core.vendor_id & 0xffff; - input_dev->id.version = 0x01; - - input_dev->evbit[0] = BIT_MASK(EV_SND); - input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); - input_dev->event = snd_hda_beep_event; - input_set_drvdata(input_dev, beep); - - beep->dev = input_dev; - return 0; -} - /** * snd_hda_enable_beep_device - Turn on/off beep sound * @codec: the HDA codec @@ -186,6 +148,38 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) } EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); +static int beep_dev_register(struct snd_device *device) +{ + struct hda_beep *beep = device->device_data; + int err; + + err = input_register_device(beep->dev); + if (!err) + beep->registered = true; + return err; +} + +static int beep_dev_disconnect(struct snd_device *device) +{ + struct hda_beep *beep = device->device_data; + + if (beep->registered) + input_unregister_device(beep->dev); + else + input_free_device(beep->dev); + turn_off_beep(beep); + return 0; +} + +static int beep_dev_free(struct snd_device *device) +{ + struct hda_beep *beep = device->device_data; + + beep->codec->beep = NULL; + kfree(beep); + return 0; +} + /** * snd_hda_attach_beep_device - Attach a beep input device * @codec: the HDA codec @@ -194,14 +188,16 @@ EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); * Attach a beep object to the given widget. If beep hint is turned off * explicitly or beep_mode of the codec is turned off, this doesn't nothing. * - * The attached beep device has to be registered via - * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device() - * appropriately. - * * Currently, only one beep device is allowed to each codec. */ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { + static struct snd_device_ops ops = { + .dev_register = beep_dev_register, + .dev_disconnect = beep_dev_disconnect, + .dev_free = beep_dev_free, + }; + struct input_dev *input_dev; struct hda_beep *beep; int err; @@ -226,14 +222,41 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); mutex_init(&beep->mutex); - err = snd_hda_do_attach(beep); - if (err < 0) { - kfree(beep); - codec->beep = NULL; - return err; + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto err_free; } + /* setup digital beep device */ + input_dev->name = "HDA Digital PCBeep"; + input_dev->phys = beep->phys; + input_dev->id.bustype = BUS_PCI; + input_dev->dev.parent = &codec->card->card_dev; + + input_dev->id.vendor = codec->core.vendor_id >> 16; + input_dev->id.product = codec->core.vendor_id & 0xffff; + input_dev->id.version = 0x01; + + input_dev->evbit[0] = BIT_MASK(EV_SND); + input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); + input_dev->event = snd_hda_beep_event; + input_set_drvdata(input_dev, beep); + + beep->dev = input_dev; + + err = snd_device_new(codec->card, SNDRV_DEV_JACK, beep, &ops); + if (err < 0) + goto err_input; + return 0; + + err_input: + input_free_device(beep->dev); + err_free: + kfree(beep); + codec->beep = NULL; + return err; } EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); @@ -243,41 +266,11 @@ EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); */ void snd_hda_detach_beep_device(struct hda_codec *codec) { - struct hda_beep *beep = codec->beep; - if (beep) { - if (beep->dev) - snd_hda_do_detach(beep); - codec->beep = NULL; - kfree(beep); - } + if (!codec->bus->shutdown && codec->beep) + snd_device_free(codec->card, codec->beep); } EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); -/** - * snd_hda_register_beep_device - Register the beep device - * @codec: the HDA codec - */ -int snd_hda_register_beep_device(struct hda_codec *codec) -{ - struct hda_beep *beep = codec->beep; - int err; - - if (!beep || !beep->dev) - return 0; - - err = input_register_device(beep->dev); - if (err < 0) { - codec_err(codec, "hda_beep: unable to register input device\n"); - input_free_device(beep->dev); - codec->beep = NULL; - kfree(beep); - return err; - } - beep->registered = true; - return 0; -} -EXPORT_SYMBOL_GPL(snd_hda_register_beep_device); - static bool ctl_has_mute(struct snd_kcontrol *kcontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index f1457c6b3969..a25358a4807a 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -34,7 +34,6 @@ struct hda_beep { int snd_hda_enable_beep_device(struct hda_codec *codec, int enable); int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); void snd_hda_detach_beep_device(struct hda_codec *codec); -int snd_hda_register_beep_device(struct hda_codec *codec); #else static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { @@ -43,9 +42,5 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) static inline void snd_hda_detach_beep_device(struct hda_codec *codec) { } -static inline int snd_hda_register_beep_device(struct hda_codec *codec) -{ - return 0; -} #endif #endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index dc7b342f00ef..5f2005098a60 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -813,7 +813,6 @@ void snd_hda_codec_register(struct hda_codec *codec) if (codec->registered) return; if (device_is_registered(hda_codec_dev(codec))) { - snd_hda_register_beep_device(codec); codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ @@ -828,14 +827,6 @@ static int snd_hda_codec_dev_register(struct snd_device *device) return 0; } -static int snd_hda_codec_dev_disconnect(struct snd_device *device) -{ - struct hda_codec *codec = device->device_data; - - snd_hda_detach_beep_device(codec); - return 0; -} - static int snd_hda_codec_dev_free(struct snd_device *device) { struct hda_codec *codec = device->device_data; @@ -921,7 +912,6 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, int err; static struct snd_device_ops dev_ops = { .dev_register = snd_hda_codec_dev_register, - .dev_disconnect = snd_hda_codec_dev_disconnect, .dev_free = snd_hda_codec_dev_free, }; From 33ae6ae2111c3118d8d15eba331b6ba5932825c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:42 -0600 Subject: [PATCH 227/461] ASoC: topology: Reduce number of dereferences when accessing dobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have passed dobj, there is no reason to access it through containing structs. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 045ef136903d..b02c41614f96 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -382,10 +382,10 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (sm->dobj.control.kcontrol->tlv.p) - p = sm->dobj.control.kcontrol->tlv.p; - snd_ctl_remove(card, sm->dobj.control.kcontrol); - list_del(&sm->dobj.list); + if (dobj->control.kcontrol->tlv.p) + p = dobj->control.kcontrol->tlv.p; + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sm); kfree(p); } @@ -404,12 +404,12 @@ static void remove_enum(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, se->dobj.control.kcontrol); - list_del(&se->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(dobj->control.dtexts[i]); kfree(se); } @@ -427,8 +427,8 @@ static void remove_bytes(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, sb->dobj.control.kcontrol); - list_del(&sb->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sb); } @@ -464,9 +464,9 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) - kfree(se->dobj.control.dtexts[j]); + kfree(dobj->control.dtexts[j]); kfree(se); kfree(w->kcontrol_news[i].name); From a46e8393d128d4e5f722b47f708a0d5de91e0176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:43 -0600 Subject: [PATCH 228/461] ASoC: topology: Remove widgets from dobj list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we unload and reload machine driver few times we end with corrupted list and try to cleanup no longer existing objects. Fix this by removing dobj from the list. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b02c41614f96..abc2d804d5bf 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -493,6 +493,8 @@ static void remove_widget(struct snd_soc_component *comp, free_news: kfree(w->kcontrol_news); + list_del(&dobj->list); + /* widget w is freed by soc-dapm.c */ } From 34db6a3e91d8f6f6fefbbd9ad7e1efc6f8d440e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:44 -0600 Subject: [PATCH 229/461] ASoC: topology: Fix memory leak from soc_tplg_denum_create_texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtexts is two dimensional array, so we also need to free it after freeing its fields. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index abc2d804d5bf..71bc5b8a9bd3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -410,6 +410,7 @@ static void remove_enum(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) kfree(dobj->control.dtexts[i]); + kfree(dobj->control.dtexts); kfree(se); } @@ -467,6 +468,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) kfree(dobj->control.dtexts[j]); + kfree(dobj->control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); @@ -1361,6 +1363,7 @@ err_se: kfree(se->dobj.control.dvalues); for (j = 0; j < ec->items; j++) kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(kc[i].name); From 7620fe9161cec2722db880affe03f5e9e2bb93d5 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 25 Jan 2019 14:06:45 -0600 Subject: [PATCH 230/461] ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create template.sname and template.name are only freed when an error occur. They should be freed in the success return case, too. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 71bc5b8a9bd3..2cb0a05e2368 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1583,6 +1583,9 @@ widget: if (ret < 0) goto ready_err; + kfree(template.sname); + kfree(template.name); + return 0; ready_err: From 5c30f43f0625a792c30e465f21dbeb1bb4dfc40b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:46 -0600 Subject: [PATCH 231/461] ASoC: topology: add SND_SOC_DOBJ_GRAPH type for dapm routes Add a new dobj type SND_SOC_DOBJ_GRAPH for dapm routes and add snd_soc_dobj member to struct snd_soc_dapm_route. This enables device drivers to save driver specific data pertaining to dapm routes and also be able to clean up the data when the driver module is unloaded. Also, reorder the snd_soc_dobj_type types to align with matching topology header types. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 ++ include/sound/soc-topology.h | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bd8163f151cb..46f2ba3ffcb7 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -540,6 +540,8 @@ struct snd_soc_dapm_route { /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); + + struct snd_soc_dobj dobj; }; /* dapm audio path between two widgets */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index fa4b8413d2e2..8c43cfc240fa 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -38,12 +38,13 @@ struct snd_soc_dapm_route; enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ SND_SOC_DOBJ_MIXER, - SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, - SND_SOC_DOBJ_PCM, - SND_SOC_DOBJ_DAI_LINK, - SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_ENUM, + SND_SOC_DOBJ_GRAPH, SND_SOC_DOBJ_WIDGET, + SND_SOC_DOBJ_DAI_LINK, + SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_CODEC_LINK, }; /* dynamic control object */ From 7df04ea7a31eaa75bdad2905f07cc097b15558ee Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:47 -0600 Subject: [PATCH 232/461] ASoC: topology: modify dapm route loading routine and add dapm route unloading struct snd_soc_dapm_route has been modified to be a dynamic object so that it can be used to save driver specific data while parsing topology and clean up driver-specific data during driver unloading. This patch makes the following changes to accomplish the above: 1. Set the dobj member of snd_soc_dapm_route during the SOC_TPLG_PASS_GRAPH pass of topology parsing. 2. Add the remove_route() routine that will be called while removing all dynamic objects from the component driver. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 102 +++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2cb0a05e2368..23d421370e6c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -433,6 +433,23 @@ static void remove_bytes(struct snd_soc_component *comp, kfree(sb); } +/* remove a route */ +static void remove_route(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dapm_route *route = + container_of(dobj, struct snd_soc_dapm_route, dobj); + + if (pass != SOC_TPLG_PASS_GRAPH) + return; + + if (dobj->ops && dobj->ops->dapm_route_unload) + dobj->ops->dapm_route_unload(comp, dobj); + + list_del(&dobj->list); + kfree(route); +} + /* remove a widget and it's kcontrols - routes must be removed first */ static void remove_widget(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) @@ -1119,9 +1136,10 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; - struct snd_soc_dapm_route route; struct snd_soc_tplg_dapm_graph_elem *elem; - int count = hdr->count, i; + struct snd_soc_dapm_route **routes; + int count = hdr->count, i, j; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_GRAPH) { tplg->pos += hdr->size + hdr->payload_size; @@ -1140,36 +1158,85 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, hdr->index); + /* allocate memory for pointer to array of dapm routes */ + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + /* + * allocate memory for each dapm route in the array. + * This needs to be done individually so that + * each route can be freed when it is removed in remove_route(). + */ + for (i = 0; i < count; i++) { + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) { + /* free previously allocated memory */ + for (j = 0; j < i; j++) + kfree(routes[j]); + + kfree(routes); + return -ENOMEM; + } + } + for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } - route.source = elem->source; - route.sink = elem->sink; - route.connected = NULL; /* set to NULL atm for tplg users */ + routes[i]->source = elem->source; + routes[i]->sink = elem->sink; + + /* set to NULL atm for tplg users */ + routes[i]->connected = NULL; if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route.control = NULL; + routes[i]->control = NULL; else - route.control = elem->control; + routes[i]->control = elem->control; - soc_tplg_add_route(tplg, &route); + /* add route dobj to dobj_list */ + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; + routes[i]->dobj.ops = tplg->ops; + routes[i]->dobj.index = tplg->index; + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); + + soc_tplg_add_route(tplg, routes[i]); /* add route, but keep going if some fail */ - snd_soc_dapm_add_routes(dapm, &route, 1); + snd_soc_dapm_add_routes(dapm, routes[i], 1); } - return 0; + /* free memory allocated for all dapm routes in case of error */ + if (ret < 0) + for (i = 0; i < count ; i++) + kfree(routes[i]); + + /* + * free pointer to array of dapm routes as this is no longer needed. + * The memory allocated for each dapm route will be freed + * when it is removed in remove_route(). + */ + kfree(routes); + + return ret; } static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( @@ -2570,6 +2637,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_BYTES: remove_bytes(comp, dobj, pass); break; + case SND_SOC_DOBJ_GRAPH: + remove_route(comp, dobj, pass); + break; case SND_SOC_DOBJ_WIDGET: remove_widget(comp, dobj, pass); break; From 27e27e6555d3a1dd3c906796af6d8e7eb538857f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 29 Jan 2019 16:04:44 +0800 Subject: [PATCH 233/461] dt-bindings: ASoC: Add Spreadtrum DMA platform documentation Add documentation for Spreadtrum DMA platform driver. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sprd-pcm.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sprd-pcm.txt diff --git a/Documentation/devicetree/bindings/sound/sprd-pcm.txt b/Documentation/devicetree/bindings/sound/sprd-pcm.txt new file mode 100644 index 000000000000..4b23e84b2e57 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd-pcm.txt @@ -0,0 +1,23 @@ +* Spreadtrum DMA platfrom bindings + +Required properties: +- compatible: Should be "sprd,pcm-platform". +- dmas: Specify the list of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + +Example: + + audio_platform:platform@0 { + compatible = "sprd,pcm-platform"; + dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, + <&agcp_dma 3 3>, <&agcp_dma 4 4>, + <&agcp_dma 5 5>, <&agcp_dma 6 6>, + <&agcp_dma 7 7>, <&agcp_dma 8 8>, + <&agcp_dma 9 9>, <&agcp_dma 10 10>; + dma-names = "normal_p_l", "normal_p_r", + "normal_c_l", "normal_c_r", + "voice_c", "fast_p", + "loop_c", "loop_p", + "voip_c", "voip_p"; + }; From 42fea318e1d19c0214ed4336d19f512c5d78cc3b Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 29 Jan 2019 16:04:45 +0800 Subject: [PATCH 234/461] ASoC: sprd: Add Spreadtrum audio DMA platfrom driver The Spreadtrum DMA engine uses the link-list mode to support audio playback or capture, thus this patch adds audio DMA platform support for CPU DAI to trigger DMA link-list transfer. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/sprd/Kconfig | 6 + sound/soc/sprd/Makefile | 4 + sound/soc/sprd/sprd-pcm-dma.c | 562 ++++++++++++++++++++++++++++++++++ sound/soc/sprd/sprd-pcm-dma.h | 15 + 6 files changed, 589 insertions(+) create mode 100644 sound/soc/sprd/Kconfig create mode 100644 sound/soc/sprd/Makefile create mode 100644 sound/soc/sprd/sprd-pcm-dma.c create mode 100644 sound/soc/sprd/sprd-pcm-dma.h diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 6592a422a047..aa35940f5c50 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -64,6 +64,7 @@ source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" +source "sound/soc/sprd/Kconfig" source "sound/soc/sti/Kconfig" source "sound/soc/stm/Kconfig" source "sound/soc/sunxi/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 48c48c1c893c..974fb9821e17 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ +obj-$(CONFIG_SND_SOC) += sprd/ obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += stm/ obj-$(CONFIG_SND_SOC) += sunxi/ diff --git a/sound/soc/sprd/Kconfig b/sound/soc/sprd/Kconfig new file mode 100644 index 000000000000..43ece7daf0e9 --- /dev/null +++ b/sound/soc/sprd/Kconfig @@ -0,0 +1,6 @@ +config SND_SOC_SPRD + tristate "SoC Audio for the Spreadtrum SoC chips" + depends on ARCH_SPRD || COMPILE_TEST + help + Say Y or M if you want to add support for codecs attached to + the Spreadtrum SoCs' Audio interfaces. diff --git a/sound/soc/sprd/Makefile b/sound/soc/sprd/Makefile new file mode 100644 index 000000000000..47620e57a9f2 --- /dev/null +++ b/sound/soc/sprd/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# Spreadtrum Audio Support + +obj-$(CONFIG_SND_SOC_SPRD) += sprd-pcm-dma.o diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c new file mode 100644 index 000000000000..cbb27c4abeba --- /dev/null +++ b/sound/soc/sprd/sprd-pcm-dma.c @@ -0,0 +1,562 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2019 Spreadtrum Communications Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sprd-pcm-dma.h" + +#define DRV_NAME "sprd_pcm_dma" +#define SPRD_PCM_DMA_LINKLIST_SIZE 64 +#define SPRD_PCM_DMA_BRUST_LEN 640 + +struct sprd_pcm_dma_data { + struct dma_chan *chan; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + dma_addr_t phys; + void *virt; + int pre_pointer; +}; + +struct sprd_pcm_dma_private { + struct snd_pcm_substream *substream; + struct sprd_pcm_dma_params *params; + struct sprd_pcm_dma_data data[SPRD_PCM_CHANNEL_MAX]; + int hw_chan; + int dma_addr_offset; +}; + +static const struct snd_pcm_hardware sprd_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .period_bytes_min = 1, + .period_bytes_max = 64 * 1024, + .periods_min = 1, + .periods_max = PAGE_SIZE / SPRD_PCM_DMA_LINKLIST_SIZE, + .buffer_bytes_max = 64 * 1024, +}; + +static int sprd_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + struct sprd_pcm_dma_private *dma_private; + int hw_chan = SPRD_PCM_CHANNEL_MAX; + int size, ret, i; + + snd_soc_set_runtime_hwparams(substream, &sprd_pcm_hardware); + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + SPRD_PCM_DMA_BRUST_LEN); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + SPRD_PCM_DMA_BRUST_LEN); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + dma_private = devm_kzalloc(dev, sizeof(*dma_private), GFP_KERNEL); + if (!dma_private) + return -ENOMEM; + + size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE; + + for (i = 0; i < hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + data->virt = dmam_alloc_coherent(dev, size, &data->phys, + GFP_KERNEL); + if (!data->virt) { + ret = -ENOMEM; + goto error; + } + } + + dma_private->hw_chan = hw_chan; + runtime->private_data = dma_private; + dma_private->substream = substream; + + return 0; + +error: + for (i = 0; i < hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->virt) + dmam_free_coherent(dev, size, data->virt, data->phys); + } + + devm_kfree(dev, dma_private); + return ret; +} + +static int sprd_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + int size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE; + int i; + + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + dmam_free_coherent(dev, size, data->virt, data->phys); + } + + devm_kfree(dev, dma_private); + + return 0; +} + +static void sprd_pcm_dma_complete(void *data) +{ + struct sprd_pcm_dma_private *dma_private = data; + struct snd_pcm_substream *substream = dma_private->substream; + + snd_pcm_period_elapsed(substream); +} + +static void sprd_pcm_release_dma_channel(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + int i; + + for (i = 0; i < SPRD_PCM_CHANNEL_MAX; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) { + dma_release_channel(data->chan); + data->chan = NULL; + } + } +} + +static int sprd_pcm_request_dma_channel(struct snd_pcm_substream *substream, + int channels) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + struct sprd_pcm_dma_params *dma_params = dma_private->params; + int i; + + if (channels > SPRD_PCM_CHANNEL_MAX) { + dev_err(dev, "invalid dma channel number:%d\n", channels); + return -EINVAL; + } + + for (i = 0; i < channels; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + data->chan = dma_request_slave_channel(dev, + dma_params->chan_name[i]); + if (!data->chan) { + dev_err(dev, "failed to request dma channel:%s\n", + dma_params->chan_name[i]); + sprd_pcm_release_dma_channel(substream); + return -ENODEV; + } + } + + return 0; +} + +static int sprd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct sprd_pcm_dma_params *dma_params; + size_t totsize = params_buffer_bytes(params); + size_t period = params_period_bytes(params); + int channels = params_channels(params); + int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct scatterlist *sg; + unsigned long flags; + int ret, i, j, sg_num; + + dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dma_params) { + dev_warn(component->dev, "no dma parameters setting\n"); + dma_private->params = NULL; + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = totsize; + return 0; + } + + if (!dma_private->params) { + dma_private->params = dma_params; + ret = sprd_pcm_request_dma_channel(substream, channels); + if (ret) + return ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + runtime->dma_bytes = totsize; + sg_num = totsize / period; + dma_private->dma_addr_offset = totsize / channels; + + sg = devm_kcalloc(component->dev, sg_num, sizeof(*sg), GFP_KERNEL); + if (!sg) { + ret = -ENOMEM; + goto sg_err; + } + + for (i = 0; i < channels; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + struct dma_chan *chan = data->chan; + struct dma_slave_config config = { }; + struct sprd_dma_linklist link = { }; + enum dma_transfer_direction dir; + struct scatterlist *sgt = sg; + + config.src_maxburst = dma_params->fragment_len[i]; + config.src_addr_width = dma_params->datawidth[i]; + config.dst_addr_width = dma_params->datawidth[i]; + if (is_playback) { + config.src_addr = runtime->dma_addr + + i * dma_private->dma_addr_offset; + config.dst_addr = dma_params->dev_phys[i]; + dir = DMA_MEM_TO_DEV; + } else { + config.src_addr = dma_params->dev_phys[i]; + config.dst_addr = runtime->dma_addr + + i * dma_private->dma_addr_offset; + dir = DMA_DEV_TO_MEM; + } + + sg_init_table(sgt, sg_num); + for (j = 0; j < sg_num; j++, sgt++) { + u32 sg_len = period / channels; + + sg_dma_len(sgt) = sg_len; + sg_dma_address(sgt) = runtime->dma_addr + + i * dma_private->dma_addr_offset + sg_len * j; + } + + /* + * Configure the link-list address for the DMA engine link-list + * mode. + */ + link.virt_addr = (unsigned long)data->virt; + link.phy_addr = data->phys; + + ret = dmaengine_slave_config(chan, &config); + if (ret) { + dev_err(component->dev, + "failed to set slave configuration: %d\n", ret); + goto config_err; + } + + /* + * We configure the DMA request mode, interrupt mode, channel + * mode and channel trigger mode by the flags. + */ + flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG, + SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT); + data->desc = chan->device->device_prep_slave_sg(chan, sg, + sg_num, dir, + flags, &link); + if (!data->desc) { + dev_err(component->dev, "failed to prepare slave sg\n"); + ret = -ENOMEM; + goto config_err; + } + + if (!runtime->no_period_wakeup) { + data->desc->callback = sprd_pcm_dma_complete; + data->desc->callback_param = dma_private; + } + } + + devm_kfree(component->dev, sg); + + return 0; + +config_err: + devm_kfree(component->dev, sg); +sg_err: + sprd_pcm_release_dma_channel(substream); + return ret; +} + +static int sprd_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + sprd_pcm_release_dma_channel(substream); + + return 0; +} + +static int sprd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct sprd_pcm_dma_private *dma_private = + substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + int ret = 0, i; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (!data->desc) + continue; + + data->cookie = dmaengine_submit(data->desc); + ret = dma_submit_error(data->cookie); + if (ret) { + dev_err(component->dev, + "failed to submit dma request: %d\n", + ret); + return ret; + } + + dma_async_issue_pending(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_resume(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_STOP: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_terminate_async(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_pause(data->chan); + } + + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + int pointer[SPRD_PCM_CHANNEL_MAX]; + int bytes_of_pointer = 0, sel_max = 0, i; + snd_pcm_uframes_t x; + struct dma_tx_state state; + enum dma_status status; + + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (!data->chan) + continue; + + status = dmaengine_tx_status(data->chan, data->cookie, &state); + if (status == DMA_ERROR) { + dev_err(component->dev, + "failed to get dma channel %d status\n", i); + return 0; + } + + /* + * We just get current transfer address from the DMA engine, so + * we need convert to current pointer. + */ + pointer[i] = state.residue - runtime->dma_addr - + i * dma_private->dma_addr_offset; + + if (i == 0) { + bytes_of_pointer = pointer[i]; + sel_max = pointer[i] < data->pre_pointer ? 1 : 0; + } else { + sel_max ^= pointer[i] < data->pre_pointer ? 1 : 0; + + if (sel_max) + bytes_of_pointer = + max(pointer[i], pointer[i - 1]) << 1; + else + bytes_of_pointer = + min(pointer[i], pointer[i - 1]) << 1; + } + + data->pre_pointer = pointer[i]; + } + + x = bytes_to_frames(runtime, bytes_of_pointer); + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int sprd_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return remap_pfn_range(vma, vma->vm_start, + runtime->dma_addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static struct snd_pcm_ops sprd_pcm_ops = { + .open = sprd_pcm_open, + .close = sprd_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = sprd_pcm_hw_params, + .hw_free = sprd_pcm_hw_free, + .trigger = sprd_pcm_trigger, + .pointer = sprd_pcm_pointer, + .mmap = sprd_pcm_mmap, +}; + +static int sprd_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_substream *substream; + int ret; + + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, + sprd_pcm_hardware.buffer_bytes_max, + &substream->dma_buffer); + if (ret) { + dev_err(card->dev, + "can't alloc playback dma buffer: %d\n", ret); + return ret; + } + } + + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (substream) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, + sprd_pcm_hardware.buffer_bytes_max, + &substream->dma_buffer); + if (ret) { + dev_err(card->dev, + "can't alloc capture dma buffer: %d\n", ret); + snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); + return ret; + } + } + + return 0; +} + +static void sprd_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + int i; + + for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { + substream = pcm->streams[i].substream; + if (substream) { + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } +} + +static const struct snd_soc_component_driver sprd_soc_component = { + .name = DRV_NAME, + .ops = &sprd_pcm_ops, + .pcm_new = sprd_pcm_new, + .pcm_free = sprd_pcm_free, +}; + +static int sprd_soc_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component, + NULL, 0); + if (ret) + dev_err(&pdev->dev, "could not register platform:%d\n", ret); + + return ret; +} + +static const struct of_device_id sprd_pcm_of_match[] = { + { .compatible = "sprd,pcm-platform", }, + { }, +}; +MODULE_DEVICE_TABLE(of, sprd_pcm_of_match); + +static struct platform_driver sprd_pcm_driver = { + .driver = { + .name = "sprd-pcm-audio", + .of_match_table = sprd_pcm_of_match, + }, + + .probe = sprd_soc_platform_probe, +}; + +module_platform_driver(sprd_pcm_driver); + +MODULE_DESCRIPTION("Spreadtrum ASoC PCM DMA"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sprd-audio"); diff --git a/sound/soc/sprd/sprd-pcm-dma.h b/sound/soc/sprd/sprd-pcm-dma.h new file mode 100644 index 000000000000..d85a34f1461d --- /dev/null +++ b/sound/soc/sprd/sprd-pcm-dma.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef __SPRD_PCM_DMA_H +#define __SPRD_PCM_DMA_H + +#define SPRD_PCM_CHANNEL_MAX 2 + +struct sprd_pcm_dma_params { + dma_addr_t dev_phys[SPRD_PCM_CHANNEL_MAX]; + u32 datawidth[SPRD_PCM_CHANNEL_MAX]; + u32 fragment_len[SPRD_PCM_CHANNEL_MAX]; + const char *chan_name[SPRD_PCM_CHANNEL_MAX]; +}; + +#endif /* __SPRD_PCM_DMA_H */ From 515548fdd8a3c579535fe05e3c39558f75158bc5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 30 Jan 2019 17:22:39 +0100 Subject: [PATCH 235/461] ALSA: pcm: remove a superfluous function declaration Declaration of snd_pcm_drop() in sound/core/pcm_native.c is superfluous since the function isn't called before being defined. Remove the declaration. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0bc4aa0ac9cf..672babd20cb1 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1806,8 +1806,6 @@ static const struct action_ops snd_pcm_action_drain_init = { .post_action = snd_pcm_post_drain_init }; -static int snd_pcm_drop(struct snd_pcm_substream *substream); - /* * Drain the stream(s). * When the substream is linked, sync until the draining of all playback streams From 9f7d35d9f7a184ffb591b090b2cbf63d2d599c02 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 Feb 2019 09:48:00 +0100 Subject: [PATCH 236/461] ALSA: hal2: pass struct device to DMA API functions The DMA API generally relies on a struct device to work properly, and only barely works without one for legacy reasons. Pass the easily available struct device from the platform_device to remedy this. Signed-off-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index a4ed54aeaf1d..d63e1565b62b 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -454,21 +454,22 @@ static inline void hal2_stop_adc(struct snd_hal2 *hal2) hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; } -static int hal2_alloc_dmabuf(struct hal2_codec *codec) +static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) { + struct device *dev = hal2->card->dev; struct hal2_desc *desc; dma_addr_t desc_dma, buffer_dma; int count = H2_BUF_SIZE / H2_BLOCK_SIZE; int i; - codec->buffer = dma_alloc_attrs(NULL, H2_BUF_SIZE, &buffer_dma, + codec->buffer = dma_alloc_attrs(dev, H2_BUF_SIZE, &buffer_dma, GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); if (!codec->buffer) return -ENOMEM; - desc = dma_alloc_attrs(NULL, count * sizeof(struct hal2_desc), + desc = dma_alloc_attrs(dev, count * sizeof(struct hal2_desc), &desc_dma, GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); if (!desc) { - dma_free_attrs(NULL, H2_BUF_SIZE, codec->buffer, buffer_dma, + dma_free_attrs(dev, H2_BUF_SIZE, codec->buffer, buffer_dma, DMA_ATTR_NON_CONSISTENT); return -ENOMEM; } @@ -482,17 +483,19 @@ static int hal2_alloc_dmabuf(struct hal2_codec *codec) desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc); desc++; } - dma_cache_sync(NULL, codec->desc, count * sizeof(struct hal2_desc), + dma_cache_sync(dev, codec->desc, count * sizeof(struct hal2_desc), DMA_TO_DEVICE); codec->desc_count = count; return 0; } -static void hal2_free_dmabuf(struct hal2_codec *codec) +static void hal2_free_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) { - dma_free_attrs(NULL, codec->desc_count * sizeof(struct hal2_desc), + struct device *dev = hal2->card->dev; + + dma_free_attrs(dev, codec->desc_count * sizeof(struct hal2_desc), codec->desc, codec->desc_dma, DMA_ATTR_NON_CONSISTENT); - dma_free_attrs(NULL, H2_BUF_SIZE, codec->buffer, codec->buffer_dma, + dma_free_attrs(dev, H2_BUF_SIZE, codec->buffer, codec->buffer_dma, DMA_ATTR_NON_CONSISTENT); } @@ -540,7 +543,7 @@ static int hal2_playback_open(struct snd_pcm_substream *substream) runtime->hw = hal2_pcm_hw; - err = hal2_alloc_dmabuf(&hal2->dac); + err = hal2_alloc_dmabuf(hal2, &hal2->dac); if (err) return err; return 0; @@ -550,7 +553,7 @@ static int hal2_playback_close(struct snd_pcm_substream *substream) { struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - hal2_free_dmabuf(&hal2->dac); + hal2_free_dmabuf(hal2, &hal2->dac); return 0; } @@ -606,7 +609,7 @@ static void hal2_playback_transfer(struct snd_pcm_substream *substream, unsigned char *buf = hal2->dac.buffer + rec->hw_data; memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes); - dma_cache_sync(NULL, buf, bytes, DMA_TO_DEVICE); + dma_cache_sync(hal2->card->dev, buf, bytes, DMA_TO_DEVICE); } @@ -629,7 +632,7 @@ static int hal2_capture_open(struct snd_pcm_substream *substream) runtime->hw = hal2_pcm_hw; - err = hal2_alloc_dmabuf(adc); + err = hal2_alloc_dmabuf(hal2, adc); if (err) return err; return 0; @@ -639,7 +642,7 @@ static int hal2_capture_close(struct snd_pcm_substream *substream) { struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - hal2_free_dmabuf(&hal2->adc); + hal2_free_dmabuf(hal2, &hal2->adc); return 0; } @@ -694,7 +697,7 @@ static void hal2_capture_transfer(struct snd_pcm_substream *substream, struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); unsigned char *buf = hal2->adc.buffer + rec->hw_data; - dma_cache_sync(NULL, buf, bytes, DMA_FROM_DEVICE); + dma_cache_sync(hal2->card->dev, buf, bytes, DMA_FROM_DEVICE); memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes); } From 6a8125c3cab887a236e9b1dc89a3416c50e46f56 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 Feb 2019 09:48:01 +0100 Subject: [PATCH 237/461] ALSA: mips: pass struct device to DMA API functions The DMA API generally relies on a struct device to work properly, and only barely works without one for legacy reasons. Pass the easily available struct device from the platform_device to remedy this. Also use GFP_KERNEL instead of GFP_USER as the gfp_t for the memory allocation, as we should treat this allocation as a normal kernel one. Signed-off-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 3ec9391a4736..53a4ee01c522 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -805,7 +805,7 @@ static int snd_sgio2audio_free(struct snd_sgio2audio *chip) free_irq(snd_sgio2_isr_table[i].irq, &chip->channel[snd_sgio2_isr_table[i].idx]); - dma_free_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, + dma_free_coherent(chip->card->dev, MACEISA_RINGBUFFERS_SIZE, chip->ring_base, chip->ring_base_dma); /* release card data */ @@ -843,8 +843,9 @@ static int snd_sgio2audio_create(struct snd_card *card, chip->card = card; - chip->ring_base = dma_alloc_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, - &chip->ring_base_dma, GFP_USER); + chip->ring_base = dma_alloc_coherent(card->dev, + MACEISA_RINGBUFFERS_SIZE, + &chip->ring_base_dma, GFP_KERNEL); if (chip->ring_base == NULL) { printk(KERN_ERR "sgio2audio: could not allocate ring buffers\n"); From 0b6a2c9cf4a00f54a0916499ece8a5cf3cced385 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Feb 2019 12:14:53 +0100 Subject: [PATCH 238/461] ALSA: isa: Avoid passing NULL to memory allocators We used to pass NULL to memory allocators for ISA devices due to historical reasons. But we prefer rather a proper device object to be assigned, so let's fix it by replacing snd_dma_isa_data() call with card->dev reference, and kill snd_dma_isa_data() definition. Reviewed-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- .../sound/kernel-api/writing-an-alsa-driver.rst | 10 +++++----- include/sound/memalloc.h | 1 - sound/isa/ad1816a/ad1816a_lib.c | 2 +- sound/isa/cmi8330.c | 2 +- sound/isa/es1688/es1688_lib.c | 2 +- sound/isa/es18xx.c | 2 +- sound/isa/gus/gus_pcm.c | 4 ++-- sound/isa/sb/sb16_main.c | 2 +- sound/isa/sb/sb8_main.c | 2 +- sound/isa/sscape.c | 7 ++++--- sound/isa/wss/wss_lib.c | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 7c2f2032d30a..6b154dbb02cc 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3520,14 +3520,14 @@ allocator will try to get an area as large as possible within the given size. The second argument (type) and the third argument (device pointer) are -dependent on the bus. In the case of the ISA bus, pass -:c:func:`snd_dma_isa_data()` as the third argument with +dependent on the bus. For normal devices, pass the device pointer +(typically identical as ``card->dev``) to the third argument with ``SNDRV_DMA_TYPE_DEV`` type. For the continuous buffer unrelated to the bus can be pre-allocated with ``SNDRV_DMA_TYPE_CONTINUOUS`` type and the ``snd_dma_continuous_data(GFP_KERNEL)`` device pointer, where -``GFP_KERNEL`` is the kernel allocation flag to use. For the PCI -scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with -``snd_dma_pci_data(pci)`` (see the `Non-Contiguous Buffers`_ +``GFP_KERNEL`` is the kernel allocation flag to use. For the +scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with the device +pointer (see the `Non-Contiguous Buffers`_ section). Once the buffer is pre-allocated, you can use the allocator in the diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index af3fa577fa06..1ac0dd82a916 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -37,7 +37,6 @@ struct snd_dma_device { }; #define snd_dma_pci_data(pci) (&(pci)->dev) -#define snd_dma_isa_data() NULL #define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x)) diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 61e8c7e524db..94b381a78e9e 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -693,7 +693,7 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) snd_ad1816a_init(chip); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + chip->card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 7e5aa06414c4..1868b73aa49c 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -470,7 +470,7 @@ static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->streams[SNDRV_PCM_STREAM_CAPTURE].ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 128*1024); chip->pcm = pcm; diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 50cdce0e8946..da341969e650 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -746,7 +746,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 64*1024); return 0; } diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 77aa9a27fb3b..07abc7f7840c 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1717,7 +1717,7 @@ static int snd_es18xx_pcm(struct snd_card *card, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); return 0; diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 131b28997e1d..b9efc6dff45d 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -891,7 +891,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024); pcm->info_flags = 0; @@ -901,7 +901,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) if (gus->gf1.dma2 == gus->gf1.dma1) pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, - SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + SNDRV_DMA_TYPE_DEV, card->dev, 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024); } strcpy(pcm->name, pcm->id); diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 981d65d122b6..473ec74ae48c 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -889,7 +889,7 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device) } snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 128*1024); return 0; } diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 8288fae90085..97645a732a71 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -610,7 +610,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device) if (chip->dma8 > 3 || chip->dma16 >= 0) max_prealloc = 128 * 1024; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, max_prealloc); return 0; diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 733adee5afbf..8181db4db019 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -167,12 +167,13 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, +static struct snd_dma_buffer *get_dmabuf(struct soundscape *s, + struct snd_dma_buffer *buf, unsigned long size) { if (buf) { if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + s->chip->card->dev, size, buf) < 0) { snd_printk(KERN_ERR "sscape: Failed to allocate " "%lu bytes for DMA\n", @@ -443,7 +444,7 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data, int ret; unsigned char val; - if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) + if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; spin_lock_irqsave(&s->lock, flags); diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index b11ef97bce1b..0dfb8065b403 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1942,7 +1942,7 @@ int snd_wss_pcm(struct snd_wss *chip, int device) strcpy(pcm->name, snd_wss_chip_id(chip)); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + chip->card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; From f497c88b195eaee8733a304f2a1dc27fb319c9c3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:46:27 +0900 Subject: [PATCH 239/461] ASoC: rsnd: synchronize connection check for simple-card/audio-graph Current rsnd driver has below function to check connection rsnd_parse_connect_simple() rsnd_parse_connect_graph() But these have different parameters. This patch synchronize these for cleanup. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 59e250cc2e9d..2a48d8a6cc76 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1032,16 +1032,13 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { }; static void rsnd_parse_connect_simple(struct rsnd_priv *priv, - struct device_node *dai_np, - int dai_i, int is_play) + struct rsnd_dai_stream *io, + struct device_node *dai_np) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); - struct rsnd_dai_stream *io = is_play ? - &rdai->playback : - &rdai->capture; struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); struct device_node *np; + int is_play = rsnd_io_is_play(io); int i, j; if (!ssiu_np) @@ -1292,8 +1289,10 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_child_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); if (rsnd_is_gen3(priv)) { - rsnd_parse_connect_simple(priv, dai_np, dai_i, 1); - rsnd_parse_connect_simple(priv, dai_np, dai_i, 0); + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); } dai_i++; } From 2264cf2e5db99cdff995592bf80ab6dea567ea91 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:47:25 +0900 Subject: [PATCH 240/461] ASoC: rsnd: fixup TDM Split mode check for CTU Renesas sound card need to judge that whether it is using "TDM Split mode". To judge it and for other purpose, it has rsnd_parse_connect_simple() and rsnd_parse_connect_graph(), but these are using different judgement policy for TDM Split mode. It is pointless and confusable. This patch add new rsnd_parse_tdm_split_mode() and use common judgement policy for simple-card/audio-graph. Without this patch, CTU will be judged as TDM Split mode on audio-graph card. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 2a48d8a6cc76..2c2c60a3f276 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1031,7 +1031,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .prepare = rsnd_soc_dai_prepare, }; -static void rsnd_parse_connect_simple(struct rsnd_priv *priv, +static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) { @@ -1044,9 +1044,6 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, if (!ssiu_np) return; - if (!rsnd_io_to_mod_ssi(io)) - return; - /* * This driver assumes that it is TDM Split mode * if it includes ssiu node @@ -1071,12 +1068,21 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, } } +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *dai_np) +{ + if (!rsnd_io_to_mod_ssi(io)) + return; + + rsnd_parse_tdm_split_mode(priv, io, dai_np); +} + static void rsnd_parse_connect_graph(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *endpoint) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_port = of_graph_get_remote_port(endpoint); struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); if (!rsnd_io_to_mod_ssi(io)) @@ -1094,14 +1100,7 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, dev_dbg(dev, "%s connected to HDMI1\n", io->name); } - /* - * This driver assumes that it is TDM Split mode - * if remote node has multi endpoint - */ - if (of_get_child_count(remote_port) > 1) { - rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); - dev_dbg(dev, "%s is part of TDM Split\n", io->name); - } + rsnd_parse_tdm_split_mode(priv, io, endpoint); } void rsnd_parse_connect_common(struct rsnd_dai *rdai, From 909d74e39fe18e145a15ba3638f764e7ac3382c1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:19 +0000 Subject: [PATCH 241/461] ASoC: arizona: Add channel numbers to AIFs Set the channel number on each AIF widget to allow unused channels not to be powered up across AIFs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 52 ++++++++++++------------- sound/soc/codecs/wm5102.c | 64 +++++++++++++++--------------- sound/soc/codecs/wm5110.c | 80 +++++++++++++++++++------------------- sound/soc/codecs/wm8997.c | 60 ++++++++++++++-------------- sound/soc/codecs/wm8998.c | 60 ++++++++++++++-------------- 5 files changed, 158 insertions(+), 158 deletions(-) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 45e50fe3bf25..b16832a6a9af 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -500,72 +500,72 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 7e817e1877c2..4466e195b66d 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1214,105 +1214,105 @@ SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b0789a03d699..b25877fa529d 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1348,122 +1348,122 @@ SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index df5b36b8fc5a..33e3dc1a1367 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -516,95 +516,95 @@ SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 409bed30a4e4..125fc32ad92a 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -626,96 +626,96 @@ SND_SOC_DAPM_MUX("AEC2 Loopback", ARIZONA_DAC_AEC_CONTROL_2, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, From 425da20a98e0ab6ba6b37ff00ab50519d7dd7740 Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Wed, 30 Jan 2019 14:47:11 +0800 Subject: [PATCH 242/461] ASoC: mediatek: add documents for btcvsd driver document for btcvsd driver Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- .../bindings/sound/mtk-btcvsd-snd.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt new file mode 100644 index 000000000000..679e44839b48 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt @@ -0,0 +1,24 @@ +Mediatek ALSA BT SCO CVSD/MSBC Driver + +Required properties: +- compatible = "mediatek,mtk-btcvsd-snd"; +- reg: register location and size of PKV and SRAM_BANK2 +- interrupts: should contain BTSCO interrupt +- mediatek,infracfg: the phandles of INFRASYS +- mediatek,offset: Array contains of register offset and mask + infra_misc_offset, + infra_conn_bt_cvsd_mask, + cvsd_mcu_read_offset, + cvsd_mcu_write_offset, + cvsd_packet_indicator_offset + +Example: + + mtk-btcvsd-snd@18000000 { + compatible = "mediatek,mtk-btcvsd-snd"; + reg=<0 0x18000000 0 0x1000>, + <0 0x18080000 0 0x8000>; + interrupts = ; + mediatek,infracfg = <&infrasys>; + mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>; + }; From 4bd8597dc36c376a2bb1ef2c72984615bdeb68de Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Wed, 30 Jan 2019 14:47:10 +0800 Subject: [PATCH 243/461] ASoC: mediatek: add btcvsd driver The driver function for transferring/receiving BT encoded data to/from BT firmware. Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 9 + sound/soc/mediatek/common/Makefile | 2 + sound/soc/mediatek/common/mtk-btcvsd.c | 1364 ++++++++++++++++++++++++ 3 files changed, 1375 insertions(+) create mode 100644 sound/soc/mediatek/common/mtk-btcvsd.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 8bb360ee7234..b35410e4020e 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -115,3 +115,12 @@ config SND_SOC_MT8183 that can be used with other codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MTK_BTCVSD + tristate "ALSA BT SCO CVSD/MSBC Driver" + help + This is for software BTCVSD. This enable + the function for transferring/receiving + BT encoded data to/from BT firmware. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index cdadabc5fd16..9ab90433a8d7 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -2,3 +2,5 @@ # platform driver snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o + +obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o \ No newline at end of file diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c new file mode 100644 index 000000000000..349a9120a0dd --- /dev/null +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -0,0 +1,1364 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA BT SCO CVSD/MSBC Driver +// +// Copyright (c) 2019 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include + +#include + +#define BTCVSD_SND_NAME "mtk-btcvsd-snd" + +#define BT_CVSD_TX_NREADY BIT(21) +#define BT_CVSD_RX_READY BIT(22) +#define BT_CVSD_TX_UNDERFLOW BIT(23) +#define BT_CVSD_RX_OVERFLOW BIT(24) +#define BT_CVSD_INTERRUPT BIT(31) + +#define BT_CVSD_CLEAR \ + (BT_CVSD_TX_NREADY | BT_CVSD_RX_READY | BT_CVSD_TX_UNDERFLOW |\ + BT_CVSD_RX_OVERFLOW | BT_CVSD_INTERRUPT) + +/* TX */ +#define SCO_TX_ENCODE_SIZE (60) +/* 18 = 6 * 180 / SCO_TX_ENCODE_SIZE */ +#define SCO_TX_PACKER_BUF_NUM (18) + +/* RX */ +#define SCO_RX_PLC_SIZE (30) +#define SCO_RX_PACKER_BUF_NUM (64) +#define SCO_RX_PACKET_MASK (0x3F) + +#define SCO_CVSD_PACKET_VALID_SIZE 2 + +#define SCO_PACKET_120 120 +#define SCO_PACKET_180 180 + +#define BTCVSD_RX_PACKET_SIZE (SCO_RX_PLC_SIZE + SCO_CVSD_PACKET_VALID_SIZE) +#define BTCVSD_TX_PACKET_SIZE (SCO_TX_ENCODE_SIZE) + +#define BTCVSD_RX_BUF_SIZE (BTCVSD_RX_PACKET_SIZE * SCO_RX_PACKER_BUF_NUM) +#define BTCVSD_TX_BUF_SIZE (BTCVSD_TX_PACKET_SIZE * SCO_TX_PACKER_BUF_NUM) + +enum bt_sco_state { + BT_SCO_STATE_IDLE, + BT_SCO_STATE_RUNNING, + BT_SCO_STATE_ENDING, +}; + +enum bt_sco_direct { + BT_SCO_DIRECT_BT2ARM, + BT_SCO_DIRECT_ARM2BT, +}; + +enum bt_sco_packet_len { + BT_SCO_CVSD_30 = 0, + BT_SCO_CVSD_60, + BT_SCO_CVSD_90, + BT_SCO_CVSD_120, + BT_SCO_CVSD_10, + BT_SCO_CVSD_20, + BT_SCO_CVSD_MAX, +}; + +enum BT_SCO_BAND { + BT_SCO_NB, + BT_SCO_WB, +}; + +struct mtk_btcvsd_snd_hw_info { + unsigned int num_valid_addr; + unsigned long bt_sram_addr[20]; + unsigned int packet_length; + unsigned int packet_num; +}; + +struct mtk_btcvsd_snd_stream { + struct snd_pcm_substream *substream; + int stream; + + enum bt_sco_state state; + + unsigned int packet_size; + unsigned int buf_size; + u8 temp_packet_buf[SCO_PACKET_180]; + + int packet_w; + int packet_r; + snd_pcm_uframes_t prev_frame; + int prev_packet_idx; + + unsigned int xrun:1; + unsigned int timeout:1; + unsigned int mute:1; + unsigned int trigger_start:1; + unsigned int wait_flag:1; + unsigned int rw_cnt; + + unsigned long long time_stamp; + unsigned long long buf_data_equivalent_time; + + struct mtk_btcvsd_snd_hw_info buffer_info; +}; + +struct mtk_btcvsd_snd { + struct device *dev; + int irq_id; + + struct regmap *infra; + void __iomem *bt_pkv_base; + void __iomem *bt_sram_bank2_base; + + unsigned int infra_misc_offset; + unsigned int conn_bt_cvsd_mask; + unsigned int cvsd_mcu_read_offset; + unsigned int cvsd_mcu_write_offset; + unsigned int cvsd_packet_indicator; + + u32 *bt_reg_pkt_r; + u32 *bt_reg_pkt_w; + u32 *bt_reg_ctl; + + unsigned int irq_disabled:1; + + spinlock_t tx_lock; /* spinlock for bt tx stream control */ + spinlock_t rx_lock; /* spinlock for bt rx stream control */ + wait_queue_head_t tx_wait; + wait_queue_head_t rx_wait; + + struct mtk_btcvsd_snd_stream *tx; + struct mtk_btcvsd_snd_stream *rx; + u8 tx_packet_buf[BTCVSD_TX_BUF_SIZE]; + u8 rx_packet_buf[BTCVSD_RX_BUF_SIZE]; + + enum BT_SCO_BAND band; +}; + +struct mtk_btcvsd_snd_time_buffer_info { + unsigned long long data_count_equi_time; + unsigned long long time_stamp_us; +}; + +static const unsigned int btsco_packet_valid_mask[BT_SCO_CVSD_MAX][6] = { + {0x1, 0x1 << 1, 0x1 << 2, 0x1 << 3, 0x1 << 4, 0x1 << 5}, + {0x1, 0x1, 0x2, 0x2, 0x4, 0x4}, + {0x1, 0x1, 0x1, 0x2, 0x2, 0x2}, + {0x1, 0x1, 0x1, 0x1, 0x0, 0x0}, + {0x7, 0x7 << 3, 0x7 << 6, 0x7 << 9, 0x7 << 12, 0x7 << 15}, + {0x3, 0x3 << 1, 0x3 << 3, 0x3 << 4, 0x3 << 6, 0x3 << 7}, +}; + +static const unsigned int btsco_packet_info[BT_SCO_CVSD_MAX][4] = { + {30, 6, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {60, 3, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {90, 2, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {120, 1, SCO_PACKET_120 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_120 / SCO_RX_PLC_SIZE}, + {10, 18, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {20, 9, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, +}; + +static const u8 table_msbc_silence[SCO_PACKET_180] = { + 0x01, 0x38, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00, + 0x01, 0xc8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00, + 0x01, 0xf8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00 +}; + +static void mtk_btcvsd_snd_irq_enable(struct mtk_btcvsd_snd *bt) +{ + regmap_update_bits(bt->infra, bt->infra_misc_offset, + bt->conn_bt_cvsd_mask, bt->conn_bt_cvsd_mask); +} + +static void mtk_btcvsd_snd_irq_disable(struct mtk_btcvsd_snd *bt) +{ + regmap_update_bits(bt->infra, bt->infra_misc_offset, + bt->conn_bt_cvsd_mask, 0); +} + +static void mtk_btcvsd_snd_set_state(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_stream *bt_stream, + int state) +{ + dev_dbg(bt->dev, "%s(), stream %d, state %d, tx->state %d, rx->state %d, irq_disabled %d\n", + __func__, + bt_stream->stream, state, + bt->tx->state, bt->rx->state, bt->irq_disabled); + + bt_stream->state = state; + + if (bt->tx->state == BT_SCO_STATE_IDLE && + bt->rx->state == BT_SCO_STATE_IDLE) { + if (!bt->irq_disabled) { + disable_irq(bt->irq_id); + mtk_btcvsd_snd_irq_disable(bt); + bt->irq_disabled = 1; + } + } else { + if (bt->irq_disabled) { + enable_irq(bt->irq_id); + mtk_btcvsd_snd_irq_enable(bt); + bt->irq_disabled = 0; + } + } +} + +static int mtk_btcvsd_snd_tx_init(struct mtk_btcvsd_snd *bt) +{ + memset(bt->tx, 0, sizeof(*bt->tx)); + memset(bt->tx_packet_buf, 0, sizeof(bt->tx_packet_buf)); + + bt->tx->packet_size = BTCVSD_TX_PACKET_SIZE; + bt->tx->buf_size = BTCVSD_TX_BUF_SIZE; + bt->tx->timeout = 0; + bt->tx->rw_cnt = 0; + bt->tx->stream = SNDRV_PCM_STREAM_PLAYBACK; + return 0; +} + +static int mtk_btcvsd_snd_rx_init(struct mtk_btcvsd_snd *bt) +{ + memset(bt->rx, 0, sizeof(*bt->rx)); + memset(bt->rx_packet_buf, 0, sizeof(bt->rx_packet_buf)); + + bt->rx->packet_size = BTCVSD_RX_PACKET_SIZE; + bt->rx->buf_size = BTCVSD_RX_BUF_SIZE; + bt->rx->timeout = 0; + bt->rx->rw_cnt = 0; + bt->tx->stream = SNDRV_PCM_STREAM_CAPTURE; + return 0; +} + +static void get_tx_time_stamp(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_time_buffer_info *ts) +{ + ts->time_stamp_us = bt->tx->time_stamp; + ts->data_count_equi_time = bt->tx->buf_data_equivalent_time; +} + +static void get_rx_time_stamp(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_time_buffer_info *ts) +{ + ts->time_stamp_us = bt->rx->time_stamp; + ts->data_count_equi_time = bt->rx->buf_data_equivalent_time; +} + +static int btcvsd_bytes_to_frame(struct snd_pcm_substream *substream, + int bytes) +{ + int count = bytes; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime->format == SNDRV_PCM_FORMAT_S32_LE || + runtime->format == SNDRV_PCM_FORMAT_U32_LE) + count = count >> 2; + else + count = count >> 1; + + count = count / runtime->channels; + return count; +} + +static void mtk_btcvsd_snd_data_transfer(enum bt_sco_direct dir, + u8 *src, u8 *dst, + unsigned int blk_size, + unsigned int blk_num) +{ + unsigned int i, j; + + if (blk_size == 60 || blk_size == 120 || blk_size == 20) { + u32 *src_32 = (u32 *)src; + u32 *dst_32 = (u32 *)dst; + + for (i = 0; i < (blk_size * blk_num / 4); i++) + *dst_32++ = *src_32++; + } else { + u16 *src_16 = (u16 *)src; + u16 *dst_16 = (u16 *)dst; + + for (j = 0; j < blk_num; j++) { + for (i = 0; i < (blk_size / 2); i++) + *dst_16++ = *src_16++; + + if (dir == BT_SCO_DIRECT_BT2ARM) + src_16++; + else + dst_16++; + } + } +} + +/* write encoded mute data to bt sram */ +static int btcvsd_tx_clean_buffer(struct mtk_btcvsd_snd *bt) +{ + unsigned int i; + unsigned int num_valid_addr; + unsigned long flags; + enum BT_SCO_BAND band = bt->band; + + /* prepare encoded mute data */ + if (band == BT_SCO_NB) + memset(bt->tx->temp_packet_buf, 170, SCO_PACKET_180); + else + memcpy(bt->tx->temp_packet_buf, + table_msbc_silence, SCO_PACKET_180); + + /* write mute data to bt tx sram buffer */ + spin_lock_irqsave(&bt->tx_lock, flags); + num_valid_addr = bt->tx->buffer_info.num_valid_addr; + + dev_info(bt->dev, "%s(), band %d, num_valid_addr %u\n", + __func__, band, num_valid_addr); + + for (i = 0; i < num_valid_addr; i++) { + void *dst; + + dev_info(bt->dev, "%s(), clean addr 0x%lx\n", __func__, + bt->tx->buffer_info.bt_sram_addr[i]); + + dst = (void *)bt->tx->buffer_info.bt_sram_addr[i]; + + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT, + bt->tx->temp_packet_buf, dst, + bt->tx->buffer_info.packet_length, + bt->tx->buffer_info.packet_num); + } + spin_unlock_irqrestore(&bt->tx_lock, flags); + + return 0; +} + +static int mtk_btcvsd_read_from_bt(struct mtk_btcvsd_snd *bt, + enum bt_sco_packet_len packet_type, + unsigned int packet_length, + unsigned int packet_num, + unsigned int blk_size, + unsigned int control) +{ + unsigned int i; + int pv; + u8 *src; + unsigned int packet_buf_ofs; + unsigned long flags; + unsigned long connsys_addr_rx, ap_addr_rx; + + connsys_addr_rx = *bt->bt_reg_pkt_r; + ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base + + (connsys_addr_rx & 0xFFFF); + + if (connsys_addr_rx == 0xdeadfeed) { + /* bt return 0xdeadfeed if read register during bt sleep */ + dev_warn(bt->dev, "%s(), connsys_addr_rx == 0xdeadfeed", + __func__); + return -EIO; + } + + src = (u8 *)ap_addr_rx; + + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src, + bt->rx->temp_packet_buf, packet_length, + packet_num); + + spin_lock_irqsave(&bt->rx_lock, flags); + for (i = 0; i < blk_size; i++) { + packet_buf_ofs = (bt->rx->packet_w & SCO_RX_PACKET_MASK) * + bt->rx->packet_size; + memcpy(bt->rx_packet_buf + packet_buf_ofs, + bt->rx->temp_packet_buf + (SCO_RX_PLC_SIZE * i), + SCO_RX_PLC_SIZE); + if ((control & btsco_packet_valid_mask[packet_type][i]) == + btsco_packet_valid_mask[packet_type][i]) + pv = 1; + else + pv = 0; + + packet_buf_ofs += SCO_RX_PLC_SIZE; + memcpy(bt->rx_packet_buf + packet_buf_ofs, (void *)&pv, + SCO_CVSD_PACKET_VALID_SIZE); + bt->rx->packet_w++; + } + spin_unlock_irqrestore(&bt->rx_lock, flags); + return 0; +} + +int mtk_btcvsd_write_to_bt(struct mtk_btcvsd_snd *bt, + enum bt_sco_packet_len packet_type, + unsigned int packet_length, + unsigned int packet_num, + unsigned int blk_size) +{ + unsigned int i; + unsigned long flags; + u8 *dst; + unsigned long connsys_addr_tx, ap_addr_tx; + bool new_ap_addr_tx = true; + + connsys_addr_tx = *bt->bt_reg_pkt_w; + ap_addr_tx = (unsigned long)bt->bt_sram_bank2_base + + (connsys_addr_tx & 0xFFFF); + + if (connsys_addr_tx == 0xdeadfeed) { + /* bt return 0xdeadfeed if read register during bt sleep */ + dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n", + __func__); + return -EIO; + } + + spin_lock_irqsave(&bt->tx_lock, flags); + for (i = 0; i < blk_size; i++) { + memcpy(bt->tx->temp_packet_buf + (bt->tx->packet_size * i), + (bt->tx_packet_buf + + (bt->tx->packet_r % SCO_TX_PACKER_BUF_NUM) * + bt->tx->packet_size), + bt->tx->packet_size); + + bt->tx->packet_r++; + } + spin_unlock_irqrestore(&bt->tx_lock, flags); + + dst = (u8 *)ap_addr_tx; + + if (!bt->tx->mute) { + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT, + bt->tx->temp_packet_buf, dst, + packet_length, packet_num); + } + + /* store bt tx buffer sram info */ + bt->tx->buffer_info.packet_length = packet_length; + bt->tx->buffer_info.packet_num = packet_num; + for (i = 0; i < bt->tx->buffer_info.num_valid_addr; i++) { + if (bt->tx->buffer_info.bt_sram_addr[i] == ap_addr_tx) { + new_ap_addr_tx = false; + break; + } + } + if (new_ap_addr_tx) { + unsigned int next_idx; + + spin_lock_irqsave(&bt->tx_lock, flags); + bt->tx->buffer_info.num_valid_addr++; + next_idx = bt->tx->buffer_info.num_valid_addr - 1; + bt->tx->buffer_info.bt_sram_addr[next_idx] = ap_addr_tx; + spin_unlock_irqrestore(&bt->tx_lock, flags); + dev_info(bt->dev, "%s(), new ap_addr_tx = 0x%lx, num_valid_addr %d\n", + __func__, ap_addr_tx, + bt->tx->buffer_info.num_valid_addr); + } + + if (bt->tx->mute) + btcvsd_tx_clean_buffer(bt); + + return 0; +} + +static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev) +{ + struct mtk_btcvsd_snd *bt = dev; + unsigned int packet_type, packet_num, packet_length; + unsigned int buf_cnt_tx, buf_cnt_rx, control; + + if (bt->rx->state != BT_SCO_STATE_RUNNING && + bt->rx->state != BT_SCO_STATE_ENDING && + bt->tx->state != BT_SCO_STATE_RUNNING && + bt->tx->state != BT_SCO_STATE_ENDING) { + dev_warn(bt->dev, "%s(), in idle state: rx->state: %d, tx->state: %d\n", + __func__, bt->rx->state, bt->tx->state); + goto irq_handler_exit; + } + + control = *bt->bt_reg_ctl; + packet_type = (control >> 18) & 0x7; + + if (((control >> 31) & 1) == 0) { + dev_warn(bt->dev, "%s(), ((control >> 31) & 1) == 0, control 0x%x\n", + __func__, control); + goto irq_handler_exit; + } + + if (packet_type >= BT_SCO_CVSD_MAX) { + dev_warn(bt->dev, "%s(), invalid packet_type %u, exit\n", + __func__, packet_type); + goto irq_handler_exit; + } + + packet_length = btsco_packet_info[packet_type][0]; + packet_num = btsco_packet_info[packet_type][1]; + buf_cnt_tx = btsco_packet_info[packet_type][2]; + buf_cnt_rx = btsco_packet_info[packet_type][3]; + + if (bt->rx->state == BT_SCO_STATE_RUNNING || + bt->rx->state == BT_SCO_STATE_ENDING) { + if (bt->rx->xrun) { + if (bt->rx->packet_w - bt->rx->packet_r <= + SCO_RX_PACKER_BUF_NUM - 2 * buf_cnt_rx) { + /* + * free space is larger then + * twice interrupt rx data size + */ + bt->rx->xrun = 0; + dev_warn(bt->dev, "%s(), rx->xrun 0!\n", + __func__); + } + } + + if (!bt->rx->xrun && + (bt->rx->packet_w - bt->rx->packet_r <= + SCO_RX_PACKER_BUF_NUM - buf_cnt_rx)) { + mtk_btcvsd_read_from_bt(bt, + packet_type, + packet_length, + packet_num, + buf_cnt_rx, + control); + bt->rx->rw_cnt++; + } else { + bt->rx->xrun = 1; + dev_warn(bt->dev, "%s(), rx->xrun 1\n", __func__); + } + } + + /* tx */ + bt->tx->timeout = 0; + if ((bt->tx->state == BT_SCO_STATE_RUNNING || + bt->tx->state == BT_SCO_STATE_ENDING) && + bt->tx->trigger_start) { + if (bt->tx->xrun) { + /* prepared data is larger then twice + * interrupt tx data size + */ + if (bt->tx->packet_w - bt->tx->packet_r >= + 2 * buf_cnt_tx) { + bt->tx->xrun = 0; + dev_warn(bt->dev, "%s(), tx->xrun 0\n", + __func__); + } + } + + if ((!bt->tx->xrun && + (bt->tx->packet_w - bt->tx->packet_r >= buf_cnt_tx)) || + bt->tx->state == BT_SCO_STATE_ENDING) { + mtk_btcvsd_write_to_bt(bt, + packet_type, + packet_length, + packet_num, + buf_cnt_tx); + bt->tx->rw_cnt++; + } else { + bt->tx->xrun = 1; + dev_warn(bt->dev, "%s(), tx->xrun 1\n", __func__); + } + } + + *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR; + + if (bt->rx->state == BT_SCO_STATE_RUNNING || + bt->rx->state == BT_SCO_STATE_ENDING) { + bt->rx->wait_flag = 1; + wake_up_interruptible(&bt->rx_wait); + snd_pcm_period_elapsed(bt->rx->substream); + } + if (bt->tx->state == BT_SCO_STATE_RUNNING || + bt->tx->state == BT_SCO_STATE_ENDING) { + bt->tx->wait_flag = 1; + wake_up_interruptible(&bt->tx_wait); + snd_pcm_period_elapsed(bt->tx->substream); + } + + return IRQ_HANDLED; +irq_handler_exit: + *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR; + return IRQ_HANDLED; +} + +static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_stream *bt_stream) +{ + unsigned long long t1, t2; + /* one interrupt period = 22.5ms */ + unsigned long long timeout_limit = 22500000; + int max_timeout_trial = 2; + int ret; + + bt_stream->wait_flag = 0; + + while (max_timeout_trial && !bt_stream->wait_flag) { + t1 = sched_clock(); + if (bt_stream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = wait_event_interruptible_timeout(bt->tx_wait, + bt_stream->wait_flag, + nsecs_to_jiffies(timeout_limit)); + } else { + ret = wait_event_interruptible_timeout(bt->rx_wait, + bt_stream->wait_flag, + nsecs_to_jiffies(timeout_limit)); + } + + t2 = sched_clock(); + t2 = t2 - t1; /* in ns (10^9) */ + + if (t2 > timeout_limit) { + dev_warn(bt->dev, "%s(), stream %d, timeout %llu, limit %llu, ret %d, flag %d\n", + __func__, bt_stream->stream, + t2, timeout_limit, ret, + bt_stream->wait_flag); + } + + if (ret < 0) { + /* + * error, -ERESTARTSYS if it was interrupted by + * a signal + */ + dev_warn(bt->dev, "%s(), stream %d, error, trial left %d\n", + __func__, + bt_stream->stream, max_timeout_trial); + + bt_stream->timeout = 1; + return ret; + } else if (ret == 0) { + /* conidtion is false after timeout */ + max_timeout_trial--; + dev_warn(bt->dev, "%s(), stream %d, error, timeout, condition is false, trial left %d\n", + __func__, + bt_stream->stream, max_timeout_trial); + + if (max_timeout_trial <= 0) { + bt_stream->timeout = 1; + return -ETIME; + } + } + } + + return 0; +} + +ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, + char __user *buf, + size_t count) +{ + ssize_t read_size = 0, read_count = 0, cur_read_idx, cont; + unsigned int cur_buf_ofs = 0; + unsigned long avail; + unsigned long flags; + unsigned int packet_size = bt->rx->packet_size; + + while (count) { + spin_lock_irqsave(&bt->rx_lock, flags); + /* available data in RX packet buffer */ + avail = (bt->rx->packet_w - bt->rx->packet_r) * packet_size; + + cur_read_idx = (bt->rx->packet_r & SCO_RX_PACKET_MASK) * + packet_size; + spin_unlock_irqrestore(&bt->rx_lock, flags); + + if (!avail) { + int ret = wait_for_bt_irq(bt, bt->rx); + + if (ret) + return read_count; + + continue; + } + + /* count must be multiple of packet_size */ + if (count % packet_size != 0 || + avail % packet_size != 0) { + dev_warn(bt->dev, "%s(), count %zu or d %lu is not multiple of packet_size %dd\n", + __func__, count, avail, packet_size); + + count -= count % packet_size; + avail -= avail % packet_size; + } + + if (count > avail) + read_size = avail; + else + read_size = count; + + /* calculate continue space */ + cont = bt->rx->buf_size - cur_read_idx; + if (read_size > cont) + read_size = cont; + + if (copy_to_user(buf + cur_buf_ofs, + bt->rx_packet_buf + cur_read_idx, + read_size)) { + dev_warn(bt->dev, "%s(), copy_to_user fail\n", + __func__); + return -EFAULT; + } + + spin_lock_irqsave(&bt->rx_lock, flags); + bt->rx->packet_r += read_size / packet_size; + spin_unlock_irqrestore(&bt->rx_lock, flags); + + read_count += read_size; + cur_buf_ofs += read_size; + count -= read_size; + } + + /* + * save current timestamp & buffer time in times_tamp and + * buf_data_equivalent_time + */ + bt->rx->time_stamp = sched_clock(); + bt->rx->buf_data_equivalent_time = + (unsigned long long)(bt->rx->packet_w - bt->rx->packet_r) * + SCO_RX_PLC_SIZE * 16 * 1000 / 2 / 64; + bt->rx->buf_data_equivalent_time += read_count * SCO_RX_PLC_SIZE * + 16 * 1000 / packet_size / 2 / 64; + /* return equivalent time(us) to data count */ + bt->rx->buf_data_equivalent_time *= 1000; + + return read_count; +} + +ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, + char __user *buf, + size_t count) +{ + int written_size = count, avail = 0, cur_write_idx, write_size, cont; + unsigned int cur_buf_ofs = 0; + unsigned long flags; + unsigned int packet_size = bt->tx->packet_size; + + /* + * save current timestamp & buffer time in time_stamp and + * buf_data_equivalent_time + */ + bt->tx->time_stamp = sched_clock(); + bt->tx->buf_data_equivalent_time = + (unsigned long long)(bt->tx->packet_w - bt->tx->packet_r) * + packet_size * 16 * 1000 / 2 / 64; + + /* return equivalent time(us) to data count */ + bt->tx->buf_data_equivalent_time *= 1000; + + while (count) { + spin_lock_irqsave(&bt->tx_lock, flags); + /* free space of TX packet buffer */ + avail = bt->tx->buf_size - + (bt->tx->packet_w - bt->tx->packet_r) * packet_size; + + cur_write_idx = (bt->tx->packet_w % SCO_TX_PACKER_BUF_NUM) * + packet_size; + spin_unlock_irqrestore(&bt->tx_lock, flags); + + if (!avail) { + int ret = wait_for_bt_irq(bt, bt->rx); + + if (ret) + return written_size; + + continue; + } + + /* count must be multiple of bt->tx->packet_size */ + if (count % packet_size != 0 || + avail % packet_size != 0) { + dev_warn(bt->dev, "%s(), count %zu or avail %d is not multiple of packet_size %d\n", + __func__, count, avail, packet_size); + count -= count % packet_size; + avail -= avail % packet_size; + } + + if (count > avail) + write_size = avail; + else + write_size = count; + + /* calculate continue space */ + cont = bt->tx->buf_size - cur_write_idx; + if (write_size > cont) + write_size = cont; + + if (copy_from_user(bt->tx_packet_buf + + cur_write_idx, + buf + cur_buf_ofs, + write_size)) { + dev_warn(bt->dev, "%s(), copy_from_user fail\n", + __func__); + return -EFAULT; + } + + spin_lock_irqsave(&bt->tx_lock, flags); + bt->tx->packet_w += write_size / packet_size; + spin_unlock_irqrestore(&bt->tx_lock, flags); + cur_buf_ofs += write_size; + count -= write_size; + } + + return written_size; +} + +static struct mtk_btcvsd_snd_stream *get_bt_stream + (struct mtk_btcvsd_snd *bt, struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return bt->tx; + else + return bt->rx; +} + +/* pcm ops */ +static const struct snd_pcm_hardware mtk_btcvsd_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .buffer_bytes_max = 24 * 1024, + .period_bytes_max = 24 * 1024, + .periods_min = 2, + .periods_max = 16, + .fifo_size = 0, +}; + +static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + int ret; + + dev_dbg(bt->dev, "%s(), stream %d, substream %p\n", + __func__, substream->stream, substream); + + snd_soc_set_runtime_hwparams(substream, &mtk_btcvsd_hardware); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = mtk_btcvsd_snd_tx_init(bt); + bt->tx->substream = substream; + } else { + ret = mtk_btcvsd_snd_rx_init(bt); + bt->rx->substream = substream; + } + + return ret; +} + +static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + + dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream); + + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_IDLE); + bt_stream->substream = NULL; + return 0; +} + +static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + params_buffer_bytes(hw_params) % bt->tx->packet_size != 0) { + dev_warn(bt->dev, "%s(), error, buffer size %d not valid\n", + __func__, + params_buffer_bytes(hw_params)); + return -EINVAL; + } + + substream->runtime->dma_bytes = params_buffer_bytes(hw_params); + return 0; +} + +static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + btcvsd_tx_clean_buffer(bt); + + return 0; +} + +static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + + dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream); + + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_RUNNING); + return 0; +} + +static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + int stream = substream->stream; + int hw_packet_ptr; + + dev_dbg(bt->dev, "%s(), stream %d, cmd %d\n", + __func__, substream->stream, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + hw_packet_ptr = stream == SNDRV_PCM_STREAM_PLAYBACK ? + bt_stream->packet_r : bt_stream->packet_w; + bt_stream->prev_packet_idx = hw_packet_ptr; + bt_stream->prev_frame = 0; + bt_stream->trigger_start = 1; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + bt_stream->trigger_start = 0; + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_ENDING); + return 0; + default: + return -EINVAL; + } +} + +static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer + (struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream; + snd_pcm_uframes_t frame = 0; + int byte = 0; + int hw_packet_ptr; + int packet_diff; + spinlock_t *lock; /* spinlock for bt stream control */ + unsigned long flags; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + lock = &bt->tx_lock; + bt_stream = bt->tx; + } else { + lock = &bt->rx_lock; + bt_stream = bt->rx; + } + + spin_lock_irqsave(lock, flags); + hw_packet_ptr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + bt->tx->packet_r : bt->rx->packet_w; + + /* get packet diff from last time */ + if (hw_packet_ptr >= bt_stream->prev_packet_idx) { + packet_diff = hw_packet_ptr - bt_stream->prev_packet_idx; + } else { + /* integer overflow */ + packet_diff = (INT_MAX - bt_stream->prev_packet_idx) + + (hw_packet_ptr - INT_MIN) + 1; + } + bt_stream->prev_packet_idx = hw_packet_ptr; + + /* increased bytes */ + byte = packet_diff * bt_stream->packet_size; + + frame = btcvsd_bytes_to_frame(substream, byte); + frame += bt_stream->prev_frame; + frame %= substream->runtime->buffer_size; + + bt_stream->prev_frame = frame; + + spin_unlock_irqrestore(lock, flags); + + return frame; +} + +static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long count) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mtk_btcvsd_snd_write(bt, buf, count); + else + mtk_btcvsd_snd_read(bt, buf, count); + + return 0; +} + +static struct snd_pcm_ops mtk_btcvsd_ops = { + .open = mtk_pcm_btcvsd_open, + .close = mtk_pcm_btcvsd_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = mtk_pcm_btcvsd_hw_params, + .hw_free = mtk_pcm_btcvsd_hw_free, + .prepare = mtk_pcm_btcvsd_prepare, + .trigger = mtk_pcm_btcvsd_trigger, + .pointer = mtk_pcm_btcvsd_pointer, + .copy_user = mtk_pcm_btcvsd_copy, +}; + +/* kcontrol */ +static const char *const btsco_band_str[] = {"NB", "WB"}; + +static const struct soc_enum btcvsd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(btsco_band_str), btsco_band_str), +}; + +static int btcvsd_band_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = bt->band; + return 0; +} + +static int btcvsd_band_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + bt->band = ucontrol->value.integer.value[0]; + dev_dbg(bt->dev, "%s(), band %d\n", __func__, bt->band); + return 0; +} + +static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) { + ucontrol->value.integer.value[0] = 0; + return 0; + } + + ucontrol->value.integer.value[0] = bt->tx->mute; + return 0; +} + +static int btcvsd_tx_mute_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) + return 0; + + bt->tx->mute = ucontrol->value.integer.value[0]; + return 0; +} + +static int btcvsd_rx_irq_received_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->rx) + return 0; + + ucontrol->value.integer.value[0] = bt->rx->rw_cnt ? 1 : 0; + return 0; +} + +static int btcvsd_rx_timeout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->rx) + return 0; + + ucontrol->value.integer.value[0] = bt->rx->timeout; + bt->rx->timeout = 0; + return 0; +} + +static int btcvsd_rx_timestamp_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + int ret = 0; + struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_rx; + + if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info)) + return -EINVAL; + + get_rx_time_stamp(bt, &time_buffer_info_rx); + + dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu", + __func__, + time_buffer_info_rx.time_stamp_us, + time_buffer_info_rx.data_count_equi_time); + + if (copy_to_user(data, &time_buffer_info_rx, + sizeof(struct mtk_btcvsd_snd_time_buffer_info))) { + dev_warn(bt->dev, "%s(), copy_to_user fail", __func__); + ret = -EFAULT; + } + + return ret; +} + +static int btcvsd_tx_irq_received_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) + return 0; + + ucontrol->value.integer.value[0] = bt->tx->rw_cnt ? 1 : 0; + return 0; +} + +static int btcvsd_tx_timeout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = bt->tx->timeout; + return 0; +} + +static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + int ret = 0; + struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_tx; + + if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info)) + return -EINVAL; + + get_tx_time_stamp(bt, &time_buffer_info_tx); + + dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu", + __func__, + time_buffer_info_tx.time_stamp_us, + time_buffer_info_tx.data_count_equi_time); + + if (copy_to_user(data, &time_buffer_info_tx, + sizeof(struct mtk_btcvsd_snd_time_buffer_info))) { + dev_warn(bt->dev, "%s(), copy_to_user fail", __func__); + ret = -EFAULT; + } + + return ret; +} + +static const struct snd_kcontrol_new mtk_btcvsd_snd_controls[] = { + SOC_ENUM_EXT("BTCVSD Band", btcvsd_enum[0], + btcvsd_band_get, btcvsd_band_set), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Mute Switch", 0, + btcvsd_tx_mute_get, btcvsd_tx_mute_set), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Irq Received Switch", 0, + btcvsd_tx_irq_received_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Timeout Switch", 0, + btcvsd_tx_timeout_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Rx Irq Received Switch", 0, + btcvsd_rx_irq_received_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Rx Timeout Switch", 0, + btcvsd_rx_timeout_get, NULL), + SND_SOC_BYTES_TLV("BTCVSD Rx Timestamp", + sizeof(struct mtk_btcvsd_snd_time_buffer_info), + btcvsd_rx_timestamp_get, NULL), + SND_SOC_BYTES_TLV("BTCVSD Tx Timestamp", + sizeof(struct mtk_btcvsd_snd_time_buffer_info), + btcvsd_tx_timestamp_get, NULL), +}; + +static int mtk_btcvsd_snd_component_probe(struct snd_soc_component *component) +{ + return snd_soc_add_component_controls(component, + mtk_btcvsd_snd_controls, + ARRAY_SIZE(mtk_btcvsd_snd_controls)); +} + +static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { + .name = BTCVSD_SND_NAME, + .ops = &mtk_btcvsd_ops, + .probe = mtk_btcvsd_snd_component_probe, +}; + +static int mtk_btcvsd_snd_probe(struct platform_device *pdev) +{ + int ret = 0; + int irq_id; + u32 offset[5] = {0, 0, 0, 0, 0}; + struct mtk_btcvsd_snd *btcvsd; + struct device *dev = &pdev->dev; + + /* init btcvsd private data */ + btcvsd = devm_kzalloc(dev, sizeof(*btcvsd), GFP_KERNEL); + if (!btcvsd) + return -ENOMEM; + platform_set_drvdata(pdev, btcvsd); + btcvsd->dev = dev; + + /* init tx/rx */ + btcvsd->rx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->rx), GFP_KERNEL); + if (!btcvsd->rx) + return -ENOMEM; + + btcvsd->tx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->tx), GFP_KERNEL); + if (!btcvsd->tx) + return -ENOMEM; + + spin_lock_init(&btcvsd->tx_lock); + spin_lock_init(&btcvsd->rx_lock); + + init_waitqueue_head(&btcvsd->tx_wait); + init_waitqueue_head(&btcvsd->rx_wait); + + mtk_btcvsd_snd_tx_init(btcvsd); + mtk_btcvsd_snd_rx_init(btcvsd); + + /* irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id <= 0) { + dev_err(dev, "%s no irq found\n", dev->of_node->name); + return irq_id < 0 ? irq_id : -ENXIO; + } + + ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler, + IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle", + (void *)btcvsd); + if (ret) { + dev_err(dev, "could not request_irq for BTCVSD_ISR_Handle\n"); + return ret; + } + + btcvsd->irq_id = irq_id; + + /* iomap */ + btcvsd->bt_pkv_base = of_iomap(dev->of_node, 0); + if (!btcvsd->bt_pkv_base) { + dev_err(dev, "iomap bt_pkv_base fail\n"); + return -EIO; + } + + btcvsd->bt_sram_bank2_base = of_iomap(dev->of_node, 1); + if (!btcvsd->bt_sram_bank2_base) { + dev_err(dev, "iomap bt_sram_bank2_base fail\n"); + return -EIO; + } + + btcvsd->infra = syscon_regmap_lookup_by_phandle(dev->of_node, + "mediatek,infracfg"); + if (IS_ERR(btcvsd->infra)) { + dev_err(dev, "cannot find infra controller: %ld\n", + PTR_ERR(btcvsd->infra)); + return PTR_ERR(btcvsd->infra); + } + + /* get offset */ + ret = of_property_read_u32_array(dev->of_node, "mediatek,offset", + offset, + ARRAY_SIZE(offset)); + if (ret) { + dev_warn(dev, "%s(), get offest fail, ret %d\n", __func__, ret); + return ret; + } + btcvsd->infra_misc_offset = offset[0]; + btcvsd->conn_bt_cvsd_mask = offset[1]; + btcvsd->cvsd_mcu_read_offset = offset[2]; + btcvsd->cvsd_mcu_write_offset = offset[3]; + btcvsd->cvsd_packet_indicator = offset[4]; + + btcvsd->bt_reg_pkt_r = btcvsd->bt_pkv_base + + btcvsd->cvsd_mcu_read_offset; + btcvsd->bt_reg_pkt_w = btcvsd->bt_pkv_base + + btcvsd->cvsd_mcu_write_offset; + btcvsd->bt_reg_ctl = btcvsd->bt_pkv_base + + btcvsd->cvsd_packet_indicator; + + /* init state */ + mtk_btcvsd_snd_set_state(btcvsd, btcvsd->tx, BT_SCO_STATE_IDLE); + mtk_btcvsd_snd_set_state(btcvsd, btcvsd->rx, BT_SCO_STATE_IDLE); + + return devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, + NULL, 0); +} + +static int mtk_btcvsd_snd_remove(struct platform_device *pdev) +{ + struct mtk_btcvsd_snd *btcvsd = dev_get_drvdata(&pdev->dev); + + iounmap(btcvsd->bt_pkv_base); + iounmap(btcvsd->bt_sram_bank2_base); + return 0; +} + +static const struct of_device_id mtk_btcvsd_snd_dt_match[] = { + { .compatible = "mediatek,mtk-btcvsd-snd", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_btcvsd_snd_dt_match); + +static struct platform_driver mtk_btcvsd_snd_driver = { + .driver = { + .name = "mtk-btcvsd-snd", + .of_match_table = mtk_btcvsd_snd_dt_match, + }, + .probe = mtk_btcvsd_snd_probe, + .remove = mtk_btcvsd_snd_remove, +}; + +module_platform_driver(mtk_btcvsd_snd_driver); + +MODULE_DESCRIPTION("Mediatek ALSA BT SCO CVSD/MSBC Driver"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); From 199ed3e81c49a621ce6fcb630ab9f30d92db6718 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:05:12 -0600 Subject: [PATCH 244/461] ASoC: dapm: fix use-after-free issue with dailink sname Commit 7620fe9161ce ("ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create") fixed a memory leak issue, but additional tests and KASAN reports show a use-after-free in soc-dapm. The widgets are created with a kmemdup operating on a template. The "name" string is also duplicated, but the "sname" string is not. As a result, when the template is freed after widget creation, its sname string is still used. Fix by explicitly duplicating the "sname" string, and freeing it when required. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c4c13419539..e71cd5b660ad 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -295,7 +295,22 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w; + + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + if (!w) + return NULL; + + /* + * w->name is duplicated in caller, but w->sname isn't. + * Duplicate it here if defined + */ + if (_widget->sname) { + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); + if (!w->sname) + return NULL; + } + return w; } struct dapm_kcontrol_data { @@ -2412,6 +2427,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); + kfree_const(w->sname); kfree(w); } @@ -3469,6 +3485,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, else w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { + kfree_const(w->sname); kfree(w); return ERR_PTR(-ENOMEM); } From 078a85f2806f0ffd11289009462a6a390f9adb5c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:18 +0000 Subject: [PATCH 245/461] ASoC: dapm: Only power up active channels from a DAI Currently all widgets attached to a DAI link will be powered up when the DAI is active, however this may include routes that are not actually in use if there are unused channels available on the DAI. The macros for creating AIF widgets already include an entry for slot, it is proposed to change that to channel. The effective difference here being respresenting the logical channel index rather than the physical slot index. The CODECs currently using the slot entry on the DAPM_AIF macros are using it in a manner consistent with this, the CODECs not using it just have the field set to zero. A variable is added to snd_soc_dapm_widget to represent this channel index and then for each AIF widget attached to a DAI this is compared against the number of channels on the stream. Enabling the links for those which will be in use. This has the nice property that the CODECs which haven't used the slot/channel entry in the macro will function exactly as before due to all the AIF widgets having a channel of zero and a stream by definition having at least one channel. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 22 +++++++----- sound/soc/soc-dapm.c | 76 ++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++ 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 46f2ba3ffcb7..79b4ddfb8e9e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -214,21 +214,21 @@ struct device; .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ -#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } -#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ @@ -407,6 +407,10 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); @@ -627,6 +631,8 @@ struct snd_soc_dapm_widget { int endpoints[2]; struct clk *clk; + + int channel; }; struct snd_soc_dapm_update { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e71cd5b660ad..36d964a52874 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2541,6 +2541,78 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); +static int dapm_update_dai_chan(struct snd_soc_dapm_path *p, + struct snd_soc_dapm_widget *w, + int channels) +{ + switch (w->id) { + case snd_soc_dapm_aif_out: + case snd_soc_dapm_aif_in: + break; + default: + return 0; + } + + dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n", + w->channel < channels ? "Connecting" : "Disconnecting", + p->source->name, p->sink->name); + + if (w->channel < channels) + soc_dapm_connect_path(p, true, "dai update"); + else + soc_dapm_connect_path(p, false, "dai update"); + + return 0; +} + +static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int dir = substream->stream; + int channels = params_channels(params); + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *w; + int ret; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, + dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + ret = dapm_update_dai_chan(p, p->sink, channels); + if (ret < 0) + return ret; + } + + snd_soc_dapm_widget_for_each_source_path(w, p) { + ret = dapm_update_dai_chan(p, p->source, channels); + if (ret < 0) + return ret; + } + + return 0; +} + +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = dapm_update_dai_unlocked(substream, params, dai); + mutex_unlock(&rtd->card->dapm_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); + /* * dapm_update_widget_flags() - Re-compute widget sink and source flags * @w: The widget for which to update the flags @@ -3706,6 +3778,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, source); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, source); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3726,6 +3800,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, sink); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, sink); } break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050..a5b40e82dea4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -969,6 +969,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_dai->channels = params_channels(&codec_params); codec_dai->sample_bits = snd_pcm_format_physical_width( params_format(&codec_params)); + + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } ret = soc_dai_hw_params(substream, params, cpu_dai); @@ -998,6 +1000,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + snd_soc_dapm_update_dai(substream, params, cpu_dai); + ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; From 411db2ab7df35804422e4b26c5849b3868e6a038 Mon Sep 17 00:00:00 2001 From: Zhiwei Jiang Date: Thu, 31 Jan 2019 19:30:05 +0800 Subject: [PATCH 246/461] ASoC: dapm: Add warnings for widget overwrite when adding route Currently, in some complex cases, more than one widgets have same name and registed from differnt dapm context, and route add from another context too. When snd_soc_dapm_add_route, the previous registered widget will overwritten by the latest same name widget, will cause unexpect error. For Asoc framework we cant avoid this situation and we cant decide which widget that wanted with route. At least we can give users a notice. Signed-off-by: Zhiwei Jiang Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 36d964a52874..5b74dffc9c11 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2829,6 +2829,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, char prefixed_sink[80]; char prefixed_source[80]; const char *prefix; + unsigned int sink_ref = 0; + unsigned int source_ref = 0; int ret; prefix = soc_dapm_prefix(dapm); @@ -2862,6 +2864,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsource) break; } + sink_ref++; + if (sink_ref > 1) + dev_warn(dapm->dev, + "ASoC: sink widget %s overwritten\n", + w->name); continue; } if (!wsource && !(strcmp(w->name, source))) { @@ -2871,6 +2878,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsink) break; } + source_ref++; + if (source_ref > 1) + dev_warn(dapm->dev, + "ASoC: source widget %s overwritten\n", + w->name); } } /* use widget from another DAPM context if not found from this */ From 11907e9d3533648615db08140e3045b829d2c141 Mon Sep 17 00:00:00 2001 From: wen yang Date: Sat, 2 Feb 2019 14:53:16 +0000 Subject: [PATCH 247/461] ASoC: fsl-asoc-card: fix object reference leaks in fsl_asoc_card_probe The of_find_device_by_node() takes a reference to the underlying device structure, we should release that reference. Signed-off-by: Wen Yang Cc: Timur Tabi Cc: Nicolin Chen Cc: Xiubo Li Cc: Fabio Estevam Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: alsa-devel@alsa-project.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 81f2fe2c6d23..60f87a0d99f4 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -689,6 +689,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) asrc_fail: of_node_put(asrc_np); of_node_put(codec_np); + put_device(&cpu_pdev->dev); fail: of_node_put(cpu_np); From 78a24e10cd94420f1b4e2dc5923ae7109e2aaba1 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 29 Jan 2019 13:47:09 -0800 Subject: [PATCH 248/461] ASoC: soc-core: clear platform pointers on error Originally snd_soc_init_platform was not cleaning up its pointers, this was fixed to always reallocate dynamic memory but created a memory leak when snd_soc_init_platform was called multiple times during the same probe attempt and also threw away any changes made to the struct between calls. In order to avoid reallocating memory that is still valid, the behaviour will be changed to clear the dynamically set pointers on a probe error and a unregister event and snd_soc_init_platform will go back to its original behaviour of only allocating null pointers so it will stop throwing away valid changes. Signed-off-by: Curtis Malainey Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 93efab486736..8c63d32ab2fe 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1048,7 +1048,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ - if (!platform || dai_link->legacy_platform) { + if (!platform) { platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); @@ -1071,6 +1071,24 @@ static int snd_soc_init_platform(struct snd_soc_card *card, return 0; } +static void soc_cleanup_platform(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + /* + * FIXME + * + * this function should be removed with snd_soc_init_platform + */ + + for_each_card_prelinks(card, i, link) { + if (link->legacy_platform) { + link->legacy_platform = 0; + link->platforms = NULL; + } + } +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -2015,6 +2033,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + soc_cleanup_platform(card); /* remove auxiliary devices */ soc_remove_aux_devices(card); From adfebb51e1750c5df9e5d42f505b73c5542a879d Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 1 Feb 2019 11:07:40 -0600 Subject: [PATCH 249/461] ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa..5223896de26f 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 23d421370e6c..246d2a2d43c8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -557,6 +557,25 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + * We however need to reset the dobj type to its initial values + */ + dobj->type = SND_SOC_DOBJ_NONE; + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2163,6 +2182,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2649,6 +2674,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From c7c3fec8a524774dbd1daf7841df1217dd589298 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:24:52 +0100 Subject: [PATCH 250/461] ALSA: x86: Avoid passing NULL to memory allocators We should pass a proper non-NULL device object to memory allocators although it was accepted in the past. The card->dev points to the most appropriate device object in such a case, so let's put it. Acked-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 16ca91f57e7f..80f79ecffc71 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1812,7 +1812,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) * try to allocate 600k buffer as default which is large enough */ snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV_UC, NULL, + SNDRV_DMA_TYPE_DEV_UC, + card->dev, HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER); /* create controls */ From bc70a9d70052c45483c2ef6a7fe08638cf88f490 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:26:27 +0100 Subject: [PATCH 251/461] ALSA: arm: Avoid passing NULL to memory allocators We should pass a proper non-NULL device object to memory allocators although it was accepted in the past. The card->dev points to the most appropriate device object in such a case, so let's put it. Acked-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 0c3f073e2600..a2d4b41096e0 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -941,7 +941,8 @@ static int aaci_init_pcm(struct aaci *aaci) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - NULL, 0, 64 * 1024); + aaci->card->dev, + 0, 64 * 1024); } return ret; From 766cc4965a3a2a8a62e70e9d98e1d946a71368d5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 4 Feb 2019 15:31:05 +0000 Subject: [PATCH 252/461] ASoC: mediatek: btcvsd: fix spelling mistake "offest" -> "offset" There is a spelling mistake in a dev_warn message. Fix this. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 349a9120a0dd..e408c1b270ab 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1309,7 +1309,7 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) offset, ARRAY_SIZE(offset)); if (ret) { - dev_warn(dev, "%s(), get offest fail, ret %d\n", __func__, ret); + dev_warn(dev, "%s(), get offset fail, ret %d\n", __func__, ret); return ret; } btcvsd->infra_misc_offset = offset[0]; From 0f747bb273790f49be4660521d86d7cebd1bbe1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= Date: Mon, 4 Feb 2019 16:35:38 +0100 Subject: [PATCH 253/461] ASoC: ak4118: fix missing header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver use the gpio consumer interface. Add the header as it's needed. Signed-off-by: Clément Péron Signed-off-by: Mark Brown --- sound/soc/codecs/ak4118.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index 238ab29f2bf4..ce419e8cf890 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include From 18d33cdb0b30392dd8f0a3ebd224c3253d07ae47 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:27:01 +0100 Subject: [PATCH 254/461] ASoC: amd: Avoid passing NULL to memory allocators We should pass a proper non-NULL device object to memory allocators although it was accepted in the past. The card->dev points to the most appropriate device object in such a case, so let's put it. Acked-by: Christoph Hellwig Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/amd/raven/acp3x-pcm-dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 3d58338fa3cf..3e7d4099364c 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -369,7 +369,8 @@ static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd) { return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, - NULL, MIN_BUFFER, + rtd->pcm->card->dev, + MIN_BUFFER, MAX_BUFFER); } From 8f74ae398aa0b96207de366e9a723517e440e590 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:27:17 +0100 Subject: [PATCH 255/461] ASoC: sh: Avoid passing NULL to memory allocators We should pass a proper non-NULL device object to memory allocators although it was accepted in the past. The card->dev points to the most appropriate device object in such a case, so let's put it. Acked-by: Christoph Hellwig Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/sh/siu_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index e263757e4a69..23384c477740 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -542,7 +542,7 @@ static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) return ret; ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, NULL, + SNDRV_DMA_TYPE_DEV, card->dev, SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); if (ret < 0) { dev_err(card->dev, From 6ce1d63ed7210e7120070297976460f868c36314 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:34:00 +0100 Subject: [PATCH 256/461] ALSA: core: Don't allow NULL device for memory allocation Since we covered all callers with NULL device pointer, let's catch the remaining calls with NULL and warn explicitly. Acked-by: Christoph Hellwig Signed-off-by: Takashi Iwai --- sound/core/memalloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 59a4adc286ed..eb974235c92b 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -182,6 +182,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, return -ENXIO; if (WARN_ON(!dmab)) return -ENXIO; + if (WARN_ON(!device)) + return -EINVAL; dmab->dev.type = type; dmab->dev.dev = device; From 348c5ad5d69cc0a3fb1f6e3f22787a9721e2a420 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:31:42 +0100 Subject: [PATCH 257/461] ALSA: info: Always register entries recursively Make sure that all children entries are registered by a single call of snd_info_register(). OTOH, don't register if a parent isn't registered yet. This allows us to create the whole procfs tree in a shot at the last stage of card registration phase in a later patch. Signed-off-by: Takashi Iwai --- sound/core/info.c | 65 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 2dfb6389c084..5cd00629c0f5 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -523,27 +523,6 @@ int snd_info_card_create(struct snd_card *card) return 0; } -/* register all pending info entries */ -static int snd_info_register_recursive(struct snd_info_entry *entry) -{ - struct snd_info_entry *p; - int err; - - if (!entry->p) { - err = snd_info_register(entry); - if (err < 0) - return err; - } - - list_for_each_entry(p, &entry->children, list) { - err = snd_info_register_recursive(p); - if (err < 0) - return err; - } - - return 0; -} - /* * register the card proc file * called from init.c @@ -557,7 +536,7 @@ int snd_info_card_register(struct snd_card *card) if (snd_BUG_ON(!card)) return -ENXIO; - err = snd_info_register_recursive(card->proc_root); + err = snd_info_register(card->proc_root); if (err < 0) return err; @@ -821,15 +800,7 @@ void snd_info_free_entry(struct snd_info_entry * entry) } EXPORT_SYMBOL(snd_info_free_entry); -/** - * snd_info_register - register the info entry - * @entry: the info entry - * - * Registers the proc info entry. - * - * Return: Zero if successful, or a negative error code on failure. - */ -int snd_info_register(struct snd_info_entry * entry) +static int __snd_info_register(struct snd_info_entry *entry) { struct proc_dir_entry *root, *p = NULL; @@ -837,6 +808,8 @@ int snd_info_register(struct snd_info_entry * entry) return -ENXIO; root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; mutex_lock(&info_mutex); + if (entry->p || !root) + goto unlock; if (S_ISDIR(entry->mode)) { p = proc_mkdir_mode(entry->name, entry->mode, root); if (!p) { @@ -858,9 +831,39 @@ int snd_info_register(struct snd_info_entry * entry) proc_set_size(p, entry->size); } entry->p = p; + unlock: mutex_unlock(&info_mutex); return 0; } + +/** + * snd_info_register - register the info entry + * @entry: the info entry + * + * Registers the proc info entry. + * The all children entries are registered recursively. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_info_register(struct snd_info_entry *entry) +{ + struct snd_info_entry *p; + int err; + + if (!entry->p) { + err = __snd_info_register(entry); + if (err < 0) + return err; + } + + list_for_each_entry(p, &entry->children, list) { + err = snd_info_register(p); + if (err < 0) + return err; + } + + return 0; +} EXPORT_SYMBOL(snd_info_register); /* From e6e8c82b97472c4e02a314e7161f980534e7bca5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:30:33 +0100 Subject: [PATCH 258/461] ALSA: atmel: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/atmel/ac97c.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 380025887aef..33c87a0547a9 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -603,11 +603,9 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops); - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, &chip->pdev->dev, hw.periods_min * hw.period_bytes_min, hw.buffer_bytes_max); - if (retval) - return retval; pcm->private_data = chip; pcm->info_flags = 0; From f32e5616005bb999fec6a2e914161805d7ad061f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:31:42 +0100 Subject: [PATCH 259/461] ALSA: parisc: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/parisc/harmony.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index f36e7006e00c..a4264b8943f0 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -669,14 +669,8 @@ snd_harmony_pcm_init(struct snd_harmony *h) } /* pre-allocate space for DMA */ - err = snd_pcm_lib_preallocate_pages_for_all(pcm, h->dma.type, - h->dma.dev, - MAX_BUF_SIZE, - MAX_BUF_SIZE); - if (err < 0) { - printk(KERN_ERR PFX "buffer allocation error: %d\n", err); - return err; - } + snd_pcm_lib_preallocate_pages_for_all(pcm, h->dma.type, h->dma.dev, + MAX_BUF_SIZE, MAX_BUF_SIZE); h->st.format = snd_harmony_set_data_format(h, SNDRV_PCM_FORMAT_S16_BE, 1); From 5116b94af07a9775ed694562f354e931b2cc04d4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:32:09 +0100 Subject: [PATCH 260/461] ALSA: pci: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ad1889.c | 7 +----- sound/pci/aw2/aw2-alsa.c | 40 ++++++++++----------------------- sound/pci/bt87x.c | 10 ++++----- sound/pci/ca0106/ca0106_main.c | 16 +++++-------- sound/pci/echoaudio/echoaudio.c | 16 ++++++------- sound/pci/emu10k1/emupcm.c | 22 ++++++++++++------ sound/pci/emu10k1/p16v.c | 17 ++++++-------- sound/pci/lx6464es/lx6464es.c | 8 +++---- sound/pci/rme9652/hdspm.c | 20 ++++------------- sound/pci/via82xx_modem.c | 8 +++---- 10 files changed, 63 insertions(+), 101 deletions(-) diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index d9c54c08e2db..410fefe5ebde 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -644,16 +644,11 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device) chip->psubs = NULL; chip->csubs = NULL; - err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), BUFFER_BYTES_MAX / 2, BUFFER_BYTES_MAX); - if (err < 0) { - dev_err(chip->card->dev, "buffer allocation error: %d\n", err); - return err; - } - return 0; } diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 9a49e4243a9c..b07c5fc1da56 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -624,15 +624,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* pre-allocation of buffers */ /* Preallocate continuous pages. */ - err = snd_pcm_lib_preallocate_pages_for_all(pcm_playback_ana, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data - (chip->pci), - 64 * 1024, 64 * 1024); - if (err) - dev_err(chip->card->dev, - "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", - err); + snd_pcm_lib_preallocate_pages_for_all(pcm_playback_ana, + SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64 * 1024, 64 * 1024); err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0, &pcm_playback_num); @@ -661,15 +656,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* pre-allocation of buffers */ /* Preallocate continuous pages. */ - err = snd_pcm_lib_preallocate_pages_for_all(pcm_playback_num, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data - (chip->pci), - 64 * 1024, 64 * 1024); - if (err) - dev_err(chip->card->dev, - "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", - err); + snd_pcm_lib_preallocate_pages_for_all(pcm_playback_num, + SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64 * 1024, 64 * 1024); err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1, &pcm_capture); @@ -699,16 +689,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip) /* pre-allocation of buffers */ /* Preallocate continuous pages. */ - err = snd_pcm_lib_preallocate_pages_for_all(pcm_capture, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data - (chip->pci), - 64 * 1024, 64 * 1024); - if (err) - dev_err(chip->card->dev, - "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", - err); - + snd_pcm_lib_preallocate_pages_for_all(pcm_capture, + SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64 * 1024, 64 * 1024); /* Create control */ err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip)); diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index ba971042f871..0adcba10c067 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -714,11 +714,11 @@ static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) pcm->private_data = chip; strcpy(pcm->name, name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); - return snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), - 128 * 1024, - ALIGN(255 * 4092, 1024)); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), + 128 * 1024, + ALIGN(255 * 4092, 1024)); + return 0; } static int snd_bt87x_create(struct snd_card *card, diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 3d1b0bbff33b..11ef0d636405 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1402,21 +1402,17 @@ static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { - if ((err = snd_pcm_lib_preallocate_pages(substream, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); } for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { - if ((err = snd_pcm_lib_preallocate_pages(substream, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), - 64*1024, 64*1024)) < 0) - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); } err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2, diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 18d30d479b6b..ea876b0b02b9 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -884,17 +884,15 @@ static const struct snd_pcm_ops digital_capture_ops = { static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) { struct snd_pcm_substream *ss; - int stream, err; + int stream; for (stream = 0; stream < 2; stream++) - for (ss = pcm->streams[stream].substream; ss; ss = ss->next) { - err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG, - dev, - ss->number ? 0 : 128<<10, - 256<<10); - if (err < 0) - return err; - } + for (ss = pcm->streams[stream].substream; ss; ss = ss->next) + snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG, + dev, + ss->number ? 0 : 128<<10, + 256<<10); + return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 30b3472d0b75..f6b4cb9ac75c 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1427,11 +1427,14 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) emu->pcm = pcm; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); return 0; } @@ -1455,8 +1458,9 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) emu->pcm_multi = pcm; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); return 0; } @@ -1489,7 +1493,9 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) strcpy(pcm->name, "Mic Capture"); emu->pcm_mic = pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); return 0; } @@ -1862,7 +1868,9 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) if (err < 0) return err; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 64*1024, 64*1024); return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 4948b95f6665..672017cac4c7 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -656,11 +656,10 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { - if ((err = snd_pcm_lib_preallocate_pages(substream, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), - ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + (65536 - 64) * 8, + (65536 - 64) * 8); /* dev_dbg(emu->card->dev, "preallocate playback substream: err=%d\n", err); @@ -670,11 +669,9 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { - if ((err = snd_pcm_lib_preallocate_pages(substream, - SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(emu->pci), - 65536 - 64, 65536 - 64)) < 0) - return err; + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(emu->pci), + 65536 - 64, 65536 - 64); /* dev_dbg(emu->card->dev, "preallocate capture substream: err=%d\n", err); diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 54f6252faca6..52ea0da1fe73 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -854,11 +854,9 @@ static int lx_pcm_create(struct lx6464es *chip) pcm->nonatomic = true; strcpy(pcm->name, card_name); - err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - size, size); - if (err < 0) - return err; + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + size, size); chip->pcm = pcm; chip->capture_stream.is_capture = 1; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 679ad0415e3b..3e66df7b5d1f 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6411,7 +6411,6 @@ static int snd_hdspm_create_hwdep(struct snd_card *card, ------------------------------------------------------------*/ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) { - int err; struct snd_pcm *pcm; size_t wanted; @@ -6419,21 +6418,10 @@ static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) wanted = HDSPM_DMA_AREA_BYTES; - err = - snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(hdspm->pci), - wanted, - wanted); - if (err < 0) { - dev_dbg(hdspm->card->dev, - "Could not preallocate %zd Bytes\n", wanted); - - return err; - } else - dev_dbg(hdspm->card->dev, - " Preallocated %zd Bytes\n", wanted); - + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(hdspm->pci), + wanted, wanted); + dev_dbg(hdspm->card->dev, " Preallocated %zd Bytes\n", wanted); return 0; } diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 3f59e0279058..3b3768acf7e1 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -865,11 +865,9 @@ static int snd_via686_pcm_new(struct via82xx_modem *chip) init_viadev(chip, 0, VIA_REG_MO_STATUS, 0); init_viadev(chip, 1, VIA_REG_MI_STATUS, 1); - if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), - 64*1024, 128*1024)) < 0) - return err; - + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), + 64*1024, 128*1024); return 0; } From c025672290d7a21df00d9b89ccc422a94eda5671 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:35:10 +0100 Subject: [PATCH 261/461] ALSA: ppc: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index abe031c9d592..521236efcc4d 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -1024,15 +1024,11 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev) the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED; /* pre-alloc PCM DMA buffer*/ - ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm, + snd_pcm_lib_preallocate_pages_for_all(the_card.pcm, SNDRV_DMA_TYPE_DEV, &dev->core, SND_PS3_PCM_PREALLOC_SIZE, SND_PS3_PCM_PREALLOC_SIZE); - if (ret < 0) { - pr_info("%s: prealloc failed\n", __func__); - goto clean_card; - } /* * allocate null buffer From 2462bca0a668393aea6fe7bc53c49066944b04fa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:35:30 +0100 Subject: [PATCH 262/461] ALSA: sh: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/sh/aica.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 2b26311405a4..e7fef3fce44a 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -464,14 +464,12 @@ static int __init snd_aicapcmchip(struct snd_card_aica snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_aicapcm_playback_ops); /* Allocate the DMA buffers */ - err = - snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data - (GFP_KERNEL), - AICA_BUFFER_SIZE, - AICA_BUFFER_SIZE); - return err; + snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + AICA_BUFFER_SIZE, + AICA_BUFFER_SIZE); + return 0; } /* Mixer controls */ From 1267e24fe749b04beca5a7f04ffa49d9d792adb0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:35:48 +0100 Subject: [PATCH 263/461] ALSA: sparc: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/sparc/dbri.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 7609eceba1a2..fc34c863b93c 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2243,12 +2243,9 @@ static int snd_dbri_pcm(struct snd_card *card) pcm->info_flags = 0; strcpy(pcm->name, card->shortname); - if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64 * 1024, 64 * 1024)) < 0) - return err; - + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64 * 1024, 64 * 1024); return 0; } From 600bacfcd706b5820d172626bfa6347482b4946b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:36:00 +0100 Subject: [PATCH 264/461] ALSA: spi: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/spi/at73c213.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 1ef52edeb538..8707e0108471 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -350,7 +350,7 @@ static int snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); - retval = snd_pcm_lib_preallocate_pages_for_all(chip->pcm, + snd_pcm_lib_preallocate_pages_for_all(chip->pcm, SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev, 64 * 1024, 64 * 1024); out: From 4d1b53034d799a0618b00ddb194e30594fafcd2f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:36:10 +0100 Subject: [PATCH 265/461] ALSA: usb: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/usx2y/usbusx2yaudio.c | 21 ++++++++++----------- sound/usb/usx2y/usx2yhwdeppcm.c | 19 ++++++++----------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 2b833054e3b0..58974d094b27 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -981,18 +981,17 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); - if ((playback_endpoint && - 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64*1024, 128*1024))) || - 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64*1024, 128*1024))) { - snd_usX2Y_pcm_private_free(pcm); - return err; + if (playback_endpoint) { + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64*1024, 128*1024); } + + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64*1024, 128*1024); usX2Y(card)->pcm_devs++; return 0; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 4fd9276b8e50..714cf50d4a4c 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -736,17 +736,14 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) pcm->info_flags = 0; sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio"); - if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64*1024, 128*1024)) || - 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64*1024, 128*1024))) { - return err; - } - + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64*1024, 128*1024); return 0; } From cf17a5ffd27234371d10748bf1c716ef172877f3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Feb 2019 11:13:59 +0000 Subject: [PATCH 266/461] ASoC: dapm: Check for NULL widget in dapm_update_dai_unlocked DAIs linked to the dummy will not have an associated playback/capture widget, so we need to skip the update in that case. Fixes: 078a85f2806f ("ASoC: dapm: Only power up active channels from a DAI") Reported-by: Krzysztof Kozlowski Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5b74dffc9c11..111a23a9708a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2580,6 +2580,9 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, else w = dai->capture_widget; + if (!w) + return 0; + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); From 37768e3917405e82611af8e693ccac1a20df38b5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 6 Feb 2019 16:29:47 +0100 Subject: [PATCH 267/461] ASoC: ssm2602: Fix ADC powerup sequencing According to the ssm2603 data sheet (control register sequencing), the digital core should be activated only after all necessary bits in the power register are enabled, and a delay determined by the decoupling capacitor on the VMID pin has passed. If the digital core is activated too early, or even before the ADC is powered up, audible artifacts appear at the beginning of the recorded signal. The digital core is also needed for playback, so when recording starts it may already be enabled. This means we cannot get the power sequence correct when we want to be able to start recording after playback. As a workaround put the MIC mute switch into the DAPM routes. This way we can keep the recording disabled until the MIC Bias has settled and thus get rid of audible artifacts. Signed-off-by: Philipp Zabel m.felsch@pengutronix.de: adapt commit message m.felsch@pengutronix.de: drop of configuration as mentioned by Mark: https://patchwork.kernel.org/patch/10407449/ Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 501a4e73b185..6f79cb0fbc63 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -26,6 +26,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -111,7 +112,6 @@ SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1, SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), -SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), }; /* Output Mixer */ @@ -121,10 +121,31 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), }; +static const struct snd_kcontrol_new mic_ctl = + SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1); + /* Input mux */ static const struct snd_kcontrol_new ssm2602_input_mux_controls = SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); +static int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + /* + * According to the ssm2603 data sheet (control register sequencing), + * the digital core should be activated only after all necessary bits + * in the power register are enabled, and a delay determined by the + * decoupling capacitor on the VMID pin has passed. If the digital core + * is activated too early, or even before the ADC is powered up, audible + * artifacts appear at the beginning and end of the recorded signal. + * + * In practice, audible artifacts disappear well over 500 ms. + */ + msleep(500); + + return 0; +} + static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), @@ -146,6 +167,9 @@ SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), +SND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl, + ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_OUTPUT("LHPOUT"), SND_SOC_DAPM_OUTPUT("RHPOUT"), SND_SOC_DAPM_INPUT("MICIN"), @@ -178,9 +202,11 @@ static const struct snd_soc_dapm_route ssm2602_routes[] = { {"LHPOUT", NULL, "Output Mixer"}, {"Input Mux", "Line", "Line Input"}, - {"Input Mux", "Mic", "Mic Bias"}, + {"Input Mux", "Mic", "Mic Switch"}, {"ADC", NULL, "Input Mux"}, + {"Mic Switch", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "MICIN"}, }; From d22b4117538d42f3dcf7e28210f07f968e46222e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Feb 2019 12:09:27 +0300 Subject: [PATCH 268/461] ASoC: wcd9335: remove some unnecessary NULL checks These are arrays, not pointers, and they can't be NULL. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 3878187bb512..981f88a5f615 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2001,20 +2001,16 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, return -EINVAL; } - if (wcd->rx_chs) { - wcd->num_rx_port = rx_num; - for (i = 0; i < rx_num; i++) { - wcd->rx_chs[i].ch_num = rx_slot[i]; - INIT_LIST_HEAD(&wcd->rx_chs[i].list); - } + wcd->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd->rx_chs[i].list); } - if (wcd->tx_chs) { - wcd->num_tx_port = tx_num; - for (i = 0; i < tx_num; i++) { - wcd->tx_chs[i].ch_num = tx_slot[i]; - INIT_LIST_HEAD(&wcd->tx_chs[i].list); - } + wcd->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd->tx_chs[i].list); } return 0; From 52cadf1fdbe87a3a3eee11d9cc4873796903c934 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:12 +0000 Subject: [PATCH 269/461] ASoC: compress: Clarify the intent of current compressed ops handling For callbacks configuring the state of the components (trigger, set_params, ack and set_metadata) simplify the code a little and make intention clearer by aborting as soon as an error is encountered. The operation has already failed and there is nothing to be gained from processing the callbacks on additional components. The operations currently abort after the callbacks, so this simply shortens the error path. For callbacks returning information from the driver (copy, get_metadata, pointer, get_codec_caps, get_caps and get_params) only look for the first callback provided, currently the code will call every callback only returning the information provided by the last. Since we can only return one set of data, it makes no sense to request the data from every component. Again this just makes the currently supported feature set a little more clear. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 106 ++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 699397a09167..fc8742383b23 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -353,7 +353,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -364,12 +364,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -394,7 +392,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) { @@ -406,9 +404,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, + cmd); + if (ret < 0) + return ret; } return ret; } @@ -433,12 +432,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -472,7 +469,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -496,12 +493,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto err; } - if (ret < 0) - goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -522,7 +517,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, cancel_delayed_work_sync(&rtd->delayed_work); - return ret; + return 0; err: mutex_unlock(&rtd->pcm_mutex); @@ -538,7 +533,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -578,12 +573,10 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); @@ -607,7 +600,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -624,9 +617,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_params) continue; - __ret = component->driver->compr_ops->get_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_params(cstream, params); + break; } err: @@ -640,7 +632,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -651,9 +643,8 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_caps) continue; - __ret = component->driver->compr_ops->get_caps(cstream, caps); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_caps(cstream, caps); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -666,7 +657,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -677,9 +668,9 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_codec_caps) continue; - __ret = component->driver->compr_ops->get_codec_caps(cstream, codec); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_codec_caps(cstream, + codec); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -692,7 +683,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -709,9 +700,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) !component->driver->compr_ops->ack) continue; - __ret = component->driver->compr_ops->ack(cstream, bytes); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->ack(cstream, bytes); + if (ret < 0) + goto err; } err: @@ -725,7 +716,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -740,9 +731,8 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, !component->driver->compr_ops->pointer) continue; - __ret = component->driver->compr_ops->pointer(cstream, tstamp); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->pointer(cstream, tstamp); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -781,7 +771,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); @@ -796,12 +786,13 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_metadata) continue; - __ret = component->driver->compr_ops->set_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_metadata(cstream, + metadata); + if (ret < 0) + return ret; } - return ret; + return 0; } static int soc_compr_get_metadata(struct snd_compr_stream *cstream, @@ -811,7 +802,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); @@ -826,12 +817,11 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_metadata) continue; - __ret = component->driver->compr_ops->get_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + return component->driver->compr_ops->get_metadata(cstream, + metadata); } - return ret; + return 0; } /* ASoC Compress operations */ From 4ef0ecb80e348f1888b0c7ebfa8f7c1ec3ed9006 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:13 +0000 Subject: [PATCH 270/461] ASoC: compress: Add helper functions for component trigger/set_params The trigger and set_params callbacks are called from 3 and 2 separate loops respectively, tidy up the code a little by factoring these out into helper functions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 117 ++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index fc8742383b23..03d5b9ccd3fc 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -345,17 +345,13 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) return 0; } -static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +static int soc_compr_components_trigger(struct snd_compr_stream *cstream, + int cmd) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + int ret; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -366,9 +362,25 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) ret = component->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) - goto out; + return ret; } + return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret; + + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -389,28 +401,12 @@ out: static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || - cmd == SND_COMPR_TRIGGER_DRAIN) { - - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, - cmd); - if (ret < 0) - return ret; - } - return ret; - } + cmd == SND_COMPR_TRIGGER_DRAIN) + return soc_compr_components_trigger(cstream, cmd); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -425,17 +421,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, cmd); - if (ret < 0) - goto out; - } + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -462,12 +450,33 @@ out: return ret; } -static int soc_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) +static int soc_compr_components_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->compr_ops || + !component->driver->compr_ops->set_params) + continue; + + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + return ret; + } + + return 0; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; @@ -486,17 +495,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto err; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -530,8 +531,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; @@ -566,17 +565,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto out; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); From 47306401835a095843df8d87a51848f7e5e5099e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Wed, 6 Feb 2019 18:00:03 +0100 Subject: [PATCH 271/461] ASoC: ssm2602: switch to SPDX identifier Drop old license header and switch to SPDX-License-Identifier. Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 39 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 6f79cb0fbc63..464a4d7873bb 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -1,30 +1,15 @@ -/* - * File: sound/soc/codecs/ssm2602.c - * Author: Cliff Cai - * - * Created: Tue June 06 2008 - * Description: Driver for ssm2602 sound chip - * - * Modified: - * Copyright 2008 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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 the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// File: sound/soc/codecs/ssm2602.c +// Author: Cliff Cai +// +// Created: Tue June 06 2008 +// Description: Driver for ssm2602 sound chip +// +// Modified: +// Copyright 2008 Analog Devices Inc. +// +// Bugs: Enter bugs at http://blackfin.uclinux.org/ #include #include From 0c298bdc38a00b8bbbd4df21c85c57d8a9dab625 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:34:12 +0100 Subject: [PATCH 272/461] ALSA: firewire: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_proc.c | 12 ++---------- sound/firewire/dice/dice-proc.c | 12 ++---------- sound/firewire/digi00x/digi00x-proc.c | 16 ++-------------- sound/firewire/fireface/ff-proc.c | 12 ++---------- sound/firewire/fireworks/fireworks_proc.c | 12 ++---------- sound/firewire/motu/motu-proc.c | 12 ++---------- sound/firewire/oxfw/oxfw-proc.c | 12 ++---------- sound/firewire/tascam/tascam-proc.c | 12 ++---------- 8 files changed, 16 insertions(+), 84 deletions(-) diff --git a/sound/firewire/bebob/bebob_proc.c b/sound/firewire/bebob/bebob_proc.c index 8096891af913..05e2a1c6326c 100644 --- a/sound/firewire/bebob/bebob_proc.c +++ b/sound/firewire/bebob/bebob_proc.c @@ -163,12 +163,8 @@ add_node(struct snd_bebob *bebob, struct snd_info_entry *root, const char *name, struct snd_info_entry *entry; entry = snd_info_create_card_entry(bebob->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, bebob, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, bebob, op); } void snd_bebob_proc_init(struct snd_bebob *bebob) @@ -184,10 +180,6 @@ void snd_bebob_proc_init(struct snd_bebob *bebob) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(bebob, root, "clock", proc_read_clock); add_node(bebob, root, "firmware", proc_read_hw_info); diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c index bb870fc73f99..9b1d509c6320 100644 --- a/sound/firewire/dice/dice-proc.c +++ b/sound/firewire/dice/dice-proc.c @@ -285,12 +285,8 @@ static void add_node(struct snd_dice *dice, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(dice->card, name, root); - if (!entry) - return; - - snd_info_set_text_ops(entry, dice, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, dice, op); } void snd_dice_create_proc(struct snd_dice *dice) @@ -306,10 +302,6 @@ void snd_dice_create_proc(struct snd_dice *dice) if (!root) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(dice, root, "dice", dice_proc_read); add_node(dice, root, "formation", dice_proc_read_formation); diff --git a/sound/firewire/digi00x/digi00x-proc.c b/sound/firewire/digi00x/digi00x-proc.c index 6996d5a6ff5f..d22e8675b10f 100644 --- a/sound/firewire/digi00x/digi00x-proc.c +++ b/sound/firewire/digi00x/digi00x-proc.c @@ -80,20 +80,8 @@ void snd_dg00x_proc_init(struct snd_dg00x *dg00x) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } entry = snd_info_create_card_entry(dg00x->card, "clock", root); - if (entry == NULL) { - snd_info_free_entry(root); - return; - } - - snd_info_set_text_ops(entry, dg00x, proc_read_clock); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - snd_info_free_entry(root); - } + if (entry) + snd_info_set_text_ops(entry, dg00x, proc_read_clock); } diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index a55e68ec1832..b886b541c94b 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -41,12 +41,8 @@ static void add_node(struct snd_ff *ff, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(ff->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, ff, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, ff, op); } void snd_ff_proc_init(struct snd_ff *ff) @@ -62,10 +58,6 @@ void snd_ff_proc_init(struct snd_ff *ff) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(ff, root, "status", proc_dump_status); } diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index 779ecec5af62..9fa5c34a9572 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c @@ -199,12 +199,8 @@ add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, struct snd_info_entry *entry; entry = snd_info_create_card_entry(efw->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, efw, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, efw, op); } void snd_efw_proc_init(struct snd_efw *efw) @@ -220,10 +216,6 @@ void snd_efw_proc_init(struct snd_efw *efw) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(efw, root, "clock", proc_read_clock); add_node(efw, root, "firmware", proc_read_hwinfo); diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index ab6830a6d242..94327853620a 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c @@ -87,12 +87,8 @@ static void add_node(struct snd_motu *motu, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(motu->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, motu, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, motu, op); } void snd_motu_proc_init(struct snd_motu *motu) @@ -108,10 +104,6 @@ void snd_motu_proc_init(struct snd_motu *motu) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(motu, root, "clock", proc_read_clock); add_node(motu, root, "format", proc_read_format); diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c index 27dac071bc73..644107e3782e 100644 --- a/sound/firewire/oxfw/oxfw-proc.c +++ b/sound/firewire/oxfw/oxfw-proc.c @@ -83,12 +83,8 @@ static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(oxfw->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, oxfw, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, oxfw, op); } void snd_oxfw_proc_init(struct snd_oxfw *oxfw) @@ -104,10 +100,6 @@ void snd_oxfw_proc_init(struct snd_oxfw *oxfw) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(oxfw, root, "formation", proc_read_formation); } diff --git a/sound/firewire/tascam/tascam-proc.c b/sound/firewire/tascam/tascam-proc.c index fee3bf32a0da..8bc8d277394a 100644 --- a/sound/firewire/tascam/tascam-proc.c +++ b/sound/firewire/tascam/tascam-proc.c @@ -58,12 +58,8 @@ static void add_node(struct snd_tscm *tscm, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(tscm->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, tscm, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, tscm, op); } void snd_tscm_proc_init(struct snd_tscm *tscm) @@ -79,10 +75,6 @@ void snd_tscm_proc_init(struct snd_tscm *tscm) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(tscm, root, "firmware", proc_read_firmware); } From 413d452f3a1c99274d6a9d967fafa7a23c850b4e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:35:16 +0100 Subject: [PATCH 273/461] ALSA: opl4: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Signed-off-by: Takashi Iwai --- sound/drivers/opl4/opl4_proc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index 16b24091d799..f1b839a0e7b7 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -114,10 +114,6 @@ int snd_opl4_create_proc(struct snd_opl4 *opl4) entry->c.ops = &snd_opl4_mem_proc_ops; entry->module = THIS_MODULE; entry->private_data = opl4; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } opl4->proc_entry = entry; return 0; From 69fad28cefe33a8d45daef7ef9f5abb69ec2d343 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:36:02 +0100 Subject: [PATCH 274/461] ALSA: emux: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Signed-off-by: Takashi Iwai --- sound/synth/emux/emux_proc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index a82b4053bee8..c14781ac7941 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c @@ -115,10 +115,6 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = emu; entry->c.text.read = snd_emux_proc_info_read; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - else - emu->proc = entry; } void snd_emux_proc_free(struct snd_emux *emu) From a8d149813b4456b689effb1f10accdc937566703 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 15:02:11 +0100 Subject: [PATCH 275/461] ALSA: pcm: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls, as well as cleaning up the calls of substream proc entries with a common helper. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 81 ++++++++++++++--------------------------- sound/core/pcm_memory.c | 21 +++++------ 2 files changed, 37 insertions(+), 65 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 4f45b3000347..7b63aee124af 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -528,28 +528,17 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } pstr->proc_root = entry; entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); - if (entry) { + if (entry) snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root); if (entry) { - entry->c.text.read = snd_pcm_xrun_debug_read; + snd_info_set_text_ops(entry, pstr, snd_pcm_xrun_debug_read); entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= 0200; - entry->private_data = pstr; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } #endif return 0; @@ -562,6 +551,21 @@ static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) return 0; } +static struct snd_info_entry * +create_substream_info_entry(struct snd_pcm_substream *substream, + const char *name, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *)) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_card_entry(substream->pcm->card, name, + substream->proc_root); + if (entry) + snd_info_set_text_ops(entry, substream, read); + return entry; +} + static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { struct snd_info_entry *entry; @@ -576,53 +580,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } substream->proc_root = entry; - entry = snd_info_create_card_entry(card, "info", substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_info_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "hw_params", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_hw_params_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "sw_params", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_sw_params_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "status", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_status_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } + + create_substream_info_entry(substream, "info", + snd_pcm_substream_proc_info_read); + create_substream_info_entry(substream, "hw_params", + snd_pcm_substream_proc_hw_params_read); + create_substream_info_entry(substream, "sw_params", + snd_pcm_substream_proc_sw_params_read); + create_substream_info_entry(substream, "status", + snd_pcm_substream_proc_status_read); #ifdef CONFIG_SND_PCM_XRUN_DEBUG - entry = snd_info_create_card_entry(card, "xrun_injection", - substream->proc_root); + entry = create_substream_info_entry(substream, "xrun_injection", NULL); if (entry) { - entry->private_data = substream; - entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | 0200; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 9a98bc61461f..4012a3a01de1 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -192,20 +192,19 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) { struct snd_info_entry *entry; - if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_lib_preallocate_proc_read; + entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", + substream->proc_root); + if (entry) { + snd_info_set_text_ops(entry, substream, + snd_pcm_lib_preallocate_proc_read); entry->c.text.write = snd_pcm_lib_preallocate_proc_write; entry->mode |= 0200; - entry->private_data = substream; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; - entry->private_data = substream; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } + entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", + substream->proc_root); + if (entry) + snd_info_set_text_ops(entry, substream, + snd_pcm_lib_preallocate_max_proc_read); } #else /* !CONFIG_SND_VERBOSE_PROCFS */ From 4a471d7cc99d6a2f7c58d11c3f1a9665ca60dcd6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:55:19 +0100 Subject: [PATCH 276/461] ALSA: compress: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/compress_offload.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index f7d2b373da0a..a1a6fd75cfe5 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -1015,22 +1015,13 @@ static int snd_compress_proc_init(struct snd_compr *compr) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } compr->proc_root = entry; entry = snd_info_create_card_entry(compr->card, "info", compr->proc_root); - if (entry) { + if (entry) snd_info_set_text_ops(entry, compr, snd_compress_proc_info_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } compr->proc_info_entry = entry; return 0; From eaffef0d5fca38939ac986de4625f4f070c49346 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:05:21 +0100 Subject: [PATCH 277/461] ALSA: pci: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls, as well as dropping the superfluous setup of SNDRV_INFO_CONTENT_TEXT. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_proc.c | 26 +++++++------------ sound/pci/cs46xx/dsp_spos.c | 40 ++++------------------------- sound/pci/cs46xx/dsp_spos_scb_lib.c | 6 ----- 3 files changed, 14 insertions(+), 58 deletions(-) diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index e120a11c69e8..20516b6907b5 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -436,25 +436,20 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) return; prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); - if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + entry = snd_info_create_card_entry(ac97->bus->card, name, + ac97->bus->proc); + if (entry) snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } ac97->proc = entry; sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); - if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + entry = snd_info_create_card_entry(ac97->bus->card, name, + ac97->bus->proc); + if (entry) { snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); #ifdef CONFIG_SND_DEBUG entry->mode |= 0200; entry->c.text.write = snd_ac97_proc_regs_write; #endif - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ac97->proc_regs = entry; } @@ -473,13 +468,10 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) char name[32]; sprintf(name, "codec97#%d", bus->num); - if ((entry = snd_info_create_card_entry(bus->card, name, bus->card->proc_root)) != NULL) { + entry = snd_info_create_card_entry(bus->card, name, + bus->card->proc_root); + if (entry) entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } bus->proc = entry; } diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 5fc497c6d738..3555f839371e 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -799,30 +799,20 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) ins->snd_card = card; - if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; + entry = snd_info_create_card_entry(card, "dsp", card->proc_root); + if (entry) entry->mode = S_IFDIR | 0555; - - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - ins->proc_dsp_dir = entry; if (!ins->proc_dsp_dir) return -ENOMEM; - if ((entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; + entry = snd_info_create_card_entry(card, "spos_symbols", + ins->proc_dsp_dir); + if (entry) { entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_sym_info_entry = entry; @@ -831,10 +821,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_modules_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_modules_info_entry = entry; @@ -843,10 +829,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_parameter_dump_info_entry = entry; @@ -855,10 +837,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_sample_dump_info_entry = entry; @@ -867,10 +845,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_task_tree_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_task_info_entry = entry; @@ -879,10 +853,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry->private_data = chip; entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_scb_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } } ins->proc_scb_info_entry = entry; diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 8d0a3d357345..e056f9dc228b 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -271,12 +271,6 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, entry->mode = S_IFREG | 0644; entry->c.text.read = cs46xx_dsp_proc_scb_info_read; - - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - kfree (scb_info); - entry = NULL; - } } out: scb->proc_info = entry; From 7453e1dafdec076f87384c8647d2960affd57ecc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:53:04 +0100 Subject: [PATCH 278/461] ALSA: info: Add standard helpers for card proc file entries Two new helper functions are added here for cleaning up the existing lengthy calls. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/info.h | 35 +++++++++++++++++++++++++++++++++++ sound/core/info.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/sound/info.h b/include/sound/info.h index becdf66d2825..96530f7599e1 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -160,6 +160,13 @@ static inline void snd_info_set_text_ops(struct snd_info_entry *entry, entry->c.text.read = read; } +int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)); + int snd_info_check_reserved_words(const char *str); #else @@ -189,10 +196,38 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name, static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), void *private_data, void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} +static inline int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)) +{ + return 0; +} static inline int snd_info_check_reserved_words(const char *str) { return 1; } #endif +/** + * snd_card_ro_proc_new - Create a read-only text proc file entry for the card + * @card: the card instance + * @name: the file name + * @private_data: the arbitrary private data + * @read: the read callback + * + * This proc file entry will be registered via snd_card_register() call, and + * it will be removed automatically at the card removal, too. + */ +static inline int +snd_card_ro_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *)) +{ + return snd_card_rw_proc_new(card, name, private_data, read, NULL); +} + /* * OSS info part */ diff --git a/sound/core/info.c b/sound/core/info.c index 5cd00629c0f5..6c149fa54d2d 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -866,6 +866,38 @@ int snd_info_register(struct snd_info_entry *entry) } EXPORT_SYMBOL(snd_info_register); +/** + * snd_card_rw_proc_new - Create a read/write text proc file entry for the card + * @card: the card instance + * @name: the file name + * @private_data: the arbitrary private data + * @read: the read callback + * @write: the write callback, NULL for read-only + * + * This proc file entry will be registered via snd_card_register() call, and + * it will be removed automatically at the card removal, too. + */ +int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_card_entry(card, name, card->proc_root); + if (!entry) + return -ENOMEM; + snd_info_set_text_ops(entry, private_data, read); + if (write) { + entry->mode |= 0200; + entry->c.text.write = write; + } + return 0; +} +EXPORT_SYMBOL_GPL(snd_card_rw_proc_new); + /* */ From 815d808c7bfc91edbf25813cea54709f4a805c71 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 15:58:33 +0100 Subject: [PATCH 279/461] ALSA: drivers: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 10 ++-------- sound/drivers/dummy.c | 10 ++-------- sound/drivers/vx/vx_core.c | 5 +---- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 65c903b639c2..8c3fbe1276be 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1133,16 +1133,10 @@ static void print_cable_info(struct snd_info_entry *entry, static int loopback_proc_new(struct loopback *loopback, int cidx) { char name[32]; - struct snd_info_entry *entry; - int err; snprintf(name, sizeof(name), "cable#%d", cidx); - err = snd_card_proc_new(loopback->card, name, &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, loopback, print_cable_info); - return 0; + return snd_card_ro_proc_new(loopback->card, name, loopback, + print_cable_info); } static int loopback_probe(struct platform_device *devptr) diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index c8d31550e9a1..2672c2e13334 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -1037,14 +1037,8 @@ static void dummy_proc_write(struct snd_info_entry *entry, static void dummy_proc_init(struct snd_dummy *chip) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) { - snd_info_set_text_ops(entry, chip, dummy_proc_read); - entry->c.text.write = dummy_proc_write; - entry->mode |= 0200; - entry->private_data = chip; - } + snd_card_rw_proc_new(chip->card, "dummy_pcm", chip, + dummy_proc_read, dummy_proc_write); } #else #define dummy_proc_init(x) diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 19496fa486aa..543945643a76 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -643,10 +643,7 @@ static void vx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *b static void vx_proc_init(struct vx_core *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "vx-status", &entry)) - snd_info_set_text_ops(entry, chip, vx_proc_read); + snd_card_ro_proc_new(chip->card, "vx-status", chip, vx_proc_read); } From 1bac5e1c814220e1a199ceffb34b427930283d84 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:00:13 +0100 Subject: [PATCH 280/461] ALSA: isa: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_irq.c | 5 +---- sound/isa/gus/gus_mem.c | 6 +----- sound/isa/opti9xx/miro.c | 5 +---- sound/isa/sb/sb16_csp.c | 5 ++--- 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index 2055aff71b50..0ca6c38e2ed9 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c @@ -140,10 +140,7 @@ static void snd_gus_irq_info_read(struct snd_info_entry *entry, void snd_gus_irq_profile_init(struct snd_gus_card *gus) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(gus->card, "gusirq", &entry)) - snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read); + snd_card_ro_proc_new(gus->card, "gusirq", gus, snd_gus_irq_info_read); } #endif diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index af888a022fc0..4ac76f46dd76 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -238,9 +238,6 @@ int snd_gf1_mem_init(struct snd_gus_card * gus) { struct snd_gf1_mem *alloc; struct snd_gf1_mem_block block; -#ifdef CONFIG_SND_DEBUG - struct snd_info_entry *entry; -#endif alloc = &gus->gf1.mem_alloc; mutex_init(&alloc->memory_mutex); @@ -263,8 +260,7 @@ int snd_gf1_mem_init(struct snd_gus_card * gus) if (snd_gf1_mem_xalloc(alloc, &block) == NULL) return -ENOMEM; #ifdef CONFIG_SND_DEBUG - if (! snd_card_proc_new(gus->card, "gusmem", &entry)) - snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read); + snd_card_ro_proc_new(gus->card, "gusmem", gus, snd_gf1_mem_info_read); #endif return 0; } diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c6136c6b0214..997cdfd7b1ea 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -997,10 +997,7 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, static void snd_miro_proc_init(struct snd_card *card, struct snd_miro *miro) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(card, "miro", &entry)) - snd_info_set_text_ops(entry, miro, snd_miro_proc_read); + snd_card_ro_proc_new(card, "miro", miro, snd_miro_proc_read); } /* diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index bf3db0d2ea12..a09ad57b8313 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1126,10 +1126,9 @@ static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p) static int init_proc_entry(struct snd_sb_csp * p, int device) { char name[16]; - struct snd_info_entry *entry; + sprintf(name, "cspD%d", device); - if (! snd_card_proc_new(p->chip->card, name, &entry)) - snd_info_set_text_ops(entry, p, info_read); + snd_card_ro_proc_new(p->chip->card, name, p, info_read); return 0; } From 5a170e9e4c74bc7f9aa57861c90e5813d63bfdab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:00:54 +0100 Subject: [PATCH 281/461] ALSA: i2c: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/i2c/other/ak4113.c | 5 ++--- sound/i2c/other/ak4114.c | 5 ++--- sound/i2c/other/ak4xxx-adda.c | 8 +------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c index 4099e6062d3c..573599d0378d 100644 --- a/sound/i2c/other/ak4113.c +++ b/sound/i2c/other/ak4113.c @@ -492,9 +492,8 @@ static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry, static void snd_ak4113_proc_init(struct ak4113 *ak4113) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(ak4113->card, "ak4113", &entry)) - snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read); + snd_card_ro_proc_new(ak4113->card, "ak4113", ak4113, + snd_ak4113_proc_regs_read); } int snd_ak4113_build(struct ak4113 *ak4113, diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 7fb1aeb46915..76afb975782d 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -465,9 +465,8 @@ static void snd_ak4114_proc_regs_read(struct snd_info_entry *entry, static void snd_ak4114_proc_init(struct ak4114 *ak4114) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(ak4114->card, "ak4114", &entry)) - snd_info_set_text_ops(entry, ak4114, snd_ak4114_proc_regs_read); + snd_card_ro_proc_new(ak4114->card, "ak4114", ak4114, + snd_ak4114_proc_regs_read); } int snd_ak4114_build(struct ak4114 *ak4114, diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 7f2761a2e7c8..62a6c5fa96b5 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -875,13 +875,7 @@ static void proc_regs_read(struct snd_info_entry *entry, static int proc_init(struct snd_akm4xxx *ak) { - struct snd_info_entry *entry; - int err; - err = snd_card_proc_new(ak->card, ak->name, &entry); - if (err < 0) - return err; - snd_info_set_text_ops(entry, ak, proc_regs_read); - return 0; + return snd_card_ro_proc_new(ak->card, ak->name, ak, proc_regs_read); } int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) From 47f2769b4b2e267cba135fc19c89c32d202b1415 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:01:39 +0100 Subject: [PATCH 282/461] ALSA: pci: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ad1889.c | 6 +-- sound/pci/ak4531_codec.c | 5 +- sound/pci/ali5451/ali5451.c | 4 +- sound/pci/asihpi/asihpi.c | 6 +-- sound/pci/atiixp.c | 5 +- sound/pci/atiixp_modem.c | 6 +-- sound/pci/ca0106/ca0106_proc.c | 40 ++++++---------- sound/pci/cmipci.c | 5 +- sound/pci/cs4281.c | 3 +- sound/pci/emu10k1/emu10k1x.c | 12 ++--- sound/pci/emu10k1/emuproc.c | 81 ++++++++++++-------------------- sound/pci/ens1370.c | 6 +-- sound/pci/hda/hda_proc.c | 9 +--- sound/pci/ice1712/ice1712.c | 5 +- sound/pci/ice1712/ice1724.c | 5 +- sound/pci/ice1712/pontis.c | 12 ++--- sound/pci/ice1712/prodigy192.c | 5 +- sound/pci/ice1712/prodigy_hifi.c | 8 +--- sound/pci/ice1712/quartet.c | 4 +- sound/pci/intel8x0.c | 6 +-- sound/pci/intel8x0m.c | 6 +-- sound/pci/korg1212/korg1212.c | 6 +-- sound/pci/lola/lola_proc.c | 16 ++----- sound/pci/lx6464es/lx6464es.c | 8 +--- sound/pci/mixart/mixart.c | 6 +-- sound/pci/oxygen/oxygen_lib.c | 5 +- sound/pci/pcxhr/pcxhr.c | 21 +++------ sound/pci/riptide/riptide.c | 6 +-- sound/pci/rme32.c | 5 +- sound/pci/rme96.c | 5 +- sound/pci/rme9652/hdsp.c | 5 +- sound/pci/rme9652/hdspm.c | 55 +++++++++------------- sound/pci/rme9652/rme9652.c | 6 +-- sound/pci/sonicvibes.c | 6 +-- sound/pci/trident/trident_main.c | 4 +- sound/pci/via82xx.c | 6 +-- sound/pci/via82xx_modem.c | 6 +-- sound/pci/ymfpci/ymfpci_main.c | 6 +-- 38 files changed, 133 insertions(+), 278 deletions(-) diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index d9c54c08e2db..f333bbf41870 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -741,10 +741,8 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe static void snd_ad1889_proc_init(struct snd_ad1889 *chip) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(chip->card, chip->card->driver, &entry)) - snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read); + snd_card_ro_proc_new(chip->card, chip->card->driver, + chip, snd_ad1889_proc_read); } static const struct ac97_quirk ac97_quirks[] = { diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index 2fb1fbba3e5e..11e902cac71b 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -481,8 +481,5 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(card, "ak4531", &entry)) - snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); + snd_card_ro_proc_new(card, "ak4531", ak4531, snd_ak4531_proc_read); } diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index e781ccca1793..f7fbe05836b3 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -2049,9 +2049,7 @@ static void snd_ali_proc_read(struct snd_info_entry *entry, static void snd_ali_proc_init(struct snd_ali *codec) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(codec->card, "ali5451", &entry)) - snd_info_set_text_ops(entry, codec, snd_ali_proc_read); + snd_card_ro_proc_new(codec->card, "ali5451", codec, snd_ali_proc_read); } static int snd_ali_resources(struct snd_ali *codec) diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index aad74e809797..32b2f9802479 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -2782,10 +2782,8 @@ snd_asihpi_proc_read(struct snd_info_entry *entry, static void snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(asihpi->card, "info", &entry)) - snd_info_set_text_ops(entry, asihpi, snd_asihpi_proc_read); + snd_card_ro_proc_new(asihpi->card, "info", asihpi, + snd_asihpi_proc_read); } /*------------------------------------------------------------ diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 7715d26916ac..169763c88f5e 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1543,10 +1543,7 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, static void snd_atiixp_proc_init(struct atiixp *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "atiixp", &entry)) - snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); + snd_card_ro_proc_new(chip->card, "atiixp", chip, snd_atiixp_proc_read); } diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index a357a8e2e73d..cece66bb3644 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -1170,10 +1170,8 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, static void snd_atiixp_proc_init(struct atiixp_modem *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) - snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); + snd_card_ro_proc_new(chip->card, "atiixp-modem", chip, + snd_atiixp_proc_read); } diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index a2c85cc37972..f5b8934db735 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -424,30 +424,20 @@ static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry, int snd_ca0106_proc_init(struct snd_ca0106 *emu) { - struct snd_info_entry *entry; - - if(! snd_card_proc_new(emu->card, "iec958", &entry)) - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_iec958); - if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32); - entry->c.text.write = snd_ca0106_proc_reg_write32; - entry->mode |= 0200; - } - if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16); - if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry)) - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read8); - if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); - entry->c.text.write = snd_ca0106_proc_reg_write; - entry->mode |= 0200; - } - if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { - entry->c.text.write = snd_ca0106_proc_i2c_write; - entry->private_data = emu; - entry->mode |= 0200; - } - if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) - snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); + snd_card_ro_proc_new(emu->card, "iec958", emu, snd_ca0106_proc_iec958); + snd_card_rw_proc_new(emu->card, "ca0106_reg32", emu, + snd_ca0106_proc_reg_read32, + snd_ca0106_proc_reg_write32); + snd_card_ro_proc_new(emu->card, "ca0106_reg16", emu, + snd_ca0106_proc_reg_read16); + snd_card_ro_proc_new(emu->card, "ca0106_reg8", emu, + snd_ca0106_proc_reg_read8); + snd_card_rw_proc_new(emu->card, "ca0106_regs1", emu, + snd_ca0106_proc_reg_read1, + snd_ca0106_proc_reg_write); + snd_card_rw_proc_new(emu->card, "ca0106_i2c", emu, NULL, + snd_ca0106_proc_i2c_write); + snd_card_ro_proc_new(emu->card, "ca0106_regs2", emu, + snd_ca0106_proc_reg_read2); return 0; } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 5bbf31c1695c..701be04aed53 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2792,10 +2792,7 @@ static void snd_cmipci_proc_read(struct snd_info_entry *entry, static void snd_cmipci_proc_init(struct cmipci *cm) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(cm->card, "cmipci", &entry)) - snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read); + snd_card_ro_proc_new(cm->card, "cmipci", cm, snd_cmipci_proc_read); } static const struct pci_device_id snd_cmipci_ids[] = { diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index a9fb819cad1d..15bbf9564c82 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1174,8 +1174,7 @@ static void snd_cs4281_proc_init(struct cs4281 *chip) { struct snd_info_entry *entry; - if (! snd_card_proc_new(chip->card, "cs4281", &entry)) - snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); + snd_card_ro_proc_new(chip->card, "cs4281", chip, snd_cs4281_proc_read); if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 611589cbdad6..576c7bd03a1a 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1065,15 +1065,9 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, static int snd_emu10k1x_proc_init(struct emu10k1x *emu) { - struct snd_info_entry *entry; - - if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read); - entry->c.text.write = snd_emu10k1x_proc_reg_write; - entry->mode |= 0200; - entry->private_data = emu; - } - + snd_card_rw_proc_new(emu->card, "emu10k1x_regs", emu, + snd_emu10k1x_proc_reg_read, + snd_emu10k1x_proc_reg_write); return 0; } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index b57008031792..a3d9f06e8e6a 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -568,55 +568,40 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG if (emu->card_capabilities->emu_model) { - if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); - } - if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); - entry->c.text.write = snd_emu_proc_io_reg_write; - entry->mode |= 0200; - } - if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a); - entry->c.text.write = snd_emu_proc_ptr_reg_write00; - entry->mode |= 0200; - } - if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b); - entry->c.text.write = snd_emu_proc_ptr_reg_write00; - entry->mode |= 0200; - } - if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a); - entry->c.text.write = snd_emu_proc_ptr_reg_write20; - entry->mode |= 0200; - } - if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b); - entry->c.text.write = snd_emu_proc_ptr_reg_write20; - entry->mode |= 0200; - } - if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c); - entry->c.text.write = snd_emu_proc_ptr_reg_write20; - entry->mode |= 0200; + snd_card_ro_proc_new(emu->card, "emu1010_regs", + emu, snd_emu_proc_emu1010_reg_read); } + snd_card_rw_proc_new(emu->card, "io_regs", emu, + snd_emu_proc_io_reg_read, + snd_emu_proc_io_reg_write); + snd_card_rw_proc_new(emu->card, "ptr_regs00a", emu, + snd_emu_proc_ptr_reg_read00a, + snd_emu_proc_ptr_reg_write00); + snd_card_rw_proc_new(emu->card, "ptr_regs00b", emu, + snd_emu_proc_ptr_reg_read00b, + snd_emu_proc_ptr_reg_write00); + snd_card_rw_proc_new(emu->card, "ptr_regs20a", emu, + snd_emu_proc_ptr_reg_read20a, + snd_emu_proc_ptr_reg_write20); + snd_card_rw_proc_new(emu->card, "ptr_regs20b", emu, + snd_emu_proc_ptr_reg_read20b, + snd_emu_proc_ptr_reg_write20); + snd_card_rw_proc_new(emu->card, "ptr_regs20c", emu, + snd_emu_proc_ptr_reg_read20c, + snd_emu_proc_ptr_reg_write20); #endif - if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read); + snd_card_ro_proc_new(emu->card, "emu10k1", emu, snd_emu10k1_proc_read); - if (emu->card_capabilities->emu10k2_chip) { - if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_spdif_read); - } - if (emu->card_capabilities->ca0151_chip) { - if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_rates_read); - } + if (emu->card_capabilities->emu10k2_chip) + snd_card_ro_proc_new(emu->card, "spdif-in", emu, + snd_emu10k1_proc_spdif_read); + if (emu->card_capabilities->ca0151_chip) + snd_card_ro_proc_new(emu->card, "capture-rates", emu, + snd_emu10k1_proc_rates_read); - if (! snd_card_proc_new(emu->card, "voices", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_voices_read); + snd_card_ro_proc_new(emu->card, "voices", emu, + snd_emu10k1_proc_voices_read); if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; @@ -646,11 +631,7 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) entry->size = emu->audigy ? A_TOTAL_SIZE_CODE : TOTAL_SIZE_CODE; entry->c.ops = &snd_emu10k1_proc_ops_fx8010; } - if (! snd_card_proc_new(emu->card, "fx8010_acode", &entry)) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = emu; - entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; - entry->c.text.read = snd_emu10k1_proc_acode_read; - } + snd_card_ro_proc_new(emu->card, "fx8010_acode", emu, + snd_emu10k1_proc_acode_read); return 0; } diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 1f2960ecc57e..1cfff35e370e 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1902,10 +1902,8 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry, static void snd_ensoniq_proc_init(struct ensoniq *ensoniq) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) - snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read); + snd_card_ro_proc_new(ensoniq->card, "audiopci", ensoniq, + snd_ensoniq_proc_read); } /* diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index a65740419650..853842987fa1 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -919,15 +919,8 @@ static void print_codec_info(struct snd_info_entry *entry, int snd_hda_codec_proc_new(struct hda_codec *codec) { char name[32]; - struct snd_info_entry *entry; - int err; snprintf(name, sizeof(name), "codec#%d", codec->core.addr); - err = snd_card_proc_new(codec->card, name, &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, codec, print_codec_info); - return 0; + return snd_card_ro_proc_new(codec->card, name, codec, print_codec_info); } diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index dda9b26192cb..fa7d90ee6e2d 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1603,10 +1603,7 @@ static void snd_ice1712_proc_read(struct snd_info_entry *entry, static void snd_ice1712_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(ice->card, "ice1712", &entry)) - snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read); + snd_card_ro_proc_new(ice->card, "ice1712", ice, snd_ice1712_proc_read); } /* diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 42994cf36156..a7d640ee4a17 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1571,10 +1571,7 @@ static void snd_vt1724_proc_read(struct snd_info_entry *entry, static void snd_vt1724_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(ice->card, "ice1724", &entry)) - snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read); + snd_card_ro_proc_new(ice->card, "ice1724", ice, snd_vt1724_proc_read); } /* diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 93b8cfc6636f..f499f1e8d0c9 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -659,12 +659,8 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff static void wm_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { - snd_info_set_text_ops(entry, ice, wm_proc_regs_read); - entry->mode |= 0200; - entry->c.text.write = wm_proc_regs_write; - } + snd_card_rw_proc_new(ice->card, "wm_codec", ice, wm_proc_regs_read, + wm_proc_regs_write); } static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) @@ -684,9 +680,7 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff static void cs_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) - snd_info_set_text_ops(entry, ice, cs_proc_regs_read); + snd_card_ro_proc_new(ice->card, "cs_codec", ice, cs_proc_regs_read); } diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 3919aed39ca0..d243309029d3 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -651,9 +651,8 @@ static void stac9460_proc_regs_read(struct snd_info_entry *entry, static void stac9460_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) - snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); + snd_card_ro_proc_new(ice->card, "stac9460_codec", ice, + stac9460_proc_regs_read); } diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index c97b5528e4b8..72f252c936e5 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -904,12 +904,8 @@ static void wm_proc_regs_read(struct snd_info_entry *entry, static void wm_proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { - snd_info_set_text_ops(entry, ice, wm_proc_regs_read); - entry->mode |= 0200; - entry->c.text.write = wm_proc_regs_write; - } + snd_card_rw_proc_new(ice->card, "wm_codec", ice, wm_proc_regs_read, + wm_proc_regs_write); } static int prodigy_hifi_add_controls(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 5bc836241c97..8ad964ee0b65 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -502,9 +502,7 @@ static void proc_regs_read(struct snd_info_entry *entry, static void proc_init(struct snd_ice1712 *ice) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(ice->card, "quartet", &entry)) - snd_info_set_text_ops(entry, ice, proc_regs_read); + snd_card_ro_proc_new(ice->card, "quartet", ice, proc_regs_read); } static int qtet_mute_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 885e1d488ed6..2784bf48cf5a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2863,10 +2863,8 @@ static void snd_intel8x0_proc_read(struct snd_info_entry * entry, static void snd_intel8x0_proc_init(struct intel8x0 *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) - snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); + snd_card_ro_proc_new(chip->card, "intel8x0", chip, + snd_intel8x0_proc_read); } static int snd_intel8x0_dev_free(struct snd_device *device) diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 44eb9e28a1eb..43c654e15452 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1084,10 +1084,8 @@ static void snd_intel8x0m_proc_read(struct snd_info_entry * entry, static void snd_intel8x0m_proc_init(struct intel8x0m *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "intel8x0m", &entry)) - snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read); + snd_card_ro_proc_new(chip->card, "intel8x0m", chip, + snd_intel8x0m_proc_read); } static int snd_intel8x0m_dev_free(struct snd_device *device) diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 4e189a93f475..fe4aba8a08ea 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2090,10 +2090,8 @@ static void snd_korg1212_proc_read(struct snd_info_entry *entry, static void snd_korg1212_proc_init(struct snd_korg1212 *korg1212) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) - snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read); + snd_card_ro_proc_new(korg1212->card, "korg1212", korg1212, + snd_korg1212_proc_read); } static int diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c index 904e3c4f4dfe..1603f9c81897 100644 --- a/sound/pci/lola/lola_proc.c +++ b/sound/pci/lola/lola_proc.c @@ -208,15 +208,9 @@ static void lola_proc_regs_read(struct snd_info_entry *entry, void lola_proc_debug_new(struct lola *chip) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(chip->card, "codec", &entry)) - snd_info_set_text_ops(entry, chip, lola_proc_codec_read); - if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) { - snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read); - entry->mode |= 0200; - entry->c.text.write = lola_proc_codec_rw_write; - } - if (!snd_card_proc_new(chip->card, "regs", &entry)) - snd_info_set_text_ops(entry, chip, lola_proc_regs_read); + snd_card_ro_proc_new(chip->card, "codec", chip, lola_proc_codec_read); + snd_card_rw_proc_new(chip->card, "codec_rw", chip, + lola_proc_codec_rw_read, + lola_proc_codec_rw_write); + snd_card_ro_proc_new(chip->card, "regs", chip, lola_proc_regs_read); } diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 54f6252faca6..198ccf9b5eb3 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -948,13 +948,7 @@ static void lx_proc_levels_read(struct snd_info_entry *entry, static int lx_proc_create(struct snd_card *card, struct lx6464es *chip) { - struct snd_info_entry *entry; - int err = snd_card_proc_new(card, "levels", &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, chip, lx_proc_levels_read); - return 0; + return snd_card_ro_proc_new(card, "levels", chip, lx_proc_levels_read); } diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 9cd297a42f24..92f616df3863 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1220,10 +1220,8 @@ static void snd_mixart_proc_init(struct snd_mixart *chip) struct snd_info_entry *entry; /* text interface to read perf and temp meters */ - if (! snd_card_proc_new(chip->card, "board_info", &entry)) { - entry->private_data = chip; - entry->c.text.read = snd_mixart_proc_read; - } + snd_card_ro_proc_new(chip->card, "board_info", chip, + snd_mixart_proc_read); if (! snd_card_proc_new(chip->card, "mixart_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index d4cfff7e49e1..3ae9dd4b39e8 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -244,10 +244,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, static void oxygen_proc_init(struct oxygen *chip) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(chip->card, "oxygen", &entry)) - snd_info_set_text_ops(entry, chip, oxygen_proc_read); + snd_card_ro_proc_new(chip->card, "oxygen", chip, oxygen_proc_read); } static const struct pci_device_id * diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index e57da4036231..4ab7efc6e9f7 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1454,21 +1454,14 @@ static void pcxhr_proc_ltc(struct snd_info_entry *entry, static void pcxhr_proc_init(struct snd_pcxhr *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "info", &entry)) - snd_info_set_text_ops(entry, chip, pcxhr_proc_info); - if (! snd_card_proc_new(chip->card, "sync", &entry)) - snd_info_set_text_ops(entry, chip, pcxhr_proc_sync); + snd_card_ro_proc_new(chip->card, "info", chip, pcxhr_proc_info); + snd_card_ro_proc_new(chip->card, "sync", chip, pcxhr_proc_sync); /* gpio available on stereo sound cards only */ - if (chip->mgr->is_hr_stereo && - !snd_card_proc_new(chip->card, "gpio", &entry)) { - snd_info_set_text_ops(entry, chip, pcxhr_proc_gpio_read); - entry->c.text.write = pcxhr_proc_gpo_write; - entry->mode |= 0200; - } - if (!snd_card_proc_new(chip->card, "ltc", &entry)) - snd_info_set_text_ops(entry, chip, pcxhr_proc_ltc); + if (chip->mgr->is_hr_stereo) + snd_card_rw_proc_new(chip->card, "gpio", chip, + pcxhr_proc_gpio_read, + pcxhr_proc_gpo_write); + snd_card_ro_proc_new(chip->card, "ltc", chip, pcxhr_proc_ltc); } /* end of proc interface */ diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 1d431c8052d6..8d1a56a9bcfd 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1973,10 +1973,8 @@ snd_riptide_proc_read(struct snd_info_entry *entry, static void snd_riptide_proc_init(struct snd_riptide *chip) { - struct snd_info_entry *entry; - - if (!snd_card_proc_new(chip->card, "riptide", &entry)) - snd_info_set_text_ops(entry, chip, snd_riptide_proc_read); + snd_card_ro_proc_new(chip->card, "riptide", chip, + snd_riptide_proc_read); } static int snd_riptide_mixer(struct snd_riptide *chip) diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 3ac8c71d567c..c6bcc0715716 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1568,10 +1568,7 @@ snd_rme32_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe static void snd_rme32_proc_init(struct rme32 *rme32) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(rme32->card, "rme32", &entry)) - snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read); + snd_card_ro_proc_new(rme32->card, "rme32", rme32, snd_rme32_proc_read); } /* diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index c56702e6cb60..42c6b5e09072 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1868,10 +1868,7 @@ snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer static void snd_rme96_proc_init(struct rme96 *rme96) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(rme96->card, "rme96", &entry)) - snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read); + snd_card_ro_proc_new(rme96->card, "rme96", rme96, snd_rme96_proc_read); } /* diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index ba99ff0e93e0..29bef48a3af3 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3708,10 +3708,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) static void snd_hdsp_proc_init(struct hdsp *hdsp) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) - snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read); + snd_card_ro_proc_new(hdsp->card, "hdsp", hdsp, snd_hdsp_proc_read); } static void snd_hdsp_free_buffers(struct hdsp *hdsp) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 679ad0415e3b..d485dd8a7b72 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -5287,44 +5287,35 @@ static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, static void snd_hdspm_proc_init(struct hdspm *hdspm) { - struct snd_info_entry *entry; + void (*read)(struct snd_info_entry *, struct snd_info_buffer *) = NULL; - if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) { - switch (hdspm->io_type) { - case AES32: - snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read_aes32); - break; - case MADI: - snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read_madi); - break; - case MADIface: - /* snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read_madiface); */ - break; - case RayDAT: - snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read_raydat); - break; - case AIO: - break; - } + switch (hdspm->io_type) { + case AES32: + read = snd_hdspm_proc_read_aes32; + break; + case MADI: + read = snd_hdspm_proc_read_madi; + break; + case MADIface: + /* read = snd_hdspm_proc_read_madiface; */ + break; + case RayDAT: + read = snd_hdspm_proc_read_raydat; + break; + case AIO: + break; } - if (!snd_card_proc_new(hdspm->card, "ports.in", &entry)) { - snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_in); - } - - if (!snd_card_proc_new(hdspm->card, "ports.out", &entry)) { - snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_out); - } + snd_card_ro_proc_new(hdspm->card, "hdspm", hdspm, read); + snd_card_ro_proc_new(hdspm->card, "ports.in", hdspm, + snd_hdspm_proc_ports_in); + snd_card_ro_proc_new(hdspm->card, "ports.out", hdspm, + snd_hdspm_proc_ports_out); #ifdef CONFIG_SND_DEBUG /* debug file to read all hdspm registers */ - if (!snd_card_proc_new(hdspm->card, "debug", &entry)) - snd_info_set_text_ops(entry, hdspm, - snd_hdspm_proc_read_debug); + snd_card_ro_proc_new(hdspm->card, "debug", hdspm, + snd_hdspm_proc_read_debug); #endif } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index edd765e22377..5228b982da5a 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1737,10 +1737,8 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff static void snd_rme9652_proc_init(struct snd_rme9652 *rme9652) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) - snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read); + snd_card_ro_proc_new(rme9652->card, "rme9652", rme9652, + snd_rme9652_proc_read); } static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652) diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 7218f38b59db..71d5ad3cffd6 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1171,10 +1171,8 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, static void snd_sonicvibes_proc_init(struct sonicvibes *sonic) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) - snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read); + snd_card_ro_proc_new(sonic->card, "sonicvibes", sonic, + snd_sonicvibes_proc_read); } /* diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index f271ea436cff..0ff32d3f5d3b 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3320,13 +3320,11 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, static void snd_trident_proc_init(struct snd_trident *trident) { - struct snd_info_entry *entry; const char *s = "trident"; if (trident->device == TRIDENT_DEVICE_ID_SI7018) s = "sis7018"; - if (! snd_card_proc_new(trident->card, s, &entry)) - snd_info_set_text_ops(entry, trident, snd_trident_proc_read); + snd_card_ro_proc_new(trident->card, s, trident, snd_trident_proc_read); } static int snd_trident_dev_free(struct snd_device *device) diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 736ac79901b3..dee1c487d6ba 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -2144,10 +2144,8 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, static void snd_via82xx_proc_init(struct via82xx *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); + snd_card_ro_proc_new(chip->card, "via82xx", chip, + snd_via82xx_proc_read); } /* diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 3f59e0279058..848bf9dbf8cd 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -937,10 +937,8 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_ static void snd_via82xx_proc_init(struct via82xx_modem *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); + snd_card_ro_proc_new(chip->card, "via82xx", chip, + snd_via82xx_proc_read); } /* diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index c688b7f481da..4d48877f211f 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -1985,11 +1985,7 @@ static void snd_ymfpci_proc_read(struct snd_info_entry *entry, static int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(card, "ymfpci", &entry)) - snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); - return 0; + return snd_card_ro_proc_new(card, "ymfpci", chip, snd_ymfpci_proc_read); } /* From 50a7a8e916edd7d5e3ce9a96c3bd1216cef93a58 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:06:27 +0100 Subject: [PATCH 283/461] ALSA: pcmcia: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index eabf29252895..910478275fd9 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -148,10 +148,7 @@ static void pdacf_proc_read(struct snd_info_entry * entry, static void pdacf_proc_init(struct snd_pdacf *chip) { - struct snd_info_entry *entry; - - if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) - snd_info_set_text_ops(entry, chip, pdacf_proc_read); + snd_card_ro_proc_new(chip->card, "pdaudiocf", chip, pdacf_proc_read); } struct snd_pdacf *snd_pdacf_create(struct snd_card *card) From 3c6ee77088a9b5188d065780b1c540f5e3d879c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:06:43 +0100 Subject: [PATCH 284/461] ALSA: sparc: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/sparc/dbri.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 7609eceba1a2..682166202098 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2510,16 +2510,10 @@ static void dbri_debug_read(struct snd_info_entry *entry, static void snd_dbri_proc(struct snd_card *card) { struct snd_dbri *dbri = card->private_data; - struct snd_info_entry *entry; - - if (!snd_card_proc_new(card, "regs", &entry)) - snd_info_set_text_ops(entry, dbri, dbri_regs_read); + snd_card_ro_proc_new(card, "regs", dbri, dbri_regs_read); #ifdef DBRI_DEBUG - if (!snd_card_proc_new(card, "debug", &entry)) { - snd_info_set_text_ops(entry, dbri, dbri_debug_read); - entry->mode = S_IFREG | 0444; /* Readable only. */ - } + snd_card_ro_proc_new(card, "debug", dbri, dbri_debug_read); #endif } From 7449054af0dcfa2839bb2da0a393bd35cf08daff Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:07:35 +0100 Subject: [PATCH 285/461] ALSA: usb: Clean up with new procfs helpers Simplify the proc fs creation code with new helper functions, snd_card_ro_proc_new() and snd_card_rw_proc_new(). Just a code refactoring and no functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 7 +++---- sound/usb/mixer_quirks.c | 6 ++---- sound/usb/proc.c | 13 +++++-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 8ad1a24c8f28..73d7dff425c1 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3441,7 +3441,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, .dev_free = snd_usb_mixer_dev_free }; struct usb_mixer_interface *mixer; - struct snd_info_entry *entry; int err; strcpy(chip->card->mixername, "USB Mixer"); @@ -3497,9 +3496,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, if (err < 0) goto _error; - if (list_empty(&chip->mixer_list) && - !snd_card_proc_new(chip->card, "usbmixer", &entry)) - snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read); + if (list_empty(&chip->mixer_list)) + snd_card_ro_proc_new(chip->card, "usbmixer", chip, + snd_usb_mixer_proc_read); list_add(&mixer->list, &chip->mixer_list); return 0; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 85ae0ff2382a..a751a18ca4c2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2195,7 +2195,6 @@ static int snd_rme_controls_create(struct usb_mixer_interface *mixer) int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; - struct snd_info_entry *entry; err = snd_usb_soundblaster_remote_init(mixer); if (err < 0) @@ -2214,9 +2213,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_audigy2nx_controls_create(mixer); if (err < 0) break; - if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) - snd_info_set_text_ops(entry, mixer, - snd_audigy2nx_proc_read); + snd_card_ro_proc_new(mixer->chip->card, "audigy2nx", + mixer, snd_audigy2nx_proc_read); break; /* EMU0204 */ diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 0ac89e294d31..e80c9d0749c9 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -61,11 +61,10 @@ static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_ void snd_usb_audio_create_proc(struct snd_usb_audio *chip) { - struct snd_info_entry *entry; - if (!snd_card_proc_new(chip->card, "usbbus", &entry)) - snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); - if (!snd_card_proc_new(chip->card, "usbid", &entry)) - snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); + snd_card_ro_proc_new(chip->card, "usbbus", chip, + proc_audio_usbbus_read); + snd_card_ro_proc_new(chip->card, "usbid", chip, + proc_audio_usbid_read); } /* @@ -167,12 +166,10 @@ static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_b void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream) { - struct snd_info_entry *entry; char name[32]; struct snd_card *card = stream->chip->card; sprintf(name, "stream%d", stream->pcm_index); - if (!snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, stream, proc_pcm_format_read); + snd_card_ro_proc_new(card, name, stream, proc_pcm_format_read); } From 9725752867cb158e076bcb6bc4bdb35d9710b1bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:10:00 +0100 Subject: [PATCH 286/461] ALSA: info: Drop unused snd_info_entry.card field It's referred only in snd_card_id_read() which can receive the card object via private_data. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/info.h | 1 - sound/core/info.c | 4 +--- sound/core/init.c | 6 ++++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/sound/info.h b/include/sound/info.h index 96530f7599e1..97fdda41e076 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -82,7 +82,6 @@ struct snd_info_entry { struct snd_info_entry_ops *ops; } c; struct snd_info_entry *parent; - struct snd_card *card; struct module *module; void *private_data; void (*private_free)(struct snd_info_entry *entry); diff --git a/sound/core/info.c b/sound/core/info.c index 6c149fa54d2d..4d23069e7928 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -750,10 +750,8 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, if (!parent) parent = card->proc_root; entry = snd_info_create_entry(name, parent); - if (entry) { + if (entry) entry->module = card->module; - entry->card = card; - } return entry; } EXPORT_SYMBOL(snd_info_create_card_entry); diff --git a/sound/core/init.c b/sound/core/init.c index 4849c611c0fe..5252a9ce13dc 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -104,7 +104,9 @@ EXPORT_SYMBOL(snd_mixer_oss_notify_callback); static void snd_card_id_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_iprintf(buffer, "%s\n", entry->card->id); + struct snd_card *card = entry->private_data; + + snd_iprintf(buffer, "%s\n", card->id); } static int init_info_for_card(struct snd_card *card) @@ -116,7 +118,7 @@ static int init_info_for_card(struct snd_card *card) dev_dbg(card->dev, "unable to create card entry\n"); return -ENOMEM; } - entry->c.text.read = snd_card_id_read; + snd_info_set_text_ops(entry, card, snd_card_id_read); card->proc_id = entry; return snd_info_card_register(card); From a858ee6655ca2f0fc6e2e5d426446bd898c92272 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:17:48 +0100 Subject: [PATCH 287/461] ALSA: info: Minor optimization Just a minor code optimization to reduce the source code size slightly. No functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/info.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 4d23069e7928..7a4e733172ee 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -463,11 +463,12 @@ static struct snd_info_entry *create_subdir(struct module *mod, } static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent); +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module); int __init snd_info_init(void) { - snd_proc_root = snd_info_create_entry("asound", NULL); + snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE); if (!snd_proc_root) return -ENOMEM; snd_proc_root->mode = S_IFDIR | 0555; @@ -684,7 +685,8 @@ EXPORT_SYMBOL(snd_info_get_str); * Return: The pointer of the new instance, or %NULL on failure. */ static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent) +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module) { struct snd_info_entry *entry; entry = kzalloc(sizeof(*entry), GFP_KERNEL); @@ -701,6 +703,7 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) INIT_LIST_HEAD(&entry->children); INIT_LIST_HEAD(&entry->list); entry->parent = parent; + entry->module = module; if (parent) list_add_tail(&entry->list, &parent->children); return entry; @@ -720,14 +723,9 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry *parent) { - struct snd_info_entry *entry; - if (!parent) parent = snd_proc_root; - entry = snd_info_create_entry(name, parent); - if (entry) - entry->module = module; - return entry; + return snd_info_create_entry(name, parent, module); } EXPORT_SYMBOL(snd_info_create_module_entry); @@ -745,14 +743,9 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry * parent) { - struct snd_info_entry *entry; - if (!parent) parent = card->proc_root; - entry = snd_info_create_entry(name, parent); - if (entry) - entry->module = card->module; - return entry; + return snd_info_create_entry(name, parent, card->module); } EXPORT_SYMBOL(snd_info_create_card_entry); From 29b2625ff605394ecd0b078e0cb67a151bb4d80c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:26:06 +0100 Subject: [PATCH 288/461] ALSA: info: Move card id proc creation into info.c The creation of card's id proc file can be moved gracefully into info.c. Also, the assignment of card->proc_id is superfluous and can be dropped. So let's do it. Basically this is no functional change but code refactoring, but one potential behavior change is that now it returns properly the error code from snd_info_card_register(), which is a good thing (tm). Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 - sound/core/info.c | 11 ++++++++++- sound/core/init.c | 33 ++++----------------------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index 36a5934cf4b1..e923c23e05dd 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -120,7 +120,6 @@ struct snd_card { struct list_head ctl_files; /* active control files */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ - struct snd_info_entry *proc_id; /* the card id */ struct proc_dir_entry *proc_root_link; /* number link to real id */ struct list_head files_list; /* all files associated to this card */ diff --git a/sound/core/info.c b/sound/core/info.c index 7a4e733172ee..96a074019c33 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -504,6 +504,14 @@ int __exit snd_info_done(void) return 0; } +static void snd_card_id_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_card *card = entry->private_data; + + snd_iprintf(buffer, "%s\n", card->id); +} + /* * create a card proc file * called from init.c @@ -521,7 +529,8 @@ int snd_info_card_create(struct snd_card *card) if (!entry) return -ENOMEM; card->proc_root = entry; - return 0; + + return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); } /* diff --git a/sound/core/init.c b/sound/core/init.c index 5252a9ce13dc..0c4dc40376a7 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -100,33 +100,6 @@ int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); EXPORT_SYMBOL(snd_mixer_oss_notify_callback); #endif -#ifdef CONFIG_SND_PROC_FS -static void snd_card_id_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_card *card = entry->private_data; - - snd_iprintf(buffer, "%s\n", card->id); -} - -static int init_info_for_card(struct snd_card *card) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_card_entry(card, "id", card->proc_root); - if (!entry) { - dev_dbg(card->dev, "unable to create card entry\n"); - return -ENOMEM; - } - snd_info_set_text_ops(entry, card, snd_card_id_read); - card->proc_id = entry; - - return snd_info_card_register(card); -} -#else /* !CONFIG_SND_PROC_FS */ -#define init_info_for_card(card) -#endif - static int check_empty_slot(struct module *module, int slot) { return !slots[slot] || !*slots[slot]; @@ -493,7 +466,6 @@ static int snd_card_do_free(struct snd_card *card) snd_device_free_all(card); if (card->private_free) card->private_free(card); - snd_info_free_entry(card->proc_id); if (snd_info_card_free(card) < 0) { dev_warn(card->dev, "unable to free card info\n"); /* Not fatal error */ @@ -797,7 +769,10 @@ int snd_card_register(struct snd_card *card) } snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); - init_info_for_card(card); + err = snd_info_card_register(card); + if (err < 0) + return err; + #if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); From 0b2338a9bf36b5ac6ed43425e2f1357fb3d3841b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:46:27 +0100 Subject: [PATCH 289/461] ALSA: cs46xx: Clean up proc file creations Again no functional changes, but only code clean up. Use a standard macro for initializing the procfs entries, also drop the info entries stored in dsp_spos_instance, as they are removed recursively by a single snd_info_free_entry() calls. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_dsp_spos.h | 6 -- sound/pci/cs46xx/dsp_spos.c | 87 ++++++++++------------------- sound/pci/cs46xx/dsp_spos_scb_lib.c | 13 ++--- 3 files changed, 33 insertions(+), 73 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_dsp_spos.h b/sound/pci/cs46xx/cs46xx_dsp_spos.h index 8008c59288a6..a02e1e19c021 100644 --- a/sound/pci/cs46xx/cs46xx_dsp_spos.h +++ b/sound/pci/cs46xx/cs46xx_dsp_spos.h @@ -177,22 +177,16 @@ struct dsp_spos_instance { /* proc fs */ struct snd_card *snd_card; struct snd_info_entry * proc_dsp_dir; - struct snd_info_entry * proc_sym_info_entry; - struct snd_info_entry * proc_modules_info_entry; - struct snd_info_entry * proc_parameter_dump_info_entry; - struct snd_info_entry * proc_sample_dump_info_entry; /* SCB's descriptors */ int nscb; int scb_highest_frag_index; struct dsp_scb_descriptor scbs[DSP_MAX_SCB_DESC]; - struct snd_info_entry * proc_scb_info_entry; struct dsp_scb_descriptor * the_null_scb; /* Task's descriptors */ int ntask; struct dsp_task_descriptor tasks[DSP_MAX_TASK_DESC]; - struct snd_info_entry * proc_task_info_entry; /* SPDIF status */ int spdif_status_out; diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 3555f839371e..c28e58602679 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -809,52 +809,39 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir); - if (entry) { - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; - } - ins->proc_sym_info_entry = entry; + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_symbol_table_read); - if ((entry = snd_info_create_card_entry(card, "spos_modules", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_modules_read; - } - ins->proc_modules_info_entry = entry; + entry = snd_info_create_card_entry(card, "spos_modules", + ins->proc_dsp_dir); + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_modules_read); - if ((entry = snd_info_create_card_entry(card, "parameter", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; - } - ins->proc_parameter_dump_info_entry = entry; + entry = snd_info_create_card_entry(card, "parameter", + ins->proc_dsp_dir); + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_parameter_dump_read); - if ((entry = snd_info_create_card_entry(card, "sample", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; - } - ins->proc_sample_dump_info_entry = entry; + entry = snd_info_create_card_entry(card, "sample", + ins->proc_dsp_dir); + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_sample_dump_read); - if ((entry = snd_info_create_card_entry(card, "task_tree", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_task_tree_read; - } - ins->proc_task_info_entry = entry; + entry = snd_info_create_card_entry(card, "task_tree", + ins->proc_dsp_dir); + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_task_tree_read); - if ((entry = snd_info_create_card_entry(card, "scb_info", ins->proc_dsp_dir)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = chip; - entry->mode = S_IFREG | 0644; - entry->c.text.read = cs46xx_dsp_proc_scb_read; - } - ins->proc_scb_info_entry = entry; + entry = snd_info_create_card_entry(card, "scb_info", + ins->proc_dsp_dir); + if (entry) + snd_info_set_text_ops(entry, chip, + cs46xx_dsp_proc_scb_read); mutex_lock(&chip->spos_mutex); /* register/update SCB's entries on proc */ @@ -876,24 +863,6 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) if (!ins) return 0; - snd_info_free_entry(ins->proc_sym_info_entry); - ins->proc_sym_info_entry = NULL; - - snd_info_free_entry(ins->proc_modules_info_entry); - ins->proc_modules_info_entry = NULL; - - snd_info_free_entry(ins->proc_parameter_dump_info_entry); - ins->proc_parameter_dump_info_entry = NULL; - - snd_info_free_entry(ins->proc_sample_dump_info_entry); - ins->proc_sample_dump_info_entry = NULL; - - snd_info_free_entry(ins->proc_scb_info_entry); - ins->proc_scb_info_entry = NULL; - - snd_info_free_entry(ins->proc_task_info_entry); - ins->proc_task_info_entry = NULL; - mutex_lock(&chip->spos_mutex); for (i = 0; i < ins->nscb; ++i) { if (ins->scbs[i].deleted) continue; diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index e056f9dc228b..1d9d610262de 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -254,8 +254,9 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL && scb->proc_info == NULL) { - if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name, - ins->proc_dsp_dir)) != NULL) { + entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name, + ins->proc_dsp_dir); + if (entry) { scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL); if (!scb_info) { snd_info_free_entry(entry); @@ -265,12 +266,8 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, scb_info->chip = chip; scb_info->scb_desc = scb; - - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->private_data = scb_info; - entry->mode = S_IFREG | 0644; - - entry->c.text.read = cs46xx_dsp_proc_scb_info_read; + snd_info_set_text_ops(entry, scb_info, + cs46xx_dsp_proc_scb_info_read); } out: scb->proc_info = entry; From f6aa470f0d3c6b2f57c1f311757a583a3ba1f584 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:37:47 +0100 Subject: [PATCH 290/461] ASoC: amd: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/amd/acp-pcm-dma.c | 26 +++++++++++--------------- sound/soc/amd/raven/acp3x-pcm-dma.c | 9 ++++----- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index f4011bebc7ec..2391c7f1dd2d 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -1142,7 +1142,6 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) { - int ret; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct audio_drv_data *adata = dev_get_drvdata(component->dev); @@ -1150,24 +1149,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) switch (adata->asic_type) { case CHIP_STONEY: - ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, - SNDRV_DMA_TYPE_DEV, - parent, - ST_MIN_BUFFER, - ST_MAX_BUFFER); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, + parent, + ST_MIN_BUFFER, + ST_MAX_BUFFER); break; default: - ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, - SNDRV_DMA_TYPE_DEV, - parent, - MIN_BUFFER, - MAX_BUFFER); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, + parent, + MIN_BUFFER, + MAX_BUFFER); break; } - if (ret < 0) - dev_err(component->dev, - "buffer preallocation failure error:%d\n", ret); - return ret; + return 0; } static int acp_dma_close(struct snd_pcm_substream *substream) diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 3e7d4099364c..1a2e15ff1456 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -367,11 +367,10 @@ static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream) static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd) { - return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->pcm->card->dev, - MIN_BUFFER, - MAX_BUFFER); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + rtd->pcm->card->dev, + MIN_BUFFER, MAX_BUFFER); + return 0; } static int acp3x_dma_hw_free(struct snd_pcm_substream *substream) From ad8ba770ca67d283b3166a8baf71cb4e42e9c973 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:38:20 +0100 Subject: [PATCH 291/461] ASoC: dwc: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/dwc/dwc-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/dwc/dwc-pcm.c b/sound/soc/dwc/dwc-pcm.c index 2cc9632024fc..a9ae91c4597f 100644 --- a/sound/soc/dwc/dwc-pcm.c +++ b/sound/soc/dwc/dwc-pcm.c @@ -249,9 +249,10 @@ static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd) { size_t size = dw_pcm_hardware.buffer_bytes_max; - return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), size, size); + return 0; } static void dw_pcm_free(struct snd_pcm *pcm) From 62961dd5f609b202080e7d9053de1a8967c9d4d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:38:42 +0100 Subject: [PATCH 292/461] ASoC: intel: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 9 ++------- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 15 ++++----------- sound/soc/intel/haswell/sst-haswell-pcm.c | 10 ++-------- sound/soc/intel/skylake/skl-pcm.c | 9 ++------- 4 files changed, 10 insertions(+), 33 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 91a2436ce952..985abda3bfbb 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -687,20 +687,15 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; - int retval = 0; if (dai->driver->playback.channels_min || dai->driver->capture.channels_min) { - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); - if (retval) { - dev_err(rtd->dev, "dma buffer allocation failure\n"); - return retval; - } } - return retval; + return 0; } static int sst_soc_probe(struct snd_soc_component *component) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index aabb35bf6b96..aa358073ac0f 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -327,23 +327,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) size_t size; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_pdata *pdata = dev_get_platdata(component->dev); - int ret = 0; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { size = sst_byt_pcm_hardware.buffer_bytes_max; - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - pdata->dma_dev, - size, size); - if (ret) { - dev_err(rtd->dev, "dma buffer allocation failed %d\n", - ret); - return ret; - } + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + pdata->dma_dev, + size, size); } - return ret; + return 0; } static struct snd_soc_dai_driver byt_dais[] = { diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fe2c826e710c..f21a7f2c11c2 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -946,27 +946,21 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) struct sst_pdata *pdata = dev_get_platdata(component->dev); struct hsw_priv_data *priv_data = dev_get_drvdata(component->dev); struct device *dev = pdata->dma_dev; - int ret = 0; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, dev, hsw_pcm_hardware.buffer_bytes_max, hsw_pcm_hardware.buffer_bytes_max); - if (ret) { - dev_err(rtd->dev, "dma buffer allocation failed %d\n", - ret); - return ret; - } } if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm; if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm; - return ret; + return 0; } #define HSW_FORMATS \ diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 557f80c0bfe5..20c88c677473 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1289,7 +1289,6 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_pcm *pcm = rtd->pcm; unsigned int size; - int retval = 0; struct skl *skl = bus_to_skl(bus); if (dai->driver->playback.channels_min || @@ -1298,17 +1297,13 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; if (size > MAX_PREALLOC_SIZE) size = MAX_PREALLOC_SIZE; - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(skl->pci), size, MAX_PREALLOC_SIZE); - if (retval) { - dev_err(dai->dev, "dma buffer allocation fail\n"); - return retval; - } } - return retval; + return 0; } static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) From 15486e63e7ce2794e6b82843ac6c57146080d98b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:39:15 +0100 Subject: [PATCH 293/461] ASoC: mediatek: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/mediatek/common/mtk-afe-platform-driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c index 697aa50aff9a..3ce527ce30ce 100644 --- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c @@ -126,9 +126,9 @@ int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); size = afe->mtk_afe_hardware->buffer_bytes_max; - return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - afe->dev, - size, size); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + afe->dev, size, size); + return 0; } EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); From fba3b09f185ebca89b93fbd606d335a717693d1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:39:39 +0100 Subject: [PATCH 294/461] ASoC: meson: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/meson/axg-fifo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index 0e4f65e654c4..75e5e480fda2 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -267,9 +267,10 @@ int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) struct snd_card *card = rtd->card->snd_card; size_t size = axg_fifo_hw.buffer_bytes_max; - return snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream, - SNDRV_DMA_TYPE_DEV, card->dev, - size, size); + snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream, + SNDRV_DMA_TYPE_DEV, card->dev, + size, size); + return 0; } EXPORT_SYMBOL_GPL(axg_fifo_pcm_new); From b76c7fe6c99d427a064e5e152dca7fe24f424f53 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:39:54 +0100 Subject: [PATCH 295/461] ASoC: sh: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Acked-by: Kuninori Morimoto Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/sh/fsi.c | 3 ++- sound/soc/sh/rcar/core.c | 5 +---- sound/soc/sh/siu_pcm.c | 13 +------------ 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index aa7e902f0c02..285afbafa662 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1768,11 +1768,12 @@ static const struct snd_pcm_ops fsi_pcm_ops = { static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { - return snd_pcm_lib_preallocate_pages_for_all( + snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, SNDRV_DMA_TYPE_DEV, rtd->card->snd_card->dev, PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); + return 0; } /* diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 59e250cc2e9d..29213b90755f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1575,7 +1575,6 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, struct rsnd_priv *priv = rsnd_io_to_priv(io); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_substream *substream; - int err; /* * use Audio-DMAC dev if we can use IPMMU @@ -1588,12 +1587,10 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, for (substream = rtd->pcm->streams[stream].substream; substream; substream = substream->next) { - err = snd_pcm_lib_preallocate_pages(substream, + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, dev, PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); - if (err < 0) - return err; } return 0; diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 23384c477740..78c3145b4109 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -541,15 +541,9 @@ static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); - if (ret < 0) { - dev_err(card->dev, - "snd_pcm_lib_preallocate_pages_for_all() err=%d", - ret); - goto fail; - } (*port_info)->pcm = pcm; @@ -562,11 +556,6 @@ static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) dev_info(card->dev, "SuperH SIU driver initialized.\n"); return 0; - -fail: - siu_free_port(siu_ports[pdev->id]); - dev_err(card->dev, "SIU: failed to initialize.\n"); - return ret; } static void siu_pcm_free(struct snd_pcm *pcm) From 18183edaad8d6a86ae8ac90ecf852527a207aad5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:40:22 +0100 Subject: [PATCH 296/461] ASoC: stm: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/stm/stm32_adfsdm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 706ff005234f..47901983a6ff 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -262,8 +262,9 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_soc_dai_get_drvdata(rtd->cpu_dai); unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE; - return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - priv->dev, size, size); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + priv->dev, size, size); + return 0; } static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm) From 4f39e4c969b1b26f44be7d697c4c3e60a6a87d0c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:40:37 +0100 Subject: [PATCH 297/461] ASoC: txx9: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/txx9/txx9aclc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 8d31fe628e2f..089bd7518606 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -313,8 +313,10 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) if (ret) goto exit; } - return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, 64 * 1024, 4 * 1024 * 1024); + return 0; exit: for (i = 0; i < 2; i++) { From c87592fec3963c8f7f95db866cb260cee48d76a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:40:55 +0100 Subject: [PATCH 298/461] ASoC: uniphier: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/uniphier/aio-dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/uniphier/aio-dma.c b/sound/soc/uniphier/aio-dma.c index 4ec6b65bfb44..fa001d3c1a88 100644 --- a/sound/soc/uniphier/aio-dma.c +++ b/sound/soc/uniphier/aio-dma.c @@ -235,10 +235,11 @@ static int uniphier_aiodma_new(struct snd_soc_pcm_runtime *rtd) if (ret) return ret; - return snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, dev, uniphier_aiodma_hw.buffer_bytes_max, uniphier_aiodma_hw.buffer_bytes_max); + return 0; } static void uniphier_aiodma_free(struct snd_pcm *pcm) From 8eea18f6a433cec20ec80d13f8483faa99ccb65f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:41:09 +0100 Subject: [PATCH 299/461] ASoC: xtensa: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/xtensa/xtfpga-i2s.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 503560916620..2f20a02c8d46 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -469,9 +469,9 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) struct snd_card *card = rtd->card->snd_card; size_t size = xtfpga_pcm_hardware.buffer_bytes_max; - return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, - SNDRV_DMA_TYPE_DEV, - card->dev, size, size); + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + card->dev, size, size); + return 0; } static const struct snd_pcm_ops xtfpga_pcm_ops = { From 6c422436638af9f8240df71c53275c3d255c2170 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:41:43 +0100 Subject: [PATCH 300/461] ASoC: dmaengine: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/soc-generic-dmaengine-pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 30e791a53352..46252b13d3b3 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -270,7 +270,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) size_t prealloc_buffer_size; size_t max_buffer_size; unsigned int i; - int ret; if (config && config->prealloc_buffer_size) { prealloc_buffer_size = config->prealloc_buffer_size; @@ -303,13 +302,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) return -EINVAL; } - ret = snd_pcm_lib_preallocate_pages(substream, + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_IRAM, dmaengine_dma_dev(pcm, substream), prealloc_buffer_size, max_buffer_size); - if (ret) - return ret; if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i])) pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; From f13d4b5f85e1c436c9bf21205509266b5a81a320 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:28 -0600 Subject: [PATCH 301/461] ASoC: dapm: harden use of lookup tables To detect potential errors, let's add: a) build-time warnings when the table size isn't aligned with the enum list b) run-time warnings when the values are not initialized. This requires an increase by one of all values to avoid the default 0. Suggested-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 + sound/soc/soc-dapm.c | 158 ++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 79b4ddfb8e9e..c00a0b8ade08 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -523,6 +523,9 @@ enum snd_soc_dapm_type { snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */ snd_soc_dapm_encoder, /* FW/SW audio encoder component */ snd_soc_dapm_decoder, /* FW/SW audio decoder component */ + + /* Don't edit below this line */ + SND_SOC_DAPM_TYPE_COUNT }; enum snd_soc_dapm_subclass { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40e7190f533a..d31d295b540f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -64,85 +64,85 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_regulator_supply] = 1, - [snd_soc_dapm_pinctrl] = 1, - [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_supply] = 2, - [snd_soc_dapm_micbias] = 3, - [snd_soc_dapm_vmid] = 3, - [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 4, - [snd_soc_dapm_dai_out] = 4, - [snd_soc_dapm_aif_in] = 4, - [snd_soc_dapm_aif_out] = 4, - [snd_soc_dapm_mic] = 5, - [snd_soc_dapm_siggen] = 5, - [snd_soc_dapm_input] = 5, - [snd_soc_dapm_output] = 5, - [snd_soc_dapm_mux] = 6, - [snd_soc_dapm_demux] = 6, - [snd_soc_dapm_dac] = 7, - [snd_soc_dapm_switch] = 8, - [snd_soc_dapm_mixer] = 8, - [snd_soc_dapm_mixer_named_ctl] = 8, - [snd_soc_dapm_pga] = 9, - [snd_soc_dapm_buffer] = 9, - [snd_soc_dapm_scheduler] = 9, - [snd_soc_dapm_effect] = 9, - [snd_soc_dapm_src] = 9, - [snd_soc_dapm_asrc] = 9, - [snd_soc_dapm_encoder] = 9, - [snd_soc_dapm_decoder] = 9, - [snd_soc_dapm_adc] = 10, - [snd_soc_dapm_out_drv] = 11, - [snd_soc_dapm_hp] = 11, - [snd_soc_dapm_spk] = 11, - [snd_soc_dapm_line] = 11, - [snd_soc_dapm_sink] = 11, - [snd_soc_dapm_kcontrol] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_regulator_supply] = 2, + [snd_soc_dapm_pinctrl] = 2, + [snd_soc_dapm_clock_supply] = 2, + [snd_soc_dapm_supply] = 3, + [snd_soc_dapm_micbias] = 4, + [snd_soc_dapm_vmid] = 4, + [snd_soc_dapm_dai_link] = 3, + [snd_soc_dapm_dai_in] = 5, + [snd_soc_dapm_dai_out] = 5, + [snd_soc_dapm_aif_in] = 5, + [snd_soc_dapm_aif_out] = 5, + [snd_soc_dapm_mic] = 6, + [snd_soc_dapm_siggen] = 6, + [snd_soc_dapm_input] = 6, + [snd_soc_dapm_output] = 6, + [snd_soc_dapm_mux] = 7, + [snd_soc_dapm_demux] = 7, + [snd_soc_dapm_dac] = 8, + [snd_soc_dapm_switch] = 9, + [snd_soc_dapm_mixer] = 9, + [snd_soc_dapm_mixer_named_ctl] = 9, + [snd_soc_dapm_pga] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, + [snd_soc_dapm_adc] = 11, + [snd_soc_dapm_out_drv] = 12, + [snd_soc_dapm_hp] = 12, + [snd_soc_dapm_spk] = 12, + [snd_soc_dapm_line] = 12, + [snd_soc_dapm_sink] = 12, + [snd_soc_dapm_kcontrol] = 13, + [snd_soc_dapm_post] = 14, }; static int dapm_down_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_kcontrol] = 1, - [snd_soc_dapm_adc] = 2, - [snd_soc_dapm_hp] = 3, - [snd_soc_dapm_spk] = 3, - [snd_soc_dapm_line] = 3, - [snd_soc_dapm_out_drv] = 3, - [snd_soc_dapm_sink] = 3, - [snd_soc_dapm_pga] = 4, - [snd_soc_dapm_buffer] = 4, - [snd_soc_dapm_scheduler] = 4, - [snd_soc_dapm_effect] = 4, - [snd_soc_dapm_src] = 4, - [snd_soc_dapm_asrc] = 4, - [snd_soc_dapm_encoder] = 4, - [snd_soc_dapm_decoder] = 4, - [snd_soc_dapm_switch] = 5, - [snd_soc_dapm_mixer_named_ctl] = 5, - [snd_soc_dapm_mixer] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_mic] = 7, - [snd_soc_dapm_siggen] = 7, - [snd_soc_dapm_input] = 7, - [snd_soc_dapm_output] = 7, - [snd_soc_dapm_micbias] = 8, - [snd_soc_dapm_vmid] = 8, - [snd_soc_dapm_mux] = 9, - [snd_soc_dapm_demux] = 9, - [snd_soc_dapm_aif_in] = 10, - [snd_soc_dapm_aif_out] = 10, - [snd_soc_dapm_dai_in] = 10, - [snd_soc_dapm_dai_out] = 10, - [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_clock_supply] = 13, - [snd_soc_dapm_pinctrl] = 13, - [snd_soc_dapm_regulator_supply] = 13, - [snd_soc_dapm_post] = 14, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_kcontrol] = 2, + [snd_soc_dapm_adc] = 3, + [snd_soc_dapm_hp] = 4, + [snd_soc_dapm_spk] = 4, + [snd_soc_dapm_line] = 4, + [snd_soc_dapm_out_drv] = 4, + [snd_soc_dapm_sink] = 4, + [snd_soc_dapm_pga] = 5, + [snd_soc_dapm_buffer] = 5, + [snd_soc_dapm_scheduler] = 5, + [snd_soc_dapm_effect] = 5, + [snd_soc_dapm_src] = 5, + [snd_soc_dapm_asrc] = 5, + [snd_soc_dapm_encoder] = 5, + [snd_soc_dapm_decoder] = 5, + [snd_soc_dapm_switch] = 6, + [snd_soc_dapm_mixer_named_ctl] = 6, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_mic] = 8, + [snd_soc_dapm_siggen] = 8, + [snd_soc_dapm_input] = 8, + [snd_soc_dapm_output] = 8, + [snd_soc_dapm_micbias] = 9, + [snd_soc_dapm_vmid] = 9, + [snd_soc_dapm_mux] = 10, + [snd_soc_dapm_demux] = 10, + [snd_soc_dapm_aif_in] = 11, + [snd_soc_dapm_aif_out] = 11, + [snd_soc_dapm_dai_in] = 11, + [snd_soc_dapm_dai_out] = 11, + [snd_soc_dapm_dai_link] = 12, + [snd_soc_dapm_supply] = 13, + [snd_soc_dapm_clock_supply] = 14, + [snd_soc_dapm_pinctrl] = 14, + [snd_soc_dapm_regulator_supply] = 14, + [snd_soc_dapm_post] = 15, }; static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) @@ -1425,11 +1425,17 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, { int *sort; + BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT); + if (power_up) sort = dapm_up_seq; else sort = dapm_down_seq; + WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id); + WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id); + if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->subseq != b->subseq) { From 62e94da3e9d8b991a467f376441a805c5d14c9c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 6 Feb 2019 12:01:48 +0100 Subject: [PATCH 302/461] media: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Acked-by: Ezequiel Garcia Signed-off-by: Takashi Iwai --- drivers/media/pci/solo6x10/solo6x10-g723.c | 4 +--- drivers/media/pci/tw686x/tw686x-audio.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 2cc05a9d57ac..a16242a9206f 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -360,13 +360,11 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) ss; ss = ss->next, i++) sprintf(ss->name, "Camera #%d Audio", i); - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), G723_PERIOD_BYTES * PERIODS, G723_PERIOD_BYTES * PERIODS); - if (ret < 0) - return ret; solo_dev->snd_pcm = pcm; diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c index a28329698e20..fb0e7573b5ae 100644 --- a/drivers/media/pci/tw686x/tw686x-audio.c +++ b/drivers/media/pci/tw686x/tw686x-audio.c @@ -301,11 +301,12 @@ static int tw686x_snd_pcm_init(struct tw686x_dev *dev) ss; ss = ss->next, i++) snprintf(ss->name, sizeof(ss->name), "vch%u audio", i); - return snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(dev->pci_dev), TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX, TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX); + return 0; } static void tw686x_audio_dma_free(struct tw686x_dev *dev, From e9d97b05a80f27d5ba7379b108db19b0d93cf267 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 5 Feb 2019 00:11:08 -0300 Subject: [PATCH 303/461] ASoC: codecs: Add jz4725b-codec driver Add jz4725b-codec driver to support the internal CODEC found in the JZ4725B SoC from Ingenic. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 12 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/jz4725b.c | 599 +++++++++++++++++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 sound/soc/codecs/jz4725b.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a15710c8a95f..fec894c725d3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC + select SND_SOC_JZ4725B_CODEC select SND_SOC_LM4857 if I2C select SND_SOC_LM49453 if I2C select SND_SOC_MAX98088 if I2C @@ -581,6 +582,17 @@ config SND_SOC_JZ4740_CODEC select REGMAP_MMIO tristate +config SND_SOC_JZ4725B_CODEC + depends on MIPS || COMPILE_TEST + select REGMAP + tristate "Ingenic JZ4725B internal CODEC" + help + Enable support for the internal CODEC found in the JZ4725B SoC + from Ingenic. + + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4725b-codec. + config SND_SOC_L3 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3d7a59761c08..b07dfb5fa700 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -86,6 +86,7 @@ snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o +snd-soc-jz4725b-codec-objs := jz4725b.o snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o @@ -357,6 +358,7 @@ obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o +obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c new file mode 100644 index 000000000000..e3dba92f30bd --- /dev/null +++ b/sound/soc/codecs/jz4725b.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ4725B CODEC driver + * + * Copyright (C) 2019, Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define ICDC_RGADW_OFFSET 0x00 +#define ICDC_RGDATA_OFFSET 0x04 + +/* ICDC internal register access control register(RGADW) */ +#define ICDC_RGADW_RGWR BIT(16) + +#define ICDC_RGADW_RGADDR_OFFSET 8 +#define ICDC_RGADW_RGADDR_MASK GENMASK(14, ICDC_RGADW_RGADDR_OFFSET) + +#define ICDC_RGADW_RGDIN_OFFSET 0 +#define ICDC_RGADW_RGDIN_MASK GENMASK(7, ICDC_RGADW_RGDIN_OFFSET) + +/* ICDC internal register data output register (RGDATA)*/ +#define ICDC_RGDATA_IRQ BIT(8) + +#define ICDC_RGDATA_RGDOUT_OFFSET 0 +#define ICDC_RGDATA_RGDOUT_MASK GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET) + +/* JZ internal register space */ +enum { + JZ4725B_CODEC_REG_AICR, + JZ4725B_CODEC_REG_CR1, + JZ4725B_CODEC_REG_CR2, + JZ4725B_CODEC_REG_CCR1, + JZ4725B_CODEC_REG_CCR2, + JZ4725B_CODEC_REG_PMR1, + JZ4725B_CODEC_REG_PMR2, + JZ4725B_CODEC_REG_CRR, + JZ4725B_CODEC_REG_ICR, + JZ4725B_CODEC_REG_IFR, + JZ4725B_CODEC_REG_CGR1, + JZ4725B_CODEC_REG_CGR2, + JZ4725B_CODEC_REG_CGR3, + JZ4725B_CODEC_REG_CGR4, + JZ4725B_CODEC_REG_CGR5, + JZ4725B_CODEC_REG_CGR6, + JZ4725B_CODEC_REG_CGR7, + JZ4725B_CODEC_REG_CGR8, + JZ4725B_CODEC_REG_CGR9, + JZ4725B_CODEC_REG_CGR10, + JZ4725B_CODEC_REG_TR1, + JZ4725B_CODEC_REG_TR2, + JZ4725B_CODEC_REG_CR3, + JZ4725B_CODEC_REG_AGC1, + JZ4725B_CODEC_REG_AGC2, + JZ4725B_CODEC_REG_AGC3, + JZ4725B_CODEC_REG_AGC4, + JZ4725B_CODEC_REG_AGC5, +}; + +#define REG_AICR_CONFIG1_OFFSET 0 +#define REG_AICR_CONFIG1_MASK (0xf << REG_AICR_CONFIG1_OFFSET) + +#define REG_CR1_SB_MICBIAS_OFFSET 7 +#define REG_CR1_MONO_OFFSET 6 +#define REG_CR1_DAC_MUTE_OFFSET 5 +#define REG_CR1_HP_DIS_OFFSET 4 +#define REG_CR1_DACSEL_OFFSET 3 +#define REG_CR1_BYPASS_OFFSET 2 + +#define REG_CR2_DAC_DEEMP_OFFSET 7 +#define REG_CR2_DAC_ADWL_OFFSET 5 +#define REG_CR2_DAC_ADWL_MASK (0x3 << REG_CR2_DAC_ADWL_OFFSET) +#define REG_CR2_ADC_ADWL_OFFSET 3 +#define REG_CR2_ADC_ADWL_MASK (0x3 << REG_CR2_ADC_ADWL_OFFSET) +#define REG_CR2_ADC_HPF_OFFSET 2 + +#define REG_CR3_SB_MIC1_OFFSET 7 +#define REG_CR3_SB_MIC2_OFFSET 6 +#define REG_CR3_SIDETONE1_OFFSET 5 +#define REG_CR3_SIDETONE2_OFFSET 4 +#define REG_CR3_MICDIFF_OFFSET 3 +#define REG_CR3_MICSTEREO_OFFSET 2 +#define REG_CR3_INSEL_OFFSET 0 +#define REG_CR3_INSEL_MASK (0x3 << REG_CR3_INSEL_OFFSET) + +#define REG_CCR1_CONFIG4_OFFSET 0 +#define REG_CCR1_CONFIG4_MASK (0xf << REG_CCR1_CONFIG4_OFFSET) + +#define REG_CCR2_DFREQ_OFFSET 4 +#define REG_CCR2_DFREQ_MASK (0xf << REG_CCR2_DFREQ_OFFSET) +#define REG_CCR2_AFREQ_OFFSET 0 +#define REG_CCR2_AFREQ_MASK (0xf << REG_CCR2_AFREQ_OFFSET) + +#define REG_PMR1_SB_DAC_OFFSET 7 +#define REG_PMR1_SB_OUT_OFFSET 6 +#define REG_PMR1_SB_MIX_OFFSET 5 +#define REG_PMR1_SB_ADC_OFFSET 4 +#define REG_PMR1_SB_LIN_OFFSET 3 +#define REG_PMR1_SB_IND_OFFSET 0 + +#define REG_PMR2_LRGI_OFFSET 7 +#define REG_PMR2_RLGI_OFFSET 6 +#define REG_PMR2_LRGOD_OFFSET 5 +#define REG_PMR2_RLGOD_OFFSET 4 +#define REG_PMR2_GIM_OFFSET 3 +#define REG_PMR2_SB_MC_OFFSET 2 +#define REG_PMR2_SB_OFFSET 1 +#define REG_PMR2_SB_SLEEP_OFFSET 0 + +#define REG_IFR_RAMP_UP_DONE_OFFSET 3 +#define REG_IFR_RAMP_DOWN_DONE_OFFSET 2 + +#define REG_CGR1_GODL_OFFSET 4 +#define REG_CGR1_GODL_MASK (0xf << REG_CGR1_GODL_OFFSET) +#define REG_CGR1_GODR_OFFSET 0 +#define REG_CGR1_GODR_MASK (0xf << REG_CGR1_GODR_OFFSET) + +#define REG_CGR2_GO1R_OFFSET 0 +#define REG_CGR2_GO1R_MASK (0x1f << REG_CGR2_GO1R_OFFSET) + +#define REG_CGR3_GO1L_OFFSET 0 +#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET) + +struct jz_icdc { + struct regmap *regmap; + void __iomem *base; + struct clk *clk; +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600); + +static const struct snd_kcontrol_new jz4725b_codec_controls[] = { + SOC_DOUBLE_TLV("Master Playback Volume", + JZ4725B_CODEC_REG_CGR1, + REG_CGR1_GODL_OFFSET, + REG_CGR1_GODR_OFFSET, + 0xf, 1, jz4725b_dac_tlv), + SOC_DOUBLE_R_TLV("Master Capture Volume", + JZ4725B_CODEC_REG_CGR3, + JZ4725B_CODEC_REG_CGR2, + REG_CGR2_GO1R_OFFSET, + 0x1f, 1, jz4725b_line_tlv), + + SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, + REG_CR1_DAC_MUTE_OFFSET, 1, 1), + + SOC_SINGLE("Deemphatize Filter Playback Switch", + JZ4725B_CODEC_REG_CR2, + REG_CR2_DAC_DEEMP_OFFSET, 1, 0), + + SOC_SINGLE("High-Pass Filter Capture Switch", + JZ4725B_CODEC_REG_CR2, + REG_CR2_ADC_HPF_OFFSET, 1, 0), +}; + +static const char * const jz4725b_codec_adc_src_texts[] = { + "Mic 1", "Mic 2", "Line In", "Mixer", +}; +static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, }; +static const SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, + JZ4725B_CODEC_REG_CR3, + REG_CR3_INSEL_OFFSET, + REG_CR3_INSEL_MASK, + jz4725b_codec_adc_src_texts, + jz4725b_codec_adc_src_values); +static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = + SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum); + +static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = { + SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1, + REG_CR1_BYPASS_OFFSET, 1, 0), +}; + +static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); + struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec); + struct regmap *map = icdc->regmap; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0); + case SND_SOC_DAPM_POST_PMU: + return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, + val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET), + 100000, 500000); + case SND_SOC_DAPM_PRE_PMD: + return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0); + case SND_SOC_DAPM_POST_PMD: + return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, + val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), + 100000, 500000); + default: + return -EINVAL; + } +} + +static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = { + /* DAC */ + SND_SOC_DAPM_DAC("DAC", "Playback", + JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC", "Capture", + JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1), + + SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0, + &jz4725b_codec_adc_src_ctrl), + + /* Mixer */ + SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_MIX_OFFSET, 1, + jz4725b_codec_mixer_controls, + ARRAY_SIZE(jz4725b_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1, + REG_CR1_DACSEL_OFFSET, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1, + REG_CR1_HP_DIS_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3, + REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0), + SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3, + REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0, + jz4725b_out_stage_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_IND_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1, + REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0), + + /* Pins */ + SND_SOC_DAPM_INPUT("MIC1P"), + SND_SOC_DAPM_INPUT("MIC1N"), + SND_SOC_DAPM_INPUT("MIC2P"), + SND_SOC_DAPM_INPUT("MIC2N"), + + SND_SOC_DAPM_INPUT("LLINEIN"), + SND_SOC_DAPM_INPUT("RLINEIN"), + + SND_SOC_DAPM_OUTPUT("LHPOUT"), + SND_SOC_DAPM_OUTPUT("RHPOUT"), +}; + +static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = { + {"Mic 1", NULL, "MIC1P"}, + {"Mic 1", NULL, "MIC1N"}, + {"Mic 2", NULL, "MIC2P"}, + {"Mic 2", NULL, "MIC2N"}, + + {"Line In", NULL, "LLINEIN"}, + {"Line In", NULL, "RLINEIN"}, + + {"Mixer", "Line In Bypass", "Line In"}, + {"DAC to Mixer", NULL, "DAC"}, + {"Mixer", NULL, "DAC to Mixer"}, + + {"Mixer to ADC", NULL, "Mixer"}, + {"ADC Source", "Mixer", "Mixer to ADC"}, + {"ADC Source", "Line In", "Line In"}, + {"ADC Source", "Mic 1", "Mic 1"}, + {"ADC Source", "Mic 2", "Mic 2"}, + {"ADC", NULL, "ADC Source"}, + + {"Out Stage", NULL, "Mixer"}, + {"HP Out", NULL, "Out Stage"}, + {"LHPOUT", NULL, "HP Out"}, + {"RHPOUT", NULL, "HP Out"}, +}; + +static int jz4725b_codec_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + struct regmap *map = icdc->regmap; + + switch (level) { + case SND_SOC_BIAS_ON: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET), 0); + break; + case SND_SOC_BIAS_PREPARE: + /* Enable sound hardware */ + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET), 0); + msleep(224); + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET), + BIT(REG_PMR2_SB_SLEEP_OFFSET)); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET), + BIT(REG_PMR2_SB_OFFSET)); + break; + } + + return 0; +} + +static int jz4725b_codec_dev_probe(struct snd_soc_component *component) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + struct regmap *map = icdc->regmap; + + clk_prepare_enable(icdc->clk); + + /* Write CONFIGn (n=1 to 8) bits. + * The value 0x0f is specified in the datasheet as a requirement. + */ + regmap_write(map, JZ4725B_CODEC_REG_AICR, + 0xf << REG_AICR_CONFIG1_OFFSET); + regmap_write(map, JZ4725B_CODEC_REG_CCR1, + 0x0 << REG_CCR1_CONFIG4_OFFSET); + + return 0; +} + +static void jz4725b_codec_dev_remove(struct snd_soc_component *component) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(icdc->clk); +} + +static const struct snd_soc_component_driver jz4725b_codec = { + .probe = jz4725b_codec_dev_probe, + .remove = jz4725b_codec_dev_remove, + .set_bias_level = jz4725b_codec_set_bias_level, + .controls = jz4725b_codec_controls, + .num_controls = ARRAY_SIZE(jz4725b_codec_controls), + .dapm_widgets = jz4725b_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(jz4725b_codec_dapm_widgets), + .dapm_routes = jz4725b_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(jz4725b_codec_dapm_routes), + .suspend_bias_off = 1, + .use_pmdown_time = 1, +}; + +static const unsigned int jz4725b_codec_sample_rates[] = { + 96000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, + 11025, 9600, 8000, +}; + +static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component); + unsigned int rate, bit_width; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + bit_width = 0; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + bit_width = 1; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + bit_width = 2; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bit_width = 3; + break; + default: + return -EINVAL; + } + + for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) { + if (jz4725b_codec_sample_rates[rate] == params_rate(params)) + break; + } + + if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates)) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CR2, + REG_CR2_DAC_ADWL_MASK, + bit_width << REG_CR2_DAC_ADWL_OFFSET); + + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CCR2, + REG_CCR2_DFREQ_MASK, + rate << REG_CCR2_DFREQ_OFFSET); + } else { + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CR2, + REG_CR2_ADC_ADWL_MASK, + bit_width << REG_CR2_ADC_ADWL_OFFSET); + + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CCR2, + REG_CCR2_AFREQ_MASK, + rate << REG_CCR2_AFREQ_OFFSET); + } + + return 0; +} + +static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = { + .hw_params = jz4725b_codec_hw_params, +}; + +#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE) + +static struct snd_soc_dai_driver jz4725b_codec_dai = { + .name = "jz4725b-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = JZ_ICDC_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = JZ_ICDC_FORMATS, + }, + .ops = &jz4725b_codec_dai_ops, +}; + +static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg) +{ + return reg == JZ4725B_CODEC_REG_IFR; +} + +static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg) +{ + return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2); +} + +static int jz4725b_codec_io_wait(struct jz_icdc *icdc) +{ + u32 reg; + + return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg, + !(reg & ICDC_RGADW_RGWR), 1000, 10000); +} + +static int jz4725b_codec_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct jz_icdc *icdc = context; + unsigned int i; + u32 tmp; + int ret; + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + tmp = readl(icdc->base + ICDC_RGADW_OFFSET); + tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK) + | (reg << ICDC_RGADW_RGADDR_OFFSET); + writel(tmp, icdc->base + ICDC_RGADW_OFFSET); + + /* wait 6+ cycles */ + for (i = 0; i < 6; i++) + *val = readl(icdc->base + ICDC_RGDATA_OFFSET) & + ICDC_RGDATA_RGDOUT_MASK; + + return 0; +} + +static int jz4725b_codec_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct jz_icdc *icdc = context; + int ret; + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val, + icdc->base + ICDC_RGADW_OFFSET); + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + return 0; +} + +static const u8 jz4725b_codec_reg_defaults[] = { + 0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51, + 0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34, + 0x07, 0x44, 0x1f, 0x00, +}; + +static const struct regmap_config jz4725b_codec_regmap_config = { + .reg_bits = 7, + .val_bits = 8, + + .max_register = JZ4725B_CODEC_REG_AGC5, + .volatile_reg = jz4725b_codec_volatile, + .readable_reg = jz4725b_codec_can_access_reg, + .writeable_reg = jz4725b_codec_can_access_reg, + + .reg_read = jz4725b_codec_reg_read, + .reg_write = jz4725b_codec_reg_write, + + .reg_defaults_raw = jz4725b_codec_reg_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static int jz4725b_codec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jz_icdc *icdc; + struct resource *mem; + int ret; + + icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL); + if (!icdc) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + icdc->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(icdc->base)) + return PTR_ERR(icdc->base); + + icdc->regmap = devm_regmap_init(dev, NULL, icdc, + &jz4725b_codec_regmap_config); + if (IS_ERR(icdc->regmap)) + return PTR_ERR(icdc->regmap); + + icdc->clk = devm_clk_get(&pdev->dev, "aic"); + if (IS_ERR(icdc->clk)) + return PTR_ERR(icdc->clk); + + platform_set_drvdata(pdev, icdc); + + ret = devm_snd_soc_register_component(dev, &jz4725b_codec, + &jz4725b_codec_dai, 1); + if (ret) + dev_err(dev, "Failed to register codec\n"); + + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id jz4725b_codec_of_matches[] = { + { .compatible = "ingenic,jz4725b-codec", }, + { } +}; +MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches); +#endif + +static struct platform_driver jz4725b_codec_driver = { + .probe = jz4725b_codec_probe, + .driver = { + .name = "jz4725b-codec", + .of_match_table = of_match_ptr(jz4725b_codec_of_matches), + }, +}; +module_platform_driver(jz4725b_codec_driver); + +MODULE_DESCRIPTION("JZ4725B SoC internal codec driver"); +MODULE_AUTHOR("Paul Cercueil "); +MODULE_LICENSE("GPL v2"); From afb86626509205b009d636dcc098066ccf3954c6 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 5 Feb 2019 05:33:25 +0800 Subject: [PATCH 304/461] ASoC: wcd9335: fix semicolon.cocci warnings sound/soc/codecs/wcd-clsh-v2.c:545:2-3: Unneeded semicolon sound/soc/codecs/wcd-clsh-v2.c:211:2-3: Unneeded semicolon sound/soc/codecs/wcd-clsh-v2.c:250:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: cc2e324d39b2 ("ASoC: wcd9335: add CLASS-H Controller support") CC: Srinivas Kandagatla Signed-off-by: kbuild test robot Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-clsh-v2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 1bd70c5a7b63..c397d713f01a 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -208,7 +208,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) case CLS_H_LP: val = WCD9XXX_HPH_CONST_SEL_LP_PATH; break; - }; + } snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, WCD9XXX_HPH_CONST_SEL_L_MASK, @@ -247,7 +247,7 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; break; - }; + } snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); @@ -542,7 +542,7 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, case WCD_CLSH_EVENT_POST_PA: _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); break; - }; + } ctrl->state = nstate; ctrl->mode = mode; From 6c3e6302364aa5d152e0f5f81d550fdbc7bb8d38 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 7 Feb 2019 09:26:42 +0000 Subject: [PATCH 305/461] ASoC: codecs: jz4725b: fix spelling mistake "Deemphatize" -> "Deemphasize" There is a spelling mistake in the SOC_SINGLE control name. Fix this. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index e3dba92f30bd..24b1b23b99c9 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -161,7 +161,7 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = { SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, REG_CR1_DAC_MUTE_OFFSET, 1, 1), - SOC_SINGLE("Deemphatize Filter Playback Switch", + SOC_SINGLE("Deemphasize Filter Playback Switch", JZ4725B_CODEC_REG_CR2, REG_CR2_DAC_DEEMP_OFFSET, 1, 0), From 63bd84890fc41f280809a9bce7326529d044e2f9 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:37 +0100 Subject: [PATCH 306/461] ASoC: sun4i-codec: Add MIC2 Pre-Amplifier, Mic2 input Add MIC2 Pre-Amplifier, Mic2 input for Allwinner A10 and Allwinner A20. Previously, there only the Mic1 input and MIC1 Pre-Amplifier was exposed. This exposes the Mic2 input and MIC2 Pre-Amplifier. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 9a3cb7704810..7b965bc50042 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,6 +64,7 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_MICG (20) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) @@ -673,6 +674,8 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, + 0); static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, @@ -741,6 +744,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { /* Mic Pre-Amplifiers */ SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0), + SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0), /* Power Amplifier */ SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL, @@ -751,6 +756,7 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { &sun4i_codec_pa_mute), SND_SOC_DAPM_INPUT("Mic1"), + SND_SOC_DAPM_INPUT("Mic2"), SND_SOC_DAPM_OUTPUT("HP Right"), SND_SOC_DAPM_OUTPUT("HP Left"), @@ -790,6 +796,12 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right ADC", NULL, "MIC1 Pre-Amplifier" }, { "MIC1 Pre-Amplifier", NULL, "Mic1"}, { "Mic1", NULL, "VMIC" }, + + /* Mic2 Routes */ + { "Left ADC", NULL, "MIC2 Pre-Amplifier" }, + { "Right ADC", NULL, "MIC2 Pre-Amplifier" }, + { "MIC2 Pre-Amplifier", NULL, "Mic2"}, + { "Mic2", NULL, "VMIC" }, }; static const struct snd_soc_component_driver sun4i_codec_codec = { From b5a656030c7435f37deb5d38b1593fba624b8d6d Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:38 +0100 Subject: [PATCH 307/461] ASoC: sun4i-codec: Add Mic Playback Volume Add a control "Mic Playback Volume" that allows the user to control the MIC gain stage (common for Mic1 and Mic2) leading to the output mixer. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 7b965bc50042..060a40b45ab0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -681,6 +681,9 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, + sun4i_codec_micin_loopback_gain_scale), }; static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { From b71a7eb56c958ffb8c90cef74f3dff6f87e6b554 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:39 +0100 Subject: [PATCH 308/461] ASoC: sun4i-codec: Add sun7i_codec_controls, sun7i_codec_codec Introduce sun7i_codec_controls because some of the controls are different on Allwinner A20 compared to Allwinner A10. Also introduce sun7i_codec_codec in order to use sun7i_codec_controls and make sun7i_codec_quirks use sun7i_codec_codec. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 060a40b45ab0..52453c46b409 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -686,6 +686,15 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { sun4i_codec_micin_loopback_gain_scale), }; +static const struct snd_kcontrol_new sun7i_codec_controls[] = { + SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, + sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, + sun4i_codec_micin_loopback_gain_scale), +}; + static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0), @@ -820,6 +829,19 @@ static const struct snd_soc_component_driver sun4i_codec_codec = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver sun7i_codec_codec = { + .controls = sun7i_codec_controls, + .num_controls = ARRAY_SIZE(sun7i_codec_controls), + .dapm_widgets = sun4i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), + .dapm_routes = sun4i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + /*** sun6i Codec ***/ /* mixer controls */ @@ -1500,7 +1522,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { static const struct sun4i_codec_quirks sun7i_codec_quirks = { .regmap_config = &sun7i_codec_regmap_config, - .codec = &sun4i_codec_codec, + .codec = &sun7i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, From b329c78eb0c80bf17e877edde6d42c0793f19024 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:40 +0100 Subject: [PATCH 309/461] ASoC: sun4i-codec: Add Mic1 Boost Volume, Mic2 Boost Volume Add Mic1 Boost Volume and Mic2 Boost Volume for Allwinner A10 and for Allwinner A20. Those controls are in different registers per chip model, so put the Allwinner A10 controls and the Allwinner A20 controls into the newly split sun4i_codec_controls and sun7i_codec_controls, respectively. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 52453c46b409..9d509ede22c7 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -95,6 +95,8 @@ #define SUN4I_CODEC_ADC_ACTL_PREG1EN (29) #define SUN4I_CODEC_ADC_ACTL_PREG2EN (28) #define SUN4I_CODEC_ADC_ACTL_VMICEN (27) +#define SUN4I_CODEC_ADC_ACTL_PREG1 (25) +#define SUN4I_CODEC_ADC_ACTL_PREG2 (23) #define SUN4I_CODEC_ADC_ACTL_VADCG (20) #define SUN4I_CODEC_ADC_ACTL_ADCIS (17) #define SUN4I_CODEC_ADC_ACTL_PA_EN (4) @@ -111,6 +113,9 @@ /* Microphone controls (sun7i only) */ #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1 (29) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2 (26) + /* * sun6i specific registers * @@ -676,6 +681,12 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, 0); +static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0)); +static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0)); static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, @@ -684,6 +695,12 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0, + sun4i_codec_micin_preamp_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0, + sun4i_codec_micin_preamp_gain_scale), }; static const struct snd_kcontrol_new sun7i_codec_controls[] = { @@ -693,6 +710,12 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, + SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0, + sun7i_codec_micin_preamp_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, + SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0, + sun7i_codec_micin_preamp_gain_scale), }; static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { From 0bbb8e83cfe02d670380798ae1876668f8bbd00c Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:41 +0100 Subject: [PATCH 310/461] ASoC: sun4i-codec: Merge sun4i_codec_left_mixer_controls and sun4i_codec_right_mixer_controls into sun4i_codec_mixer_controls Since it's now possible to have a DAPM mixer control with multiple channels, use it to cut down the total number of controls. Keep "Left Mixer Left DAC Playback Switch" and "Right Mixer Right DAC Playback Switch" name & layout the same as before for compatibility. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 9d509ede22c7..279a7880d623 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -718,15 +718,15 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { sun7i_codec_micin_preamp_gain_scale), }; -static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, - SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0), -}; - -static const struct snd_kcontrol_new sun4i_codec_right_mixer_controls[] = { - SOC_DAPM_SINGLE("Right DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, - SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 1, 0), - SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, +static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS, + 1, 0), + SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS, + 1, 0), + SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), }; @@ -762,11 +762,11 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { /* Mixers */ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, - sun4i_codec_left_mixer_controls, - ARRAY_SIZE(sun4i_codec_left_mixer_controls)), + sun4i_codec_mixer_controls, + ARRAY_SIZE(sun4i_codec_mixer_controls)), SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, - sun4i_codec_right_mixer_controls, - ARRAY_SIZE(sun4i_codec_right_mixer_controls)), + sun4i_codec_mixer_controls, + ARRAY_SIZE(sun4i_codec_mixer_controls)), /* Global Mixer Enable */ SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, @@ -808,12 +808,12 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { /* Right Mixer Routes */ { "Right Mixer", NULL, "Mixer Enable" }, - { "Right Mixer", "Left DAC Playback Switch", "Left DAC" }, - { "Right Mixer", "Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, + { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, - { "Left Mixer", "Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, /* Power Amplifier Routes */ { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, From 44a1f4e8cfcc5492c4e33b983987506719714786 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:42 +0100 Subject: [PATCH 311/461] ASoC: sun4i-codec: Add Mic1 Playback Switch, Mic2 Playback Switch Add Mic1 Playback Switch and Mic2 Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 279a7880d623..87bb16e59da7 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -68,6 +68,10 @@ #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) +#define SUN4I_CODEC_DAC_ACTL_MIC1LS (12) +#define SUN4I_CODEC_DAC_ACTL_MIC1RS (11) +#define SUN4I_CODEC_DAC_ACTL_MIC2LS (10) +#define SUN4I_CODEC_DAC_ACTL_MIC2RS (9) #define SUN4I_CODEC_DAC_ACTL_DACPAS (8) #define SUN4I_CODEC_DAC_ACTL_MIXPAS (7) #define SUN4I_CODEC_DAC_ACTL_PA_MUTE (6) @@ -728,6 +732,12 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MIC1LS, + SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MIC2LS, + SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0), }; static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { @@ -810,10 +820,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Power Amplifier Routes */ { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, From 50d164194879ade8dbb1a473232fed0e77d8bfd1 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:43 +0100 Subject: [PATCH 312/461] ASoC: sun4i-codec: Add FM Playback Volume, FM Left, FM Right, FM Playback Switch Add FM Playback Volume for Allwinner A10 and Allwinner A20. Add FM Left, FM Right, FM Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 87bb16e59da7..2ec7a43975f6 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,7 +64,10 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_FMG (23) #define SUN4I_CODEC_DAC_ACTL_MICG (20) +#define SUN4I_CODEC_DAC_ACTL_LFMS (17) +#define SUN4I_CODEC_DAC_ACTL_RFMS (16) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) @@ -683,6 +686,8 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150, + 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, 0); static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale, @@ -696,6 +701,9 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, + sun4i_codec_fmin_loopback_gain_scale), SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), @@ -711,6 +719,9 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, + sun4i_codec_fmin_loopback_gain_scale), SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), @@ -732,6 +743,9 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LFMS, + SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0), SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MIC1LS, SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0), @@ -800,6 +814,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("FM Right"), + SND_SOC_DAPM_INPUT("FM Left"), SND_SOC_DAPM_INPUT("Mic1"), SND_SOC_DAPM_INPUT("Mic2"), @@ -820,12 +836,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "FM Playback Switch", "FM Right" }, { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "FM Playback Switch", "FM Left" }, { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, From 67690c286de6afa0dc954b19a9878e3623153cb7 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:44 +0100 Subject: [PATCH 313/461] ASoC: sun4i-codec: Add Line Playback Volume, Line Boost Volume, Line Right, Line Left, Line Playback Switch Add Line Playback Volume for Allwinner A10 and Allwinner A20. Add Line Boost Volume for Allwinner A10 and Allwinner A20. Add Line Right, Line Left, Line Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 2ec7a43975f6..15d08e343b47 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,8 +64,11 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_LNG (26) #define SUN4I_CODEC_DAC_ACTL_FMG (23) #define SUN4I_CODEC_DAC_ACTL_MICG (20) +#define SUN4I_CODEC_DAC_ACTL_LLNS (19) +#define SUN4I_CODEC_DAC_ACTL_RLNS (18) #define SUN4I_CODEC_DAC_ACTL_LFMS (17) #define SUN4I_CODEC_DAC_ACTL_RFMS (16) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) @@ -106,6 +109,7 @@ #define SUN4I_CODEC_ADC_ACTL_PREG2 (23) #define SUN4I_CODEC_ADC_ACTL_VADCG (20) #define SUN4I_CODEC_ADC_ACTL_ADCIS (17) +#define SUN4I_CODEC_ADC_ACTL_LNPREG (13) #define SUN4I_CODEC_ADC_ACTL_PA_EN (4) #define SUN4I_CODEC_ADC_ACTL_DDE (3) #define SUN4I_CODEC_ADC_DEBUG (0x2c) @@ -686,6 +690,10 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150, + 0); +static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300, + 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, @@ -701,6 +709,12 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, + sun4i_codec_linein_loopback_gain_scale), + SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, + sun4i_codec_linein_preamp_gain_scale), SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, sun4i_codec_fmin_loopback_gain_scale), @@ -719,6 +733,12 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, + sun4i_codec_linein_loopback_gain_scale), + SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, + sun4i_codec_linein_preamp_gain_scale), SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, sun4i_codec_fmin_loopback_gain_scale), @@ -743,6 +763,9 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LLNS, + SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0), SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LFMS, SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0), @@ -814,6 +837,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("Line Right"), + SND_SOC_DAPM_INPUT("Line Left"), SND_SOC_DAPM_INPUT("FM Right"), SND_SOC_DAPM_INPUT("FM Left"), SND_SOC_DAPM_INPUT("Mic1"), @@ -836,6 +861,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Line Playback Switch", "Line Right" }, { "Right Mixer", "FM Playback Switch", "FM Right" }, { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, @@ -843,6 +869,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Line Playback Switch", "Line Left" }, { "Left Mixer", "FM Playback Switch", "FM Left" }, { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, From 7c536bade37f11833ea358fbb84aca045b157fa4 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:38 -0300 Subject: [PATCH 314/461] dt-bindings: sound: Document jz4740-codec bindings Add documentation about how to probe the jz4740-codec driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4740-codec.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt new file mode 100644 index 000000000000..1ffcade87e7b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt @@ -0,0 +1,20 @@ +Ingenic JZ4740 codec controller + +Required properties: +- compatible : "ingenic,jz4740-codec" +- reg : codec registers location and length +- clocks : phandle to the AIC clock. +- clock-names: must be set to "aic". +- #sound-dai-cells: Must be set to 0. + +Example: + +codec: audio-codec@10020080 { + compatible = "ingenic,jz4740-codec"; + reg = <0x10020080 0x8>; + + #sound-dai-cells = <0>; + + clocks = <&cgu JZ4740_CLK_AIC>; + clock-names = "aic"; +}; From f58f2b0a9f6ecfd76cb08fe1c4894ab009a30c66 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:39 -0300 Subject: [PATCH 315/461] dt-bindings: sound: Document jz4725b-codec bindings Add documentation about how to probe the jz4725b-codec driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4725b-codec.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt new file mode 100644 index 000000000000..05adc0d47b13 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt @@ -0,0 +1,20 @@ +Ingenic JZ4725B codec controller + +Required properties: +- compatible : "ingenic,jz4725b-codec" +- reg : codec registers location and length +- clocks : phandle to the AIC clock. +- clock-names: must be set to "aic". +- #sound-dai-cells: Must be set to 0. + +Example: + +codec: audio-codec@100200a4 { + compatible = "ingenic,jz4725b-codec"; + reg = <0x100200a4 0x8>; + + #sound-dai-cells = <0>; + + clocks = <&cgu JZ4725B_CLK_AIC>; + clock-names = "aic"; +}; From 06a334ae98d15c3e32ae4ef8ce18a241a12f3dff Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:40 -0300 Subject: [PATCH 316/461] ASoC: codecs: jz4740: Use SPDX license notifier Add license information as a standard SPDX license notifier instead of custom text. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 9395b583432c..9b3e1227a971 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -1,15 +1,8 @@ -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ +// SPDX-License-Identifier: GPL-2.0 +// +// JZ4740 CODEC driver +// +// Copyright (C) 2009-2010, Lars-Peter Clausen #include #include From 030a79e97730976f54299634fa3bbb7a99e32b71 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:41 -0300 Subject: [PATCH 317/461] ASoC: codecs: jz4740: Add support for devicetree Add support for probing the driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 9b3e1227a971..974e17fa1911 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -346,10 +346,19 @@ static int jz4740_codec_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_OF +static const struct of_device_id jz4740_codec_of_matches[] = { + { .compatible = "ingenic,jz4740-codec", }, + { } +}; +MODULE_DEVICE_TABLE(of, jz4740_codec_of_matches); +#endif + static struct platform_driver jz4740_codec_driver = { .probe = jz4740_codec_probe, .driver = { .name = "jz4740-codec", + .of_match_table = of_match_ptr(jz4740_codec_of_matches), }, }; From edcd3ed182f804ebec71b063bab32c424ddd8b6a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:42 -0300 Subject: [PATCH 318/461] ASoC: codecs: Kconfig: Show knob, and depend on MIPS || COMPILE_TEST Show the knob to enable or disable the jz4740-codec driver, add a proper description, and add a dependency on MIPS || COMPILE_TEST, as this driver is only useful on MIPS. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fec894c725d3..e6ce18c21b98 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -579,8 +579,15 @@ config SND_SOC_CX20442 depends on TTY config SND_SOC_JZ4740_CODEC + depends on MIPS || COMPILE_TEST select REGMAP_MMIO - tristate + tristate "Ingenic JZ4740 internal CODEC" + help + Enable support for the internal CODEC found in the JZ4740 SoC + from Ingenic. + + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4740-codec. config SND_SOC_JZ4725B_CODEC depends on MIPS || COMPILE_TEST From a50e32694fbcdbf55875095258b9398e2eabd71f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:43 -0300 Subject: [PATCH 319/461] ASoC: codecs: jz4725b: Use C++ style comments in header Change the header comment to use C++ style, so that it looks more consistent with the rest of ASoC. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 24b1b23b99c9..103ccbc5d55c 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * JZ4725B CODEC driver - * - * Copyright (C) 2019, Paul Cercueil - */ +// +// JZ4725B CODEC driver +// +// Copyright (C) 2019, Paul Cercueil #include #include From 511d53ac86746f397791e7c4bd47993244fc7420 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:22:56 +0100 Subject: [PATCH 320/461] ASoC: doc: Fix typos in dpcm.rst This patch fixes a few typos in the DPCM documentation. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- Documentation/sound/soc/dpcm.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Documentation/sound/soc/dpcm.rst b/Documentation/sound/soc/dpcm.rst index f6845b2278ea..77f67ded53de 100644 --- a/Documentation/sound/soc/dpcm.rst +++ b/Documentation/sound/soc/dpcm.rst @@ -13,7 +13,7 @@ drivers that expose several ALSA PCMs and can route to multiple DAIs. The DPCM runtime routing is determined by the ALSA mixer settings in the same way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM graph representing the DSP internal audio paths and uses the mixer settings to -determine the patch used by each ALSA PCM. +determine the path used by each ALSA PCM. DPCM re-uses all the existing component codec, platform and DAI drivers without any modifications. @@ -101,7 +101,7 @@ The audio driver processes this as follows :- 4. Machine driver or audio HAL enables the speaker path. -5. DPCM runs the PCM ops for startup(), hw_params(), prepapre() and +5. DPCM runs the PCM ops for startup(), hw_params(), prepare() and trigger(start) for DAI1 Speakers since the path is enabled. In this example, the machine driver or userspace audio HAL can alter the routing @@ -221,7 +221,7 @@ like a BT phone call :- This allows the host CPU to sleep while the DSP, MODEM DAI and the BT DAI are still in operation. -A BE DAI link can also set the codec to a dummy device if the code is a device +A BE DAI link can also set the codec to a dummy device if the codec is a device that is managed externally. Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the @@ -249,7 +249,7 @@ configuration. struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - /* The DSP will covert the FE rate to 48k, stereo */ + /* The DSP will convert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; @@ -386,5 +386,3 @@ This means creating a new FE that is connected with a virtual path to both DAI links. The DAI links will be started when the FE PCM is started and stopped when the FE PCM is stopped. Note that the FE PCM cannot read or write data in this configuration. - - From 6ba9dd6c893b8e60639cfe34e983786068dba9fa Mon Sep 17 00:00:00 2001 From: James Schulman Date: Thu, 7 Feb 2019 12:12:15 -0600 Subject: [PATCH 321/461] ASoC: cs35l36: Add support for Cirrus CS35L36 Amplifier Add driver support for Cirrus Logic CS35L36 boosted speaker amplifier Signed-off-by: James Schulman Reviewed-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- include/sound/cs35l36.h | 43 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l36.c | 1958 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l36.h | 446 ++++++++ 5 files changed, 2454 insertions(+) create mode 100644 include/sound/cs35l36.h create mode 100644 sound/soc/codecs/cs35l36.c create mode 100644 sound/soc/codecs/cs35l36.h diff --git a/include/sound/cs35l36.h b/include/sound/cs35l36.h new file mode 100644 index 000000000000..8f8049d390f0 --- /dev/null +++ b/include/sound/cs35l36.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * linux/sound/cs35l36.h -- Platform data for CS35L36 + * + * Copyright 2018 Cirrus Logic, Inc. + * + * Author: James Schulman + * + */ + +#ifndef __CS35L36_H +#define __CS35L36_H + +struct cs35l36_vpbr_cfg { + bool is_present; + bool vpbr_en; + int vpbr_thld; + int vpbr_atk_rate; + int vpbr_atk_vol; + int vpbr_max_attn; + int vpbr_wait; + int vpbr_rel_rate; + int vpbr_mute_en; +}; + +struct cs35l36_platform_data { + bool multi_amp_mode; + bool dcm_mode; + bool amp_pcm_inv; + bool imon_pol_inv; + bool vmon_pol_inv; + int boost_ind; + int bst_vctl; + int bst_vctl_sel; + int bst_ipk; + bool extern_boost; + int temp_warn_thld; + int irq_drv_sel; + int irq_gpio_sel; + struct cs35l36_vpbr_cfg vpbr_config; +}; + +#endif /* __CS35L36_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e6ce18c21b98..419114edfd57 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -55,6 +55,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C select SND_SOC_CS35L35 if I2C + select SND_SOC_CS35L36 if I2C select SND_SOC_CS42L42 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT @@ -484,6 +485,10 @@ config SND_SOC_CS35L35 tristate "Cirrus Logic CS35L35 CODEC" depends on I2C +config SND_SOC_CS35L36 + tristate "Cirrus Logic CS35L36 CODEC" + depends on I2C + config SND_SOC_CS42L42 tristate "Cirrus Logic CS42L42 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b07dfb5fa700..aab2ad95a137 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -47,6 +47,7 @@ snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs35l35-objs := cs35l35.o +snd-soc-cs35l36-objs := cs35l36.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -319,6 +320,7 @@ obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o +obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c new file mode 100644 index 000000000000..4f880a678812 --- /dev/null +++ b/sound/soc/codecs/cs35l36.c @@ -0,0 +1,1958 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// cs35l36.c -- CS35L36 ALSA SoC audio driver +// +// Copyright 2018 Cirrus Logic, Inc. +// +// Author: James Schulman + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs35l36.h" + +/* + * Some fields take zero as a valid value so use a high bit flag that won't + * get written to the device to mark those. + */ +#define CS35L36_VALID_PDATA 0x80000000 + +static const char * const cs35l36_supplies[] = { + "VA", + "VP", +}; + +struct cs35l36_private { + struct device *dev; + struct cs35l36_platform_data pdata; + struct regmap *regmap; + struct regulator_bulk_data supplies[2]; + int num_supplies; + int clksrc; + int chip_version; + int rev_id; + int ldm_mode_sel; + struct gpio_desc *reset_gpio; +}; + +struct cs35l36_pll_config { + int freq; + int clk_cfg; + int fll_igain; +}; + +static const struct cs35l36_pll_config cs35l36_pll_sysclk[] = { + {32768, 0x00, 0x05}, + {8000, 0x01, 0x03}, + {11025, 0x02, 0x03}, + {12000, 0x03, 0x03}, + {16000, 0x04, 0x04}, + {22050, 0x05, 0x04}, + {24000, 0x06, 0x04}, + {32000, 0x07, 0x05}, + {44100, 0x08, 0x05}, + {48000, 0x09, 0x05}, + {88200, 0x0A, 0x06}, + {96000, 0x0B, 0x06}, + {128000, 0x0C, 0x07}, + {176400, 0x0D, 0x07}, + {192000, 0x0E, 0x07}, + {256000, 0x0F, 0x08}, + {352800, 0x10, 0x08}, + {384000, 0x11, 0x08}, + {512000, 0x12, 0x09}, + {705600, 0x13, 0x09}, + {750000, 0x14, 0x09}, + {768000, 0x15, 0x09}, + {1000000, 0x16, 0x0A}, + {1024000, 0x17, 0x0A}, + {1200000, 0x18, 0x0A}, + {1411200, 0x19, 0x0A}, + {1500000, 0x1A, 0x0A}, + {1536000, 0x1B, 0x0A}, + {2000000, 0x1C, 0x0A}, + {2048000, 0x1D, 0x0A}, + {2400000, 0x1E, 0x0A}, + {2822400, 0x1F, 0x0A}, + {3000000, 0x20, 0x0A}, + {3072000, 0x21, 0x0A}, + {3200000, 0x22, 0x0A}, + {4000000, 0x23, 0x0A}, + {4096000, 0x24, 0x0A}, + {4800000, 0x25, 0x0A}, + {5644800, 0x26, 0x0A}, + {6000000, 0x27, 0x0A}, + {6144000, 0x28, 0x0A}, + {6250000, 0x29, 0x08}, + {6400000, 0x2A, 0x0A}, + {6500000, 0x2B, 0x08}, + {6750000, 0x2C, 0x09}, + {7526400, 0x2D, 0x0A}, + {8000000, 0x2E, 0x0A}, + {8192000, 0x2F, 0x0A}, + {9600000, 0x30, 0x0A}, + {11289600, 0x31, 0x0A}, + {12000000, 0x32, 0x0A}, + {12288000, 0x33, 0x0A}, + {12500000, 0x34, 0x08}, + {12800000, 0x35, 0x0A}, + {13000000, 0x36, 0x0A}, + {13500000, 0x37, 0x0A}, + {19200000, 0x38, 0x0A}, + {22579200, 0x39, 0x0A}, + {24000000, 0x3A, 0x0A}, + {24576000, 0x3B, 0x0A}, + {25000000, 0x3C, 0x0A}, + {25600000, 0x3D, 0x0A}, + {26000000, 0x3E, 0x0A}, + {27000000, 0x3F, 0x0A}, +}; + +struct reg_default cs35l36_reg[] = { + {CS35L36_TESTKEY_CTRL, 0x00000000}, + {CS35L36_USERKEY_CTL, 0x00000000}, + {CS35L36_OTP_CTRL1, 0x00002460}, + {CS35L36_OTP_CTRL2, 0x00000000}, + {CS35L36_OTP_CTRL3, 0x00000000}, + {CS35L36_OTP_CTRL4, 0x00000000}, + {CS35L36_OTP_CTRL5, 0x00000000}, + {CS35L36_PAC_CTL1, 0x00000004}, + {CS35L36_PAC_CTL2, 0x00000000}, + {CS35L36_PAC_CTL3, 0x00000000}, + {CS35L36_PWR_CTRL1, 0x00000000}, + {CS35L36_PWR_CTRL2, 0x00003321}, + {CS35L36_PWR_CTRL3, 0x01000010}, + {CS35L36_CTRL_OVRRIDE, 0x00000002}, + {CS35L36_AMP_OUT_MUTE, 0x00000000}, + {CS35L36_OTP_TRIM_STATUS, 0x00000000}, + {CS35L36_DISCH_FILT, 0x00000000}, + {CS35L36_PROTECT_REL_ERR, 0x00000000}, + {CS35L36_PAD_INTERFACE, 0x00000038}, + {CS35L36_PLL_CLK_CTRL, 0x00000010}, + {CS35L36_GLOBAL_CLK_CTRL, 0x00000003}, + {CS35L36_ADC_CLK_CTRL, 0x00000000}, + {CS35L36_SWIRE_CLK_CTRL, 0x00000000}, + {CS35L36_SP_SCLK_CLK_CTRL, 0x00000000}, + {CS35L36_MDSYNC_EN, 0x00000000}, + {CS35L36_MDSYNC_TX_ID, 0x00000000}, + {CS35L36_MDSYNC_PWR_CTRL, 0x00000000}, + {CS35L36_MDSYNC_DATA_TX, 0x00000000}, + {CS35L36_MDSYNC_TX_STATUS, 0x00000002}, + {CS35L36_MDSYNC_RX_STATUS, 0x00000000}, + {CS35L36_MDSYNC_ERR_STATUS, 0x00000000}, + {CS35L36_BSTCVRT_VCTRL1, 0x00000000}, + {CS35L36_BSTCVRT_VCTRL2, 0x00000001}, + {CS35L36_BSTCVRT_PEAK_CUR, 0x0000004A}, + {CS35L36_BSTCVRT_SFT_RAMP, 0x00000003}, + {CS35L36_BSTCVRT_COEFF, 0x00002424}, + {CS35L36_BSTCVRT_SLOPE_LBST, 0x00005800}, + {CS35L36_BSTCVRT_SW_FREQ, 0x00010000}, + {CS35L36_BSTCVRT_DCM_CTRL, 0x00002001}, + {CS35L36_BSTCVRT_DCM_MODE_FORCE, 0x00000000}, + {CS35L36_BSTCVRT_OVERVOLT_CTRL, 0x00000130}, + {CS35L36_VPI_LIMIT_MODE, 0x00000000}, + {CS35L36_VPI_LIMIT_MINMAX, 0x00003000}, + {CS35L36_VPI_VP_THLD, 0x00101010}, + {CS35L36_VPI_TRACK_CTRL, 0x00000000}, + {CS35L36_VPI_TRIG_MODE_CTRL, 0x00000000}, + {CS35L36_VPI_TRIG_STEPS, 0x00000000}, + {CS35L36_VI_SPKMON_FILT, 0x00000003}, + {CS35L36_VI_SPKMON_GAIN, 0x00000909}, + {CS35L36_VI_SPKMON_IP_SEL, 0x00000000}, + {CS35L36_DTEMP_WARN_THLD, 0x00000002}, + {CS35L36_DTEMP_STATUS, 0x00000000}, + {CS35L36_VPVBST_FS_SEL, 0x00000001}, + {CS35L36_VPVBST_VP_CTRL, 0x000001C0}, + {CS35L36_VPVBST_VBST_CTRL, 0x000001C0}, + {CS35L36_ASP_TX_PIN_CTRL, 0x00000028}, + {CS35L36_ASP_RATE_CTRL, 0x00090000}, + {CS35L36_ASP_FORMAT, 0x00000002}, + {CS35L36_ASP_FRAME_CTRL, 0x00180018}, + {CS35L36_ASP_TX1_TX2_SLOT, 0x00010000}, + {CS35L36_ASP_TX3_TX4_SLOT, 0x00030002}, + {CS35L36_ASP_TX5_TX6_SLOT, 0x00050004}, + {CS35L36_ASP_TX7_TX8_SLOT, 0x00070006}, + {CS35L36_ASP_RX1_SLOT, 0x00000000}, + {CS35L36_ASP_RX_TX_EN, 0x00000000}, + {CS35L36_ASP_RX1_SEL, 0x00000008}, + {CS35L36_ASP_TX1_SEL, 0x00000018}, + {CS35L36_ASP_TX2_SEL, 0x00000019}, + {CS35L36_ASP_TX3_SEL, 0x00000028}, + {CS35L36_ASP_TX4_SEL, 0x00000029}, + {CS35L36_ASP_TX5_SEL, 0x00000020}, + {CS35L36_ASP_TX6_SEL, 0x00000000}, + {CS35L36_SWIRE_P1_TX1_SEL, 0x00000018}, + {CS35L36_SWIRE_P1_TX2_SEL, 0x00000019}, + {CS35L36_SWIRE_P2_TX1_SEL, 0x00000028}, + {CS35L36_SWIRE_P2_TX2_SEL, 0x00000029}, + {CS35L36_SWIRE_P2_TX3_SEL, 0x00000020}, + {CS35L36_SWIRE_DP1_FIFO_CFG, 0x0000001B}, + {CS35L36_SWIRE_DP2_FIFO_CFG, 0x0000001B}, + {CS35L36_SWIRE_DP3_FIFO_CFG, 0x0000001B}, + {CS35L36_SWIRE_PCM_RX_DATA, 0x00000000}, + {CS35L36_SWIRE_FS_SEL, 0x00000001}, + {CS35L36_AMP_DIG_VOL_CTRL, 0x00008000}, + {CS35L36_VPBR_CFG, 0x02AA1905}, + {CS35L36_VBBR_CFG, 0x02AA1905}, + {CS35L36_VPBR_STATUS, 0x00000000}, + {CS35L36_VBBR_STATUS, 0x00000000}, + {CS35L36_OVERTEMP_CFG, 0x00000001}, + {CS35L36_AMP_ERR_VOL, 0x00000000}, + {CS35L36_CLASSH_CFG, 0x000B0405}, + {CS35L36_CLASSH_FET_DRV_CFG, 0x00000111}, + {CS35L36_NG_CFG, 0x00000033}, + {CS35L36_AMP_GAIN_CTRL, 0x00000273}, + {CS35L36_PWM_MOD_IO_CTRL, 0x00000000}, + {CS35L36_PWM_MOD_STATUS, 0x00000000}, + {CS35L36_DAC_MSM_CFG, 0x00000000}, + {CS35L36_AMP_SLOPE_CTRL, 0x00000B00}, + {CS35L36_AMP_PDM_VOLUME, 0x00000000}, + {CS35L36_AMP_PDM_RATE_CTRL, 0x00000000}, + {CS35L36_PDM_CH_SEL, 0x00000000}, + {CS35L36_AMP_NG_CTRL, 0x0000212F}, + {CS35L36_PDM_HIGHFILT_CTRL, 0x00000000}, + {CS35L36_PAC_INT0_CTRL, 0x00000001}, + {CS35L36_PAC_INT1_CTRL, 0x00000001}, + {CS35L36_PAC_INT2_CTRL, 0x00000001}, + {CS35L36_PAC_INT3_CTRL, 0x00000001}, + {CS35L36_PAC_INT4_CTRL, 0x00000001}, + {CS35L36_PAC_INT5_CTRL, 0x00000001}, + {CS35L36_PAC_INT6_CTRL, 0x00000001}, + {CS35L36_PAC_INT7_CTRL, 0x00000001}, +}; + +bool cs35l36_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L36_SW_RESET: + case CS35L36_SW_REV: + case CS35L36_HW_REV: + case CS35L36_TESTKEY_CTRL: + case CS35L36_USERKEY_CTL: + case CS35L36_OTP_MEM30: + case CS35L36_OTP_CTRL1: + case CS35L36_OTP_CTRL2: + case CS35L36_OTP_CTRL3: + case CS35L36_OTP_CTRL4: + case CS35L36_OTP_CTRL5: + case CS35L36_PAC_CTL1: + case CS35L36_PAC_CTL2: + case CS35L36_PAC_CTL3: + case CS35L36_DEVICE_ID: + case CS35L36_FAB_ID: + case CS35L36_REV_ID: + case CS35L36_PWR_CTRL1: + case CS35L36_PWR_CTRL2: + case CS35L36_PWR_CTRL3: + case CS35L36_CTRL_OVRRIDE: + case CS35L36_AMP_OUT_MUTE: + case CS35L36_OTP_TRIM_STATUS: + case CS35L36_DISCH_FILT: + case CS35L36_PROTECT_REL_ERR: + case CS35L36_PAD_INTERFACE: + case CS35L36_PLL_CLK_CTRL: + case CS35L36_GLOBAL_CLK_CTRL: + case CS35L36_ADC_CLK_CTRL: + case CS35L36_SWIRE_CLK_CTRL: + case CS35L36_SP_SCLK_CLK_CTRL: + case CS35L36_TST_FS_MON0: + case CS35L36_MDSYNC_EN: + case CS35L36_MDSYNC_TX_ID: + case CS35L36_MDSYNC_PWR_CTRL: + case CS35L36_MDSYNC_DATA_TX: + case CS35L36_MDSYNC_TX_STATUS: + case CS35L36_MDSYNC_RX_STATUS: + case CS35L36_MDSYNC_ERR_STATUS: + case CS35L36_BSTCVRT_VCTRL1: + case CS35L36_BSTCVRT_VCTRL2: + case CS35L36_BSTCVRT_PEAK_CUR: + case CS35L36_BSTCVRT_SFT_RAMP: + case CS35L36_BSTCVRT_COEFF: + case CS35L36_BSTCVRT_SLOPE_LBST: + case CS35L36_BSTCVRT_SW_FREQ: + case CS35L36_BSTCVRT_DCM_CTRL: + case CS35L36_BSTCVRT_DCM_MODE_FORCE: + case CS35L36_BSTCVRT_OVERVOLT_CTRL: + case CS35L36_BST_TST_MANUAL: + case CS35L36_BST_ANA2_TEST: + case CS35L36_VPI_LIMIT_MODE: + case CS35L36_VPI_LIMIT_MINMAX: + case CS35L36_VPI_VP_THLD: + case CS35L36_VPI_TRACK_CTRL: + case CS35L36_VPI_TRIG_MODE_CTRL: + case CS35L36_VPI_TRIG_STEPS: + case CS35L36_VI_SPKMON_FILT: + case CS35L36_VI_SPKMON_GAIN: + case CS35L36_VI_SPKMON_IP_SEL: + case CS35L36_DTEMP_WARN_THLD: + case CS35L36_DTEMP_STATUS: + case CS35L36_VPVBST_FS_SEL: + case CS35L36_VPVBST_VP_CTRL: + case CS35L36_VPVBST_VBST_CTRL: + case CS35L36_ASP_TX_PIN_CTRL: + case CS35L36_ASP_RATE_CTRL: + case CS35L36_ASP_FORMAT: + case CS35L36_ASP_FRAME_CTRL: + case CS35L36_ASP_TX1_TX2_SLOT: + case CS35L36_ASP_TX3_TX4_SLOT: + case CS35L36_ASP_TX5_TX6_SLOT: + case CS35L36_ASP_TX7_TX8_SLOT: + case CS35L36_ASP_RX1_SLOT: + case CS35L36_ASP_RX_TX_EN: + case CS35L36_ASP_RX1_SEL: + case CS35L36_ASP_TX1_SEL: + case CS35L36_ASP_TX2_SEL: + case CS35L36_ASP_TX3_SEL: + case CS35L36_ASP_TX4_SEL: + case CS35L36_ASP_TX5_SEL: + case CS35L36_ASP_TX6_SEL: + case CS35L36_SWIRE_P1_TX1_SEL: + case CS35L36_SWIRE_P1_TX2_SEL: + case CS35L36_SWIRE_P2_TX1_SEL: + case CS35L36_SWIRE_P2_TX2_SEL: + case CS35L36_SWIRE_P2_TX3_SEL: + case CS35L36_SWIRE_DP1_FIFO_CFG: + case CS35L36_SWIRE_DP2_FIFO_CFG: + case CS35L36_SWIRE_DP3_FIFO_CFG: + case CS35L36_SWIRE_PCM_RX_DATA: + case CS35L36_SWIRE_FS_SEL: + case CS35L36_AMP_DIG_VOL_CTRL: + case CS35L36_VPBR_CFG: + case CS35L36_VBBR_CFG: + case CS35L36_VPBR_STATUS: + case CS35L36_VBBR_STATUS: + case CS35L36_OVERTEMP_CFG: + case CS35L36_AMP_ERR_VOL: + case CS35L36_CLASSH_CFG: + case CS35L36_CLASSH_FET_DRV_CFG: + case CS35L36_NG_CFG: + case CS35L36_AMP_GAIN_CTRL: + case CS35L36_PWM_MOD_IO_CTRL: + case CS35L36_PWM_MOD_STATUS: + case CS35L36_DAC_MSM_CFG: + case CS35L36_AMP_SLOPE_CTRL: + case CS35L36_AMP_PDM_VOLUME: + case CS35L36_AMP_PDM_RATE_CTRL: + case CS35L36_PDM_CH_SEL: + case CS35L36_AMP_NG_CTRL: + case CS35L36_PDM_HIGHFILT_CTRL: + case CS35L36_INT1_STATUS: + case CS35L36_INT2_STATUS: + case CS35L36_INT3_STATUS: + case CS35L36_INT4_STATUS: + case CS35L36_INT1_RAW_STATUS: + case CS35L36_INT2_RAW_STATUS: + case CS35L36_INT3_RAW_STATUS: + case CS35L36_INT4_RAW_STATUS: + case CS35L36_INT1_MASK: + case CS35L36_INT2_MASK: + case CS35L36_INT3_MASK: + case CS35L36_INT4_MASK: + case CS35L36_INT1_EDGE_LVL_CTRL: + case CS35L36_INT3_EDGE_LVL_CTRL: + case CS35L36_PAC_INT_STATUS: + case CS35L36_PAC_INT_RAW_STATUS: + case CS35L36_PAC_INT_FLUSH_CTRL: + case CS35L36_PAC_INT0_CTRL: + case CS35L36_PAC_INT1_CTRL: + case CS35L36_PAC_INT2_CTRL: + case CS35L36_PAC_INT3_CTRL: + case CS35L36_PAC_INT4_CTRL: + case CS35L36_PAC_INT5_CTRL: + case CS35L36_PAC_INT6_CTRL: + case CS35L36_PAC_INT7_CTRL: + return true; + default: + if (reg >= CS35L36_PAC_PMEM_WORD0 && + reg <= CS35L36_PAC_PMEM_WORD1023) + return true; + else + return false; + } +} + +bool cs35l36_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L36_TESTKEY_CTRL: + case CS35L36_USERKEY_CTL: + case CS35L36_TST_FS_MON0: + return true; + default: + return false; + } +} + +bool cs35l36_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L36_SW_RESET: + case CS35L36_SW_REV: + case CS35L36_HW_REV: + case CS35L36_TESTKEY_CTRL: + case CS35L36_USERKEY_CTL: + case CS35L36_DEVICE_ID: + case CS35L36_FAB_ID: + case CS35L36_REV_ID: + case CS35L36_INT1_STATUS: + case CS35L36_INT2_STATUS: + case CS35L36_INT3_STATUS: + case CS35L36_INT4_STATUS: + case CS35L36_INT1_RAW_STATUS: + case CS35L36_INT2_RAW_STATUS: + case CS35L36_INT3_RAW_STATUS: + case CS35L36_INT4_RAW_STATUS: + case CS35L36_INT1_MASK: + case CS35L36_INT2_MASK: + case CS35L36_INT3_MASK: + case CS35L36_INT4_MASK: + case CS35L36_INT1_EDGE_LVL_CTRL: + case CS35L36_INT3_EDGE_LVL_CTRL: + case CS35L36_PAC_INT_STATUS: + case CS35L36_PAC_INT_RAW_STATUS: + case CS35L36_PAC_INT_FLUSH_CTRL: + return true; + default: + if (reg >= CS35L36_PAC_PMEM_WORD0 && + reg <= CS35L36_PAC_PMEM_WORD1023) + return true; + else + return false; + } +} + +static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 25, 0); +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); + +static const char * const cs35l36_pcm_sftramp_text[] = { + "Off", ".5ms", "1ms", "2ms", "4ms", "8ms", "15ms", "30ms"}; + +static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, CS35L36_AMP_DIG_VOL_CTRL, 0, + cs35l36_pcm_sftramp_text); + +static int cs35l36_ldm_sel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = cs35l36->ldm_mode_sel; + + return 0; +} + +static int cs35l36_ldm_sel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + int val = (ucontrol->value.integer.value[0]) ? CS35L36_NG_AMP_EN_MASK : + 0; + + cs35l36->ldm_mode_sel = val; + + regmap_update_bits(cs35l36->regmap, CS35L36_NG_CFG, + CS35L36_NG_AMP_EN_MASK, val); + + return 0; +} + +static const struct snd_kcontrol_new cs35l36_aud_controls[] = { + SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L36_AMP_DIG_VOL_CTRL, + 3, 0x4D0, 0x390, dig_vol_tlv), + SOC_SINGLE_TLV("Analog PCM Volume", CS35L36_AMP_GAIN_CTRL, 5, 0x13, 0, + amp_gain_tlv), + SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp), + SOC_SINGLE("Amp Gain Zero-Cross Switch", CS35L36_AMP_GAIN_CTRL, + CS35L36_AMP_ZC_SHIFT, 1, 0), + SOC_SINGLE("PDM LDM Enter Ramp Switch", CS35L36_DAC_MSM_CFG, + CS35L36_PDM_LDM_ENTER_SHIFT, 1, 0), + SOC_SINGLE("PDM LDM Exit Ramp Switch", CS35L36_DAC_MSM_CFG, + CS35L36_PDM_LDM_EXIT_SHIFT, 1, 0), + SOC_SINGLE_BOOL_EXT("LDM Select Switch", 0, cs35l36_ldm_sel_get, + cs35l36_ldm_sel_put), +}; + +static int cs35l36_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + u32 reg; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(cs35l36->regmap, CS35L36_PWR_CTRL1, + CS35L36_GLOBAL_EN_MASK, + 1 << CS35L36_GLOBAL_EN_SHIFT); + + usleep_range(2000, 2100); + + regmap_read(cs35l36->regmap, CS35L36_INT4_RAW_STATUS, ®); + + if (WARN_ON_ONCE(reg & CS35L36_PLL_UNLOCK_MASK)) + dev_crit(cs35l36->dev, "PLL Unlocked\n"); + + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RX1_SEL, + CS35L36_PCM_RX_SEL_MASK, + CS35L36_PCM_RX_SEL_PCM); + regmap_update_bits(cs35l36->regmap, CS35L36_AMP_OUT_MUTE, + CS35L36_AMP_MUTE_MASK, + 0 << CS35L36_AMP_MUTE_SHIFT); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RX1_SEL, + CS35L36_PCM_RX_SEL_MASK, + CS35L36_PCM_RX_SEL_ZERO); + regmap_update_bits(cs35l36->regmap, CS35L36_AMP_OUT_MUTE, + CS35L36_AMP_MUTE_MASK, + 1 << CS35L36_AMP_MUTE_SHIFT); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(cs35l36->regmap, CS35L36_PWR_CTRL1, + CS35L36_GLOBAL_EN_MASK, + 0 << CS35L36_GLOBAL_EN_SHIFT); + + usleep_range(2000, 2100); + break; + default: + dev_dbg(component->dev, "Invalid event = 0x%x\n", event); + return -EINVAL; + } + + return 0; +} + +static int cs35l36_boost_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!cs35l36->pdata.extern_boost) + regmap_update_bits(cs35l36->regmap, CS35L36_PWR_CTRL2, + CS35L36_BST_EN_MASK, + CS35L36_BST_EN << + CS35L36_BST_EN_SHIFT); + break; + case SND_SOC_DAPM_POST_PMD: + if (!cs35l36->pdata.extern_boost) + regmap_update_bits(cs35l36->regmap, CS35L36_PWR_CTRL2, + CS35L36_BST_EN_MASK, + CS35L36_BST_DIS_VP << + CS35L36_BST_EN_SHIFT); + break; + default: + dev_dbg(component->dev, "Invalid event = 0x%x\n", event); + return -EINVAL; + } + + return 0; +} + +static const char * const cs35l36_chan_text[] = { + "RX1", + "RX2", +}; + +static SOC_ENUM_SINGLE_DECL(chansel_enum, CS35L36_ASP_RX1_SLOT, 0, + cs35l36_chan_text); + +static const struct snd_kcontrol_new cs35l36_chan_mux = + SOC_DAPM_ENUM("Input Mux", chansel_enum); + +static const struct snd_kcontrol_new amp_enable_ctrl = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", CS35L36_AMP_OUT_MUTE, + CS35L36_AMP_MUTE_SHIFT, 1, 1); + +static const struct snd_kcontrol_new boost_ctrl = + SOC_DAPM_SINGLE_VIRT("Switch", 1); + +static const char * const asp_tx_src_text[] = { + "Zero Fill", "ASPRX1", "VMON", "IMON", "ERRVOL", "VPMON", "VBSTMON" +}; + +static const unsigned int asp_tx_src_values[] = { + 0x00, 0x08, 0x18, 0x19, 0x20, 0x28, 0x29 +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx1_src_enum, CS35L36_ASP_TX1_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx1_src = + SOC_DAPM_ENUM("ASPTX1SRC", asp_tx1_src_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx2_src_enum, CS35L36_ASP_TX2_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx2_src = + SOC_DAPM_ENUM("ASPTX2SRC", asp_tx2_src_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx3_src_enum, CS35L36_ASP_TX3_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx3_src = + SOC_DAPM_ENUM("ASPTX3SRC", asp_tx3_src_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx4_src_enum, CS35L36_ASP_TX4_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx4_src = + SOC_DAPM_ENUM("ASPTX4SRC", asp_tx4_src_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx5_src_enum, CS35L36_ASP_TX5_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx5_src = + SOC_DAPM_ENUM("ASPTX5SRC", asp_tx5_src_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(asp_tx6_src_enum, CS35L36_ASP_TX6_SEL, 0, + CS35L36_APS_TX_SEL_MASK, asp_tx_src_text, + asp_tx_src_values); + +static const struct snd_kcontrol_new asp_tx6_src = + SOC_DAPM_ENUM("ASPTX6SRC", asp_tx6_src_enum); + +static const struct snd_soc_dapm_widget cs35l36_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Channel Mux", SND_SOC_NOPM, 0, 0, &cs35l36_chan_mux), + SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS35L36_ASP_RX_TX_EN, 16, 0), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L36_PWR_CTRL2, 0, 0, NULL, 0, + cs35l36_main_amp_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 1, &_enable_ctrl), + SND_SOC_DAPM_MIXER("CLASS H", CS35L36_PWR_CTRL3, 4, 0, NULL, 0), + SND_SOC_DAPM_SWITCH_E("BOOST Enable", SND_SOC_NOPM, 0, 0, &boost_ctrl, + cs35l36_boost_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, CS35L36_ASP_RX_TX_EN, 0, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 1, CS35L36_ASP_RX_TX_EN, 1, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 2, CS35L36_ASP_RX_TX_EN, 2, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 3, CS35L36_ASP_RX_TX_EN, 3, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX5", NULL, 4, CS35L36_ASP_RX_TX_EN, 4, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX6", NULL, 5, CS35L36_ASP_RX_TX_EN, 5, 0), + + SND_SOC_DAPM_MUX("ASPTX1SRC", SND_SOC_NOPM, 0, 0, &asp_tx1_src), + SND_SOC_DAPM_MUX("ASPTX2SRC", SND_SOC_NOPM, 0, 0, &asp_tx2_src), + SND_SOC_DAPM_MUX("ASPTX3SRC", SND_SOC_NOPM, 0, 0, &asp_tx3_src), + SND_SOC_DAPM_MUX("ASPTX4SRC", SND_SOC_NOPM, 0, 0, &asp_tx4_src), + SND_SOC_DAPM_MUX("ASPTX5SRC", SND_SOC_NOPM, 0, 0, &asp_tx5_src), + SND_SOC_DAPM_MUX("ASPTX6SRC", SND_SOC_NOPM, 0, 0, &asp_tx6_src), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L36_PWR_CTRL2, 12, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L36_PWR_CTRL2, 13, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L36_PWR_CTRL2, 8, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L36_PWR_CTRL2, 9, 0), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VBST"), + SND_SOC_DAPM_INPUT("VSENSE"), +}; + +static const struct snd_soc_dapm_route cs35l36_audio_map[] = { + {"VPMON ADC", NULL, "VP"}, + {"VBSTMON ADC", NULL, "VBST"}, + {"IMON ADC", NULL, "VSENSE"}, + {"VMON ADC", NULL, "VSENSE"}, + + {"ASPTX1SRC", "IMON", "IMON ADC"}, + {"ASPTX1SRC", "VMON", "VMON ADC"}, + {"ASPTX1SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX1SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX2SRC", "IMON", "IMON ADC"}, + {"ASPTX2SRC", "VMON", "VMON ADC"}, + {"ASPTX2SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX2SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX3SRC", "IMON", "IMON ADC"}, + {"ASPTX3SRC", "VMON", "VMON ADC"}, + {"ASPTX3SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX3SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX4SRC", "IMON", "IMON ADC"}, + {"ASPTX4SRC", "VMON", "VMON ADC"}, + {"ASPTX4SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX4SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX5SRC", "IMON", "IMON ADC"}, + {"ASPTX5SRC", "VMON", "VMON ADC"}, + {"ASPTX5SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX5SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX6SRC", "IMON", "IMON ADC"}, + {"ASPTX6SRC", "VMON", "VMON ADC"}, + {"ASPTX6SRC", "VBSTMON", "VBSTMON ADC"}, + {"ASPTX6SRC", "VPMON", "VPMON ADC"}, + + {"ASPTX1", NULL, "ASPTX1SRC"}, + {"ASPTX2", NULL, "ASPTX2SRC"}, + {"ASPTX3", NULL, "ASPTX3SRC"}, + {"ASPTX4", NULL, "ASPTX4SRC"}, + {"ASPTX5", NULL, "ASPTX5SRC"}, + {"ASPTX6", NULL, "ASPTX6SRC"}, + + {"AMP Capture", NULL, "ASPTX1"}, + {"AMP Capture", NULL, "ASPTX2"}, + {"AMP Capture", NULL, "ASPTX3"}, + {"AMP Capture", NULL, "ASPTX4"}, + {"AMP Capture", NULL, "ASPTX5"}, + {"AMP Capture", NULL, "ASPTX6"}, + + {"AMP Enable", "Switch", "AMP Playback"}, + {"SDIN", NULL, "AMP Enable"}, + {"Channel Mux", "RX1", "SDIN"}, + {"Channel Mux", "RX2", "SDIN"}, + {"BOOST Enable", "Switch", "Channel Mux"}, + {"CLASS H", NULL, "BOOST Enable"}, + {"Main AMP", NULL, "Channel Mux"}, + {"Main AMP", NULL, "CLASS H"}, + {"SPK", NULL, "Main AMP"}, +}; + +static int cs35l36_set_dai_fmt(struct snd_soc_dai *component_dai, + unsigned int fmt) +{ + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component_dai->component); + unsigned int asp_fmt, lrclk_fmt, sclk_fmt, slave_mode, clk_frc; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + slave_mode = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + slave_mode = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL, + CS35L36_SCLK_MSTR_MASK, + slave_mode << CS35L36_SCLK_MSTR_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RATE_CTRL, + CS35L36_LRCLK_MSTR_MASK, + slave_mode << CS35L36_LRCLK_MSTR_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: + clk_frc = 1; + break; + case SND_SOC_DAIFMT_GATED: + clk_frc = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL, + CS35L36_SCLK_FRC_MASK, clk_frc << + CS35L36_SCLK_FRC_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RATE_CTRL, + CS35L36_LRCLK_FRC_MASK, clk_frc << + CS35L36_LRCLK_FRC_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = 0; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = 2; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + lrclk_fmt = 1; + sclk_fmt = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + lrclk_fmt = 0; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + lrclk_fmt = 1; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_NB_NF: + lrclk_fmt = 0; + sclk_fmt = 0; + break; + default: + return -EINVAL; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_RATE_CTRL, + CS35L36_LRCLK_INV_MASK, + lrclk_fmt << CS35L36_LRCLK_INV_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL, + CS35L36_SCLK_INV_MASK, + sclk_fmt << CS35L36_SCLK_INV_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_FORMAT, + CS35L36_ASP_FMT_MASK, asp_fmt); + + return 0; +} + +struct cs35l36_global_fs_config { + int rate; + int fs_cfg; +}; + +static const struct cs35l36_global_fs_config cs35l36_fs_rates[] = { + {12000, 0x01}, + {24000, 0x02}, + {48000, 0x03}, + {96000, 0x04}, + {192000, 0x05}, + {384000, 0x06}, + {11025, 0x09}, + {22050, 0x0A}, + {44100, 0x0B}, + {88200, 0x0C}, + {176400, 0x0D}, + {8000, 0x11}, + {16000, 0x12}, + {32000, 0x13}, +}; + +static int cs35l36_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(dai->component); + unsigned int asp_width, global_fs = params_rate(params); + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l36_fs_rates); i++) { + if (global_fs == cs35l36_fs_rates[i].rate) + regmap_update_bits(cs35l36->regmap, + CS35L36_GLOBAL_CLK_CTRL, + CS35L36_GLOBAL_FS_MASK, + cs35l36_fs_rates[i].fs_cfg << + CS35L36_GLOBAL_FS_SHIFT); + } + + switch (params_width(params)) { + case 16: + asp_width = CS35L36_ASP_WIDTH_16; + break; + case 24: + asp_width = CS35L36_ASP_WIDTH_24; + break; + case 32: + asp_width = CS35L36_ASP_WIDTH_32; + break; + default: + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_FRAME_CTRL, + CS35L36_ASP_RX_WIDTH_MASK, + asp_width << CS35L36_ASP_RX_WIDTH_SHIFT); + } else { + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_FRAME_CTRL, + CS35L36_ASP_TX_WIDTH_MASK, + asp_width << CS35L36_ASP_TX_WIDTH_SHIFT); + } + + return 0; +} + +static int cs35l36_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + int fs1, fs2; + + if (freq > CS35L36_FS_NOM_6MHZ) { + fs1 = CS35L36_FS1_DEFAULT_VAL; + fs2 = CS35L36_FS2_DEFAULT_VAL; + } else { + fs1 = 3 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4; + fs2 = 5 * ((CS35L36_FS_NOM_6MHZ * 4 + freq - 1) / freq) + 4; + } + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK2); + + regmap_update_bits(cs35l36->regmap, CS35L36_TST_FS_MON0, + CS35L36_FS1_WINDOW_MASK | CS35L36_FS2_WINDOW_MASK, + fs1 | (fs2 << CS35L36_FS2_WINDOW_SHIFT)); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK2); + return 0; +} + +static const struct cs35l36_pll_config *cs35l36_get_clk_config( + struct cs35l36_private *cs35l36, int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l36_pll_sysclk); i++) { + if (cs35l36_pll_sysclk[i].freq == freq) + return &cs35l36_pll_sysclk[i]; + } + + return NULL; +} + +static const unsigned int cs35l36_src_rates[] = { + 8000, 12000, 11025, 16000, 22050, 24000, 32000, + 44100, 48000, 88200, 96000, 176400, 192000, 384000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l36_constraints = { + .count = ARRAY_SIZE(cs35l36_src_rates), + .list = cs35l36_src_rates, +}; + +static int cs35l36_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l36_constraints); + + return 0; +} + +static const struct snd_soc_dai_ops cs35l36_ops = { + .startup = cs35l36_pcm_startup, + .set_fmt = cs35l36_set_dai_fmt, + .hw_params = cs35l36_pcm_hw_params, + .set_sysclk = cs35l36_dai_set_sysclk, +}; + +static struct snd_soc_dai_driver cs35l36_dai[] = { + { + .name = "cs35l36-pcm", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L36_RX_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L36_TX_FORMATS, + }, + .ops = &cs35l36_ops, + .symmetric_rates = 1, + }, +}; + +static int cs35l36_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) +{ + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + const struct cs35l36_pll_config *clk_cfg; + int prev_clksrc; + bool pdm_switch; + + prev_clksrc = cs35l36->clksrc; + + switch (clk_id) { + case 0: + cs35l36->clksrc = CS35L36_PLLSRC_SCLK; + break; + case 1: + cs35l36->clksrc = CS35L36_PLLSRC_LRCLK; + break; + case 2: + cs35l36->clksrc = CS35L36_PLLSRC_PDMCLK; + break; + case 3: + cs35l36->clksrc = CS35L36_PLLSRC_SELF; + break; + case 4: + cs35l36->clksrc = CS35L36_PLLSRC_MCLK; + break; + default: + return -EINVAL; + } + + clk_cfg = cs35l36_get_clk_config(cs35l36, freq); + if (clk_cfg == NULL) { + dev_err(component->dev, "Invalid CLK Config Freq: %d\n", freq); + return -EINVAL; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_PLL_OPENLOOP_MASK, + 1 << CS35L36_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_REFCLK_FREQ_MASK, + clk_cfg->clk_cfg << CS35L36_REFCLK_FREQ_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_PLL_REFCLK_EN_MASK, + 0 << CS35L36_PLL_REFCLK_EN_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_PLL_CLK_SEL_MASK, + cs35l36->clksrc); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_PLL_OPENLOOP_MASK, + 0 << CS35L36_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_CLK_CTRL, + CS35L36_PLL_REFCLK_EN_MASK, + 1 << CS35L36_PLL_REFCLK_EN_SHIFT); + + if (cs35l36->rev_id == CS35L36_REV_A0) { + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK2); + + regmap_write(cs35l36->regmap, CS35L36_DCO_CTRL, 0x00036DA8); + regmap_write(cs35l36->regmap, CS35L36_MISC_CTRL, 0x0100EE0E); + + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_LOOP_PARAMS, + CS35L36_PLL_IGAIN_MASK, + CS35L36_PLL_IGAIN << + CS35L36_PLL_IGAIN_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_PLL_LOOP_PARAMS, + CS35L36_PLL_FFL_IGAIN_MASK, + clk_cfg->fll_igain); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK2); + } + + if (cs35l36->clksrc == CS35L36_PLLSRC_PDMCLK) { + pdm_switch = cs35l36->ldm_mode_sel && + (prev_clksrc != CS35L36_PLLSRC_PDMCLK); + + if (pdm_switch) + regmap_update_bits(cs35l36->regmap, CS35L36_NG_CFG, + CS35L36_NG_DELAY_MASK, + 0 << CS35L36_NG_DELAY_SHIFT); + + regmap_update_bits(cs35l36->regmap, CS35L36_DAC_MSM_CFG, + CS35L36_PDM_MODE_MASK, + 1 << CS35L36_PDM_MODE_SHIFT); + + if (pdm_switch) + regmap_update_bits(cs35l36->regmap, CS35L36_NG_CFG, + CS35L36_NG_DELAY_MASK, + 3 << CS35L36_NG_DELAY_SHIFT); + } else { + pdm_switch = cs35l36->ldm_mode_sel && + (prev_clksrc == CS35L36_PLLSRC_PDMCLK); + + if (pdm_switch) + regmap_update_bits(cs35l36->regmap, CS35L36_NG_CFG, + CS35L36_NG_DELAY_MASK, + 0 << CS35L36_NG_DELAY_SHIFT); + + regmap_update_bits(cs35l36->regmap, CS35L36_DAC_MSM_CFG, + CS35L36_PDM_MODE_MASK, + 0 << CS35L36_PDM_MODE_SHIFT); + + if (pdm_switch) + regmap_update_bits(cs35l36->regmap, CS35L36_NG_CFG, + CS35L36_NG_DELAY_MASK, + 3 << CS35L36_NG_DELAY_SHIFT); + } + + return 0; +} + +static int cs35l36_boost_inductor(struct cs35l36_private *cs35l36, int inductor) +{ + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_COEFF, + CS35L36_BSTCVRT_K1_MASK, 0x3C); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_COEFF, + CS35L36_BSTCVRT_K2_MASK, + 0x3C << CS35L36_BSTCVRT_K2_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_SW_FREQ, + CS35L36_BSTCVRT_CCMFREQ_MASK, 0x00); + + switch (inductor) { + case 1000: /* 1 uH */ + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_SLOPE_LBST, + CS35L36_BSTCVRT_SLOPE_MASK, + 0x75 << CS35L36_BSTCVRT_SLOPE_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_SLOPE_LBST, + CS35L36_BSTCVRT_LBSTVAL_MASK, 0x00); + break; + case 1200: /* 1.2 uH */ + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_SLOPE_LBST, + CS35L36_BSTCVRT_SLOPE_MASK, + 0x6B << CS35L36_BSTCVRT_SLOPE_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_SLOPE_LBST, + CS35L36_BSTCVRT_LBSTVAL_MASK, 0x01); + break; + default: + dev_err(cs35l36->dev, "%s Invalid Inductor Value %d uH\n", + __func__, inductor); + return -EINVAL; + } + + return 0; +} + +static int cs35l36_component_probe(struct snd_soc_component *component) +{ + struct cs35l36_private *cs35l36 = + snd_soc_component_get_drvdata(component); + int ret = 0; + + if ((cs35l36->rev_id == CS35L36_REV_A0) && cs35l36->pdata.dcm_mode) { + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_DCM_CTRL, + CS35L36_DCM_AUTO_MASK, + CS35L36_DCM_AUTO_MASK); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK2); + + regmap_update_bits(cs35l36->regmap, CS35L36_BST_TST_MANUAL, + CS35L36_BST_MAN_IPKCOMP_MASK, + 0 << CS35L36_BST_MAN_IPKCOMP_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BST_TST_MANUAL, + CS35L36_BST_MAN_IPKCOMP_EN_MASK, + CS35L36_BST_MAN_IPKCOMP_EN_MASK); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK2); + } + + if (cs35l36->pdata.amp_pcm_inv) + regmap_update_bits(cs35l36->regmap, CS35L36_AMP_DIG_VOL_CTRL, + CS35L36_AMP_PCM_INV_MASK, + CS35L36_AMP_PCM_INV_MASK); + + if (cs35l36->pdata.multi_amp_mode) + regmap_update_bits(cs35l36->regmap, CS35L36_ASP_TX_PIN_CTRL, + CS35L36_ASP_TX_HIZ_MASK, + CS35L36_ASP_TX_HIZ_MASK); + + if (cs35l36->pdata.imon_pol_inv) + regmap_update_bits(cs35l36->regmap, CS35L36_VI_SPKMON_FILT, + CS35L36_IMON_POL_MASK, 0); + + if (cs35l36->pdata.vmon_pol_inv) + regmap_update_bits(cs35l36->regmap, CS35L36_VI_SPKMON_FILT, + CS35L36_VMON_POL_MASK, 0); + + if (cs35l36->pdata.bst_vctl) + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL1, + CS35L35_BSTCVRT_CTL_MASK, + cs35l36->pdata.bst_vctl); + + if (cs35l36->pdata.bst_vctl_sel) + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL2, + CS35L35_BSTCVRT_CTL_SEL_MASK, + cs35l36->pdata.bst_vctl_sel); + + if (cs35l36->pdata.bst_ipk) + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_PEAK_CUR, + CS35L36_BST_IPK_MASK, + cs35l36->pdata.bst_ipk); + + if (cs35l36->pdata.boost_ind) { + ret = cs35l36_boost_inductor(cs35l36, cs35l36->pdata.boost_ind); + if (ret < 0) { + dev_err(cs35l36->dev, + "Boost inductor config failed(%d)\n", ret); + return ret; + } + } + + if (cs35l36->pdata.temp_warn_thld) + regmap_update_bits(cs35l36->regmap, CS35L36_DTEMP_WARN_THLD, + CS35L36_TEMP_THLD_MASK, + cs35l36->pdata.temp_warn_thld); + + if (cs35l36->pdata.irq_drv_sel) + regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE, + CS35L36_INT_DRV_SEL_MASK, + cs35l36->pdata.irq_drv_sel << + CS35L36_INT_DRV_SEL_SHIFT); + + if (cs35l36->pdata.irq_gpio_sel) + regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE, + CS35L36_INT_GPIO_SEL_MASK, + cs35l36->pdata.irq_gpio_sel << + CS35L36_INT_GPIO_SEL_SHIFT); + + /* + * Rev B0 has 2 versions + * L36 is 10V + * L37 is 12V + * If L36 we need to clamp some values for safety + * after probe has setup dt values. We want to make + * sure we dont miss any values set in probe + */ + if (cs35l36->chip_version == CS35L36_10V_L36) { + regmap_update_bits(cs35l36->regmap, + CS35L36_BSTCVRT_OVERVOLT_CTRL, + CS35L36_BST_OVP_THLD_MASK, + CS35L36_BST_OVP_THLD_11V); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK2); + + regmap_update_bits(cs35l36->regmap, CS35L36_BST_ANA2_TEST, + CS35L36_BST_OVP_TRIM_MASK, + CS35L36_BST_OVP_TRIM_11V << + CS35L36_BST_OVP_TRIM_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL2, + CS35L36_BST_CTRL_LIM_MASK, + 1 << CS35L36_BST_CTRL_LIM_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_BSTCVRT_VCTRL1, + CS35L35_BSTCVRT_CTL_MASK, + CS35L36_BST_CTRL_10V_CLAMP); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK2); + } + + /* + * RevA and B require the disabling of + * SYNC_GLOBAL_OVR when GLOBAL_EN = 0. + * Just turn it off from default + */ + regmap_update_bits(cs35l36->regmap, CS35L36_CTRL_OVRRIDE, + CS35L36_SYNC_GLOBAL_OVR_MASK, + 0 << CS35L36_SYNC_GLOBAL_OVR_SHIFT); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_cs35l36 = { + .probe = &cs35l36_component_probe, + .set_sysclk = cs35l36_component_set_sysclk, + .dapm_widgets = cs35l36_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l36_dapm_widgets), + .dapm_routes = cs35l36_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l36_audio_map), + .controls = cs35l36_aud_controls, + .num_controls = ARRAY_SIZE(cs35l36_aud_controls), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static struct regmap_config cs35l36_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = CS35L36_PAC_PMEM_WORD1023, + .reg_defaults = cs35l36_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l36_reg), + .precious_reg = cs35l36_precious_reg, + .volatile_reg = cs35l36_volatile_reg, + .readable_reg = cs35l36_readable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static irqreturn_t cs35l36_irq(int irq, void *data) +{ + struct cs35l36_private *cs35l36 = data; + unsigned int status[4]; + unsigned int masks[4]; + int ret = IRQ_NONE; + + /* ack the irq by reading all status registers */ + regmap_bulk_read(cs35l36->regmap, CS35L36_INT1_STATUS, status, + ARRAY_SIZE(status)); + + regmap_bulk_read(cs35l36->regmap, CS35L36_INT1_MASK, masks, + ARRAY_SIZE(masks)); + + /* Check to see if unmasked bits are active */ + if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) && + !(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) { + return IRQ_NONE; + } + + /* + * The following interrupts require a + * protection release cycle to get the + * speaker out of Safe-Mode. + */ + if (status[2] & CS35L36_AMP_SHORT_ERR) { + dev_crit(cs35l36->dev, "Amp short error\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_AMP_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_AMP_SHORT_ERR_RLS, + CS35L36_AMP_SHORT_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_AMP_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT3_STATUS, + CS35L36_AMP_SHORT_ERR, + CS35L36_AMP_SHORT_ERR); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L36_TEMP_WARN) { + dev_crit(cs35l36->dev, "Over temperature warning\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_WARN_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_WARN_ERR_RLS, + CS35L36_TEMP_WARN_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_WARN_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS, + CS35L36_TEMP_WARN, CS35L36_TEMP_WARN); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L36_TEMP_ERR) { + dev_crit(cs35l36->dev, "Over temperature error\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, CS35L36_TEMP_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS, + CS35L36_TEMP_ERR, CS35L36_TEMP_ERR); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L36_BST_OVP_ERR) { + dev_crit(cs35l36->dev, "VBST Over Voltage error\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, CS35L36_TEMP_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_TEMP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS, + CS35L36_BST_OVP_ERR, CS35L36_BST_OVP_ERR); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L36_BST_DCM_UVP_ERR) { + dev_crit(cs35l36->dev, "DCM VBST Under Voltage Error\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_UVP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_UVP_ERR_RLS, + CS35L36_BST_UVP_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_UVP_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS, + CS35L36_BST_DCM_UVP_ERR, + CS35L36_BST_DCM_UVP_ERR); + ret = IRQ_HANDLED; + } + + if (status[0] & CS35L36_BST_SHORT_ERR) { + dev_crit(cs35l36->dev, "LBST SHORT error!\n"); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_SHORT_ERR_RLS, + CS35L36_BST_SHORT_ERR_RLS); + regmap_update_bits(cs35l36->regmap, CS35L36_PROTECT_REL_ERR, + CS35L36_BST_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l36->regmap, CS35L36_INT1_STATUS, + CS35L36_BST_SHORT_ERR, + CS35L36_BST_SHORT_ERR); + ret = IRQ_HANDLED; + } + + return ret; +} + +static int cs35l36_handle_of_data(struct i2c_client *i2c_client, + struct cs35l36_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + struct cs35l36_vpbr_cfg *vpbr_config = &pdata->vpbr_config; + struct device_node *vpbr_node; + unsigned int val; + int ret; + + if (!np) + return 0; + + ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val); + if (!ret) { + if (val < 2550 || val > 12000) { + dev_err(&i2c_client->dev, + "Invalid Boost Voltage %d mV\n", val); + return -EINVAL; + } + pdata->bst_vctl = (((val - 2550) / 100) + 1) << 1; + } else { + dev_err(&i2c_client->dev, + "Unable to find required parameter 'cirrus,boost-ctl-millivolt'"); + return -EINVAL; + } + + ret = of_property_read_u32(np, "cirrus,boost-ctl-select", &val); + if (!ret) + pdata->bst_vctl_sel = val | CS35L36_VALID_PDATA; + + ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val); + if (!ret) { + if (val < 1600 || val > 4500) { + dev_err(&i2c_client->dev, + "Invalid Boost Peak Current %u mA\n", val); + return -EINVAL; + } + + pdata->bst_ipk = (val - 1600) / 50; + } else { + dev_err(&i2c_client->dev, + "Unable to find required parameter 'cirrus,boost-peak-milliamp'"); + return -EINVAL; + } + + pdata->multi_amp_mode = of_property_read_bool(np, + "cirrus,multi-amp-mode"); + + pdata->dcm_mode = of_property_read_bool(np, + "cirrus,dcm-mode-enable"); + + pdata->amp_pcm_inv = of_property_read_bool(np, + "cirrus,amp-pcm-inv"); + + pdata->imon_pol_inv = of_property_read_bool(np, + "cirrus,imon-pol-inv"); + + pdata->vmon_pol_inv = of_property_read_bool(np, + "cirrus,vmon-pol-inv"); + + if (of_property_read_u32(np, "cirrus,temp-warn-threshold", &val) >= 0) + pdata->temp_warn_thld = val | CS35L36_VALID_PDATA; + + if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) { + pdata->boost_ind = val; + } else { + dev_err(&i2c_client->dev, "Inductor not specified.\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "cirrus,irq-drive-select", &val) >= 0) + pdata->irq_drv_sel = val | CS35L36_VALID_PDATA; + + if (of_property_read_u32(np, "cirrus,irq-gpio-select", &val) >= 0) + pdata->irq_gpio_sel = val | CS35L36_VALID_PDATA; + + /* VPBR Config */ + vpbr_node = of_get_child_by_name(np, "cirrus,vpbr-config"); + vpbr_config->is_present = vpbr_node ? true : false; + if (vpbr_config->is_present) { + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-en", + &val) >= 0) + vpbr_config->vpbr_en = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-thld", + &val) >= 0) + vpbr_config->vpbr_thld = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-atk-rate", + &val) >= 0) + vpbr_config->vpbr_atk_rate = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-atk-vol", + &val) >= 0) + vpbr_config->vpbr_atk_vol = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-max-attn", + &val) >= 0) + vpbr_config->vpbr_max_attn = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-wait", + &val) >= 0) + vpbr_config->vpbr_wait = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-rel-rate", + &val) >= 0) + vpbr_config->vpbr_rel_rate = val; + if (of_property_read_u32(vpbr_node, "cirrus,vpbr-mute-en", + &val) >= 0) + vpbr_config->vpbr_mute_en = val; + } + of_node_put(vpbr_node); + + return 0; +} + +static int cs35l36_pac(struct cs35l36_private *cs35l36) +{ + int ret, count; + unsigned int val; + + if (cs35l36->rev_id != CS35L36_REV_B0) + return 0; + + /* + * Magic code for internal PAC + */ + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_UNLOCK2); + + usleep_range(9500, 10500); + + regmap_write(cs35l36->regmap, CS35L36_PAC_CTL1, + CS35L36_PAC_RESET); + regmap_write(cs35l36->regmap, CS35L36_PAC_CTL3, + CS35L36_PAC_MEM_ACCESS); + regmap_write(cs35l36->regmap, CS35L36_PAC_PMEM_WORD0, + CS35L36_B0_PAC_PATCH); + + regmap_write(cs35l36->regmap, CS35L36_PAC_CTL3, + CS35L36_PAC_MEM_ACCESS_CLR); + regmap_write(cs35l36->regmap, CS35L36_PAC_CTL1, + CS35L36_PAC_ENABLE_MASK); + + usleep_range(9500, 10500); + + ret = regmap_read(cs35l36->regmap, CS35L36_INT4_STATUS, &val); + if (ret < 0) { + dev_err(cs35l36->dev, "Failed to read int4_status %d\n", ret); + return ret; + } + + count = 0; + while (!(val & CS35L36_MCU_CONFIG_CLR)) { + usleep_range(100, 200); + count++; + + ret = regmap_read(cs35l36->regmap, CS35L36_INT4_STATUS, + &val); + if (ret < 0) { + dev_err(cs35l36->dev, "Failed to read int4_status %d\n", + ret); + return ret; + } + + if (count >= 100) + return -EINVAL; + } + + regmap_write(cs35l36->regmap, CS35L36_INT4_STATUS, + CS35L36_MCU_CONFIG_CLR); + regmap_update_bits(cs35l36->regmap, CS35L36_PAC_CTL1, + CS35L36_PAC_ENABLE_MASK, 0); + + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK1); + regmap_write(cs35l36->regmap, CS35L36_TESTKEY_CTRL, + CS35L36_TEST_LOCK2); + + return 0; +} + +static void cs35l36_apply_vpbr_config(struct cs35l36_private *cs35l36) +{ + struct cs35l36_platform_data *pdata = &cs35l36->pdata; + struct cs35l36_vpbr_cfg *vpbr_config = &pdata->vpbr_config; + + regmap_update_bits(cs35l36->regmap, CS35L36_PWR_CTRL3, + CS35L36_VPBR_EN_MASK, + vpbr_config->vpbr_en << + CS35L36_VPBR_EN_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_THLD_MASK, + vpbr_config->vpbr_thld << + CS35L36_VPBR_THLD_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_MAX_ATTN_MASK, + vpbr_config->vpbr_max_attn << + CS35L36_VPBR_MAX_ATTN_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_ATK_VOL_MASK, + vpbr_config->vpbr_atk_vol << + CS35L36_VPBR_ATK_VOL_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_ATK_RATE_MASK, + vpbr_config->vpbr_atk_rate << + CS35L36_VPBR_ATK_RATE_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_WAIT_MASK, + vpbr_config->vpbr_wait << + CS35L36_VPBR_WAIT_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_REL_RATE_MASK, + vpbr_config->vpbr_rel_rate << + CS35L36_VPBR_REL_RATE_SHIFT); + regmap_update_bits(cs35l36->regmap, CS35L36_VPBR_CFG, + CS35L36_VPBR_MUTE_EN_MASK, + vpbr_config->vpbr_mute_en << + CS35L36_VPBR_MUTE_EN_SHIFT); +} + +static const struct reg_sequence cs35l36_reva0_errata_patch[] = { + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_UNLOCK1 }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_UNLOCK2 }, + /* Errata Writes */ + { CS35L36_OTP_CTRL1, 0x00002060 }, + { CS35L36_OTP_CTRL2, 0x00000001 }, + { CS35L36_OTP_CTRL1, 0x00002460 }, + { CS35L36_OTP_CTRL2, 0x00000001 }, + { 0x00002088, 0x012A1838 }, + { 0x00003014, 0x0100EE0E }, + { 0x00003008, 0x0008184A }, + { 0x00007418, 0x509001C8 }, + { 0x00007064, 0x0929A800 }, + { 0x00002D10, 0x0002C01C }, + { 0x0000410C, 0x00000A11 }, + { 0x00006E08, 0x8B19140C }, + { 0x00006454, 0x0300000A }, + { CS35L36_AMP_NG_CTRL, 0x000020EF }, + { 0x00007E34, 0x0000000E }, + { 0x0000410C, 0x00000A11 }, + { 0x00007410, 0x20514B00 }, + /* PAC Config */ + { CS35L36_CTRL_OVRRIDE, 0x00000000 }, + { CS35L36_PAC_INT0_CTRL, 0x00860001 }, + { CS35L36_PAC_INT1_CTRL, 0x00860001 }, + { CS35L36_PAC_INT2_CTRL, 0x00860001 }, + { CS35L36_PAC_INT3_CTRL, 0x00860001 }, + { CS35L36_PAC_INT4_CTRL, 0x00860001 }, + { CS35L36_PAC_INT5_CTRL, 0x00860001 }, + { CS35L36_PAC_INT6_CTRL, 0x00860001 }, + { CS35L36_PAC_INT7_CTRL, 0x00860001 }, + { CS35L36_PAC_INT_FLUSH_CTRL, 0x000000FF }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK1 }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK2 }, +}; + +static const struct reg_sequence cs35l36_revb0_errata_patch[] = { + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_UNLOCK1 }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_UNLOCK2 }, + { 0x00007064, 0x0929A800 }, + { 0x00007850, 0x00002FA9 }, + { 0x00007854, 0x0003F1D5 }, + { 0x00007858, 0x0003F5E3 }, + { 0x0000785C, 0x00001137 }, + { 0x00007860, 0x0001A7A5 }, + { 0x00007864, 0x0002F16A }, + { 0x00007868, 0x00003E21 }, + { 0x00007848, 0x00000001 }, + { 0x00003854, 0x05180240 }, + { 0x00007418, 0x509001C8 }, + { 0x0000394C, 0x028764BD }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK1 }, + { CS35L36_TESTKEY_CTRL, CS35L36_TEST_LOCK2 }, +}; + +static int cs35l36_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l36_private *cs35l36; + struct device *dev = &i2c_client->dev; + struct cs35l36_platform_data *pdata = dev_get_platdata(dev); + struct irq_data *irq_d; + int ret, irq_pol, chip_irq_pol, i; + u32 reg_id, reg_revid, l37_id_reg; + + cs35l36 = devm_kzalloc(dev, sizeof(struct cs35l36_private), GFP_KERNEL); + if (!cs35l36) + return -ENOMEM; + + cs35l36->dev = dev; + + i2c_set_clientdata(i2c_client, cs35l36); + cs35l36->regmap = devm_regmap_init_i2c(i2c_client, &cs35l36_regmap); + if (IS_ERR(cs35l36->regmap)) { + ret = PTR_ERR(cs35l36->regmap); + dev_err(dev, "regmap_init() failed: %d\n", ret); + goto err; + } + + cs35l36->num_supplies = ARRAY_SIZE(cs35l36_supplies); + for (i = 0; i < ARRAY_SIZE(cs35l36_supplies); i++) + cs35l36->supplies[i].supply = cs35l36_supplies[i]; + + ret = devm_regulator_bulk_get(dev, cs35l36->num_supplies, + cs35l36->supplies); + if (ret != 0) { + dev_err(dev, "Failed to request core supplies: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l36->pdata = *pdata; + } else { + pdata = devm_kzalloc(dev, sizeof(struct cs35l36_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (i2c_client->dev.of_node) { + ret = cs35l36_handle_of_data(i2c_client, pdata); + if (ret != 0) + return ret; + + } + + cs35l36->pdata = *pdata; + } + + ret = regulator_bulk_enable(cs35l36->num_supplies, cs35l36->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable core supplies: %d\n", ret); + return ret; + } + + /* returning NULL can be an option if in stereo mode */ + cs35l36->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(cs35l36->reset_gpio)) { + ret = PTR_ERR(cs35l36->reset_gpio); + cs35l36->reset_gpio = NULL; + if (ret == -EBUSY) { + dev_info(dev, "Reset line busy, assuming shared reset\n"); + } else { + dev_err(dev, "Failed to get reset GPIO: %d\n", ret); + goto err_disable_regs; + } + } + + if (cs35l36->reset_gpio) + gpiod_set_value_cansleep(cs35l36->reset_gpio, 1); + + usleep_range(2000, 2100); + + /* initialize amplifier */ + ret = regmap_read(cs35l36->regmap, CS35L36_SW_RESET, ®_id); + if (ret < 0) { + dev_err(dev, "Get Device ID failed %d\n", ret); + goto err; + } + + if (reg_id != CS35L36_CHIP_ID) { + dev_err(dev, "Device ID (%X). Expected ID %X\n", reg_id, + CS35L36_CHIP_ID); + ret = -ENODEV; + goto err; + } + + ret = regmap_read(cs35l36->regmap, CS35L36_REV_ID, ®_revid); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed %d\n", ret); + goto err; + } + + cs35l36->rev_id = reg_revid >> 8; + + ret = regmap_read(cs35l36->regmap, CS35L36_OTP_MEM30, &l37_id_reg); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to read otp_id Register %d\n", + ret); + return ret; + } + + if ((l37_id_reg & CS35L36_OTP_REV_MASK) == CS35L36_OTP_REV_L37) + cs35l36->chip_version = CS35L36_12V_L37; + else + cs35l36->chip_version = CS35L36_10V_L36; + + switch (cs35l36->rev_id) { + case CS35L36_REV_A0: + ret = regmap_register_patch(cs35l36->regmap, + cs35l36_reva0_errata_patch, + ARRAY_SIZE(cs35l36_reva0_errata_patch)); + if (ret < 0) { + dev_err(dev, "Failed to apply A0 errata patch %d\n", + ret); + goto err; + } + break; + case CS35L36_REV_B0: + ret = cs35l36_pac(cs35l36); + if (ret < 0) { + dev_err(dev, "Failed to Trim OTP %d\n", ret); + goto err; + } + + ret = regmap_register_patch(cs35l36->regmap, + cs35l36_revb0_errata_patch, + ARRAY_SIZE(cs35l36_revb0_errata_patch)); + if (ret < 0) { + dev_err(dev, "Failed to apply B0 errata patch %d\n", + ret); + goto err; + } + break; + } + + if (pdata->vpbr_config.is_present) + cs35l36_apply_vpbr_config(cs35l36); + + irq_d = irq_get_irq_data(i2c_client->irq); + if (IS_ERR(irq_d)) { + dev_err(&i2c_client->dev, "Invalid IRQ: %d\n", i2c_client->irq); + ret = PTR_ERR(irq_d); + goto err; + } + + irq_pol = irqd_get_trigger_type(irq_d); + + switch (irq_pol) { + case IRQF_TRIGGER_FALLING: + case IRQF_TRIGGER_LOW: + chip_irq_pol = 0; + break; + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + chip_irq_pol = 1; + break; + default: + dev_err(cs35l36->dev, "Invalid IRQ polarity: %d\n", irq_pol); + ret = -EINVAL; + goto err; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE, + CS35L36_INT_POL_SEL_MASK, + chip_irq_pol << CS35L36_INT_POL_SEL_SHIFT); + + ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l36_irq, + IRQF_ONESHOT | irq_pol, "cs35l36", + cs35l36); + if (ret != 0) { + dev_err(dev, "Failed to request IRQ: %d\n", ret); + goto err; + } + + regmap_update_bits(cs35l36->regmap, CS35L36_PAD_INTERFACE, + CS35L36_INT_OUTPUT_EN_MASK, 1); + + /* Set interrupt masks for critical errors */ + regmap_write(cs35l36->regmap, CS35L36_INT1_MASK, + CS35L36_INT1_MASK_DEFAULT); + regmap_write(cs35l36->regmap, CS35L36_INT3_MASK, + CS35L36_INT3_MASK_DEFAULT); + + dev_info(&i2c_client->dev, "Cirrus Logic CS35L%d, Revision: %02X\n", + cs35l36->chip_version, reg_revid >> 8); + + ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs35l36, + cs35l36_dai, + ARRAY_SIZE(cs35l36_dai)); + if (ret < 0) { + dev_err(dev, "%s: Register component failed %d\n", __func__, + ret); + goto err; + } + + return 0; + +err: + gpiod_set_value_cansleep(cs35l36->reset_gpio, 0); + +err_disable_regs: + regulator_bulk_disable(cs35l36->num_supplies, cs35l36->supplies); + return ret; +} + +static int cs35l36_i2c_remove(struct i2c_client *client) +{ + struct cs35l36_private *cs35l36 = i2c_get_clientdata(client); + + /* Reset interrupt masks for device removal */ + regmap_write(cs35l36->regmap, CS35L36_INT1_MASK, + CS35L36_INT1_MASK_RESET); + regmap_write(cs35l36->regmap, CS35L36_INT3_MASK, + CS35L36_INT3_MASK_RESET); + + if (cs35l36->reset_gpio) + gpiod_set_value_cansleep(cs35l36->reset_gpio, 0); + + regulator_bulk_disable(cs35l36->num_supplies, cs35l36->supplies); + + return 0; +} +static const struct of_device_id cs35l36_of_match[] = { + {.compatible = "cirrus,cs35l36"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l36_of_match); + +static const struct i2c_device_id cs35l36_id[] = { + {"cs35l36", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l36_id); + +static struct i2c_driver cs35l36_i2c_driver = { + .driver = { + .name = "cs35l36", + .of_match_table = cs35l36_of_match, + }, + .id_table = cs35l36_id, + .probe = cs35l36_i2c_probe, + .remove = cs35l36_i2c_remove, +}; +module_i2c_driver(cs35l36_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS35L36 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l36.h b/sound/soc/codecs/cs35l36.h new file mode 100644 index 000000000000..f6e38c633b93 --- /dev/null +++ b/sound/soc/codecs/cs35l36.h @@ -0,0 +1,446 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * cs35l36.h -- CS35L36 ALSA SoC audio driver + * + * Copyright 2018 Cirrus Logic, Inc. + * + * Author: James Schulman + * + */ + +#ifndef __CS35L36_H__ +#define __CS35L36_H__ + +#include + +#define CS35L36_FIRSTREG 0x00000000 +#define CS35L36_LASTREG 0x00E037FC +#define CS35L36_SW_RESET 0x00000000 +#define CS35L36_SW_REV 0x00000004 +#define CS35L36_HW_REV 0x00000008 +#define CS35L36_TESTKEY_CTRL 0x00000020 +#define CS35L36_USERKEY_CTL 0x00000024 +#define CS35L36_OTP_MEM30 0x00000478 +#define CS35L36_OTP_CTRL1 0x00000500 +#define CS35L36_OTP_CTRL2 0x00000504 +#define CS35L36_OTP_CTRL3 0x00000508 +#define CS35L36_OTP_CTRL4 0x0000050C +#define CS35L36_OTP_CTRL5 0x00000510 +#define CS35L36_PAC_CTL1 0x00000C00 +#define CS35L36_PAC_CTL2 0x00000C04 +#define CS35L36_PAC_CTL3 0x00000C08 +#define CS35L36_DEVICE_ID 0x00002004 +#define CS35L36_FAB_ID 0x00002008 +#define CS35L36_REV_ID 0x0000200C +#define CS35L36_PWR_CTRL1 0x00002014 +#define CS35L36_PWR_CTRL2 0x00002018 +#define CS35L36_PWR_CTRL3 0x0000201C +#define CS35L36_CTRL_OVRRIDE 0x00002020 +#define CS35L36_AMP_OUT_MUTE 0x00002024 +#define CS35L36_OTP_TRIM_STATUS 0x00002028 +#define CS35L36_DISCH_FILT 0x0000202C +#define CS35L36_OSC_TRIM 0x00002030 +#define CS35L36_PROTECT_REL_ERR 0x00002034 +#define CS35L36_PAD_INTERFACE 0x00002400 +#define CS35L36_PLL_CLK_CTRL 0x00002C04 +#define CS35L36_GLOBAL_CLK_CTRL 0x00002C0C +#define CS35L36_ADC_CLK_CTRL 0x00002C10 +#define CS35L36_SWIRE_CLK_CTRL 0x00002C14 +#define CS35L36_SP_SCLK_CLK_CTRL 0x00002D00 +#define CS35L36_TST_FS_MON0 0x00002D10 +#define CS35L36_PLL_LOOP_PARAMS 0x00003008 +#define CS35L36_DCO_CTRL 0x00003010 +#define CS35L36_MISC_CTRL 0x00003014 +#define CS35L36_MDSYNC_EN 0x00003404 +#define CS35L36_MDSYNC_TX_ID 0x00003408 +#define CS35L36_MDSYNC_PWR_CTRL 0x0000340C +#define CS35L36_MDSYNC_DATA_TX 0x00003410 +#define CS35L36_MDSYNC_TX_STATUS 0x0000341C +#define CS35L36_MDSYNC_RX_STATUS 0x00003420 +#define CS35L36_MDSYNC_ERR_STATUS 0x00003424 +#define CS35L36_BSTCVRT_VCTRL1 0x00003800 +#define CS35L36_BSTCVRT_VCTRL2 0x00003804 +#define CS35L36_BSTCVRT_PEAK_CUR 0x00003808 +#define CS35L36_BSTCVRT_SFT_RAMP 0x0000380C +#define CS35L36_BSTCVRT_COEFF 0x00003810 +#define CS35L36_BSTCVRT_SLOPE_LBST 0x00003814 +#define CS35L36_BSTCVRT_SW_FREQ 0x00003818 +#define CS35L36_BSTCVRT_DCM_CTRL 0x0000381C +#define CS35L36_BSTCVRT_DCM_MODE_FORCE 0x00003820 +#define CS35L36_BSTCVRT_OVERVOLT_CTRL 0x00003830 +#define CS35L36_BST_TST_MANUAL 0x0000393C +#define CS35L36_BST_ANA2_TEST 0x0000394C +#define CS35L36_VPI_LIMIT_MODE 0x00003C04 +#define CS35L36_VPI_LIMIT_MINMAX 0x00003C08 +#define CS35L36_VPI_VP_THLD 0x00003C0C +#define CS35L36_VPI_TRACK_CTRL 0x00003C10 +#define CS35L36_VPI_TRIG_MODE_CTRL 0x00003C14 +#define CS35L36_VPI_TRIG_STEPS 0x00003C18 +#define CS35L36_VI_SPKMON_FILT 0x00004004 +#define CS35L36_VI_SPKMON_GAIN 0x00004008 +#define CS35L36_VI_SPKMON_IP_SEL 0x00004100 +#define CS35L36_DTEMP_WARN_THLD 0x00004220 +#define CS35L36_DTEMP_STATUS 0x00004300 +#define CS35L36_VPVBST_FS_SEL 0x00004400 +#define CS35L36_VPVBST_VP_CTRL 0x00004440 +#define CS35L36_VPVBST_VBST_CTRL 0x00004444 +#define CS35L36_ASP_TX_PIN_CTRL 0x00004800 +#define CS35L36_ASP_RATE_CTRL 0x00004804 +#define CS35L36_ASP_FORMAT 0x00004808 +#define CS35L36_ASP_FRAME_CTRL 0x00004818 +#define CS35L36_ASP_TX1_TX2_SLOT 0x0000481C +#define CS35L36_ASP_TX3_TX4_SLOT 0x00004820 +#define CS35L36_ASP_TX5_TX6_SLOT 0x00004824 +#define CS35L36_ASP_TX7_TX8_SLOT 0x00004828 +#define CS35L36_ASP_RX1_SLOT 0x0000482C +#define CS35L36_ASP_RX_TX_EN 0x0000483C +#define CS35L36_ASP_RX1_SEL 0x00004C00 +#define CS35L36_ASP_TX1_SEL 0x00004C20 +#define CS35L36_ASP_TX2_SEL 0x00004C24 +#define CS35L36_ASP_TX3_SEL 0x00004C28 +#define CS35L36_ASP_TX4_SEL 0x00004C2C +#define CS35L36_ASP_TX5_SEL 0x00004C30 +#define CS35L36_ASP_TX6_SEL 0x00004C34 +#define CS35L36_SWIRE_P1_TX1_SEL 0x00004C40 +#define CS35L36_SWIRE_P1_TX2_SEL 0x00004C44 +#define CS35L36_SWIRE_P2_TX1_SEL 0x00004C60 +#define CS35L36_SWIRE_P2_TX2_SEL 0x00004C64 +#define CS35L36_SWIRE_P2_TX3_SEL 0x00004C68 +#define CS35L36_SWIRE_DP1_FIFO_CFG 0x00005000 +#define CS35L36_SWIRE_DP2_FIFO_CFG 0x00005004 +#define CS35L36_SWIRE_DP3_FIFO_CFG 0x00005008 +#define CS35L36_SWIRE_PCM_RX_DATA 0x0000500C +#define CS35L36_SWIRE_FS_SEL 0x00005010 +#define CS35L36_SPARE_CP_BITS 0x00005C00 +#define CS35L36_AMP_DIG_VOL_CTRL 0x00006000 +#define CS35L36_VPBR_CFG 0x00006404 +#define CS35L36_VBBR_CFG 0x00006408 +#define CS35L36_VPBR_STATUS 0x0000640C +#define CS35L36_VBBR_STATUS 0x00006410 +#define CS35L36_OVERTEMP_CFG 0x00006414 +#define CS35L36_AMP_ERR_VOL 0x00006418 +#define CS35L36_CLASSH_CFG 0x00006800 +#define CS35L36_CLASSH_FET_DRV_CFG 0x00006804 +#define CS35L36_NG_CFG 0x00006808 +#define CS35L36_AMP_GAIN_CTRL 0x00006C04 +#define CS35L36_PWM_MOD_IO_CTRL 0x0000706C +#define CS35L36_PWM_MOD_STATUS 0x00007070 +#define CS35L36_DAC_MSM_CFG 0x00007400 +#define CS35L36_AMP_SLOPE_CTRL 0x00007410 +#define CS35L36_AMP_PDM_VOLUME 0x00007E04 +#define CS35L36_AMP_PDM_RATE_CTRL 0x00007E08 +#define CS35L36_PDM_CH_SEL 0x00007E10 +#define CS35L36_AMP_NG_CTRL 0x00007E14 +#define CS35L36_PDM_HIGHFILT_CTRL 0x00007E3C +#define CS35L36_INT1_STATUS 0x00D00000 +#define CS35L36_INT2_STATUS 0x00D00004 +#define CS35L36_INT3_STATUS 0x00D00008 +#define CS35L36_INT4_STATUS 0x00D0000C +#define CS35L36_INT1_RAW_STATUS 0x00D00020 +#define CS35L36_INT2_RAW_STATUS 0x00D00024 +#define CS35L36_INT3_RAW_STATUS 0x00D00028 +#define CS35L36_INT4_RAW_STATUS 0x00D0002C +#define CS35L36_INT1_MASK 0x00D00040 +#define CS35L36_INT2_MASK 0x00D00044 +#define CS35L36_INT3_MASK 0x00D00048 +#define CS35L36_INT4_MASK 0x00D0004C +#define CS35L36_INT1_EDGE_LVL_CTRL 0x00D00060 +#define CS35L36_INT3_EDGE_LVL_CTRL 0x00D00068 +#define CS35L36_PAC_INT_STATUS 0x00D00200 +#define CS35L36_PAC_INT_RAW_STATUS 0x00D00210 +#define CS35L36_PAC_INT_FLUSH_CTRL 0x00D00218 +#define CS35L36_PAC_INT0_CTRL 0x00D00220 +#define CS35L36_PAC_INT1_CTRL 0x00D00224 +#define CS35L36_PAC_INT2_CTRL 0x00D00228 +#define CS35L36_PAC_INT3_CTRL 0x00D0022C +#define CS35L36_PAC_INT4_CTRL 0x00D00230 +#define CS35L36_PAC_INT5_CTRL 0x00D00234 +#define CS35L36_PAC_INT6_CTRL 0x00D00238 +#define CS35L36_PAC_INT7_CTRL 0x00D0023C +#define CS35L36_PAC_PMEM_WORD0 0x00E02800 +#define CS35L36_PAC_PMEM_WORD1 0x00E02804 +#define CS35L36_PAC_PMEM_WORD1023 0x00E037FC + +#define CS35L36_INTPAC_REG_COUNT 25 +#define CS35L36_CHIP_ID 0x00035A36 + +#define CS35L36_INT_OUTPUT_EN_MASK 0x01 +#define CS35L36_INT_GPIO_SEL_MASK 0x02 +#define CS35L36_INT_GPIO_SEL_SHIFT 1 +#define CS35L36_INT_POL_SEL_MASK 0x04 +#define CS35L36_INT_POL_SEL_SHIFT 2 +#define CS35L36_INT_DRV_SEL_MASK 0x20 +#define CS35L36_INT_DRV_SEL_SHIFT 5 +#define CS35L36_IRQ_SRC_MASK 0x08 +#define CS35L36_IRQ_SRC_SHIFT 3 + +#define CS35L36_SCLK_MSTR_MASK 0x40 +#define CS35L36_SCLK_MSTR_SHIFT 6 +#define CS35L36_LRCLK_MSTR_MASK 0x01 +#define CS35L36_LRCLK_MSTR_SHIFT 0 +#define CS35L36_SCLK_INV_MASK 0x100 +#define CS35L36_SCLK_INV_SHIFT 8 +#define CS35L36_LRCLK_INV_MASK 0x04 +#define CS35L36_LRCLK_INV_SHIFT 2 +#define CS35L36_SCLK_FRC_MASK 0x80 +#define CS35L36_SCLK_FRC_SHIFT 7 +#define CS35L36_LRCLK_FRC_MASK 0x02 +#define CS35L36_LRCLK_FRC_SHIFT 1 + +#define CS35L36_PDM_MODE_MASK 0x01 +#define CS35L36_PDM_MODE_SHIFT 0 + +#define CS35L36_ASP_FMT_MASK 0x07 +#define CS35L36_ASP_FMT_SHIFT 0 + +#define CS35L36_ASP_RX_WIDTH_MASK 0xFF0000 +#define CS35L36_ASP_RX_WIDTH_SHIFT 16 +#define CS35L36_ASP_TX_WIDTH_MASK 0xFF +#define CS35L36_ASP_TX_WIDTH_SHIFT 0 +#define CS35L36_ASP_WIDTH_16 0x10 +#define CS35L36_ASP_WIDTH_24 0x18 +#define CS35L36_ASP_WIDTH_32 0x20 + +#define CS35L36_ASP_RX1_SLOT_MASK 0x3F +#define CS35L36_ASP_RX1_EN_MASK 0x00010000 +#define CS35L36_ASP_RX1_EN_SHIFT 16 + +#define CS35L36_ASP_TX1_SLOT_MASK 0x3F +#define CS35L36_ASP_TX2_SLOT_MASK 0x3F0000 +#define CS35L36_ASP_TX2_SLOT_SHIFT 16 +#define CS35L36_ASP_TX3_SLOT_MASK 0x3F +#define CS35L36_ASP_TX4_SLOT_MASK 0x3F0000 +#define CS35L36_ASP_TX4_SLOT_SHIFT 16 +#define CS35L36_ASP_TX5_SLOT_MASK 0x3F +#define CS35L36_ASP_TX6_SLOT_MASK 0x3F0000 +#define CS35L36_ASP_TX6_SLOT_SHIFT 16 +#define CS35L36_ASP_TX7_SLOT_MASK 0x3F +#define CS35L36_ASP_TX8_SLOT_MASK 0x3F0000 +#define CS35L36_ASP_TX8_SLOT_SHIFT 16 +#define CS35L36_ASP_TX_HIZ_MASK 0x200000 + +#define CS35L36_APS_TX_SEL_MASK 0x7F + +#define CS35L36_ASP_TX1_EN_MASK 0x01 +#define CS35L36_ASP_TX2_EN_MASK 0x02 +#define CS35L36_ASP_TX2_EN_SHIFT 1 +#define CS35L36_ASP_TX3_EN_MASK 0x04 +#define CS35L36_ASP_TX3_EN_SHIFT 2 +#define CS35L36_ASP_TX4_EN_MASK 0x08 +#define CS35L36_ASP_TX4_EN_SHIFT 3 +#define CS35L36_ASP_TX5_EN_MASK 0x10 +#define CS35L36_ASP_TX5_EN_SHIFT 4 +#define CS35L36_ASP_TX6_EN_MASK 0x20 +#define CS35L36_ASP_TX6_EN_SHIFT 5 +#define CS35L36_ASP_TX7_EN_MASK 0x40 +#define CS35L36_ASP_TX7_EN_SHIFT 6 +#define CS35L36_ASP_TX8_EN_MASK 0x80 +#define CS35L36_ASP_TX8_EN_SHIFT 7 + + +#define CS35L36_PLL_CLK_SEL_MASK 0x07 +#define CS35L36_PLL_CLK_SEL_SHIFT 0 +#define CS35L36_PLLSRC_SCLK 0 +#define CS35L36_PLLSRC_LRCLK 1 +#define CS35L36_PLLSRC_SELF 3 +#define CS35L36_PLLSRC_PDMCLK 4 +#define CS35L36_PLLSRC_MCLK 5 +#define CS35L36_PLLSRC_SWIRE 7 +#define CS35L36_REFCLK_FREQ_MASK 0x7E0 +#define CS35L36_REFCLK_FREQ_SHIFT 5 +#define CS35L36_PLL_OPENLOOP_MASK 0x800 +#define CS35L36_PLL_OPENLOOP_SHIFT 11 +#define CS35L36_PLL_REFCLK_EN_MASK 0x10 +#define CS35L36_PLL_REFCLK_EN_SHIFT 4 + + +#define CS35L36_GLOBAL_FS_MASK 0x1F +#define CS35L36_GLOBAL_FS_SHIFT 0 + +#define CS35L36_HPF_PCM_EN_MASK 0x800 +#define CS35L36_HPF_PCM_EN_SHIFT 15 +#define CS35L36_PCM_RX_SEL_MASK 0x7F +#define CS35L36_PCM_RX_SEL_SHIFT 0 + +#define CS35L36_PCM_RX_SEL_ZERO 0x00 +#define CS35L36_PCM_RX_SEL_PCM 0x08 +#define CS35L36_PCM_RX_SEL_SWIRE 0x10 +#define CS35L36_PCM_RX_SEL_DIAG 0x04 + +#define CS35L36_GLOBAL_EN_MASK 0x01 +#define CS35L36_GLOBAL_EN_SHIFT 0x00 + +#define CS35L36_AMP_PCM_INV_MASK 0x4000 +#define CS35L36_AMP_PCM_INV_SHIFT 14 + +#define CS35L36_AMP_VOL_PCM_MASK 0x3FF8 +#define CS35L36_AMP_VOL_PCM_SHIFT 3 +#define CS35L36_DIGITAL_MUTE 0x04CF + +#define CS35L36_AMP_RAMP_MASK 0x0007 +#define CS35L36_AMP_RAMP_SHIFT 0 + +#define CS35L36_AMP_MUTE_MASK 0x0010 +#define CS35L36_AMP_MUTE_SHIFT 4 + +#define CS35L36_GLOBAL_RESYNC_FS1_MASK 0x00000200 +#define CS35L36_GLOBAL_RESYNC_FS2_MASK 0x00000400 +#define CS35L36_SYNC_GLOBAL_OVR_MASK 0x00000002 +#define CS35L36_SYNC_GLOBAL_OVR_SHIFT 1 + +#define CS35L36_REFCLK_IN_MASK 0x00100000 +#define CS35L36_PLL_UNLOCK_MASK 0x00002000 + +#define CS35L36_ASP_RX_UDF_MASK 0x00000040 +#define CS35L36_ASP_RX_OVF_MASK 0x00000080 + +#define CS35L36_IMON_POL_MASK 0x02 +#define CS35L36_IMON_POL_SHIFT 1 + +#define CS35L36_VMON_POL_MASK 0x01 +#define CS35L36_VMON_POL_SHIFT 0 + +#define CS35L36_PDN_DONE 0x40 +#define CS35L36_PDN_DONE_SHIFT 6 +#define CS35L36_PUP_DONE 0x80 +#define CS35L36_PUP_DONE_SHIFT 7 +#define CS35L36_GLOBAL_EN_ASSRT 0x20 +#define CS35L36_PUP_DONE_IRQ_UNMASK 0x7F +#define CS35L36_PUP_DONE_IRQ_MASK 0xBF + +#define CS35L36_FS1_WINDOW_MASK 0x000007FF +#define CS35L36_FS2_WINDOW_MASK 0x00FFF800 +#define CS35L36_FS2_WINDOW_SHIFT 12 + +#define CS35L36_PLL_FFL_IGAIN_MASK 0x0F +#define CS35L36_PLL_IGAIN_MASK 0x3F0 +#define CS35L36_PLL_IGAIN_SHIFT 4 +#define CS35L36_PLL_IGAIN 0x04 + +#define CS35L36_BST_EN_MASK 0x30 +#define CS35L36_BST_EN 0x02 +#define CS35L36_BST_DIS_VP 0x01 +#define CS35L36_BST_DIS_EXTN 0x00 +#define CS35L36_BST_EN_SHIFT 4 +#define CS35L36_BST_MAN_IPKCOMP_MASK 0x200 +#define CS35L36_BST_MAN_IPKCOMP_SHIFT 9 + +#define CS35L36_BST_MAN_IPKCOMP_EN_MASK 0x100 +#define CS35L36_BST_MAN_IPKCOMP_EN_SHIFT 8 + +#define CS35L36_BST_IPK_MASK 0x7F +#define CS35L36_BST_OVP_THLD_MASK 0x3F +#define CS35L36_BST_OVP_THLD_11V 0x10 +#define CS35L36_BST_OVP_TRIM_MASK 0x00078000 +#define CS35L36_BST_OVP_TRIM_SHIFT 15 +#define CS35L36_BST_OVP_TRIM_11V 0x0C +#define CS35L36_BST_CTRL_LIM_MASK 0x04 +#define CS35L36_BST_CTRL_LIM_SHIFT 2 +#define CS35L36_BST_CTRL_10V_CLAMP 0x96 + +#define CS35L36_NG_AMP_EN_MASK 0x3F00 +#define CS35L36_NG_DELAY_MASK 0x70 +#define CS35L36_NG_DELAY_SHIFT 4 +#define CS35L36_AMP_ZC_SHIFT 10 +#define CS35L36_PDM_LDM_ENTER_SHIFT 3 +#define CS35L36_PDM_LDM_EXIT_SHIFT 4 + +#define CS35L36_BSTCVRT_K1_MASK 0xFF +#define CS35L36_BSTCVRT_K2_MASK 0xFF00 +#define CS35L36_BSTCVRT_K2_SHIFT 8 +#define CS35L36_BSTCVRT_SLOPE_MASK 0xFF00 +#define CS35L36_BSTCVRT_SLOPE_SHIFT 8 +#define CS35L36_BSTCVRT_CCMFREQ_MASK 0x0F +#define CS35L36_BSTCVRT_LBSTVAL_MASK 0x03 +#define CS35L35_BSTCVRT_CTL_MASK 0xFF +#define CS35L35_BSTCVRT_CTL_SEL_MASK 0x03 +#define CS35L36_DCM_AUTO_MASK 0x01 + +#define CS35L36_INT1_MASK_DEFAULT 0xF9BA7FFF +#define CS35L36_INT1_MASK_RESET 0xFFFFFFFF +#define CS35L36_INT3_MASK_DEFAULT 0xFFFFEFFF +#define CS35L36_INT3_MASK_RESET 0xFFFFFFFF + + +#define CS35L36_AMP_SHORT_ERR 0x1000 +#define CS35L36_BST_SHORT_ERR 0x40000 +#define CS35L36_TEMP_WARN 0x2000000 +#define CS35L36_TEMP_ERR 0x4000000 +#define CS35L36_BST_OVP_ERR 0x10000 +#define CS35L36_BST_DCM_UVP_ERR 0x20000 + +#define CS35L36_AMP_SHORT_ERR_RLS 0x02 +#define CS35L36_BST_SHORT_ERR_RLS 0x04 +#define CS35L36_BST_OVP_ERR_RLS 0x08 +#define CS35L36_BST_UVP_ERR_RLS 0x10 +#define CS35L36_TEMP_WARN_ERR_RLS 0x20 +#define CS35L36_TEMP_ERR_RLS 0x40 +#define CS35L36_TEMP_THLD_MASK 0x03 + +#define CS35L36_REV_B0 0xb0 +#define CS35L36_REV_A0 0xa0 +#define CS35L36_B0_PAC_PATCH 0x00DD0102 + +#define CS35L36_OTP_ECC_EN_MASK 0x400 +#define CS35L36_OTP_ECC_EN_SHIFT 10 +#define CS35L36_OTP_RUN_BOOT_MASK 0x01 +#define CS35L36_OTP_BOOT_DONE 0x2000000 +#define CS35L36_PAC_RESET_MASK 0x04 +#define CS35L36_PAC_RESET_SHIFT 2 +#define CS35L36_PAC_STALL_MASK 0x02 +#define CS35L36_PAC_STALL_SHIFT 1 +#define CS35L36_PAC_ENABLE_MASK 0x00000001 +#define CS35L36_PAC_MEM_ACCESS 0x01 +#define CS35L36_PAC_MEM_ACCESS_CLR 0 +#define CS35L36_SOFT_RESET 0x5AAA +#define CS35L36_MCU_BOOT_COMPLETE 0x02 +#define CS35L36_MCU_CONFIG_UNMASK 0x00FEFFFF +#define CS35L36_MCU_CONFIG_CLR 0x00010000 +#define CS35L36_MCU_CONFIG_MASK 0x00FFFFFF +#define CS35L36_GPIO_INT_SEL_MASK 0x0000003B +#define CS35L36_GPIO_INT_SEL_UNMASK 0x0000003A +#define CS35L36_PAC_RESET 0x00000000 +#define CS35L36_OTP_REV_MASK 0x00FF0000 +#define CS35L36_OTP_REV_L37 0x00CC0000 +#define CS35L36_12V_L37 37 +#define CS35L36_10V_L36 36 + +#define CS35L36_VPBR_EN_MASK 0x00001000 +#define CS35L36_VPBR_EN_SHIFT 12 + +#define CS35L36_VPBR_THLD_MASK 0x0000001F +#define CS35L36_VPBR_THLD_SHIFT 0 +#define CS35L36_VPBR_MAX_ATTN_MASK 0x00000F00 +#define CS35L36_VPBR_MAX_ATTN_SHIFT 8 +#define CS35L36_VPBR_ATK_VOL_MASK 0x0000F000 +#define CS35L36_VPBR_ATK_VOL_SHIFT 12 +#define CS35L36_VPBR_ATK_RATE_MASK 0x00070000 +#define CS35L36_VPBR_ATK_RATE_SHIFT 16 +#define CS35L36_VPBR_WAIT_MASK 0x00180000 +#define CS35L36_VPBR_WAIT_SHIFT 19 +#define CS35L36_VPBR_REL_RATE_MASK 0x00E00000 +#define CS35L36_VPBR_REL_RATE_SHIFT 21 +#define CS35L36_VPBR_MUTE_EN_MASK 0x01000000 +#define CS35L36_VPBR_MUTE_EN_SHIFT 24 + +#define CS35L36_OSC_FREQ_TRIM_MASK 0x070 +#define CS35L36_OSC_TRIM_DONE 0x08 + +#define CS35L36_FS1_DEFAULT_VAL 16 +#define CS35L36_FS2_DEFAULT_VAL 36 +#define CS35L36_FS_NOM_6MHZ 6000000 + +#define CS35L36_TEST_UNLOCK1 0x00005555 +#define CS35L36_TEST_UNLOCK2 0x0000AAAA +#define CS35L36_TEST_LOCK1 0x0000CCCC +#define CS35L36_TEST_LOCK2 0x00003333 + +#define CS35L36_PAC_PROG_MEM 512 + +#define CS35L36_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) +#define CS35L36_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE \ + | SNDRV_PCM_FMTBIT_S32_LE) + +extern const int cs35l36_a0_pac_patch[CS35L36_PAC_PROG_MEM]; + +#endif From 0d250bf24a68ec25b4aa2b07c200b7de4607b182 Mon Sep 17 00:00:00 2001 From: James Schulman Date: Thu, 7 Feb 2019 12:12:19 -0600 Subject: [PATCH 322/461] ASoC: cs35l36: Add device tree documentation for CS35L36 Add device tree documentation for Cirrus Logic CS35L36 speaker amplifier Signed-off-by: James Schulman Reviewed-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs35l36.txt | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs35l36.txt diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt new file mode 100644 index 000000000000..912bd162b477 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs35l36.txt @@ -0,0 +1,168 @@ +CS35L36 Speaker Amplifier + +Required properties: + + - compatible : "cirrus,cs35l36" + + - reg : the I2C address of the device for I2C + + - VA-supply, VP-supply : power supplies for the device, + as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + + - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost + converter's output voltage in mV. The range is from 2550mV to 12000mV with + increments of 50mV. + (Default) VP + + - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA. + Configures the peak current by monitoring the current through the boost FET. + Range starts at 1600mA and goes to a maximum of 4500mA with increments of + 50mA. + (Default) 4.50 Amps + + - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value. + Seeds the digital boost converter's inductor estimation block with the initial + inductance value to reference. + + 1000 = 1uH (Default) + 1200 = 1.2uH + +Optional properties: + - cirrus,multi-amp-mode : Boolean to determine if there are more than + one amplifier in the system. If more than one it is best to Hi-Z the ASP + port to prevent bus contention on the output signal + + - cirrus,boost-ctl-select : Boost conerter control source selection. + Selects the source of the BST_CTL target VBST voltage for the boost + converter to generate. + 0x00 - Control Port Value + 0x01 - Class H Tracking (Default) + 0x10 - MultiDevice Sync Value + + - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming + PCM data + + - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the + polarity of outbound IMON feedback data + + - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the + polarity of outbound VMON feedback data + + - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable. + This enables the digital boost converter to operate in a low power + (Discontinuous Conduction) mode during low loading conditions. + + - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is + reduced when operating in a Weak-FET Drive Mode and must not be used to drive + a large load. + + - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay + (in ms) before the Class H algorithm switches to the weak-FET voltage + (after the audio falls and remains below the value specified in WKFET_AMP_THLD). + + 0 = 0ms + 1 = 5ms + 2 = 10ms + 3 = 50ms + 4 = 100ms (Default) + 5 = 200ms + 6 = 500ms + 7 = 1000ms + + - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold. + Configures the signal threshold at which the PWM output stage enters + weak-FET operation. The range is 50mV to 700mV in 50mV increments. + + - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold. + Configures the threshold at which the overtemperature warning condition occurs. + When the threshold is met, the overtemperature warning attenuation is applied + and the TEMP_WARN_EINT interrupt status bit is set. + If TEMP_WARN_MASK = 0, INTb is asserted. + + 0 = 105C + 1 = 115C + 2 = 125C (Default) + 3 = 135C + + - cirrus,irq-drive-select : Selects the driver type of the selected interrupt + output. + + 0 = Open-drain + 1 = Push-pull (Default) + + - cirrus,irq-gpio-select : Selects the pin to serve as the programmable + interrupt output. + + 0 = PDM_DATA / SWIRE_SD / INT (Default) + 1 = GPIO + +Optional properties for the "cirrus,vpbr-config" Sub-node + + - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the + VBST brownout prevention algorithm is enabled or disabled. + + 0 = VBST brownout prevention disabled (default) + 1 = VBST brownout prevention enabled + + See Section 7.31.1 VPBR Config for configuration options & further details + + - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout + threshold voltage + + - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the + amount delay between consecutive volume attenuation steps when a brownout + condition is present and the VP brownout condition is in an attacking state. + + - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP + brownout prevention attacking attenuation step size when operating in either + digital volume or analog gain modes. + + - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention + can apply to the audio signal. + + - cirrus,vpbr-wait : Configures the delay time between a brownout condition + no longer being present and the VP brownout prevention entering an attenuation + release state. + + - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay + between consecutive volume attenuation release steps when a brownout condition + is not longer present and the VP brownout is in an attenuation release state. + + - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value + is reached, the error condition still remains, and this bit is set, the audio + is muted. + +Example: + +cs35l36: cs35l36@40 { + compatible = "cirrus,cs35l36"; + reg = <0x40>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&gpio0 54 0>; + interrupt-parent = <&gpio8>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-ctl-millivolt = <10000>; + cirrus,boost-peak-milliamp = <4500>; + cirrus,boost-ctl-select = <0x00>; + cirrus,weak-fet-delay = <0x04>; + cirrus,weak-fet-thld = <0x01>; + cirrus,temp-warn-threshold = <0x01>; + cirrus,multi-amp-mode; + cirrus,irq-drive-select = <0x01>; + cirrus,irq-gpio-select = <0x01>; + + cirrus,vpbr-config { + cirrus,vpbr-en = <0x00>; + cirrus,vpbr-thld = <0x05>; + cirrus,vpbr-atk-rate = <0x02>; + cirrus,vpbr-atk-vol = <0x01>; + cirrus,vpbr-max-attn = <0x09>; + cirrus,vpbr-wait = <0x01>; + cirrus,vpbr-rel-rate = <0x05>; + cirrus,vpbr-mute-en = <0x00>; + }; +}; From d9186330c881468722c005ee772ca745c81a29ef Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 7 Feb 2019 21:59:18 -0700 Subject: [PATCH 323/461] ASoC: codecs: jz4725b: Remove unnecessary const qualifier Clang warns: sound/soc/codecs/jz4725b.c:177:14: warning: duplicate 'const' declaration specifier [-Wduplicate-decl-specifier] static const SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, ^ include/sound/soc.h:356:2: note: expanded from macro 'SOC_VALUE_ENUM_SINGLE_DECL' SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) ^ include/sound/soc.h:353:2: note: expanded from macro 'SOC_VALUE_ENUM_DOUBLE_DECL' const struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ ^ As it points out, SOC_VALUE_ENUM_DOUBLE_DECL has the const attribute in its definition so remove it here. Fixes: e9d97b05a80f ("ASoC: codecs: Add jz4725b-codec driver") Link: https://github.com/ClangBuiltLinux/linux/issues/354 Signed-off-by: Nathan Chancellor Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 103ccbc5d55c..766354c73076 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -173,12 +173,12 @@ static const char * const jz4725b_codec_adc_src_texts[] = { "Mic 1", "Mic 2", "Line In", "Mixer", }; static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, }; -static const SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, - JZ4725B_CODEC_REG_CR3, - REG_CR3_INSEL_OFFSET, - REG_CR3_INSEL_MASK, - jz4725b_codec_adc_src_texts, - jz4725b_codec_adc_src_values); +static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, + JZ4725B_CODEC_REG_CR3, + REG_CR3_INSEL_OFFSET, + REG_CR3_INSEL_MASK, + jz4725b_codec_adc_src_texts, + jz4725b_codec_adc_src_values); static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum); From 307cce4a0017f94c6266050487c117660d66104e Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 8 Feb 2019 11:49:53 +0100 Subject: [PATCH 324/461] ASoC: stm32: i2s: add power management Add suspend and resume sleep callbacks, to support system low power modes. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 6d0bf78d114d..dbe23a709d24 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -186,8 +186,9 @@ enum i2s_datlen { #define STM32_I2S_IS_SLAVE(x) ((x)->ms_flg == I2S_MS_SLAVE) /** + * struct stm32_i2s_data - private data of I2S * @regmap_conf: I2S register map configuration pointer - * @egmap: I2S register map pointer + * @regmap: I2S register map pointer * @pdev: device data pointer * @dai_drv: DAI driver pointer * @dma_data_tx: dma configuration data for tx channel @@ -596,8 +597,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } - ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, - I2S_CR1_CSTART, I2S_CR1_CSTART); + ret = regmap_write_bits(i2s->regmap, STM32_I2S_CR1_REG, + I2S_CR1_CSTART, I2S_CR1_CSTART); if (ret < 0) { dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; @@ -703,6 +704,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { .volatile_reg = stm32_i2s_volatile_reg, .writeable_reg = stm32_i2s_writeable_reg, .fast_io = true, + .cache_type = REGCACHE_FLAT, }; static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { @@ -929,10 +931,35 @@ static int stm32_i2s_remove(struct platform_device *pdev) MODULE_DEVICE_TABLE(of, stm32_i2s_ids); +#ifdef CONFIG_PM_SLEEP +static int stm32_i2s_suspend(struct device *dev) +{ + struct stm32_i2s_data *i2s = dev_get_drvdata(dev); + + regcache_cache_only(i2s->regmap, true); + regcache_mark_dirty(i2s->regmap); + + return 0; +} + +static int stm32_i2s_resume(struct device *dev) +{ + struct stm32_i2s_data *i2s = dev_get_drvdata(dev); + + regcache_cache_only(i2s->regmap, false); + return regcache_sync(i2s->regmap); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops stm32_i2s_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume) +}; + static struct platform_driver stm32_i2s_driver = { .driver = { .name = "st,stm32-i2s", .of_match_table = stm32_i2s_ids, + .pm = &stm32_i2s_pm_ops, }, .probe = stm32_i2s_probe, .remove = stm32_i2s_remove, From 6a68eeee0f03ab371bec7a719795f69b05be183f Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Fri, 8 Feb 2019 11:49:54 +0100 Subject: [PATCH 325/461] SoC: stm32: i2s: manage clock power Kernel clock management: Enable/disable I2S kernel clock on audio stream startup/shutdown. Peripheral clock management: Manage I2S peripheral clock power through regmap services. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 44 +++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index dbe23a709d24..a25919d32187 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -545,9 +545,16 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + int ret; i2s->substream = substream; + ret = clk_prepare_enable(i2s->i2sclk); + if (ret < 0) { + dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); + return ret; + } + spin_lock(&i2s->lock_fd); i2s->refcount++; spin_unlock(&i2s->lock_fd); @@ -674,6 +681,8 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); + + clk_disable_unprepare(i2s->i2sclk); } static int stm32_i2s_dai_probe(struct snd_soc_dai *cpu_dai) @@ -874,49 +883,26 @@ static int stm32_i2s_probe(struct platform_device *pdev) if (ret) return ret; - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->base, - i2s->regmap_conf); + i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", + i2s->base, i2s->regmap_conf); if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); return PTR_ERR(i2s->regmap); } - ret = clk_prepare_enable(i2s->pclk); - if (ret) { - dev_err(&pdev->dev, "Enable pclk failed: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(i2s->i2sclk); - if (ret) { - dev_err(&pdev->dev, "Enable i2sclk failed: %d\n", ret); - goto err_pclk_disable; - } - ret = devm_snd_soc_register_component(&pdev->dev, &stm32_i2s_component, i2s->dai_drv, 1); if (ret) - goto err_clocks_disable; + return ret; ret = devm_snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); if (ret) - goto err_clocks_disable; + return ret; /* Set SPI/I2S in i2s mode */ - ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, - I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); - if (ret) - goto err_clocks_disable; - - return ret; - -err_clocks_disable: - clk_disable_unprepare(i2s->i2sclk); -err_pclk_disable: - clk_disable_unprepare(i2s->pclk); - - return ret; + return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, + I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); } static int stm32_i2s_remove(struct platform_device *pdev) From 510135535382db7f5ee8727818172e42c9c9cbd5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 7 Feb 2019 17:57:55 +0100 Subject: [PATCH 326/461] dt-bindings: sound: msm8916-wcd-analog: fix example regulator names Fix upper-case regulator names in the binding example which do not match the corresponding required properties. While at it, add a blank line after the required-properties section to improve readability. Signed-off-by: Johan Hovold Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt index fdcea3d12ee5..e7d17dda55db 100644 --- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt @@ -30,6 +30,7 @@ Required properties - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. + Optional Properties: - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons detection on headset when the mbhc is powered up @@ -92,9 +93,9 @@ spmi_bus { "cdc_ear_cnp_int", "cdc_hphr_cnp_int", "cdc_hphl_cnp_int"; - VDD-CDC-IO-supply = <&pm8916_l5>; - VDD-CDC-TX-RX-CX-supply = <&pm8916_l5>; - VDD-MICBIAS-supply = <&pm8916_l13>; + vdd-cdc-io-supply = <&pm8916_l5>; + vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>; + vdd-micbias-supply = <&pm8916_l13>; #sound-dai-cells = <1>; }; }; From 95d14640d9843f277214893541aef3acb7456a25 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 8 Feb 2019 13:18:23 +1100 Subject: [PATCH 327/461] ASoC: xlnx: fix up for snd_pcm_lib_preallocate_pages_for_all() API change Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/soc/xilinx/xlnx_formatter_pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index 97177d35652e..dc8721f4f56b 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -536,10 +536,11 @@ static int xlnx_formatter_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, xlnx_pcm_hardware.buffer_bytes_max, xlnx_pcm_hardware.buffer_bytes_max); + return 0; } static const struct snd_pcm_ops xlnx_formatter_pcm_ops = { From bb580602f3924976d8bc36c171266de73e92cbf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:42:24 +0100 Subject: [PATCH 328/461] ALSA: pcm: Define snd_pcm_lib_preallocate_*() as returning void Now all callers no longer check the return value from snd_pcm_lib_preallocate_pages() and co, let's make them to return void, so that any new code won't fall into the same pitfall. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 8 ++++---- sound/core/pcm_memory.c | 29 ++++++++--------------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index ca20f80f8976..465d7d033c4c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1185,12 +1185,12 @@ static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, * Memory */ -int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream); -int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm); -int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, +void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream); +void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm); +void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max); -int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, +void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, size_t size, size_t max); int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 4012a3a01de1..ed73be80bd29 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -87,13 +87,10 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream * @substream: the pcm substream instance * * Releases the pre-allocated buffer of the given substream. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) +void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); - return 0; } /** @@ -101,10 +98,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) * @pcm: the pcm instance * * Releases all the pre-allocated buffers on the given pcm. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) +void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int stream; @@ -112,7 +107,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_free(substream); - return 0; } EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); @@ -214,7 +208,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) /* * pre-allocate the buffer and create a proc file for the substream */ -static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, +static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, size_t size, size_t max) { @@ -225,7 +219,6 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, substream->buffer_bytes_max = substream->dma_buffer.bytes; substream->dma_max = max; preallocate_info_init(substream); - return 0; } @@ -238,16 +231,14 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, * @max: the max. allowed pre-allocation size * * Do pre-allocation for the given DMA buffer type. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, +void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max) { substream->dma_buffer.dev.type = type; substream->dma_buffer.dev.dev = data; - return snd_pcm_lib_preallocate_pages1(substream, size, max); + snd_pcm_lib_preallocate_pages1(substream, size, max); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); @@ -261,21 +252,17 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); * * Do pre-allocation to all substreams of the given pcm for the * specified DMA type. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, +void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, size_t size, size_t max) { struct snd_pcm_substream *substream; - int stream, err; + int stream; for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0) - return err; - return 0; + snd_pcm_lib_preallocate_pages(substream, type, data, size, max); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); From 0bb423f2eaafedf89715c482a543dcd629ba3946 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Feb 2019 14:45:20 +0100 Subject: [PATCH 329/461] ASoC: regulator notifier registration should be managed Regulator notifiers, that were registered during codec driver probing, must be unregistered during driver release, or device managed versions have to be used. This patch fixes codec drivers, that weren't explicitly unregistering notifiers and simplifies those, that did that manually. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown --- sound/soc/codecs/max9860.c | 3 ++- sound/soc/codecs/pcm512x.c | 5 +++-- sound/soc/codecs/tlv320aic31xx.c | 16 +++------------- sound/soc/codecs/tlv320aic3x.c | 25 ++++--------------------- sound/soc/codecs/wm8770.c | 18 +++--------------- sound/soc/codecs/wm8962.c | 9 +++------ sound/soc/codecs/wm8995.c | 29 +++++++---------------------- sound/soc/codecs/wm8996.c | 9 +++------ 8 files changed, 28 insertions(+), 86 deletions(-) diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index de3d44e9199b..8be636fe6552 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -615,7 +615,8 @@ static int max9860_probe(struct i2c_client *i2c) max9860->dvddio_nb.notifier_call = max9860_dvddio_event; - ret = regulator_register_notifier(max9860->dvddio, &max9860->dvddio_nb); + ret = devm_regulator_register_notifier(max9860->dvddio, + &max9860->dvddio_nb); if (ret) dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ae3bd533eadb..62d05b01711f 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1540,8 +1540,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { - ret = regulator_register_notifier(pcm512x->supplies[i].consumer, - &pcm512x->supply_nb[i]); + ret = devm_regulator_register_notifier( + pcm512x->supplies[i].consumer, + &pcm512x->supply_nb[i]); if (ret != 0) { dev_err(dev, "Failed to register regulator notifier: %d\n", diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c6048d95c6d3..c544a1e35f5e 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1274,8 +1274,9 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) aic31xx->disable_nb[i].nb.notifier_call = aic31xx_regulator_event; aic31xx->disable_nb[i].aic31xx = aic31xx; - ret = regulator_register_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic31xx->supplies[i].consumer, + &aic31xx->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", @@ -1298,19 +1299,8 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) return 0; } -static void aic31xx_codec_remove(struct snd_soc_component *component) -{ - struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); - int i; - - for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) - regulator_unregister_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); -} - static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, - .remove = aic31xx_codec_remove, .set_bias_level = aic31xx_set_bias_level, .controls = common31xx_snd_controls, .num_controls = ARRAY_SIZE(common31xx_snd_controls), diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6aa0edf8c5ef..283583d1db60 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1615,13 +1615,14 @@ static int aic3x_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; - ret = regulator_register_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", ret); - goto err_notif; + return ret; } } @@ -1679,29 +1680,11 @@ static int aic3x_probe(struct snd_soc_component *component) aic3x_add_widgets(component); return 0; - -err_notif: - while (i--) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); - return ret; -} - -static void aic3x_remove(struct snd_soc_component *component) -{ - struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); - int i; - - list_del(&aic3x->list); - for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); } static const struct snd_soc_component_driver soc_component_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, .probe = aic3x_probe, - .remove = aic3x_remove, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 806245c70f8b..37467c512597 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -666,8 +666,9 @@ static int wm8770_spi_probe(struct spi_device *spi) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { - ret = regulator_register_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); if (ret) { dev_err(&spi->dev, "Failed to register regulator notifier: %d\n", @@ -687,25 +688,12 @@ static int wm8770_spi_probe(struct spi_device *spi) return ret; } -static int wm8770_spi_remove(struct spi_device *spi) -{ - struct wm8770_priv *wm8770 = spi_get_drvdata(spi); - int i; - - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) - regulator_unregister_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - - return 0; -} - static struct spi_driver wm8770_spi_driver = { .driver = { .name = "wm8770", .of_match_table = wm8770_of_match, }, .probe = wm8770_spi_probe, - .remove = wm8770_spi_remove }; module_spi_driver(wm8770_spi_driver); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index efd8910b1ff7..467ed78dd2df 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3424,8 +3424,9 @@ static int wm8962_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) { - ret = regulator_register_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8962->supplies[i].consumer, + &wm8962->disable_nb[i]); if (ret != 0) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -3467,15 +3468,11 @@ static int wm8962_probe(struct snd_soc_component *component) static void wm8962_remove(struct snd_soc_component *component) { struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - int i; cancel_delayed_work_sync(&wm8962->mic_work); wm8962_free_gpio(component); wm8962_free_beep(component); - for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) - regulator_unregister_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); } static const struct snd_soc_component_driver soc_component_dev_wm8962 = { diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 68c99fe37097..79ee91906bb9 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1995,20 +1995,6 @@ static int wm8995_set_bias_level(struct snd_soc_component *component, return 0; } -static void wm8995_remove(struct snd_soc_component *component) -{ - struct wm8995_priv *wm8995; - int i; - - wm8995 = snd_soc_component_get_drvdata(component); - - for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) - regulator_unregister_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); - - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -} - static int wm8995_probe(struct snd_soc_component *component) { struct wm8995_priv *wm8995; @@ -2021,8 +2007,9 @@ static int wm8995_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) wm8995->supplies[i].supply = wm8995_supply_names[i]; - ret = regulator_bulk_get(component->dev, ARRAY_SIZE(wm8995->supplies), - wm8995->supplies); + ret = devm_regulator_bulk_get(component->dev, + ARRAY_SIZE(wm8995->supplies), + wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to request supplies: %d\n", ret); return ret; @@ -2039,8 +2026,9 @@ static int wm8995_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) { - ret = regulator_register_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8995->supplies[i].consumer, + &wm8995->disable_nb[i]); if (ret) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -2052,7 +2040,7 @@ static int wm8995_probe(struct snd_soc_component *component) wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = snd_soc_component_read32(component, WM8995_SOFTWARE_RESET); @@ -2099,8 +2087,6 @@ static int wm8995_probe(struct snd_soc_component *component) err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); return ret; } @@ -2188,7 +2174,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { static const struct snd_soc_component_driver soc_component_dev_wm8995 = { .probe = wm8995_probe, - .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, .controls = wm8995_snd_controls, .num_controls = ARRAY_SIZE(wm8995_snd_controls), diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 91711f8958c5..ab04ea18c312 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2801,8 +2801,9 @@ static int wm8996_i2c_probe(struct i2c_client *i2c, /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { - ret = regulator_register_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8996->supplies[i].consumer, + &wm8996->disable_nb[i]); if (ret != 0) { dev_err(&i2c->dev, "Failed to register regulator notifier: %d\n", @@ -3071,16 +3072,12 @@ err: static int wm8996_i2c_remove(struct i2c_client *client) { struct wm8996_priv *wm8996 = i2c_get_clientdata(client); - int i; wm8996_free_gpio(wm8996); if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_free(wm8996->pdata.ldo_ena); } - for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) - regulator_unregister_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); return 0; } From 3f22e31da833e576fcfecce1f4e7ed958477d1ec Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 8 Feb 2019 16:16:55 +0100 Subject: [PATCH 330/461] ASoC: msm8916-wcd-analog: add missing license information Add the missing license and copyright information which never made it into the analog driver when the original driver was split in two as part of the review process. Link: https://lkml.kernel.org/r/1465582725-30183-3-git-send-email-srinivas.kandagatla@linaro.org Fixes: 585e881e5b9e ("ASoC: codecs: Add msm8916-wcd analog codec") Cc: Srinivas Kandagatla Signed-off-by: Johan Hovold Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index b7cf7cce95fe..368b6c09474b 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2016, The Linux Foundation. All rights reserved. + #include #include #include From 3ebc584ce7d1cc73151682c77ad2bea9318ddf98 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 8 Feb 2019 16:16:56 +0100 Subject: [PATCH 331/461] ASoC: msm8916-wcd-digital: convert license header to SPDX Convert the GPLv2-only license header to SPDX. Signed-off-by: Johan Hovold Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 423bfebabed4..a63961861e55 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -1,14 +1,5 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2016, The Linux Foundation. All rights reserved. #include #include From 4d1f7a6eabd45639d9de22a8a004f3c208d13c1a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Feb 2019 22:49:46 +0200 Subject: [PATCH 332/461] gpiolib: acpi: Introduce ACPI_GPIO_QUIRK_ONLY_GPIOIO New quirk enforces search for GPIO based on its type, i.e. iterate over GpioIo resources only. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Acked-by: Linus Walleij Tested-by: Hans de Goede Signed-off-by: Mark Brown --- drivers/gpio/gpiolib-acpi.c | 15 ++++-- include/linux/acpi.h | 7 +++ sound/soc/intel/boards/bytcr_rt5651.c | 74 ++++----------------------- 3 files changed, 27 insertions(+), 69 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 259cf6ab969b..4d291b75cb9f 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -530,17 +530,24 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) if (ares->type != ACPI_RESOURCE_TYPE_GPIO) return 1; - if (lookup->n++ == lookup->index && !lookup->desc) { + if (!lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; - int pin_index = lookup->pin_index; + bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + int pin_index; + if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint) + lookup->index++; + + if (lookup->n++ != lookup->index) + return 1; + + pin_index = lookup->pin_index; if (pin_index >= agpio->pin_table_length) return 1; lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, agpio->pin_table[pin_index]); - lookup->info.gpioint = - agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + lookup->info.gpioint = gpioint; /* * Polarity and triggering are only specified for GpioInt diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 87715f20b69a..03b4c4f225d0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1014,6 +1014,13 @@ struct acpi_gpio_mapping { /* Ignore IoRestriction field */ #define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) +/* + * When ACPI GPIO mapping table is in use the index parameter inside it + * refers to the GPIO resource in _CRS method. That index has no + * distinction of actual type of the resource. When consumer wants to + * get GpioIo type explicitly, this quirk may be used. + */ +#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1) unsigned int quirks; }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index c3b7732929cc..b0a4d297176e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -844,74 +844,18 @@ static const struct x86_cpu_id cherrytrail_cpu_ids[] = { {} }; -static const struct acpi_gpio_params first_gpio = { 0, 0, false }; -static const struct acpi_gpio_params second_gpio = { 1, 0, false }; +static const struct acpi_gpio_params ext_amp_enable_gpios = { 0, 0, false }; -static const struct acpi_gpio_mapping byt_rt5651_amp_en_first[] = { - { "ext-amp-enable-gpios", &first_gpio, 1 }, +static const struct acpi_gpio_mapping cht_rt5651_gpios[] = { + /* + * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, + * other boards may have I2cSerialBusV2, GpioInt, GpioIo instead. + * We want the GpioIo one for the ext-amp-enable-gpio. + */ + { "ext-amp-enable-gpios", &ext_amp_enable_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { }, }; -static const struct acpi_gpio_mapping byt_rt5651_amp_en_second[] = { - { "ext-amp-enable-gpios", &second_gpio, 1 }, - { }, -}; - -/* - * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, other - * boards may have I2cSerialBusV2, GpioInt, GpioIo instead. We want the - * GpioIo one for the ext-amp-enable-gpio and both count for the index in - * acpi_gpio_params index. So we have 2 different mappings and the code - * below figures out which one to use. - */ -struct byt_rt5651_acpi_resource_data { - int gpio_count; - int gpio_int_idx; -}; - -static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) -{ - struct byt_rt5651_acpi_resource_data *data = arg; - - if (ares->type != ACPI_RESOURCE_TYPE_GPIO) - return 0; - - if (ares->data.gpio.connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) - data->gpio_int_idx = data->gpio_count; - - data->gpio_count++; - return 0; -} - -static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) -{ - struct byt_rt5651_acpi_resource_data data = { 0, -1 }; - LIST_HEAD(resources); - int ret; - - ret = acpi_dev_get_resources(ACPI_COMPANION(codec), &resources, - snd_byt_rt5651_acpi_resource, &data); - if (ret < 0) { - dev_warn(codec, "Failed to get ACPI resources, not adding external amplifier GPIO mapping\n"); - return; - } - - /* All info we need is gathered during the walk */ - acpi_dev_free_resource_list(&resources); - - switch (data.gpio_int_idx) { - case 0: - byt_rt5651_gpios = byt_rt5651_amp_en_second; - break; - case 1: - byt_rt5651_gpios = byt_rt5651_amp_en_first; - break; - default: - dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", - data.gpio_int_idx); - } -} - struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ u64 aif_value; /* 1: AIF1, 2: AIF2 */ u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ @@ -1038,7 +982,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* Cherry Trail devices use an external amplifier enable gpio */ if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) - snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + byt_rt5651_gpios = cht_rt5651_gpios; if (byt_rt5651_gpios) { devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); From b450b87847b157d69dbf9af7aefb4cec29e89cc9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:23 -0600 Subject: [PATCH 333/461] ASoC: core: don't increase component module refcount unconditionally The ASoC core has for the longest time increased the module reference counts, even before the transition to the component model. This is probably fine on most platforms, but it introduces a deadlock case on Intel devices with the Skylake and SOF drivers which cannot be removed due to their reference counts being modified by the core. In these 2 cases, the PCI or ACPI driver .probe creates a platform device to let the machine driver .probe register the audio card. Conversely the PCI or ACPI driver .remove will unregister the platform device which results in the card being removed by the machine driver .remove. With ascii art, this can be represented as modprobe snd_soc_skl/ soc-pci-dev/sof-acpci-dev ----------> pci/acpi probe ^ | | ---------------| | | | | V V increase register register machine refcount component platform_device ^ | | | | V component <---- register card <---- probe probe The issue is that by playing with the component's module reference counts during the card registration, it's no longer possible to remove the module which controls the component. This can be shown, e.g. with the following error: root@plb-XPS-13-9350:~# lsmod | grep snd_soc_skl snd_soc_skl 110592 1 root@plb-XPS-13-9350:~# rmmod snd_soc_skl rmmod: ERROR: Module snd_soc_skl is in use Increasing the reference count during the component probe is not useful. If the PCI/ACPI module is removed, the card will be removed anyway. To avoid breaking existing platforms and allowing Intel platforms to safely deal with module load/unload cases, this patch introduces a flag which needs to be set during the component initialization. This is a strictly opt-in capability that should only be used when the handling of the component module does not require a reference count increase to prevent removal during use. Note that this solution is not directly applicable to the legacy Atom/SST driver, which uses a different device hierarchy. There are however additional refcount issues which prevent the ACPI driver from being removed. This is a different issue which would need a different patch. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 95689680336b..eb7db605955b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,6 +802,9 @@ struct snd_soc_component_driver { int probe_order; int remove_order; + /* signal if the module handling the component cannot be removed */ + unsigned int ignore_module_refcount:1; + /* bits */ unsigned int idle_bias_on:1; unsigned int suspend_bias_off:1; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 994d21d7ba0f..93d316d5bf8e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,8 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - module_put(component->dev->driver->owner); + if (!component->driver->ignore_module_refcount) + module_put(component->dev->driver->owner); } static void soc_remove_component(struct snd_soc_component *component) @@ -1380,7 +1381,8 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!try_module_get(component->dev->driver->owner)) + if (!component->driver->ignore_module_refcount && + !try_module_get(component->dev->driver->owner)) return -ENODEV; component->card = card; From e0771fc98909096b65c9781c438ac9d9c98ac41a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:24 -0600 Subject: [PATCH 334/461] ASoC: Intel: Skylake: set .ignore_module_refcount field in component There is no risk of the module being removed while the platform components are in use. This solves the problem of the snd_soc_skl module not being removable with rmmod Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 8e589d698c58..a4284778f117 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1464,6 +1464,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, + .ignore_module_refcount = 1, /* do not increase the refcount in core */ }; int skl_platform_register(struct device *dev) From a3daee085905e97ba20e6b9e72e6639fa518209c Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Mon, 11 Feb 2019 07:08:38 +0100 Subject: [PATCH 335/461] ASoC: pcm3060: Add soft reset on probe Softly reset registers values on module probe Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 6714aa8d9026..543cb86fd764 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -287,6 +287,14 @@ int pcm3060_probe(struct device *dev) int rc; struct pcm3060_priv *priv = dev_get_drvdata(dev); + /* soft reset */ + rc = regmap_update_bits(priv->regmap, PCM3060_REG64, + PCM3060_REG_MRST, 0); + if (rc) { + dev_err(dev, "failed to reset component, rc=%d\n", rc); + return rc; + } + if (dev->of_node) pcm3060_parse_dt(dev->of_node, priv); From 1e61405e201515d5767106babb4d750661ba5dcd Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Mon, 11 Feb 2019 07:08:39 +0100 Subject: [PATCH 336/461] ASoC: pcm3060: Add clock select ADC and DAC can be clocked from separate or same sources CLK1 and CLK2. By default, ADC is clocked from CLK1, and DAC - from CLK2. This commits allows sound cards to selest a proper clock source during `hw_params()` via `snd_soc_dai_set_sysclk()`. It makes possible to have a single clock source for both ADC and DAC. Signed-off-by: Kirill Marinushkin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3060.c | 27 +++++++++++++++++++++++++++ sound/soc/codecs/pcm3060.h | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 543cb86fd764..32b26f1c2282 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -18,12 +18,39 @@ static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct snd_soc_component *comp = dai->component; struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp); + unsigned int reg; + unsigned int val; if (dir != SND_SOC_CLOCK_IN) { dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir); return -EINVAL; } + switch (clk_id) { + case PCM3060_CLK_DEF: + val = 0; + break; + + case PCM3060_CLK1: + val = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG_CSEL : 0); + break; + + case PCM3060_CLK2: + val = (dai->id == PCM3060_DAI_ID_DAC ? 0 : PCM3060_REG_CSEL); + break; + + default: + dev_err(comp->dev, "unsupported sysclock id: %d\n", clk_id); + return -EINVAL; + } + + if (dai->id == PCM3060_DAI_ID_DAC) + reg = PCM3060_REG67; + else + reg = PCM3060_REG72; + + regmap_update_bits(priv->regmap, reg, PCM3060_REG_CSEL, val); + priv->dai[dai->id].sclk_freq = freq; return 0; diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h index 6a027b4a845d..75931c9a9d85 100644 --- a/sound/soc/codecs/pcm3060.h +++ b/sound/soc/codecs/pcm3060.h @@ -17,6 +17,11 @@ extern const struct regmap_config pcm3060_regmap; #define PCM3060_DAI_ID_ADC 1 #define PCM3060_DAI_IDS_NUM 2 +/* ADC and DAC can be clocked from separate or same sources CLK1 and CLK2 */ +#define PCM3060_CLK_DEF 0 /* default: CLK1->ADC, CLK2->DAC */ +#define PCM3060_CLK1 1 +#define PCM3060_CLK2 2 + struct pcm3060_priv_dai { bool is_master; unsigned int sclk_freq; From 49ff8cfb1755a6bb7d4f1645f9346962fb4e473e Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Mon, 11 Feb 2019 11:04:41 +0800 Subject: [PATCH 337/461] ASoC: mediatek: use %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index e408c1b270ab..4b613d57e2d4 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1269,7 +1269,7 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) /* irq */ irq_id = platform_get_irq(pdev, 0); if (irq_id <= 0) { - dev_err(dev, "%s no irq found\n", dev->of_node->name); + dev_err(dev, "%pOFn no irq found\n", dev->of_node); return irq_id < 0 ? irq_id : -ENXIO; } diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index ff3111ec876c..4e045dd305a7 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1139,7 +1139,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) /* request irq */ irq_id = platform_get_irq(pdev, 0); if (!irq_id) { - dev_err(dev, "%s no irq found\n", dev->of_node->name); + dev_err(dev, "%pOFn no irq found\n", dev->of_node); return -ENXIO; } ret = devm_request_irq(dev, irq_id, mt8183_afe_irq_handler, From c7ba4e5396fbe998502390e4fc7935163b189c50 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:26:53 -0600 Subject: [PATCH 338/461] ASoC: hdac_hdmi: use devm_kzalloc for all structures Loading/unloading modules exposes issues with memory allocation, which is a mix of devm_kzalloc and manual kzalloc. Move to devm_k routines everywhere to simplify all this. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 87 ++++++++---------------------------- 1 file changed, 18 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b19d7a3e7a2c..5eeb0fe836a9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1176,13 +1176,15 @@ static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; - cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + cvt = devm_kzalloc(&hdev->dev, sizeof(*cvt), GFP_KERNEL); if (!cvt) return -ENOMEM; cvt->nid = nid; sprintf(name, "cvt %d", cvt->nid); - cvt->name = kstrdup(name, GFP_KERNEL); + cvt->name = devm_kstrdup(&hdev->dev, name, GFP_KERNEL); + if (!cvt->name) + return -ENOMEM; list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; @@ -1287,8 +1289,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, mutex_unlock(&hdmi->pin_mutex); } -static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_add_ports(struct hdac_device *hdev, + struct hdac_hdmi_pin *pin) { struct hdac_hdmi_port *ports; int max_ports = HDA_MAX_PORTS; @@ -1300,7 +1302,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, * implemented. */ - ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(&hdev->dev, max_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -1319,14 +1321,14 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_pin *pin; int ret; - pin = kzalloc(sizeof(*pin), GFP_KERNEL); + pin = devm_kzalloc(&hdev->dev, sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM; pin->nid = nid; pin->mst_capable = false; pin->hdev = hdev; - ret = hdac_hdmi_add_ports(hdmi, pin); + ret = hdac_hdmi_add_ports(hdev, pin); if (ret < 0) return ret; @@ -1468,8 +1470,6 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, { hda_nid_t nid; int i, num_nodes; - struct hdac_hdmi_cvt *temp_cvt, *cvt_next; - struct hdac_hdmi_pin *temp_pin, *pin_next; struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int ret; @@ -1497,51 +1497,35 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, case AC_WID_AUD_OUT: ret = hdac_hdmi_add_cvt(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; case AC_WID_PIN: ret = hdac_hdmi_add_pin(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; } } if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; - goto free_widgets; + dev_err(&hdev->dev, "Bad pin/cvt setup in %s\n", __func__); + return ret; } ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt); if (ret) { dev_err(&hdev->dev, "Failed to create dais with err: %d\n", - ret); - goto free_widgets; + ret); + return ret; } *num_dais = hdmi->num_cvt; ret = hdac_hdmi_init_dai_map(hdev); if (ret < 0) - goto free_widgets; - - return ret; - -free_widgets: - list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&temp_cvt->head); - kfree(temp_cvt->name); - kfree(temp_cvt); - } - - list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < temp_pin->num_ports; i++) - temp_pin->ports[i].pin = NULL; - kfree(temp_pin->ports); - list_del(&temp_pin->head); - kfree(temp_pin); - } - + dev_err(&hdev->dev, "Failed to init DAI map with err: %d\n", + ret); return ret; } @@ -1782,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, * this is a new PCM device, create new pcm and * add to the pcm list */ - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->pcm_id = device; @@ -1798,7 +1782,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, dev_err(&hdev->dev, "chmap control add failed with err: %d for pcm: %d\n", err, device); - kfree(pcm); return err; } } @@ -2075,42 +2058,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) static int hdac_hdmi_dev_remove(struct hdac_device *hdev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pin *pin, *pin_next; - struct hdac_hdmi_cvt *cvt, *cvt_next; - struct hdac_hdmi_pcm *pcm, *pcm_next; - struct hdac_hdmi_port *port, *port_next; - int i; - snd_hdac_display_power(hdev->bus, hdev->addr, false); - list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { - pcm->cvt = NULL; - if (list_empty(&pcm->port_list)) - continue; - - list_for_each_entry_safe(port, port_next, - &pcm->port_list, head) - list_del(&port->head); - - list_del(&pcm->head); - kfree(pcm); - } - - list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&cvt->head); - kfree(cvt->name); - kfree(cvt); - } - - list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < pin->num_ports; i++) - pin->ports[i].pin = NULL; - kfree(pin->ports); - list_del(&pin->head); - kfree(pin); - } - return 0; } From d9c0b2afe820fa3b3f8258a659daee2cc71ca3ef Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 8 Feb 2019 17:29:53 -0600 Subject: [PATCH 339/461] ALSA: PCM: check if ops are defined before suspending PCM BE dai links only have internal PCM's and their substream ops may not be set. Suspending these PCM's will result in their ops->trigger() being invoked and cause a kernel oops. So skip suspending PCM's if their ops are NULL. [ NOTE: this change is required now for following the recent PCM core change to get rid of snd_pcm_suspend() call. Since DPCM BE takes the runtime carried from FE while keeping NULL ops, it can hit this bug. See details at: https://github.com/thesofproject/linux/pull/582 -- tiwai ] Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 672babd20cb1..f731f904e8cc 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1520,6 +1520,14 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) /* FIXME: the open/close code should lock this as well */ if (substream->runtime == NULL) continue; + + /* + * Skip BE dai link PCM's that are internal and may + * not have their substream ops set. + */ + if (!substream->ops) + continue; + err = snd_pcm_suspend(substream); if (err < 0 && err != -EBUSY) return err; From 36b1599340b5bbaf4d4f015cbfe89b7bc8cd7873 Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 10 Feb 2019 16:28:04 +0100 Subject: [PATCH 340/461] ASoC: wm8741: Add digital mute callback Signed-off-by: Sergej Sawazki Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8741.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 1fedf74da705..fdda83b7ca82 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -358,6 +358,15 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } +int wm8741_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_component *component = codec_dai->component; + + snd_soc_component_update_bits(component, WM8741_VOLUME_CONTROL, + WM8741_SOFT_MASK, !!mute << WM8741_SOFT_SHIFT); + return 0; +} + #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ @@ -371,6 +380,7 @@ static const struct snd_soc_dai_ops wm8741_dai_ops = { .hw_params = wm8741_hw_params, .set_sysclk = wm8741_set_dai_sysclk, .set_fmt = wm8741_set_dai_fmt, + .digital_mute = wm8741_mute, }; static struct snd_soc_dai_driver wm8741_dai = { From e9418629e2fcf7374c19750f3afa7f3a7ff0afa2 Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 10 Feb 2019 16:29:29 +0100 Subject: [PATCH 341/461] ASoC: wm8741: Set OSR mode in hw_params() For correct operation of the digital filtering and other processing on the WM8741, the user must ensure the correct value of OSR[1:0] is set at all times.[1] Hence, depending the selected sampling rate, set the OSR (over- sampling rate) mode in hw_params(). References: [1] "WM8741 Data Sheet" Signed-off-by: Sergej Sawazki Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8741.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index fdda83b7ca82..a4b8c459ea57 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -196,7 +196,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component); - unsigned int iface; + unsigned int iface, mode; int i; /* The set of sample rates that can be supported depends on the @@ -240,11 +240,21 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* oversampling rate */ + if (params_rate(params) > 96000) + mode = 0x40; + else if (params_rate(params) > 48000) + mode = 0x20; + else + mode = 0x00; + dev_dbg(component->dev, "wm8741_hw_params: bit size param = %d, rate param = %d", params_width(params), params_rate(params)); snd_soc_component_update_bits(component, WM8741_FORMAT_CONTROL, WM8741_IWL_MASK, iface); + snd_soc_component_update_bits(component, WM8741_MODE_CONTROL_1, WM8741_OSR_MASK, + mode); return 0; } From fc23af99e47612042964ace44121872158ae834d Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Tue, 12 Feb 2019 15:18:47 +0800 Subject: [PATCH 342/461] ASoC: mediatek: btcvsd fix rx stream assign fix tx/rx stream assign wrong direction Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 4b613d57e2d4..1b8bcdaf02d1 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -250,7 +250,7 @@ static int mtk_btcvsd_snd_rx_init(struct mtk_btcvsd_snd *bt) bt->rx->buf_size = BTCVSD_RX_BUF_SIZE; bt->rx->timeout = 0; bt->rx->rw_cnt = 0; - bt->tx->stream = SNDRV_PCM_STREAM_CAPTURE; + bt->rx->stream = SNDRV_PCM_STREAM_CAPTURE; return 0; } From 674f9abd094552dc297a2afd0cb72d30aec539a3 Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Mon, 11 Feb 2019 22:06:30 +0100 Subject: [PATCH 343/461] tlv320aic32x4: delay i2c access by 1 ms after hardware reset As stated in 'TLV320AIC3254 Application Reference Guide' ([1]): 3.2 Device Startup Lockout Times After the TLV320AIC3254 initializes through hardware reset at power-up or software reset, the internal registers initialize to default values. This initialization takes place within 1ms after pulling the RESET signal high. During this initialization phase, no register-read or register-write operation should be performed on ADC or DAC coefficient buffers. Also, no block within the codec should be powered up during the initialization phase. [1] http://www.ti.com/lit/an/slaa408a/slaa408a.pdf Signed-off-by: Peter Seiderer Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e1bfba62fc08..96f1526cb258 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -970,6 +970,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) if (gpio_is_valid(aic32x4->rstn_gpio)) { ndelay(10); gpio_set_value(aic32x4->rstn_gpio, 1); + mdelay(1); } snd_soc_component_write(component, AIC32X4_RESET, 0x01); From 595d2f74cd3caedb704a118bd09c1b4dfbfc0ec0 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 23 Jan 2019 20:41:30 +0100 Subject: [PATCH 344/461] ASoC: Use __printf markup to silence compiler Silence warnings (triggered at W=1) by adding relevant __printf attributes. sound/soc/soc-dapm.c:149:2: warning: function 'pop_dbg' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format] Signed-off-by: Mathieu Malaterre Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d31d295b540f..dea6fc2353e4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -157,6 +157,7 @@ static void pop_wait(u32 pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } +__printf(3, 4) static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) { va_list args; From 51256d348c9af1bf544a4432abc1d5f2fd3ef34b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:09 +0100 Subject: [PATCH 345/461] ASoC: dmaengine: Improve of_node test in dmaengine_pcm_request_chan_of() Currently when of_node of the "PCM" device is null dmaengine_pcm_request_chan_of() function will bail out, including cases when custom DMA device is intended to be used. To have the channels properly requested when custom DMA device is provided extend the of_node test to also consider dma_dev->of_node. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 30e791a53352..6d7638c1233d 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -415,7 +415,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + (!dev->of_node && !(config && config->dma_dev && + config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 10cbf3507bcb9baa82bf3445502e8ccafaa09fc8 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:10 +0100 Subject: [PATCH 346/461] ASoC: dmaengine: Extend use of chan_names provided in custom DMA config There are currently two ways to specify custom DMA channel names: - through the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag and snd_dmaengine_dai_dma_data data structure, - through chan_names field of struct snd_dmaengine_pcm_config. In order to replace the DAI DMA data method with the custom DMA config one on non-DT platforms the dmaengine_pcm_new() function is extended to also consider channel names specified in the custom DMA config. If both config->chan_names and dma_data->chan_name are provided the former will be used. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-generic-dmaengine-pcm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6d7638c1233d..1b44e363c50c 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -288,9 +288,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || + (config && config->chan_names[i]))) { + const char *chan_name = dma_data->chan_name; + + if (config && config->chan_names[i]) + chan_name = config->chan_names[i]; + pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); + chan_name); + } if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, From 96f06cde2c00d78395f5200cbbdf216c5ce3bc3f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:11 +0100 Subject: [PATCH 347/461] ASoC: samsung: dmaengine: Allow to specify custom DMA device The additional function argument will allow to select proper DMA device for requesting DMA channel for the secondary CPU DAI. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/dma.h | 3 ++- sound/soc/samsung/dmaengine.c | 4 +++- sound/soc/samsung/i2s.c | 4 ++-- sound/soc/samsung/pcm.c | 2 +- sound/soc/samsung/s3c2412-i2s.c | 2 +- sound/soc/samsung/s3c24xx-i2s.c | 2 +- sound/soc/samsung/spdif.c | 2 +- 7 files changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 7ae580d677c8..0ae15d01a3f6 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -17,5 +17,6 @@ * otherwise actual DMA channel names must be passed to this function. */ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, - const char *tx, const char *rx); + const char *tx, const char *rx, + struct device *dma_dev); #endif /* _SAMSUNG_DMA_H */ diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 9104c98deeb7..84601fa9aa46 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -25,7 +25,8 @@ #include "dma.h" int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, - const char *tx, const char *rx) + const char *tx, const char *rx, + struct device *dma_dev) { unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; struct snd_dmaengine_pcm_config *pcm_conf; @@ -36,6 +37,7 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; pcm_conf->compat_filter_fn = filter; + pcm_conf->dma_dev = dma_dev; if (dev->of_node) { pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d6c62aa13041..efc8704d36e3 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1345,7 +1345,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->i2s_dai_drv.playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, - NULL, NULL); + NULL, NULL, NULL); if (ret < 0) goto err_disable_clk; @@ -1382,7 +1382,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->sec_dai = sec_dai; ret = samsung_asoc_dma_platform_register(&pdev->dev, - sec_dai->filter, "tx-sec", NULL); + sec_dai->filter, "tx-sec", NULL, NULL); if (ret < 0) goto err_disable_clk; diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 37f95eee1558..3c7baa561084 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -553,7 +553,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err_dis_pclk; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index cc0840fff5aa..67dfa27ae321 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -177,7 +177,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) ret = samsung_asoc_dma_platform_register(&pdev->dev, pdata->dma_filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { pr_err("failed to register the DMA: %d\n", ret); return ret; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 8d58d02183bf..ba0f2b94f8d4 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -446,7 +446,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index cb59911e65c0..5e4afb330416 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -430,7 +430,7 @@ static int spdif_probe(struct platform_device *pdev) spdif->dma_playback = &spdif_stereo_out; ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, - NULL, NULL); + NULL, NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); goto err4; From a404b72d2bdd45878e1441650967a75452d5e420 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:13 +0100 Subject: [PATCH 348/461] ASoC: samsung: i2s: Convert to single component with multiple DAIs This patch includes minimal changes as a prerequisite for adding support for the Exynos secondary I2S interface as second DAI of the I2S component. Doing it that way allows to avoid problems as indicated in commmit 6b01e0365b1689 ("ASoC: samsung: i2s: disable secondary DAI until it gets fixed") The samsung_i2s_get_pri_dai() helper added in this patch is temporary and will be removed in one of subsequent patches. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 186 ++++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 74 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index efc8704d36e3..455bc65d115a 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -34,6 +34,9 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +#define SAMSUNG_I2S_ID_PRIMARY 1 +#define SAMSUNG_I2S_ID_SECONDARY 2 + struct samsung_i2s_variant_regs { unsigned int bfs_off; unsigned int rfs_off; @@ -79,8 +82,10 @@ struct i2s_dai { #define DAI_OPENED (1 << 0) /* Dai is opened */ #define DAI_MANAGER (1 << 1) /* Dai is the manager */ unsigned mode; + /* Driver for this DAI */ - struct snd_soc_dai_driver i2s_dai_drv; + struct snd_soc_dai_driver *drv; + /* DMA parameters */ struct snd_dmaengine_dai_dma_data dma_playback; struct snd_dmaengine_dai_dma_data dma_capture; @@ -92,8 +97,6 @@ struct i2s_dai { u32 suspend_i2spsr; const struct samsung_i2s_variant_regs *variant_regs; - /* Spinlock protecting access to the device's registers */ - spinlock_t spinlock; spinlock_t *lock; /* Below fields are only valid if this is the primary FIFO */ @@ -104,10 +107,29 @@ struct i2s_dai { /* Lock for cross i/f checks */ static DEFINE_SPINLOCK(lock); -/* If this is the 'overlay' stereo DAI */ +struct samsung_i2s_priv { + struct platform_device *pdev; + + /* Spinlock protecting access to the device's registers */ + spinlock_t spinlock; + + /* CPU DAIs and their corresponding drivers */ + struct i2s_dai *dai; + struct snd_soc_dai_driver *dai_drv; + int num_dais; +}; + +struct i2s_dai *samsung_i2s_get_pri_dai(struct device *dev) +{ + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); + + return &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; +} + +/* Returns true if this is the 'overlay' stereo DAI */ static inline bool is_secondary(struct i2s_dai *i2s) { - return i2s->pri_dai ? true : false; + return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; } /* If operating in SoC-Slave mode */ @@ -202,7 +224,9 @@ static inline bool any_active(struct i2s_dai *i2s) static inline struct i2s_dai *to_info(struct snd_soc_dai *dai) { - return snd_soc_dai_get_drvdata(dai); + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); + + return &priv->dai[dai->id - 1]; } static inline bool is_opened(struct i2s_dai *i2s) @@ -1059,7 +1083,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { - struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); + struct i2s_dai *i2s = to_info(dai); unsigned long flags; pm_runtime_get_sync(dai->dev); @@ -1096,47 +1120,63 @@ static const struct snd_soc_component_driver samsung_i2s_component = { SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, - const struct samsung_i2s_dai_data *i2s_dai_data, - bool sec) +static int i2s_alloc_dais(struct samsung_i2s_priv *priv, + const struct samsung_i2s_dai_data *i2s_dai_data, + int num_dais) { - struct i2s_dai *i2s; + static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; + struct snd_soc_dai_driver *dai_drv; + struct i2s_dai *dai; + int i; - i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL); - if (i2s == NULL) - return NULL; + priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais, + sizeof(*dai), GFP_KERNEL); + if (!priv->dai) + return -ENOMEM; - i2s->pdev = pdev; - i2s->pri_dai = NULL; - i2s->sec_dai = NULL; - i2s->i2s_dai_drv.id = 1; - i2s->i2s_dai_drv.symmetric_rates = 1; - i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe; - i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove; - i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops; - i2s->i2s_dai_drv.suspend = i2s_suspend; - i2s->i2s_dai_drv.resume = i2s_resume; - i2s->i2s_dai_drv.playback.channels_min = 1; - i2s->i2s_dai_drv.playback.channels_max = 2; - i2s->i2s_dai_drv.playback.rates = i2s_dai_data->pcm_rates; - i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS; + priv->dai_drv = devm_kcalloc(&priv->pdev->dev, num_dais, + sizeof(*dai_drv), GFP_KERNEL); + if (!priv->dai_drv) + return -ENOMEM; - if (!sec) { - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI; - i2s->i2s_dai_drv.capture.channels_min = 1; - i2s->i2s_dai_drv.capture.channels_max = 2; - i2s->i2s_dai_drv.capture.rates = i2s_dai_data->pcm_rates; - i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; - } else { - i2s->i2s_dai_drv.name = SAMSUNG_I2S_DAI_SEC; + for (i = 0; i < num_dais; i++) { + dai_drv = &priv->dai_drv[i]; + + dai_drv->probe = samsung_i2s_dai_probe; + dai_drv->remove = samsung_i2s_dai_remove; + dai_drv->suspend = i2s_suspend; + dai_drv->resume = i2s_resume; + + dai_drv->symmetric_rates = 1; + dai_drv->ops = &samsung_i2s_dai_ops; + + dai_drv->playback.channels_min = 1; + dai_drv->playback.channels_max = 2; + dai_drv->playback.rates = i2s_dai_data->pcm_rates; + dai_drv->playback.formats = SAMSUNG_I2S_FMTS; + + dai_drv->id = i + 1; + dai_drv->name = dai_names[i]; + + priv->dai[i].drv = &priv->dai_drv[i]; + priv->dai[i].pdev = priv->pdev; } - return i2s; + + /* Initialize capture only for the primary DAI */ + dai_drv = &priv->dai_drv[SAMSUNG_I2S_ID_PRIMARY - 1]; + + dai_drv->capture.channels_min = 1; + dai_drv->capture.channels_max = 2; + dai_drv->capture.rates = i2s_dai_data->pcm_rates; + dai_drv->capture.formats = SAMSUNG_I2S_FMTS; + + return 0; } #ifdef CONFIG_PM static int i2s_runtime_suspend(struct device *dev) { - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); i2s->suspend_i2scon = readl(i2s->addr + I2SCON); @@ -1151,7 +1191,7 @@ static int i2s_runtime_suspend(struct device *dev) static int i2s_runtime_resume(struct device *dev) { - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; ret = clk_prepare_enable(i2s->clk); @@ -1186,7 +1226,7 @@ static void i2s_unregister_clocks(struct i2s_dai *i2s) static void i2s_unregister_clock_provider(struct platform_device *pdev) { - struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(&pdev->dev); of_clk_del_provider(pdev->dev.of_node); i2s_unregister_clocks(i2s); @@ -1194,11 +1234,12 @@ static void i2s_unregister_clock_provider(struct platform_device *pdev) static int i2s_register_clock_provider(struct platform_device *pdev) { + const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" }; const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; const char *p_names[2] = { NULL }; struct device *dev = &pdev->dev; - struct i2s_dai *i2s = dev_get_drvdata(dev); + struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; struct clk *rclksrc; @@ -1273,7 +1314,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) u32 regs_base, quirks = 0, idma_addr = 0; struct device_node *np = pdev->dev.of_node; const struct samsung_i2s_dai_data *i2s_dai_data; - int ret; + int num_dais, ret; + struct samsung_i2s_priv *priv; if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) i2s_dai_data = of_device_get_match_data(&pdev->dev); @@ -1281,14 +1323,24 @@ static int samsung_i2s_probe(struct platform_device *pdev) i2s_dai_data = (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; - pri_dai = i2s_alloc_dai(pdev, i2s_dai_data, false); - if (!pri_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - } - spin_lock_init(&pri_dai->spinlock); - pri_dai->lock = &pri_dai->spinlock; + quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; + quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); + + num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; + priv->pdev = pdev; + + ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais); + if (ret < 0) + return ret; + + pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; + + spin_lock_init(&priv->spinlock); + pri_dai->lock = &priv->spinlock; if (!np) { if (i2s_pdata == NULL) { @@ -1300,10 +1352,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; pri_dai->filter = i2s_pdata->dma_filter; - quirks = i2s_pdata->type.quirks; idma_addr = i2s_pdata->type.idma_addr; } else { - quirks = i2s_dai_data->quirks; if (of_property_read_u32(np, "samsung,idma-addr", &idma_addr)) { if (quirks & QUIRK_SUPPORTS_IDMA) { @@ -1312,7 +1362,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } } } - quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); @@ -1342,28 +1391,17 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; if (quirks & QUIRK_PRI_6CHAN) - pri_dai->i2s_dai_drv.playback.channels_max = 6; + pri_dai->drv->playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, NULL, NULL, NULL); if (ret < 0) goto err_disable_clk; - ret = devm_snd_soc_register_component(&pdev->dev, - &samsung_i2s_component, - &pri_dai->i2s_dai_drv, 1); - if (ret < 0) - goto err_disable_clk; - if (quirks & QUIRK_SEC_DAI) { - sec_dai = i2s_alloc_dai(pdev, i2s_dai_data, true); - if (!sec_dai) { - dev_err(&pdev->dev, "Unable to alloc I2S_sec\n"); - ret = -ENOMEM; - goto err_disable_clk; - } + sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; - sec_dai->lock = &pri_dai->spinlock; + sec_dai->lock = &priv->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; sec_dai->dma_playback.chan_name = "tx-sec"; @@ -1386,11 +1424,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_clk; - ret = devm_snd_soc_register_component(&pdev->dev, - &samsung_i2s_component, - &sec_dai->i2s_dai_drv, 1); - if (ret < 0) - goto err_disable_clk; } if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { @@ -1399,7 +1432,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) goto err_disable_clk; } - dev_set_drvdata(&pdev->dev, pri_dai); + dev_set_drvdata(&pdev->dev, priv); + + ret = devm_snd_soc_register_component(&pdev->dev, + &samsung_i2s_component, + priv->dai_drv, num_dais); + if (ret < 0) + goto err_disable_clk; pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1421,9 +1460,8 @@ err_disable_clk: static int samsung_i2s_remove(struct platform_device *pdev) { - struct i2s_dai *pri_dai; - - pri_dai = dev_get_drvdata(&pdev->dev); + struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); + struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); From e529a9d44a9778b851a1683e6689c2f52d6750ac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:41 -0600 Subject: [PATCH 349/461] ASoC: Intel: bxt-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-bxt-match.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 61dedc103b19..c0e5780e2ad1 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -51,8 +51,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-rt298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -61,30 +61,30 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &bxt_codecs, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-da7219.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-pcm512x.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-wm8804.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-wm8804.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", .drv_name = "bxt_tdf8532", .machine_quirk = apl_quirk, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 528f07152a7840b5affe1c8844ddd1ee9d3aabd7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:42 -0600 Subject: [PATCH 350/461] ASoC: Intel: byt-match.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-byt-match.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 96f9c553fe6c..a46a3514a0f0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -83,8 +83,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5670.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -93,8 +93,8 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -136,8 +136,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", .machine_quirk = byt_quirk, - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -145,8 +145,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -154,8 +154,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -163,8 +163,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -172,8 +172,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -181,8 +181,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -190,8 +190,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ @@ -200,8 +200,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -209,8 +209,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ @@ -219,8 +219,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-max98090.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From 2e441dea9fee379e85dca15988671c23d6013d1c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:43 -0600 Subject: [PATCH 351/461] ASoC: Intel: cht-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-cht-match.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 91bb99b69601..21ce4bcbf25b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -68,8 +68,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -77,8 +77,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -86,8 +86,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -95,8 +95,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -104,8 +104,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -113,8 +113,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-max98090.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -122,8 +122,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-nau8824", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-nau8824.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-nau8824.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -131,8 +131,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -140,8 +140,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -149,8 +149,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-es8316.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ @@ -160,8 +160,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", .machine_quirk = cht_quirk, - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -169,8 +169,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ @@ -179,8 +179,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5651.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From 7466e749a3b4e838882cc8728bc66a39df0e9dfa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:44 -0600 Subject: [PATCH 352/461] ASoC: Intel: cnl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ec8e28e7b937..b80b50ddb22b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", .pdata = &cnl_pdata, - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cnl-rt274.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From 6d356d52297ded6b1bae86c54b364d7784c0a528 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:45 -0600 Subject: [PATCH 353/461] ASoC: Intel: glk-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 305875af71ca..75bc0109166a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -19,8 +19,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .id = "INT343A", .drv_name = "glk_alc298s_i2s", .fw_filename = "intel/dsp_fw_glk.bin", - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-alc298.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-alc298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -29,8 +29,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-da7219.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From e576b097918f8ee563fbfde7d4186f09df856fe9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:46 -0600 Subject: [PATCH 354/461] ASoC: Intel: hda-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-hda-match.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 533c1064f84b..68ae43f7b4b2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -23,7 +23,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { /* .sof_fw_filename is dynamically set in sof/intel driver */ - .sof_tplg_filename = "intel/sof-hda-generic.tplg", + .sof_tplg_filename = "sof-hda-generic.tplg", /* * .machine_quirk and .quirk_data are not used here but From bb2538e28a54f97455597eca01e1b9452c67a5d4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:47 -0600 Subject: [PATCH 355/461] ASoC: Intel: hsw-bdw-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-hsw-bdw-match.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index 494a0ea9b029..ddfe4250c2bc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST1.bin", - .sof_fw_filename = "intel/sof-hsw.ri", - .sof_tplg_filename = "intel/sof-hsw.tplg", + .sof_fw_filename = "sof-hsw.ri", + .sof_tplg_filename = "sof-hsw.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} @@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .id = "INT343A", .drv_name = "broadwell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt286.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt286.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", .drv_name = "bdw-rt5677", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5677.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5640.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} From a5b1e2284567c487b1023b580656de4a19cc1a83 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:48 -0600 Subject: [PATCH 356/461] ASoC: Intel: icl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 33b441dca4d3..bf6e25257a39 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", .pdata = &icl_pdata, - .sof_fw_filename = "intel/sof-icl.ri", - .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From dcc9de2ebe86791a041a92cdf9806bde004706c6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:49 -0600 Subject: [PATCH 357/461] ASoC: Intel: soc-acpi: bxt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index c0e5780e2ad1..229e39586868 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -53,7 +53,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-rt298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -63,21 +62,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .quirk_data = &bxt_codecs, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-pcm512x.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-wm8804.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", @@ -85,7 +81,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .machine_quirk = apl_quirk, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-tdf8532.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From f01d00c30095f420ad8b447ba21c9492da93cebf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:50 -0600 Subject: [PATCH 358/461] ASoC: Intel: soc-acpi: byt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index a46a3514a0f0..fe812a909db4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -85,7 +85,6 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach byt_pov_p1006w = { @@ -95,7 +94,6 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *byt_quirk(void *arg) @@ -138,7 +136,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .machine_quirk = byt_quirk, .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5642", @@ -147,7 +144,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "INTCCFFD", @@ -156,7 +152,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5651", @@ -165,7 +160,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -174,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -183,7 +176,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -192,7 +184,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { @@ -202,7 +193,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5648", @@ -211,7 +201,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ { @@ -221,7 +210,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 9eebe4372f4a608e51b7a2c0b064069e78a6ce5b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:51 -0600 Subject: [PATCH 359/461] ASoC: Intel: soc-acpi: cht-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-cht-match.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 21ce4bcbf25b..deafd87cc764 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -46,7 +46,6 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *cht_quirk(void *arg) @@ -70,7 +69,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5672", @@ -79,7 +77,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5645", @@ -88,7 +85,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5650", @@ -97,7 +93,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3270", @@ -106,7 +101,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "193C9890", @@ -115,7 +109,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10508824", @@ -124,7 +117,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-nau8824.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -133,7 +125,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -142,7 +133,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -151,7 +141,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ { @@ -162,7 +151,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .machine_quirk = cht_quirk, .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3276", @@ -171,7 +159,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ { @@ -181,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 3f4d9d67c3399bde7e08aeeb9758868852413343 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:52 -0600 Subject: [PATCH 360/461] ASoC: Intel: soc-acpi: glk-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 75bc0109166a..3f2061475ae4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -21,7 +21,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-alc298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -31,7 +30,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .quirk_data = &glk_codecs, .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From 2eddca128be282f600347ea07ef0b516dbc4e7ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:53 -0600 Subject: [PATCH 361/461] ASoC: Intel: soc-acpi: hsw-bdw-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index ddfe4250c2bc..690b305a255b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -25,7 +25,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .fw_filename = "intel/IntcSST1.bin", .sof_fw_filename = "sof-hsw.ri", .sof_tplg_filename = "sof-hsw.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; @@ -38,7 +37,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt286.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", @@ -46,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5677.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5640.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; From fc906fda39c1705c2d89937fce13a6c11a5955bb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:54 -0600 Subject: [PATCH 362/461] ASoC: Intel: soc-acpi: icl-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index bf6e25257a39..e5a6be5bc0ee 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .pdata = &icl_pdata, .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From c5898050fe801443dc66cd0302c21ceefa313916 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:55 -0600 Subject: [PATCH 363/461] ASoC: Intel: soc-acpi: cnl-match.c: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index b80b50ddb22b..a914dd238d0a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .pdata = &cnl_pdata, .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From ecefff3e5b9b6a427a1a78c0c3f5eb147fd2d761 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:56 -0600 Subject: [PATCH 364/461] ASoC: soc-acpi: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 6cbbeed9cdd0..655e4e010cc8 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,8 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @asoc_plat_name: ASoC platform name, used for binding machine drivers - * if non NULL * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ @@ -102,7 +100,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - const char *asoc_plat_name; struct platform_device * (*new_mach_data)(void *pdata); }; From b3d8f7cad1b41411de443018cc5323070db06ab2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:57 -0600 Subject: [PATCH 365/461] ASoC: soc-acpi: remove new_mach_data field We never used this field (or in older SOF implementations), let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 655e4e010cc8..35b38e41e5b2 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,7 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { @@ -100,7 +99,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - struct platform_device * (*new_mach_data)(void *pdata); }; #define SND_SOC_ACPI_MAX_CODECS 3 From 932a81519572156a88dbc2349d183c603446f9c4 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Wed, 13 Feb 2019 00:57:51 -0200 Subject: [PATCH 366/461] ALSA: pcm: Comment why read blocks when PCM is not running This avoids bringing back the problem introduced by 62ba568f7aef ("ALSA: pcm: Return 0 when size < start_threshold in capture") and fixed in 00a399cad1a0 ("ALSA: pcm: Revert capture stream behavior change in blocking mode"), which prevented the user from starting capture from another thread. Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index bcb06bd3d81d..345ab1ab2cac 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2176,6 +2176,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); + /* + * If size < start_threshold, wait indefinitely. Another + * thread may start capture + */ if (!is_playback && runtime->status->state == SNDRV_PCM_STATE_PREPARED && size >= runtime->start_threshold) { From 7196c64c7d0c6d421c9bb721d8d66c6d0edc5385 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:22 +0100 Subject: [PATCH 367/461] ASoC: samsung: i2s: Restore support for the secondary PCM This patch introduces again registration of additional platform device as we still need it for registering the secondary dmaengine PCM component. This patch in most part is a revert of changes done in commit be2c92eb64023e ("ASoC: samsung: i2s: Remove virtual device for secondary DAI") Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 52 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 455bc65d115a..cc983afae735 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -109,6 +109,7 @@ static DEFINE_SPINLOCK(lock); struct samsung_i2s_priv { struct platform_device *pdev; + struct platform_device *pdev_sec; /* Spinlock protecting access to the device's registers */ spinlock_t spinlock; @@ -1306,6 +1307,34 @@ static int i2s_register_clock_provider(struct platform_device *pdev) return ret; } +/* Create platform device for the secondary PCM */ +static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_register_simple("samsung-i2s-sec", -1, NULL, 0); + if (!pdev) + return -ENOMEM; + + ret = device_attach(&pdev->dev); + if (ret < 0) { + dev_info(&pdev->dev, "device_attach() failed\n"); + return ret; + } + + priv->pdev_sec = pdev; + + return 0; +} + +static void i2s_delete_secondary_device(struct samsung_i2s_priv *priv) +{ + if (priv->pdev_sec) { + platform_device_del(priv->pdev_sec); + priv->pdev_sec = NULL; + } +} static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; @@ -1323,13 +1352,15 @@ static int samsung_i2s_probe(struct platform_device *pdev) i2s_dai_data = (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; + /* Nothing to do if it is the secondary device probe */ + if (!i2s_dai_data) + return 0; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; - quirks &= ~(QUIRK_SEC_DAI | QUIRK_SUPPORTS_IDMA); - num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; priv->pdev = pdev; @@ -1419,8 +1450,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; - ret = samsung_asoc_dma_platform_register(&pdev->dev, - sec_dai->filter, "tx-sec", NULL, NULL); + ret = i2s_create_secondary_device(priv); + if (ret < 0) + goto err_disable_clk; + + ret = samsung_asoc_dma_platform_register(&priv->pdev_sec->dev, + sec_dai->filter, "tx-sec", NULL, + &pdev->dev); if (ret < 0) goto err_disable_clk; @@ -1455,6 +1491,7 @@ err_disable_pm: pm_runtime_disable(&pdev->dev); err_disable_clk: clk_disable_unprepare(pri_dai->clk); + i2s_delete_secondary_device(priv); return ret; } @@ -1463,12 +1500,17 @@ static int samsung_i2s_remove(struct platform_device *pdev) struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); + /* The secondary device has no driver data assigned */ + if (!priv) + return 0; + pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); i2s_unregister_clock_provider(pdev); clk_disable_unprepare(pri_dai->clk); pm_runtime_put_noidle(&pdev->dev); + i2s_delete_secondary_device(priv); return 0; } @@ -1566,6 +1608,8 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { { .name = "samsung-i2s", .driver_data = (kernel_ulong_t)&i2sv3_dai_type, + }, { + .name = "samsung-i2s-sec", }, {}, }; From 89d2e831487682b567525275f89d679793dd53da Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:23 +0100 Subject: [PATCH 368/461] ASoC: samsung: i2s: Move clk supplier data to common driver data structure Having the clocks provider data in struct samsung_i2s_priv, i.e. per the I2S controller instance, rather than per CPU DAI better models the hardware and simplifies the code a little. The clock provider is common for both DAIs. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 68 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 273620914471..fffc76ab60da 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -99,9 +99,7 @@ struct i2s_dai { spinlock_t *lock; - /* Below fields are only valid if this is the primary FIFO */ - struct clk *clk_table[3]; - struct clk_onecell_data clk_data; + struct samsung_i2s_priv *priv; }; /* Lock for cross i/f checks */ @@ -118,6 +116,10 @@ struct samsung_i2s_priv { struct i2s_dai *dai; struct snd_soc_dai_driver *dai_drv; int num_dais; + + /* The clock provider's data */ + struct clk *clk_table[3]; + struct clk_onecell_data clk_data; }; struct i2s_dai *samsung_i2s_get_pri_dai(struct device *dev) @@ -625,11 +627,10 @@ err: return ret; } -static int i2s_set_fmt(struct snd_soc_dai *dai, - unsigned int fmt) +static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = get_other_dai(i2s); int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; u32 mod, tmp = 0; unsigned long flags; @@ -687,8 +688,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * clock configuration assigned in DT is not overwritten. */ - if (i2s->rclk_srcrate == 0 && i2s->clk_data.clks == NULL && - other->clk_data.clks == NULL) + if (i2s->rclk_srcrate == 0 && priv->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -725,8 +725,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, static int i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - struct i2s_dai *other = get_other_dai(i2s); u32 mod, mask = 0, val = 0; struct clk *rclksrc; unsigned long flags; @@ -811,10 +811,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s->frmclk = params_rate(params); - rclksrc = i2s->clk_table[CLK_I2S_RCLK_SRC]; - if (!rclksrc || IS_ERR(rclksrc)) - rclksrc = other->clk_table[CLK_I2S_RCLK_SRC]; - + rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; if (rclksrc && !IS_ERR(rclksrc)) i2s->rclk_srcrate = clk_get_rate(rclksrc); @@ -1221,31 +1218,30 @@ static int i2s_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ -static void i2s_unregister_clocks(struct i2s_dai *i2s) +static void i2s_unregister_clocks(struct samsung_i2s_priv *priv) { int i; - for (i = 0; i < i2s->clk_data.clk_num; i++) { - if (!IS_ERR(i2s->clk_table[i])) - clk_unregister(i2s->clk_table[i]); + for (i = 0; i < priv->clk_data.clk_num; i++) { + if (!IS_ERR(priv->clk_table[i])) + clk_unregister(priv->clk_table[i]); } } -static void i2s_unregister_clock_provider(struct platform_device *pdev) +static void i2s_unregister_clock_provider(struct samsung_i2s_priv *priv) { - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(&pdev->dev); - - of_clk_del_provider(pdev->dev.of_node); - i2s_unregister_clocks(i2s); + of_clk_del_provider(priv->pdev->dev.of_node); + i2s_unregister_clocks(priv); } -static int i2s_register_clock_provider(struct platform_device *pdev) + +static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) { const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" }; const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; const char *p_names[2] = { NULL }; - struct device *dev = &pdev->dev; + struct device *dev = &priv->pdev->dev; struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; @@ -1277,37 +1273,37 @@ static int i2s_register_clock_provider(struct platform_device *pdev) u32 val = readl(i2s->addr + I2SPSR); writel(val | PSR_PSREN, i2s->addr + I2SPSR); - i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, + priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, i2s_clk_name[CLK_I2S_RCLK_SRC], p_names, ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, i2s->addr + I2SMOD, reg_info->rclksrc_off, 1, 0, i2s->lock); - i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, + priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; - i2s->clk_data.clk_num = 2; + priv->clk_data.clk_num = 2; } - i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, + priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, i2s->addr + I2SMOD, reg_info->cdclkcon_off, CLK_GATE_SET_TO_DISABLE, i2s->lock); - i2s->clk_data.clk_num += 1; - i2s->clk_data.clks = i2s->clk_table; + priv->clk_data.clk_num += 1; + priv->clk_data.clks = priv->clk_table; ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, - &i2s->clk_data); + &priv->clk_data); if (ret < 0) { dev_err(dev, "failed to add clock provider: %d\n", ret); - i2s_unregister_clocks(i2s); + i2s_unregister_clocks(priv); } return ret; @@ -1426,6 +1422,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; + pri_dai->priv = priv; if (quirks & QUIRK_PRI_6CHAN) pri_dai->drv->playback.channels_max = 6; @@ -1454,6 +1451,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; + sec_dai->priv = priv; pri_dai->sec_dai = sec_dai; ret = i2s_create_secondary_device(priv); @@ -1485,11 +1483,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - ret = i2s_register_clock_provider(pdev); + ret = i2s_register_clock_provider(priv); if (ret < 0) goto err_disable_pm; - pri_dai->op_clk = clk_get_parent(pri_dai->clk_table[CLK_I2S_RCLK_SRC]); + pri_dai->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); return 0; @@ -1513,7 +1511,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - i2s_unregister_clock_provider(pdev); + i2s_unregister_clock_provider(priv); clk_disable_unprepare(pri_dai->clk); pm_runtime_put_noidle(&pdev->dev); i2s_delete_secondary_device(priv); From 64aba9bca5bd8d0957b0410bdfa192afb1fcb267 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:24 +0100 Subject: [PATCH 369/461] ASoC: samsung: i2s: Add widgets and routes for DPCM support This patch adds DAPM widgets required to model the internal mixer of the I2S controller merging audio streams from the primary and from the secondary PCM interface. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index fffc76ab60da..29bcfca20572 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1116,8 +1116,31 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = { .delay = i2s_delay, }; +static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = { + /* Backend DAI */ + SND_SOC_DAPM_AIF_OUT("Mixer DAI TX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("Mixer DAI RX", NULL, 0, SND_SOC_NOPM, 0, 0), + + /* Playback Mixer */ + SND_SOC_DAPM_MIXER("Playback Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { + { "Playback Mixer", NULL, "Primary" }, + { "Playback Mixer", NULL, "Secondary" }, + + { "Mixer DAI TX", NULL, "Playback Mixer" }, + { "Playback Mixer", NULL, "Mixer DAI RX" }, +}; + static const struct snd_soc_component_driver samsung_i2s_component = { - .name = "samsung-i2s", + .name = "samsung-i2s", + + .dapm_widgets = samsung_i2s_widgets, + .num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets), + + .dapm_routes = samsung_i2s_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(samsung_i2s_dapm_routes), }; #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ @@ -1129,6 +1152,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, int num_dais) { static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" }; + static const char *stream_names[] = { "Primary", "Secondary" }; struct snd_soc_dai_driver *dai_drv; struct i2s_dai *dai; int i; @@ -1158,6 +1182,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, dai_drv->playback.channels_max = 2; dai_drv->playback.rates = i2s_dai_data->pcm_rates; dai_drv->playback.formats = SAMSUNG_I2S_FMTS; + dai_drv->playback.stream_name = stream_names[i]; dai_drv->id = i + 1; dai_drv->name = dai_names[i]; From b5d015e68e6ce36e0373cda3537009aaa96b5902 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:25 +0100 Subject: [PATCH 370/461] ASoC: samsung: i2s: Move core clk to the driver common data structure The core clock is also common for both CPU DAIs so move it to the driver's private data structure. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 29bcfca20572..159c19fdb662 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -71,8 +71,6 @@ struct i2s_dai { * 0 indicates CPU driver is free to choose any value. */ unsigned rfs, bfs; - /* I2S Controller's core clock */ - struct clk *clk; /* Clock for generating I2S signals */ struct clk *op_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ @@ -117,6 +115,9 @@ struct samsung_i2s_priv { struct snd_soc_dai_driver *dai_drv; int num_dais; + /* The I2S controller's core clock */ + struct clk *clk; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -1205,6 +1206,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, #ifdef CONFIG_PM static int i2s_runtime_suspend(struct device *dev) { + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); @@ -1213,24 +1215,25 @@ static int i2s_runtime_suspend(struct device *dev) if (i2s->op_clk) clk_disable_unprepare(i2s->op_clk); - clk_disable_unprepare(i2s->clk); + clk_disable_unprepare(priv->clk); return 0; } static int i2s_runtime_resume(struct device *dev) { + struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; - ret = clk_prepare_enable(i2s->clk); + ret = clk_prepare_enable(priv->clk); if (ret) return ret; if (i2s->op_clk) { ret = clk_prepare_enable(i2s->op_clk); if (ret) { - clk_disable_unprepare(i2s->clk); + clk_disable_unprepare(priv->clk); return ret; } } @@ -1428,13 +1431,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) regs_base = res->start; - pri_dai->clk = devm_clk_get(&pdev->dev, "iis"); - if (IS_ERR(pri_dai->clk)) { + priv->clk = devm_clk_get(&pdev->dev, "iis"); + if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "Failed to get iis clock\n"); - return PTR_ERR(pri_dai->clk); + return PTR_ERR(priv->clk); } - ret = clk_prepare_enable(pri_dai->clk); + ret = clk_prepare_enable(priv->clk); if (ret != 0) { dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); return ret; @@ -1472,7 +1475,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.addr_width = 4; sec_dai->addr = pri_dai->addr; - sec_dai->clk = pri_dai->clk; sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; @@ -1519,7 +1521,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) err_disable_pm: pm_runtime_disable(&pdev->dev); err_disable_clk: - clk_disable_unprepare(pri_dai->clk); + clk_disable_unprepare(priv->clk); i2s_delete_secondary_device(priv); return ret; } @@ -1527,7 +1529,6 @@ err_disable_clk: static int samsung_i2s_remove(struct platform_device *pdev) { struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev); - struct i2s_dai *pri_dai = samsung_i2s_get_pri_dai(&pdev->dev); /* The secondary device has no driver data assigned */ if (!priv) @@ -1537,7 +1538,7 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); i2s_unregister_clock_provider(priv); - clk_disable_unprepare(pri_dai->clk); + clk_disable_unprepare(priv->clk); pm_runtime_put_noidle(&pdev->dev); i2s_delete_secondary_device(priv); From 3b0fa51ffd827b66f4362397acdfb9742c609b13 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:26 +0100 Subject: [PATCH 371/461] ASoC: samsung: i2s: Move opclk data to common driver data structure The clock for generating I2S signals is also common for both CPU DAIs so move it to the driver's common data structure. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 70 +++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 159c19fdb662..d8414d781f83 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -62,8 +62,6 @@ struct i2s_dai { struct platform_device *pdev; /* Memory mapped SFR region */ void __iomem *addr; - /* Rate of RCLK source clock */ - unsigned long rclk_srcrate; /* Frame Clock */ unsigned frmclk; /* @@ -71,8 +69,6 @@ struct i2s_dai { * 0 indicates CPU driver is free to choose any value. */ unsigned rfs, bfs; - /* Clock for generating I2S signals */ - struct clk *op_clk; /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */ struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ @@ -118,6 +114,12 @@ struct samsung_i2s_priv { /* The I2S controller's core clock */ struct clk *clk; + /* Clock for generating I2S signals */ + struct clk *op_clk; + + /* Rate of RCLK source clock */ + unsigned long rclk_srcrate; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -496,9 +498,10 @@ static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) writel(readl(fic) & ~flush, fic); } -static int i2s_set_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int rfs, int dir) +static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, + int dir) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; @@ -554,44 +557,39 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, clk_id = 1; if (!any_active(i2s)) { - if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { + if (priv->op_clk && !IS_ERR(priv->op_clk)) { if ((clk_id && !(mod & rsrc_mask)) || (!clk_id && (mod & rsrc_mask))) { - clk_disable_unprepare(i2s->op_clk); - clk_put(i2s->op_clk); + clk_disable_unprepare(priv->op_clk); + clk_put(priv->op_clk); } else { - i2s->rclk_srcrate = - clk_get_rate(i2s->op_clk); + priv->rclk_srcrate = + clk_get_rate(priv->op_clk); goto done; } } if (clk_id) - i2s->op_clk = clk_get(&i2s->pdev->dev, + priv->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk1"); else - i2s->op_clk = clk_get(&i2s->pdev->dev, + priv->op_clk = clk_get(&i2s->pdev->dev, "i2s_opclk0"); - if (WARN_ON(IS_ERR(i2s->op_clk))) { - ret = PTR_ERR(i2s->op_clk); - i2s->op_clk = NULL; + if (WARN_ON(IS_ERR(priv->op_clk))) { + ret = PTR_ERR(priv->op_clk); + priv->op_clk = NULL; goto err; } - ret = clk_prepare_enable(i2s->op_clk); + ret = clk_prepare_enable(priv->op_clk); if (ret) { - clk_put(i2s->op_clk); - i2s->op_clk = NULL; + clk_put(priv->op_clk); + priv->op_clk = NULL; goto err; } - i2s->rclk_srcrate = clk_get_rate(i2s->op_clk); + priv->rclk_srcrate = clk_get_rate(priv->op_clk); - /* Over-ride the other's */ - if (other) { - other->op_clk = i2s->op_clk; - other->rclk_srcrate = i2s->rclk_srcrate; - } } else if ((!clk_id && (mod & rsrc_mask)) || (clk_id && !(mod & rsrc_mask))) { dev_err(&i2s->pdev->dev, @@ -600,8 +598,6 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, goto err; } else { /* Call can't be on the active DAI */ - i2s->op_clk = other->op_clk; - i2s->rclk_srcrate = other->rclk_srcrate; goto done; } @@ -689,7 +685,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * clock configuration assigned in DT is not overwritten. */ - if (i2s->rclk_srcrate == 0 && priv->clk_data.clks == NULL) + if (priv->rclk_srcrate == 0 && priv->clk_data.clks == NULL) i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0, 0, SND_SOC_CLOCK_IN); break; @@ -814,7 +810,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC]; if (rclksrc && !IS_ERR(rclksrc)) - i2s->rclk_srcrate = clk_get_rate(rclksrc); + priv->rclk_srcrate = clk_get_rate(rclksrc); return 0; } @@ -872,6 +868,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, static int config_setup(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; struct i2s_dai *other = get_other_dai(i2s); unsigned rfs, bfs, blc; u32 psr; @@ -920,11 +917,11 @@ static int config_setup(struct i2s_dai *i2s) return 0; if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { - psr = i2s->rclk_srcrate / i2s->frmclk / rfs; + psr = priv->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n", - i2s->rclk_srcrate, psr, rfs, bfs); + priv->rclk_srcrate, psr, rfs, bfs); } return 0; @@ -1067,7 +1064,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; i2s->bfs = 0; - i2s->rclk_srcrate = 0; spin_lock_irqsave(i2s->lock, flags); i2s_txctrl(i2s, 0); @@ -1213,8 +1209,8 @@ static int i2s_runtime_suspend(struct device *dev) i2s->suspend_i2scon = readl(i2s->addr + I2SCON); i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); - if (i2s->op_clk) - clk_disable_unprepare(i2s->op_clk); + if (priv->op_clk) + clk_disable_unprepare(priv->op_clk); clk_disable_unprepare(priv->clk); return 0; @@ -1230,8 +1226,8 @@ static int i2s_runtime_resume(struct device *dev) if (ret) return ret; - if (i2s->op_clk) { - ret = clk_prepare_enable(i2s->op_clk); + if (priv->op_clk) { + ret = clk_prepare_enable(priv->op_clk); if (ret) { clk_disable_unprepare(priv->clk); return ret; @@ -1514,7 +1510,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_pm; - pri_dai->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); + priv->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]); return 0; From 81bcbf2c72948d36ba431ac0812d7d7c3d8da0ce Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:27 +0100 Subject: [PATCH 372/461] ASoC: samsung: i2s: Move registers cache to common driver data structure There is no need to keep the PM suspend/resume register cache separate for each DAI as those registers are common, move related i2s_dai data structure to the driver's common data structure. This will allow us to simplify the code a little eventually and to make it easier to follow. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d8414d781f83..72f0cb7abb30 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -86,9 +86,6 @@ struct i2s_dai { struct snd_dmaengine_dai_dma_data idma_playback; dma_filter_fn filter; u32 quirks; - u32 suspend_i2smod; - u32 suspend_i2scon; - u32 suspend_i2spsr; const struct samsung_i2s_variant_regs *variant_regs; spinlock_t *lock; @@ -120,6 +117,11 @@ struct samsung_i2s_priv { /* Rate of RCLK source clock */ unsigned long rclk_srcrate; + /* Cache of selected I2S registers for system suspend */ + u32 suspend_i2smod; + u32 suspend_i2scon; + u32 suspend_i2spsr; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -1205,9 +1207,9 @@ static int i2s_runtime_suspend(struct device *dev) struct samsung_i2s_priv *priv = dev_get_drvdata(dev); struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); - i2s->suspend_i2smod = readl(i2s->addr + I2SMOD); - i2s->suspend_i2scon = readl(i2s->addr + I2SCON); - i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR); + priv->suspend_i2smod = readl(i2s->addr + I2SMOD); + priv->suspend_i2scon = readl(i2s->addr + I2SCON); + priv->suspend_i2spsr = readl(i2s->addr + I2SPSR); if (priv->op_clk) clk_disable_unprepare(priv->op_clk); @@ -1234,9 +1236,9 @@ static int i2s_runtime_resume(struct device *dev) } } - writel(i2s->suspend_i2scon, i2s->addr + I2SCON); - writel(i2s->suspend_i2smod, i2s->addr + I2SMOD); - writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR); + writel(priv->suspend_i2scon, i2s->addr + I2SCON); + writel(priv->suspend_i2smod, i2s->addr + I2SMOD); + writel(priv->suspend_i2spsr, i2s->addr + I2SPSR); return 0; } From 51bef0f378f39ed0604296354b964e3919161396 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 13 Feb 2019 01:43:32 +0000 Subject: [PATCH 373/461] ASoC: cs35l36: Remove unused including Remove including that don't need it. Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index 4f880a678812..e374fffb7e17 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include From 03bf3aeb03a8562a7ad6ed629e49953f132217c1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 13 Feb 2019 06:29:44 +0000 Subject: [PATCH 374/461] ASoC: mediatek: mt8183: make some functions static Fixes the following sparse warnings: sound/soc/mediatek/mt8183/mt8183-dai-i2s.c:966:5: warning: symbol 'mt8183_dai_i2s_get_share' was not declared. Should it be static? sound/soc/mediatek/mt8183/mt8183-dai-i2s.c:986:5: warning: symbol 'mt8183_dai_i2s_set_priv' was not declared. Should it be static? Fixes: a94aec035a12 ("ASoC: mediatek: mt8183: add platform driver") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-dai-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c index c25024f72e72..777e93d70bea 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -963,7 +963,7 @@ static const struct mtk_afe_i2s_priv mt8183_i2s_priv[DAI_I2S_NUM] = { }, }; -int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) +static int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) { struct mt8183_afe_private *afe_priv = afe->platform_priv; const struct device_node *of_node = afe->dev->of_node; @@ -983,7 +983,7 @@ int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) return 0; } -int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) +static int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) { struct mt8183_afe_private *afe_priv = afe->platform_priv; struct mtk_afe_i2s_priv *i2s_priv; From a4cbb465bcc98f1c5740c887d4be3a68f1a47279 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 13 Feb 2019 06:29:56 +0000 Subject: [PATCH 375/461] ASoC: cros_ec_codec: Make symbol 'cros_ec_dai' static Fixes the following sparse warning: sound/soc/codecs/cros_ec_codec.c:209:27: warning: symbol 'cros_ec_dai' was not declared. Should it be static? Fixes: b291f42a3718 ("ASoC: cros_ec_codec: Add codec driver for Cros EC") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index b14100b6a939..99a3af8a15ff 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -206,7 +206,7 @@ static const struct snd_soc_dai_ops cros_ec_i2s_dai_ops = { .set_fmt = cros_ec_i2s_set_dai_fmt, }; -struct snd_soc_dai_driver cros_ec_dai[] = { +static struct snd_soc_dai_driver cros_ec_dai[] = { { .name = "cros_ec_codec I2S", .id = 0, From a06702ca023feccb7c1a5171987f5cac959427ed Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 14 Feb 2019 02:10:33 +0000 Subject: [PATCH 376/461] ALSA: es1688: Remove set but not used variable 'hw' Fixes gcc '-Wunused-but-set-variable' warning: sound/isa/es1688/es1688_lib.c: In function 'snd_es1688_probe': sound/isa/es1688/es1688_lib.c:124:31: warning: variable 'hw' set but not used [-Wunused-but-set-variable] unsigned short major, minor, hw; ^ Signed-off-by: YueHaibing Signed-off-by: Takashi Iwai --- sound/isa/es1688/es1688_lib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index da341969e650..1d9556c045e9 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -121,7 +121,7 @@ EXPORT_SYMBOL(snd_es1688_reset); static int snd_es1688_probe(struct snd_es1688 *chip) { unsigned long flags; - unsigned short major, minor, hw; + unsigned short major, minor; int i; /* @@ -166,14 +166,12 @@ static int snd_es1688_probe(struct snd_es1688 *chip) if (!chip->version) return -ENODEV; /* probably SB */ - hw = ES1688_HW_AUTO; switch (chip->version & 0xfff0) { case 0x4880: snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, " "but driver is in another place\n", chip->port); return -ENODEV; case 0x6880: - hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688; break; default: snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip " From e2e16fa6a32dcf0a340cb2b6155a44d1bf5858ef Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:35 +0100 Subject: [PATCH 377/461] ASoC: samsung: i2s: Move SFR pointer to common driver data structure The SFR region is common for both DAIs so move related data structure field from struct i2s_dai to the common driver data structure. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 106 ++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 72f0cb7abb30..3f8955608a94 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -60,8 +60,7 @@ struct samsung_i2s_dai_data { struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; - /* Memory mapped SFR region */ - void __iomem *addr; + /* Frame Clock */ unsigned frmclk; /* @@ -100,6 +99,9 @@ struct samsung_i2s_priv { struct platform_device *pdev; struct platform_device *pdev_sec; + /* Memory mapped SFR region */ + void __iomem *addr; + /* Spinlock protecting access to the device's registers */ spinlock_t spinlock; @@ -143,7 +145,9 @@ static inline bool is_secondary(struct i2s_dai *i2s) /* If operating in SoC-Slave mode */ static inline bool is_slave(struct i2s_dai *i2s) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + + u32 mod = readl(priv->addr + I2SMOD); return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; } @@ -155,7 +159,7 @@ static inline bool tx_active(struct i2s_dai *i2s) if (!i2s) return false; - active = readl(i2s->addr + I2SCON); + active = readl(i2s->priv->addr + I2SCON); if (is_secondary(i2s)) active &= CON_TXSDMA_ACTIVE; @@ -193,7 +197,7 @@ static inline bool rx_active(struct i2s_dai *i2s) if (!i2s) return false; - active = readl(i2s->addr + I2SCON) & CON_RXDMA_ACTIVE; + active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE; return active ? true : false; } @@ -256,8 +260,10 @@ static inline bool is_manager(struct i2s_dai *i2s) /* Read RCLK of I2S (in multiples of LRCLK) */ static inline unsigned get_rfs(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; u32 rfs; - rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; + + rfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->rfs_off; rfs &= i2s->variant_regs->rfs_mask; switch (rfs) { @@ -275,7 +281,8 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) /* Write RCLK of I2S (in multiples of LRCLK) */ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + u32 mod = readl(priv->addr + I2SMOD); int rfs_shift = i2s->variant_regs->rfs_off; mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); @@ -307,14 +314,16 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) break; } - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); } /* Read Bit-Clock of I2S (in multiples of LRCLK) */ static inline unsigned get_bfs(struct i2s_dai *i2s) { + struct samsung_i2s_priv *priv = i2s->priv; u32 bfs; - bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; + + bfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->bfs_off; bfs &= i2s->variant_regs->bfs_mask; switch (bfs) { @@ -333,7 +342,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) /* Write Bit-Clock of I2S (in multiples of LRCLK) */ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { - u32 mod = readl(i2s->addr + I2SMOD); + struct samsung_i2s_priv *priv = i2s->priv; + u32 mod = readl(priv->addr + I2SMOD); int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; int bfs_shift = i2s->variant_regs->bfs_off; @@ -378,13 +388,13 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) return; } - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); } /* Sample-Size */ static inline int get_blc(struct i2s_dai *i2s) { - int blc = readl(i2s->addr + I2SMOD); + int blc = readl(i2s->priv->addr + I2SMOD); blc = (blc >> 13) & 0x3; @@ -398,7 +408,8 @@ static inline int get_blc(struct i2s_dai *i2s) /* TX Channel Control */ static void i2s_txctrl(struct i2s_dai *i2s, int on) { - void __iomem *addr = i2s->addr; + struct samsung_i2s_priv *priv = i2s->priv; + void __iomem *addr = priv->addr; int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -448,7 +459,8 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) /* RX Channel Control */ static void i2s_rxctrl(struct i2s_dai *i2s, int on) { - void __iomem *addr = i2s->addr; + struct samsung_i2s_priv *priv = i2s->priv; + void __iomem *addr = priv->addr; int txr_off = i2s->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -485,9 +497,9 @@ static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush) return; if (is_secondary(i2s)) - fic = i2s->addr + I2SFICS; + fic = i2s->priv->addr + I2SFICS; else - fic = i2s->addr + I2SFIC; + fic = i2s->priv->addr + I2SFIC; /* Flush the FIFO */ writel(readl(fic) | flush, fic); @@ -516,7 +528,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, pm_runtime_get_sync(dai->dev); spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); switch (clk_id) { @@ -613,9 +625,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, } spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); done: pm_runtime_put(dai->dev); @@ -698,7 +710,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) pm_runtime_get_sync(dai->dev); spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this * channel. @@ -714,7 +726,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); pm_runtime_put(dai->dev); @@ -801,9 +813,9 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, } spin_lock_irqsave(i2s->lock, flags); - mod = readl(i2s->addr + I2SMOD); + mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; - writel(mod, i2s->addr + I2SMOD); + writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(i2s->lock, flags); snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); @@ -837,7 +849,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, i2s->mode |= DAI_MANAGER; if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) - writel(CON_RSTCLR, i2s->addr + I2SCON); + writel(CON_RSTCLR, i2s->priv->addr + I2SCON); spin_unlock_irqrestore(&lock, flags); @@ -920,7 +932,7 @@ static int config_setup(struct i2s_dai *i2s) if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { psr = priv->rclk_srcrate / i2s->frmclk / rfs; - writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR); + writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n", priv->rclk_srcrate, psr, rfs, bfs); @@ -1008,8 +1020,9 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, static snd_pcm_sframes_t i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); - u32 reg = readl(i2s->addr + I2SFIC); + u32 reg = readl(priv->addr + I2SFIC); snd_pcm_sframes_t delay; const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; @@ -1018,7 +1031,7 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) delay = FIC_RXCOUNT(reg); else if (is_secondary(i2s)) - delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); + delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS)); else delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; @@ -1042,6 +1055,7 @@ static int i2s_resume(struct snd_soc_dai *dai) static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; @@ -1056,10 +1070,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) &i2s->dma_capture); if (i2s->quirks & QUIRK_NEED_RSTCLR) - writel(CON_RSTCLR, i2s->addr + I2SCON); + writel(CON_RSTCLR, priv->addr + I2SCON); if (i2s->quirks & QUIRK_SUPPORTS_IDMA) - idma_reg_addr_init(i2s->addr, + idma_reg_addr_init(priv->addr, i2s->sec_dai->idma_playback.addr); } @@ -1086,6 +1100,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); unsigned long flags; @@ -1094,7 +1109,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { spin_lock_irqsave(i2s->lock, flags); - writel(0, i2s->addr + I2SCON); + writel(0, priv->addr + I2SCON); spin_unlock_irqrestore(i2s->lock, flags); } } @@ -1205,11 +1220,10 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, static int i2s_runtime_suspend(struct device *dev) { struct samsung_i2s_priv *priv = dev_get_drvdata(dev); - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); - priv->suspend_i2smod = readl(i2s->addr + I2SMOD); - priv->suspend_i2scon = readl(i2s->addr + I2SCON); - priv->suspend_i2spsr = readl(i2s->addr + I2SPSR); + priv->suspend_i2smod = readl(priv->addr + I2SMOD); + priv->suspend_i2scon = readl(priv->addr + I2SCON); + priv->suspend_i2spsr = readl(priv->addr + I2SPSR); if (priv->op_clk) clk_disable_unprepare(priv->op_clk); @@ -1221,7 +1235,6 @@ static int i2s_runtime_suspend(struct device *dev) static int i2s_runtime_resume(struct device *dev) { struct samsung_i2s_priv *priv = dev_get_drvdata(dev); - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); int ret; ret = clk_prepare_enable(priv->clk); @@ -1236,9 +1249,9 @@ static int i2s_runtime_resume(struct device *dev) } } - writel(priv->suspend_i2scon, i2s->addr + I2SCON); - writel(priv->suspend_i2smod, i2s->addr + I2SMOD); - writel(priv->suspend_i2spsr, i2s->addr + I2SPSR); + writel(priv->suspend_i2scon, priv->addr + I2SCON); + writel(priv->suspend_i2smod, priv->addr + I2SMOD); + writel(priv->suspend_i2spsr, priv->addr + I2SPSR); return 0; } @@ -1296,21 +1309,21 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { /* Activate the prescaler */ - u32 val = readl(i2s->addr + I2SPSR); - writel(val | PSR_PSREN, i2s->addr + I2SPSR); + u32 val = readl(priv->addr + I2SPSR); + writel(val | PSR_PSREN, priv->addr + I2SPSR); priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev, i2s_clk_name[CLK_I2S_RCLK_SRC], p_names, ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, - i2s->addr + I2SMOD, reg_info->rclksrc_off, + priv->addr + I2SMOD, reg_info->rclksrc_off, 1, 0, i2s->lock); priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, - i2s->addr + I2SPSR, 8, 6, 0, i2s->lock); + priv->addr + I2SPSR, 8, 6, 0, i2s->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; priv->clk_data.clk_num = 2; @@ -1319,7 +1332,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev, i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, - i2s->addr + I2SMOD, reg_info->cdclkcon_off, + priv->addr + I2SMOD, reg_info->cdclkcon_off, CLK_GATE_SET_TO_DISABLE, i2s->lock); priv->clk_data.clk_num += 1; @@ -1423,9 +1436,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pri_dai->addr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pri_dai->addr)) - return PTR_ERR(pri_dai->addr); + priv->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->addr)) + return PTR_ERR(priv->addr); regs_base = res->start; @@ -1472,7 +1485,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } sec_dai->dma_playback.addr_width = 4; - sec_dai->addr = pri_dai->addr; sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; From 9d7939c929413d0f9effef599a0ca73300b494be Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:36 +0100 Subject: [PATCH 378/461] ASoC: samsung: i2s: Drop spinlock pointer from i2s_dai data structure As we now have the 'priv' pointer in most of the places we can use priv->lock directly, dropping extra indirection in the SFR region spinlock access. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 51 +++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 3f8955608a94..cf8615e23879 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -87,8 +87,6 @@ struct i2s_dai { u32 quirks; const struct samsung_i2s_variant_regs *variant_regs; - spinlock_t *lock; - struct samsung_i2s_priv *priv; }; @@ -103,7 +101,7 @@ struct samsung_i2s_priv { void __iomem *addr; /* Spinlock protecting access to the device's registers */ - spinlock_t spinlock; + spinlock_t lock; /* CPU DAIs and their corresponding drivers */ struct i2s_dai *dai; @@ -527,9 +525,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); switch (clk_id) { case SAMSUNG_I2S_OPCLK: @@ -624,11 +622,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, goto err; } - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); done: pm_runtime_put(dai->dev); @@ -709,7 +707,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this @@ -717,7 +715,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) */ if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); @@ -727,7 +725,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); return 0; @@ -812,11 +810,11 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); mod = readl(priv->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, priv->addr + I2SMOD); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); @@ -944,6 +942,7 @@ static int config_setup(struct i2s_dai *i2s) static int i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); struct snd_soc_pcm_runtime *rtd = substream->private_data; struct i2s_dai *i2s = to_info(rtd->cpu_dai); @@ -954,10 +953,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (config_setup(i2s)) { - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return -EINVAL; } @@ -966,12 +965,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream, else i2s_txctrl(i2s, 1); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); if (capture) { i2s_rxctrl(i2s, 0); @@ -981,7 +980,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, i2s_fifo(i2s, FIC_TXFLUSH); } - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); pm_runtime_put(dai->dev); break; } @@ -1081,13 +1080,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) i2s->rfs = 0; i2s->bfs = 0; - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); i2s_txctrl(i2s, 0); i2s_rxctrl(i2s, 0); i2s_fifo(i2s, FIC_TXFLUSH); i2s_fifo(other, FIC_TXFLUSH); i2s_fifo(i2s, FIC_RXFLUSH); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); /* Gate CDCLK by default */ if (!is_opened(other)) @@ -1108,9 +1107,9 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { - spin_lock_irqsave(i2s->lock, flags); + spin_lock_irqsave(&priv->lock, flags); writel(0, priv->addr + I2SCON); - spin_unlock_irqrestore(i2s->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); } } @@ -1317,13 +1316,13 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) ARRAY_SIZE(p_names), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, priv->addr + I2SMOD, reg_info->rclksrc_off, - 1, 0, i2s->lock); + 1, 0, &priv->lock); priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev, i2s_clk_name[CLK_I2S_RCLK_PSR], i2s_clk_name[CLK_I2S_RCLK_SRC], CLK_SET_RATE_PARENT, - priv->addr + I2SPSR, 8, 6, 0, i2s->lock); + priv->addr + I2SPSR, 8, 6, 0, &priv->lock); p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR]; priv->clk_data.clk_num = 2; @@ -1333,7 +1332,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) i2s_clk_name[CLK_I2S_CDCLK], p_names[0], CLK_SET_RATE_PARENT, priv->addr + I2SMOD, reg_info->cdclkcon_off, - CLK_GATE_SET_TO_DISABLE, i2s->lock); + CLK_GATE_SET_TO_DISABLE, &priv->lock); priv->clk_data.clk_num += 1; priv->clk_data.clks = priv->clk_table; @@ -1411,8 +1410,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; - spin_lock_init(&priv->spinlock); - pri_dai->lock = &priv->spinlock; + spin_lock_init(&priv->lock); if (!np) { if (i2s_pdata == NULL) { @@ -1474,7 +1472,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (quirks & QUIRK_SEC_DAI) { sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; - sec_dai->lock = &priv->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; sec_dai->dma_playback.chan_name = "tx-sec"; From 5bfaeddc269401677d61f6d7d40eec76f40e6d4c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:37 +0100 Subject: [PATCH 379/461] ASoC: samsung: i2s: Move IP variant data to common driver data structure The IP variant data is another thing common for both DAIs, move it to the driver's common data structure. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index cf8615e23879..0c4c4de8c7e9 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -85,7 +85,6 @@ struct i2s_dai { struct snd_dmaengine_dai_dma_data idma_playback; dma_filter_fn filter; u32 quirks; - const struct samsung_i2s_variant_regs *variant_regs; struct samsung_i2s_priv *priv; }; @@ -122,6 +121,8 @@ struct samsung_i2s_priv { u32 suspend_i2scon; u32 suspend_i2spsr; + const struct samsung_i2s_variant_regs *variant_regs; + /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; @@ -146,7 +147,7 @@ static inline bool is_slave(struct i2s_dai *i2s) struct samsung_i2s_priv *priv = i2s->priv; u32 mod = readl(priv->addr + I2SMOD); - return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; + return (mod & (1 << priv->variant_regs->mss_off)) ? true : false; } /* If this interface of the controller is transmitting data */ @@ -261,8 +262,8 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) struct samsung_i2s_priv *priv = i2s->priv; u32 rfs; - rfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->rfs_off; - rfs &= i2s->variant_regs->rfs_mask; + rfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->rfs_off; + rfs &= priv->variant_regs->rfs_mask; switch (rfs) { case 7: return 192; @@ -281,9 +282,9 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) { struct samsung_i2s_priv *priv = i2s->priv; u32 mod = readl(priv->addr + I2SMOD); - int rfs_shift = i2s->variant_regs->rfs_off; + int rfs_shift = priv->variant_regs->rfs_off; - mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); + mod &= ~(priv->variant_regs->rfs_mask << rfs_shift); switch (rfs) { case 192: @@ -321,8 +322,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) struct samsung_i2s_priv *priv = i2s->priv; u32 bfs; - bfs = readl(priv->addr + I2SMOD) >> i2s->variant_regs->bfs_off; - bfs &= i2s->variant_regs->bfs_mask; + bfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->bfs_off; + bfs &= priv->variant_regs->bfs_mask; switch (bfs) { case 8: return 256; @@ -343,7 +344,7 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) struct samsung_i2s_priv *priv = i2s->priv; u32 mod = readl(priv->addr + I2SMOD); int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; - int bfs_shift = i2s->variant_regs->bfs_off; + int bfs_shift = priv->variant_regs->bfs_off; /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ if (!tdm && bfs > 48) { @@ -351,7 +352,7 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) return; } - mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift); + mod &= ~(priv->variant_regs->bfs_mask << bfs_shift); switch (bfs) { case 48: @@ -408,7 +409,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) { struct samsung_i2s_priv *priv = i2s->priv; void __iomem *addr = priv->addr; - int txr_off = i2s->variant_regs->txr_off; + int txr_off = priv->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -459,7 +460,7 @@ static void i2s_rxctrl(struct i2s_dai *i2s, int on) { struct samsung_i2s_priv *priv = i2s->priv; void __iomem *addr = priv->addr; - int txr_off = i2s->variant_regs->txr_off; + int txr_off = priv->variant_regs->txr_off; u32 con = readl(addr + I2SCON); u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); @@ -516,7 +517,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); - const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; + const struct samsung_i2s_variant_regs *i2s_regs = priv->variant_regs; unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; u32 mod, mask, val = 0; @@ -644,9 +645,9 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) u32 mod, tmp = 0; unsigned long flags; - lrp_shift = i2s->variant_regs->lrp_off; - sdf_shift = i2s->variant_regs->sdf_off; - mod_slave = 1 << i2s->variant_regs->mss_off; + lrp_shift = priv->variant_regs->lrp_off; + sdf_shift = priv->variant_regs->sdf_off; + mod_slave = 1 << priv->variant_regs->mss_off; sdf_mask = MOD_SDF_MASK << sdf_shift; lrp_rlow = MOD_LR_RLOW << lrp_shift; @@ -1023,7 +1024,6 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) struct i2s_dai *i2s = to_info(dai); u32 reg = readl(priv->addr + I2SFIC); snd_pcm_sframes_t delay; - const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; WARN_ON(!pm_runtime_active(dai->dev)); @@ -1032,7 +1032,7 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) else if (is_secondary(i2s)) delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS)); else - delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; + delay = (reg >> priv->variant_regs->ftx0cnt_off) & 0x7f; return delay; } @@ -1281,7 +1281,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) const char *p_names[2] = { NULL }; struct device *dev = &priv->pdev->dev; struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); - const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs; + const struct samsung_i2s_variant_regs *reg_info = priv->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; struct clk *rclksrc; int ret, i; @@ -1400,6 +1400,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->variant_regs = i2s_dai_data->i2s_variant_regs; + quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; priv->pdev = pdev; @@ -1458,7 +1460,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_playback.addr_width = 4; pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; - pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; pri_dai->priv = priv; if (quirks & QUIRK_PRI_6CHAN) @@ -1472,7 +1473,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (quirks & QUIRK_SEC_DAI) { sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; - sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; sec_dai->dma_playback.chan_name = "tx-sec"; From 5944170f497c8d8c93704c40d18e794351673a11 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:38 +0100 Subject: [PATCH 380/461] ASoC: samsung: i2s: Move quirks data to common driver data structure The quirk flags are common for the primary and the secondary DAI so move respective field from struct i2s_dai to common driver data structure. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 0c4c4de8c7e9..8f0af4b0f25a 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -84,7 +84,6 @@ struct i2s_dai { struct snd_dmaengine_dai_dma_data dma_capture; struct snd_dmaengine_dai_dma_data idma_playback; dma_filter_fn filter; - u32 quirks; struct samsung_i2s_priv *priv; }; @@ -122,19 +121,13 @@ struct samsung_i2s_priv { u32 suspend_i2spsr; const struct samsung_i2s_variant_regs *variant_regs; + u32 quirks; /* The clock provider's data */ struct clk *clk_table[3]; struct clk_onecell_data clk_data; }; -struct i2s_dai *samsung_i2s_get_pri_dai(struct device *dev) -{ - struct samsung_i2s_priv *priv = dev_get_drvdata(dev); - - return &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; -} - /* Returns true if this is the 'overlay' stereo DAI */ static inline bool is_secondary(struct i2s_dai *i2s) { @@ -343,7 +336,7 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { struct samsung_i2s_priv *priv = i2s->priv; u32 mod = readl(priv->addr + I2SMOD); - int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; + int tdm = priv->quirks & QUIRK_SUPPORTS_TDM; int bfs_shift = priv->variant_regs->bfs_off; /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ @@ -563,7 +556,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */ mask = 1 << i2s_regs->rclksrc_off; - if ((i2s->quirks & QUIRK_NO_MUXPSR) + if ((priv->quirks & QUIRK_NO_MUXPSR) || (clk_id == SAMSUNG_I2S_RCLKSRC_0)) clk_id = 0; else @@ -832,6 +825,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, static int i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; @@ -847,7 +841,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, else i2s->mode |= DAI_MANAGER; - if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) + if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR)) writel(CON_RSTCLR, i2s->priv->addr + I2SCON); spin_unlock_irqrestore(&lock, flags); @@ -929,7 +923,7 @@ static int config_setup(struct i2s_dai *i2s) if (is_slave(i2s)) return 0; - if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { + if (!(priv->quirks & QUIRK_NO_MUXPSR)) { psr = priv->rclk_srcrate / i2s->frmclk / rfs; writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR); dev_dbg(&i2s->pdev->dev, @@ -1068,10 +1062,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); - if (i2s->quirks & QUIRK_NEED_RSTCLR) + if (priv->quirks & QUIRK_NEED_RSTCLR) writel(CON_RSTCLR, priv->addr + I2SCON); - if (i2s->quirks & QUIRK_SUPPORTS_IDMA) + if (priv->quirks & QUIRK_SUPPORTS_IDMA) idma_reg_addr_init(priv->addr, i2s->sec_dai->idma_playback.addr); } @@ -1106,7 +1100,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) pm_runtime_get_sync(dai->dev); if (!is_secondary(i2s)) { - if (i2s->quirks & QUIRK_NEED_RSTCLR) { + if (priv->quirks & QUIRK_NEED_RSTCLR) { spin_lock_irqsave(&priv->lock, flags); writel(0, priv->addr + I2SCON); spin_unlock_irqrestore(&priv->lock, flags); @@ -1280,7 +1274,6 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" }; const char *p_names[2] = { NULL }; struct device *dev = &priv->pdev->dev; - struct i2s_dai *i2s = samsung_i2s_get_pri_dai(dev); const struct samsung_i2s_variant_regs *reg_info = priv->variant_regs; const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)]; struct clk *rclksrc; @@ -1306,7 +1299,7 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) return -ENOMEM; } - if (!(i2s->quirks & QUIRK_NO_MUXPSR)) { + if (!(priv->quirks & QUIRK_NO_MUXPSR)) { /* Activate the prescaler */ u32 val = readl(priv->addr + I2SPSR); writel(val | PSR_PSREN, priv->addr + I2SPSR); @@ -1400,11 +1393,11 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->variant_regs = i2s_dai_data->i2s_variant_regs; - quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; priv->pdev = pdev; + priv->variant_regs = i2s_dai_data->i2s_variant_regs; + priv->quirks = quirks; ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais); if (ret < 0) @@ -1459,7 +1452,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.chan_name = "rx"; pri_dai->dma_playback.addr_width = 4; pri_dai->dma_capture.addr_width = 4; - pri_dai->quirks = quirks; pri_dai->priv = priv; if (quirks & QUIRK_PRI_6CHAN) @@ -1482,7 +1474,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } sec_dai->dma_playback.addr_width = 4; - sec_dai->quirks = quirks; sec_dai->idma_playback.addr = idma_addr; sec_dai->pri_dai = pri_dai; sec_dai->priv = priv; From defc67c6e3638020cc6189d056e0bc187b297068 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:39 +0100 Subject: [PATCH 381/461] ASoC: samsung: i2s: Get rid of a static spinlock This patch makes the spinlock serializing access to the primary/secondary PCM a per I2S controller lock, rather than a global one. There is no need to have a global lock across multiple I2S controllers in the SoC. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 8f0af4b0f25a..692a752b194c 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -88,9 +88,6 @@ struct i2s_dai { struct samsung_i2s_priv *priv; }; -/* Lock for cross i/f checks */ -static DEFINE_SPINLOCK(lock); - struct samsung_i2s_priv { struct platform_device *pdev; struct platform_device *pdev_sec; @@ -101,6 +98,9 @@ struct samsung_i2s_priv { /* Spinlock protecting access to the device's registers */ spinlock_t lock; + /* Lock for cross i/f checks */ + spinlock_t pcm_lock; + /* CPU DAIs and their corresponding drivers */ struct i2s_dai *dai; struct snd_soc_dai_driver *dai_drv; @@ -832,7 +832,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, pm_runtime_get_sync(dai->dev); - spin_lock_irqsave(&lock, flags); + spin_lock_irqsave(&priv->pcm_lock, flags); i2s->mode |= DAI_OPENED; @@ -844,7 +844,7 @@ static int i2s_startup(struct snd_pcm_substream *substream, if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR)) writel(CON_RSTCLR, i2s->priv->addr + I2SCON); - spin_unlock_irqrestore(&lock, flags); + spin_unlock_irqrestore(&priv->pcm_lock, flags); return 0; } @@ -852,11 +852,12 @@ static int i2s_startup(struct snd_pcm_substream *substream, static void i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai); struct i2s_dai *i2s = to_info(dai); struct i2s_dai *other = get_other_dai(i2s); unsigned long flags; - spin_lock_irqsave(&lock, flags); + spin_lock_irqsave(&priv->pcm_lock, flags); i2s->mode &= ~DAI_OPENED; i2s->mode &= ~DAI_MANAGER; @@ -868,7 +869,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, i2s->rfs = 0; i2s->bfs = 0; - spin_unlock_irqrestore(&lock, flags); + spin_unlock_irqrestore(&priv->pcm_lock, flags); pm_runtime_put(dai->dev); } @@ -1406,6 +1407,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1]; spin_lock_init(&priv->lock); + spin_lock_init(&priv->pcm_lock); if (!np) { if (i2s_pdata == NULL) { From bc3cf17b575a7a97b4af7ddcf86133175da7a582 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:40 +0100 Subject: [PATCH 382/461] ASoC: samsung: odroid: Add support for secondary CPU DAI This patch adds DPCM links in order to support the secondary I2S interface. For the secondary PCM interface to be actually available one more entry should be added to the sound-dai property in sound/cpu node in DT. The changes in driver are done in a way so we are backwards compatible with existing DTS/DTB, i.e. if the cpu sound-dai property contains only one entry only one PCM will be registered. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 137 ++++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 39 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index e7b371b07230..18bb3bfe0300 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -17,21 +18,24 @@ struct odroid_priv { struct snd_soc_card card; - struct snd_soc_dai_link dai_link; - struct clk *clk_i2s_bus; struct clk *sclk_i2s; }; -static int odroid_card_startup(struct snd_pcm_substream *substream) +static int odroid_card_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); + return 0; } -static int odroid_card_hw_params(struct snd_pcm_substream *substream, +static const struct snd_soc_ops odroid_card_fe_ops = { + .startup = odroid_card_fe_startup, +}; + +static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -86,19 +90,55 @@ static int odroid_card_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_ops odroid_card_ops = { - .startup = odroid_card_startup, - .hw_params = odroid_card_hw_params, +static const struct snd_soc_ops odroid_card_be_ops = { + .hw_params = odroid_card_be_hw_params, +}; + +static struct snd_soc_dai_link odroid_card_dais[] = { + { + /* Primary FE <-> BE link */ + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .ops = &odroid_card_fe_ops, + .name = "Primary", + .stream_name = "Primary", + .platform_name = "3830000.i2s", + .dynamic = 1, + .dpcm_playback = 1, + }, { + /* BE <-> CODECs link */ + .name = "I2S Mixer", + .cpu_name = "snd-soc-dummy", + .cpu_dai_name = "snd-soc-dummy-dai", + .platform_name = "snd-soc-dummy", + .ops = &odroid_card_be_ops, + .no_pcm = 1, + .dpcm_playback = 1, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + }, { + /* Secondary FE <-> BE link */ + .playback_only = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .ops = &odroid_card_fe_ops, + .name = "Secondary", + .stream_name = "Secondary", + .platform_name = "samsung-i2s-sec", + .dynamic = 1, + .dpcm_playback = 1, + } }; static int odroid_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *cpu, *codec; + struct device_node *cpu, *cpu_dai, *codec; struct odroid_priv *priv; - struct snd_soc_dai_link *link; struct snd_soc_card *card; - int ret; + struct snd_soc_dai_link *link, *codec_link; + int num_pcms, ret, i; + struct of_phandle_args args = {}; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -130,45 +170,67 @@ static int odroid_audio_probe(struct platform_device *pdev) return ret; } - link = &priv->dai_link; - - link->ops = &odroid_card_ops; - link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; - - card->dai_link = &priv->dai_link; - card->num_links = 1; + card->dai_link = odroid_card_dais; + card->num_links = ARRAY_SIZE(odroid_card_dais); cpu = of_get_child_by_name(dev->of_node, "cpu"); codec = of_get_child_by_name(dev->of_node, "codec"); + link = card->dai_link; + codec_link = &card->dai_link[1]; - link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); - if (!link->cpu_of_node) { - dev_err(dev, "Failed parsing cpu/sound-dai property\n"); - return -EINVAL; + /* + * For backwards compatibility create the secondary CPU DAI link only + * if there are 2 CPU DAI entries in the cpu sound-dai property in DT. + */ + num_pcms = of_count_phandle_with_args(cpu, "sound-dai", + "#sound-dai-cells"); + if (num_pcms == 1) + card->num_links--; + + for (i = 0; i < num_pcms; i++, link += 2) { + ret = of_parse_phandle_with_args(cpu, "sound-dai", + "#sound-dai-cells", i, &args); + if (ret < 0) + return ret; + + if (!args.np) { + dev_err(dev, "sound-dai property parse error: %d\n", ret); + return -EINVAL; + } + + ret = snd_soc_get_dai_name(&args, &link->cpu_dai_name); + of_node_put(args.np); + + if (ret < 0) + return ret; } - ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); + of_node_put(cpu); + of_node_put(codec); + + ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); if (ret < 0) goto err_put_codec_n; - link->platform_of_node = link->cpu_of_node; - - link->name = "Primary"; - link->stream_name = link->name; - - - priv->sclk_i2s = of_clk_get_by_name(link->cpu_of_node, "i2s_opclk1"); - if (IS_ERR(priv->sclk_i2s)) { - ret = PTR_ERR(priv->sclk_i2s); - goto err_put_i2s_n; + /* Set capture capability only for boards with the MAX98090 CODEC */ + if (codec_link->num_codecs > 1) { + card->dai_link[0].dpcm_capture = 1; + card->dai_link[1].dpcm_capture = 1; } - priv->clk_i2s_bus = of_clk_get_by_name(link->cpu_of_node, "iis"); + priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); + if (IS_ERR(priv->sclk_i2s)) { + ret = PTR_ERR(priv->sclk_i2s); + goto err_put_codec_n; + } + + priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); if (IS_ERR(priv->clk_i2s_bus)) { ret = PTR_ERR(priv->clk_i2s_bus); goto err_put_sclk; } + of_node_put(cpu_dai); ret = devm_snd_soc_register_card(dev, card); if (ret < 0) { @@ -182,10 +244,8 @@ err_put_clk_i2s: clk_put(priv->clk_i2s_bus); err_put_sclk: clk_put(priv->sclk_i2s); -err_put_i2s_n: - of_node_put(link->cpu_of_node); err_put_codec_n: - snd_soc_of_put_dai_link_codecs(link); + snd_soc_of_put_dai_link_codecs(codec_link); return ret; } @@ -193,8 +253,7 @@ static int odroid_audio_remove(struct platform_device *pdev) { struct odroid_priv *priv = platform_get_drvdata(pdev); - of_node_put(priv->dai_link.cpu_of_node); - snd_soc_of_put_dai_link_codecs(&priv->dai_link); + snd_soc_of_put_dai_link_codecs(&priv->card.dai_link[1]); clk_put(priv->sclk_i2s); clk_put(priv->clk_i2s_bus); From 0f928c19b646f6af39ccf7481a546e5da616bb78 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:41 +0100 Subject: [PATCH 383/461] ASoC: samsung: Specify DMA channel names through custom DMA config This is a part of conversion of Samsung platforms to use the custom DMA config for specifying DMA channel names, in addition to passing custom DMA device for the secondary CPU DAI's "PCM" component for some variants of the I2S controller. We also don't set the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME any more as setting it wouldn't allow to specify DMA channels through the custom DMA config. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/dmaengine.c | 12 ++++-------- sound/soc/samsung/i2s.c | 2 +- sound/soc/samsung/s3c2412-i2s.c | 2 +- sound/soc/samsung/s3c24xx-i2s.c | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 84601fa9aa46..302871974cb3 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -28,7 +28,6 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, const char *tx, const char *rx, struct device *dma_dev) { - unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; struct snd_dmaengine_pcm_config *pcm_conf; pcm_conf = devm_kzalloc(dev, sizeof(*pcm_conf), GFP_KERNEL); @@ -39,14 +38,11 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, pcm_conf->compat_filter_fn = filter; pcm_conf->dma_dev = dma_dev; - if (dev->of_node) { - pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; - pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; - } else { - flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME; - } + pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; + pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; - return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags); + return devm_snd_dmaengine_pcm_register(dev, pcm_conf, + SND_DMAENGINE_PCM_FLAG_COMPAT); } EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 692a752b194c..6ab99e38e6dd 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1460,7 +1460,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->drv->playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, - NULL, NULL, NULL); + "tx", "rx", NULL); if (ret < 0) goto err_disable_clk; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 67dfa27ae321..c08638b0e458 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -177,7 +177,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) ret = samsung_asoc_dma_platform_register(&pdev->dev, pdata->dma_filter, - NULL, NULL, NULL); + "tx", "rx", NULL); if (ret) { pr_err("failed to register the DMA: %d\n", ret); return ret; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index ba0f2b94f8d4..a8026b640c95 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -446,7 +446,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, - NULL, NULL, NULL); + "tx", "rx", NULL); if (ret) { dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; From 1c3816a194870e7a6622345dab7fb56c7d708613 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Sat, 9 Feb 2019 10:41:09 +0000 Subject: [PATCH 384/461] ASoC: stm32: sai: add missing put_device() The of_find_device_by_node() takes a reference to the underlying device structure, we should release that reference. Fixes: 7dd0d835582f ("ASoC: stm32: sai: simplify sync modes management") Signed-off-by: Wen Yang Acked-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index bcb35cae2a2c..14c9591aae42 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -112,16 +112,21 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!sai_provider) { dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); - return -EINVAL; + ret = -EINVAL; + goto out_put_dev; } /* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) - return ret; + goto out_put_dev; /* Configure sync provider */ - return stm32_sai_sync_conf_provider(sai_provider, synco); + ret = stm32_sai_sync_conf_provider(sai_provider, synco); + +out_put_dev: + put_device(&pdev->dev); + return ret; } static int stm32_sai_probe(struct platform_device *pdev) From eb540d3988d93d2b0231a5b36012aa0b3abaec81 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:44 +0100 Subject: [PATCH 385/461] ASoC: samsung: i2s: Simplify pri_dai, sec_dai pointers usage If the probe call is on the primary DAI we can use 'other' in place of i2s->sec_dai, if the probe call is on the secondary DAI we can use 'i2s' in place of other->sec_dai. While at it fix one whitespace issue. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 6ab99e38e6dd..967c1b22ac35 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1057,18 +1057,17 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) pm_runtime_get_sync(dai->dev); if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ - snd_soc_dai_init_dma_data(dai, &other->sec_dai->dma_playback, - NULL); + snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL); } else { snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, - &i2s->dma_capture); + &i2s->dma_capture); if (priv->quirks & QUIRK_NEED_RSTCLR) writel(CON_RSTCLR, priv->addr + I2SCON); if (priv->quirks & QUIRK_SUPPORTS_IDMA) idma_reg_addr_init(priv->addr, - i2s->sec_dai->idma_playback.addr); + other->idma_playback.addr); } /* Reset any constraint on RFS and BFS */ From c5ba619247391527248c4a8fb27e68f7cece8d0d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:45 +0100 Subject: [PATCH 386/461] ASoC: samsung: i2s: Change indentation in SAMSUNG_I2S_FMTS definition Change indentation so this macro definition spans 2 rows and looks more consistent with surrounding code. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 967c1b22ac35..07f815a730df 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1150,9 +1150,8 @@ static const struct snd_soc_component_driver samsung_i2s_component = { .num_dapm_routes = ARRAY_SIZE(samsung_i2s_dapm_routes), }; -#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S24_LE) +#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) static int i2s_alloc_dais(struct samsung_i2s_priv *priv, const struct samsung_i2s_dai_data *i2s_dai_data, From 9f9f8a5b79b0855d162153de41ffda687fd2241f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:46 +0100 Subject: [PATCH 387/461] ASoC: samsung: i2s: Comments clean up Spelling error fixes, upper/lower case letter changes. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 07f815a730df..84cfa2c0ba68 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1,5 +1,4 @@ -/* sound/soc/samsung/i2s.c - * +/* * ALSA SoC Audio Layer - Samsung I2S Controller driver * * Copyright (c) 2010 Samsung Electronics Co. Ltd. @@ -61,10 +60,10 @@ struct i2s_dai { /* Platform device for this DAI */ struct platform_device *pdev; - /* Frame Clock */ + /* Frame clock */ unsigned frmclk; /* - * Specifically requested RCLK,BCLK by MACHINE Driver. + * Specifically requested RCLK, BCLK by machine driver. * 0 indicates CPU driver is free to choose any value. */ unsigned rfs, bfs; @@ -72,8 +71,9 @@ struct i2s_dai { struct i2s_dai *pri_dai; /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */ struct i2s_dai *sec_dai; -#define DAI_OPENED (1 << 0) /* Dai is opened */ -#define DAI_MANAGER (1 << 1) /* Dai is the manager */ + +#define DAI_OPENED (1 << 0) /* DAI is opened */ +#define DAI_MANAGER (1 << 1) /* DAI is the manager */ unsigned mode; /* Driver for this DAI */ @@ -98,7 +98,7 @@ struct samsung_i2s_priv { /* Spinlock protecting access to the device's registers */ spinlock_t lock; - /* Lock for cross i/f checks */ + /* Lock for cross interface checks */ spinlock_t pcm_lock; /* CPU DAIs and their corresponding drivers */ @@ -309,7 +309,7 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) writel(mod, priv->addr + I2SMOD); } -/* Read Bit-Clock of I2S (in multiples of LRCLK) */ +/* Read bit-clock of I2S (in multiples of LRCLK) */ static inline unsigned get_bfs(struct i2s_dai *i2s) { struct samsung_i2s_priv *priv = i2s->priv; @@ -331,7 +331,7 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) } } -/* Write Bit-Clock of I2S (in multiples of LRCLK) */ +/* Write bit-clock of I2S (in multiples of LRCLK) */ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) { struct samsung_i2s_priv *priv = i2s->priv; @@ -383,7 +383,7 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) writel(mod, priv->addr + I2SMOD); } -/* Sample-Size */ +/* Sample size */ static inline int get_blc(struct i2s_dai *i2s) { int blc = readl(i2s->priv->addr + I2SMOD); @@ -397,7 +397,7 @@ static inline int get_blc(struct i2s_dai *i2s) } } -/* TX Channel Control */ +/* TX channel control */ static void i2s_txctrl(struct i2s_dai *i2s, int on) { struct samsung_i2s_priv *priv = i2s->priv; @@ -742,7 +742,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, switch (params_channels(params)) { case 6: val |= MOD_DC2_EN; - /* fall through */ + /* Fall through */ case 4: val |= MOD_DC1_EN; break; @@ -821,7 +821,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -/* We set constraints on the substream acc to the version of I2S */ +/* We set constraints on the substream according to the version of I2S */ static int i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1056,7 +1056,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) pm_runtime_get_sync(dai->dev); - if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ + if (is_secondary(i2s)) { + /* If this is probe on the secondary DAI */ snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL); } else { snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, From c1b2db4d038938c64f86b1764da2a5b04f95c171 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 10:37:47 +0100 Subject: [PATCH 388/461] ASoC: samsung: i2s: Convert to SPDX License Indentifier Replace GPL v2.0 license statements with SPDX license identifier. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 84cfa2c0ba68..03fff1c657be 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1,13 +1,9 @@ -/* - * ALSA SoC Audio Layer - Samsung I2S Controller driver - * - * Copyright (c) 2010 Samsung Electronics Co. Ltd. - * Jaswinder Singh - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// ALSA SoC Audio Layer - Samsung I2S Controller driver +// +// Copyright (c) 2010 Samsung Electronics Co. Ltd. +// Jaswinder Singh #include #include From 9fd729542cf4aff3c70b8e5be6f510e6722bc369 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:29 +0000 Subject: [PATCH 389/461] ASoC: da7219: Add support for master mode BCLK rate adjustment Previously the driver would default the BCLK periods per WCLK to 64, to cover all possible non-TDM scenarios when the codec was DAI clock master. However some devices require a lower BCLK rate to operate correctly so with this in mind, this commit updates the code to be more dynamic, with BCLK rate now based on SR and word length provided to hw_params(). Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 36 ++++++++++++++++++++++++++---------- sound/soc/codecs/da7219.h | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index b1df4bb36105..c599aa9f609b 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1376,11 +1376,7 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - /* By default 64 BCLKs per WCLK is supported */ - dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64; - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK | DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK, dai_clk_mode); snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK, @@ -1399,14 +1395,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, __le16 offset; u32 frame_size; - /* No channels enabled so disable TDM, revert to 64-bit frames */ + /* No channels enabled so disable TDM */ if (!tx_mask) { snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, 0); - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - DA7219_DAI_BCLKS_PER_WCLK_64); + da7219->tdm_en = false; return 0; } @@ -1458,6 +1452,8 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); + da7219->tdm_en = true; + return 0; } @@ -1466,10 +1462,13 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - u8 dai_ctrl = 0, fs; + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs; unsigned int channels; + int word_len = params_width(params); + int frame_size; - switch (params_width(params)) { + switch (word_len) { case 16: dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; break; @@ -1533,6 +1532,23 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* + * If we're master, then we have a limited set of BCLK rates we + * support. For slave mode this isn't the case and the codec can detect + * the BCLK rate automatically. + */ + if (da7219->master && !da7219->tdm_en) { + frame_size = word_len * 2; + if (frame_size <= 32) + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + else + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + } + snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_WORD_LENGTH_MASK | DA7219_DAI_CH_NUM_MASK, diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 366cf46118a0..018819c631fb 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -830,6 +830,7 @@ struct da7219_priv { int clk_src; bool master; + bool tdm_en; bool alc_en; bool micbias_on_event; unsigned int mic_pga_delay; From 541ccdc113f000d51858ee7e135889e4096a3316 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:30 +0000 Subject: [PATCH 390/461] ASoC: da7219: Update TDM usage to be more flexible The previous implementatation was restrictive with regards to BCLK rates for slave mode where the driver would not allow rates the codec couldn't provide itself as clock master. The codec is able to automatically determine and handle whatever rate is provided so this restriction isn't necessary for slave mode. The code was also flawed with regards to setting of the frame offset as using rx_mask to explicitly set the offset has the knock on effect of impacting the min and max channels for the codec, in soc_pcm_hw_params() through the call to soc_pcm_codec_params_fixup(). With this update, the driver now only limits frame size if codec is clock master, and dynamically determines the BCLK offset relating to WCLK using the tx_mask for slot offset along with the slot width provided. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 80 +++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index c599aa9f609b..121a8190f93e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1391,8 +1391,10 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, { struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u8 dai_bclks_per_wclk; - __le16 offset; + unsigned int ch_mask; + u8 dai_bclks_per_wclk, slot_offset; + u16 offset; + __le16 dai_offset; u32 frame_size; /* No channels enabled so disable TDM */ @@ -1405,51 +1407,63 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, } /* Check we have valid slots */ - if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) { - dev_err(component->dev, "Invalid number of slots, max = %d\n", + slot_offset = ffs(tx_mask) - 1; + ch_mask = (tx_mask >> slot_offset); + if (fls(ch_mask) > DA7219_DAI_TDM_MAX_SLOTS) { + dev_err(component->dev, + "Invalid number of slots, max = %d\n", DA7219_DAI_TDM_MAX_SLOTS); return -EINVAL; } - /* Check we have a valid offset given */ - if (rx_mask > DA7219_DAI_OFFSET_MAX) { - dev_err(component->dev, "Invalid slot offset, max = %d\n", - DA7219_DAI_OFFSET_MAX); + /* + * Ensure we have a valid offset into the frame, based on slot width + * and slot offset of first slot we're interested in. + */ + offset = slot_offset * slot_width; + if (offset > DA7219_DAI_OFFSET_MAX) { + dev_err(component->dev, "Invalid frame offset %d\n", offset); return -EINVAL; } - /* Calculate & validate frame size based on slot info provided. */ - frame_size = slots * slot_width; - switch (frame_size) { - case 32: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; - break; - case 64: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; - break; - case 128: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; - break; - case 256: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; - break; - default: - dev_err(component->dev, "Invalid frame size %d\n", frame_size); - return -EINVAL; + /* + * If we're master, calculate & validate frame size based on slot info + * provided as we have a limited set of rates available. + */ + if (da7219->master) { + frame_size = slots * slot_width; + switch (frame_size) { + case 32: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; + break; + default: + dev_err(component->dev, "Invalid frame size %d\n", + frame_size); + return -EINVAL; + } + + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); } - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - dai_bclks_per_wclk); - - offset = cpu_to_le16(rx_mask); + dai_offset = cpu_to_le16(offset); regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER, - &offset, sizeof(offset)); + &dai_offset, sizeof(dai_offset)); snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, - (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | + (ch_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); da7219->tdm_en = true; From 76d9c68b360f852e784170f10cb431e4713c7d0b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 16:45:55 +0100 Subject: [PATCH 391/461] ASoC: dmaengine: Remove unused SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag There is now no users of this flag so remove it together with related code. The chan_name field of snd_dmaengine_dai_dma_data data structure is not removed as it is still in use by the PXA platform. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 4 ---- sound/soc/soc-generic-dmaengine-pcm.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 2c4cfaa135a6..c679f6116580 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -99,10 +99,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) -/* - * The PCM streams have custom channel names specified. - */ -#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 1b44e363c50c..f1ab6285a085 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -265,7 +265,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_component_to_pcm(component); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = component->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -285,19 +284,9 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || - (config && config->chan_names[i]))) { - const char *chan_name = dma_data->chan_name; - - if (config && config->chan_names[i]) - chan_name = config->chan_names[i]; - + if (!pcm->chan[i] && config && config->chan_names[i]) pcm->chan[i] = dma_request_slave_channel(dev, - chan_name); - } + config->chan_names[i]); if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, @@ -420,10 +409,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - (!dev->of_node && !(config && config->dma_dev && - config->dma_dev->of_node))) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || (!dev->of_node && + !(config && config->dma_dev && config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 6e434122d9041c48841709385e823eef3225663e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 16:58:40 +0100 Subject: [PATCH 392/461] ASoC: samsung: i2s: Prevent potential NULL platform data dereference When np is NULL i2s_pdata could also be NULL but i2s_pdata is now being dereferenced without proper check. Fix this and shorten the error message so we don't exceed 80 characters limit. Reported-by: Dan Carpenter Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 03fff1c657be..02472f576e17 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1369,7 +1369,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) struct i2s_dai *pri_dai, *sec_dai = NULL; struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; struct resource *res; - u32 regs_base, quirks = 0, idma_addr = 0; + u32 regs_base, idma_addr = 0; struct device_node *np = pdev->dev.of_node; const struct samsung_i2s_dai_data *i2s_dai_data; int num_dais, ret; @@ -1389,11 +1389,19 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - quirks = np ? i2s_dai_data->quirks : i2s_pdata->type.quirks; - num_dais = (quirks & QUIRK_SEC_DAI) ? 2 : 1; + if (np) { + priv->quirks = i2s_dai_data->quirks; + } else { + if (!i2s_pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -EINVAL; + } + priv->quirks = i2s_pdata->type.quirks; + } + + num_dais = (priv->quirks & QUIRK_SEC_DAI) ? 2 : 1; priv->pdev = pdev; priv->variant_regs = i2s_dai_data->i2s_variant_regs; - priv->quirks = quirks; ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais); if (ret < 0) @@ -1405,11 +1413,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) spin_lock_init(&priv->pcm_lock); if (!np) { - if (i2s_pdata == NULL) { - dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); - return -EINVAL; - } - pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback; pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture; pri_dai->filter = i2s_pdata->dma_filter; @@ -1418,7 +1421,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) } else { if (of_property_read_u32(np, "samsung,idma-addr", &idma_addr)) { - if (quirks & QUIRK_SUPPORTS_IDMA) { + if (priv->quirks & QUIRK_SUPPORTS_IDMA) { dev_info(&pdev->dev, "idma address is not"\ "specified"); } @@ -1451,7 +1454,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->dma_capture.addr_width = 4; pri_dai->priv = priv; - if (quirks & QUIRK_PRI_6CHAN) + if (priv->quirks & QUIRK_PRI_6CHAN) pri_dai->drv->playback.channels_max = 6; ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, @@ -1459,7 +1462,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_clk; - if (quirks & QUIRK_SEC_DAI) { + if (priv->quirks & QUIRK_SEC_DAI) { sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1]; sec_dai->dma_playback.addr = regs_base + I2STXDS; From c7a13264918b9796f80c634f20fea56e1612572d Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Mon, 18 Feb 2019 00:17:21 +0200 Subject: [PATCH 393/461] ALSA: usb-audio: Expose sample resolution through proc interface At least some USB devices use (MSB-aligned) audio format larger than the actual resolution of the device. In order to expose the actual device resolution (bBitResolution), add extra field to the procfs stream info interface. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/card.h | 1 + sound/usb/format.c | 2 ++ sound/usb/proc.c | 1 + 3 files changed, 4 insertions(+) diff --git a/sound/usb/card.h b/sound/usb/card.h index ac785d15ced4..79fa2a19fb7b 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -14,6 +14,7 @@ struct audioformat { u64 formats; /* ALSA format bits */ unsigned int channels; /* # channels */ unsigned int fmt_type; /* USB audio format type (1-3) */ + unsigned int fmt_bits; /* number of significant bits */ unsigned int frame_size; /* samples per frame for non-audio */ int iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ diff --git a/sound/usb/format.c b/sound/usb/format.c index fd13ac11b136..3ee7d6f853b7 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -87,6 +87,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, } } + fp->fmt_bits = sample_width; + if ((pcm_formats == 0) && (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) { /* some devices don't define this correctly... */ diff --git a/sound/usb/proc.c b/sound/usb/proc.c index e80c9d0749c9..ef9190530fd2 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -109,6 +109,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s if (subs->speed != USB_SPEED_FULL) snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); + snd_iprintf(buffer, " Bits: %d\n", fp->fmt_bits); // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); // snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes); } From cb8cdb6f3344bcb472640d2f5f956dbde0bfd509 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 17 Feb 2019 22:48:30 +0000 Subject: [PATCH 394/461] ASoC: fsi: fix spelling mistake "doens't" -> "doesn't" There is a spelling mistake in a dev_err message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index aa7e902f0c02..db929b00ae5e 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -780,7 +780,7 @@ static int fsi_clk_init(struct device *dev, return -EINVAL; } if (clock->div == clock->own) { - dev_err(dev, "cpu doens't support div clock\n"); + dev_err(dev, "cpu doesn't support div clock\n"); return -EINVAL; } } From 7aac8d13fc60db3ec2422f26c4dc2425a7fef20c Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Feb 2019 16:10:28 +0000 Subject: [PATCH 395/461] ASoC: codecs: ad193x: Remove capture support for codecs without ADC Some ad193x codecs don't have ADCs, so they have no capture capabilities. This way, we can use this driver in multicodec cards. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 4b60ebee491d..21a38cc9e3da 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -351,6 +351,20 @@ static struct snd_soc_dai_driver ad193x_dai = { .ops = &ad193x_dai_ops, }; +/* codec DAI instance for DAC only */ +static struct snd_soc_dai_driver ad193x_no_adc_dai = { + .name = "ad193x-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &ad193x_dai_ops, +}; + static int ad193x_component_probe(struct snd_soc_component *component) { struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); @@ -444,8 +458,11 @@ int ad193x_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, ad193x); + if (ad193x_has_adc(ad193x)) + return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, + &ad193x_dai, 1); return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x, - &ad193x_dai, 1); + &ad193x_no_adc_dai, 1); } EXPORT_SYMBOL_GPL(ad193x_probe); From 75c2ecb4bda296f89d4ea6a42750f48bfcd8a1d9 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Feb 2019 16:10:30 +0000 Subject: [PATCH 396/461] ASoC: codecs: ad193x: Set constraint to always have 32 sample bits DACs and ADCs on ad193x codecs require a 32 bit slot size. We should assure that no other size is used. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 21a38cc9e3da..c16c9969d1a0 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -37,6 +37,13 @@ static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); +static const unsigned int ad193x_sb[] = {32}; + +static struct snd_pcm_hw_constraint_list constr = { + .list = ad193x_sb, + .count = ARRAY_SIZE(ad193x_sb), +}; + static const struct snd_kcontrol_new ad193x_snd_controls[] = { /* DAC volume control */ SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL, @@ -321,7 +328,16 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, return 0; } +static int ad193x_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + &constr); +} + static const struct snd_soc_dai_ops ad193x_dai_ops = { + .startup = ad193x_startup, .hw_params = ad193x_hw_params, .digital_mute = ad193x_mute, .set_tdm_slot = ad193x_set_tdm_slot, From 90f6e68031397fb6212bef5619193cd15707fa0f Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Feb 2019 16:10:32 +0000 Subject: [PATCH 397/461] ASoC: codecs: ad193x: Fix frame polarity for DSP_A format By default, the codec starts to interpret the left (first) channel on the falling edge (low polarity) of LRCLK. However, for DSP_A, the left channel needs to start on the rising edge of LRCLK. This patch fixes this channel swap by toggling the bit which selects the LRCLK polarity. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index c16c9969d1a0..315ec9775118 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -228,6 +228,12 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } + /* For DSP_*, LRCLK's polarity must be inverted */ + if (fmt & SND_SOC_DAIFMT_DSP_A) { + change_bit(ffs(AD193X_DAC_LEFT_HIGH) - 1, + (unsigned long *)&dac_fmt); + } + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */ adc_fmt |= AD193X_ADC_LCR_MASTER; From bccf9c7e14830af0004399d42d861b33c92eacff Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Feb 2019 16:10:34 +0000 Subject: [PATCH 398/461] ASoC: codecs: ad193x: Add runtime support for DSP_A and I2S modes The driver only supports DPS_A for DAC, which is configured at probe. This patch adds support for DSP_A and I2S modes by using the set_fmt() callback. A trivial break is also removed from a case's default branch. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 315ec9775118..f8cf182518a3 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -188,23 +188,26 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component); unsigned int adc_serfmt = 0; + unsigned int dac_serfmt = 0; unsigned int adc_fmt = 0; unsigned int dac_fmt = 0; /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S - * with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) + * with TDM), ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) and DAC I2S mode + * (SND_SOC_DAIFMT_I2S) */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: adc_serfmt |= AD193X_ADC_SERFMT_TDM; + dac_serfmt |= AD193X_DAC_SERFMT_STEREO; break; case SND_SOC_DAIFMT_DSP_A: adc_serfmt |= AD193X_ADC_SERFMT_AUX; + dac_serfmt |= AD193X_DAC_SERFMT_TDM; break; default: if (ad193x_has_adc(ad193x)) return -EINVAL; - break; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -261,6 +264,8 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2, AD193X_ADC_FMT_MASK, adc_fmt); } + regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0, + AD193X_DAC_SERFMT_MASK, dac_serfmt); regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1, AD193X_DAC_FMT_MASK, dac_fmt); From 59529473751e987e28c926838f70aaef588b83b0 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 18 Feb 2019 16:10:36 +0000 Subject: [PATCH 399/461] ASoC: codecs: ad193x: Add support to disable on-chip PLL The on-chip PLL can be disabled if on the MCLKI pin we have an external clock at 512 x fs. This clock can be used as direct internal clock for ADCs or DACs. To support this, we add an extra clock id that can be configured using the set_sysclk() callback. Signed-off-by: Codrin Ciubotariu Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 26 +++++++++++++++++++++++++- sound/soc/codecs/ad193x.h | 8 ++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index f8cf182518a3..96d7cb2e4a56 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -100,6 +100,15 @@ static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = { SND_SOC_DAPM_INPUT("ADC2IN"), }; +static int ad193x_check_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm); + struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); + + return !!ad193x->sysclk; +} + static const struct snd_soc_dapm_route audio_paths[] = { { "DAC", NULL, "SYSCLK" }, { "DAC Output", NULL, "DAC" }, @@ -108,7 +117,7 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "DAC2OUT", NULL, "DAC Output" }, { "DAC3OUT", NULL, "DAC Output" }, { "DAC4OUT", NULL, "DAC Output" }, - { "SYSCLK", NULL, "PLL_PWR" }, + { "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll }, }; static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = { @@ -276,7 +285,22 @@ static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_component *component = codec_dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component); + + if (clk_id == AD193X_SYSCLK_MCLK) { + /* MCLK must be 512 x fs */ + if (dir == SND_SOC_CLOCK_OUT || freq != 24576000) + return -EINVAL; + + regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1, + AD193X_PLL_SRC_MASK, + AD193X_PLL_DAC_SRC_MCLK | + AD193X_PLL_CLK_SRC_MCLK); + + snd_soc_dapm_sync(dapm); + return 0; + } switch (freq) { case 12288000: case 18432000: diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index 8b1e65f928d2..27d6afbd7dfb 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h @@ -31,6 +31,11 @@ int ad193x_probe(struct device *dev, struct regmap *regmap, #define AD193X_PLL_INPUT_512 (2 << 1) #define AD193X_PLL_INPUT_768 (3 << 1) #define AD193X_PLL_CLK_CTRL1 0x01 +#define AD193X_PLL_SRC_MASK 0x03 +#define AD193X_PLL_DAC_SRC_PLL 0 +#define AD193X_PLL_DAC_SRC_MCLK 1 +#define AD193X_PLL_CLK_SRC_PLL (0 << 1) +#define AD193X_PLL_CLK_SRC_MCLK (1 << 1) #define AD193X_DAC_CTRL0 0x02 #define AD193X_DAC_POWERDOWN 0x01 #define AD193X_DAC_SERFMT_MASK 0xC0 @@ -96,4 +101,7 @@ int ad193x_probe(struct device *dev, struct regmap *regmap, #define AD193X_NUM_REGS 17 +#define AD193X_SYSCLK_PLL 0 +#define AD193X_SYSCLK_MCLK 1 + #endif From 30c498a10ac6586778062062c064ae54e3897762 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Mon, 18 Feb 2019 14:12:17 +0000 Subject: [PATCH 400/461] ASoC: fsl_spdif: fix TXCLK_DF mask According to RM SPDIF TXCLK_DF mask is 7-bit wide. Signed-off-by: Viorel Suman Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h index 7666dabaccfd..e6c61e07bc1a 100644 --- a/sound/soc/fsl/fsl_spdif.h +++ b/sound/soc/fsl/fsl_spdif.h @@ -152,7 +152,7 @@ enum spdif_gainsel { #define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET) #define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET) #define STC_TXCLK_DF_OFFSET 0 -#define STC_TXCLK_DF_MASK (0x7ff << STC_TXCLK_DF_OFFSET) +#define STC_TXCLK_DF_MASK (0x7f << STC_TXCLK_DF_OFFSET) #define STC_TXCLK_DF(x) ((((x) - 1) << STC_TXCLK_DF_OFFSET) & STC_TXCLK_DF_MASK) #define STC_TXCLK_SRC_MAX 8 From 2231609a2c0a4807c017822ecb5834bbb7f59fb9 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Mon, 18 Feb 2019 15:25:00 +0000 Subject: [PATCH 401/461] ASoC: fsl_spdif: fix sysclk_df type According to RM SPDIF STC SYSCLK_DF field is 9-bit wide, values being in 0..511 range. Use a proper type to handle sysclk_df. Signed-off-by: Viorel Suman Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index a26686e7281c..4842e6df9a2d 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -96,7 +96,7 @@ struct fsl_spdif_priv { bool dpll_locked; u32 txrate[SPDIF_TXRATE_MAX]; u8 txclk_df[SPDIF_TXRATE_MAX]; - u8 sysclk_df[SPDIF_TXRATE_MAX]; + u16 sysclk_df[SPDIF_TXRATE_MAX]; u8 txclk_src[SPDIF_TXRATE_MAX]; u8 rxclk_src; struct clk *txclk[SPDIF_TXRATE_MAX]; @@ -376,7 +376,8 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, struct platform_device *pdev = spdif_priv->pdev; unsigned long csfs = 0; u32 stc, mask, rate; - u8 clk, txclk_df, sysclk_df; + u16 sysclk_df; + u8 clk, txclk_df; int ret; switch (sample_rate) { @@ -1109,8 +1110,9 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); u64 rate_ideal, rate_actual, sub; - u32 sysclk_dfmin, sysclk_dfmax; - u32 txclk_df, sysclk_df, arate; + u32 arate; + u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; + u8 txclk_df; /* The sysclk has an extra divisor [2, 512] */ sysclk_dfmin = is_sysclk ? 2 : 1; From 74c6ecf4194ebed285b29964a950e0cd7414fe19 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 18 Feb 2019 12:18:19 +0800 Subject: [PATCH 402/461] ASoC: qcom: Kconfig: select dmic for sdm845 sdm845 uses dmic on EC so it should select CROS_EC_CODEC. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 7948e993adba..8f206cb4fcc0 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_SDM845 select SND_SOC_QCOM_COMMON select SND_SOC_RT5663 select SND_SOC_MAX98927 + select SND_SOC_CROS_EC_CODEC help To add support for audio on Qualcomm Technologies Inc. SDM845 SoC-based systems. From b2c02c63ac254530cffe3a7dc7d4e433da1b3a67 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 18 Feb 2019 07:46:53 +0000 Subject: [PATCH 403/461] ASoC: cs35l36: Make some symbols static Fixes the following sparse warnings: sound/soc/codecs/cs35l36.c:135:20: warning: symbol 'cs35l36_reg' was not declared. Should it be static? sound/soc/codecs/cs35l36.c:248:6: warning: symbol 'cs35l36_readable_reg' was not declared. Should it be static? sound/soc/codecs/cs35l36.c:398:6: warning: symbol 'cs35l36_precious_reg' was not declared. Should it be static? sound/soc/codecs/cs35l36.c:410:6: warning: symbol 'cs35l36_volatile_reg' was not declared. Should it be static? Fixes: 6ba9dd6c893b ("ASoC: cs35l36: Add support for Cirrus CS35L36 Amplifier") Signed-off-by: Wei Yongjun Acked-by: James Schulman Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index e374fffb7e17..dc8cf61b9db8 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -131,7 +131,7 @@ static const struct cs35l36_pll_config cs35l36_pll_sysclk[] = { {27000000, 0x3F, 0x0A}, }; -struct reg_default cs35l36_reg[] = { +static struct reg_default cs35l36_reg[] = { {CS35L36_TESTKEY_CTRL, 0x00000000}, {CS35L36_USERKEY_CTL, 0x00000000}, {CS35L36_OTP_CTRL1, 0x00002460}, @@ -244,7 +244,7 @@ struct reg_default cs35l36_reg[] = { {CS35L36_PAC_INT7_CTRL, 0x00000001}, }; -bool cs35l36_readable_reg(struct device *dev, unsigned int reg) +static bool cs35l36_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L36_SW_RESET: @@ -394,7 +394,7 @@ bool cs35l36_readable_reg(struct device *dev, unsigned int reg) } } -bool cs35l36_precious_reg(struct device *dev, unsigned int reg) +static bool cs35l36_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L36_TESTKEY_CTRL: @@ -406,7 +406,7 @@ bool cs35l36_precious_reg(struct device *dev, unsigned int reg) } } -bool cs35l36_volatile_reg(struct device *dev, unsigned int reg) +static bool cs35l36_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L36_SW_RESET: From 70605450fd42060783b0072a61a30f42a74f2917 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 18 Feb 2019 14:50:26 +0000 Subject: [PATCH 404/461] ASoC: stm32: sai: remove set but not used variables 'mask, cr1' Fixes gcc '-Wunused-but-set-variable' warning: sound/soc/stm/stm32_sai_sub.c: In function 'stm32_sai_configure_clock': sound/soc/stm/stm32_sai_sub.c:902:11: warning: variable 'mask' set but not used [-Wunused-but-set-variable] sound/soc/stm/stm32_sai_sub.c:902:6: warning: variable 'cr1' set but not used [-Wunused-but-set-variable] It's not used any more after 8307b2afd386 ("ASoC: stm32: sai: set sai as mclk clock provider") Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index d4825700b63f..f9297228c41c 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -898,7 +898,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); - int cr1, mask, div = 0; + int div = 0; int sai_clk_rate, mclk_ratio, den; unsigned int rate = params_rate(params); @@ -943,10 +943,8 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, } else { if (sai->mclk_rate) { mclk_ratio = sai->mclk_rate / rate; - if (mclk_ratio == 512) { - mask = SAI_XCR1_OSR; - cr1 = SAI_XCR1_OSR; - } else if (mclk_ratio != 256) { + if ((mclk_ratio != 512) && + (mclk_ratio != 256)) { dev_err(cpu_dai->dev, "Wrong mclk ratio %d\n", mclk_ratio); From b5c16a24efc809554c4c651df6bd9b48b084a5a3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 17:00:11 +0100 Subject: [PATCH 405/461] ASoC: samsung: odroid: Ensure proper sample rate on pri/sec PCM Currently when playing sound with different sample rates actual sample rate will be determined by audio stream which starts first on either primary or secondary PCM. The audio root clock will be configured appropriately only for the first stream. As the hardware is limited to same sample rate on both interfaces we need to disallow streams with different sample rates. It is done by this patch by returning error in FE hw_params if there is already active stream running with different sample rate. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 18bb3bfe0300..941e8c3f67a4 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -20,6 +20,11 @@ struct odroid_priv { struct snd_soc_card card; struct clk *clk_i2s_bus; struct clk *sclk_i2s; + + /* Spinlock protecting fields below */ + spinlock_t lock; + unsigned int be_sample_rate; + bool be_active; }; static int odroid_card_fe_startup(struct snd_pcm_substream *substream) @@ -31,8 +36,25 @@ static int odroid_card_fe_startup(struct snd_pcm_substream *substream) return 0; } +static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->be_active && priv->be_sample_rate != params_rate(params)) + ret = -EINVAL; + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + static const struct snd_soc_ops odroid_card_fe_ops = { .startup = odroid_card_fe_startup, + .hw_params = odroid_card_fe_hw_params, }; static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, @@ -41,6 +63,7 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); unsigned int pll_freq, rclk_freq, rfs; + unsigned long flags; int ret; switch (params_rate(params)) { @@ -87,11 +110,43 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, return ret; } + spin_lock_irqsave(&priv->lock, flags); + priv->be_sample_rate = params_rate(params); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + priv->be_active = true; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + priv->be_active = false; + break; + } + + spin_unlock_irqrestore(&priv->lock, flags); + return 0; } static const struct snd_soc_ops odroid_card_be_ops = { .hw_params = odroid_card_be_hw_params, + .trigger = odroid_card_be_trigger, }; static struct snd_soc_dai_link odroid_card_dais[] = { @@ -150,6 +205,7 @@ static int odroid_audio_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->fully_routed = true; + spin_lock_init(&priv->lock); snd_soc_card_set_drvdata(card, priv); ret = snd_soc_of_parse_card_name(card, "model"); From 461d854c0dba3cdf63cce37ffb9423eca0793a47 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sat, 16 Feb 2019 10:09:42 +0000 Subject: [PATCH 406/461] ASoC: simple-card: Fix refcount underflow of_get_child_by_name() takes a reference we'll need to drop later so when we substitute in top we need to take a reference as well as just assigning. Without this patch we hit the following error: [ 1.246852] OF: ERROR: Bad of_node_put() on /sound-wm8524 [ 1.262261] Hardware name: NXP i.MX8MQ EVK (DT) [ 1.266807] Workqueue: events deferred_probe_work_func [ 1.271950] Call trace: [ 1.274406] dump_backtrace+0x0/0x158 [ 1.278074] show_stack+0x14/0x20 [ 1.281396] dump_stack+0xa8/0xcc [ 1.284717] of_node_release+0xb0/0xc8 [ 1.288474] kobject_put+0x74/0xf0 [ 1.291879] of_node_put+0x14/0x28 [ 1.295286] __of_get_next_child+0x44/0x70 [ 1.299387] of_get_next_child+0x3c/0x60 [ 1.303315] simple_for_each_link+0x1dc/0x230 [ 1.307676] simple_probe+0x80/0x540 [ 1.311256] platform_drv_probe+0x50/0xa0 This patch is based on an earlier version posted by Kuninori Morimoto and commit message includes explanations from Mark Brown. https://patchwork.kernel.org/patch/10814255/ Reported-by: Vicente Bergas Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 08df261024cf..dc18c4492955 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -445,7 +445,7 @@ static int simple_for_each_link(struct simple_priv *priv, /* Check if it has dai-link */ node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { - node = top; + node = of_node_get(top); is_top = 1; } From 8fa857da9744f513036df1c43ab57f338941ae7d Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 18 Feb 2019 15:13:47 +0000 Subject: [PATCH 407/461] SoC: imx-sgtl5000: add missing put_device() The of_find_device_by_node() takes a reference to the underlying device structure, we should release that reference. Detected by coccinelle with the following warnings: ./sound/soc/fsl/imx-sgtl5000.c:169:1-7: ERROR: missing put_device; call of_find_device_by_node on line 105, but without a corresponding object release within this function. ./sound/soc/fsl/imx-sgtl5000.c:177:1-7: ERROR: missing put_device; call of_find_device_by_node on line 105, but without a corresponding object release within this function. Signed-off-by: Wen Yang Cc: Timur Tabi Cc: Nicolin Chen Cc: Xiubo Li Cc: Fabio Estevam Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: NXP Linux Team Cc: alsa-devel@alsa-project.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index b6cb80480b60..bf8597f57dce 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -108,6 +108,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ret = -EPROBE_DEFER; goto fail; } + put_device(&ssi_pdev->dev); codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { dev_dbg(&pdev->dev, "failed to find codec platform device\n"); From d98afe1353b6dbd1527f3833da70d8525e6dbae3 Mon Sep 17 00:00:00 2001 From: Bogdan Togorean Date: Fri, 15 Feb 2019 12:26:33 +0200 Subject: [PATCH 408/461] ASoC: adau1977: Fix reset-gpios typo This change fixes a typo in the dt-binding examples (reset_gpio -> reset-gpios). Even though 'reset-gpio' is a valid construct for gpiolib the naming 'reset-gpios' is more suited for dt-bindings documentation. Signed-off-by: Bogdan Togorean Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/adi,adau1977.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt index e79aeef73f28..11acd94b1665 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau1977.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau1977.txt @@ -17,7 +17,7 @@ Required properties: Documentation/devicetree/bindings/regulator/regulator.txt Optional properties: - - reset-gpio: the reset pin for the chip, for more details consult + - reset-gpios: the reset pin for the chip, for more details consult Documentation/devicetree/bindings/gpio/gpio.txt - DVDD-supply: supply voltage for the digital core, please consult @@ -40,7 +40,7 @@ Examples: AVDD-supply = <®ulator>; DVDD-supply = <®ulator_digital>; - reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>; }; adau1977_i2c: adau1977@11 { @@ -50,5 +50,5 @@ Examples: AVDD-supply = <®ulator>; DVDD-supply = <®ulator_digital>; - reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>; }; From cc29ea007347f39f4c5a4d27b0b555955a0277f9 Mon Sep 17 00:00:00 2001 From: "S.j. Wang" Date: Mon, 18 Feb 2019 08:29:11 +0000 Subject: [PATCH 409/461] ASoC: fsl_esai: fix register setting issue in RIGHT_J mode The ESAI_xCR_xWA is xCR's bit, not the xCCR's bit, driver set it to wrong register, correct it. Fixes 43d24e76b698 ("ASoC: fsl_esai: Add ESAI CPU DAI driver") Cc: Signed-off-by: Shengjiu Wang Reviewed-by: Fabio Estevam Ackedy-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 57b484768a58..afe67c865330 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -398,7 +398,8 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; case SND_SOC_DAIFMT_RIGHT_J: /* Data on rising edge of bclk, frame high, right aligned */ - xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA; + xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; + xcr |= ESAI_xCR_xWA; break; case SND_SOC_DAIFMT_DSP_A: /* Data on rising edge of bclk, frame high, 1clk before data */ @@ -455,12 +456,12 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR; + mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR | ESAI_xCR_xWA; regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr); regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr); mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP | - ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA; + ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr); regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr); From 76a60f312f64dc48450b15a7f167b46e6230e4d1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 16 Feb 2019 01:35:56 +0000 Subject: [PATCH 410/461] ASoC: wm8741: Make function 'wm8741_mute' static Fixes the following sparse warning: sound/soc/codecs/wm8741.c:371:5: warning: symbol 'wm8741_mute' was not declared. Should it be static? Fixes: 36b1599340b5 ("ASoC: wm8741: Add digital mute callback") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/wm8741.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index a4b8c459ea57..546ea735f534 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -368,7 +368,7 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -int wm8741_mute(struct snd_soc_dai *codec_dai, int mute) +static int wm8741_mute(struct snd_soc_dai *codec_dai, int mute) { struct snd_soc_component *component = codec_dai->component; From f89aea0f132142b29dc0c8cf4d445bd12db7b1a6 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 15 Feb 2019 13:04:22 +0100 Subject: [PATCH 411/461] ASoC: samsung: odroid: Add missing DAPM routes With old DTS there will be missing DAPM routes linking BE with CODECs. Add those routes in the card driver so sound works properly on Odroid XU3/4 also without DTS updates enabling the secondary PCM. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 941e8c3f67a4..5b2bcd1d3450 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -149,6 +149,12 @@ static const struct snd_soc_ops odroid_card_be_ops = { .trigger = odroid_card_be_trigger, }; +/* DAPM routes for backward compatibility with old DTS */ +static const struct snd_soc_dapm_route odroid_dapm_routes[] = { + { "I2S Playback", NULL, "Mixer DAI TX" }, + { "HiFi Playback", NULL, "Mixer DAI TX" }, +}; + static struct snd_soc_dai_link odroid_card_dais[] = { { /* Primary FE <-> BE link */ @@ -237,11 +243,15 @@ static int odroid_audio_probe(struct platform_device *pdev) /* * For backwards compatibility create the secondary CPU DAI link only * if there are 2 CPU DAI entries in the cpu sound-dai property in DT. + * Also add required DAPM routes not available in old DTS. */ num_pcms = of_count_phandle_with_args(cpu, "sound-dai", "#sound-dai-cells"); - if (num_pcms == 1) + if (num_pcms == 1) { + card->dapm_routes = odroid_dapm_routes; + card->num_dapm_routes = ARRAY_SIZE(odroid_dapm_routes); card->num_links--; + } for (i = 0; i < num_pcms; i++, link += 2) { ret = of_parse_phandle_with_args(cpu, "sound-dai", From a6d9cef30eb11b2de8cbfed9065e3dc5b1f829a8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Feb 2019 15:04:27 +0300 Subject: [PATCH 412/461] ASoC: dapm: Potential small memory leak in dapm_cnew_widget() We should free "w" on the error path. Fixes: 199ed3e81c49 ("ASoC: dapm: fix use-after-free issue with dailink sname") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dea6fc2353e4..1ec06ef6d161 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -332,8 +332,10 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( */ if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); - if (!w->sname) + if (!w->sname) { + kfree(w); return NULL; + } } return w; } From fb7a97456e324b4ac13044db17a4f5b974e49e33 Mon Sep 17 00:00:00 2001 From: Bogdan Togorean Date: Tue, 19 Feb 2019 16:11:38 +0200 Subject: [PATCH 413/461] ASoC: adau1977: Add MICBIAS example in DT bindings Add MICBIAS property to the optional devicetree bindings. Signed-off-by: Bogdan Togorean Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/adi,adau1977.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/adi,adau1977.txt b/Documentation/devicetree/bindings/sound/adi,adau1977.txt index e79aeef73f28..87c16e6f2e7c 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau1977.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau1977.txt @@ -23,6 +23,12 @@ Optional properties: - DVDD-supply: supply voltage for the digital core, please consult Documentation/devicetree/bindings/regulator/regulator.txt +- adi,micbias: configures the voltage setting for the MICBIAS pin. + Select 0/1/2/3/4/5/6/7/8 to specify MICBIAS voltage + 5V/5.5V/6V/6.5V/7V/7.5V/8V/8.5V/9V + If not specified the default value will be "7" meaning 8.5 Volts. + This property is only valid for the ADAU1977 + For required properties on SPI, please consult Documentation/devicetree/bindings/spi/spi-bus.txt @@ -40,6 +46,7 @@ Examples: AVDD-supply = <®ulator>; DVDD-supply = <®ulator_digital>; + adi,micbias = <3>; reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>; }; From 65d257ee12860340947bbc336243b4a9a5d721df Mon Sep 17 00:00:00 2001 From: Bogdan Togorean Date: Tue, 19 Feb 2019 16:11:39 +0200 Subject: [PATCH 414/461] ASoC: adau1977: Add support for setting MICBIAS via DT If platform_data is NULL add reading of optional adi,micbias property from DT. If adi,micbias is not set keep the default value for micbias. Signed-off-by: Bogdan Togorean Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 116af6a9ce3b..11c53bcb71dd 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -885,13 +885,15 @@ static int adau1977_setup_micbias(struct adau1977 *adau1977) struct adau1977_platform_data *pdata = adau1977->dev->platform_data; unsigned int micbias; - if (pdata) { + if (pdata) micbias = pdata->micbias; - if (micbias > ADAU1977_MICBIAS_9V0) - return -EINVAL; - - } else { + else if (device_property_read_u32(adau1977->dev, "adi,micbias", + &micbias)) micbias = ADAU1977_MICBIAS_8V5; + + if (micbias > ADAU1977_MICBIAS_9V0) { + dev_err(adau1977->dev, "Invalid value for 'adi,micbias'\n"); + return -EINVAL; } return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, From 5fd812e6f5ae0376134234ceb70e8de541ccb10d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 13 Feb 2019 15:04:56 +0800 Subject: [PATCH 415/461] ASoC: sunxi: sun50i-codec-analog: Rename hpvcc regulator supply to cpvdd The A64 datasheet lists the supply rail for the headphone amp's charge pump as "CPVDD". cpvdd-supply is the name of the property for this power rail specified in the device tree bindings. "HPVCC" was the name used in the A33 datasheet for the same function. Rename the supply so it matches the datasheet, bindings, and the subject from the original commit. Fixes: ca0412a05756 ("ASoC: sunxi: sun50i-codec-analog: Add support for cpvdd regulator supply") Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun50i-codec-analog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index df1fed0aa001..d105c90c3706 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -274,7 +274,7 @@ static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = { * stream widgets at the card level. */ - SND_SOC_DAPM_REGULATOR_SUPPLY("hpvcc", 0, 0), + SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0), SND_SOC_DAPM_MUX("Headphone Source Playback Route", SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src), SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL, @@ -362,7 +362,7 @@ static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = { { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, { "Headphone Amp", NULL, "Headphone Source Playback Route" }, - { "Headphone Amp", NULL, "hpvcc" }, + { "Headphone Amp", NULL, "cpvdd" }, { "HP", NULL, "Headphone Amp" }, /* Microphone Routes */ From 9dd9b210f8c6104690ba48a630bbe9af2f32c292 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:51 -0600 Subject: [PATCH 416/461] ASoC: Intel: Headset button support in broxton machine driver Map the 4 headset buttons to KEY_PAUSE, KEY_VOLUMEUP, KEY_VOLUMEDOWN and KEY_VOICECOMMAND. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c00925f9da73..30311b81a543 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -193,6 +194,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3, + KEY_VOICECOMMAND); + da7219_aad_jack_det(component, &broxton_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); From c011245a197017f8e9e9d140b658bdb2b702a0c5 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:52 -0600 Subject: [PATCH 417/461] ASoC: Intel: Add Geminilake Dialog Maxim machine driver This patch enables support for GeminiLake with the DA7219 codec and MAX98357A amplifier. To avoid duplicating code, the existing machine driver for ApolloLake is reused with only changes in hardware connectivity (SSP2 for DA7219 and SSP1 for MAX98357A). The dailinks are directly modified in this patch. Using a helper would be nicer, but it'll be done in a follow-up step with validation done across multiple machine drivers. Acked-by: Pierre-Louis Bossart Signed-off-by: Yong Zhi Signed-off-by: Naveen Manohar Signed-off-by: Harsha Priya Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 79 ++++++++++++++++--- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 30311b81a543..407b0cfc5167 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -104,7 +105,7 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU), }; -static const struct snd_soc_dapm_route broxton_map[] = { +static const struct snd_soc_dapm_route audio_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone Jack", NULL, "HPL"}, {"Headphone Jack", NULL, "HPR"}, @@ -119,15 +120,6 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"DMic", NULL, "SoC DMIC"}, /* CODEC BE connections */ - {"HiFi Playback", NULL, "ssp5 Tx"}, - {"ssp5 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp1 Rx"}, - {"ssp1 Rx", NULL, "Capture"}, - {"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, {"HDMI2", NULL, "hif7-0 Output"}, @@ -147,6 +139,28 @@ static const struct snd_soc_dapm_route broxton_map[] = { { "Headset Mic", NULL, "Platform Clock" }, }; +static const struct snd_soc_dapm_route broxton_map[] = { + {"HiFi Playback", NULL, "ssp5 Tx"}, + {"ssp5 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp1 Rx"}, + {"ssp1 Rx", NULL, "Capture"}, +}; + +static const struct snd_soc_dapm_route gemini_map[] = { + {"HiFi Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "Capture"}, +}; + static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -539,6 +553,11 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +static const struct x86_cpu_id glk_ids[] = { + { X86_VENDOR_INTEL, 6, 0x7A }, /* Geminilake CPU_ID */ + {} +}; + #define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { @@ -548,6 +567,13 @@ static int bxt_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + if (x86_match_cpu(glk_ids)) + snd_soc_dapm_add_routes(&card->dapm, gemini_map, + ARRAY_SIZE(gemini_map)); + else + snd_soc_dapm_add_routes(&card->dapm, broxton_map, + ARRAY_SIZE(broxton_map)); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -583,8 +609,8 @@ static struct snd_soc_card broxton_audio_card = { .num_controls = ARRAY_SIZE(broxton_controls), .dapm_widgets = broxton_widgets, .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_map, - .num_dapm_routes = ARRAY_SIZE(broxton_map), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), .fully_routed = true, .late_probe = bxt_card_late_probe, }; @@ -604,6 +630,26 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + if (x86_match_cpu(glk_ids)) { + unsigned int i; + + broxton_audio_card.name = "glkda7219max"; + /* Fixup the SSP entries for geminilake */ + for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { + /* MAXIM_CODEC is connected to SSP1. */ + if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_MAXIM_CODEC_DAI)) { + broxton_dais[i].name = "SSP1-Codec"; + broxton_dais[i].cpu_dai_name = "SSP1 Pin"; + } + /* DIALOG_CODE is connected to SSP2 */ + else if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_DIALOG_CODEC_DAI)) { + broxton_dais[i].name = "SSP2-Codec"; + broxton_dais[i].cpu_dai_name = "SSP2 Pin"; + } + } + } /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; @@ -617,12 +663,19 @@ static int broxton_audio_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } +static const struct platform_device_id bxt_board_ids[] = { + { .name = "bxt_da7219_max98357a" }, + { .name = "glk_da7219_max98357a" }, + { } +}; + static struct platform_driver broxton_audio = { .probe = broxton_audio_probe, .driver = { .name = "bxt_da7219_max98357a", .pm = &snd_soc_pm_ops, }, + .id_table = bxt_board_ids, }; module_platform_driver(broxton_audio) @@ -632,5 +685,7 @@ MODULE_AUTHOR("Sathyanarayana Nujella "); MODULE_AUTHOR("Rohit Ainapure "); MODULE_AUTHOR("Harsha Priya "); MODULE_AUTHOR("Conrad Cooke "); +MODULE_AUTHOR("Naveen Manohar "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:bxt_da7219_max98357a"); +MODULE_ALIAS("platform:glk_da7219_max98357a"); From bc3523a3acb3ba311d5d9939901ff2b7f8833e44 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:53 -0600 Subject: [PATCH 418/461] ASoC: Intel: glk: Add DAI links for Multi-Playback Add FE DAI link to support parallel playback on 2 ports simultaneously. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 407b0cfc5167..5cadb7f654f3 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -51,6 +51,7 @@ struct bxt_card_private { enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, + BXT_DPCM_AUDIO_HS_PB, BXT_DPCM_AUDIO_REF_CP, BXT_DPCM_AUDIO_DMIC_CP, BXT_DPCM_AUDIO_HDMI1_PB, @@ -405,6 +406,20 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_capture = 1, .ops = &broxton_da7219_fe_ops, }, + [BXT_DPCM_AUDIO_HS_PB] = { + .name = "Bxt Audio Headset Playback", + .stream_name = "Headset Playback", + .cpu_dai_name = "System Pin2", + .platform_name = "0000:00:0e.0", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &broxton_da7219_fe_ops, + }, [BXT_DPCM_AUDIO_REF_CP] = { .name = "Bxt Audio Reference cap", From 022c4156697b9ae30a00f5cd7cee08ed61554e86 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 19 Feb 2019 16:19:40 +0100 Subject: [PATCH 419/461] ASoC: samsung: i2s: Fix secondary platform device unregistration This fixes unregistration of the secondary platform device so all resources are properly released. Additionally the removal sequence is corrected so it is in reverse order comparing to probe sequence. The test against NULL priv->pdev_sec is removed as it is not necessary. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 02472f576e17..cd92bb6e1da1 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1359,11 +1359,10 @@ static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) static void i2s_delete_secondary_device(struct samsung_i2s_priv *priv) { - if (priv->pdev_sec) { - platform_device_del(priv->pdev_sec); - priv->pdev_sec = NULL; - } + platform_device_unregister(priv->pdev_sec); + priv->pdev_sec = NULL; } + static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; @@ -1487,14 +1486,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->filter, "tx-sec", NULL, &pdev->dev); if (ret < 0) - goto err_disable_clk; + goto err_del_sec; } if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); ret = -EINVAL; - goto err_disable_clk; + goto err_del_sec; } dev_set_drvdata(&pdev->dev, priv); @@ -1503,7 +1502,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) &samsung_i2s_component, priv->dai_drv, num_dais); if (ret < 0) - goto err_disable_clk; + goto err_del_sec; pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1518,9 +1517,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) err_disable_pm: pm_runtime_disable(&pdev->dev); +err_del_sec: + i2s_delete_secondary_device(priv); err_disable_clk: clk_disable_unprepare(priv->clk); - i2s_delete_secondary_device(priv); return ret; } @@ -1536,9 +1536,10 @@ static int samsung_i2s_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); i2s_unregister_clock_provider(priv); - clk_disable_unprepare(priv->clk); - pm_runtime_put_noidle(&pdev->dev); i2s_delete_secondary_device(priv); + clk_disable_unprepare(priv->clk); + + pm_runtime_put_noidle(&pdev->dev); return 0; } From c6bebefa2f0603fb21ae329521e15461b0486679 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 19 Feb 2019 16:19:41 +0100 Subject: [PATCH 420/461] ASoC: samsung: i2s: Fix multiple "IIS multi" devices initialization On some SoCs (e.g. Exynos5433) there are multiple "IIS multi audio interfaces" and the driver will try to register there multiple times same platform device for the secondary FIFO, which of course fails miserably. To fix this we derive the secondary platform device name from the primary device name. The secondary device name will now be -sec instead of fixed "samsung-i2s-sec". The fixed platform_device_id table entry is removed as the secondary device name is now dynamic and device/driver matching is done through driver_override. Reported-by: Marek Szyprowski Suggested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 50 +++++++++++++++++++++++++------------- sound/soc/samsung/odroid.c | 2 +- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index cd92bb6e1da1..4231001226f4 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1339,20 +1339,35 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) /* Create platform device for the secondary PCM */ static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) { - struct platform_device *pdev; + struct platform_device *pdev_sec; + const char *devname; int ret; - pdev = platform_device_register_simple("samsung-i2s-sec", -1, NULL, 0); - if (!pdev) + devname = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s-sec", + dev_name(&priv->pdev->dev)); + if (!devname) return -ENOMEM; - ret = device_attach(&pdev->dev); + pdev_sec = platform_device_alloc(devname, -1); + if (!pdev_sec) + return -ENOMEM; + + pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); + + ret = platform_device_add(pdev_sec); if (ret < 0) { - dev_info(&pdev->dev, "device_attach() failed\n"); + platform_device_put(pdev_sec); return ret; } - priv->pdev_sec = pdev; + ret = device_attach(&pdev_sec->dev); + if (ret <= 0) { + platform_device_unregister(priv->pdev_sec); + dev_info(&pdev_sec->dev, "device_attach() failed\n"); + return ret; + } + + priv->pdev_sec = pdev_sec; return 0; } @@ -1367,22 +1382,25 @@ static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; - struct resource *res; u32 regs_base, idma_addr = 0; struct device_node *np = pdev->dev.of_node; const struct samsung_i2s_dai_data *i2s_dai_data; - int num_dais, ret; + const struct platform_device_id *id; struct samsung_i2s_priv *priv; + struct resource *res; + int num_dais, ret; - if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { i2s_dai_data = of_device_get_match_data(&pdev->dev); - else - i2s_dai_data = (struct samsung_i2s_dai_data *) - platform_get_device_id(pdev)->driver_data; + } else { + id = platform_get_device_id(pdev); - /* Nothing to do if it is the secondary device probe */ - if (!i2s_dai_data) - return 0; + /* Nothing to do if it is the secondary device probe */ + if (!id) + return 0; + + i2s_dai_data = (struct samsung_i2s_dai_data *)id->driver_data; + } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1637,8 +1655,6 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { { .name = "samsung-i2s", .driver_data = (kernel_ulong_t)&i2sv3_dai_type, - }, { - .name = "samsung-i2s-sec", }, {}, }; diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 5b2bcd1d3450..bd2c5163dc7f 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -185,7 +185,7 @@ static struct snd_soc_dai_link odroid_card_dais[] = { .ops = &odroid_card_fe_ops, .name = "Secondary", .stream_name = "Secondary", - .platform_name = "samsung-i2s-sec", + .platform_name = "3830000.i2s-sec", .dynamic = 1, .dpcm_playback = 1, } From fcf4daabf08079e6d09958a2992e7446ef8d0438 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 19 Feb 2019 16:29:12 +0000 Subject: [PATCH 421/461] ASoC: codecs: pcm186x: fix wrong usage of DECLARE_TLV_DB_SCALE() According to DS, the gain is between -12 dB and 40 dB, with a 0.5 dB step. Tested on pcm1863. Signed-off-by: Codrin Ciubotariu Acked-by: Andrew F. Davis Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/pcm186x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 809b7e9f03ca..c36a391fec8a 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -42,7 +42,7 @@ struct pcm186x_priv { bool is_master_mode; }; -static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 4000, 50); +static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0); static const struct snd_kcontrol_new pcm1863_snd_controls[] = { SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L, From 05bd7fcdd06b19a10f069af1bea3ad9abac038d7 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Tue, 19 Feb 2019 16:29:28 +0000 Subject: [PATCH 422/461] ASoC: codecs: pcm186x: Fix energysense SLEEP bit The ADCs are sleeping when the SLEEP bit is set and running when it's cleared, so the bit should be inverted. Tested on pcm1863. Signed-off-by: Codrin Ciubotariu Acked-by: Andrew F. Davis Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/pcm186x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index c36a391fec8a..c5fcc632f670 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -158,7 +158,7 @@ static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = { * Put the codec into SLEEP mode when not in use, allowing the * Energysense mechanism to operate. */ - SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 0), + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 1), }; static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = { @@ -184,8 +184,8 @@ static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = { * Put the codec into SLEEP mode when not in use, allowing the * Energysense mechanism to operate. */ - SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 0), - SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 0), + SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 1), + SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 1), }; static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = { From 31d2350d602511efc9ef626b848fe521233b0387 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Feb 2019 14:38:06 +0100 Subject: [PATCH 423/461] ALSA: ac97: Fix of-node refcount unbalance ac97_of_get_child_device() take the refcount of the node explicitly via of_node_get(), but this leads to an unbalance. The for_each_child_of_node() loop itself takes the refcount for each iteration node, hence you don't need to take the extra refcount again. Fixes: 2225a3e6af78 ("ALSA: ac97: add codecs devicetree binding") Reviewed-by: Robert Jarzmik Signed-off-by: Takashi Iwai --- sound/ac97/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 9f0c480489ef..9cbf6927abe9 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -84,7 +84,7 @@ ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx, if ((idx != of_property_read_u32(node, "reg", ®)) || !of_device_is_compatible(node, compat)) continue; - return of_node_get(node); + return node; } return NULL; From 00178c9175402c364a1456742c0d71bdc4189e0c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Feb 2019 14:41:25 +0100 Subject: [PATCH 424/461] ALSA: aoa: Fix of-node refcount unbalance We forgot to unreference a node obtained via of_find_node_by_name() after its usage. Reviewed-by: Johannes Berg Signed-off-by: Takashi Iwai --- sound/aoa/core/gpio-feature.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index 65557421fe0b..c3ff721e4660 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c @@ -82,6 +82,7 @@ static struct device_node *get_gpio(char *name, if (altname && (strcmp(audio_gpio, altname) == 0)) break; } + of_node_put(gpio); /* still not found, assume not there */ if (!np) return NULL; From 5e2c9465825595e3c295085c1ffb14eb239e3278 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Feb 2019 15:05:24 +0100 Subject: [PATCH 425/461] ALSA: ppc: Fix of-node refcount unbalance We forgot to unreference the node when aborting from the loop of for_each_child_of_node() in snd_pmac_tumbler_init(). This leads to unbalanced node refcount. Fix it by adding the missing of_node_put() call. Signed-off-by: Takashi Iwai --- sound/ppc/tumbler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 6d7ffffcce95..78e5798ae967 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1371,6 +1371,7 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip) mix->anded_reset = 1; if (of_get_property(np, "layout-id", NULL)) mix->reset_on_sleep = 0; + of_node_put(np); break; } } From cf4ba4dc5f4ce6400a430c1e9a51d74283c706a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Feb 2019 12:53:08 +0100 Subject: [PATCH 426/461] ALSA: hda/realtek - Fix a typo in model documentation Some garbage was taken via copy-and-paste error. Clean up. Fixes: a26d96c7802e ("ALSA: hda/realtek - Comprehensive model list for ALC259 & co") Signed-off-by: Takashi Iwai --- Documentation/sound/hd-audio/models.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 368a07a165f5..ef6101a78136 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -254,7 +254,7 @@ alc274-dell-aio ALC274 fixups on Dell AIO machines alc255-dummy-lineout Dell Precision 3930 fixups -alc255-dell-headset"}, +alc255-dell-headset Dell Precision 3630 fixups alc295-hp-x360 HP Spectre X360 fixups From b16d7ee241d8b998bf2ecb72f83fefec31cae96f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Feb 2019 12:55:21 +0100 Subject: [PATCH 427/461] ALSA: hda/realtek - Add model description for Chrome headset button quirk Forgot to update the document. Fixes: e854747d7593 ("ALSA: hda/realtek - Enable headset button support for new codec") Signed-off-by: Takashi Iwai --- Documentation/sound/hd-audio/models.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index ef6101a78136..7d7c191102a7 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst @@ -258,6 +258,8 @@ alc255-dell-headset Dell Precision 3630 fixups alc295-hp-x360 HP Spectre X360 fixups +alc-sense-combo + Headset button support for Chrome platform ALC66x/67x/892 ============== From f938f3485c385b9b5c796b2e93427c015a7d18fa Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Tue, 19 Feb 2019 17:31:57 +0000 Subject: [PATCH 428/461] ASoC: wm_adsp: Update cached error state on trigger If a compressed stream is restarted after getting an error, the cached error value will still be used on the next pointer request, preventing the stream from starting. Resolve this by ensuring the error status is updated on trigger start. Signed-off-by: Stuart Henderson Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 1dd291cebe67..d15cf6e42adc 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3422,6 +3422,23 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp) return 0; } +static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) +{ + int ret; + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); + if (ret < 0) { + adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); + return ret; + } + if (buf->error != 0) { + adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); + return -EIO; + } + + return 0; +} + int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) { struct wm_adsp_compr *compr = stream->runtime->private_data; @@ -3443,6 +3460,10 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) } } + ret = wm_adsp_buffer_get_error(compr->buf); + if (ret < 0) + break; + wm_adsp_buffer_clear(compr->buf); /* Trigger the IRQ at one fragment of data */ @@ -3518,23 +3539,6 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) return 0; } -static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) -{ - int ret; - - ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); - if (ret < 0) { - adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); - return ret; - } - if (buf->error != 0) { - adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); - return -EIO; - } - - return 0; -} - int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) { struct wm_adsp_compr_buf *buf; From fb13f19d102ee47c0f27fda70387052a3fd3e656 Mon Sep 17 00:00:00 2001 From: Andrew Ford Date: Tue, 19 Feb 2019 17:31:56 +0000 Subject: [PATCH 429/461] ASoC: wm_adsp: Allow compressed buffers in any memory region Currently, compressed buffers can only be specified in the XM memory region. There is no reason to have such a restriction with the newer meta-data based way of specifying the buffers, so remove it. Signed-off-by: Andrew Ford Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 1dd291cebe67..12ef85e85c29 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -344,6 +344,7 @@ struct wm_adsp_compr_buf { u32 irq_count; int read_index; int avail; + int host_buf_mem_type; }; struct wm_adsp_compr { @@ -3219,14 +3220,14 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, unsigned int field_offset, u32 *data) { - return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM, + return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type, buf->host_buf_ptr + field_offset, data); } static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, unsigned int field_offset, u32 data) { - return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM, + return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type, buf->host_buf_ptr + field_offset, data); } @@ -3264,6 +3265,8 @@ static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) if (!buf->host_buf_ptr) return -EIO; + buf->host_buf_mem_type = WMFW_ADSP2_XM; + adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; @@ -3282,6 +3285,7 @@ wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf) if (!ctl->enabled) continue; + buf->host_buf_mem_type = ctl->alg_region.type; return ctl; } From 2757970f6d0d0a112247600b23d38c0c728ceeb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:47 +0100 Subject: [PATCH 430/461] ASoC: fsl: Fix of-node refcount unbalance in fsl_ssi_probe_from_dt() The node obtained from of_find_node_by_path() has to be unreferenced after the use, but we forgot it for the root node. Fixes: f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support") Cc: Timur Tabi Cc: Nicolin Chen Cc: Xiubo Li Cc: Fabio Estevam Signed-off-by: Takashi Iwai Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 0a648229e643..09b2967befd9 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1439,8 +1439,10 @@ static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi) * different name to register the device. */ if (!ssi->card_name[0] && of_get_property(np, "codec-handle", NULL)) { - sprop = of_get_property(of_find_node_by_path("/"), - "compatible", NULL); + struct device_node *root = of_find_node_by_path("/"); + + sprop = of_get_property(root, "compatible", NULL); + of_node_put(root); /* Strip "fsl," in the compatible name if applicable */ p = strrchr(sprop, ','); if (p) From 44662f90cda7ce0b65e77a7f1eefe45fb9053a4e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:48 +0100 Subject: [PATCH 431/461] ASoC: simple-card: Fix missing of_node_put() at simple_dai_link_of() We forgot to unreference the platform node object obtained from of_get_child_by_name(). This leads to the unbalance of node refcount. Fixes: e0ae225b7e96 ("ASoC: simple-card: support platform in dts parse") Signed-off-by: Takashi Iwai Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index dc18c4492955..092963e90e1e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -421,6 +421,7 @@ static int simple_dai_link_of(struct simple_priv *priv, asoc_simple_card_canonicalize_platform(dai_link); dai_link_of_err: + of_node_put(plat); of_node_put(node); return ret; From 0b9c9ed6dd3b61b1d3ef1638786a7216006f67c5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:49 +0100 Subject: [PATCH 432/461] ASoC: simple-card: Fix of-node refcount unbalance in DAI-link parser The function simple_for_each_link() has a few missing places that forgot unrefereing of-nodes after the use. The main do-while loop may abort when loop=0, and this leaves the node object still referenced. A similar leak is found in the error handling of NULL codec that aborts the loop as well. Last but not least, the inner for_each_child_of_node() loop may abort in the middle, and this leaks the refcount of the iterator node. This patch addresses these missing refcount issues. Signed-off-by: Takashi Iwai Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 092963e90e1e..7147bba45a2a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -442,6 +442,7 @@ static int simple_for_each_link(struct simple_priv *priv, struct device_node *top = dev->of_node; struct device_node *node; bool is_top = 0; + int ret = 0; /* Check if it has dai-link */ node = of_get_child_by_name(top, PREFIX "dai-link"); @@ -456,13 +457,14 @@ static int simple_for_each_link(struct simple_priv *priv, struct device_node *codec; struct device_node *np; int num = of_get_child_count(node); - int ret; /* get codec */ codec = of_get_child_by_name(node, is_top ? PREFIX "codec" : "codec"); - if (!codec) - return -ENODEV; + if (!codec) { + ret = -ENODEV; + goto error; + } of_node_put(codec); @@ -485,14 +487,18 @@ static int simple_for_each_link(struct simple_priv *priv, else ret = func_noml(priv, np, codec, li, is_top); - if (ret < 0) - return ret; + if (ret < 0) { + of_node_put(np); + goto error; + } } node = of_get_next_child(top, node); } while (!is_top && node); - return 0; + error: + of_node_put(node); + return ret; } static int simple_parse_aux_devs(struct device_node *node, From c0ca5eced22215c1e03e3ad479f8fab0bbb30772 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 20 Feb 2019 16:15:45 +0100 Subject: [PATCH 433/461] ALSA: hda/realtek - Reduce click noise on Dell Precision 5820 headphone Dell Precision 5820 with ALC3234 codec (which is equivalent with ALC255) shows click noises at (runtime) PM resume on the headphone. The biggest source of the noise comes from the cleared headphone pin control at resume, which is done via the standard shutup procedure. Although we have an override of the standard shutup callback to replace with NOP, this would skip other needed stuff (e.g. the pull down of headset power). So, instead, this "fixes" the behavior of alc_fixup_no_shutup() by introducing spec->no_shutup_pins flag. When this flag is set, Realtek codec won't call the standard snd_hda_shutup_pins() & co. Now alc_fixup_no_shutup() just sets this flag instead of overriding spec->shutup callback itself. This allows us to apply the similar fix for other entries easily if needed in future. Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 57 +++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1212955f7ab5..5855648b500c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -118,6 +118,7 @@ struct alc_spec { unsigned int has_alc5505_dsp:1; unsigned int no_depop_delay:1; unsigned int done_hp_init:1; + unsigned int no_shutup_pins:1; /* for PLL fix */ hda_nid_t pll_nid; @@ -476,6 +477,14 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) set_eapd(codec, *p, on); } +static void alc_shutup_pins(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->no_shutup_pins) + snd_hda_shutup_pins(codec); +} + /* generic shutup callback; * just turning off EAPD and a little pause for avoiding pop-noise */ @@ -486,7 +495,7 @@ static void alc_eapd_shutup(struct hda_codec *codec) alc_auto_setup_eapd(codec, false); if (!spec->no_depop_delay) msleep(200); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } /* generic EAPD initialization */ @@ -814,7 +823,7 @@ static inline void alc_shutup(struct hda_codec *codec) if (spec && spec->shutup) spec->shutup(codec); else - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } static void alc_reboot_notify(struct hda_codec *codec) @@ -2922,7 +2931,7 @@ static void alc269_shutup(struct hda_codec *codec) (alc_get_coef0(codec) & 0x00ff) == 0x018) { msleep(150); } - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } static struct coef_fw alc282_coefs[] = { @@ -3025,14 +3034,15 @@ static void alc282_shutup(struct hda_codec *codec) if (hp_pin_sense) msleep(85); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); if (hp_pin_sense) msleep(100); alc_auto_setup_eapd(codec, false); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); alc_write_coef_idx(codec, 0x78, coef78); } @@ -3138,15 +3148,16 @@ static void alc283_shutup(struct hda_codec *codec) if (hp_pin_sense) msleep(100); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (hp_pin_sense) msleep(100); alc_auto_setup_eapd(codec, false); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); alc_write_coef_idx(codec, 0x43, 0x9614); } @@ -3212,14 +3223,15 @@ static void alc256_shutup(struct hda_codec *codec) /* NOTE: call this before clearing the pin, otherwise codec stalls */ alc_update_coef_idx(codec, 0x46, 0, 3 << 12); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); if (hp_pin_sense) msleep(100); alc_auto_setup_eapd(codec, false); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } static void alc225_init(struct hda_codec *codec) @@ -3306,7 +3318,7 @@ static void alc225_shutup(struct hda_codec *codec) msleep(100); alc_auto_setup_eapd(codec, false); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } static void alc_default_init(struct hda_codec *codec) @@ -3360,14 +3372,15 @@ static void alc_default_shutup(struct hda_codec *codec) if (hp_pin_sense) msleep(85); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); if (hp_pin_sense) msleep(100); alc_auto_setup_eapd(codec, false); - snd_hda_shutup_pins(codec); + alc_shutup_pins(codec); } static void alc294_hp_init(struct hda_codec *codec) @@ -3384,8 +3397,9 @@ static void alc294_hp_init(struct hda_codec *codec) msleep(100); - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); alc_update_coef_idx(codec, 0x6f, 0x000f, 0);/* Set HP depop to manual mode */ alc_update_coefex_idx(codec, 0x58, 0x00, 0x8000, 0x8000); /* HP depop procedure start */ @@ -4981,16 +4995,12 @@ static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, } } -static void alc_no_shutup(struct hda_codec *codec) -{ -} - static void alc_fixup_no_shutup(struct hda_codec *codec, const struct hda_fixup *fix, int action) { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct alc_spec *spec = codec->spec; - spec->shutup = alc_no_shutup; + spec->no_shutup_pins = 1; } } @@ -6639,6 +6649,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), + SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), From d832d2b246c516eacb2d0ba53ec17ed59c3cd62b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Feb 2019 12:06:07 +0100 Subject: [PATCH 434/461] ASoC: samsung: odroid: Fix of_node refcount unbalance In odroid_audio_probe() some OF nodes are left without reference count decrease after use. Fix it by ensuring required of_node_calls() are done before exiting probe. Reported-by: Takashi Iwai Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index bd2c5163dc7f..c3b0f6c612cb 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -257,27 +257,31 @@ static int odroid_audio_probe(struct platform_device *pdev) ret = of_parse_phandle_with_args(cpu, "sound-dai", "#sound-dai-cells", i, &args); if (ret < 0) - return ret; + break; if (!args.np) { dev_err(dev, "sound-dai property parse error: %d\n", ret); - return -EINVAL; + ret = -EINVAL; + break; } ret = snd_soc_get_dai_name(&args, &link->cpu_dai_name); of_node_put(args.np); if (ret < 0) - return ret; + break; } + if (ret == 0) + cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); - cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); of_node_put(cpu); of_node_put(codec); + if (ret < 0) + return ret; ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); if (ret < 0) - goto err_put_codec_n; + goto err_put_cpu_dai; /* Set capture capability only for boards with the MAX98090 CODEC */ if (codec_link->num_codecs > 1) { @@ -288,7 +292,7 @@ static int odroid_audio_probe(struct platform_device *pdev) priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); if (IS_ERR(priv->sclk_i2s)) { ret = PTR_ERR(priv->sclk_i2s); - goto err_put_codec_n; + goto err_put_cpu_dai; } priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); @@ -310,7 +314,8 @@ err_put_clk_i2s: clk_put(priv->clk_i2s_bus); err_put_sclk: clk_put(priv->sclk_i2s); -err_put_codec_n: +err_put_cpu_dai: + of_node_put(cpu_dai); snd_soc_of_put_dai_link_codecs(codec_link); return ret; } From 8d1667200850f8753c0265fa4bd25c9a6e5f94ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:50 +0100 Subject: [PATCH 435/461] ASoC: qcom: Fix of-node refcount unbalance in apq8016_sbc_parse_of() The apq8016 driver leaves the of-node refcount at aborting from the loop of for_each_child_of_node() in the error path. Not only the iterator node of for_each_child_of_node(), the children nodes referred from it for codec and cpu have to be properly unreferenced. Fixes: bdb052e81f62 ("ASoC: qcom: add apq8016 sound card support") Cc: Patrick Lai Cc: Banajit Goswami Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/qcom/apq8016_sbc.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 1dd23bba1bed..4b559932adc3 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -164,41 +164,52 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) if (!cpu || !codec) { dev_err(dev, "Can't find cpu/codec DT node\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); if (!link->cpu_of_node) { dev_err(card->dev, "error getting cpu phandle\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); if (ret) { dev_err(card->dev, "error getting cpu dai name\n"); - return ERR_PTR(ret); + goto error; } ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { dev_err(card->dev, "error getting codec dai name\n"); - return ERR_PTR(ret); + goto error; } link->platform_of_node = link->cpu_of_node; ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); - return ERR_PTR(ret); + goto error; } link->stream_name = link->name; link->init = apq8016_sbc_dai_init; link++; + + of_node_put(cpu); + of_node_put(codec); } return data; + + error: + of_node_put(np); + of_node_put(cpu); + of_node_put(codec); + return ERR_PTR(ret); } static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { From 70b773219a32c7b8f3e53e041bc023ad99fd81f4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:51 +0100 Subject: [PATCH 436/461] ASoC: qcom: Fix of-node refcount unbalance in qcom_snd_parse_of() Although qcom_snd_parse_of() tries to manage the of-node refcount, there are still a few places that lead to the unblanced refcount in the error code path. Namely, - for_each_child_of_node() needs to unreference the iterator node if aborting the loop in the middle, - cpu, codec and platform node objects have to be unreferenced at each iteration, - platform and codec node objects have to be referred before jumping to the error handling code that unreference them unconditionally. This patch tries to address these by moving the assignment of platform and codec node objects to the beginning of the loop and adding the of_node_put() calls adequately. Fixes: c25e295cd77b ("ASoC: qcom: Add support to parse common audio device nodes") Cc: Patrick Lai Cc: Banajit Goswami Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/qcom/common.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 4715527054e5..5661025e8cec 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -42,6 +42,9 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link = card->dai_link; for_each_child_of_node(dev->of_node, np) { cpu = of_get_child_by_name(np, "cpu"); + platform = of_get_child_by_name(np, "platform"); + codec = of_get_child_by_name(np, "codec"); + if (!cpu) { dev_err(dev, "Can't find cpu DT node\n"); ret = -EINVAL; @@ -63,8 +66,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card) goto err; } - platform = of_get_child_by_name(np, "platform"); - codec = of_get_child_by_name(np, "codec"); if (codec && platform) { link->platform_of_node = of_parse_phandle(platform, "sound-dai", @@ -100,10 +101,15 @@ int qcom_snd_parse_of(struct snd_soc_card *card) link->dpcm_capture = 1; link->stream_name = link->name; link++; + + of_node_put(cpu); + of_node_put(codec); + of_node_put(platform); } return 0; err: + of_node_put(np); of_node_put(cpu); of_node_put(codec); of_node_put(platform); From 3af8160028bfac4116d80edcb7eb04095323d112 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Feb 2019 10:42:28 +0100 Subject: [PATCH 437/461] ASoC: samsung: odroid: Prevent uninitialized variable use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This addresses an issue pointed out by compiler warning: sound/soc/samsung/odroid.c: In function ‘odroid_audio_probe’: sound/soc/samsung/odroid.c:298:22: warning: ‘cpu_dai’ may be used uninitialized in this function [-Wmaybe-uninitialized] priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index c3b0f6c612cb..694512f980fd 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -194,7 +194,8 @@ static struct snd_soc_dai_link odroid_card_dais[] = { static int odroid_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *cpu, *cpu_dai, *codec; + struct device_node *cpu_dai = NULL; + struct device_node *cpu, *codec; struct odroid_priv *priv; struct snd_soc_card *card; struct snd_soc_dai_link *link, *codec_link; @@ -271,8 +272,11 @@ static int odroid_audio_probe(struct platform_device *pdev) if (ret < 0) break; } - if (ret == 0) + if (ret == 0) { cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); + if (!cpu_dai) + ret = -EINVAL; + } of_node_put(cpu); of_node_put(codec); From 8bb37a2a4d7c02affef554f5dc05f6d2e39c31f9 Mon Sep 17 00:00:00 2001 From: Jian-Hong Pan Date: Thu, 21 Feb 2019 17:00:18 +0800 Subject: [PATCH 438/461] ALSA: hda/realtek: Enable audio jacks of ASUS UX362FA with ALC294 The ASUS UX362FA with ALC294 cannot detect the headset MIC and outputs through the internal speaker and the headphone. This issue can be fixed by the quirk in the commit 4e0511067 ALSA: hda/realtek: Enable audio jacks of ASUS UX533FD with ALC294. Besides, ASUS UX362FA and UX533FD have the same audio initial pin config values. So, this patch replaces SND_PCI_QUIRK of UX533FD with a new SND_HDA_PIN_QUIRK which benefits both UX362FA and UX533FD. Fixes: 4e051106730d ("ALSA: hda/realtek: Enable audio jacks of ASUS UX533FD with ALC294") Signed-off-by: Jian-Hong Pan Signed-off-by: Ming Shuo Chiu Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5855648b500c..3bd1286eb5a8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6744,7 +6744,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), - SND_PCI_QUIRK(0x1043, 0x14a1, "ASUS UX533FD", ALC294_FIXUP_ASUS_SPK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), @@ -7361,6 +7360,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x14, 0x90170110}, {0x1b, 0x90a70130}, {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK, + {0x12, 0x90a60130}, + {0x17, 0x90170110}, + {0x21, 0x03211020}), SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK, {0x12, 0x90a60130}, {0x17, 0x90170110}, From a0d183c329165fdd77becba1f58bbe22a5f72ae9 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 20 Feb 2019 20:43:22 +0530 Subject: [PATCH 439/461] ALSA: hda/tegra: property for card name An optional property "nvidia,model" is introduced for hda to pass custom name for the sound card. The suffix "-hda" in the name passed is useful to distinguish between multiple cards available for a platform. When the property is not specified, default name("tegra-hda") mentioned in hda driver is used. This property can be added in platform specific file of the board and card name can relate to the board in use. Signed-off-by: Sameer Pujar Reviewed-by: Jonathan Hunter Signed-off-by: Takashi Iwai --- .../devicetree/bindings/sound/nvidia,tegra30-hda.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt index 44d27456e8a4..21cd310963b1 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-hda.txt @@ -13,6 +13,10 @@ Required properties: See ../reset/reset.txt for details. - reset-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x +Optional properties: +- nvidia,model : The user-visible name of this sound complex. Since the property + is optional, legacy boards can use default name provided in hda driver. + Example: hda@70030000 { @@ -27,4 +31,5 @@ hda@70030000 { <&tegra_car 128>, /* hda2hdmi */ <&tegra_car 111>; /* hda2codec_2x */ reset-names = "hda", "hda2hdmi", "hda2codec_2x"; + nvidia,model = "jetson-tk1-hda"; }; From 11ce4308307c380d0fa7a7694739ce712acb6174 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 20 Feb 2019 20:43:23 +0530 Subject: [PATCH 440/461] arm64: tegra: custom name for hda sound card "nvidia,model" property is added to pass custom name for hda sound card. This is parsed in hda driver and used for card name. This aligns with the way with which sound cards are named in general. This patch populates above for jetson-tx1, jetson-tx2 and jetson-xavier. Signed-off-by: Sameer Pujar Reviewed-by: Jonathan Hunter Signed-off-by: Takashi Iwai --- arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 1 + arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 1 + arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts index 65487eee2ce6..05611eff53f6 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts @@ -52,6 +52,7 @@ }; hda@3510000 { + nvidia,model = "jetson-tx2-hda"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts index adf351010ff5..39c616737232 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts @@ -25,6 +25,7 @@ }; hda@3510000 { + nvidia,model = "jetson-xavier-hda"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi index a96e6ee70c21..6096dfb7e17a 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2597.dtsi @@ -1331,6 +1331,7 @@ }; hda@70030000 { + nvidia,model = "jetson-tx1-hda"; status = "okay"; }; From c0bde003a01384b599b7600a4b16ee706163ac53 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 20 Feb 2019 20:43:24 +0530 Subject: [PATCH 441/461] ALSA: hda/tegra: sound card name from device tree A platform can have multiple sound cards for different audio paths. Following is the print seen duirng device boot for jetson-xavier, ALSA device list: #0: nvidia,p2972-0000 at 0x3518000 irq 17 By looking at above, it is not very clear if the sound card is for HDA. It becomes confusing when platform has registered multiple cards, and platform model name is used for card. This patch uses "nvidia,model" property mentioned in hda device tree to get the card name. Since property is optional, legacy boards will continue to use "tegra-hda". Custom name can be passed wherever needed. This naming convention is conistent with the way sound cards are named in general. Signed-off-by: Sameer Pujar Reviewed-by: Jonathan Hunter Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_tegra.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index c8d18dc4da2a..dbd8da5685cb 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -380,8 +380,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) int err; unsigned short gcap; int irq_id = platform_get_irq(pdev, 0); - const char *sname; - struct device_node *root; + const char *sname, *drv_name = "tegra-hda"; + struct device_node *np = pdev->dev.of_node; err = hda_tegra_init_chip(chip, pdev); if (err) @@ -440,17 +440,11 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) } /* driver name */ - strcpy(card->driver, "tegra-hda"); - - root = of_find_node_by_path("/"); - sname = of_get_property(root, "compatible", NULL); - of_node_put(root); - if (!sname) { - dev_err(card->dev, - "failed to get compatible property from root node\n"); - return -ENODEV; - } + strncpy(card->driver, drv_name, sizeof(card->driver)); /* shortname for card */ + sname = of_get_property(np, "nvidia,model", NULL); + if (!sname) + sname = drv_name; if (strlen(sname) > sizeof(card->shortname)) dev_info(card->dev, "truncating shortname for card\n"); strncpy(card->shortname, sname, sizeof(card->shortname)); From eb23dcd20e91fe97679257dc4d195a707b4a0d1a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Feb 2019 09:31:51 +0300 Subject: [PATCH 442/461] ASoC: cs35l36: Fix an IS_ERR() vs NULL checking bug The irq_get_irq_data() function doesn't return error pointers, it returns NULL. Fixes: 6ba9dd6c893b ("ASoC: cs35l36: Add support for Cirrus CS35L36 Amplifier") Signed-off-by: Dan Carpenter Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index dc8cf61b9db8..e9b5f76f27a8 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1845,9 +1845,9 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client, cs35l36_apply_vpbr_config(cs35l36); irq_d = irq_get_irq_data(i2c_client->irq); - if (IS_ERR(irq_d)) { + if (!irq_d) { dev_err(&i2c_client->dev, "Invalid IRQ: %d\n", i2c_client->irq); - ret = PTR_ERR(irq_d); + ret = -ENODEV; goto err; } From cc7d6ce90216d101ae16f330fe05bd38e0e64cde Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2019 10:04:17 +0000 Subject: [PATCH 443/461] ASoC: wm_adsp: Factor out stripping padding from ADSP data In preparation for more refactoring add a helper function to strip the padding from ADSP data. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 12ef85e85c29..bd3241aacdb6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3231,6 +3231,21 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, buf->host_buf_ptr + field_offset, data); } +static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size) +{ + u8 *pack_in = (u8 *)buf; + u8 *pack_out = (u8 *)buf; + int i, j; + + /* Remove the padding bytes from the data read from the DSP */ + for (i = 0; i < nwords; i++) { + for (j = 0; j < data_word_size; j++) + *pack_out++ = *pack_in++; + + pack_in += sizeof(*buf) - data_word_size; + } +} + static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) { struct wm_adsp_alg_region *alg_region; @@ -3666,11 +3681,9 @@ EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) { struct wm_adsp_compr_buf *buf = compr->buf; - u8 *pack_in = (u8 *)compr->raw_buf; - u8 *pack_out = (u8 *)compr->raw_buf; unsigned int adsp_addr; int mem_type, nwords, max_read; - int i, j, ret; + int i, ret; /* Calculate read parameters */ for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) @@ -3702,13 +3715,7 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) if (ret < 0) return ret; - /* Remove the padding bytes from the data read from the DSP */ - for (i = 0; i < nwords; i++) { - for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++) - *pack_out++ = *pack_in++; - - pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE; - } + wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE); /* update read index to account for words read */ buf->read_index += nwords; From 1e38f069c7d74109cfb5cff04e7fb7a24fea1ea6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2019 10:04:18 +0000 Subject: [PATCH 444/461] ASoC: wm_adsp: Reorder some functions for improved clarity Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 81 +++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index bd3241aacdb6..852ab3f70689 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3246,6 +3246,47 @@ static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size) } } +static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) +{ + const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; + struct wm_adsp_buffer_region *region; + u32 offset = 0; + int i, ret; + + for (i = 0; i < caps->num_regions; ++i) { + region = &buf->regions[i]; + + region->offset = offset; + region->mem_type = caps->region_defs[i].mem_type; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, + ®ion->base_addr); + if (ret < 0) + return ret; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, + &offset); + if (ret < 0) + return ret; + + region->cumulative_size = offset; + + adsp_dbg(buf->dsp, + "region=%d type=%d base=%08x off=%08x size=%08x\n", + i, region->mem_type, region->base_addr, + region->offset, region->cumulative_size); + } + + return 0; +} + +static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf) +{ + buf->irq_count = 0xFFFFFFFF; + buf->read_index = -1; + buf->avail = 0; +} + static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) { struct wm_adsp_alg_region *alg_region; @@ -3343,46 +3384,6 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) return 0; } -static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) -{ - const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; - struct wm_adsp_buffer_region *region; - u32 offset = 0; - int i, ret; - - for (i = 0; i < caps->num_regions; ++i) { - region = &buf->regions[i]; - - region->offset = offset; - region->mem_type = caps->region_defs[i].mem_type; - - ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, - ®ion->base_addr); - if (ret < 0) - return ret; - - ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, - &offset); - if (ret < 0) - return ret; - - region->cumulative_size = offset; - - adsp_dbg(buf->dsp, - "region=%d type=%d base=%08x off=%08x size=%08x\n", - i, region->mem_type, region->base_addr, - region->offset, region->cumulative_size); - } - - return 0; -} - -static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf) -{ - buf->irq_count = 0xFFFFFFFF; - buf->read_index = -1; - buf->avail = 0; -} static int wm_adsp_buffer_init(struct wm_adsp *dsp) { From a792af69b08fd7f89b156c8cba1dfc2088522582 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2019 10:04:19 +0000 Subject: [PATCH 445/461] ASoC: wm_adsp: Refactor compress stream initialisation Make the code slightly clearer and prepare things for the addition of multiple compressed streams on a single DSP core. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 139 ++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 852ab3f70689..4fdcef3f0ecc 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3253,6 +3253,11 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) u32 offset = 0; int i, ret; + buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions), + GFP_KERNEL); + if (!buf->regions) + return -ENOMEM; + for (i = 0; i < caps->num_regions; ++i) { region = &buf->regions[i]; @@ -3287,13 +3292,34 @@ static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf) buf->avail = 0; } -static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) +static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + + buf->dsp = dsp; + + wm_adsp_buffer_clear(buf); + + dsp->buffer = buf; + + return buf; +} + +static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) { struct wm_adsp_alg_region *alg_region; - struct wm_adsp *dsp = buf->dsp; + struct wm_adsp_compr_buf *buf; u32 xmalg, addr, magic; int i, ret; + buf = wm_adsp_buffer_alloc(dsp); + if (!buf) + return -ENOMEM; + alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); @@ -3303,7 +3329,7 @@ static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) return ret; if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) - return -EINVAL; + return -ENODEV; addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); for (i = 0; i < 5; ++i) { @@ -3323,49 +3349,27 @@ static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf) buf->host_buf_mem_type = WMFW_ADSP2_XM; - adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + ret = wm_adsp_buffer_populate(buf); + if (ret < 0) + return ret; + + adsp_dbg(dsp, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; } -static struct wm_coeff_ctl * -wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf) +static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) { - struct wm_adsp *dsp = buf->dsp; - struct wm_coeff_ctl *ctl; - - list_for_each_entry(ctl, &dsp->ctl_list, list) { - if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) - continue; - - if (!ctl->enabled) - continue; - - buf->host_buf_mem_type = ctl->alg_region.type; - return ctl; - } - - return NULL; -} - -static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) -{ - struct wm_adsp *dsp = buf->dsp; - struct wm_coeff_ctl *ctl; - unsigned int reg; - u32 val; - int i, ret; - - ctl = wm_adsp_find_host_buffer_ctrl(buf); - if (!ctl) - return wm_adsp_legacy_host_buf_addr(buf); + struct wm_adsp_compr_buf *buf; + unsigned int val, reg; + int ret, i; ret = wm_coeff_base_reg(ctl, ®); if (ret) return ret; for (i = 0; i < 5; ++i) { - ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); + ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val)); if (ret < 0) return ret; @@ -3375,56 +3379,61 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) usleep_range(1000, 2000); } - if (!val) + if (!val) { + adsp_err(ctl->dsp, "Failed to acquire host buffer\n"); return -EIO; + } + buf = wm_adsp_buffer_alloc(ctl->dsp); + if (!buf) + return -ENOMEM; + + buf->host_buf_mem_type = ctl->alg_region.type; buf->host_buf_ptr = be32_to_cpu(val); - adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + + ret = wm_adsp_buffer_populate(buf); + if (ret < 0) + return ret; + + adsp_dbg(ctl->dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; } - static int wm_adsp_buffer_init(struct wm_adsp *dsp) { - struct wm_adsp_compr_buf *buf; + struct wm_coeff_ctl *ctl; int ret; - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return -ENOMEM; + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) + continue; - buf->dsp = dsp; + if (!ctl->enabled) + continue; - wm_adsp_buffer_clear(buf); + ret = wm_adsp_buffer_parse_coeff(ctl); + if (ret < 0) { + adsp_err(dsp, "Failed to parse coeff: %d\n", ret); + goto error; + } - ret = wm_adsp_buffer_locate(buf); - if (ret < 0) { - adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret); - goto err_buffer; + return 0; } - buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions, - sizeof(*buf->regions), GFP_KERNEL); - if (!buf->regions) { - ret = -ENOMEM; - goto err_buffer; + if (!dsp->buffer) { + /* Fall back to legacy support */ + ret = wm_adsp_buffer_parse_legacy(dsp); + if (ret) { + adsp_err(dsp, "Failed to parse legacy: %d\n", ret); + goto error; + } } - ret = wm_adsp_buffer_populate(buf); - if (ret < 0) { - adsp_err(dsp, "Failed to populate host buffer: %d\n", ret); - goto err_regions; - } - - dsp->buffer = buf; - return 0; -err_regions: - kfree(buf->regions); -err_buffer: - kfree(buf); +error: + wm_adsp_buffer_free(dsp); return ret; } From 4f2d4eabf57718875b97363a3bd35de490f354c5 Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Fri, 22 Feb 2019 10:04:20 +0000 Subject: [PATCH 446/461] ASoC: wm_adsp: Add support for multiple compressed buffers Currently, only a single compressed stream is supported per firmware. Add support for multiple compressed streams on a single firmware, this allows additional features like completely independent trigger words or separate debug capture streams to be implemented. Signed-off-by: Stuart Henderson Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 166 ++++++++++++++++++++++++++----------- sound/soc/codecs/wm_adsp.h | 4 +- 2 files changed, 119 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 4fdcef3f0ecc..fe802fc331c5 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -310,6 +310,12 @@ struct wm_adsp_alg_xm_struct { __be64 smoothed_power; }; +struct wm_adsp_host_buf_coeff_v1 { + __be32 host_buf_ptr; /* Host buffer pointer */ + __be32 versions; /* Version numbers */ + __be32 name[4]; /* The buffer name */ +}; + struct wm_adsp_buffer { __be32 buf1_base; /* Base addr of first buffer area */ __be32 buf1_size; /* Size of buf1 area in DSP words */ @@ -334,6 +340,7 @@ struct wm_adsp_buffer { struct wm_adsp_compr; struct wm_adsp_compr_buf { + struct list_head list; struct wm_adsp *dsp; struct wm_adsp_compr *compr; @@ -345,9 +352,12 @@ struct wm_adsp_compr_buf { int read_index; int avail; int host_buf_mem_type; + + char *name; }; struct wm_adsp_compr { + struct list_head list; struct wm_adsp *dsp; struct wm_adsp_compr_buf *buf; @@ -358,6 +368,8 @@ struct wm_adsp_compr { unsigned int copied_total; unsigned int sample_rate; + + const char *name; }; #define WM_ADSP_DATA_WORD_SIZE 3 @@ -375,6 +387,11 @@ struct wm_adsp_compr { #define ALG_XM_FIELD(field) \ (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32)) +#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER 1 + +#define HOST_BUF_COEFF_COMPAT_VER_MASK 0xFF00 +#define HOST_BUF_COEFF_COMPAT_VER_SHIFT 8 + static int wm_adsp_buffer_init(struct wm_adsp *dsp); static int wm_adsp_buffer_free(struct wm_adsp *dsp); @@ -708,7 +725,7 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, mutex_lock(&dsp[e->shift_l].pwr_lock); - if (dsp[e->shift_l].booted || dsp[e->shift_l].compr) + if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list)) ret = -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; @@ -2430,6 +2447,8 @@ static int wm_adsp_common_init(struct wm_adsp *dsp) INIT_LIST_HEAD(&dsp->alg_regions); INIT_LIST_HEAD(&dsp->ctl_list); + INIT_LIST_HEAD(&dsp->compr_list); + INIT_LIST_HEAD(&dsp->buffer_list); mutex_init(&dsp->pwr_lock); @@ -2972,14 +2991,19 @@ static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) { - /* - * Note this will be more complex once each DSP can support multiple - * streams - */ - if (!compr->dsp->buffer) + struct wm_adsp_compr_buf *buf = NULL, *tmp; + + list_for_each_entry(tmp, &compr->dsp->buffer_list, list) { + if (!tmp->name || !strcmp(compr->name, tmp->name)) { + buf = tmp; + break; + } + } + + if (!buf) return -EINVAL; - compr->buf = compr->dsp->buffer; + compr->buf = buf; compr->buf->compr = compr; return 0; @@ -3002,7 +3026,8 @@ static void wm_adsp_compr_detach(struct wm_adsp_compr *compr) int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) { - struct wm_adsp_compr *compr; + struct wm_adsp_compr *compr, *tmp; + struct snd_soc_pcm_runtime *rtd = stream->private_data; int ret = 0; mutex_lock(&dsp->pwr_lock); @@ -3019,11 +3044,12 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) goto out; } - if (dsp->compr) { - /* It is expect this limitation will be removed in future */ - adsp_err(dsp, "Only a single stream supported per DSP\n"); - ret = -EBUSY; - goto out; + list_for_each_entry(tmp, &dsp->compr_list, list) { + if (!strcmp(tmp->name, rtd->codec_dai->name)) { + adsp_err(dsp, "Only a single stream supported per dai\n"); + ret = -EBUSY; + goto out; + } } compr = kzalloc(sizeof(*compr), GFP_KERNEL); @@ -3034,8 +3060,9 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) compr->dsp = dsp; compr->stream = stream; + compr->name = rtd->codec_dai->name; - dsp->compr = compr; + list_add_tail(&compr->list, &dsp->compr_list); stream->runtime->private_data = compr; @@ -3054,7 +3081,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream) mutex_lock(&dsp->pwr_lock); wm_adsp_compr_detach(compr); - dsp->compr = NULL; + list_del(&compr->list); kfree(compr->raw_buf); kfree(compr); @@ -3304,7 +3331,7 @@ static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp) wm_adsp_buffer_clear(buf); - dsp->buffer = buf; + list_add_tail(&buf->list, &dsp->buffer_list); return buf; } @@ -3360,6 +3387,7 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) { + struct wm_adsp_host_buf_coeff_v1 coeff_v1; struct wm_adsp_compr_buf *buf; unsigned int val, reg; int ret, i; @@ -3395,9 +3423,45 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) if (ret < 0) return ret; - adsp_dbg(ctl->dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + /* + * v0 host_buffer coefficients didn't have versioning, so if the + * control is one word, assume version 0. + */ + if (ctl->len == 4) { + adsp_dbg(ctl->dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + return 0; + } - return 0; + ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1, + sizeof(coeff_v1)); + if (ret < 0) + return ret; + + coeff_v1.versions = be32_to_cpu(coeff_v1.versions); + val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK; + val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; + + if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) { + adsp_err(ctl->dsp, + "Host buffer coeff ver %u > supported version %u\n", + val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++) + coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]); + + wm_adsp_remove_padding((u32 *)&coeff_v1.name, + ARRAY_SIZE(coeff_v1.name), + WM_ADSP_DATA_WORD_SIZE); + + buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, + (char *)&coeff_v1.name); + + adsp_dbg(ctl->dsp, "host_buf_ptr=%x coeff version %u\n", + buf->host_buf_ptr, val); + + return val; } static int wm_adsp_buffer_init(struct wm_adsp *dsp) @@ -3416,12 +3480,13 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp) if (ret < 0) { adsp_err(dsp, "Failed to parse coeff: %d\n", ret); goto error; + } else if (ret == 0) { + /* Only one buffer supported for version 0 */ + return 0; } - - return 0; } - if (!dsp->buffer) { + if (list_empty(&dsp->buffer_list)) { /* Fall back to legacy support */ ret = wm_adsp_buffer_parse_legacy(dsp); if (ret) { @@ -3439,13 +3504,16 @@ error: static int wm_adsp_buffer_free(struct wm_adsp *dsp) { - if (dsp->buffer) { - wm_adsp_compr_detach(dsp->buffer->compr); + struct wm_adsp_compr_buf *buf, *tmp; - kfree(dsp->buffer->regions); - kfree(dsp->buffer); + list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) { + if (buf->compr) + wm_adsp_compr_detach(buf->compr); - dsp->buffer = NULL; + kfree(buf->name); + kfree(buf->regions); + list_del(&buf->list); + kfree(buf); } return 0; @@ -3572,39 +3640,39 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) mutex_lock(&dsp->pwr_lock); - buf = dsp->buffer; - compr = dsp->compr; - - if (!buf) { + if (list_empty(&dsp->buffer_list)) { ret = -ENODEV; goto out; } - adsp_dbg(dsp, "Handling buffer IRQ\n"); - ret = wm_adsp_buffer_get_error(buf); - if (ret < 0) - goto out_notify; /* Wake poll to report error */ + list_for_each_entry(buf, &dsp->buffer_list, list) { + compr = buf->compr; - ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), - &buf->irq_count); - if (ret < 0) { - adsp_err(dsp, "Failed to get irq_count: %d\n", ret); - goto out; - } + ret = wm_adsp_buffer_get_error(buf); + if (ret < 0) + goto out_notify; /* Wake poll to report error */ - ret = wm_adsp_buffer_update_avail(buf); - if (ret < 0) { - adsp_err(dsp, "Error reading avail: %d\n", ret); - goto out; - } + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), + &buf->irq_count); + if (ret < 0) { + adsp_err(dsp, "Failed to get irq_count: %d\n", ret); + goto out; + } - if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) - ret = WM_ADSP_COMPR_VOICE_TRIGGER; + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) + ret = WM_ADSP_COMPR_VOICE_TRIGGER; out_notify: - if (compr && compr->stream) - snd_compr_fragment_elapsed(compr->stream); + if (compr && compr->stream) + snd_compr_fragment_elapsed(compr->stream); + } out: mutex_unlock(&dsp->pwr_lock); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 4b8778b0b06c..59e07ad16329 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -90,8 +90,8 @@ struct wm_adsp { struct work_struct boot_work; - struct wm_adsp_compr *compr; - struct wm_adsp_compr_buf *buffer; + struct list_head compr_list; + struct list_head buffer_list; struct mutex pwr_lock; From 0d3fba3e7a566917f4286dd42b83c780c47dcbf7 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 22 Feb 2019 10:04:21 +0000 Subject: [PATCH 447/461] ASoC: wm_adsp: Improve logging messages As the compressed stream implementation has acquired support for multiple DAI links and compressed streams it has become harder to interpret messages in the kernel log. Add additional macros to include the compressed DAI name in the log messages, allowing different streams to be easily disambiguated. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 97 +++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index fe802fc331c5..8077c18cbcdf 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -46,6 +46,13 @@ #define adsp_dbg(_dsp, fmt, ...) \ dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__) +#define compr_err(_obj, fmt, ...) \ + adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \ + ##__VA_ARGS__) +#define compr_dbg(_obj, fmt, ...) \ + adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \ + ##__VA_ARGS__) + #define ADSP1_CONTROL_1 0x00 #define ADSP1_CONTROL_2 0x02 #define ADSP1_CONTROL_3 0x03 @@ -3033,20 +3040,23 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) mutex_lock(&dsp->pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps == 0) { - adsp_err(dsp, "Firmware does not support compressed API\n"); + adsp_err(dsp, "%s: Firmware does not support compressed API\n", + rtd->codec_dai->name); ret = -ENXIO; goto out; } if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { - adsp_err(dsp, "Firmware does not support stream direction\n"); + adsp_err(dsp, "%s: Firmware does not support stream direction\n", + rtd->codec_dai->name); ret = -EINVAL; goto out; } list_for_each_entry(tmp, &dsp->compr_list, list) { if (!strcmp(tmp->name, rtd->codec_dai->name)) { - adsp_err(dsp, "Only a single stream supported per dai\n"); + adsp_err(dsp, "%s: Only a single stream supported per dai\n", + rtd->codec_dai->name); ret = -EBUSY; goto out; } @@ -3106,9 +3116,9 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { - adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n", - params->buffer.fragment_size, - params->buffer.fragments); + compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n", + params->buffer.fragment_size, + params->buffer.fragments); return -EINVAL; } @@ -3136,9 +3146,9 @@ static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, return 0; } - adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", - params->codec.id, params->codec.ch_in, params->codec.ch_out, - params->codec.sample_rate, params->codec.format); + compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", + params->codec.id, params->codec.ch_in, params->codec.ch_out, + params->codec.sample_rate, params->codec.format); return -EINVAL; } @@ -3160,8 +3170,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream, compr->size = params->buffer; - adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", - compr->size.fragment_size, compr->size.fragments); + compr_dbg(compr, "fragment_size=%d fragments=%d\n", + compr->size.fragment_size, compr->size.fragments); size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); @@ -3303,10 +3313,10 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) region->cumulative_size = offset; - adsp_dbg(buf->dsp, - "region=%d type=%d base=%08x off=%08x size=%08x\n", - i, region->mem_type, region->base_addr, - region->offset, region->cumulative_size); + compr_dbg(buf, + "region=%d type=%d base=%08x off=%08x size=%08x\n", + i, region->mem_type, region->base_addr, + region->offset, region->cumulative_size); } return 0; @@ -3380,7 +3390,7 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) if (ret < 0) return ret; - adsp_dbg(dsp, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); + compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; } @@ -3428,7 +3438,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) * control is one word, assume version 0. */ if (ctl->len == 4) { - adsp_dbg(ctl->dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); return 0; } @@ -3458,8 +3468,8 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, (char *)&coeff_v1.name); - adsp_dbg(ctl->dsp, "host_buf_ptr=%x coeff version %u\n", - buf->host_buf_ptr, val); + compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", + buf->host_buf_ptr, val); return val; } @@ -3525,7 +3535,7 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) struct wm_adsp *dsp = compr->dsp; int ret = 0; - adsp_dbg(dsp, "Trigger: %d\n", cmd); + compr_dbg(compr, "Trigger: %d\n", cmd); mutex_lock(&dsp->pwr_lock); @@ -3534,8 +3544,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) if (!wm_adsp_compr_attached(compr)) { ret = wm_adsp_compr_attach(compr); if (ret < 0) { - adsp_err(dsp, "Failed to link buffer and stream: %d\n", - ret); + compr_err(compr, "Failed to link buffer and stream: %d\n", + ret); break; } } @@ -3547,8 +3557,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) HOST_BUFFER_FIELD(high_water_mark), wm_adsp_compr_frag_words(compr)); if (ret < 0) { - adsp_err(dsp, "Failed to set high water mark: %d\n", - ret); + compr_err(compr, "Failed to set high water mark: %d\n", + ret); break; } break; @@ -3589,7 +3599,7 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) read_index = sign_extend32(next_read_index, 23); if (read_index < 0) { - adsp_dbg(buf->dsp, "Avail check on unstarted stream\n"); + compr_dbg(buf, "Avail check on unstarted stream\n"); return 0; } @@ -3607,8 +3617,8 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) if (avail < 0) avail += wm_adsp_buffer_size(buf); - adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", - buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); + compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n", + buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); buf->avail = avail; @@ -3621,11 +3631,11 @@ static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); if (ret < 0) { - adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); + compr_err(buf, "Failed to check buffer error: %d\n", ret); return ret; } if (buf->error != 0) { - adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); + compr_err(buf, "Buffer error occurred: %d\n", buf->error); return -EIO; } @@ -3644,6 +3654,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) ret = -ENODEV; goto out; } + adsp_dbg(dsp, "Handling buffer IRQ\n"); list_for_each_entry(buf, &dsp->buffer_list, list) { @@ -3656,13 +3667,13 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), &buf->irq_count); if (ret < 0) { - adsp_err(dsp, "Failed to get irq_count: %d\n", ret); + compr_err(buf, "Failed to get irq_count: %d\n", ret); goto out; } ret = wm_adsp_buffer_update_avail(buf); if (ret < 0) { - adsp_err(dsp, "Error reading avail: %d\n", ret); + compr_err(buf, "Error reading avail: %d\n", ret); goto out; } @@ -3686,8 +3697,7 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) if (buf->irq_count & 0x01) return 0; - adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n", - buf->irq_count); + compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count); buf->irq_count |= 0x01; @@ -3703,7 +3713,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, struct wm_adsp_compr_buf *buf; int ret = 0; - adsp_dbg(dsp, "Pointer request\n"); + compr_dbg(compr, "Pointer request\n"); mutex_lock(&dsp->pwr_lock); @@ -3718,7 +3728,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, if (buf->avail < wm_adsp_compr_frag_words(compr)) { ret = wm_adsp_buffer_update_avail(buf); if (ret < 0) { - adsp_err(dsp, "Error reading avail: %d\n", ret); + compr_err(compr, "Error reading avail: %d\n", ret); goto out; } @@ -3737,9 +3747,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, ret = wm_adsp_buffer_reenable_irq(buf); if (ret < 0) { - adsp_err(dsp, - "Failed to re-enable buffer IRQ: %d\n", - ret); + compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", + ret); goto out; } } @@ -3814,11 +3823,10 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) static int wm_adsp_compr_read(struct wm_adsp_compr *compr, char __user *buf, size_t count) { - struct wm_adsp *dsp = compr->dsp; int ntotal = 0; int nwords, nbytes; - adsp_dbg(dsp, "Requested read of %zu bytes\n", count); + compr_dbg(compr, "Requested read of %zu bytes\n", count); if (!compr->buf || compr->buf->error) { snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); @@ -3830,17 +3838,18 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, do { nwords = wm_adsp_buffer_capture_block(compr, count); if (nwords < 0) { - adsp_err(dsp, "Failed to capture block: %d\n", nwords); + compr_err(compr, "Failed to capture block: %d\n", + nwords); return nwords; } nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; - adsp_dbg(dsp, "Read %d bytes\n", nbytes); + compr_dbg(compr, "Read %d bytes\n", nbytes); if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { - adsp_err(dsp, "Failed to copy data to user: %d, %d\n", - ntotal, nbytes); + compr_err(compr, "Failed to copy data to user: %d, %d\n", + ntotal, nbytes); return -EFAULT; } From cfc35f9c128cea8fce6a5513b1de50d36f3b209f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Feb 2019 16:49:27 +0100 Subject: [PATCH 448/461] ALSA: hda: Extend i915 component bind timeout I set 10 seconds for the timeout of the i915 audio component binding with a hope that recent machines are fast enough to handle all probe tasks in that period, but I was too optimistic. The binding may take longer than that, and this caused a problem on the machine with both audio and graphics driver modules loaded in parallel, as Paul Menzel experienced. This problem haven't hit so often just because the KMS driver is loaded in initrd on most machines. As a simple workaround, extend the timeout to 60 seconds. Fixes: f9b54e1961c7 ("ALSA: hda/i915: Allow delayed i915 audio component binding") Reported-by: Paul Menzel Cc: Signed-off-by: Takashi Iwai --- sound/hda/hdac_i915.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 617ff1aa818f..27eb0270a711 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -144,9 +144,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus) return -ENODEV; if (!acomp->ops) { request_module("i915"); - /* 10s timeout */ + /* 60s timeout */ wait_for_completion_timeout(&bind_complete, - msecs_to_jiffies(10 * 1000)); + msecs_to_jiffies(60 * 1000)); } if (!acomp->ops) { dev_info(bus->dev, "couldn't bind with audio component\n"); From 7dc661bd8d3261053b69e4e2d0050cd1ee540fc1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 26 Feb 2019 13:38:16 +0900 Subject: [PATCH 449/461] ALSA: bebob: use more identical mod_alias for Saffire Pro 10 I/O against Liquid Saffire 56 ALSA bebob driver has an entry for Focusrite Saffire Pro 10 I/O. The entry matches vendor_id in root directory and model_id in unit directory of configuration ROM for IEEE 1394 bus. On the other hand, configuration ROM of Focusrite Liquid Saffire 56 has the same vendor_id and model_id. This device is an application of TCAT Dice (TCD2220 a.k.a Dice Jr.) however ALSA bebob driver can be bound to it randomly instead of ALSA dice driver. At present, drivers in ALSA firewire stack can not handle this situation appropriately. This commit uses more identical mod_alias for Focusrite Saffire Pro 10 I/O in ALSA bebob driver. $ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 042a829d bus_info_length 4, crc_length 42, crc 33437 404 31333934 bus_name "1394" 408 f0649222 irmc 1, cmc 1, isc 1, bmc 1, pmc 0, cyc_clk_acc 100, max_rec 9 (1024), max_rom 2, gen 2, spd 2 (S400) 40c 00130e01 company_id 00130e | 410 000606e0 device_id 01000606e0 | EUI-64 00130e01000606e0 root directory ----------------------------------------------------------------- 414 0009d31c directory_length 9, crc 54044 418 04000014 hardware version 41c 0c0083c0 node capabilities per IEEE 1394 420 0300130e vendor 424 81000012 --> descriptor leaf at 46c 428 17000006 model 42c 81000016 --> descriptor leaf at 484 430 130120c2 version 434 d1000002 --> unit directory at 43c 438 d4000006 --> dependent info directory at 450 unit directory at 43c ----------------------------------------------------------------- 43c 0004707c directory_length 4, crc 28796 440 1200a02d specifier id: 1394 TA 444 13010001 version: AV/C 448 17000006 model 44c 81000013 --> descriptor leaf at 498 dependent info directory at 450 ----------------------------------------------------------------- 450 000637c7 directory_length 6, crc 14279 454 120007f5 specifier id 458 13000001 version 45c 3affffc7 (immediate value) 460 3b100000 (immediate value) 464 3cffffc7 (immediate value) 468 3d600000 (immediate value) descriptor leaf at 46c ----------------------------------------------------------------- 46c 00056f3b leaf_length 5, crc 28475 470 00000000 textual descriptor 474 00000000 minimal ASCII 478 466f6375 "Focu" 47c 73726974 "srit" 480 65000000 "e" descriptor leaf at 484 ----------------------------------------------------------------- 484 0004a165 leaf_length 4, crc 41317 488 00000000 textual descriptor 48c 00000000 minimal ASCII 490 50726f31 "Pro1" 494 30494f00 "0IO" descriptor leaf at 498 ----------------------------------------------------------------- 498 0004a165 leaf_length 4, crc 41317 49c 00000000 textual descriptor 4a0 00000000 minimal ASCII 4a4 50726f31 "Pro1" 4a8 30494f00 "0IO" $ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 040442e4 bus_info_length 4, crc_length 4, crc 17124 404 31333934 bus_name "1394" 408 e0ff8112 irmc 1, cmc 1, isc 1, bmc 0, pmc 0, cyc_clk_acc 255, max_rec 8 (512), max_rom 1, gen 1, spd 2 (S400) 40c 00130e04 company_id 00130e | 410 018001e9 device_id 04018001e9 | EUI-64 00130e04018001e9 root directory ----------------------------------------------------------------- 414 00065612 directory_length 6, crc 22034 418 0300130e vendor 41c 8100000a --> descriptor leaf at 444 420 17000006 model 424 8100000e --> descriptor leaf at 45c 428 0c0087c0 node capabilities per IEEE 1394 42c d1000001 --> unit directory at 430 unit directory at 430 ----------------------------------------------------------------- 430 000418a0 directory_length 4, crc 6304 434 1200130e specifier id 438 13000001 version 43c 17000006 model 440 8100000f --> descriptor leaf at 47c descriptor leaf at 444 ----------------------------------------------------------------- 444 00056f3b leaf_length 5, crc 28475 448 00000000 textual descriptor 44c 00000000 minimal ASCII 450 466f6375 "Focu" 454 73726974 "srit" 458 65000000 "e" descriptor leaf at 45c ----------------------------------------------------------------- 45c 000762c6 leaf_length 7, crc 25286 460 00000000 textual descriptor 464 00000000 minimal ASCII 468 4c495155 "LIQU" 46c 49445f53 "ID_S" 470 41464649 "AFFI" 474 52455f35 "RE_5" 478 36000000 "6" descriptor leaf at 47c ----------------------------------------------------------------- 47c 000762c6 leaf_length 7, crc 25286 480 00000000 textual descriptor 484 00000000 minimal ASCII 488 4c495155 "LIQU" 48c 49445f53 "ID_S" 490 41464649 "AFFI" 494 52455f35 "RE_5" 498 36000000 "6" Cc: # v3.16+ Fixes: 25784ec2d034 ("ALSA: bebob: Add support for Focusrite Saffire/SaffirePro series") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index d91874275d2c..5b46e8dcc2dd 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -448,7 +448,19 @@ static const struct ieee1394_device_id bebob_id_table[] = { /* Focusrite, SaffirePro 26 I/O */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec), /* Focusrite, SaffirePro 10 I/O */ - SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000006, &saffirepro_10_spec), + { + // The combination of vendor_id and model_id is the same as the + // same as the one of Liquid Saffire 56. + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VEN_FOCUSRITE, + .model_id = 0x000006, + .specifier_id = 0x00a02d, + .version = 0x010001, + .driver_data = (kernel_ulong_t)&saffirepro_10_spec, + }, /* Focusrite, Saffire(no label and LE) */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH, &saffire_spec), From f97a0944a72b26a2bece72516294e112a890f98a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 26 Feb 2019 13:38:37 +0900 Subject: [PATCH 450/461] ALSA: firewire-motu: fix construction of PCM frame for capture direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In data blocks of common isochronous packet for MOTU devices, PCM frames are multiplexed in a shape of '24 bit * 4 Audio Pack', described in IEC 61883-6. The frames are not aligned to quadlet. For capture PCM substream, ALSA firewire-motu driver constructs PCM frames by reading data blocks byte-by-byte. However this operation includes bug for lower byte of the PCM sample. This brings invalid content of the PCM samples. This commit fixes the bug. Reported-by: Peter Sjöberg Cc: # v4.12+ Fixes: 4641c9394010 ("ALSA: firewire-motu: add MOTU specific protocol layer") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/amdtp-motu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index f0555a24d90e..6c9b743ea74b 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -136,7 +136,9 @@ static void read_pcm_s32(struct amdtp_stream *s, byte = (u8 *)buffer + p->pcm_byte_offset; for (c = 0; c < channels; ++c) { - *dst = (byte[0] << 24) | (byte[1] << 16) | byte[2]; + *dst = (byte[0] << 24) | + (byte[1] << 16) | + (byte[2] << 8); byte += 3; dst++; } From 8af6c521cc236534093f9e744cfa004314bfe5ae Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Mon, 25 Feb 2019 12:14:20 +0100 Subject: [PATCH 451/461] ASoC: rsnd: gen: fix SSI9 4/5/6/7 busif related register address Currently each SSI unit 's busif mode/adinr/dalign address is registered by: (in busif4 case) RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80) RSND_GEN_M_REG(SSI_BUSIF4_ADINR,0x504, 0x80) RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80) But according to user manual 41.1.4 Register Configuration ssi9 4/5/6/7 busif mode/adinr/dalign register address ( SSI9-[4/5/6/7]_BUSIF_[MODE/ADINR/DALIGN] ) are out of this rule. This patch registers ssi9 4/5/6/7 mode/adinr/dalign register as single register, and access these registers in case of SSI9 BUSIF 4/5/6/7. Fixes: commit 8c9d75033340 ("ASoC: rsnd: ssiu: Support BUSIF other than BUSIF0") Signed-off-by: Jiada Wang Signed-off-by: Timo Wischer Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 24 ++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 27 +++++++++++++++++++++++++++ sound/soc/sh/rcar/ssiu.c | 24 +++++++++++------------- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 7cda60188f41..af19010b9d88 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -255,6 +255,30 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), + RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c), + RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484), + RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488), + RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0), + RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4), + RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8), + RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0), + RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4), + RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8), + RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0), + RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4), + RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8), + RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80), + RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84), + RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88), + RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0), + RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4), + RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8), + RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0), + RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4), + RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8), + RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0), + RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4), + RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8), }; static const struct rsnd_regmap_field_conf conf_scu[] = { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 605e4b934982..90625c57847b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -191,6 +191,30 @@ enum rsnd_reg { SSI_SYS_STATUS7, HDMI0_SEL, HDMI1_SEL, + SSI9_BUSIF0_MODE, + SSI9_BUSIF1_MODE, + SSI9_BUSIF2_MODE, + SSI9_BUSIF3_MODE, + SSI9_BUSIF4_MODE, + SSI9_BUSIF5_MODE, + SSI9_BUSIF6_MODE, + SSI9_BUSIF7_MODE, + SSI9_BUSIF0_ADINR, + SSI9_BUSIF1_ADINR, + SSI9_BUSIF2_ADINR, + SSI9_BUSIF3_ADINR, + SSI9_BUSIF4_ADINR, + SSI9_BUSIF5_ADINR, + SSI9_BUSIF6_ADINR, + SSI9_BUSIF7_ADINR, + SSI9_BUSIF0_DALIGN, + SSI9_BUSIF1_DALIGN, + SSI9_BUSIF2_DALIGN, + SSI9_BUSIF3_DALIGN, + SSI9_BUSIF4_DALIGN, + SSI9_BUSIF5_DALIGN, + SSI9_BUSIF6_DALIGN, + SSI9_BUSIF7_DALIGN, /* SSI */ SSICR, @@ -209,6 +233,9 @@ enum rsnd_reg { #define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) #define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) #define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) +#define SSI9_BUSIF_MODE(i) (SSI9_BUSIF0_MODE + (i)) +#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i)) +#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i)) #define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index c74991dd18ab..2347f3404c06 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -181,28 +181,26 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, if (rsnd_ssi_use_busif(io)) { int id = rsnd_mod_id(mod); int busif = rsnd_mod_id_sub(mod); + enum rsnd_reg adinr_reg, mode_reg, dalign_reg; - /* - * FIXME - * - * We can't support SSI9-4/5/6/7, because its address is - * out of calculation rule - */ if ((id == 9) && (busif >= 4)) { - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "This driver doesn't support SSI%d-%d, so far", - id, busif); + adinr_reg = SSI9_BUSIF_ADINR(busif); + mode_reg = SSI9_BUSIF_MODE(busif); + dalign_reg = SSI9_BUSIF_DALIGN(busif); + } else { + adinr_reg = SSI_BUSIF_ADINR(busif); + mode_reg = SSI_BUSIF_MODE(busif); + dalign_reg = SSI_BUSIF_DALIGN(busif); } - rsnd_mod_write(mod, SSI_BUSIF_ADINR(busif), + rsnd_mod_write(mod, adinr_reg, rsnd_get_adinr_bit(mod, io) | (rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, SSI_BUSIF_MODE(busif), + rsnd_mod_write(mod, mode_reg, rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, SSI_BUSIF_DALIGN(busif), + rsnd_mod_write(mod, dalign_reg, rsnd_get_dalign(mod, io)); } From 716d53cc7837aec7f439ce2a20fc2597a89dae53 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Mon, 25 Feb 2019 22:17:31 +0530 Subject: [PATCH 452/461] ASoC: Intel: Boards: Add Maxim98373 support This patch enables the reuse of kbl_da7219_max98927 machine driver to support max98373. The same machine driver is modified for cases where one amplifier is swapped out with another. Most of the changes are about renaming the codec and codec_dai names, with minor differences due to support for 24 bits in one case and 16 in the other. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/kbl_da7219_max98927.c | 201 ++++++++++++++++-- .../intel/common/soc-acpi-intel-kbl-match.c | 19 ++ 3 files changed, 199 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0a7e40d06395..12d6b73e9531 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,6 +293,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7219 select SND_SOC_MAX98927 + select SND_SOC_MAX98373 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI help diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 6dd5c69671b3..2768a572d065 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -2,7 +2,7 @@ // Copyright(c) 2018 Intel Corporation. /* - * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs * * Modified from: * Intel Kabylake I2S Machine driver supporting MAX98927 and @@ -24,8 +24,14 @@ #define KBL_DIALOG_CODEC_DAI "da7219-hifi" #define MAX98927_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define MAX98927_DEV0_NAME "i2c-MX98927:00" +#define MAX98927_DEV1_NAME "i2c-MX98927:01" + +#define MAX98373_CODEC_DAI "max98373-aif1" +#define MAX98373_DEV0_NAME "i2c-MX98373:00" +#define MAX98373_DEV1_NAME "i2c-MX98373:01" + + #define DUAL_CHANNEL 2 #define QUAD_CHANNEL 4 #define NAME_SIZE 32 @@ -176,20 +182,38 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, for (j = 0; j < runtime->num_codecs; j++) { struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); return ret; } } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); return ret; } } + if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x03, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x0C, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } } return 0; @@ -212,6 +236,25 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, + * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. + * Skipping the port wise FE and BE configuration for kblda7219m98373 & + * kblmax98373 as the topology (FE & BE) supports S24_LE only. + */ + + if (!strcmp(rtd->card->name, "kblda7219m98373") || + !strcmp(rtd->card->name, "kblmax98373")) { + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = DUAL_CHANNEL; + + /* set SSP to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; + } + /* * The ADSP will convert the FE rate to 48k, stereo, 24 bit */ @@ -352,20 +395,31 @@ static struct snd_pcm_hw_constraint_list constraints_channels_quad = { static int kbl_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; /* * On this platform for PCM device we support, * 48Khz * stereo - * 16 bit audio */ runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels); + /* + * Setup S24_LE (32 bit container and 24 bit valid data) for + * kblda7219m98373 & kblmax98373. For kblda7219m98927 & + * kblmax98927 keeping it as 16/16 due to topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + } else { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); @@ -398,11 +452,23 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels_quad); + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE. + * The DMIC also configured for S24_LE. Forcing the DMIC format to + * S24_LE due to the topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + } + return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } @@ -448,29 +514,55 @@ static struct snd_soc_ops skylake_refcap_ops = { static struct snd_soc_codec_conf max98927_codec_conf[] = { { - .dev_name = MAXIM_DEV0_NAME, + .dev_name = MAX98927_DEV0_NAME, .name_prefix = "Right", }, { - .dev_name = MAXIM_DEV1_NAME, + .dev_name = MAX98927_DEV1_NAME, .name_prefix = "Left", }, }; -static struct snd_soc_dai_link_component ssp0_codec_components[] = { +static struct snd_soc_codec_conf max98373_codec_conf[] = { + + { + .dev_name = MAX98373_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAX98373_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component max98927_ssp0_codec_components[] = { { /* Left */ - .name = MAXIM_DEV0_NAME, + .name = MAX98927_DEV0_NAME, .dai_name = MAX98927_CODEC_DAI, }, { /* For Right */ - .name = MAXIM_DEV1_NAME, + .name = MAX98927_DEV1_NAME, .dai_name = MAX98927_CODEC_DAI, }, }; +static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { + { /* Left */ + .name = MAX98373_DEV0_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + + { /* For Right */ + .name = MAX98373_DEV1_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + +}; + /* kabylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link kabylake_dais[] = { /* Front End DAI links */ @@ -607,8 +699,8 @@ static struct snd_soc_dai_link kabylake_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -683,7 +775,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { }; /* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98927_dais[] = { +static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { /* Front End DAI links */ [KBL_DPCM_AUDIO_PB] = { .name = "Kbl Audio Port", @@ -802,8 +894,8 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -917,8 +1009,8 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = { static struct snd_soc_card kbl_audio_card_max98927 = { .name = "kblmax98927", .owner = THIS_MODULE, - .dai_link = kabylake_max98927_dais, - .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), .controls = kabylake_controls, .num_controls = ARRAY_SIZE(kabylake_controls), .dapm_widgets = kabylake_widgets, @@ -931,9 +1023,46 @@ static struct snd_soc_card kbl_audio_card_max98927 = { .late_probe = kabylake_card_late_probe, }; +static struct snd_soc_card kbl_audio_card_da7219_m98373 = { + .name = "kblda7219m98373", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static struct snd_soc_card kbl_audio_card_max98373 = { + .name = "kblmax98373", + .owner = THIS_MODULE, + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; + struct snd_soc_dai_link *kbl_dai_link; + struct snd_soc_dai_link_component **codecs; + int i = 0; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -944,6 +1073,22 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card = (struct snd_soc_card *)pdev->id_entry->driver_data; + kbl_dai_link = kabylake_audio_card->dai_link; + + /* Update codecs for SSP0 with max98373 codec info */ + if (!strcmp(pdev->name, "kbl_da7219_max98373") || + (!strcmp(pdev->name, "kbl_max98373"))) { + for (i = 0; i < kabylake_audio_card->num_links; ++i) { + if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) + continue; + + codecs = &(kbl_dai_link[i].codecs); + *codecs = max98373_ssp0_codec_components; + kbl_dai_link[i].num_codecs = + ARRAY_SIZE(max98373_ssp0_codec_components); + break; + } + } kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); @@ -961,13 +1106,23 @@ static const struct platform_device_id kbl_board_ids[] = { .driver_data = (kernel_ulong_t)&kbl_audio_card_max98927, }, + { + .name = "kbl_da7219_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98373, + }, + { + .name = "kbl_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98373, + }, { } }; static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, .driver = { - .name = "kbl_da7219_max98927", + .name = "kbl_da7219_max98_927_373", .pm = &snd_soc_pm_ops, }, .id_table = kbl_board_ids, @@ -976,8 +1131,10 @@ static struct platform_driver kabylake_audio = { module_platform_driver(kabylake_audio) /* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:kbl_da7219_max98927"); MODULE_ALIAS("platform:kbl_max98927"); +MODULE_ALIAS("platform:kbl_da7219_max98373"); +MODULE_ALIAS("platform:kbl_max98373"); diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index e6fa6f470526..4b331058e807 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -37,6 +37,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { .codecs = {"MX98927"} }; +static struct snd_soc_acpi_codecs kbl_7219_98373_codecs = { + .num_codecs = 1, + .codecs = {"MX98373"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -106,6 +111,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .drv_name = "kbl_rt5660", .fw_filename = "intel/dsp_fw_kbl.bin", }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98373_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98373", + .drv_name = "kbl_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From cdcdba5d624fc3fbad224230ca318c6ddf73795a Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 25 Feb 2019 21:54:05 +0800 Subject: [PATCH 453/461] ASoC: qcom: Kconfig: fix dependency for sdm845 SND_SOC_CROS_EC_CODEC depends on MFD_CROS_EC. Add that dependency to SND_SOC_SDM845 to fix unmet direct dependencies warning. Fixes: 74c6ecf4194e (ASoC: qcom: Kconfig: select dmic for sdm845) Signed-off-by: Cheng-Yi Chiang Reported-by: Randy Dunlap Tested-by: Enric Balletbo i Serra Tested-by: Randy Dunlap Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 8f206cb4fcc0..75ceb04d8bf0 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -98,7 +98,7 @@ config SND_SOC_MSM8996 config SND_SOC_SDM845 tristate "SoC Machine driver for SDM845 boards" - depends on QCOM_APR + depends on QCOM_APR && MFD_CROS_EC select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON select SND_SOC_RT5663 From 8ba3c5215d69c09f5c39783ff3b78347769822ad Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:04 +0100 Subject: [PATCH 454/461] ASoC: stm32: i2s: fix IRQ clearing Because of regmap cache, interrupts may not be cleared as expected. Declare IFCR register as write only and make writings to IFCR register unconditional. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index a25919d32187..339cd4715b2e 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -247,8 +247,8 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) return IRQ_NONE; } - regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, flags); + regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, flags); if (flags & I2S_SR_OVR) { dev_dbg(&pdev->dev, "Overrun\n"); @@ -277,7 +277,6 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) case STM32_I2S_CFG2_REG: case STM32_I2S_IER_REG: case STM32_I2S_SR_REG: - case STM32_I2S_IFCR_REG: case STM32_I2S_TXDR_REG: case STM32_I2S_RXDR_REG: case STM32_I2S_CGFR_REG: @@ -559,8 +558,8 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, i2s->refcount++; spin_unlock(&i2s->lock_fd); - return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, I2S_IFCR_MASK); + return regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, @@ -611,8 +610,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } - regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, - I2S_IFCR_MASK, I2S_IFCR_MASK); + regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); if (playback_flg) { ier = I2S_IER_UDRIE; From 0c4c68d6fa1bae74d450e50823c24fcc3cd0b171 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:05 +0100 Subject: [PATCH 455/461] ASoC: stm32: i2s: fix 16 bit format support I2S supports 16 bits data in 32 channel length. However the expected driver behavior, is to set channel length to 16 bits when data format is 16 bits. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 339cd4715b2e..7d4c67433916 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -501,7 +501,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, switch (format) { case 16: cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16); - cfgr_mask = I2S_CGFR_DATLEN_MASK; + cfgr_mask = I2S_CGFR_DATLEN_MASK | I2S_CGFR_CHLEN; break; case 32: cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_32) | From ebf629d502cf7aa138b86f36dc016faf6c8e39e3 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:06 +0100 Subject: [PATCH 456/461] ASoC: stm32: i2s: fix stream count management Move counter handling to trigger start section to manage multiple start/stop events. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 7d4c67433916..7f56d7b51ba3 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -554,10 +554,6 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, return ret; } - spin_lock(&i2s->lock_fd); - i2s->refcount++; - spin_unlock(&i2s->lock_fd); - return regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, I2S_IFCR_MASK, I2S_IFCR_MASK); } @@ -613,18 +609,19 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, I2S_IFCR_MASK, I2S_IFCR_MASK); + spin_lock(&i2s->lock_fd); + i2s->refcount++; if (playback_flg) { ier = I2S_IER_UDRIE; } else { ier = I2S_IER_OVRIE; - spin_lock(&i2s->lock_fd); if (i2s->refcount == 1) /* dummy write to trigger capture */ regmap_write(i2s->regmap, STM32_I2S_TXDR_REG, 0); - spin_unlock(&i2s->lock_fd); } + spin_unlock(&i2s->lock_fd); if (STM32_I2S_IS_SLAVE(i2s)) ier |= I2S_IER_TIFREIE; @@ -649,7 +646,6 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, spin_unlock(&i2s->lock_fd); break; } - spin_unlock(&i2s->lock_fd); dev_dbg(cpu_dai->dev, "stop I2S\n"); @@ -657,8 +653,10 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, I2S_CR1_SPE, 0); if (ret < 0) { dev_err(cpu_dai->dev, "Error %d disabling I2S\n", ret); + spin_unlock(&i2s->lock_fd); return ret; } + spin_unlock(&i2s->lock_fd); cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, From 1ac2bd16448997d9ec01922423486e1e85535eda Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:07 +0100 Subject: [PATCH 457/461] ASoC: stm32: i2s: fix dma configuration DMA configuration is not balanced on start/stop. Move DMA configuration to trigger callback. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 7f56d7b51ba3..95fffb61faa5 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -488,7 +488,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); int format = params_width(params); - u32 cfgr, cfgr_mask, cfg1, cfg1_mask; + u32 cfgr, cfgr_mask, cfg1; unsigned int fthlv; int ret; @@ -529,15 +529,11 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; - cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; - cfg1_mask = cfg1; - fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; - cfg1 |= I2S_CFG1_FTHVL_SET(fthlv - 1); - cfg1_mask |= I2S_CFG1_FTHVL_MASK; + cfg1 = I2S_CFG1_FTHVL_SET(fthlv - 1); return regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, - cfg1_mask, cfg1); + I2S_CFG1_FTHVL_MASK, cfg1); } static int stm32_i2s_startup(struct snd_pcm_substream *substream, @@ -592,6 +588,10 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, /* Enable i2s */ dev_dbg(cpu_dai->dev, "start I2S\n"); + cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; + regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, + cfg1_mask, cfg1_mask); + ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, I2S_CR1_SPE, I2S_CR1_SPE); if (ret < 0) { From 88dce52ee9b58b627cf75f5aeb53ab5ea6340472 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:08 +0100 Subject: [PATCH 458/461] ASoC: stm32: i2s: remove useless callback Clocks do not need to be released on driver removal, as this is already managed before. Remove useless remove callback. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 95fffb61faa5..9edb753ffa1b 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -902,16 +902,6 @@ static int stm32_i2s_probe(struct platform_device *pdev) I2S_CGFR_I2SMOD, I2S_CGFR_I2SMOD); } -static int stm32_i2s_remove(struct platform_device *pdev) -{ - struct stm32_i2s_data *i2s = platform_get_drvdata(pdev); - - clk_disable_unprepare(i2s->i2sclk); - clk_disable_unprepare(i2s->pclk); - - return 0; -} - MODULE_DEVICE_TABLE(of, stm32_i2s_ids); #ifdef CONFIG_PM_SLEEP @@ -945,7 +935,6 @@ static struct platform_driver stm32_i2s_driver = { .pm = &stm32_i2s_pm_ops, }, .probe = stm32_i2s_probe, - .remove = stm32_i2s_remove, }; module_platform_driver(stm32_i2s_driver); From 3005decf4fe43e65d882dce838716bd6715757c1 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:09 +0100 Subject: [PATCH 459/461] ASoC: stm32: i2s: fix race condition in irq handler When snd_pcm_stop_xrun() is called in interrupt routine, substream context may have already been released. Add protection on substream context. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 9edb753ffa1b..42ce87a35104 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -201,6 +201,7 @@ enum i2s_datlen { * @base: mmio register base virtual address * @phys_addr: I2S registers physical base address * @lock_fd: lock to manage race conditions in full duplex mode + * @irq_lock: prevent race condition with IRQ * @dais_name: DAI name * @mclk_rate: master clock frequency (Hz) * @fmt: DAI protocol @@ -222,6 +223,7 @@ struct stm32_i2s_data { void __iomem *base; dma_addr_t phys_addr; spinlock_t lock_fd; /* Manage race conditions for full duplex */ + spinlock_t irq_lock; /* used to prevent race condition with IRQ */ char dais_name[STM32_I2S_DAI_NAME_SIZE]; unsigned int mclk_rate; unsigned int fmt; @@ -263,8 +265,10 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) if (flags & I2S_SR_TIFRE) dev_dbg(&pdev->dev, "Frame error\n"); - if (err) + spin_lock(&i2s->irq_lock); + if (err && i2s->substream) snd_pcm_stop_xrun(i2s->substream); + spin_unlock(&i2s->irq_lock); return IRQ_HANDLED; } @@ -540,9 +544,12 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; int ret; + spin_lock_irqsave(&i2s->irq_lock, flags); i2s->substream = substream; + spin_unlock_irqrestore(&i2s->irq_lock, flags); ret = clk_prepare_enable(i2s->i2sclk); if (ret < 0) { @@ -673,13 +680,16 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); - - i2s->substream = NULL; + unsigned long flags; regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); clk_disable_unprepare(i2s->i2sclk); + + spin_lock_irqsave(&i2s->irq_lock, flags); + i2s->substream = NULL; + spin_unlock_irqrestore(&i2s->irq_lock, flags); } static int stm32_i2s_dai_probe(struct snd_soc_dai *cpu_dai) @@ -874,6 +884,7 @@ static int stm32_i2s_probe(struct platform_device *pdev) i2s->pdev = pdev; i2s->ms_flg = I2S_MS_NOT_SET; spin_lock_init(&i2s->lock_fd); + spin_lock_init(&i2s->irq_lock); platform_set_drvdata(pdev, i2s); ret = stm32_i2s_dais_init(pdev, i2s); From 7b6b0049e2b70d103adf1b7d0320802f70ddceca Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Tue, 26 Feb 2019 14:51:10 +0100 Subject: [PATCH 460/461] ASoC: stm32: i2s: skip useless write in slave mode Dummy write in capture master mode is used to gate bus clocks. This write is useless in slave mode as the clocks are not managed by slave. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 42ce87a35104..47c334de6b09 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -623,8 +623,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, } else { ier = I2S_IER_OVRIE; - if (i2s->refcount == 1) - /* dummy write to trigger capture */ + if (STM32_I2S_IS_MASTER(i2s) && i2s->refcount == 1) + /* dummy write to gate bus clocks */ regmap_write(i2s->regmap, STM32_I2S_TXDR_REG, 0); } From a634090a0f242caa8ebc91967b118995a80eb13b Mon Sep 17 00:00:00 2001 From: Manuel Reinhardt Date: Thu, 28 Feb 2019 20:34:04 +0100 Subject: [PATCH 461/461] ALSA: usb-audio: Add quirk for MOTU MicroBook II Add an entry to the quirks-table to for usb-audio to recognize the Microbook II (although it only exposes vendor interfaces). A simple boot quirk is also implemented to set up the sample rate and make sure that no audio urbs are sent before the device is ready. This patch only provides audio playback and capture at 96kHz sample rate. Notice the following shortcomings: - The sample rate is currently hardcoded to 96k although the device also supports 48k and 44.1k. - The various mixer controls of the MicroBook are not made available. - The keep-iface control should be on by default because the device shuts down whenever the altsetting is reset which is usually unwanted. (I don't know the best way to do this) - The communication format used by the MicroBook for sample rate setting and also other setup has been reverse engineered by looking at the usbmon output while running the windows driver through virtualbox. In this patch the first byte of every message is set to \0 while in the observed communications the first byte acts as a "message-counter" increasing its value with every message sent. Leaving it at \0 does not seem to affect the device. Signed-off-by: Manuel Reinhardt Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 4 ++ sound/usb/quirks-table.h | 65 +++++++++++++++++++++++++ sound/usb/quirks.c | 101 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index db114f3977e0..056af0a57b22 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -354,6 +354,10 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, ep = 0x81; ifnum = 1; goto add_sync_ep_from_ifnum; + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ + ep = 0x84; + ifnum = 0; + goto add_sync_ep_from_ifnum; } if (attr == USB_ENDPOINT_SYNC_ASYNC && diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index b345beb447bd..86e80916a029 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3398,5 +3398,70 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .ifnum = QUIRK_NO_INTERFACE } }, +/* MOTU Microbook II */ +{ + USB_DEVICE(0x07fd, 0x0004), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "MOTU", + .product_name = "MicroBookII", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 6, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0, + .endpoint = 0x84, + .rates = SNDRV_PCM_RATE_96000, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .rate_min = 96000, + .rate_max = 96000, + .nr_rates = 1, + .maxpacksize = 0x00d8, + .rate_table = (unsigned int[]) { + 96000 + } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 8, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0, + .endpoint = 0x03, + .rates = SNDRV_PCM_RATE_96000, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .rate_min = 96000, + .rate_max = 96000, + .nr_rates = 1, + .maxpacksize = 0x0120, + .rate_table = (unsigned int[]) { + 96000 + } + } + }, + { + .ifnum = -1 + } + } + } +}, #undef USB_DEVICE_VENDOR_SPEC diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index f372c624bbf4..e6ce1bbe6ca6 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1000,6 +1000,105 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) return 0; } + +#define MICROBOOK_BUF_SIZE 128 + +static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf, + int buf_size, int *length) +{ + int err, actual_length; + + err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length, + &actual_length, 1000); + if (err < 0) + return err; + + print_hex_dump(KERN_DEBUG, "MicroBookII snd: ", DUMP_PREFIX_NONE, 16, 1, + buf, actual_length, false); + + memset(buf, 0, buf_size); + + err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size, + &actual_length, 1000); + if (err < 0) + return err; + + print_hex_dump(KERN_DEBUG, "MicroBookII rcv: ", DUMP_PREFIX_NONE, 16, 1, + buf, actual_length, false); + + *length = actual_length; + return 0; +} + +static int snd_usb_motu_microbookii_boot_quirk(struct usb_device *dev) +{ + int err, actual_length, poll_attempts = 0; + static const u8 set_samplerate_seq[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x14, + 0x00, 0x00, 0x00, 0x01 }; + static const u8 poll_ready_seq[] = { 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x18 }; + u8 *buf = kzalloc(MICROBOOK_BUF_SIZE, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + dev_info(&dev->dev, "Waiting for MOTU Microbook II to boot up...\n"); + + /* First we tell the device which sample rate to use. */ + memcpy(buf, set_samplerate_seq, sizeof(set_samplerate_seq)); + actual_length = sizeof(set_samplerate_seq); + err = snd_usb_motu_microbookii_communicate(dev, buf, MICROBOOK_BUF_SIZE, + &actual_length); + + if (err < 0) { + dev_err(&dev->dev, + "failed setting the sample rate for Motu MicroBook II: %d\n", + err); + goto free_buf; + } + + /* Then we poll every 100 ms until the device informs of its readiness. */ + while (true) { + if (++poll_attempts > 100) { + dev_err(&dev->dev, + "failed booting Motu MicroBook II: timeout\n"); + err = -ENODEV; + goto free_buf; + } + + memset(buf, 0, MICROBOOK_BUF_SIZE); + memcpy(buf, poll_ready_seq, sizeof(poll_ready_seq)); + + actual_length = sizeof(poll_ready_seq); + err = snd_usb_motu_microbookii_communicate( + dev, buf, MICROBOOK_BUF_SIZE, &actual_length); + if (err < 0) { + dev_err(&dev->dev, + "failed booting Motu MicroBook II: communication error %d\n", + err); + goto free_buf; + } + + /* the device signals its readiness through a message of the + * form + * XX 06 00 00 00 00 0b 18 00 00 00 01 + * If the device is not yet ready to accept audio data, the + * last byte of that sequence is 00. + */ + if (actual_length == 12 && buf[actual_length - 1] == 1) + break; + + msleep(100); + } + + dev_info(&dev->dev, "MOTU MicroBook II ready\n"); + +free_buf: + kfree(buf); + return err; +} + /* * Setup quirks */ @@ -1177,6 +1276,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, return snd_usb_gamecon780_boot_quirk(dev); case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */ return snd_usb_axefx3_boot_quirk(dev); + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ + return snd_usb_motu_microbookii_boot_quirk(dev); } return 0;